stim-vignette

The stim package fits the Stability Informed Model which incorporates variable stability–how a variable correlates with future versions of itself–into cross-sectional estimates. Assuming the process is stationary, the model is specified correctly, and the stability values are correct, the Stability Informed Model can estimate parameters that are unbiased for cross-lagged (longitudinal) effects even when only cross-sectional data are available.

For more information on the Stability Informed Model see https://psyarxiv.com/vg5as

This tutorial outlines how to estimate a Stability Informed Model using the stim package within an SEM framework.

Installation

You can install the development version of stim from GitHub with

devtools::install_github("https://github.com/AnnaWysocki/stim")

Example

Let’s create some data to use in our example.

library(stim)

S <-  matrix(c(1, .3, .3,
              .3,  1, .3,
              .3, .3,  1), 
             nrow = 3, ncol = 3,
             dimnames = list(c("X", "Y", "Z"), 
                             c("X", "Y", "Z")))

stim Function Overview

Estimate a single or a set of Stability Informed Models using the stim() function.

stim() has five arguments

More details on the model and stability arguments can be found below.

The model Argument

Input an object with the cross-sectional model specified in lavaan syntax. The model syntax should be specified as a cross-sectional path model in lavaan (See https://lavaan.ugent.be/tutorial/tutorial.pdf for information on lavaan syntax).

This input determines what parameters/effects are estimated. Note, the Stability Informed model can estimate a maximum of \[ \frac{p (p-1)}{2} \] parameters (where p is the number of measured variables). These parameters can be, for example, cross-lagged effects or residual covariances.

To estimate the effect of X on Y, I could create the following object

model <- 'Y ~ X' # outcome ~ predictor

More complex models can be specified as well.

model2 <- 'Y ~ X
           Z ~ X + Y'

The default is to constrain all residual covariances to 0. But this constraint can be relaxed by specifying a residual covariance in the model syntax.

model2 <- 'Y ~ X
           Z ~ X + Y
          
           X ~~ Y' # Allows X and Y to have covarying residuals

The above model object specifies 4 estimated parameters, but, with 3 measured variables, the Stability Informed Model can only estimate 3 parameters. The remaining effects can either be fixed to 0 or fixed to a non-zero value.

model2 <- 'Y ~ .6 * X  # fix effect of X on Y to .6
           Z ~ X + Y
          
           X ~~  Y' 

Labels can be specified for the estimated parameters.

model2 <- 'Y ~ .6 * X 
           Z ~ Effect1 * X + Y # label the estimated effect of X on Z
          
           X ~~ Y'

If no label is specified for a cross-lagged parameter, the default label is ‘CL’ and a subscript with the predictor name and the outcome name.

Residual covariances are labeled ‘RCov’ and a subscript with the names of the two variable whose residuals are covarying.

Inputs for the stability Argument

Input a object with the stability information for each variable in the model.

To fit model2, the stability input should have a stability value for X, Y, and Z.

stability <- c(X = .5, Y = .1, Z = .1)

The stability values need to be named, and the names must match the variable names in the data or S input.

Multiple stability values can be specified for each variable. This results in multiple Stability Informed Models being estimated (one for each stability condition).

stability <- data.frame(X = c(.5, .55), Y = c(.1, .15), Z = c(.1, .2))

rownames(stability) <- c("Model 1", "Model 2")

stability
#>            X    Y   Z
#> Model 1 0.50 0.10 0.1
#> Model 2 0.55 0.15 0.2

If this is the stability input, two models will be estimated. One model where the stability values for X, Y, and Z are .5, .1, and .1, respectively, and one where the stability values for X, Y, and Z are .55, .15, and .2, respectively.

Estimate the Stability Informed Model

modelFit <- stim(S = S, n = 1000, model = model2, stability = stability) 
#> StIM: Stability Informed Models 
#> -------------------------------------
#> -------------------------------------
#> 
#> Variables (p): 3 
#> Sample Size (n): 1000 
#> Estimated Parameters (q): 3 
#> Degrees of Freedom: 0 
#> Number of Models Estimated: 2 
#> 
#> -------------------------------------

Some information about the model(s) is automatically printed out when the stim() function is run. The summary() function can be used to print out more information

summary(modelFit)
#> StIM: Stability Informed Models 
#> -------------------------------------
#> -------------------------------------
#> 
#> Variables (p): 3 
#> Sample Size (n): 1000 
#> Estimated Parameters (q): 3 
#> Degrees of Freedom: 0 
#> 
#> -------------------------------------
#> Model 1 
#> 
#> Stability:
#>    X   Y   Z
#>  0.5 0.1 0.1
#> 
#>  Autoregressive Effects:
#>         ARX         ARY         ARZ 
#>  0.50025018 -0.07985993 -0.24540155 
#> 
#>  Cross Lagged Effects:
#>   Effect Estimate Standard.Error P.Value
#>  Effect1    0.468          0.117   0.000
#>     CLYZ    0.684          0.616   0.266
#> 
#>  Residual Covariances:
#>  Effect Estimate Standard.Error P.Value
#>  RCovYX    0.012          0.037   0.754
#> 
#> -------------------------------------
#>  Model 2 
#> 
#> Stability:
#>     X    Y   Z
#>  0.55 0.15 0.2
#> 
#>  Autoregressive Effects:
#>         ARX         ARY         ARZ 
#>  0.55027521 -0.02983492 -0.15827996 
#> 
#>  Cross Lagged Effects:
#>   Effect Estimate Standard.Error P.Value
#>  Effect1    0.334          0.348   0.337
#>     CLYZ    0.861          1.648   0.601
#> 
#>  Residual Covariances:
#>  Effect Estimate Standard.Error P.Value
#>  RCovYX   -0.025          0.037    0.49
#> 
#> -------------------------------------
#> 

Eploring the stim Output Object

modelFit is a stim object that contains a list of objects with information for the Stability Informed Model

stability

A table of the stability conditions. Each row contains the stability information for one Stability Informed Model.

modelFit$stability 
#>            X    Y   Z
#> Model 1 0.50 0.10 0.1
#> Model 2 0.55 0.15 0.2

CLEffectTable

A table with information on the cross-lagged paths. It has the predictor and outcome names, cross-lagged effect labels, and whether the cross-lagged path is estimated or constrained.

modelFit$CLEffectTable 
#>   predictor outcome    name estimate
#> 1       X_0       Y     0.6       No
#> 2       X_0       Z Effect1      Yes
#> 3       Y_0       Z    CLYZ      Yes

CLMatrices

A list of matrices with the estimated cross-lagged effects and standard errors and p-values for each of the estimated cross-lagged effects. Each matrix corresponds to one of the estimated Stability Informed Models.

modelFit$CLMatrices 
#> $Model1
#>    Effect Estimate Standard.Error P.Value
#> 3 Effect1    0.468          0.117   0.000
#> 6    CLYZ    0.684          0.616   0.266
#> 
#> $Model2
#>    Effect Estimate Standard.Error P.Value
#> 3 Effect1    0.334          0.348   0.337
#> 6    CLYZ    0.861          1.648   0.601

RCovMatrices

A list of matrices with the estimated residual covariances and their standard errors and p-values. Each matrix corresponds to one of the estimated Stability Informed Models.

modelFit$RCovMatrices 
#> $Model1
#>    Effect Estimate Standard.Error P.Value
#> 16 RCovYX    0.012          0.037   0.754
#> 
#> $Model2
#>    Effect Estimate Standard.Error P.Value
#> 16 RCovYX   -0.025          0.037    0.49

ARVector

A list of vectors (1 for each Stability Informed Model that was estimated) with the values for the auto-regressive effects.

A list of vectors with the values for each auto-regressive effect. Each vector corresponds to one of the estimated Stability Informed Models.

modelFit$ARVector
#> $Model1
#>         ARX         ARY         ARZ 
#>  0.50025018 -0.07985993 -0.24540155 
#> 
#> $Model2
#>         ARX         ARY         ARZ 
#>  0.55027521 -0.02983492 -0.15827996

lavaanObjects

A list of lavaan objects (1 for each Stability Informed Model)

To output the lavaan object easily, you can use the lavaanSummary() function

lavaanSummary(modelFit)
#> Model 1 
#> lavaan 0.6-12 ended normally after 143 iterations
#> 
#>   Estimator                                         ML
#>   Optimization method                           NLMINB
#>   Number of model parameters                        12
#> 
#>   Number of observations                          1000
#> 
#> Model Test User Model:
#>                                                       
#>   Test statistic                                 0.000
#>   Degrees of freedom                                 0
#> 
#> Parameter Estimates:
#> 
#>   Standard errors                             Standard
#>   Information                                 Expected
#>   Information saturated (h1) model          Structured
#> 
#> Latent Variables:
#>                    Estimate  Std.Err  z-value  P(>|z|)
#>   X_0 =~                                              
#>     X        (ARX)    0.500                           
#>     Y                 0.600                           
#>     Z       (Eff1)    0.468    0.117    4.009    0.000
#>   Y_0 =~                                              
#>     X                 0.000                           
#>     Y        (ARY)   -0.080    0.020   -4.033    0.000
#>     Z       (CLYZ)    0.684    0.616    1.111    0.266
#>   Z_0 =~                                              
#>     X                 0.000                           
#>     Y                 0.000                           
#>     Z        (ARZ)   -0.245    0.160   -1.534    0.125
#> 
#> Covariances:
#>                    Estimate  Std.Err  z-value  P(>|z|)
#>   X_0 ~~                                              
#>     Y_0     (CvXY)    0.300    0.033    9.087    0.000
#>     Z_0     (CvXZ)    0.300    0.033    9.087    0.000
#>   Y_0 ~~                                              
#>     Z_0     (CvYZ)    0.300    0.033    9.087    0.000
#>  .X ~~                                                
#>    .Y       (RCYX)    0.012    0.037    0.313    0.754
#> 
#> Variances:
#>                    Estimate  Std.Err  z-value  P(>|z|)
#>     X_0     (VarX)    1.000                           
#>     Y_0     (VarY)    1.000                           
#>     Z_0     (VarZ)    1.000                           
#>    .X                 0.749    0.045   16.765    0.000
#>    .Y                 0.661    0.048   13.775    0.000
#>    .Z                 0.229    0.778    0.295    0.768
#> 
#> Constraints:
#>                                                |Slack|
#>     ARX - (0.5/VarX)                             0.000
#>     ARY - ((0.1-0.6*CovXY)/VarY)                 0.000
#>     ARZ-((0.1-(Effect1*CovXZ+CLYZ*CvYZ))/VrZ)    0.000
#>     CovXY - ((0.6*VarX+ARY*CovXY)*ARX+RCovYX)    0.000
#>     CvXZ-((Effct1*VrX+CLYZ*CvXY+ARZ*CXZ)*ARX)    0.000
#>     CYZ-(0.6*(E1*VX+CLYZ*CXY+ARZ*CXZ)+(E1*CXY    0.000
#> 
#> Model 2 
#> lavaan 0.6-12 ended normally after 193 iterations
#> 
#>   Estimator                                         ML
#>   Optimization method                           NLMINB
#>   Number of model parameters                        12
#> 
#>   Number of observations                          1000
#> 
#> Model Test User Model:
#>                                                       
#>   Test statistic                                 0.000
#>   Degrees of freedom                                 0
#> 
#> Parameter Estimates:
#> 
#>   Standard errors                             Standard
#>   Information                                 Expected
#>   Information saturated (h1) model          Structured
#> 
#> Latent Variables:
#>                    Estimate  Std.Err  z-value  P(>|z|)
#>   X_0 =~                                              
#>     X        (ARX)    0.550       NA                  
#>     Y                 0.600                           
#>     Z       (Eff1)    0.334    0.348    0.961    0.337
#>   Y_0 =~                                              
#>     X                 0.000                           
#>     Y        (ARY)   -0.030    0.020   -1.507    0.132
#>     Z       (CLYZ)    0.861    1.648    0.522    0.601
#>   Z_0 =~                                              
#>     X                 0.000                           
#>     Y                 0.000                           
#>     Z        (ARZ)   -0.158    0.382   -0.415    0.678
#> 
#> Covariances:
#>                    Estimate  Std.Err  z-value  P(>|z|)
#>   X_0 ~~                                              
#>     Y_0     (CvXY)    0.300    0.033    9.087    0.000
#>     Z_0     (CvXZ)    0.300    0.033    9.087    0.000
#>   Y_0 ~~                                              
#>     Z_0     (CvYZ)    0.300    0.033    9.087    0.000
#>  .X ~~                                                
#>    .Y       (RCYX)   -0.025    0.037   -0.690    0.490
#> 
#> Variances:
#>                    Estimate  Std.Err  z-value  P(>|z|)
#>     X_0     (VarX)    1.000                           
#>     Y_0     (VarY)    1.000                           
#>     Z_0     (VarZ)    1.000                           
#>    .X                 0.696    0.045   15.590    0.000
#>    .Y                 0.649    0.048   13.514    0.000
#>    .Z                 0.062    2.486    0.025    0.980
#> 
#> Constraints:
#>                                                |Slack|
#>     ARX - (0.55/VarX)                            0.000
#>     ARY - ((0.15-0.6*CovXY)/VarY)                0.000
#>     ARZ-((0.2-(Effect1*CovXZ+CLYZ*CvYZ))/VrZ)    0.000
#>     CovXY - ((0.6*VarX+ARY*CovXY)*ARX+RCovYX)    0.000
#>     CvXZ-((Effct1*VrX+CLYZ*CvXY+ARZ*CXZ)*ARX)    0.000
#>     CYZ-(0.6*(E1*VX+CLYZ*CXY+ARZ*CXZ)+(E1*CXY    0.000

You can also print a subset of the lavaan objects by using the subset argument.

lavaanSummary(modelFit, subset = 1)
#> lavaan 0.6-12 ended normally after 143 iterations
#> 
#>   Estimator                                         ML
#>   Optimization method                           NLMINB
#>   Number of model parameters                        12
#> 
#>   Number of observations                          1000
#> 
#> Model Test User Model:
#>                                                       
#>   Test statistic                                 0.000
#>   Degrees of freedom                                 0
#> 
#> Parameter Estimates:
#> 
#>   Standard errors                             Standard
#>   Information                                 Expected
#>   Information saturated (h1) model          Structured
#> 
#> Latent Variables:
#>                    Estimate  Std.Err  z-value  P(>|z|)
#>   X_0 =~                                              
#>     X        (ARX)    0.500                           
#>     Y                 0.600                           
#>     Z       (Eff1)    0.468    0.117    4.009    0.000
#>   Y_0 =~                                              
#>     X                 0.000                           
#>     Y        (ARY)   -0.080    0.020   -4.033    0.000
#>     Z       (CLYZ)    0.684    0.616    1.111    0.266
#>   Z_0 =~                                              
#>     X                 0.000                           
#>     Y                 0.000                           
#>     Z        (ARZ)   -0.245    0.160   -1.534    0.125
#> 
#> Covariances:
#>                    Estimate  Std.Err  z-value  P(>|z|)
#>   X_0 ~~                                              
#>     Y_0     (CvXY)    0.300    0.033    9.087    0.000
#>     Z_0     (CvXZ)    0.300    0.033    9.087    0.000
#>   Y_0 ~~                                              
#>     Z_0     (CvYZ)    0.300    0.033    9.087    0.000
#>  .X ~~                                                
#>    .Y       (RCYX)    0.012    0.037    0.313    0.754
#> 
#> Variances:
#>                    Estimate  Std.Err  z-value  P(>|z|)
#>     X_0     (VarX)    1.000                           
#>     Y_0     (VarY)    1.000                           
#>     Z_0     (VarZ)    1.000                           
#>    .X                 0.749    0.045   16.765    0.000
#>    .Y                 0.661    0.048   13.775    0.000
#>    .Z                 0.229    0.778    0.295    0.768
#> 
#> Constraints:
#>                                                |Slack|
#>     ARX - (0.5/VarX)                             0.000
#>     ARY - ((0.1-0.6*CovXY)/VarY)                 0.000
#>     ARZ-((0.1-(Effect1*CovXZ+CLYZ*CvYZ))/VrZ)    0.000
#>     CovXY - ((0.6*VarX+ARY*CovXY)*ARX+RCovYX)    0.000
#>     CvXZ-((Effct1*VrX+CLYZ*CvXY+ARZ*CXZ)*ARX)    0.000
#>     CYZ-(0.6*(E1*VX+CLYZ*CXY+ARZ*CXZ)+(E1*CXY    0.000

NoWarnings

A vector with logical information on whether there were any errors or warnings for each of the estimated models.

FALSE means no warnings TRUE means warnings.

modelFit$NoWarnings # Means no warnings for both models
#> [1] TRUE TRUE

CSModelSyntax

The user-specified model syntax (input for model argument)

modelFit$CSModelSyntax 
#> [1] "Y ~ .6 * X \n           Z ~ Effect1 * X + Y # label the estimated effect of X on Z\n          \n           X ~~ Y"

SIMSyntax

The syntax for the Stability Informed Model–model syntax for the lavaan function. This contains the syntax to specify the structural part of the Stability Informed Model as well as the parameter constraints for the auto-regressive paths and the latent correlations

modelFit$SIMSyntax 
#> [[1]]
#>  [1] "X_0=~ARX*X+0.6*Y+Effect1*Z"                                                            
#>  [2] "Y_0=~0*X+ARY*Y+CLYZ*Z"                                                                 
#>  [3] "Z_0=~0*X+0*Y+ARZ*Z"                                                                    
#>  [4] "X_0~~ CovXY*Y_0"                                                                       
#>  [5] "X_0~~ CovXZ*Z_0"                                                                       
#>  [6] "Y_0~~ CovYZ*Z_0"                                                                       
#>  [7] "X_0~~VarX*X_0"                                                                         
#>  [8] "Y_0~~VarY*Y_0"                                                                         
#>  [9] "Z_0~~VarZ*Z_0"                                                                         
#> [10] "Y~~RCovYX*X"                                                                           
#> [11] "ARX==0.5/VarX"                                                                         
#> [12] "ARY==(0.1-0.6*CovXY)/VarY"                                                             
#> [13] "ARZ==(0.1-(Effect1*CovXZ+CLYZ*CovYZ))/VarZ"                                            
#> [14] "CovXY==(0.6*VarX+ARY*CovXY)*ARX+RCovYX"                                                
#> [15] "CovXZ==(Effect1*VarX+CLYZ*CovXY+ARZ*CovXZ)*ARX"                                        
#> [16] "CovYZ==0.6*(Effect1*VarX+CLYZ*CovXY+ARZ*CovXZ)+(Effect1*CovXY+CLYZ*VarY+ARZ*CovYZ)*ARY"
#> 
#> [[2]]
#>  [1] "X_0=~ARX*X+0.6*Y+Effect1*Z"                                                            
#>  [2] "Y_0=~0*X+ARY*Y+CLYZ*Z"                                                                 
#>  [3] "Z_0=~0*X+0*Y+ARZ*Z"                                                                    
#>  [4] "X_0~~ CovXY*Y_0"                                                                       
#>  [5] "X_0~~ CovXZ*Z_0"                                                                       
#>  [6] "Y_0~~ CovYZ*Z_0"                                                                       
#>  [7] "X_0~~VarX*X_0"                                                                         
#>  [8] "Y_0~~VarY*Y_0"                                                                         
#>  [9] "Z_0~~VarZ*Z_0"                                                                         
#> [10] "Y~~RCovYX*X"                                                                           
#> [11] "ARX==0.55/VarX"                                                                        
#> [12] "ARY==(0.15-0.6*CovXY)/VarY"                                                            
#> [13] "ARZ==(0.2-(Effect1*CovXZ+CLYZ*CovYZ))/VarZ"                                            
#> [14] "CovXY==(0.6*VarX+ARY*CovXY)*ARX+RCovYX"                                                
#> [15] "CovXZ==(Effect1*VarX+CLYZ*CovXY+ARZ*CovXZ)*ARX"                                        
#> [16] "CovYZ==0.6*(Effect1*VarX+CLYZ*CovXY+ARZ*CovXZ)+(Effect1*CovXY+CLYZ*VarY+ARZ*CovYZ)*ARY"

modelImpliedEquations

Model implied equations for the latent covariances and auto-regressive paths

modelFit$modelImpliedEquations 
#> [[1]]
#> [1] "ARX==0.5/VarX"                                                                         
#> [2] "ARY==(0.1-0.6*CovXY)/VarY"                                                             
#> [3] "ARZ==(0.1-(Effect1*CovXZ+CLYZ*CovYZ))/VarZ"                                            
#> [4] "CovXY==(0.6*VarX+ARY*CovXY)*ARX+RCovYX"                                                
#> [5] "CovXZ==(Effect1*VarX+CLYZ*CovXY+ARZ*CovXZ)*ARX"                                        
#> [6] "CovYZ==0.6*(Effect1*VarX+CLYZ*CovXY+ARZ*CovXZ)+(Effect1*CovXY+CLYZ*VarY+ARZ*CovYZ)*ARY"
#> 
#> [[2]]
#> [1] "ARX==0.55/VarX"                                                                        
#> [2] "ARY==(0.15-0.6*CovXY)/VarY"                                                            
#> [3] "ARZ==(0.2-(Effect1*CovXZ+CLYZ*CovYZ))/VarZ"                                            
#> [4] "CovXY==(0.6*VarX+ARY*CovXY)*ARX+RCovYX"                                                
#> [5] "CovXZ==(Effect1*VarX+CLYZ*CovXY+ARZ*CovXZ)*ARX"                                        
#> [6] "CovYZ==0.6*(Effect1*VarX+CLYZ*CovXY+ARZ*CovXZ)+(Effect1*CovXY+CLYZ*VarY+ARZ*CovYZ)*ARY"