Search code examples
r-lavaan

How to perform simplest Moderation in lavaan and measuring its effect to other vars?


How to perform simplest Moderation in lavaan and measuring its effect to other vars?

You have a model in r, in lavaan - how you add an moderation term?:

  1. Does by adding a ~b + c make "c" a moderator term?
  2. What is the difference between interaction term and moderation?
  3. lavaan project do not offer a such example, and many ask similar questions without a proper and clear answer.

Not a clear answer i found on web, in terms of simple words and example.

model_sem <- 
  '
a=~ x1 + x2
b=~ z1 + z2
a ~ b
'

Solution

  • Moderation = Testing if Interaction term is Significant or not (in Lavaan). This simple thing is not so clearly written to web with some exceptions. see here

    When you have two observed variables (those that containing data) then the things are very simple

    Let say you have X regressed onto (->) Y (X~Y) and M = Moderation variable

    Note: that a simple lm syntax with interaction term is valid too. eg.

    summary( lm( Y ~ X + X*Y ) )

    In Lavaan see here and here:

    library(psych)
    library(dplyr)
    library(lavaan)
    library(semTools)
    
    # Note that Centering variables is essential 
    
    # Creating interaction term prior of sem running
    myData <- myData %>% mutate(Χ_x_Μ = myData$X * myData$M)
    
    moderation_model <- '
      # Hayes Process model 1
      # regressions
      Y ~ b1*X
      Y ~ b2*M
      Y ~ b3*Χ_x_Μ
      
      # define mean parameter label for centered math for use in simple slopes
      M ~ M.mean*1
      
      # define variance parameter label for centered math for use in simple slopes
      M ~~ M.var*M
      
      # simple slopes for condition effect
      SD.below := b1 + b3*(M.mean - sqrt(M.var))
      mean := b1 + b3*(M.mean)
      SD.above := b1 + b3*(M.mean + sqrt(M.var))
      '
    
    model <- moderation_model 
    sem_fit <- lavaan::sem( model, std.lv = TRUE, data = myData, fixed.x = FALSE   )
    summary( sem_fit, standardized = TRUE,  rsquare = TRUE )
    standardizedSolution( sem_fit, type = "std.all" )
    

    However, things can go weird when you would like to interact 1st order or even 2nd order latent variables (ps. in some cases Factors). Because, Lavaan does not support this, in an easy way.

    Steps:

    # Create observed Factors by using their items
    
        df$x1_o  = (df$f11 + df$f12 + df$f13 ) /3
        df$x2_o  = (df$f21 + df$f22 + df$f33 ) /3
        
        df$M_o   = (df$m1 + df$m2 + df$m3 ) /3
        df$Y_o   = (df$y1 + df$y2 ) /3
        df$X_o   = (df$x1_o + df$x2_o ) /3
    
    
    # Mean Center all your SEM variables
    
        cn                        = colnames( df )
        df_center                 = df - data.frame( matrix( rep( colMeans( df ), nrow( df ) ), ncol = ncol( df ), byrow = T))  # mean centering
        colnames( df_center )     = cn      
    
    # Make to interact each item of Moderator (M) with the X Variable to test its effect on the Y variable
    
        prod = df_center$x1_o   * df_center$m1;   df_center$prod11 = prod - mean(prod)
        prod = df_center$x1_o   * df_center$m2;   df_center$prod12 = prod - mean(prod)
        prod = df_center$x1_o   * df_center$m3;   df_center$prod13 = prod - mean(prod)
        prod = df_center$x2_o   * df_center$m1;   df_center$prod11 = prod - mean(prod)
        prod = df_center$x2_o   * df_center$m2;   df_center$prod12 = prod - mean(prod)
        prod = df_center$x2_o   * df_center$m3;   df_center$prod13 = prod - mean(prod)
        head(df_center, 2)
    
    # Make your Lavaan moderated model 
    # Note that in defining mean and variance of (M) Moderator, 
    # we used the observed factored Moderator (M_o)
    # and not the Latent (without values) construct (M).
    
    # This happened cause Lavaan was saying that M.var has no free parameters. 
    # So, I did that. If you think something else, please make a comment or a 
    # post.  
    
        moderation_model  <- 
          '
        x1  =  f11 + f12 + 13 
        x2  =  f21 + f22 + f33 
        M   =   m1 + m2 + m3 
        Y   =   y1 + y2 
        X   =   x1 + x2
        
        INT   =~ prod11 + prod12 + prod13 + prod21 + prod22 + prod23 
        
        Y ~  b1 * X
        Y ~  b2 * M
        Y ~  b3 * INT
        
        
         # define mean parameter label for centered math for use in simple slopes
         M_o  ~ M_o.mean*1
          
         # define variance parameter label for centered math for use in simple slopes
         M_o  ~~ M_o.var*M_o 
          
         # simple slopes for condition effect
          SD.below := b1 + b3*(M_o.mean - sqrt(M_o.var))
          mean     := b1 + b3*(M_o.mean)
          SD.above := b1 + b3*(M_o.mean + sqrt(M_o.var))
          
        ' 
    
    # ps. If Lavaan says that there is non-definite matrix cause is negative, 
    # please, remove some items from the relevant variable from moderation model. 
    
    
    # Check if lavaan sem can run it: 
    
    
        model <- moderation_model 
        sem_fit <- lavaan::sem( model, std.lv = TRUE, data = df_center, fixed.x = FALSE   )
        summary( sem_fit, standardized = TRUE,  rsquare = TRUE )
        standardizedSolution( sem_fit, type = "std.all" )