Setup

library(pacman)
p_load(lavaan, semPlot, ggplot2, psych, efast)
#Correlation matrices

lowerEUR = '
1                                           
0.624   1                                       
0.641   0.687   1                                   
0.198   0.333   0.252   1                               
0.119   0.229   0.19    0.368   1                           
0.307   0.427   0.452   0.494   0.403   1                       
0.29    0.22    0.219   0.021   0.11    0.145   1                   
0.238   0.279   0.188   0.05    0.097   0.114   0.578   1               
0.217   0.157   0.217   0.037   0.093   0.199   0.625   0.635   1           
0.051   0.189   0.125   0.206   0.357   0.35    0.139   0.108   0.187   1       
0.073   0.143   0.131   0.126   0.326   0.331   0.266   0.191   0.296   0.521   1   
0.139   0.167   0.132   0.073   0.217   0.32    0.186   0.214   0.236   0.497   0.662   1'

lowerAFR = '
1                                           
0.614   1                                       
0.668   0.665   1                                   
0.161   0.317   0.227   1                               
0.137   0.243   0.224   0.33    1                           
0.373   0.537   0.525   0.478   0.402   1                       
0.361   0.32    0.297   0.067   0.097   0.131   1                   
0.218   0.253   0.268   -0.026  -0.004  0.093   0.523   1               
0.196   0.25    0.242   0.069   0.017   0.121   0.582   0.698   1           
0.02    0.167   0.154   0.2 0.266   0.235   0.108   0.072   0.151   1       
0.06    0.093   0.17    -0.044  0.228   0.194   0.179   0.221   0.25    0.411   1   
0.114   0.131   0.198   -0.054  0.22    0.257   0.121   0.125   0.166   0.356   0.686   1'

#Variable names

Names = list("I1", "I2", "I3", "I4", "I5", "I6", "I7", "I8", "I9", "I10", "I11", "I12")

#Convert to variance-covariance matrices

EUR.cor = getCov(lowerEUR, names = Names)
AFR.cor = getCov(lowerAFR, names = Names)
EURSDs <- c(1.5, 1.48, 1.51, 1.88, 1.74, 1.66, 1.29, 1.26, 1.34, 1.64, 1.59, 1.59)
AFRSDs <- c(1.63, 1.63, 1.54, 1.88, 1.79, 1.68, 1.33, 1.19, 1.35, 1.71, 1.59, 1.61)
EUR.cov = lavaan::cor2cov(R = EUR.cor, sds = EURSDs)
AFR.cov = lavaan::cor2cov(R = AFR.cor, sds = AFRSDs)

#Means

EURmeans = c(5.25, 5.21, 4.93, 4.45, 4.48, 3.91, 5.27, 5.77, 5.29, 4.36, 3.96, 3.65)
AFRmeans = c(5.2, 5.09, 4.85, 4.62, 4.65, 3.98, 5.25, 5.81, 5.31, 4.09, 3.71, 3.44)

#Group inputs

GCovs <- list(EUR.cov, AFR.cov)
GMeans <- list(EURmeans, AFRmeans)
GNs <- list(350, 317)

#Fit measures

FITM <- c("chisq", "df", "nPar", "cfi", "rmsea", "rmsea.ci.lower", "rmsea.ci.upper", "aic", "bic")

#For plotting

LATS <- list(
  PAP = c("I1", "I2", "I3"),
  PAV = c("I4", "I5","I6"),
  MAP = c("I7", "I8", "I9"),
  MAV = c("I10", "I11", "I12"))

Background

The Modified Achievement Goal Questionnaire (AGQ-M) is intended to measure achievement goal orientation. It theoretically features four dimensions described by Campbell et al. (2008) as follows:

Under this new framework, mastery-approach (MAP) orientation refers to the goal of developing competence, which is evaluated using absolute or intrapersonal standards of competence. Mastery-avoidance (MAV) orientation refers to the goal of avoiding misunderstanding, which is evaluated using absolute or intrapersonal standards of competence. Performance-approach (PAP) orientation refers to the goal of striving to be superior to or better than others on a task, which is evaluated using normative or interpersonal standards of competence. Finally, performance-avoidance (PAV) refers to the goal of avoiding inferiority or not being the worst on a task, which is evaluated using normative or interpersonal standards of competence.

Campbell et al. (2008) aimed to test if the AGQ-M was invariant, and thus suitable for use, by race, in African- and European-American university students. To note, the sample may be selected on achievement orientation. Nonetheless, they ended up with 317 African- and almost 8,000 European-American students’ results. To avoid issues with relatively group sizes, they randomly selected 350 European-American students to form their sample. This probably should not have been done because if strict factorial invariance holds, relatively group sizes do not matter. But they did not test strict factorial invariance. In fact, they only tested to scalar invariance. This is a bit worrying because it still leaves open the possibility that the influences on achievement goal orientation could differ by ethnic group. With that in mind, I went ahead and tested everything below.

Model Testing

MGCFA

#Correlated group factor model from the paper

MAQM.model <- '
PAP =~ I1 + I2 + I3
PAV =~ I4 + I5 + I6
MAP =~ I7 + I8 + I9
MAV =~ I10 + I11 + I12'

# Plot

MAQE.fit <- cfa(MAQM.model, sample.cov = EUR.cov, sample.nobs = 350, std.lv = T, orthogonal = F)

semPaths(MAQE.fit, "model", "std", title = F, residuals = F, groups = "LATS", pastel = T, mar = c(2, 1, 3, 1))

# Multiple-group

MAQMC.fit <- cfa(MAQM.model, sample.cov = GCovs, sample.mean = GMeans, sample.nobs = GNs, std.lv = T, orthogonal = F)

MAQMM.fit <- cfa(MAQM.model, sample.cov = GCovs, sample.mean = GMeans, sample.nobs = GNs, std.lv = F, orthogonal = F, group.equal = "loadings")

MAQMS.fit <- cfa(MAQM.model, sample.cov = GCovs, sample.mean = GMeans, sample.nobs = GNs, std.lv = F, orthogonal = F, group.equal = c("loadings", "intercepts"))

MAQMF.fit <- cfa(MAQM.model, sample.cov = GCovs, sample.mean = GMeans, sample.nobs = GNs, std.lv = F, orthogonal = F, group.equal = c("loadings", "intercepts", "residuals"))

MAQMLV.fit <- cfa(MAQM.model, sample.cov = GCovs, sample.mean = GMeans, sample.nobs = GNs, std.lv = T, orthogonal = F, group.equal = c("loadings", "intercepts", "residuals"))

MAQMLA.fit <- cfa(MAQM.model, sample.cov = GCovs, sample.mean = GMeans, sample.nobs = GNs, std.lv = T, orthogonal = F, group.equal = c("loadings", "intercepts", "residuals", "means"))

round(cbind(CONFIGURAL = fitMeasures(MAQMC.fit, FITM),
            METRIC = fitMeasures(MAQMM.fit, FITM),
            SCALAR = fitMeasures(MAQMS.fit, FITM),
            STRICT = fitMeasures(MAQMF.fit, FITM),
            LVARS = fitMeasures(MAQMLV.fit, FITM),
            MEANS = fitMeasures(MAQMLA.fit, FITM)), 3)
##                CONFIGURAL    METRIC    SCALAR    STRICT     LVARS     MEANS
## chisq             262.760   271.008   274.434   294.406   294.406   305.088
## df                 96.000   104.000   112.000   124.000   124.000   128.000
## npar               84.000    76.000    68.000    56.000    56.000    52.000
## cfi                 0.945     0.945     0.946     0.944     0.944     0.941
## rmsea               0.072     0.069     0.066     0.064     0.064     0.064
## rmsea.ci.lower      0.062     0.059     0.056     0.055     0.055     0.055
## rmsea.ci.upper      0.083     0.080     0.076     0.074     0.074     0.074
## aic             26944.548 26936.797 26924.222 26920.195 26920.195 26922.877
## bic             27322.783 27279.009 27230.412 27172.351 27172.351 27157.022

Fit Plots

df <- data.frame("FIT" = c(fitMeasures(MAQMC.fit, "bic") - fitMeasures(MAQMC.fit, "bic"), fitMeasures(MAQMM.fit, "bic") - fitMeasures(MAQMC.fit, "bic"), fitMeasures(MAQMS.fit, "bic") - fitMeasures(MAQMC.fit, "bic"), fitMeasures(MAQMF.fit, "bic") - fitMeasures(MAQMC.fit, "bic"), fitMeasures(MAQMLA.fit, "bic") - fitMeasures(MAQMC.fit, "bic"), fitMeasures(MAQMC.fit, "aic") - fitMeasures(MAQMC.fit, "aic"), fitMeasures(MAQMM.fit, "aic") - fitMeasures(MAQMC.fit, "aic"), fitMeasures(MAQMS.fit, "aic") - fitMeasures(MAQMC.fit, "aic"), fitMeasures(MAQMF.fit, "aic") - fitMeasures(MAQMC.fit, "aic"), fitMeasures(MAQMLA.fit, "aic") - fitMeasures(MAQMC.fit, "aic")), "Model" = c("Configural", "Metric", "Scalar", "Strict", "Mean Homogeneity"), "LM" = c("BIC", "BIC", "BIC", "BIC", "BIC", "AIC", "AIC", "AIC", "AIC", "AIC"))

df
df$Model <- factor(df$Model, levels = c("Configural", "Metric", "Scalar", "Strict", "Mean Homogeneity"))
ggplot(df, aes(x = Model, y = FIT, group = LM, shape = LM, color = LM)) + geom_line() + geom_point() + xlab("Level of Invariance") + ylab("Value") + scale_colour_discrete(name = "Information Criteria", breaks = c("AIC", "BIC"), labels = c("Akaike", "Schwarz"), c = 60) + scale_shape_discrete(name = "Factor Model", breaks = c("Akaike", "Schwarz"), labels = c("AIC", "BIC")) + theme_bw() + theme(text = element_text(size = 12, family = "serif"))

General Model?

MAQHOF.model <- '
PAP =~ I1 + I2 + I3
PAV =~ I4 + I5 + I6
MAP =~ I7 + I8 + I9
MAV =~ I10 + I11 + I12

GAM =~ PAP + PAV + MAP + MAV'

MAQBF.model <- '
PAP =~ I1 + I2 + I3
PAV =~ I4 + I5 + I6
MAP =~ I7 + I8 + I9
MAV =~ I10 + I11 + I12

GAM =~ I1 + I2 + I3 + I4 + I5 + I6 + I7 + I8 + I9 + I10 + I11 + I12

I4 ~~ 1*I4' #negative residual variance constraint

MAQE2.fit <- cfa(MAQHOF.model, sample.cov = EUR.cov, sample.nobs = 350, std.lv = T, orthogonal = F)

MAQE3.fit <- cfa(MAQBF.model, sample.cov = EUR.cov, sample.nobs = 350, std.lv = T, orthogonal = T)

round(cbind(CGF = fitMeasures(MAQE.fit, FITM),
            HOF = fitMeasures(MAQE2.fit, FITM),
            BF = fitMeasures(MAQE3.fit, FITM)),3)
##                      CGF       HOF        BF
## chisq            126.370   161.673   136.819
## df                48.000    50.000    43.000
## npar              30.000    28.000    35.000
## cfi                0.951     0.930     0.941
## rmsea              0.068     0.080     0.079
## rmsea.ci.lower     0.054     0.066     0.064
## rmsea.ci.upper     0.083     0.094     0.094
## aic            13998.603 14029.906 14019.052
## bic            14114.341 14137.928 14154.080

Discussion

The results are as follows:

  1. The four-factor structure was fine. It actually performed better than a higher-order general factor structure, and if \(\omega_hs\) is calculated alongside \(\omega_h\), we can actually see good evidence for distinct dimensions! Given how rare that is, that’s a very exciting find and a sign that the makers of the AGQ-M did an excellent job that yielded structural fidelity for their theory. I do not often get to say that. A bifactor model was incoherent and led to errors without modification and showed evidence against unidimensionality. Perhaps one could be modeled as a method factor, but it’s not necessary.

  2. Encouragingly and in a clear extension of Campbell et al.’s (2008) results, invariance was achieved, and not only at the level of SFI, but all the way to mean homogeneity. A substantive restatement of these results would be as follows: there are no black-white differences in whatever the AGQ-M measures in samples of university students.

Generalization to other populations should be tested. Most importantly, this adds more support for the attitude-achievement paradox, or something like it. At least among black and white university students in the US, it may be the case that culture is irrelevant, or at least that the cultural backgrounds of the people in this sample were so similar that it was irrelevant. Even if it affected the factor means and variances directly, there were neither mean nor latent variance differences.

References

Campbell, H. L., Barry, C. L., Joe, J. N., & Finney, S. J. (2008). Configural, metric, and scalar invariance of the modified achievement goal questionnaire across African American and white university students. Educational and Psychological Measurement, 68(6), 988–1007. https://doi.org/10.1177/0013164408315269

Supplement: EFA in Lavaan

The new (and great) efast package actually makes this easier than ever before.

EFA <- '
  efa("x4") * F1 +
  efa("x4") * F2 +
  efa("x4") * F3 +
  efa("x4") * F4 =~ I1 + I2 + I3 + I4 + I5 + I6 + I7 + I8 + I9 + I10 + I11 + I12'

EFAAGMQ <- lavaan(model = EFA, sample.cov = EUR.cov, sample.nobs = 350, auto.var = TRUE, auto.efa = TRUE)

#summary(EFAAGMQ, stand = T, fit = T)
inspect(EFAAGMQ, what="std")$lambda
##         F1     F2     F3     F4
## I1   0.804 -0.112  0.054  0.010
## I2   0.775  0.118 -0.013 -0.012
## I3   0.820  0.043 -0.016 -0.006
## I4   0.013  0.790 -0.003 -0.301
## I5  -0.038  0.577  0.023  0.038
## I6   0.221  0.622  0.008  0.023
## I7   0.058 -0.035  0.739  0.019
## I8   0.038 -0.012  0.761 -0.035
## I9  -0.060  0.046  0.841  0.012
## I10 -0.021  0.310 -0.011  0.475
## I11  0.002  0.125  0.064  0.744
## I12  0.127 -0.021 -0.023  0.804
PFA <- fa(EUR.cor, n.obs = 350, nfactors = 4, rotate = "geominQ")
## Loading required namespace: GPArotation
print(PFA$loadings)
## 
## Loadings:
##     MR2    MR3    MR1    MR4   
## I1   0.792                     
## I2   0.761                0.136
## I3   0.823                     
## I4                -0.255  0.772
## I5                        0.559
## I6   0.229                0.597
## I7          0.740              
## I8          0.764              
## I9          0.834              
## I10                0.505  0.290
## I11                0.759  0.103
## I12  0.114         0.813       
## 
##                  MR2   MR3   MR1   MR4
## SS loadings    1.961 1.838 1.571 1.392
## Proportion Var 0.163 0.153 0.131 0.116
## Cumulative Var 0.163 0.317 0.448 0.564
FFA <- efast_efa(data = EUR.cor, sample.nobs = 350, M = 4)
## Warning in lavData(data = data, group = group, cluster = cluster, ov.names =
## OV.NAMES, : lavaan WARNING: std.ov argument is ignored if only sample statistics
## are provided.
efast_loadings(FFA)
## 
## Loadings:
##     F1     F2     F3     F4    
## I1   0.796                     
## I2   0.771  0.124              
## I3   0.815                     
## I4          0.769        -0.244
## I5          0.551              
## I6   0.225  0.598              
## I7                 0.737       
## I8                 0.760       
## I9                 0.839       
## I10         0.278         0.508
## I11                       0.766
## I12  0.104                0.816
## 
##                   F1    F2    F3    F4
## SS loadings    1.964 1.371 1.834 1.584
## Proportion Var 0.164 0.114 0.153 0.132
## Cumulative Var 0.164 0.278 0.431 0.563