Fit the Continuous-Time Vector Autoregressive Model Using the dynr Package
Ivan Jacob Agaloos Pesigan
2025-02-21
Source:vignettes/fit-ct-var-dynr.Rmd
fit-ct-var-dynr.Rmd
Data Generation Using the SimSSMOUFixed
Function from
the simStateSpace
Package
n
#> [1] 100
time
#> [1] 1000
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.3518368 0.7442809 -0.4586826 0.01729864
#> -0.4888158 0.726799 -0.02382471 -0.00979981 -0.6883465 -1.418096 0.096098
#> -0.2088241 -2.681141 0.2898495 -2.881284 -1.615145 -1.611841 -1.603598
#> 0.006364943 -0.04257927 0.1301567 0.1400115 0.3596348 0.1963933 0.07053978
#> 0.1436827 -0.1098101
#>
#> Transformed fitted parameters: -0.3518368 0.7442809 -0.4586826 0.01729864
#> -0.4888158 0.726799 -0.02382471 -0.00979981 -0.6883465 0.2421747 0.0232725
#> -0.05057192 0.0707214 0.01499047 0.07237695 0.1988618 0.1995199 0.2011713
#> 0.006364943 -0.04257927 0.1301567 1.150287 0.4136832 0.2259086 1.221862
#> 0.2354286 0.9625248
#>
#> Doing end processing
#> Successful trial
#> Total Time: 2.68385
#> Backend Time: 2.68365
summary(fit)
#> Coefficients:
#> Estimate Std. Error t value ci.lower ci.upper Pr(>|t|)
#> phi_1_1 -0.351837 0.040477 -8.692 -0.431170 -0.272503 <2e-16 ***
#> phi_2_1 0.744281 0.022684 32.810 0.699821 0.788741 <2e-16 ***
#> phi_3_1 -0.458683 0.023307 -19.680 -0.504364 -0.413001 <2e-16 ***
#> phi_1_2 0.017299 0.035160 0.492 -0.051614 0.086211 0.3114
#> phi_2_2 -0.488816 0.019999 -24.442 -0.528013 -0.449619 <2e-16 ***
#> phi_3_2 0.726799 0.020673 35.157 0.686280 0.767318 <2e-16 ***
#> phi_1_3 -0.023825 0.026208 -0.909 -0.075191 0.027542 0.1817
#> phi_2_3 -0.009800 0.015134 -0.648 -0.039463 0.019863 0.2586
#> phi_3_3 -0.688346 0.015868 -43.379 -0.719448 -0.657245 <2e-16 ***
#> sigma_1_1 0.242175 0.007291 33.216 0.227885 0.256465 <2e-16 ***
#> sigma_2_1 0.023273 0.002647 8.792 0.018084 0.028461 <2e-16 ***
#> sigma_3_1 -0.050572 0.002740 -18.459 -0.055941 -0.045202 <2e-16 ***
#> sigma_2_2 0.070721 0.001916 36.921 0.066967 0.074476 <2e-16 ***
#> sigma_3_2 0.014990 0.001380 10.865 0.012286 0.017695 <2e-16 ***
#> sigma_3_3 0.072377 0.002106 34.361 0.068249 0.076505 <2e-16 ***
#> theta_1_1 0.198862 0.001189 167.270 0.196532 0.201192 <2e-16 ***
#> theta_2_2 0.199520 0.001001 199.355 0.197558 0.201481 <2e-16 ***
#> theta_3_3 0.201171 0.001017 197.798 0.199178 0.203165 <2e-16 ***
#> mu0_1_1 0.006365 0.118695 0.054 -0.226274 0.239004 0.4786
#> mu0_2_1 -0.042579 0.113165 -0.376 -0.264378 0.179220 0.3534
#> mu0_3_1 0.130157 0.102344 1.272 -0.070434 0.330747 0.1017
#> sigma0_1_1 1.150287 0.205378 5.601 0.747754 1.552820 <2e-16 ***
#> sigma0_2_1 0.413683 0.134865 3.067 0.149352 0.678015 0.0011 **
#> sigma0_3_1 0.225909 0.118800 1.902 -0.006935 0.458753 0.0286 *
#> sigma0_2_2 1.221862 0.198459 6.157 0.832890 1.610835 <2e-16 ***
#> sigma0_3_2 0.235429 0.125869 1.870 -0.011271 0.482128 0.0307 *
#> sigma0_3_3 0.962525 0.150708 6.387 0.667142 1.257908 <2e-16 ***
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#>
#> -2 log-likelihood value at convergence = 429365.49
#> AIC = 429419.49
#> BIC = 429676.34
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.3518368 0.01729864 -0.02382471
#> [2,] 0.7442809 -0.48881584 -0.00979981
#> [3,] -0.4586826 0.72679902 -0.68834647
vcov_phi_vec
#> phi_1_1 phi_2_1 phi_3_1 phi_1_2 phi_2_2
#> phi_1_1 1.638395e-03 4.205720e-05 -2.365513e-04 -1.376185e-03 -4.400313e-05
#> phi_2_1 4.205720e-05 5.145749e-04 1.901381e-05 -2.143907e-05 -4.359631e-04
#> phi_3_1 -2.365513e-04 1.901381e-05 5.432299e-04 1.936645e-04 -9.386709e-06
#> phi_1_2 -1.376185e-03 -2.143907e-05 1.936645e-04 1.236241e-03 3.126359e-05
#> phi_2_2 -4.400313e-05 -4.359631e-04 -9.386709e-06 3.126359e-05 3.999593e-04
#> phi_3_2 2.074921e-04 -2.517298e-05 -4.623548e-04 -1.848726e-04 1.576373e-05
#> phi_1_3 9.257184e-04 8.251254e-06 -1.204207e-04 -8.555641e-04 -1.597444e-05
#> phi_2_3 3.762530e-05 2.928343e-04 7.109899e-07 -3.090243e-05 -2.783699e-04
#> phi_3_3 -1.487146e-04 2.380476e-05 3.133472e-04 1.369958e-04 -1.775455e-05
#> phi_3_2 phi_1_3 phi_2_3 phi_3_3
#> phi_1_1 2.074921e-04 9.257184e-04 3.762530e-05 -1.487146e-04
#> phi_2_1 -2.517298e-05 8.251254e-06 2.928343e-04 2.380476e-05
#> phi_3_1 -4.623548e-04 -1.204207e-04 7.109899e-07 3.133472e-04
#> phi_1_2 -1.848726e-04 -8.555641e-04 -3.090243e-05 1.369958e-04
#> phi_2_2 1.576373e-05 -1.597444e-05 -2.783699e-04 -1.775455e-05
#> phi_3_2 4.273789e-04 1.199960e-04 -4.260080e-06 -3.007907e-04
#> phi_1_3 1.199960e-04 6.868542e-04 2.386256e-05 -1.071758e-04
#> phi_2_3 -4.260080e-06 2.386256e-05 2.290520e-04 8.181839e-06
#> phi_3_3 -3.007907e-04 -1.071758e-04 8.181839e-06 2.518045e-04
Process Noise Covariance Matrix with Corresponding Sampling Covariance Matrix
sigma
#> [,1] [,2] [,3]
#> [1,] 0.24217468 0.02327250 -0.05057192
#> [2,] 0.02327250 0.07072140 0.01499047
#> [3,] -0.05057192 0.01499047 0.07237695
vcov_sigma_vech
#> sigma_1_1 sigma_2_1 sigma_3_1 sigma_2_2 sigma_3_2
#> sigma_1_1 5.315788e-05 -1.473938e-06 -5.848017e-06 4.039293e-07 -2.565611e-08
#> sigma_2_1 -1.473938e-06 7.006599e-06 1.438703e-07 -6.227217e-07 -9.558368e-07
#> sigma_3_1 -5.848017e-06 1.438703e-07 7.505554e-06 7.860849e-09 -2.941660e-07
#> sigma_2_2 4.039293e-07 -6.227217e-07 7.860849e-09 3.669146e-06 6.984348e-08
#> sigma_3_2 -2.565611e-08 -9.558368e-07 -2.941660e-07 6.984348e-08 1.903497e-06
#> sigma_3_3 7.654383e-07 2.524688e-08 -2.011280e-06 -4.218391e-08 5.149938e-08
#> sigma_3_3
#> sigma_1_1 7.654383e-07
#> sigma_2_1 2.524688e-08
#> sigma_3_1 -2.011280e-06
#> sigma_2_2 -4.218391e-08
#> sigma_3_2 5.149938e-08
#> sigma_3_3 4.436798e-06
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.35183681 0.74428086 -0.45868259 0.01729864 -0.48881584 0.72679902
#> phi_1_3 phi_2_3 phi_3_3 sigma_1_1 sigma_2_1 sigma_3_1
#> -0.02382471 -0.00979981 -0.68834647 0.24217468 0.02327250 -0.05057192
#> sigma_2_2 sigma_3_2 sigma_3_3
#> 0.07072140 0.01499047 0.07237695
vcov_theta
#> phi_1_1 phi_2_1 phi_3_1 phi_1_2 phi_2_2
#> phi_1_1 1.638395e-03 4.205720e-05 -2.365513e-04 -1.376185e-03 -4.400313e-05
#> phi_2_1 4.205720e-05 5.145749e-04 1.901381e-05 -2.143907e-05 -4.359631e-04
#> phi_3_1 -2.365513e-04 1.901381e-05 5.432299e-04 1.936645e-04 -9.386709e-06
#> phi_1_2 -1.376185e-03 -2.143907e-05 1.936645e-04 1.236241e-03 3.126359e-05
#> phi_2_2 -4.400313e-05 -4.359631e-04 -9.386709e-06 3.126359e-05 3.999593e-04
#> phi_3_2 2.074921e-04 -2.517298e-05 -4.623548e-04 -1.848726e-04 1.576373e-05
#> phi_1_3 9.257184e-04 8.251254e-06 -1.204207e-04 -8.555641e-04 -1.597444e-05
#> phi_2_3 3.762530e-05 2.928343e-04 7.109899e-07 -3.090243e-05 -2.783699e-04
#> phi_3_3 -1.487146e-04 2.380476e-05 3.133472e-04 1.369958e-04 -1.775455e-05
#> sigma_1_1 -2.442013e-04 -1.579694e-05 3.757720e-05 1.933901e-04 1.302756e-05
#> sigma_2_1 2.297497e-05 -3.896357e-05 -7.962854e-06 -2.294436e-05 2.962651e-05
#> sigma_3_1 1.863072e-05 3.619382e-06 -4.198918e-05 -1.170724e-05 -2.840243e-06
#> sigma_2_2 -3.578211e-06 1.541868e-05 2.332149e-06 3.281239e-06 -1.545537e-05
#> sigma_3_2 -1.431835e-06 1.927127e-06 8.322808e-06 1.615242e-06 1.176296e-07
#> sigma_3_3 -2.203611e-06 -1.270215e-06 4.429654e-06 1.092348e-06 8.732957e-07
#> phi_3_2 phi_1_3 phi_2_3 phi_3_3 sigma_1_1
#> phi_1_1 2.074921e-04 9.257184e-04 3.762530e-05 -1.487146e-04 -2.442013e-04
#> phi_2_1 -2.517298e-05 8.251254e-06 2.928343e-04 2.380476e-05 -1.579694e-05
#> phi_3_1 -4.623548e-04 -1.204207e-04 7.109899e-07 3.133472e-04 3.757720e-05
#> phi_1_2 -1.848726e-04 -8.555641e-04 -3.090243e-05 1.369958e-04 1.933901e-04
#> phi_2_2 1.576373e-05 -1.597444e-05 -2.783699e-04 -1.775455e-05 1.302756e-05
#> phi_3_2 4.273789e-04 1.199960e-04 -4.260080e-06 -3.007907e-04 -3.085525e-05
#> phi_1_3 1.199960e-04 6.868542e-04 2.386256e-05 -1.071758e-04 -1.210257e-04
#> phi_2_3 -4.260080e-06 2.386256e-05 2.290520e-04 8.181839e-06 -8.695992e-06
#> phi_3_3 -3.007907e-04 -1.071758e-04 8.181839e-06 2.518045e-04 2.042787e-05
#> sigma_1_1 -3.085525e-05 -1.210257e-04 -8.695992e-06 2.042787e-05 5.315788e-05
#> sigma_2_1 7.563860e-06 1.524066e-05 -1.770462e-05 -5.242933e-06 -1.473938e-06
#> sigma_3_1 3.205242e-05 1.735962e-06 1.379332e-06 -1.843388e-05 -5.848017e-06
#> sigma_2_2 -2.613218e-06 -2.319797e-06 9.763319e-06 1.906244e-06 4.039293e-07
#> sigma_3_2 -8.237631e-06 -9.189074e-07 -2.405728e-06 4.981899e-06 -2.565611e-08
#> sigma_3_3 -2.240050e-07 5.646350e-07 -1.197923e-07 -5.157492e-06 7.654383e-07
#> sigma_2_1 sigma_3_1 sigma_2_2 sigma_3_2 sigma_3_3
#> phi_1_1 2.297497e-05 1.863072e-05 -3.578211e-06 -1.431835e-06 -2.203611e-06
#> phi_2_1 -3.896357e-05 3.619382e-06 1.541868e-05 1.927127e-06 -1.270215e-06
#> phi_3_1 -7.962854e-06 -4.198918e-05 2.332149e-06 8.322808e-06 4.429654e-06
#> phi_1_2 -2.294436e-05 -1.170724e-05 3.281239e-06 1.615242e-06 1.092348e-06
#> phi_2_2 2.962651e-05 -2.840243e-06 -1.545537e-05 1.176296e-07 8.732957e-07
#> phi_3_2 7.563860e-06 3.205242e-05 -2.613218e-06 -8.237631e-06 -2.240050e-07
#> phi_1_3 1.524066e-05 1.735962e-06 -2.319797e-06 -9.189074e-07 5.646350e-07
#> phi_2_3 -1.770462e-05 1.379332e-06 9.763319e-06 -2.405728e-06 -1.197923e-07
#> phi_3_3 -5.242933e-06 -1.843388e-05 1.906244e-06 4.981899e-06 -5.157492e-06
#> sigma_1_1 -1.473938e-06 -5.848017e-06 4.039293e-07 -2.565611e-08 7.654383e-07
#> sigma_2_1 7.006599e-06 1.438703e-07 -6.227217e-07 -9.558368e-07 2.524688e-08
#> sigma_3_1 1.438703e-07 7.505554e-06 7.860849e-09 -2.941660e-07 -2.011280e-06
#> sigma_2_2 -6.227217e-07 7.860849e-09 3.669146e-06 6.984348e-08 -4.218391e-08
#> sigma_3_2 -9.558368e-07 -2.941660e-07 6.984348e-08 1.903497e-06 5.149938e-08
#> sigma_3_3 2.524688e-08 -2.011280e-06 -4.218391e-08 5.149938e-08 4.436798e-06
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/