Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Testing differences in slopes and intercepts by group in a multi-group SEM model

    I have an unbalanced panel and have performed a simple FIML SEM multi-group modelling exercise.

    Code:
    ********************************************************************************
    * SIMULATED DATA FOR MULTI-GROUP LATENT GROWTH CURVE MODEL
    ********************************************************************************
    
    clear all
    set seed 12345
    
    * Create 400 observations (200 per group)
    set obs 400
    gen id = _n
    
    * Create two groups (mode: 1=HD, 2=PD)
    gen mode = cond(_n <= 200, 1, 2)
    
    ********************************************************************************
    * SIMULATE LATENT GROWTH TRAJECTORIES
    ********************************************************************************
    
    * Group 1 (HD): Baseline ~15, slight increase over time
    * Group 2 (PD): Baseline ~16, slight decrease over time
    
    * Individual-level random effects
    gen intercept_i = rnormal(0, 2)
    gen slope_i = rnormal(0, 0.1)
    
    * Generate observed scores at each timepoint with measurement error
    * Group 1 (HD): Mean intercept = 15, Mean slope = 0.02
    * Group 2 (PD): Mean intercept = 16, Mean slope = -0.05
    
    gen RAWGH0 = cond(mode==1, 15, 16) + intercept_i + 0*slope_i + rnormal(0, 2)
    gen RAWGH6 = cond(mode==1, 15, 16) + intercept_i + 6*cond(mode==1, 0.02, -0.05) + 6*slope_i + rnormal(0, 2)
    gen RAWGH12 = cond(mode==1, 15, 16) + intercept_i + 12*cond(mode==1, 0.02, -0.05) + 12*slope_i + rnormal(0, 2)
    gen RAWGH18 = cond(mode==1, 15, 16) + intercept_i + 18*cond(mode==1, 0.02, -0.05) + 18*slope_i + rnormal(0, 2)
    
    * Add some missing data to make it realistic
    replace RAWGH6 = . if uniform() < 0.10
    replace RAWGH12 = . if uniform() < 0.15
    replace RAWGH18 = . if uniform() < 0.20
    
    * Clean up intermediate variables
    drop intercept_i slope_i
    
    * Label variables
    label variable id "Patient ID"
    label variable mode "Dialysis modality"
    label define mode_label 1 "HD" 2 "PD"
    label values mode mode_label
    label variable RAWGH0 "General Health at baseline"
    label variable RAWGH6 "General Health at 6 months"
    label variable RAWGH12 "General Health at 12 months"
    label variable RAWGH18 "General Health at 18 months"
    
    ********************************************************************************
    * DESCRIPTIVE STATISTICS
    ********************************************************************************
    
    tabulate mode
    summarize RAWGH0 RAWGH6 RAWGH12 RAWGH18
    
    bysort mode: summarize RAWGH0 RAWGH6 RAWGH12 RAWGH18
    
    ********************************************************************************
    * MULTI-GROUP LATENT GROWTH CURVE MODEL
    ********************************************************************************
    
    sem (Intercept@1 Slope@0 -> RAWGH0) ///
        (Intercept@1 Slope@6 -> RAWGH6) ///
        (Intercept@1 Slope@12 -> RAWGH12) ///
        (Intercept@1 Slope@18 -> RAWGH18), ///
        latent(Intercept Slope) ///
        method(mlmv) ///
        group(mode)
    
    estimates store model_multigroup
    
    * Display the parameter estimates
    matrix list e(b)
    
    * Show the model framework
    estat framework
    QUESTION FOR STATALIST: How do I test whether the latent growth trajectories differ between groups?

    Specifically, I want to test:

    1. Do the mean intercepts differ between mode=1 and mode=2? (i.e., is baseline General Health different between groups?)

    2. Do the mean slopes differ between mode=1 and mode=2? (i.e., is the rate of change different between groups?)

    3. Joint test: Do trajectories differ overall?

    I can see from matrix list e(b) that there are parameters like:

    * mean(Intercept) 1.mode
    * mean(Intercept) 2.mode
    * mean(Slope) 1.mode
    * mean(Slope) 2.mode

    But I cannot figure out the correct test syntax. I've tried:

    Code:
    test [mean(Intercept)]1.mode = [mean(Intercept)]2.mode
    test mean(Intercept):1.mode = mean(Intercept):2.mode
    test _b[mean(Intercept):1.mode] = _b[mean(Intercept):2.mode]
    All give errors. What is the correct syntax?
    Last edited by Mark Marshall; 13 Feb 2026, 10:08.

  • #2
    Thanks for the reproducible example. Make use of the -coeflegend- option to see how to refer to the individual coefficients.

    Code:
    ********************************************************************************
    * SIMULATED DATA FOR MULTI-GROUP LATENT GROWTH CURVE MODEL
    ********************************************************************************
    
    clear all
    set seed 12345
    
    * Create 400 observations (200 per group)
    set obs 400
    gen id = _n
    
    * Create two groups (mode: 1=HD, 2=PD)
    gen mode = cond(_n <= 200, 1, 2)
    
    ********************************************************************************
    * SIMULATE LATENT GROWTH TRAJECTORIES
    ********************************************************************************
    
    * Group 1 (HD): Baseline ~15, slight increase over time
    * Group 2 (PD): Baseline ~16, slight decrease over time
    
    * Individual-level random effects
    gen intercept_i = rnormal(0, 2)
    gen slope_i = rnormal(0, 0.1)
    
    * Generate observed scores at each timepoint with measurement error
    * Group 1 (HD): Mean intercept = 15, Mean slope = 0.02
    * Group 2 (PD): Mean intercept = 16, Mean slope = -0.05
    
    gen RAWGH0 = cond(mode==1, 15, 16) + intercept_i + 0*slope_i + rnormal(0, 2)
    gen RAWGH6 = cond(mode==1, 15, 16) + intercept_i + 6*cond(mode==1, 0.02, -0.05) + 6*slope_i + rnormal(0, 2)
    gen RAWGH12 = cond(mode==1, 15, 16) + intercept_i + 12*cond(mode==1, 0.02, -0.05) + 12*slope_i + rnormal(0, 2)
    gen RAWGH18 = cond(mode==1, 15, 16) + intercept_i + 18*cond(mode==1, 0.02, -0.05) + 18*slope_i + rnormal(0, 2)
    
    * Add some missing data to make it realistic
    replace RAWGH6 = . if uniform() < 0.10
    replace RAWGH12 = . if uniform() < 0.15
    replace RAWGH18 = . if uniform() < 0.20
    
    * Clean up intermediate variables
    drop intercept_i slope_i
    
    * Label variables
    label variable id "Patient ID"
    label variable mode "Dialysis modality"
    label define mode_label 1 "HD" 2 "PD"
    label values mode mode_label
    label variable RAWGH0 "General Health at baseline"
    label variable RAWGH6 "General Health at 6 months"
    label variable RAWGH12 "General Health at 12 months"
    label variable RAWGH18 "General Health at 18 months"
    
    ********************************************************************************
    * DESCRIPTIVE STATISTICS
    ********************************************************************************
    
    tabulate mode
    summarize RAWGH0 RAWGH6 RAWGH12 RAWGH18
    
    bysort mode: summarize RAWGH0 RAWGH6 RAWGH12 RAWGH18
    
    ********************************************************************************
    * MULTI-GROUP LATENT GROWTH CURVE MODEL
    ********************************************************************************
    
    sem (Intercept@1 Slope@0 -> RAWGH0) ///
        (Intercept@1 Slope@6 -> RAWGH6) ///
        (Intercept@1 Slope@12 -> RAWGH12) ///
        (Intercept@1 Slope@18 -> RAWGH18), ///
        latent(Intercept Slope) ///
        method(mlmv) ///
        group(mode) 
    
    estimates store model_multigroup
    
    * Display the parameter estimates
    matrix list e(b)
    
    * Show the model framework
    estat framework
    
    
    sem (Intercept@1 Slope@0 -> RAWGH0) ///
        (Intercept@1 Slope@6 -> RAWGH6) ///
        (Intercept@1 Slope@12 -> RAWGH12) ///
        (Intercept@1 Slope@18 -> RAWGH18), ///
        latent(Intercept Slope) ///
        method(mlmv) ///
        group(mode) nolog coefl
        
    test _b[/var(Intercept)#1.mode] = _b[/var(Intercept)#2.mode]
    Res.:

    Code:
    . sem (Intercept@1 Slope@0 -> RAWGH0) ///
    >     (Intercept@1 Slope@6 -> RAWGH6) ///
    >     (Intercept@1 Slope@12 -> RAWGH12) ///
    >     (Intercept@1 Slope@18 -> RAWGH18), ///
    >     latent(Intercept Slope) ///
    >     method(mlmv) ///
    >     group(mode) nolog coefl
    
    Endogenous variables
      Measurement: RAWGH0 RAWGH6 RAWGH12 RAWGH18
    
    Exogenous variables
      Latent: Intercept Slope
    
    Structural equation model                               Number of obs    = 400
    Grouping variable: mode                                 Number of groups =   2
    Estimation method: mlmv
    
    Log likelihood = -3419.7708
    
     ( 1)  [RAWGH0]1bn.mode#c.Intercept = 1
     ( 2)  [RAWGH6]1bn.mode#c.Intercept = 1
     ( 3)  [RAWGH6]1bn.mode#c.Slope = 6
     ( 4)  [RAWGH12]1bn.mode#c.Intercept = 1
     ( 5)  [RAWGH12]1bn.mode#c.Slope = 12
     ( 6)  [RAWGH18]1bn.mode#c.Intercept = 1
     ( 7)  [RAWGH18]1bn.mode#c.Slope = 18
     ( 8)  [RAWGH0]1bn.mode - [RAWGH0]2.mode = 0
     ( 9)  [RAWGH6]1bn.mode - [RAWGH6]2.mode = 0
     (10)  [RAWGH12]1bn.mode - [RAWGH12]2.mode = 0
     (11)  [RAWGH18]1bn.mode - [RAWGH18]2.mode = 0
     (12)  [RAWGH0]2.mode#c.Intercept = 1
     (13)  [RAWGH6]2.mode#c.Intercept = 1
     (14)  [RAWGH6]2.mode#c.Slope = 6
     (15)  [RAWGH12]2.mode#c.Intercept = 1
     (16)  [RAWGH12]2.mode#c.Slope = 12
     (17)  [RAWGH18]2.mode#c.Intercept = 1
     (18)  [RAWGH18]2.mode#c.Slope = 18
     (19)  [/]mean(Intercept)#1bn.mode = 0
     (20)  [/]mean(Slope)#1bn.mode = 0
    
    Group: HD                                                  Number of obs = 200
    
    -------------------------------------------------------------------------------------
                        | Coefficient  Legend
    --------------------+----------------------------------------------------------------
    Measurement         |
      RAWGH0            |
              Intercept |          1  _b[RAWGH0:1.mode#c.Intercept]
                  _cons |   15.02188  _b[RAWGH0:1.mode]
      ------------------+----------------------------------------------------------------
      RAWGH6            |
              Intercept |          1  _b[RAWGH6:1.mode#c.Intercept]
                  Slope |          6  _b[RAWGH6:1.mode#c.Slope]
                  _cons |   15.33624  _b[RAWGH6:1.mode]
      ------------------+----------------------------------------------------------------
      RAWGH12           |
              Intercept |          1  _b[RAWGH12:1.mode#c.Intercept]
                  Slope |         12  _b[RAWGH12:1.mode#c.Slope]
                  _cons |   15.39398  _b[RAWGH12:1.mode]
      ------------------+----------------------------------------------------------------
      RAWGH18           |
              Intercept |          1  _b[RAWGH18:1.mode#c.Intercept]
                  Slope |         18  _b[RAWGH18:1.mode#c.Slope]
                  _cons |   15.70896  _b[RAWGH18:1.mode]
    --------------------+----------------------------------------------------------------
         mean(Intercept)|          0  _b[/mean(Intercept)#1.mode]
             mean(Slope)|          0  _b[/mean(Slope)#1.mode]
    --------------------+----------------------------------------------------------------
           var(e.RAWGH0)|   2.600853  _b[/var(e.RAWGH0)#1.mode]
           var(e.RAWGH6)|    3.93511  _b[/var(e.RAWGH6)#1.mode]
          var(e.RAWGH12)|   4.363104  _b[/var(e.RAWGH12)#1.mode]
          var(e.RAWGH18)|   3.226292  _b[/var(e.RAWGH18)#1.mode]
          var(Intercept)|   5.041323  _b[/var(Intercept)#1.mode]
              var(Slope)|   .0193276  _b[/var(Slope)#1.mode]
    --------------------+----------------------------------------------------------------
    cov(Intercept,Slope)|   -.080502  _b[/cov(Intercept,Slope)#1.mode]
    -------------------------------------------------------------------------------------
    
    Group: PD                                                  Number of obs = 200
    
    -------------------------------------------------------------------------------------
                        | Coefficient  Legend
    --------------------+----------------------------------------------------------------
    Measurement         |
      RAWGH0            |
              Intercept |          1  _b[RAWGH0:2.mode#c.Intercept]
                  _cons |   15.02188  _b[RAWGH0:2.mode]
      ------------------+----------------------------------------------------------------
      RAWGH6            |
              Intercept |          1  _b[RAWGH6:2.mode#c.Intercept]
                  Slope |          6  _b[RAWGH6:2.mode#c.Slope]
                  _cons |   15.33624  _b[RAWGH6:2.mode]
      ------------------+----------------------------------------------------------------
      RAWGH12           |
              Intercept |          1  _b[RAWGH12:2.mode#c.Intercept]
                  Slope |         12  _b[RAWGH12:2.mode#c.Slope]
                  _cons |   15.39398  _b[RAWGH12:2.mode]
      ------------------+----------------------------------------------------------------
      RAWGH18           |
              Intercept |          1  _b[RAWGH18:2.mode#c.Intercept]
                  Slope |         18  _b[RAWGH18:2.mode#c.Slope]
                  _cons |   15.70896  _b[RAWGH18:2.mode]
    --------------------+----------------------------------------------------------------
         mean(Intercept)|   1.219038  _b[/mean(Intercept)#2.mode]
             mean(Slope)|  -.0992847  _b[/mean(Slope)#2.mode]
    --------------------+----------------------------------------------------------------
           var(e.RAWGH0)|   3.623588  _b[/var(e.RAWGH0)#2.mode]
           var(e.RAWGH6)|   3.539811  _b[/var(e.RAWGH6)#2.mode]
          var(e.RAWGH12)|   3.605434  _b[/var(e.RAWGH12)#2.mode]
          var(e.RAWGH18)|   3.144006  _b[/var(e.RAWGH18)#2.mode]
          var(Intercept)|   5.087432  _b[/var(Intercept)#2.mode]
              var(Slope)|   .0194198  _b[/var(Slope)#2.mode]
    --------------------+----------------------------------------------------------------
    cov(Intercept,Slope)|  -.0353745  _b[/cov(Intercept,Slope)#2.mode]
    -------------------------------------------------------------------------------------
    LR test of model vs. saturated: chi2(8) = 4.46                   Prob > chi2 = 0.8133
    
    .     
    . test _b[/var(Intercept)#1.mode] = _b[/var(Intercept)#2.mode]
    
     ( 1)  [/]var(Intercept)#1bn.mode - [/]var(Intercept)#2.mode = 0
    
               chi2(  1) =    0.00
             Prob > chi2 =    0.9695

    Comment


    • #3
      Thanks so much, perfect.

      Comment

      Working...
      X