Estimating Parameters using SAEM
PumasEMModels can optionally be fitted using SAEM. Here is an example PumasEMModel definition:
using Pumas
using PumasUtilities
using Random
covariate_saem_cov = @emmodel begin
@random begin
CL ~ 1 + logwt | LogNormal
v ~ 1 | LogNormal
end
@covariance 2
@covariates wt
@pre begin
Vc = wt * v
end
@dynamics Central1
@post begin
cp = Central / Vc
end
@error begin
dv ~ ProportionalNormal(cp)
end
endPumasEMModel
Parameters with random effects:
CL ~ (1, :logwt) | LogNormal
v ~ (1,) | LogNormal
Covariates: wt
Pre-dynamical variables: Vc
Dynamical system variables: Central
Post-dynamical variables: cpSee the documentation on the @emmodel macro interface for an explanation of the syntax. To fit this model, we'll simulate data using simobs.
sim_params_covariate_cov = (;
CL = (4.0, 0.75),
v = 70.0,
Ω = (Pumas.@SMatrix([0.1 0.05; 0.05 0.1]),),
σ = ((0.2,),),
)
obstimes = 0.0:100.0
dose = DosageRegimen(1_000; addl = 2, ii = 24)
function choose_covariates()
wt = (55 + 25rand()) / 70
return (; wt, logwt = log(wt))
end
pop = [Subject(; id = i, events = dose, covariates = choose_covariates()) for i = 1:72]
sims = simobs(
covariate_saem_cov,
pop,
sim_params_covariate_cov;
obstimes,
ensemblealg = EnsembleSerial(),
)
reread_df = DataFrame(sims);
pop_covariate = read_pumas(reread_df; observations = [:dv], covariates = [:logwt, :wt])Population
Subjects: 72
Covariates: logwt, wt
Observations: dvWhen specifying inits, it is not necessary to specify any variance parameters for the random effects or error models.
init_covariate = (; CL = (2.0, 2 / 3), v = 50.0)(CL = (2.0, 0.6666666666666666), v = 50.0)If unspecified, they will be initialized to 1.0 or the identity matrix for covariances. SAEM's stochastic exploration phase is most effective when these variance parameters are much larger than the true variances. Thus, if the true variances are believed to be around 1.0 or larger, it is recommended to specify larger initial values manually.
It is possible to pass a vector of random number generates as an argument to fit. If so, the fit will use one thread per RNG. By specifying the seeds of each RNG, SAEM() can be fully reproducible:
rngv = [MersenneTwister(1941964947i + 1) for i ∈ 1:Threads.nthreads()];
fit_covariate_cov1 = fit(
covariate_saem_cov,
pop_covariate,
init_covariate,
SAEM();
ensemblealg = EnsembleThreads(),
rng = rngv,
)rngv = [MersenneTwister(1941964947i + 1) for i ∈ 1:Threads.nthreads()];
fit_covariate_cov2 = fit(
covariate_saem_cov,
pop_covariate,
init_covariate,
SAEM();
ensemblealg = EnsembleThreads(),
rng = rngv,
)coef(fit_covariate_cov1) == coef(fit_covariate_cov2) # truetrueOne can also specify the number of iterations for each of the three phases (rapid exploration, convergence, smoothing):
fit_covariate_cov =
fit(covariate_saem_cov, pop_covariate, init_covariate, SAEM(; iters = (1000, 500, 500)))FittedPumasEMModel
Dynamical system type: Closed form
Number of subjects: 72
Observation records: Active Missing
dv: 7272 0
Total: 7272 0
Number of parameters: Constant Optimized
0 7
Estimation method: SAEM
-------------------
Estimate
-------------------
CL₁ 3.9022
CL₂ 0.90284
v 69.388
Ω₁,₁ 0.092099
Ω₂,₁ 0.051034
Ω₂,₂ 0.10231
σ 0.19826
-------------------The results of a fit can be analyzed normally:
infer_cov = infer(fit_covariate_cov)Asymptotic inference results using sandwich estimator
Dynamical system type: Closed form
Number of subjects: 72
Observation records: Active Missing
dv: 7272 0
Total: 7272 0
Number of parameters: Constant Optimized
0 7
Estimation method: SAEM
--------------------------------------------------------
Estimate SE 95.0% C.I.
--------------------------------------------------------
CL_base 3.9022 0.15064 [ 3.607 ; 4.1975 ]
CL_logwt 0.90284 0.33181 [ 0.2525 ; 1.5532 ]
v_base 69.388 2.6254 [ 64.242 ; 74.534 ]
ω_1₁,₁ 0.30348 0.022222 [ 0.25992; 0.34703]
ω_1₂,₁ 0.16816 0.032414 [ 0.10463; 0.23169]
ω_1₂,₂ 0.27209 0.024323 [ 0.22442; 0.31976]
σ_0 0.19826 0.0017514 [ 0.19483; 0.20169]
--------------------------------------------------------coeftable(infer_cov)| Row | parameter | description | constant | estimate | se | relative_se | ci_lower | ci_upper |
|---|---|---|---|---|---|---|---|---|
| String | String | Bool | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | CL_base | CL_base | false | 3.90225 | 0.150644 | 0.0386045 | 3.60699 | 4.1975 |
| 2 | CL_logwt | CL_logwt | false | 0.902838 | 0.331812 | 0.367521 | 0.252499 | 1.55318 |
| 3 | v_base | v_base | false | 69.388 | 2.62536 | 0.0378359 | 64.2424 | 74.5336 |
| 4 | ω_1₁,₁ | ω_1₁,₁ | false | 0.303479 | 0.0222225 | 0.0732257 | 0.259924 | 0.347034 |
| 5 | ω_1₂,₁ | ω_1₂,₁ | false | 0.168162 | 0.0324144 | 0.192757 | 0.104631 | 0.231693 |
| 6 | ω_1₂,₂ | ω_1₂,₂ | false | 0.272091 | 0.0243232 | 0.0893934 | 0.224419 | 0.319764 |
| 7 | σ_0 | σ_0 | false | 0.198259 | 0.00175141 | 0.00883398 | 0.194826 | 0.201691 |
inspect_cov = inspect(fit_covariate_cov)[ Info: Calculating predictions.
[ Info: Calculating weighted residuals.
[ Info: Calculating empirical bayes.
[ Info: Evaluating dose control parameters.
[ Info: Evaluating individual parameters.
[ Info: Done.SAEM does not compute a likelihood while fitting, so quantities derived from one have to be given the approximation to use:
loglikelihood(fit_covariate_cov, FOCE())
lrtest(fit_reduced, fit_full, FOCE())Calling them without an approximation is deprecated, and falls back to LaplaceI. The same applies indirectly to the information criteria aic and bic, which are computed from the log-likelihood and take no approximation argument, so for a fit obtained with SAEM they report LaplaceI values.