Hi - for fitting a TTE model in R with gamma distribution, I would do:
flexsurvreg(Surv(time, event) ~ cov1 + cov2 , data=df, dist="gamma")
Could someone please let me know how to do this in Pumas? Thanks.
Hi - for fitting a TTE model in R with gamma distribution, I would do:
flexsurvreg(Surv(time, event) ~ cov1 + cov2 , data=df, dist="gamma")
Could someone please let me know how to do this in Pumas? Thanks.
If you follow the Time to Event tutorials and implement the Gamma distribution in the @pre
and @vars
blocks that should be enough.
Thank you, Jose. I apologize, I should’ve been clearer in my ask. My question is stemming from the fact there is no analytical form to the hazard function in this case (like Exponential, Weibull, and Gompertz as you have shown in the tutorials). Can you please let me know how the model code would look like if we assume the failure time to follow a gamma distribution?
@storopoli I was able to perform some simulations using the gamma
function available in the SpecialFunctions
package but I cannot get the fit
to work. I am attaching the code for simulations, fit, and error from fit at the bottom. Please let me know if it is possible to make the fitting work. Thanks.
Simulation code:
using SpecialFunctions
gamma_model = @model begin
@param begin
scale1 ∈ RealDomain(lower=0)
shape1 ∈ RealDomain(lower=0)
end
@pre begin
scale_typ = scale1
shape_typ = shape1
pdf_gamma = (t^(shape_typ-1.) * exp(-t/scale_typ)) / (gamma(shape_typ) * scale_typ^shape_typ)
cdf_gamma = gamma(shape_typ, t/scale_typ) - gamma(shape_typ)
haz = pdf_gamma / (1. - cdf_gamma)
end
@vars begin
λ = haz
end
@dynamics begin
Λ' = λ
end
@derived begin
event ~ @. TimeToEvent(λ, Λ)
end
end
dt_sim = DataFrame(id = 1, time = 10., event=missing)
pop4tte = read_pumas(dt_sim, observations = [:event], event_data=false)
gamma_params = (; scale1 = 0.15, shape1 = 1.2,)
gamma_sims = simobstte(
gamma_model, pop4tte[1], gamma_params, NamedTuple();
minT = 0, nT = 100, repeated=false, maxT=500)
gamma_sims_df = DataFrame(gamma_sims)
Fit code:
num_subj = 10
dt_fit = DataFrame(id = 1:10, time = rand(Gamma(0.2, 10.), num_subj), event = float.(rand(Bernoulli(0.4), num_subj)))
pop4tte = read_pumas(dt_fit, observations = [:event], event_data=false)
gamma_params = (; scale1 = 0.15, shape1 = 10.2,)
gamma_fit = fit(gamma_model, pop4tte, gamma_params, Pumas.NaivePooled())
Fitting error:
julia> gamma_fit = fit(gamma_model, pop4tte, gamma_params, Pumas.NaivePooled())
[ Info: Checking the initial parameter values.
ERROR: MethodError: no method matching floatmax(::ForwardDiff.Dual{ForwardDiff.Tag{Pumas.Tag, Float64}, Float64, 2})
Closest candidates are:
floatmax() at /opt/julia-1.7.3/share/julia/base/float.jl:903
floatmax(::T) where T<:AbstractFloat at /opt/julia-1.7.3/share/julia/base/float.jl:900
floatmax(::Type{T}) where T<:FixedPointNumbers.FixedPoint at /build/_work/PumasSystemImages/PumasSystemImages/julia_depot/packages/FixedPointNumbers/HAGk2/src/FixedPointNumbers.jl:119
...
Stacktrace:
[1] En_cf_gamma(ν::ForwardDiff.Dual{ForwardDiff.Tag{Pumas.Tag, Float64}, Float64, 2}, z::ForwardDiff.Dual{ForwardDiff.Tag{Pumas.Tag, Float64}, Float64, 2}, n::Int64)
@ SpecialFunctions /build/_work/PumasSystemImages/PumasSystemImages/julia_depot/packages/SpecialFunctions/hefUc/src/expint.jl:215
[2] En_cf(ν::ForwardDiff.Dual{ForwardDiff.Tag{Pumas.Tag, Float64}, Float64, 2}, z::ForwardDiff.Dual{ForwardDiff.Tag{Pumas.Tag, Float64}, Float64, 2}, niter::Int64)
@ SpecialFunctions /build/_work/PumasSystemImages/PumasSystemImages/julia_depot/packages/SpecialFunctions/hefUc/src/expint.jl:248
[3] _expint(ν::ForwardDiff.Dual{ForwardDiff.Tag{Pumas.Tag, Float64}, Float64, 2}, z::ForwardDiff.Dual{ForwardDiff.Tag{Pumas.Tag, Float64}, Float64, 2}, niter::Int64, ::Val{false})
@ SpecialFunctions /build/_work/PumasSystemImages/PumasSystemImages/julia_depot/packages/SpecialFunctions/hefUc/src/expint.jl:437
[4] expint (repeats 2 times)
@ /build/_work/PumasSystemImages/PumasSystemImages/julia_depot/packages/SpecialFunctions/hefUc/src/expint.jl:516 [inlined]
[5] _gamma(a::ForwardDiff.Dual{ForwardDiff.Tag{Pumas.Tag, Float64}, Float64, 2}, x::ForwardDiff.Dual{ForwardDiff.Tag{Pumas.Tag, Float64}, Float64, 2})
@ SpecialFunctions
...
Right not, I think it might not be possible to fit such a model in Pumas. The problem is that the derivatives of the gamma pdf are incorrect
julia> using ForwardDiff
julia> using Distributions
julia> ForwardDiff.gradient(t -> pdf(Gamma(t[1], t[2]), t[3]), [3.1, 2.2, 0.0])
3-element Vector{Float64}:
NaN
NaN
NaN
julia> ForwardDiff.gradient(t -> pdf(Gamma(t[1], t[2]), t[3]), [3.1, 2.2, 1e-100])
3-element Vector{Float64}:
-9.163068198811177e-210
-5.56513941603919e-212
8.293852936161633e-112
and not yet supported at all for the cdf
julia> ForwardDiff.gradient(t -> cdf(Gamma(t[1], t[2]), t[3]), [3.1, 2.2, 1e-100])
ERROR: MethodError: no method matching _gamma_inc(::ForwardDiff.Dual{ForwardDiff.Tag{var"#19#20", Float64}, Float64, 3}, ::ForwardDiff.Dual{ForwardDiff.Tag{var"#19#20", Float64}, Float64, 3}, ::Int64)
Closest candidates are:
_gamma_inc(::Float64, ::Float64, ::Integer) at ~/.julia/packages/SpecialFunctions/hefUc/src/gamma_inc.jl:860
_gamma_inc(::BigFloat, ::BigFloat, ::Integer) at ~/.julia/packages/SpecialFunctions/hefUc/src/gamma_inc.jl:950
_gamma_inc(::Float32, ::Float32, ::Integer) at ~/.julia/packages/SpecialFunctions/hefUc/src/gamma_inc.jl:956
...
Stacktrace:
[1] gamma_inc(a::ForwardDiff.Dual{ForwardDiff.Tag{var"#19#20", Float64}, Float64, 3}, x::Float64, ind::Int64)
@ SpecialFunctions ~/.julia/packages/SpecialFunctions/hefUc/src/gamma_inc.jl:858
[2] gamma_inc(a::ForwardDiff.Dual{ForwardDiff.Tag{var"#19#20", Float64}, Float64, 3}, d::ForwardDiff.Dual{ForwardDiff.Tag{var"#19#20", Float64}, Float64, 3}, ind::Int64)
@ ForwardDiff ~/.julia/packages/ForwardDiff/QdStj/src/dual.jl:773
[3] gamma_inc(a::ForwardDiff.Dual{ForwardDiff.Tag{var"#19#20", Float64}, Float64, 3}, x::ForwardDiff.Dual{ForwardDiff.Tag{var"#19#20", Float64}, Float64, 3})
@ SpecialFunctions ~/.julia/packages/SpecialFunctions/hefUc/src/gamma_inc.jl:858
[4] gammacdf(k::ForwardDiff.Dual{ForwardDiff.Tag{var"#19#20", Float64}, Float64, 3}, θ::ForwardDiff.Dual{ForwardDiff.Tag{var"#19#20", Float64}, Float64, 3}, x::ForwardDiff.Dual{ForwardDiff.Tag{var"#19#20", Float64}, Float64, 3})
@ StatsFuns ~/.julia/packages/StatsFuns/beHKc/src/distrs/gamma.jl:34
[5] cdf
@ ~/.julia/packages/Distributions/bQ6Gj/src/univariates.jl:636 [inlined]
[6] #19
@ ./REPL[58]:1 [inlined]
[7] vector_mode_dual_eval!
@ ~/.julia/packages/ForwardDiff/QdStj/src/apiutils.jl:37 [inlined]
[8] vector_mode_gradient(f::var"#19#20", x::Vector{Float64}, cfg::ForwardDiff.GradientConfig{ForwardDiff.Tag{var"#19#20", Float64}, Float64, 3, Vector{ForwardDiff.Dual{ForwardDiff.Tag{var"#19#20", Float64}, Float64, 3}}})
@ ForwardDiff ~/.julia/packages/ForwardDiff/QdStj/src/gradient.jl:106
[9] gradient(f::Function, x::Vector{Float64}, cfg::ForwardDiff.GradientConfig{ForwardDiff.Tag{var"#19#20", Float64}, Float64, 3, Vector{ForwardDiff.Dual{ForwardDiff.Tag{var"#19#20", Float64}, Float64, 3}}}, ::Val{true})
@ ForwardDiff ~/.julia/packages/ForwardDiff/QdStj/src/gradient.jl:0
[10] gradient(f::Function, x::Vector{Float64}, cfg::ForwardDiff.GradientConfig{ForwardDiff.Tag{var"#19#20", Float64}, Float64, 3, Vector{ForwardDiff.Dual{ForwardDiff.Tag{var"#19#20", Float64}, Float64, 3}}}) (repeats 2 times)
@ ForwardDiff ~/.julia/packages/ForwardDiff/QdStj/src/gradient.jl:17
[11] top-level scope
@ REPL[58]:1
We are working adding support for computing these gradients but, meanwhile, you’ll probably have to try with other functional forms.