setwd("C:/Work Files/8190 MLM/Data Assignment Keys")
Data Assignment 2 Answer Key
After setting the working directory, you need to load the requisite packages. I always load tidyverse which includes ggplot2 among several other data management packages. Because you are running both latent growth models (SEM) and MLM growth models you will need both lavaan and lme4. Because lme4 does not provide significance tests for whatever reason, you also need to load lmerTest.
library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.4 ✔ readr 2.1.5
✔ forcats 1.0.0 ✔ stringr 1.5.1
✔ ggplot2 3.5.1 ✔ tibble 3.2.1
✔ lubridate 1.9.3 ✔ tidyr 1.3.1
✔ purrr 1.0.2
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(lavaan)
This is lavaan 0.6-18
lavaan is FREE software! Please report any bugs.
library(lme4)
Loading required package: Matrix
Attaching package: 'Matrix'
The following objects are masked from 'package:tidyr':
expand, pack, unpack
library(lmerTest)
Attaching package: 'lmerTest'
The following object is masked from 'package:lme4':
lmer
The following object is masked from 'package:stats':
step
Next load the data set for the assignment
<-read.csv("Assn_2_Data.csv") Assn_2_Data
Once you have loaded the data set, you should look over the data. The head command will give you a quick look at the data in a spreadsheet format. I also usually run the names command to make sure I have a reference for the names of the variables and the columns in which they are located. Finally it is important to run the str command to see how the data is structured in terms of variable types.
head(Assn_2_Data)
StudentID Time GPA Work Sex
1 1 1 2.3 2 1
2 1 2 2.1 2 1
3 1 3 3.0 2 1
4 1 4 3.0 2 1
5 1 5 3.0 2 1
6 1 6 3.3 2 1
names(Assn_2_Data)
[1] "StudentID" "Time" "GPA" "Work" "Sex"
str(Assn_2_Data)
'data.frame': 1200 obs. of 5 variables:
$ StudentID: int 1 1 1 1 1 1 2 2 2 2 ...
$ Time : int 1 2 3 4 5 6 1 2 3 4 ...
$ GPA : num 2.3 2.1 3 3 3 3.3 2.2 2.5 2.6 2.6 ...
$ Work : int 2 2 2 2 2 2 2 3 2 2 ...
$ Sex : int 1 1 1 1 1 1 0 0 0 0 ...
The data looks like it loaded correctly and there are no issues with the variable names (e.g., sometimes the id gets loaded as ~…id when pulling data in from a csv or excel file.) One thing to note is that both Sex and Work are shown as integer data, however, they are actually factors. Since Sex is coded as binary technically you don’t have to change it, but you might not get data labels in your output if you leave it as an integer. Work on the other hand has 3 categories and lme4 will read it as an unordered nominal variable and will not handle it correctly in regression-based models. So before proceeding you will need to convert both Sex and Work to factors.
$Work <- factor(Assn_2_Data$Work,
Assn_2_Datalevels=c(1,2,3),
labels = c("No Work","Part-time", "Full-time"))
$Sex <- factor(Assn_2_Data$Sex,
Assn_2_Datalevels = c(0,1),
labels = c("Male","Female"))
str(Assn_2_Data$Sex)
Factor w/ 2 levels "Male","Female": 2 2 2 2 2 2 1 1 1 1 ...
str(Assn_2_Data$Work)
Factor w/ 3 levels "No Work","Part-time",..: 2 2 2 2 2 2 2 3 2 2 ...
table(Assn_2_Data$Work)
No Work Part-time Full-time
51 971 178
table(Assn_2_Data$Sex)
Male Female
408 408
After running the code to convert Sex and Work to factors I usually run the str command on those variables separately **(it wouldn’t make much difference if you did it for the whole data set in this case, because there are a small number of variables, but with a larger data set confirming that the structure was changed appropriately would be more time consuming.) **
I also usually run a simple table for each factor to make sure that the distributions are correct and that the labels are being applied correctly.
The next step is to plot the trajectories at the sample and individual levels. This serves the same purpose as looking at the univariate descriptive statistics and histograms before conducting non-nested analyses; it gives a quick insight into how the outcome is changing over time and how much variability in trajectories there is within the sample. First, create mean values and standard errors for the outcome of interest (GPA). This will make plotting the sample average trajectory more straightforward and it will allow for the inclusion of 95% CI error bars.
<- Assn_2_Data %>%
mean_data group_by(Time) %>%
summarise(mean_GPA = mean(GPA),
se_GPA = sd(GPA) / sqrt(n()))
<-ggplot(mean_data, aes(x = Time, y = mean_GPA)) +
mean_traj_plot geom_line(color = "blue", size = 1) +
geom_point(color = "blue", size = 2) +
geom_errorbar(aes(ymin = mean_GPA - se_GPA, ymax = mean_GPA + se_GPA), width = 0.2) +
labs(title = "Mean Trajectory Over Time",
x = "Time",
y = "GPA") +
theme_minimal()
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.
mean_traj_plot
Looking at the plot for changes in GPA overtime, it is clear that there is a general upward trend from grade 11 to 4th year in university (11th grade to college senior in American English) . Also, the error bars look to be very similar so the time specific variance seems to be homoscedastic. Because ggplot is using the range to determine the scaling of the y-axis, this upward trajectory looks steeper than it actually is. To get a more realistic graph, the min and max for the y-axis can be set to range from 0-4 (full range of GPA).
+
mean_traj_plot ylim(0,4)
The mean GPA trajectory suggests a linear growth process and the time-specific variance looks homoscedastic, but this doesn’t give much insight into the variability in intra-individual variance. To get a better sense of that we need to run spaghetti plots. To run spaghetti plots in ggplot2 the data has to be in long form (or at least it is easier to do in long form). The x-axis will be our index of time, the y-axis is the outcome (GPA) and group is set to StudentID so that ggplot will generate a separate plot for each participant by ID. The trajectories can also be color coded to assess potential group differences in trajectory by predictors of interest. In this example I am using participant sex.
ggplot(Assn_2_Data, aes(x = Time, y = GPA, group = StudentID, color = Sex)) +
geom_line(alpha = 0.5) +
geom_point(alpha = 0.5) +
labs(title = "Individual Trajectories (Spaghetti Plot)",
x = "Time",
y = "Outcome") +
theme_minimal()
In this spaghetti plot the general upward trend in GPA is still clear, but there is a good deal of variability. There are some individual nonlinearities, but the overall pattern is still linear and so a nonlinear growth model is not really warranted. The color coding by participant gender also suggests that there might be gender differences, at least in intercept, with female students having slightly higher GPA’s on average.
Before moving on to testing the model, we need to take a look at the missingness patterns. First run the descriptives to see how much missing data there is. I personally like the psych package for this.
library(psych)
Attaching package: 'psych'
The following object is masked from 'package:lavaan':
cor2cov
The following objects are masked from 'package:ggplot2':
%+%, alpha
names(Assn_2_Data[,-1])
[1] "Time" "GPA" "Work" "Sex"
describe(Assn_2_Data[,-1])
vars n mean sd median trimmed mad min max range skew kurtosis se
Time 1 1200 3.50 1.71 3.5 3.50 2.22 1.0 6 5.0 0.00 -1.27 0.05
GPA 2 1200 2.87 0.39 2.8 2.86 0.44 1.7 4 2.3 0.18 -0.02 0.01
Work* 3 1200 2.11 0.42 2.0 2.06 0.00 1.0 3 2.0 0.62 1.90 0.01
Sex* 4 816 1.50 0.50 1.5 1.50 0.74 1.0 2 1.0 0.00 -2.00 0.02
The data is mostly complete with the exception of participant sex, which is missing quite a bit. To look at this in more dept there are a few options. mice, VIM, nanair, missForest, and Amelia are the most comprehensive packages for visualizing and imputing missing data. For our purposes VIM will do.
library(VIM)
Loading required package: colorspace
Loading required package: grid
VIM is ready to use.
Suggestions and bug-reports can be submitted at: https://github.com/statistikat/VIM/issues
Attaching package: 'VIM'
The following object is masked from 'package:datasets':
sleep
<- aggr(Assn_2_Data[,-1], col=c('navyblue','red'), numbers=TRUE, sortVars=TRUE, labels=names(Assn_2_Data[,-1]), cex.axis=.7, gap=3, ylab=c("Histogram of missing data","Pattern")) aggr_plot
Variables sorted by number of missings:
Variable Count
Sex 0.32
Time 0.00
GPA 0.00
Work 0.00
marginplot(Assn_2_Data[c(3,5)])
The first graph displays the percent of missing data by variable in a histogram format. We can see that sex is missing 32% of the values. You could run a Little’s MCAR test here with the nanair package. Unfortunately it is not available for the newest version of R - there are ways around that, but we don’t need to spend time with it now. Perhaps a better indicator anyway is to examine how the missingness is related to our outcome GPA. The best option for this data would be to only run it as a latent growth curve (LGC) rather than a MLM because LGC can use FIML. The other option is to impute the missing data, but I am not completely comfortable with imputing demographics, especially with a limited number of variables. But, this is an assignment so we will do both.
Modeling Growth using an MLM approach
It isn’t necessary, but is advisable to first conduct an unconditional growth model before adding in the predictors. This is useful in testing model assumptions (e.g., linear v. nonlinear) and assessing the degree of variance in both intercept and slope.
To specify this model we will use the lmer (linear mixed effects regression) command from lme4 with GPA as the DV, the tilda indicates a regression and the level 1 predictor is time. To specify the level 2 or random effects we will add to the simple regression a set of parentheses and a vertical pipe. The left side of the pipe specifies the random effects. A value of 1 specifies a random intercept - if we did not include a 1 or put in a zero the model would only estimate fixed effects for the intercept. We also want random effects for our level 1 predictor (time) which will give us random slopes as well. To the right of the vertical pipe we indicate the nesting variable. Since for growth curves, time is nested within person, our index of person (StudentID) is the nesting variable. Finally, we specify which data set to use in estimating this model.
<- lmer(GPA ~ Time +
UC_model 1 + Time | StudentID), data = Assn_2_Data)
(
# Summary of the model
summary(UC_model)
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: GPA ~ Time + (1 + Time | StudentID)
Data: Assn_2_Data
REML criterion at convergence: 261
Scaled residuals:
Min 1Q Median 3Q Max
-3.2695 -0.5377 -0.0128 0.5326 3.1939
Random effects:
Groups Name Variance Std.Dev. Corr
StudentID (Intercept) 0.052503 0.22913
Time 0.004504 0.06711 -0.38
Residual 0.042388 0.20588
Number of obs: 1200, groups: StudentID, 200
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 2.493e+00 2.112e-02 1.990e+02 118.02 <2e-16 ***
Time 1.063e-01 5.885e-03 1.990e+02 18.07 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr)
Time -0.579
Looking at the output we see that the fixed effect (true sample average) intercept, or GPA at time 1 is 2.49 and the fixed effect slope is .01. So for every year we add .01 GPA points to the sample average at baseline. The intercept and slope are correlated at -0.38 indicating that for every unit of GPA a student’s baseline GPA is higher than the mean we have to subtract 0.38 from the trajectory over time and vice versa for scores below the mean.
lme4 does not have a convenient way to check the significance of the random effects, but we can check it by comparing the model fit with and without a random effect specified. The random effect for the slope (on average the degree to which individual slopes differ from each other) is .004, but we can’t tell if that is significantly different from 0. So we will specify an new model with only a random intercept by removing the time variable from the parentheses. We need to use a new model name as well. Then we can see if adding the random effect significantly improved model fit.
<- lmer(GPA ~ Time +
UC_model_2 1 | StudentID), data = Assn_2_Data)
(
anova(UC_model, UC_model_2)
refitting model(s) with ML (instead of REML)
Data: Assn_2_Data
Models:
UC_model_2: GPA ~ Time + (1 | StudentID)
UC_model: GPA ~ Time + (1 + Time | StudentID)
npar AIC BIC logLik deviance Chisq Df Pr(>Chisq)
UC_model_2 4 401.65 422.01 -196.82 393.65
UC_model 6 258.23 288.77 -123.12 246.23 147.41 2 < 2.2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
The output indicates that the random variation in slopes is significant. The model AIC and BIC are both substantially lower for the random slope effects model and the chi-square difference test is significant. The key thing here is that because the intercepts and slopes have significant variation between participants we can try and model that variability with person level (level 2) predictors. In the conditional model below, participant sex, participant work level, and the interaction of sex by work are included as predictors of the initial GPA and the rate of change in GPA over time.
<- lmer(GPA ~ Time + Sex + Work + Time:Sex + Time:Work +
Cond_model 1 + Time | StudentID), data = Assn_2_Data)
(
# Summary of the model
summary(Cond_model)
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: GPA ~ Time + Sex + Work + Time:Sex + Time:Work + (1 + Time |
StudentID)
Data: Assn_2_Data
REML criterion at convergence: 95.7
Scaled residuals:
Min 1Q Median 3Q Max
-3.2310 -0.5353 0.0183 0.5296 2.8413
Random effects:
Groups Name Variance Std.Dev. Corr
StudentID (Intercept) 0.028691 0.1694
Time 0.002992 0.0547 -0.64
Residual 0.044290 0.2105
Number of obs: 816, groups: StudentID, 136
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 2.917670 0.247577 663.771899 11.785 <2e-16 ***
Time -0.008471 0.054129 690.942440 -0.157 0.8757
SexFemale 0.107903 0.044735 136.851572 2.412 0.0172 *
WorkPart-time -0.515520 0.246287 649.054112 -2.093 0.0367 *
WorkFull-time -0.634121 0.250559 657.980488 -2.531 0.0116 *
Time:SexFemale 0.027976 0.012860 136.504978 2.175 0.0313 *
Time:WorkPart-time 0.081672 0.053605 674.843050 1.524 0.1281
Time:WorkFull-time 0.086795 0.054932 686.010531 1.580 0.1146
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr) Time SexFml WrkPr- WrkFl- Tm:SxF Tm:WP-
Time -0.958
SexFemale -0.124 0.129
WorkPart-tm -0.991 0.949 0.030
WorkFull-tm -0.978 0.938 0.052 0.978
Time:SexFml 0.097 -0.158 -0.772 -0.024 -0.045
Tm:WrkPrt-t 0.954 -0.984 -0.033 -0.963 -0.941 0.034
Tm:WrkFll-t 0.935 -0.969 -0.059 -0.934 -0.960 0.063 0.969
Here we see that the intercept, which represents the baseline GPA when our predictors (sex and work) are at 0, so this represents the average GPA for males (sex = 0) and not working (work = 0) = 2.92. The average rate of change in GPA over time is no longer significant. The fixed effect for sex is significant meaning that on average female students had a GPA .11 units higher or (2.92 + 0.11) 3.03 at baseline. Working part-time (b=-0.51) and full-time (b=-0.63) were both significant predictors of the intercept relative to not working. Again we start with a baseline sample average GPA of 2.92. For students working part-time that initial GPA drops by .51 GPA units or a baseline average GPA of 2.41. Working full-time reduces the baseline even further (b=-0.63) for a baseline average GPA of 2.29.
Now looking at the slope we start with the average rate of change at -0.008, but for female students the average rate of change increases by (b=0.028) relative to males. In other words the average rate of change in GPA each year is (-0.008 + 0.028) = .02. We can then say that for female students they have an average GPA of 3.03 and it increases by .02 units every year. Neither part-time work or full-time work had a significant impact on the rate of change in GPA over time.
Modeling growth using an SEM framework
Next we can assess growth using a latent growth model or SEM approach. Before we can specify the growth model we need to rotate the data from long format to wide format. To save code and time I did this in SPSS and am just importing that data file directly from SPSS using the haven package.
library(haven)
<-read_sav("Assn_2_Data_Wide.sav") Assn_2_Data_Wide
Just like with the MLM, it is a good idea to start with an unconditional growth model. This is a highly constrained SEM with two latent variables, a latent intercept and a latent slope. The factor loadings for the intercept are all fixed to 1, because we need to borrow the scaling metric from the DV (GPA). These factor loadings cannot be changed because doing so would conflate real mean level changes overtime with changes in measurement scale over time. The latent slope factor loadings are where we include our index of time in the model. The factor loadings correspond to the number of time units from baseline for each wave. At baseline the factor loading is 0, because it is 0 time units from baseline, the second factor loading is 1 because it is one time unit (year) from baseline, the third factor loading is 2 because it is two time units from the baseline, etc. The model fit commands are the same as those used in SEM. Importantly, we can use FIML to handle missing data. The unconditional models will both have n=200 because sex is not included in either model and that is the only variable with missing data. However, there will be a sample size difference for the conditional models.
<-'
UC_LGC I=~ 1*GPA.1 + 1*GPA.2 + 1*GPA.3 + 1*GPA.4 + 1*GPA.5 + 1*GPA.6
S=~ 0*GPA.1 + 1*GPA.2 + 2*GPA.3 + 3*GPA.4 + 4*GPA.5 + 5*GPA.6
'
<- growth(UC_LGC, estimator= "ML", data=Assn_2_Data_Wide, mimic = "Mplus", missing = "FIML")
UC_LGC_fit summary(UC_LGC_fit, fit.measures = TRUE, standardized=TRUE)
lavaan 0.6-18 ended normally after 73 iterations
Estimator ML
Optimization method NLMINB
Number of model parameters 11
Number of observations 200
Number of missing patterns 1
Model Test User Model:
Test statistic 43.945
Degrees of freedom 16
P-value (Chi-square) 0.000
Model Test Baseline Model:
Test statistic 811.632
Degrees of freedom 15
P-value 0.000
User Model versus Baseline Model:
Comparative Fit Index (CFI) 0.965
Tucker-Lewis Index (TLI) 0.967
Robust Comparative Fit Index (CFI) 0.965
Robust Tucker-Lewis Index (TLI) 0.967
Loglikelihood and Information Criteria:
Loglikelihood user model (H0) -49.385
Loglikelihood unrestricted model (H1) -27.413
Akaike (AIC) 120.770
Bayesian (BIC) 157.052
Sample-size adjusted Bayesian (SABIC) 122.203
Root Mean Square Error of Approximation:
RMSEA 0.093
90 Percent confidence interval - lower 0.061
90 Percent confidence interval - upper 0.127
P-value H_0: RMSEA <= 0.050 0.016
P-value H_0: RMSEA >= 0.080 0.772
Robust RMSEA 0.093
90 Percent confidence interval - lower 0.061
90 Percent confidence interval - upper 0.127
P-value H_0: Robust RMSEA <= 0.050 0.016
P-value H_0: Robust RMSEA >= 0.080 0.772
Standardized Root Mean Square Residual:
SRMR 0.233
Parameter Estimates:
Standard errors Standard
Information Observed
Observed information based on Hessian
Latent Variables:
Estimate Std.Err z-value P(>|z|) Std.lv Std.all
I =~
GPA.1 1.000 0.187 0.552
GPA.2 1.000 0.187 0.553
GPA.3 1.000 0.187 0.558
GPA.4 1.000 0.187 0.568
GPA.5 1.000 0.187 0.535
GPA.6 1.000 0.187 0.471
S =~
GPA.1 0.000 0.000 0.000
GPA.2 1.000 0.057 0.170
GPA.3 2.000 0.114 0.342
GPA.4 3.000 0.172 0.522
GPA.5 4.000 0.229 0.656
GPA.6 5.000 0.286 0.721
Covariances:
Estimate Std.Err z-value P(>|z|) Std.lv Std.all
I ~~
S 0.002 0.002 1.565 0.118 0.232 0.232
Intercepts:
Estimate Std.Err z-value P(>|z|) Std.lv Std.all
I 2.598 0.018 141.886 0.000 13.923 13.923
S 0.106 0.005 20.317 0.000 1.862 1.862
Variances:
Estimate Std.Err z-value P(>|z|) Std.lv Std.all
.GPA.1 0.080 0.010 8.049 0.000 0.080 0.696
.GPA.2 0.071 0.008 8.518 0.000 0.071 0.621
.GPA.3 0.054 0.006 9.020 0.000 0.054 0.483
.GPA.4 0.029 0.003 8.486 0.000 0.029 0.268
.GPA.5 0.015 0.003 5.589 0.000 0.015 0.121
.GPA.6 0.016 0.004 4.336 0.000 0.016 0.100
I 0.035 0.007 4.937 0.000 1.000 1.000
S 0.003 0.001 5.593 0.000 1.000 1.000
The results of this model indicate that a linear growth model provides an adequate fit to the data [ \(\chi^2\) (16) = 43.95, p<.001, CFI = .96, TLI = .96, RMSEA = .09, SRMR = .233]. It is notable that the \(\chi^2\) , CFI, and TLI do not align with the RMSEA and SRMR, particularly the latter - one common reason for this is that the SRMR and to a lesser extent the RMSEA work well for estimating fit of the model to the variance/covariance matrix, but do not take into account the mean structure, which often causes them to produce erroneous misfit information (see also, Full article: The Problem with Having Two Watches: Assessment of Fit When RMSEA and CFI Disagree)
Similar to the MLM model we see that the sample average GPA at baseline is 2.59 and the sample average rate of change is 0.11 GPA units per year. These values are the same as the MLM unconditional model
What we are really looking for in this model is the fact that, just like the unconditional MLM, there is significant variability in the intercept (\(\sigma^2\) = .035) and slope ( \[\sigma^2\] = .003) factors. It makes logical sense then to add predictors to see if they account for that variability. We can specify this conditional model by adding code to regress sex and work onto the Intercept and Slope variables.
<-'
Cond_LGC I=~ 1*GPA.1 + 1*GPA.2 + 1*GPA.3 + 1*GPA.4 + 1*GPA.5 + 1*GPA.6
S=~ 0*GPA.1 + 1*GPA.2 + 2*GPA.3 + 3*GPA.4 + 4*GPA.5 + 5*GPA.6
I ~ Sex + Work
S ~ Sex + Work
'
<- growth(Cond_LGC, estimator= "ML", data=Assn_2_Data_Wide, mimic = "Mplus", missing = "FIML")
Cond_LGC_fit summary(Cond_LGC_fit, fit.measures = TRUE, standardized=TRUE)
lavaan 0.6-18 ended normally after 79 iterations
Estimator ML
Optimization method NLMINB
Number of model parameters 15
Number of observations 200
Number of missing patterns 1
Model Test User Model:
Test statistic 64.422
Degrees of freedom 24
P-value (Chi-square) 0.000
Model Test Baseline Model:
Test statistic 993.679
Degrees of freedom 27
P-value 0.000
User Model versus Baseline Model:
Comparative Fit Index (CFI) 0.958
Tucker-Lewis Index (TLI) 0.953
Robust Comparative Fit Index (CFI) 0.958
Robust Tucker-Lewis Index (TLI) 0.953
Loglikelihood and Information Criteria:
Loglikelihood user model (H0) 31.400
Loglikelihood unrestricted model (H1) NA
Akaike (AIC) -32.800
Bayesian (BIC) 16.675
Sample-size adjusted Bayesian (SABIC) -30.846
Root Mean Square Error of Approximation:
RMSEA 0.092
90 Percent confidence interval - lower 0.065
90 Percent confidence interval - upper 0.119
P-value H_0: RMSEA <= 0.050 0.007
P-value H_0: RMSEA >= 0.080 0.781
Robust RMSEA 0.092
90 Percent confidence interval - lower 0.065
90 Percent confidence interval - upper 0.119
P-value H_0: Robust RMSEA <= 0.050 0.007
P-value H_0: Robust RMSEA >= 0.080 0.781
Standardized Root Mean Square Residual:
SRMR 0.160
Parameter Estimates:
Standard errors Standard
Information Observed
Observed information based on Hessian
Latent Variables:
Estimate Std.Err z-value P(>|z|) Std.lv Std.all
I =~
GPA.1 1.000 0.189 0.576
GPA.2 1.000 0.189 0.556
GPA.3 1.000 0.189 0.565
GPA.4 1.000 0.189 0.575
GPA.5 1.000 0.189 0.541
GPA.6 1.000 0.189 0.483
S =~
GPA.1 0.000 0.000 0.000
GPA.2 1.000 0.059 0.172
GPA.3 2.000 0.117 0.350
GPA.4 3.000 0.176 0.535
GPA.5 4.000 0.234 0.670
GPA.6 5.000 0.293 0.749
Regressions:
Estimate Std.Err z-value P(>|z|) Std.lv Std.all
I ~
Sex 0.148 0.019 7.626 0.000 0.781 0.634
Work -0.144 0.048 -3.020 0.003 -0.760 -0.251
S ~
Sex 0.037 0.006 6.215 0.000 0.627 0.509
Work 0.028 0.015 1.897 0.058 0.470 0.155
Covariances:
Estimate Std.Err z-value P(>|z|) Std.lv Std.all
.I ~~
.S -0.001 0.001 -0.921 0.357 -0.193 -0.193
Intercepts:
Estimate Std.Err z-value P(>|z|) Std.lv Std.all
.I 2.610 0.113 23.158 0.000 13.806 13.806
.S -0.024 0.034 -0.711 0.477 -0.417 -0.417
Variances:
Estimate Std.Err z-value P(>|z|) Std.lv Std.all
.GPA.1 0.072 0.009 7.961 0.000 0.072 0.669
.GPA.2 0.073 0.008 8.645 0.000 0.073 0.629
.GPA.3 0.055 0.006 9.097 0.000 0.055 0.492
.GPA.4 0.030 0.004 8.599 0.000 0.030 0.279
.GPA.5 0.017 0.003 6.110 0.000 0.017 0.136
.GPA.6 0.013 0.003 3.734 0.000 0.013 0.083
.I 0.018 0.005 3.374 0.001 0.502 0.502
.S 0.003 0.000 5.045 0.000 0.733 0.733
The overall model fit is adequate [ \(\chi^2\) (24) = 64.42, p <.001; CFI = .96, TLI = .95, RMSEA = .09, SRMR = .16] with the caveat that the RMSEA and SRMR are inconsistent with the rest of the fit statistics. For this model the sample average intercept for males (sex = 0) and non-working students (work = 0) is 2.61 and the average rate of change for non-working male students is -0.024. These are a bit different than the MLM model, however, the MLM estimates were based on a sample size of 136 and the LGC model estimates are based on a sample size of 200. But they are still in the same ballpark. Female students have a significantly higher baseline GPA than male students (b = .148) with an average GPA of (2.61 + .148) = 2.76. Similarly work status is also significant for the intercept, reducing the baseline GPA by -0.144 for part-time workers (GPA = 2.46) and -.288 for full-time workers (GPA = 2.32). This is based on the work variable being coded 0,1,2 - to be more explicit you could dummy code the work status variable. Being female increases the rate of change in GPA overtime significantly (b=.037) so the female rate of change would be -0.024 + .037 = .013 GPA units per year. Work status does not influence the rate of change in GPA over time, just like in the MLM version.