3  Customizing Interaction Terms

By default, modsem() creates product indicators for you, based on the interaction specified in your model. Behind the scenes we can see that modsem() creates in total 9 variables (product indicators) used as the indicators for your latent product.

library(modsem)
m1 <- '
# Outer Model
X =~ x1 + x2 + x3
Y =~ y1 + y2 + y3
Z =~ z1 + z2 + z3

# Inner model
Y ~ X + Z + X:Z 
'

est1 <- modsem(m1, oneInt)
cat(est1$newSyntax)
X =~ x1
X =~ x2
X =~ x3
Y =~ y1
Y =~ y2
Y =~ y3
Z =~ z1
Z =~ z2
Z =~ z3
Y ~ X
Y ~ Z
Y ~ XZ
XZ =~ 1*x1z1
XZ =~ x2z1
XZ =~ x3z1
XZ =~ x1z2
XZ =~ x2z2
XZ =~ x3z2
XZ =~ x1z3
XZ =~ x2z3
XZ =~ x3z3
x1z1 ~~ 0*x2z2
x1z1 ~~ 0*x3z2
x1z1 ~~ 0*x2z3
x1z1 ~~ 0*x3z3
x2z1 ~~ 0*x1z2
x2z1 ~~ 0*x3z2
x2z1 ~~ 0*x1z3
x2z1 ~~ 0*x3z3
x3z1 ~~ 0*x1z2
x3z1 ~~ 0*x2z2
x3z1 ~~ 0*x1z3
x3z1 ~~ 0*x2z3
x1z2 ~~ 0*x2z3
x1z2 ~~ 0*x3z3
x2z2 ~~ 0*x1z3
x2z2 ~~ 0*x3z3
x3z2 ~~ 0*x1z3
x3z2 ~~ 0*x2z3
x1z1 ~~ x2z1
x1z1 ~~ x3z1
x1z1 ~~ x1z2
x1z1 ~~ x1z3
x2z1 ~~ x3z1
x2z1 ~~ x2z2
x2z1 ~~ x2z3
x3z1 ~~ x3z2
x3z1 ~~ x3z3
x1z2 ~~ x2z2
x1z2 ~~ x3z2
x1z2 ~~ x1z3
x2z2 ~~ x3z2
x2z2 ~~ x2z3
x3z2 ~~ x3z3
x1z3 ~~ x2z3
x1z3 ~~ x3z3
x2z3 ~~ x3z3

Whilst this often is sufficient, you might want some control over how these indicators are created. In general, modsem() has two mechanisms for giving control over the creating of indicator products: 1. By specifying the measurement model of your latent product your self, and 2. By using the mean() and sum() function, collectively known as parceling operations.

3.1 Specifying The Measurement Model

By default, modsem() creates all possible combinations of different product indicators. However, another common approach is to match the indicators by order. For example, let’s say you have an interaction between the laten variables X and Z: ‘X =~ x1 + x2’ and ‘Z =~ z1 + z2’. By default you would get ‘XZ =~ x1z1 + x1z2 + x2z1 + x2z2’. If you wanted to use the matching approach you would want to get ‘XZ =~ x1z1 + x2z2’ instead.

To specify the measurements your self in modsem() you would write the measurement model for your product term using semicolons to denote interactions between latents and observed variables: ‘X:Z =~ x1:z1 + x2:z2’.

m2 <- '
# Outer Model
X =~ x1 + x2
Y =~ y1 + y2
Z =~ z1 + z2
X:Z =~ x1:z1 + x2:z2

# Inner model
Y ~ X + Z + X:Z 
'

est2 <- modsem(m2, oneInt)
summary(est2)
ModSEM: 
Method = rca 
lavaan 0.6.17.1913 ended normally after 124 iterations

  Estimator                                         ML
  Optimization method                           NLMINB
  Number of model parameters                        22

  Number of observations                          1000

Model Test User Model:
                                                      
  Test statistic                                12.354
  Degrees of freedom                                14
  P-value (Chi-square)                           0.578

Parameter Estimates:

  Standard errors                             Standard
  Information                                 Expected
  Information saturated (h1) model          Structured

Latent Variables:
                   Estimate  Std.Err  z-value  P(>|z|)
  X =~                                                
    x1                1.000                           
    x2                0.931    0.096    9.663    0.000
  Y =~                                                
    y1                1.000                           
    y2                1.018    0.052   19.559    0.000
  Z =~                                                
    z1                1.000                           
    z2                1.051    0.061   17.098    0.000
  XZ =~                                               
    x1z1              1.000                           
    x2z2              0.803    0.254    3.154    0.002

Regressions:
                   Estimate  Std.Err  z-value  P(>|z|)
  Y ~                                                 
    X                 0.367    0.047    7.775    0.000
    Z                 0.504    0.045   11.128    0.000
    XZ                0.072    0.026    2.716    0.007

Covariances:
                   Estimate  Std.Err  z-value  P(>|z|)
 .x1z1 ~~                                             
   .x2z2              0.000                           
  X ~~                                                
    Z                -0.196    0.149   -1.314    0.189
    XZ               -0.000    0.370   -0.000    1.000
  Z ~~                                                
    XZ                0.000    0.326    0.000    1.000

Variances:
                   Estimate  Std.Err  z-value  P(>|z|)
   .x1                1.542    0.433    3.560    0.000
   .x2                2.731    0.390    7.004    0.000
   .y1                1.506    0.270    5.574    0.000
   .y2                1.993    0.285    6.986    0.000
   .z1                0.772    0.203    3.796    0.000
   .z2                1.282    0.229    5.606    0.000
   .x1z1              5.784    6.508    0.889    0.374
   .x2z2             23.057    4.313    5.346    0.000
    X                 4.302    0.496    8.667    0.000
   .Y                 4.160    0.323   12.860    0.000
    Z                 3.682    0.280   13.130    0.000
    XZ               20.665    6.605    3.129    0.002

3.2 Using parceling

Another approach to creating product terms, is by using parcels. Parcels are basically ways of packaging multiple indicators into a single indicator, before using them in indicator products. Currently modsem() supports two different types of parcles: mean() and sum().

When you use mean(), you bascially just compute the average score for a participant on a given set of indicators (i.e., a row mean). If we for example, writing ‘mean(x1, x2, x3)’ is equivalent to creating a new variable ‘mean_x1_x2_x3 <- (x1 + x2 + x3)/3’, and using it as your indicator. Similarily, you can use sum() to compute the sum of the variables, so ‘sum(x1, x2, x3)’ is equivalent to ‘sum_x1_x2_x3 <- x1 + x2 + x3’.

Parceling is particularily useful when one of the latent variables in your product, has considerably more indicators than the other.

m3 <- '
# Outer Model
X =~ x1 + x2
Y =~ y1 + y2
Z =~ z1 + z2
X:Z =~ x1:mean(z1, z2) + mean(x2, x3):z2

# Inner model
Y ~ X + Z + X:Z 
'
est3 <- modsem(m3, oneInt)
summary(est3)
ModSEM: 
Method = rca 
lavaan 0.6.17.1913 ended normally after 135 iterations

  Estimator                                         ML
  Optimization method                           NLMINB
  Number of model parameters                        22

  Number of observations                          1000

Model Test User Model:
                                                      
  Test statistic                                11.873
  Degrees of freedom                                14
  P-value (Chi-square)                           0.617

Parameter Estimates:

  Standard errors                             Standard
  Information                                 Expected
  Information saturated (h1) model          Structured

Latent Variables:
                   Estimate  Std.Err  z-value  P(>|z|)
  X =~                                                
    x1                1.000                           
    x2                0.929    0.096    9.661    0.000
  Y =~                                                
    y1                1.000                           
    y2                1.013    0.052   19.566    0.000
  Z =~                                                
    z1                1.000                           
    z2                1.052    0.062   17.100    0.000
  XZ =~                                               
    x1MEAN_z1_z2      1.000                           
    MEAN_x2_x3z2      0.783    0.169    4.641    0.000

Regressions:
                   Estimate  Std.Err  z-value  P(>|z|)
  Y ~                                                 
    X                 0.367    0.047    7.776    0.000
    Z                 0.505    0.045   11.150    0.000
    XZ                0.064    0.020    3.247    0.001

Covariances:
                   Estimate  Std.Err  z-value  P(>|z|)
 .x1MEAN_z1_z2 ~~                                     
   .MEAN_x2_x3z2      0.000                           
  X ~~                                                
    Z                -0.196    0.149   -1.316    0.188
    XZ                0.018    0.375    0.048    0.962
  Z ~~                                                
    XZ               -0.000    0.331   -0.000    1.000

Variances:
                   Estimate  Std.Err  z-value  P(>|z|)
   .x1                1.534    0.434    3.535    0.000
   .x2                2.738    0.389    7.030    0.000
   .y1                1.480    0.271    5.463    0.000
   .y2                2.020    0.284    7.103    0.000
   .z1                0.775    0.203    3.814    0.000
   .z2                1.279    0.229    5.588    0.000
   .x1MEAN_z1_z2      2.663    5.145    0.518    0.605
   .MEAN_x2_x3z2     10.811    3.186    3.393    0.001
    X                 4.310    0.497    8.668    0.000
   .Y                 4.190    0.325   12.907    0.000
    Z                 3.679    0.280   13.126    0.000
    XZ               24.067    5.279    4.559    0.000

3.2.1 Using just parcels

A common way to estimate latent interactions, has been to first run a factor analysis, and create mean indices based on items belonging to the factors. While it is not recommended to do so, we can achieve the same thing by using the mean() operator.

In this first example we manually create mean indices based on our factors, and then perform an observed variable regression.

indices <- oneInt
indices$Z <- (oneInt$z1 + oneInt$z2 + oneInt$z3)/3
indices$X <- (oneInt$x1 + oneInt$x2 + oneInt$x3)/3
indices$Y <- (oneInt$y1 + oneInt$y2 + oneInt$y3)/3

reg <- lm(Y ~ X*Z, indices)
summary(reg)

Call:
lm(formula = Y ~ X * Z, data = indices)

Residuals:
    Min      1Q  Median      3Q     Max 
-6.7144 -1.4198 -0.0752  1.3174  8.2751 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 2.913937   0.466632   6.245 6.28e-10 ***
X           0.004832   0.083846   0.058    0.954    
Z           0.069984   0.088918   0.787    0.431    
X:Z         0.070336   0.016049   4.383 1.30e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 2.234 on 996 degrees of freedom
Multiple R-squared:  0.2161,    Adjusted R-squared:  0.2137 
F-statistic: 91.51 on 3 and 996 DF,  p-value: < 2.2e-16

Now we do the same, by using the mean() operator in modsem().

m4 <- 'mean(y1, y2, y3) ~ mean(x1, x2, x3) + mean(z1, z2, z3) + mean(x1, x2, x3):mean(z1, z2, z3)'
est4 <- modsem(m4, oneInt, method = "pind")
summary(est4)
ModSEM: 
Method = pind 
lavaan 0.6.17.1913 ended normally after 1 iteration

  Estimator                                         ML
  Optimization method                           NLMINB
  Number of model parameters                         4

  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

Regressions:
                   Estimate  Std.Err  z-value  P(>|z|)
  MEAN_y1_y2_y3 ~                                     
    MEAN_x1_x2_x3     0.005    0.084    0.058    0.954
    MEAN_z1_z2_z3     0.070    0.089    0.789    0.430
    MEAN_1_2_3MEAN    0.070    0.016    4.391    0.000

Variances:
                   Estimate  Std.Err  z-value  P(>|z|)
   .MEAN_y1_y2_y3     4.973    0.222   22.361    0.000