1 Background

1.1 The Family Stress Model

The Family Stress Model outlines a process in which economic stressors influence child and adolescent adjustment through various mediating pathways. This markdown examines how stress is conceptualized and measured across groups and time in various ways by using data from the Baby’s First Years study.

1.2 Data Source

Baby’s First Years (BFY) data are freely available to the research community through the Interuniversity Consortium for Political and Social Research (ICPSR). Some fast facts about BFY:

  • Who: 1,000 mothers of infants with incomes below the federal poverty line​

  • What: Mothers receive a monthly unconditional cash gift of either $333/month or $20/month for the first 52 months of their child’s life​

  • Where: New York City, New Orleans, Twin Cities, Omaha metropolitan area​

  • When: Recruitment of study participants began in May 2018 and ended in June 2019. Quantitative data is being collected just after birth and when the child reaches 12, 24, 36, and 48 months of age.​ This study uses data from waves 1 (child is 12 months) and 2 (child is 24 months).

  • Why: Examine the causal impact of monthly, unconditional cash gifts to low-income mothers on their child’s cognitive, socio-emotional, and brain development​

2 The Current Study

2.1 Theory

The Baby’s First Years Study plans to analyze how “aspects of family life hypothesized to be affected by poverty, including parent stress” contribute to child development, using an longitudinal, experimental design.

Since stress is known to be a major contributor to childhood outcomes as depicted by the Family Stress Model, and stress will be used as a major focal predictor in future analyses using the Baby’s First Years data set (see Troller-Renfree, S. et al., 2022), it’s important to understand if (1) the latent factor “stress” is equivalent across experimental groups, and (2), the latent factor “stress” is equivalent across time.

2.2 Research Questions

  1. Are there measurement differences in the latent factor “stress” among mothers who were experimental assigned to a “high cash” group and “low cash” group? (Model 3.1)
  2. Is the association between stress and child developmental outcomes the same between the experimental groups? (Model 3.2)
  3. Are there measurement differences in the latent factor “stress” among mothers across time? (Model 3.3)

2.3 Variables

To examine the stress latent factor, I will use four indicators of stress. These indicators were measured at Time 1, when children were 12 months old (2019-2020), and Time 2, when children were 24 months old (2020-2021).

  • Perceived Stress - Perceived maternal stress was assessed using the perceived stress scale (PSS; Cohen et al., 1994; Cohen & Williamson, 1988).

  • Parenting Stress - Parenting stress was assessed through a pre-registered seven-item index. Three items were used from the Aggravation in Parenting Scale (PSID-Child Development Supplement) and four were used from the Cleminshaw – Guidubaldi Parent Satisfaction Scale (Guidubaldi & Cleminshaw, 2010).

  • Economic Stress - Economic stress was assessed through mothers’ self-report on nine questions (Kling et al., 2007).

  • Household Chaos - Household stress was measured through the Confusion, Hubbub, and Order Scale (CHAOS; Matheny et al., 1995).

To examine the association between stress and child developmental outcomes at Time 2 (child is 24 months old), I will use the following outcome variable:

  • The Brief Infant-Toddler Social and Emotional Assessment (BITSEA, Briggs-Gowan et al., 2004)

2.4 Summary Statistics

Summary Statistics of Variables at Time 2 (child is 24 months old).
Summary Statistics of Variables at Time 2 (child is 24 months old).

3 Models

3.1 Group Measurement Model

Is the latent construct “stress” equivalent across experimental groups?

Schematic of First-order Individual Experimental Group Models.
Schematic of First-order Individual Experimental Group Models.
#Loading data from Year 2 of the study: 
load("/Users/allisonlanger/Desktop/SEM_final/37871-0003-Data.rda")
# loading indicator variables
Perceived<-scale(da37871.0003$MPERCEIVEDSTRESSA2)  #self report perceived stress
Parenting<-scale(da37871.0003$MPARENTINGSTRESSA2) #self report parenting stress
Economic<-scale(as.numeric(da37871.0003$EXPENSEWORRYA2)) #self report economic stress/expense worry
Household_Chaos<-scale(da37871.0003$HHCHAOSA2) #household chaos scale
outcome<-scale(da37871.0003$CBITSEAPROBLEMA2) #BITSEA scores

#creating dataframe
df<-data.frame(Perceived, Parenting, Economic, Household_Chaos, outcome)

#getting experimental group info & creating separate groups
df$group<-NA
df$group<-as.numeric(da37871.0003$TREAT)
df$group[df$group=="1"]<-"0"
df$group[df$group=="2"]<-"1"

Correlation Table for Variables at Time 2:

apa.cor.table(
  df,
  table.number = 1,
  show.conf.interval = TRUE,
  show.sig.stars = TRUE,
  landscape = TRUE)
## 
## 
## Table 1 
## 
## Means, standard deviations, and correlations with confidence intervals
##  
## 
##   Variable           M     SD   1            2            3           
##   1. Perceived       -0.00 1.00                                       
##                                                                       
##   2. Parenting       -0.00 1.00 .45**                                 
##                                 [.40, .50]                            
##                                                                       
##   3. Economic        -0.00 1.00 -.30**       -.20**                   
##                                 [-.36, -.24] [-.26, -.13]             
##                                                                       
##   4. Household_Chaos -0.00 1.00 .41**        .34**        -.16**      
##                                 [.36, .47]   [.28, .39]   [-.23, -.10]
##                                                                       
##   5. outcome         0.00  1.00 .36**        .30**        -.18**      
##                                 [.30, .42]   [.24, .36]   [-.25, -.12]
##                                                                       
##   4         
##             
##             
##             
##             
##             
##             
##             
##             
##             
##             
##             
##   .33**     
##   [.27, .39]
##             
## 
## Note. M and SD are used to represent mean and standard deviation, respectively.
## Values in square brackets indicate the 95% confidence interval.
## The confidence interval is a plausible range of population correlations 
## that could have caused the sample correlation (Cumming, 2014).
##  * indicates p < .05. ** indicates p < .01.
## 

Code for function to get commonly used fit indices:

trim_fit <- function(inp, outname) {
  #Multiple steps to get smaller amount of information
  fit_res <- data.frame(fitMeasures(inp))
  fit_res <- round(fit_res, 3)
  fit_res$index <- row.names(fit_res)
  #rownames(fit_res) <- c()
  
#  Retaining only the commonly used indices; the last '[c(2,1)]' just changes the 
#  order of the columns
  out <- fit_res[fit_res$index %in% c("npar", "chisq", "df", "pvalue",
                                          "rmsea", "rmsea.ci.lower", "rmsea.ci.upper",
                                          "rmsea.pvalue", "cfi", "tli", "aic", "bic", "bic2"),][c(2,1)]
  names(out) <- c("index", "value")
  assign(deparse(substitute(outname)), out, envir=.GlobalEnv)
}
#Building the models
model <- 'Stress =~ NA*Perceived + Parenting + Economic + Household_Chaos
                   Stress ~~ 1*Stress'

#subset group into high cash (1) and low cash (0) groups
model_high_res <- sem(model, subset(df, group == 1))
model_low_res <- sem(model, subset(df, group == 0))
        library(semPlot)

trim_fit(model_high_res, model_high_res_fit)
trim_fit(model_low_res, model_low_res_fit)

#Putting the high cash and low cash groups together
H_L_Fit <- cbind(model_high_res_fit, model_low_res_fit[2])
names(H_L_Fit) <- c("Index", "High Cash Model", "Low Cash Model")

#Configural invariance model - Are the same indicators reflective of stress across groups?
model_configural <- 'Stress =~ NA*Perceived + Parenting + Economic + Household_Chaos
                   Stress ~~ 1*Stress'
model_Configural_res <- sem(model_configural, df, group = "group")

#Model fit information
trim_fit(model_Configural_res, model_Configural_res_fit)

#View model fit information
model_Configural_res_fit
parameterestimates(model_Configural_res, ci = F, standardized = T)

#Metric invariance model - Are factor loadings to indicators equal across groups? 
model_metric <- 'Stress =~ c(NA, NA)*Perceived + c(l1, l1)*Perceived + c(l2,l2)*Parenting + c(l3, l3)*Economic + c(l4,l4)*Household_Chaos
                   Stress ~~ c(1, NA)*Stress'

model_metric_res <- sem(model_metric, df, group = "group")
#Model fit information
trim_fit(model_metric_res, model_metric_res_fit)
#View model fit information
model_metric_res_fit
parameterestimates(model_metric_res, ci = F, standardized = T)

#Scalar invariance model - Are intercepts of indicator variables equal across groups? 
model_scalar <- 'Stress =~ c(NA, NA)*Perceived + c(l1, l1)*Perceived + c(l2,l2)*Parenting + c(l3, l3)*Economic + c(l4,l4)*Household_Chaos
                   Stress ~~ c(1, NA)*Stress
                   Perceived ~ c(i1, i1)*1
                   Parenting ~ c(i2, i2)*1
                   Economic ~ c(i3, i3)*1
                   Household_Chaos ~ c(i4, i4)*1
                   Stress ~ c(1, NA)*1'

model_scalar_res <- sem(model_scalar, df, group = "group")
#Model fit information
trim_fit(model_scalar_res, model_scalar_res_fit)
#View model fit information
model_scalar_res_fit
parameterestimates(model_scalar_res, ci = F, standardized = T)

Fit Statistics for Configural, Metric, and Scalar Invariance for Stress across Experimental Groups

#Pulling all model fit together
all_fit <- cbind(model_Configural_res_fit, model_metric_res_fit[2], model_scalar_res_fit[2])
names(all_fit) <- c("Index", "Configural Model", "Metric Model", "Scalar Model")
print(all_fit)
##                         Index Configural Model Metric Model Scalar Model
## npar                     npar           24.000       21.000       18.000
## chisq                   chisq            6.309        8.801       11.110
## df                         df            4.000        7.000       10.000
## pvalue                 pvalue            0.177        0.267        0.349
## cfi                       cfi            0.995        0.996        0.998
## tli                       tli            0.986        0.994        0.997
## aic                       aic         9919.755     9916.247     9912.556
## bic                       bic        10035.409    10017.445     9999.296
## bic2                     bic2         9959.188     9950.751     9942.130
## rmsea                   rmsea            0.036        0.024        0.016
## rmsea.ci.lower rmsea.ci.lower            0.000        0.000        0.000
## rmsea.ci.upper rmsea.ci.upper            0.085        0.065        0.054
## rmsea.pvalue     rmsea.pvalue            0.615        0.819        0.919

The fit indices for the configural (RMSEA = 0.036; CFI = .995), metric (RMSEA = 0.24; CFI = 0.996) and scalar (RMSEA = 0.016; CFI= 0.998) models suggest the models support invariance in measuring the latent factor “stress” across experimental groups at Time 2 of the study. We can therefore make mean-level comparisons across the experimental groups with this data wave. Yay!

3.2 Pathway Model

Is the association between stress and child outcomes different across experimental groups?

Schematic for pathway model of stress and child outcomes (BITSEA).
Schematic for pathway model of stress and child outcomes (BITSEA).
  • Null: Association between stress and child outcome (BITSEA) is equal across groups.

  • Alternative: Association between stress and child outcome (BITSEA) differs across groups.

null <- '
Stress =~ c(NA, NA)*Perceived + c(l1, l1)*Perceived + c(l2,l2)*Parenting + c(l3, l3)*Economic + c(l4,l4)*Household_Chaos
                   Stress ~~ c(1, NA)*Stress
                   Perceived ~ c(i1, i1)*1
                   Parenting ~ c(i2, i2)*1
                   Economic ~ c(i3, i3)*1
                   Household_Chaos ~ c(i4, i4)*1
                   Stress ~ c(1, NA)*1

                   #Structural Path
                   outcome ~ c(eq, eq)*Stress'

alt <- '
Stress =~ c(NA, NA)*Perceived + c(l1, l1)*Perceived + c(l2,l2)*Parenting + c(l3, l3)*Economic + c(l4,l4)*Household_Chaos
                   Stress ~~ c(1, NA)*Stress
                   Perceived ~ c(i1, i1)*1
                   Parenting ~ c(i2, i2)*1
                   Economic ~ c(i3, i3)*1
                   Household_Chaos ~ c(i4, i4)*1
                   Stress ~ c(1, NA)*1

                   #Structural Path
                   outcome ~ c(r, l)*Stress'

null_res <- sem(null, df, group = "group")
alt_res <- sem(alt, df, group = "group")
anova(null_res, alt_res)

We retain the null (chi-square=1.04, p>.05) that the association between stress and child outcomes, as measured by the BITSEA, is equal across experimental groups (high or low cash payments).

3.3 Longitudinal Measurement Model

Is the latent construct “stress” equivalent across time?

Schematic for Longitudinal Measurement Model using Time 1 (T1) and Time 2 (T2) data waves.
Schematic for Longitudinal Measurement Model using Time 1 (T1) and Time 2 (T2) data waves.
#load T1 Data
load("/Users/allisonlanger/Desktop/SEM_final/37871-0002-Data.rda")
#load T2 Data
load("/Users/allisonlanger/Desktop/SEM_final/37871-0003-Data.rda")

Perceived1<-scale(da37871.0002$MPERCEIVEDSTRESSA1) #self report perceived stress
Perceived2<-scale(da37871.0003$MPERCEIVEDSTRESSA2) 
Parenting1<-scale(da37871.0002$MPARENTINGSTRESSA1) #self report parenting stress
Parenting2<-scale(da37871.0003$MPARENTINGSTRESSA2) 
Economic1<-scale(as.numeric(da37871.0002$EXPENSEWORRYA1)) #self report economic stress/expense worry
Economic2<-scale(as.numeric(da37871.0003$EXPENSEWORRYA2)) 
Household_Chaos1<-scale(da37871.0002$HHCHAOSA1) #household chaos scale
Household_Chaos2<-scale(da37871.0003$HHCHAOSA2) 

df2<-data.frame(Perceived1, Parenting1, Economic1, Household_Chaos1, Perceived2, Parenting2, Economic2, Household_Chaos2)

Correlation Table for Variables at Time 1 & Time 2:

library(apaTables)
apa.cor.table(
  df2,
  filename = '/Users/allisonlanger/Desktop/assignment7tablefinal.doc',
  table.number = 1,
  show.conf.interval = TRUE,
  show.sig.stars = TRUE,
  landscape = TRUE
)
## 
## 
## Table 1 
## 
## Means, standard deviations, and correlations with confidence intervals
##  
## 
##   Variable            M     SD   1            2            3           
##   1. Perceived1       0.00  1.00                                       
##                                                                        
##   2. Parenting1       -0.00 1.00 .37**                                 
##                                  [.31, .42]                            
##                                                                        
##   3. Economic1        -0.00 1.00 -.30**       -.11**                   
##                                  [-.35, -.24] [-.18, -.05]             
##                                                                        
##   4. Household_Chaos1 -0.00 1.00 .48**        .33**        -.13**      
##                                  [.42, .52]   [.27, .38]   [-.19, -.06]
##                                                                        
##   5. Perceived2       -0.00 1.00 .54**        .34**        -.20**      
##                                  [.50, .59]   [.28, .40]   [-.26, -.13]
##                                                                        
##   6. Parenting2       -0.00 1.00 .31**        .58**        -.11**      
##                                  [.25, .37]   [.54, .63]   [-.18, -.05]
##                                                                        
##   7. Economic2        -0.00 1.00 -.31**       -.15**       .51**       
##                                  [-.37, -.25] [-.22, -.09] [.46, .55]  
##                                                                        
##   8. Household_Chaos2 -0.00 1.00 .36**        .25**        -.05        
##                                  [.30, .41]   [.19, .31]   [-.11, .02] 
##                                                                        
##   4            5            6            7           
##                                                      
##                                                      
##                                                      
##                                                      
##                                                      
##                                                      
##                                                      
##                                                      
##                                                      
##                                                      
##                                                      
##   .35**                                              
##   [.29, .41]                                         
##                                                      
##   .30**        .45**                                 
##   [.23, .35]   [.40, .50]                            
##                                                      
##   -.20**       -.30**       -.20**                   
##   [-.26, -.13] [-.36, -.24] [-.26, -.13]             
##                                                      
##   .63**        .41**        .34**        -.16**      
##   [.59, .67]   [.36, .47]   [.28, .39]   [-.23, -.10]
##                                                      
## 
## Note. M and SD are used to represent mean and standard deviation, respectively.
## Values in square brackets indicate the 95% confidence interval.
## The confidence interval is a plausible range of population correlations 
## that could have caused the sample correlation (Cumming, 2014).
##  * indicates p < .05. ** indicates p < .01.
## 
T1_m <- 'Stress_T1 =~ NA*Perceived1 + Parenting1 + Economic1 + Household_Chaos1
                        Stress_T1 ~~ 1*Stress_T1'

T2_m <- 'Stress_T2 =~ NA*Perceived2 + Parenting2 + Economic2 + Household_Chaos2
                        Stress_T2 ~~ 1*Stress_T2'

#latent factors covary
Config_m <- 'Stress_T1 =~ NA*Perceived1 + Parenting1 + Economic1 + Household_Chaos1
             Stress_T2 =~ NA*Perceived2 + Parenting2 + Economic2 + Household_Chaos2
                            Stress_T1 ~~ 1*Stress_T1
                            Stress_T2 ~~ 1*Stress_T2'

#Metric model - fix loadings (no parameters labels across groups, just the one constraint)
Metric_m <- '
Stress_T1 =~ NA*Perceived1 + l1*Perceived1 + l2*Parenting1 + l3*Economic1 + l4*Household_Chaos1
Stress_T2 =~ NA*Perceived2 + l1*Perceived2 + l2*Parenting2 + l3*Economic2 + l4*Household_Chaos2
             Stress_T1 ~~ 1*Stress_T1
             Stress_T2 ~~ NA*Stress_T2'

#Scalar model - fix loadings and intercepts 
Scalar_m <- '
Stress_T1 =~ NA*Perceived1 + l1*Perceived1 + l2*Parenting1 + l3*Economic1 + 43*Household_Chaos1
Stress_T2 =~ NA*Perceived2 + l1*Perceived2 + l2*Parenting2 + l3*Economic2 + l4*Household_Chaos2
                            Perceived1 ~ i1*1
                            Parenting1 ~ i2*1
                            Economic1 ~ i3*1
                            Household_Chaos1 ~ i4*1
                            Perceived2 ~ i1*1
                            Parenting2 ~ i2*1
                            Economic2 ~ i3*1
                            Household_Chaos2 ~ i4*1
                            Stress_T1 ~~ 1*Stress_T1
                            Stress_T2 ~~ NA*Stress_T2
                            Stress_T2 ~ NA*1'

#constraints on residual variances 
Strict_m <- 
'Stress_T1 =~ NA*Perceived1 + l1*Perceived1 + l2*Parenting1 + l3*Economic1 + l4*Household_Chaos1
Stress_T2 =~ NA*Perceived2 + l1*Perceived2+ l2*Parenting2 + l3*Economic2 + l4*Household_Chaos2
                            Perceived1 ~ i1*1
                            Parenting1 ~ i2*1
                            Economic1 ~ i3*1
                            Household_Chaos1 ~ i4*1
                            Perceived2 ~ i1*1
                            Parenting2 ~ i2*1
                            Economic2 ~ i3*1
                            Household_Chaos2 ~ i4*1
                            Stress_T1 ~~ 1*Stress_T1
                            Stress_T2 ~~ NA*Stress_T2
                            Stress_T2 ~ NA*1
                            Perceived1 ~ rv1*Perceived1
                            Parenting1 ~~ rv2*Parenting1
                            Economic1 ~~ rv3*Economic1
                            Household_Chaos1 ~~ rv4*Household_Chaos1
                            Perceived2 ~ rv1*Perceived2
                            Parenting2 ~~ rv2*Parenting2
                            Economic2 ~~ rv3*Economic2
                            Household_Chaos2 ~~ rv4*Household_Chaos2'

T1_m_res <- sem(T1_m, df2)
trim_fit(T1_m_res, T1_m_res_fit)
T1_m_res_fit
parameterestimates(T1_m_res, ci = F, standardized = T)

T2_m_res <- sem(T2_m, df2)
trim_fit(T2_m_res, T2_m_res_fit)
T2_m_res_fit
parameterestimates(T2_m_res, ci = F, standardized = T)

Config_m_res <- sem(Config_m, df2)
trim_fit(Config_m_res, Config_m_res_fit)
Config_m_res_fit
parameterestimates(Config_m_res, ci = F, standardized = T)

Metric_m_res <- sem(Metric_m, df2)
trim_fit(Metric_m_res, Metric_m_res_fit)
Metric_m_res_fit
parameterestimates(Metric_m_res, ci = F, standardized = T)

Scalar_m_res <- sem(Scalar_m, df2)
trim_fit(Scalar_m_res, Scalar_m_res_fit)
Scalar_m_res_fit
parameterestimates(Scalar_m_res, ci = F, standardized = T)

Strict_m_res <- sem(Strict_m, df2)
trim_fit(Strict_m_res, Strict_m_res_fit)
Strict_m_res_fit
parameterestimates(Strict_m_res, ci = F, standardized = T)
attachment_results <- data.frame(t(cbind(T1_m_res_fit, 
                            T2_m_res_fit[2],
                            Config_m_res_fit[2],
                            Metric_m_res_fit[2],
                            Scalar_m_res_fit[2],
                            Strict_m_res_fit[2])))

attachment_results <- attachment_results[-1, ]
str(attachment_results)

attachment_results$Model <- c("T1", "T2", "Configural Model", "Metric Model", "Scalar Model", "Strict Model")
attachment_results <- attachment_results[c(14, 1:13)]
attachment_results$RMSEA_CI <- paste0(attachment_results$rmsea, " (",as.numeric(as.character(attachment_results$rmsea.ci.lower)),"-",attachment_results$rmsea.ci.upper,")")
sm_attachment_results <- attachment_results[c(1, 3, 4, 5, 6, 7, 15)]

Fit Statistics for Configural, Metric, Scalar, & Strict Invariance for Stress at Time 1 and Time 2

sm_attachment_results

Yikes! It appears there is a failure to support invariance, which suggests interpretations of mean-level differences across time may not be valid. This is indicated by the high jumps in chi-square values as the models become more restrictive, as well as the decrease in values for CFI and TLI. RMSEA values are only in an acceptable range for the basic first-order factor model with no restrictions.

So what’s happening? Beyond the influence of the latent factor, it’s possible the indicators could be associated for other reasons, which could be elucidated further by examining indicator residuals. It could also be possible that the time frame in which the items of each indicator variable were asked caused a difference in how they were interpreted. These two data waves were collected pre, post, and during covid lockdowns. It’s possible that certain measures (household chaos? economic pressures?) were conceptualized differently across these hugely different contexts.

4 Summary

Let’s return to our research questions now that we have answers:

Research Questions What did our models tell us?
Is the latent construct “stress” equivalent across experimental groups?(Model 3.1) Yes! Well, yes for Time 2 data. We need to check other data waves too.
Is the association between stress and child developmental outcomes the same between the experimental groups? (Model 3.2) Yes. We retained the null hypothesis.
Is the latent construct “stress” equivalent across experimental time? (Model 3.3) No! We need to look into why…

5 Implications

These analyses suggest that researchers who are using the Baby’s First Years data set to examine how stress may impact children’s development should…

  • Test for measurement invariance of latent constructs across the two experimental groups

  • Test for measurement invariance of latent constructs across the data collection waves

    …before making cross-group or cross-time mean comparisons.

Thanks for scrolling!

if (FALSE) {
# upload a document
result <- rpubsUpload("Temple University SEM Spring 2024", "SEMFinalPresentationFinal.html")
if (!is.null(result$continueUrl))
   browseURL(result$continueUrl)
else
   stop(result$error)

# update the same document with a new title
updateResult <- rpubsUpload("Temple University SEM 2024", "SEMFinalPresentationFinal.html",
                            id = result$id)
}