Skip to contents

transforms fitted ctsem model to cpptsem model. The implementation of cpptsem closely follows that of ctsemOMX (Driver et al., 2017)

Usage

cpptsemFromCtsem(
  ctsemModel,
  wideData,
  removeD = TRUE,
  group = NULL,
  groupSpecificParameters = NULL,
  silent = FALSE
)

Arguments

ctsemModel

fittet ctsem object

wideData

Please provide a data set in wide format compatible to ctsemOMX

removeD

removes the D matrix in the mxObject; This should be set to TRUE

group

numeric vector indicating which group a person belongs to

groupSpecificParameters

string vector indicating which parameters should be group specific

silent

suppress messages

Details

# References

Driver, C. C., Oud, J. H. L., & Voelkle, M. C. (2017). Continuous Time Structural Equation Modelling With R Package ctsem. Journal of Statistical Software, 77(5), 1–36. https://doi.org/10.18637/jss.v077.i05

Examples

if (FALSE) {
library(regCtsem)

addCINT <- FALSE
if(addCINT){
  CINT = matrix(c("cint1", "cint2"), nrow = 2, ncol = 1)
}else{
  CINT = matrix(c(0,0), nrow = 2, ncol = 1)
}
stationary <- c('T0TRAITEFFECT','T0TIPREDEFFECT')

## ctsem model without trait
AnomAuthmodel1 <- ctModel(LAMBDA = matrix(c(1, 0, 0, 1), nrow = 2, ncol = 2),
                          Tpoints = 5, n.latent = 2, n.manifest = 2,
                          MANIFESTVAR=diag(0, 2),
                          TRAITVAR = NULL,
                          CINT = CINT)
AnomAuthfit1 <- ctFit(AnomAuth, AnomAuthmodel1, useOptimizer = FALSE, stationary = stationary)
AnomAuthfit1$mxobj$fitfunction$result[[1]]
gradientModel1 <- OpenMx::mxRun(OpenMx::mxModel(AnomAuthfit1$mxobj,
                                                OpenMx::mxComputeSequence(steps=list(
                                                  OpenMx::mxComputeNumericDeriv(checkGradient = FALSE,
                                                                                hessian = FALSE))
                                                )))
centralGrandients <- gradientModel1$compute$steps[[1]]$output[["gradient"]][,"central"]
names(centralGrandients) <- rownames(gradientModel1$compute$steps[[1]]$output[["gradient"]])
centralGrandients

## with cpptsem
cpptsemmodel1 <- cpptsemFromCtsem(ctsemModel = AnomAuthfit1, wideData = AnomAuth)
cpptsemmodel1$computeRAM()
cpptsemmodel1$fitRAM()
cpptsemmodel1$m2LL
cpptsemmodel1$approxRAMGradients((1.1 * 10^(-16))^(1/3))[names(centralGrandients)]

# change parameter values
AnomAuthfit1_1 <- ctFit(AnomAuth, AnomAuthmodel1, useOptimizer = TRUE, stationary = stationary)
newParameters <- omxGetParameters(AnomAuthfit1_1$mxobj)
cpptsemmodel1$setParameterValues(newParameters, names(newParameters))
cpptsemmodel1$computeRAM()
cpptsemmodel1$fitRAM()
cpptsemmodel1$m2LL

# Compute and compare standard errors
ctsemSummary <- summary(AnomAuthfit1_1)
ctsemSummary$ctparameters
computeStandardErrorsDelta(cpptsemObject = cpptsemmodel1,
                           objective = "ML")

## ctsem model with trait
AnomAuthmodel2 <- ctModel(LAMBDA = matrix(c(1, 0, 0, 1), nrow = 2, ncol = 2),
                          Tpoints = 5, n.latent = 2, n.manifest = 2,
                          MANIFESTVAR=diag(0, 2),
                          TRAITVAR = "auto",
                          CINT = CINT)
AnomAuthfit2 <- ctFit(AnomAuth, AnomAuthmodel2, useOptimizer = FALSE, stationary = stationary)
AnomAuthfit2$mxobj$fitfunction$result[[1]]
gradientModel2 <- OpenMx::mxRun(OpenMx::mxModel(AnomAuthfit2$mxobj,
                                                OpenMx::mxComputeSequence(steps=list(
                                                  OpenMx::mxComputeNumericDeriv(checkGradient = FALSE,
                                                                                hessian = FALSE))
                                                )))
centralGrandients <- gradientModel2$compute$steps[[1]]$output[["gradient"]][,"central"]
names(centralGrandients) <- rownames(gradientModel2$compute$steps[[1]]$output[["gradient"]])
centralGrandients
## with cpptsem
cpptsemmodel2 <- cpptsemFromCtsem(AnomAuthfit2, wideData = AnomAuth)
cpptsemmodel2$computeRAM()
cpptsemmodel2$fitRAM()
cpptsemmodel2$m2LL
cpptsemmodel2$approxRAMGradients((1.1 * 10^(-16))^(1/3))[names(centralGrandients)]


## Example 3: Kalman Filter
set.seed(175446)
## define the population model:

# set the drift matrix. Note that drift eta_1_eta2 is set to equal 0 in the population.
ct_drift <- matrix(c(-.3,.2,0,-.5), ncol = 2)

generatingModel<-ctsem::ctModel(Tpoints=20,n.latent=2,n.TDpred=0,n.TIpred=0,n.manifest=2,
                                MANIFESTVAR=diag(0,2),
                                LAMBDA=diag(1,2),
                                DRIFT=ct_drift,
                                DIFFUSION=matrix(c(.5,0,0,.5),2),
                                CINT=matrix(0,nrow = 2, ncol = 1),
                                T0MEANS=matrix(0,ncol=1,nrow=2),
                                T0VAR=diag(1,2), type = "omx")

# simulate a training data and testing data set
traindata <- ctsem::ctGenerate(generatingModel,n.subjects = 20, wide = TRUE)

## Build the analysis model. Note that drift eta1_eta2 is freely estimated
# although it is 0 in the population.
myModel <- ctsem::ctModel(Tpoints=20,n.latent=2,n.TDpred=0,n.TIpred=0,n.manifest=2,
                          LAMBDA=diag(1,2),
                          MANIFESTVAR=diag(0,2),
                          CINT=CINT,
                          DIFFUSION=matrix(c('eta1_eta1',0,0,'eta2_eta2'),2),
                          T0MEANS=matrix(0,ncol=1,nrow=2),
                          T0VAR="auto", type = "omx")
myModel <- ctFit(myModel, dat = traindata, objective = "Kalman", useOptimizer = F, stationary = stationary)
myModel$mxobj$fitfunction$result[[1]]

gradientModel3 <- OpenMx::mxRun(OpenMx::mxModel(myModel$mxobj,
                                                OpenMx::mxComputeSequence(steps=list(
                                                  OpenMx::mxComputeNumericDeriv(checkGradient = FALSE,
                                                                                hessian = FALSE))
                                                )))
centralGrandients <- gradientModel3$compute$steps[[1]]$output[["gradient"]][,"central"]
names(centralGrandients) <- rownames(gradientModel3$compute$steps[[1]]$output[["gradient"]])
centralGrandients
KalmanScores <- mxKalmanScores(myModel$mxobj)
KalmanScores$xUpdated[2:21,]

## with cpptsem
cpptsemmodel3 <- cpptsemFromCtsem(ctsemModel = myModel,wideData = traindata)
cpptsemmodel3$computeAndFitKalman(0) # the 0 tells cpptsem that the fit of the full sample should be computed. Passing 1, 2, ... N to the function will compute the fit for a single sample
cpptsemmodel3$m2LL
cpptsemmodel3$latentScores[1,]
cpptsemmodel3$approxKalmanGradients((1.1 * 10^(-16))^(1/3))[names(centralGrandients)]

## Example 4: Kalman Filter with group or person specific parameter values
set.seed(175446)
## define the population model:
addCINT <- FALSE
if(addCINT){
CINT = matrix(c("cint1", "cint2"), nrow = 2, ncol = 1)
}else{
CINT = matrix(c(0,0), nrow = 2, ncol = 1)
}
stationary <- c('T0TRAITEFFECT','T0TIPREDEFFECT')
# set the drift matrix. Note that drift eta_1_eta2 is set to equal 0 in the population.
ct_drift1 <- matrix(c(-.3,.2,0,-.5), ncol = 2)
ct_drift2 <- matrix(c(-.5,.1,.1,-.2), ncol = 2)
generatingModel1<-ctsem::ctModel(Tpoints=200,n.latent=2,n.TDpred=0,n.TIpred=0,n.manifest=2,
                                 MANIFESTVAR=diag(0,2),
                                 LAMBDA=diag(1,2),
                                 DRIFT=ct_drift1,
                                 DIFFUSION=matrix(c(.5,0,0,.5),2),
                                 CINT=matrix(0,nrow = 2, ncol = 1),
                                 T0MEANS=matrix(0,ncol=1,nrow=2),
                                 T0VAR=diag(1,2), type = "omx")
generatingModel2<-ctsem::ctModel(Tpoints=200,n.latent=2,n.TDpred=0,n.TIpred=0,n.manifest=2,
                                 MANIFESTVAR=diag(0,2),
                                 LAMBDA=diag(1,2),
                                 DRIFT=ct_drift2,
                                 DIFFUSION=matrix(c(.5,0,0,.5),2),
                                 CINT=matrix(0,nrow = 2, ncol = 1),
                                 T0MEANS=matrix(0,ncol=1,nrow=2),
                                 T0VAR=diag(1,2), type = "omx")
traindata1 <- ctsem::ctGenerate(generatingModel1,n.subjects = 10, wide = TRUE)
traindata2 <- ctsem::ctGenerate(generatingModel2,n.subjects = 10, wide = TRUE)
traindata <- rbind(traindata1, traindata2)
## Build the analysis model.
myModel <- ctsem::ctModel(Tpoints=200,n.latent=2,n.TDpred=0,n.TIpred=0,n.manifest=2,
                          LAMBDA=diag(1,2),
                          MANIFESTVAR=diag(0,2),
                          CINT=CINT,
                          DIFFUSION=matrix(c('eta1_eta1',0,0,'eta2_eta2'),2),
                          T0MEANS=matrix(0,ncol=1,nrow=2),
                          T0VAR="auto", type = "omx")
myModel <- ctFit(myModel, dat = traindata, objective = "Kalman", useOptimizer = F, stationary = stationary)

## with cpptsem
cpptsemmodel3 <- cpptsemFromCtsem(ctsemModel = myModel, wideData = traindata, group = c(rep(1,10), rep(2,10)), groupSpecificParameters = c(myModel$mxobj$DRIFT$labels))

startingValues <- cpptsemmodel3$getParameterValues()

m2LLCpptsem <- function(parameters, cpptsemmodel){
  cpptsemmodel$setParameterValues(parameters, names(parameters))
  # catching all errors from cpptsemmodel
# when parameter values are impossible
  invisible(utils::capture.output(KALMAN <- try(cpptsemmodel$computeAndFitKalman(0),
                                         silent = TRUE),
                           type = "message"))

  if(class(KALMAN) == "try-error" | is.na(cpptsemmodel$m2LL)){
    return(99999999)
  }
  return(cpptsemmodel$m2LL)
}

# compute
kalmanCpptsemFit <- Rsolnp::solnp(pars = startingValues,
                                  fun = m2LLCpptsem,
                                  eqfun = NULL, eqB = NULL, ineqfun = NULL, ineqLB = NULL,
                                  ineqUB = NULL, LB = NULL, UB = NULL, control = list(trace = 0),
                                  cpptsemmodel3)
kalmanCpptsemFit$pars
ct_drift1
}