Fit the Continuous-Time Vector Autoregressive Model Using the dynr Package
Ivan Jacob Agaloos Pesigan
2025-01-18
Source:vignettes/fit-ct-var-dynr.Rmd
fit-ct-var-dynr.Rmd
Data Generation Using the SimSSMOUFixed
Function from
the simStateSpace
Package
n
#> [1] 50
time
#> [1] 100
delta_t
#> [1] 0.1
mu0
#> [1] 0 0 0
sigma0
#> [,1] [,2] [,3]
#> [1,] 1.0 0.2 0.2
#> [2,] 0.2 1.0 0.2
#> [3,] 0.2 0.2 1.0
sigma0_l # sigma0_l <- t(chol(sigma0))
#> [,1] [,2] [,3]
#> [1,] 1.0 0.0000000 0.0000000
#> [2,] 0.2 0.9797959 0.0000000
#> [3,] 0.2 0.1632993 0.9660918
mu
#> [1] 0 0 0
phi
#> [,1] [,2] [,3]
#> [1,] -0.357 0.000 0.000
#> [2,] 0.771 -0.511 0.000
#> [3,] -0.450 0.729 -0.693
sigma
#> [,1] [,2] [,3]
#> [1,] 0.24455556 0.02201587 -0.05004762
#> [2,] 0.02201587 0.07067800 0.01539456
#> [3,] -0.05004762 0.01539456 0.07553061
sigma_l # sigma_l <- t(chol(sigma))
#> [,1] [,2] [,3]
#> [1,] 0.49452559 0.0000000 0.000000
#> [2,] 0.04451917 0.2620993 0.000000
#> [3,] -0.10120330 0.0759256 0.243975
nu
#> [1] 0 0 0
lambda
#> [,1] [,2] [,3]
#> [1,] 1 0 0
#> [2,] 0 1 0
#> [3,] 0 0 1
theta
#> [,1] [,2] [,3]
#> [1,] 0.2 0.0 0.0
#> [2,] 0.0 0.2 0.0
#> [3,] 0.0 0.0 0.2
theta_l # theta_l <- t(chol(theta))
#> [,1] [,2] [,3]
#> [1,] 0.4472136 0.0000000 0.0000000
#> [2,] 0.0000000 0.4472136 0.0000000
#> [3,] 0.0000000 0.0000000 0.4472136
library(simStateSpace)
sim <- SimSSMOUFixed(
n = n,
time = time,
delta_t = delta_t,
mu0 = mu0,
sigma0_l = sigma0_l,
mu = mu,
phi = phi,
sigma_l = sigma_l,
nu = nu,
lambda = lambda,
theta_l = theta_l,
type = 0
)
data <- as.data.frame(sim)
colnames(data) <- c("id", "time", "x", "m", "y")
head(data)
#> id time x m y
#> 1 1 0.0 -0.3504435 0.41877429 2.611996
#> 2 1 0.1 -0.5920330 1.07433208 1.669272
#> 3 1 0.2 -0.7619855 1.21483834 2.369837
#> 4 1 0.3 -1.6964652 0.21209722 2.128531
#> 5 1 0.4 -1.2282686 0.09950326 1.891140
#> 6 1 0.5 0.1433985 0.66784226 2.036033
Model Fitting
We use the dynr
package to fit the continuous-time
vector autoregressive model.
Prepare the Initial Condition
dynr_initial <- prep.initial(
values.inistate = c(
0, 0, 0
),
params.inistate = c(
"mu0_1_1", "mu0_2_1", "mu0_3_1"
),
values.inicov = matrix(
data = c(
1.0, 0.2, 0.2,
0.2, 1.0, 0.2,
0.2, 0.2, 1.0
),
nrow = 3
),
params.inicov = matrix(
data = c(
"sigma0_1_1", "sigma0_2_1", "sigma0_3_1",
"sigma0_2_1", "sigma0_2_2", "sigma0_3_2",
"sigma0_3_1", "sigma0_3_2", "sigma0_3_3"
),
nrow = 3
)
)
Prepare the Measurement Model
dynr_measurement <- prep.measurement(
values.load = diag(3),
params.load = matrix(
data = "fixed",
nrow = 3,
ncol = 3
),
state.names = c("eta_x", "eta_m", "eta_y"),
obs.names = c("x", "m", "y")
)
Prepare the Dynamic Model
dynr_dynamics <- prep.formulaDynamics(
formula = list(
eta_x ~ phi_1_1 * eta_x + phi_1_2 * eta_m + phi_1_3 * eta_y,
eta_m ~ phi_2_1 * eta_x + phi_2_2 * eta_m + phi_2_3 * eta_y,
eta_y ~ phi_3_1 * eta_x + phi_3_2 * eta_m + phi_3_3 * eta_y
),
startval = c(
phi_1_1 = -0.2, phi_2_1 = 0.0, phi_3_1 = 0.0,
phi_1_2 = 0.0, phi_2_2 = -0.2, phi_3_2 = 0.0,
phi_1_3 = 0.0, phi_2_3 = 0.0, phi_3_3 = -0.2
),
isContinuousTime = TRUE
)
Prepare the Noise Matrices
dynr_noise <- prep.noise(
values.latent = matrix(
data = 0.2 * diag(3),
nrow = 3
),
params.latent = matrix(
data = c(
"sigma_1_1", "sigma_2_1", "sigma_3_1",
"sigma_2_1", "sigma_2_2", "sigma_3_2",
"sigma_3_1", "sigma_3_2", "sigma_3_3"
),
nrow = 3
),
values.observed = 0.2 * diag(3),
params.observed = matrix(
data = c(
"theta_1_1", "fixed", "fixed",
"fixed", "theta_2_2", "fixed",
"fixed", "fixed", "theta_3_3"
),
nrow = 3
)
)
Prepare the Model
In this example, we increase the maximum evaluations in the optimization process and constrain the lower and upper bounds of the parameters for the drift matrix.
dynr_model <- dynr.model(
data = dynr_data,
initial = dynr_initial,
measurement = dynr_measurement,
dynamics = dynr_dynamics,
noise = dynr_noise,
outfile = tempfile(
paste0(
"src-",
format(
Sys.time(),
"%Y-%m-%d-%H-%M-%OS3"
)
),
fileext = ".c"
)
)
dynr_model@options$maxeval <- 100000
lb <- ub <- rep(NA, times = length(dynr_model$xstart))
names(ub) <- names(lb) <- names(dynr_model$xstart)
lb[
c(
"phi_1_1", "phi_2_1", "phi_3_1",
"phi_1_2", "phi_2_2", "phi_3_2",
"phi_1_3", "phi_2_3", "phi_3_3"
)
] <- -1.5
ub[
c(
"phi_1_1", "phi_2_1", "phi_3_1",
"phi_1_2", "phi_2_2", "phi_3_2",
"phi_1_3", "phi_2_3", "phi_3_3"
)
] <- 1.5
dynr_model$lb <- lb
dynr_model$ub <- ub
Fit the Model
fit <- dynr.cook(
dynr_model,
verbose = FALSE
)
#> [1] "Get ready!!!!"
#> using C compiler: ‘gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0’
#> Optimization function called.
#> Starting Hessian calculation ...
#> Finished Hessian calculation.
#> Original exit flag: 3
#> Modified exit flag: 3
#> Optimization terminated successfully: ftol_rel or ftol_abs was reached.
#> Original fitted parameters: -0.2938068 0.8243958 -0.4543161 -0.07191554
#> -0.5689988 0.707647 0.02579061 0.08266777 -0.6875018 -1.444748 0.07916771
#> -0.2743246 -2.582169 0.1772108 -2.804538 -1.604288 -1.652135 -1.622277
#> -0.06854665 0.08457349 0.1157207 -0.05902917 0.1716259 0.1095353 0.379774
#> -0.08084045 -0.07765938
#>
#> Transformed fitted parameters: -0.2938068 0.8243958 -0.4543161 -0.07191554
#> -0.5689988 0.707647 0.02579061 0.08266777 -0.6875018 0.2358056 0.01866819
#> -0.06468727 0.07708775 0.008277734 0.08065449 0.2010327 0.1916402 0.1974485
#> -0.06854665 0.08457349 0.1157207 0.9426793 0.1617881 0.1032567 1.489721
#> -0.1004635 0.9461439
#>
#> Doing end processing
#> Successful trial
#> Total Time: 6.042105
#> Backend Time: 6.031054
summary(fit)
#> Coefficients:
#> Estimate Std. Error t value ci.lower ci.upper Pr(>|t|)
#> phi_1_1 -0.293807 0.082574 -3.558 -0.455648 -0.131966 0.0002 ***
#> phi_2_1 0.824396 0.056914 14.485 0.712846 0.935946 <2e-16 ***
#> phi_3_1 -0.454316 0.057647 -7.881 -0.567303 -0.341329 <2e-16 ***
#> phi_1_2 -0.071916 0.068787 -1.045 -0.206735 0.062904 0.1479
#> phi_2_2 -0.568999 0.048532 -11.724 -0.664119 -0.473878 <2e-16 ***
#> phi_3_2 0.707647 0.048636 14.550 0.612322 0.802972 <2e-16 ***
#> phi_1_3 0.025791 0.062589 0.412 -0.096882 0.148463 0.3402
#> phi_2_3 0.082668 0.043529 1.899 -0.002647 0.167983 0.0288 *
#> phi_3_3 -0.687502 0.044092 -15.593 -0.773920 -0.601084 <2e-16 ***
#> sigma_1_1 0.235806 0.022759 10.361 0.191198 0.280413 <2e-16 ***
#> sigma_2_1 0.018668 0.010045 1.858 -0.001020 0.038356 0.0316 *
#> sigma_3_1 -0.064687 0.010768 -6.007 -0.085793 -0.043582 <2e-16 ***
#> sigma_2_2 0.077088 0.009447 8.160 0.058572 0.095603 <2e-16 ***
#> sigma_3_2 0.008278 0.006655 1.244 -0.004765 0.021321 0.1068
#> sigma_3_3 0.080654 0.010196 7.910 0.060670 0.100639 <2e-16 ***
#> theta_1_1 0.201033 0.005107 39.363 0.191023 0.211043 <2e-16 ***
#> theta_2_2 0.191640 0.004373 43.823 0.183069 0.200211 <2e-16 ***
#> theta_3_3 0.197449 0.004521 43.677 0.188588 0.206309 <2e-16 ***
#> mu0_1_1 -0.068547 0.142210 -0.482 -0.347273 0.210180 0.3149
#> mu0_2_1 0.084573 0.176685 0.479 -0.261722 0.430869 0.3161
#> mu0_3_1 0.115721 0.141485 0.818 -0.161585 0.393026 0.2067
#> sigma0_1_1 0.942679 0.205369 4.590 0.540164 1.345195 <2e-16 ***
#> sigma0_2_1 0.161788 0.179880 0.899 -0.190769 0.514346 0.1842
#> sigma0_3_1 0.103257 0.143856 0.718 -0.178696 0.385209 0.2365
#> sigma0_2_2 1.489721 0.311204 4.787 0.879772 2.099670 <2e-16 ***
#> sigma0_3_2 -0.100464 0.178078 -0.564 -0.449491 0.248563 0.2863
#> sigma0_3_3 0.946144 0.204219 4.633 0.545882 1.346406 <2e-16 ***
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#>
#> -2 log-likelihood value at convergence = 21626.57
#> AIC = 21680.57
#> BIC = 21856.53
coefs <- coef(fit)
vcovs <- vcov(fit)
Extract Matrices from the Fitted Model to use in cTMed
phi_names <- c(
"phi_1_1", "phi_2_1", "phi_3_1",
"phi_1_2", "phi_2_2", "phi_3_2",
"phi_1_3", "phi_2_3", "phi_3_3"
)
sigma_names <- c(
"sigma_1_1", "sigma_2_1", "sigma_3_1",
"sigma_2_1", "sigma_2_2", "sigma_3_2",
"sigma_3_1", "sigma_3_2", "sigma_3_3"
)
sigma_vech_names <- c(
"sigma_1_1", "sigma_2_1", "sigma_3_1",
"sigma_2_2", "sigma_3_2",
"sigma_3_3"
)
theta_names <- c(
"phi_1_1", "phi_2_1", "phi_3_1",
"phi_1_2", "phi_2_2", "phi_3_2",
"phi_1_3", "phi_2_3", "phi_3_3",
"sigma_1_1", "sigma_2_1", "sigma_3_1",
"sigma_2_2", "sigma_3_2",
"sigma_3_3"
)
phi <- matrix(
data = coefs[phi_names],
nrow = 3,
ncol = 3
)
sigma <- matrix(
data = coefs[sigma_names],
nrow = 3,
ncol = 3
)
theta <- coefs[theta_names]
vcov_phi_vec <- vcovs[phi_names, phi_names]
vcov_sigma_vech <- vcovs[sigma_vech_names, sigma_vech_names]
vcov_theta <- vcovs[theta_names, theta_names]
Estimated Drift Matrix with Corresponding Sampling Covariance Matrix
phi
#> [,1] [,2] [,3]
#> [1,] -0.2938068 -0.07191554 0.02579061
#> [2,] 0.8243958 -0.56899879 0.08266777
#> [3,] -0.4543161 0.70764697 -0.68750180
vcov_phi_vec
#> phi_1_1 phi_2_1 phi_3_1 phi_1_2 phi_2_2
#> phi_1_1 0.0068183887 3.328110e-04 -0.0014352362 -0.0049087319 -2.786146e-04
#> phi_2_1 0.0003328110 3.239243e-03 -0.0001186669 -0.0001298602 -2.425089e-03
#> phi_3_1 -0.0014352362 -1.186669e-04 0.0033232239 0.0009753620 1.079346e-04
#> phi_1_2 -0.0049087319 -1.298602e-04 0.0009753620 0.0047316027 1.927033e-04
#> phi_2_2 -0.0002786146 -2.425089e-03 0.0001079346 0.0001927033 2.355321e-03
#> phi_3_2 0.0010343753 3.893230e-05 -0.0024481377 -0.0009945998 -8.261422e-05
#> phi_1_3 0.0033608473 4.732055e-05 -0.0006083507 -0.0034296101 -8.603025e-05
#> phi_2_3 0.0002256333 1.691774e-03 -0.0001006453 -0.0001924514 -1.731951e-03
#> phi_3_3 -0.0007319213 -7.091233e-06 0.0016871746 0.0007482711 3.091309e-05
#> phi_3_2 phi_1_3 phi_2_3 phi_3_3
#> phi_1_1 1.034375e-03 3.360847e-03 2.256333e-04 -7.319213e-04
#> phi_2_1 3.893230e-05 4.732055e-05 1.691774e-03 -7.091233e-06
#> phi_3_1 -2.448138e-03 -6.083507e-04 -1.006453e-04 1.687175e-03
#> phi_1_2 -9.945998e-04 -3.429610e-03 -1.924514e-04 7.482711e-04
#> phi_2_2 -8.261422e-05 -8.603025e-05 -1.731951e-03 3.091309e-05
#> phi_3_2 2.365471e-03 6.672321e-04 1.034336e-04 -1.733689e-03
#> phi_1_3 6.672321e-04 3.917403e-03 1.804875e-04 -8.681116e-04
#> phi_2_3 1.034336e-04 1.804875e-04 1.894760e-03 -9.774066e-05
#> phi_3_3 -1.733689e-03 -8.681116e-04 -9.774066e-05 1.944073e-03
Process Noise Covariance Matrix with Corresponding Sampling Covariance Matrix
sigma
#> [,1] [,2] [,3]
#> [1,] 0.23580555 0.018668186 -0.064687273
#> [2,] 0.01866819 0.077087752 0.008277734
#> [3,] -0.06468727 0.008277734 0.080654489
vcov_sigma_vech
#> sigma_1_1 sigma_2_1 sigma_3_1 sigma_2_2 sigma_3_2
#> sigma_1_1 5.179936e-04 1.286404e-05 -9.425124e-05 9.869593e-07 -5.327209e-06
#> sigma_2_1 1.286404e-05 1.009005e-04 -3.493273e-06 4.327901e-06 -2.213247e-05
#> sigma_3_1 -9.425124e-05 -3.493273e-06 1.159554e-04 -4.600131e-07 3.190146e-06
#> sigma_2_2 9.869593e-07 4.327901e-06 -4.600131e-07 8.924541e-05 -2.785630e-06
#> sigma_3_2 -5.327209e-06 -2.213247e-05 3.190146e-06 -2.785630e-06 4.428372e-05
#> sigma_3_3 1.933227e-05 1.524740e-06 -4.759391e-05 -1.091407e-07 -2.565877e-06
#> sigma_3_3
#> sigma_1_1 1.933227e-05
#> sigma_2_1 1.524740e-06
#> sigma_3_1 -4.759391e-05
#> sigma_2_2 -1.091407e-07
#> sigma_3_2 -2.565877e-06
#> sigma_3_3 1.039638e-04
Estimated Drift Matrix and Process Noise Covariance Matrix with Corresponding Sampling Covariance Matrix
theta
#> phi_1_1 phi_2_1 phi_3_1 phi_1_2 phi_2_2 phi_3_2
#> -0.293806753 0.824395779 -0.454316070 -0.071915544 -0.568998789 0.707646969
#> phi_1_3 phi_2_3 phi_3_3 sigma_1_1 sigma_2_1 sigma_3_1
#> 0.025790607 0.082667770 -0.687501801 0.235805550 0.018668186 -0.064687273
#> sigma_2_2 sigma_3_2 sigma_3_3
#> 0.077087752 0.008277734 0.080654489
vcov_theta
#> phi_1_1 phi_2_1 phi_3_1 phi_1_2 phi_2_2
#> phi_1_1 6.818389e-03 3.328110e-04 -1.435236e-03 -4.908732e-03 -2.786146e-04
#> phi_2_1 3.328110e-04 3.239243e-03 -1.186669e-04 -1.298602e-04 -2.425089e-03
#> phi_3_1 -1.435236e-03 -1.186669e-04 3.323224e-03 9.753620e-04 1.079346e-04
#> phi_1_2 -4.908732e-03 -1.298602e-04 9.753620e-04 4.731603e-03 1.927033e-04
#> phi_2_2 -2.786146e-04 -2.425089e-03 1.079346e-04 1.927033e-04 2.355321e-03
#> phi_3_2 1.034375e-03 3.893230e-05 -2.448138e-03 -9.945998e-04 -8.261422e-05
#> phi_1_3 3.360847e-03 4.732055e-05 -6.083507e-04 -3.429610e-03 -8.603025e-05
#> phi_2_3 2.256333e-04 1.691774e-03 -1.006453e-04 -1.924514e-04 -1.731951e-03
#> phi_3_3 -7.319213e-04 -7.091233e-06 1.687175e-03 7.482711e-04 3.091309e-05
#> sigma_1_1 -1.106468e-03 -1.398287e-04 2.517698e-04 6.261763e-04 8.119764e-05
#> sigma_2_1 1.010203e-04 -2.425122e-04 -3.718890e-05 -1.273680e-04 1.291759e-04
#> sigma_3_1 1.334626e-04 2.947566e-05 -2.751090e-04 -3.525638e-05 -1.042500e-05
#> sigma_2_2 -4.057314e-06 1.151342e-04 1.195059e-05 5.574693e-06 -1.403873e-04
#> sigma_3_2 -5.525374e-06 2.791248e-05 5.403340e-05 1.195423e-05 8.511003e-06
#> sigma_3_3 -2.843026e-05 -1.384687e-05 5.809073e-05 7.685408e-06 5.321714e-06
#> phi_3_2 phi_1_3 phi_2_3 phi_3_3 sigma_1_1
#> phi_1_1 1.034375e-03 3.360847e-03 2.256333e-04 -7.319213e-04 -1.106468e-03
#> phi_2_1 3.893230e-05 4.732055e-05 1.691774e-03 -7.091233e-06 -1.398287e-04
#> phi_3_1 -2.448138e-03 -6.083507e-04 -1.006453e-04 1.687175e-03 2.517698e-04
#> phi_1_2 -9.945998e-04 -3.429610e-03 -1.924514e-04 7.482711e-04 6.261763e-04
#> phi_2_2 -8.261422e-05 -8.603025e-05 -1.731951e-03 3.091309e-05 8.119764e-05
#> phi_3_2 2.365471e-03 6.672321e-04 1.034336e-04 -1.733689e-03 -1.438765e-04
#> phi_1_3 6.672321e-04 3.917403e-03 1.804875e-04 -8.681116e-04 -2.973809e-04
#> phi_2_3 1.034336e-04 1.804875e-04 1.894760e-03 -9.774066e-05 -4.129221e-05
#> phi_3_3 -1.733689e-03 -8.681116e-04 -9.774066e-05 1.944073e-03 7.127045e-05
#> sigma_1_1 -1.438765e-04 -2.973809e-04 -4.129221e-05 7.127045e-05 5.179936e-04
#> sigma_2_1 3.881781e-05 7.657799e-05 -5.873909e-05 -2.257847e-05 1.286404e-05
#> sigma_3_1 1.436551e-04 -6.840144e-05 -7.334321e-06 -4.241756e-05 -9.425124e-05
#> sigma_2_2 -1.299325e-05 -3.273776e-06 8.554974e-05 8.082729e-06 9.869593e-07
#> sigma_3_2 -6.474756e-05 -4.432167e-06 -4.542482e-05 3.582377e-05 -5.327209e-06
#> sigma_3_3 1.565448e-05 2.001541e-05 5.982094e-06 -1.016672e-04 1.933227e-05
#> sigma_2_1 sigma_3_1 sigma_2_2 sigma_3_2 sigma_3_3
#> phi_1_1 1.010203e-04 1.334626e-04 -4.057314e-06 -5.525374e-06 -2.843026e-05
#> phi_2_1 -2.425122e-04 2.947566e-05 1.151342e-04 2.791248e-05 -1.384687e-05
#> phi_3_1 -3.718890e-05 -2.751090e-04 1.195059e-05 5.403340e-05 5.809073e-05
#> phi_1_2 -1.273680e-04 -3.525638e-05 5.574693e-06 1.195423e-05 7.685408e-06
#> phi_2_2 1.291759e-04 -1.042500e-05 -1.403873e-04 8.511003e-06 5.321714e-06
#> phi_3_2 3.881781e-05 1.436551e-04 -1.299325e-05 -6.474756e-05 1.565448e-05
#> phi_1_3 7.657799e-05 -6.840144e-05 -3.273776e-06 -4.432167e-06 2.001541e-05
#> phi_2_3 -5.873909e-05 -7.334321e-06 8.554974e-05 -4.542482e-05 5.982094e-06
#> phi_3_3 -2.257847e-05 -4.241756e-05 8.082729e-06 3.582377e-05 -1.016672e-04
#> sigma_1_1 1.286404e-05 -9.425124e-05 9.869593e-07 -5.327209e-06 1.933227e-05
#> sigma_2_1 1.009005e-04 -3.493273e-06 4.327901e-06 -2.213247e-05 1.524740e-06
#> sigma_3_1 -3.493273e-06 1.159554e-04 -4.600131e-07 3.190146e-06 -4.759391e-05
#> sigma_2_2 4.327901e-06 -4.600131e-07 8.924541e-05 -2.785630e-06 -1.091407e-07
#> sigma_3_2 -2.213247e-05 3.190146e-06 -2.785630e-06 4.428372e-05 -2.565877e-06
#> sigma_3_3 1.524740e-06 -4.759391e-05 -1.091407e-07 -2.565877e-06 1.039638e-04
References
Ou, L., Hunter, M. D., & Chow, S.-M. (2019). What’s for dynr: A package for linear and nonlinear dynamic
modeling in R. The R Journal, 11(1), 91.
https://doi.org/10.32614/rj-2019-012
R Core Team. (2024). R: A language and environment for
statistical computing. R Foundation for Statistical Computing. https://www.R-project.org/