Very much a work-in-progress.

Setup

Packages

library(pacman)
p_load(kirkegaard, dplyr, psych, lavaan, semPlot, umx)

Functions

#From Gunn, Grimm & Edwards (2019)

SDI2.UDI2 = function(p, loading1, loading2, intercept1, intercept2, stdev2, fmean2, fsd2, nodewidth = 0.01, lowerLV = -5, upperLV = 5) {
   LV = seq(lowerLV,upperLV,nodewidth)
   DiffExpItem12 = matrix(NA,length(LV),p)
   pdfLV2 = matrix(NA,length(LV),1)
   SDI2numerator = matrix(NA,length(LV),p)
   UDI2numerator = matrix(NA,length(LV),p)
   SDI2 = matrix(NA,p,1)
   UDI2 = matrix(NA,p,1)
   for(j in 1:p){
    for(k in 1:length(LV)){
      DiffExpItem12[k,j] <- (intercept1[j]-intercept2[j]) + (loading1[j]-loading2[j])*LV[k]
      pdfLV2[k] = dnorm(LV[k], mean=fmean2, sd=fsd2)
      SDI2numerator[k,j] = DiffExpItem12[k,j]*pdfLV2[k]*nodewidth
      UDI2numerator[k,j] = abs(SDI2numerator[k,j])
    }
    SDI2[j] <- sum(SDI2numerator[,j])/stdev2[j]
    UDI2[j] <- sum(UDI2numerator[,j])/stdev2[j]
   }
  colnames(SDI2) = "SDI2"
  colnames(UDI2) = "UDI2"
  return(list(SDI2=round(SDI2,4), UDI2=round(UDI2,4)))}

#Based on Naaman (2016)

NZ <- function(N, S) {
  NZ = qnorm(1-(N^-(6/5))/S) #'1-' included instead of 'abs()'; change it if you don't like it
  return(NZ)}

#Based on work from Millsap & Olivera-Aguilar (2012); also works for intercepts

MOES <- function(T1, T2, S1, S2) {
  ES = (T1 - T2) / (S1^2 - S2^2)
  return(ES)}

Data

Too large for DT :( - you can get the data at the osf.

#VES <- read.csv(".../VES_dataset.csv")

VES %<>% rename(
  WBD = WAIS_BD, #WAIS Block Design
  WGI = WAIS_GI, #WAIS General Information
  GPTR = GPT_right, #Grooved Pegboard Task - Right Hand
  GPTL = GPT_left, #Grooved Pegboard Task - Left Hand
  CD = copy_direct, #Rey-Osterrieth Complex Figure Drawing - Direct, i.e., in sight
  CI = copy_immediate, #Complex Figure Drawing - Immediate(ly after removal from sight)
  CY = copy_delayed, #Complex Figure Drawing - Delayed, i.e., asked to draw the figure after time has passed from viewing
  ACVE = ACB_verbal_early, #Army Classification Battery Verbal subtest administered at introduction
  ACVL = ACB_verbal_later, #Verbal subtest administered at follow-up
  ACAE = ACB_arithmetic_early, #Arithmetic subtest administered at introduction
  ACAL = ACB_arithmetic_later) #Arithmetic subtest administered at follow-up

VES$CC = (standardize(VES$CI) + standardize(VES$CY))/2 #Very similar, which unnecessarily harms path model fit.

early_tests = c("ACVE", "ACAE", "PA", "GIT", "AFQT") #Tests taken at introduction
later_tests = c("WRAT", "CVLT", "WCST", "WBD", "WGI", "GPTR", "GPTL", "PASAT", "CD", "CC", "WLGT", "ACVL", "ACAL") #Tests taken at follow-up. Unlisted above are the Wisconsin Card Sorting Test (WCST), California Verbal Learning Test (CVLT), Wide-Range Achievement Test (WRAT), Word List Generation Test (WLGT), and Paced Auditory Serial Addition Test (PASAT)
tests = c(early_tests, later_tests) #All tests

#Model fit measures

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

Rationale

Replication of Ritchie, Bates & Deary (2015) including measurement invariance assessment (MI) via (1) MGCFA; (2) LSEM; (3) MNLFA. Current upload (24/5/2020) is just the headline result and replication, not the additional analyses, which include testing MI, gains to the sumscore, comparisons of apparent and real effects on \(g\), assessment of the (lack of) relationship of education with sensory measures, computation of whether residual variances change for more educated groups as expected under an effect model, and computation of “economic gains” (increased income) due to education and their (lack of) mediation by cognitive improvement. More analyses may be performed if I think of them or people care. This dataset will also be used to compare factor and network models and at that point network effects of education will be assessed (see: Fried; note: add cites).

Analysis

#describe(VES) <- too long to look good with chosen theme. 

Path Model

Five tests were administered at entrance and an additional 15 at follow-up. Two of these - the immediated and delayed Rey-Osterrieth Complex Figure Drawing tasks - are highly intercorrelated and specific, so they’ve been combined (see ‘Data’ above), leaving us with 18 items where \(\mu = 100, \sigma = 15\). For this initial analysis and upload, I’ll output the three models Ritchie, Bates & Deary (2015) assessed. Briefly, these are (A) education effects only on \(g\); (B) education effects on both \(g\) and individual subtests, and; (C) education effects solely relegated to individual subtests.

The variable in the path models below, ‘\(gl\)’, corresponds to the general factor of intelligence measured at follow-up, and ‘\(ge\)’ is the same variable measured at induction into the study. \(ge\) is regressed on \(gl\) rather than being covaried with it because it is the temporally antecedent form of the same construct. The rest should be common sense but anyone legitimately struggling with them can send me an email or read the VES documentation.

The first model assesses merely how correlated the \(g\) factors from the different timepoints are. Initial testing occurred at approximately high school graduation (i.e., ~18 years-of-age) and follow-up occurred around age 35. The same tests administered at both time-points (from the ACB) are residually covaried for goodness-of-fit and the substantive reason that they’re the same tests, and as such expected to share method/test/item variance. Because group factors are not modeled and the battery is large, the fit is poor, so a handful of residual covariances (selected if modification indices met or exceeded 100) are allowed, although the full analysis will include group factors. It is debatable whether other residual covariances should be allowed between early and later subtests; in the model below, four are allowed; they are substantively inconsequential.

GCOR.model<-'

ge =~ ACVE + ACAE + AFQT + GIT + PA

gl =~ WRAT + CVLT + WCST + WBD + WGI + CD + CC + PASAT + GPTL + GPTR + WLGT + ACVL + ACAL

ge ~ gl

ACVE ~~ ACVL
ACAE ~~ ACAL
CD ~~ CC
GPTL ~~ GPTR

ACVE ~~ WRAT 
AFQT ~~ PA + WBD
PA ~~ WBD + CC
WRAT ~~ WGI + WLGT + ACVL
CC ~~ CVLT + WBD
WGI ~~ PASAT'

GCOR.fit <- sem(GCOR.model, data = VES, std.lv=T)

parameterEstimates(GCOR.fit, stand = T) %>% 
  filter(op == "~") %>% 
  dplyr::select(Early = lhs, Later = rhs, "Unstandardized Regression" = est, SE = se, Z = z, 'p-value' = pvalue, Beta = std.all) %>% 
  kable(digits = 3, format = "pandoc")
Early Later Unstandardized Regression SE Z p-value Beta
ge gl 2.88 0.086 33.7 0 0.945

The stability of the \(g\) factor over time is considerable (\(r = 0.945\)).

A.model <- '
ge =~ ACVE + ACAE + AFQT + GIT + PA

gl =~ WRAT + CVLT + WCST + WBD + WGI + CD + CC + PASAT + GPTL + GPTR + WLGT + ACVL + ACAL

ge ~ gl + education

gl ~ education

ACVE ~~ ACVL
ACAE ~~ ACAL
CD ~~ CC
GPTL ~~ GPTR

ACVE ~~ WRAT 
AFQT ~~ PA + WBD
PA ~~ WBD + CC
WRAT ~~ WGI + WLGT + ACVL
CC ~~ CVLT + WBD
WGI ~~ PASAT'

B.model <- '
ge =~ ACVE + ACAE + AFQT + GIT + PA

gl =~ WRAT + CVLT + WCST + WBD + WGI + CD + CC + PASAT + GPTL + GPTR + WLGT + ACVL + ACAL

gl + education ~ ge

gl + WRAT + CVLT + WCST + WBD + WGI + CD + CC + PASAT + GPTL + GPTR + WLGT + ACVL + ACAL ~ education

ACVE ~~ ACVL
ACAE ~~ ACAL
CD ~~ CC
GPTL ~~ GPTR

ACVE ~~ WRAT 
AFQT ~~ PA + WBD
PA ~~ WBD + CC
WRAT ~~ WGI + WLGT + ACVL
CC ~~ CVLT + WBD
WGI ~~ PASAT'

C.model <- '
ge =~ ACVE + ACAE + AFQT + GIT + PA

gl =~ WRAT + CVLT + WCST + WBD + WGI + CD + CC + PASAT + GPTL + GPTR + WLGT + ACVL + ACAL

gl + education ~ ge

WRAT + CVLT + WCST + WBD + WGI + CD + CC + PASAT + GPTL + GPTR + WLGT + ACVL + ACAL ~ education

ACVE ~~ ACVL
ACAE ~~ ACAL
CD ~~ CC
GPTL ~~ GPTR

ACVE ~~ WRAT 
AFQT ~~ PA + WBD
PA ~~ WBD + CC
WRAT ~~ WGI + WLGT + ACVL
CC ~~ CVLT + WBD
WGI ~~ PASAT'

A.fit <- sem(A.model, data = VES, std.lv = T)
B.fit <- sem(B.model, data = VES, std.lv = T)
C.fit <- sem(C.model, data = VES, std.lv = T)

round(cbind(JUSTG = fitMeasures(A.fit, FITM),
            GPLUS = fitMeasures(B.fit, FITM),
            JUSTS = fitMeasures(C.fit, FITM)), 3)
                    JUSTG      GPLUS      JUSTS
chisq            2456.636   2154.666   2154.667
df                135.000    122.000    123.000
npar               54.000     68.000     67.000
cfi                 0.952      0.958      0.958
rmsea               0.063      0.062      0.062
rmsea.ci.lower      0.061      0.060      0.060
rmsea.ci.upper      0.065      0.064      0.064
aic            595165.045 614311.103 614309.103
bic            595509.054 614744.300 614735.930

It appears that model C - effects on specific subtests - fits best. At this point, it’s appropriate to look at A, B, and C, to see if they show any signs of misfit like Heywood cases.

parameterEstimates(A.fit, stand = T) %>% 
  filter(op == "~") %>% 
  dplyr::select(Dependent = lhs, Independent = rhs, "Unstandardized Regression" = est, SE = se, Z = z, 'p-value' = pvalue, Beta = std.all) %>% 
  kable(digits = 3, format = "pandoc")
Dependent Independent Unstandardized Regression SE Z p-value Beta
ge gl 2.305 0.071 32.37 0.000 0.934
ge education 0.026 0.013 2.05 0.041 0.019
gl education 0.322 0.008 39.29 0.000 0.594
parameterEstimates(B.fit, stand = T) %>% 
  filter(op == "~") %>% 
  dplyr::select(Dependent = lhs, Independent = rhs, "Unstandardized Regression" = est, SE = se, Z = z, 'p-value' = pvalue, Beta = std.all) %>% 
  kable(digits = 3, format = "pandoc")
Dependent Independent Unstandardized Regression SE Z p-value Beta
gl ge 2.79 NA NA NA 0.431
education ge 1.30 NA NA NA 0.566
gl education 1.91 NA NA NA 0.678
WRAT education -5.40 NA NA NA -0.833
CVLT education -4.31 NA NA NA -0.659
WCST education -4.33 NA NA NA -0.663
WBD education -6.43 NA NA NA -0.997
WGI education -5.33 NA NA NA -0.815
CD education -4.35 NA NA NA -0.679
CC education -4.97 NA NA NA -0.771
PASAT education -6.00 NA NA NA -0.919
GPTL education -2.90 NA NA NA -0.450
GPTR education -3.23 NA NA NA -0.495
WLGT education -3.54 NA NA NA -0.542
ACVL education -7.41 NA NA NA -1.140
ACAL education -7.62 NA NA NA -1.169
parameterEstimates(C.fit, stand = T) %>% 
  filter(op == "~") %>% 
  dplyr::select(Dependent = lhs, Independent = rhs, "Unstandardized Regression" = est, SE = se, Z = z, 'p-value' = pvalue, Beta = std.all) %>% 
  kable(digits = 3, format = "pandoc")
Dependent Independent Unstandardized Regression SE Z p-value Beta
gl ge 2.789 0.086 32.550 0.000 0.941
education ge 1.297 0.033 38.773 0.000 0.566
WRAT education 0.911 0.080 11.442 0.000 0.140
CVLT education -0.137 0.112 -1.228 0.219 -0.021
WCST education 0.026 0.110 0.233 0.816 0.004
WBD education -0.269 0.088 -3.041 0.002 -0.042
WGI education 1.284 0.082 15.716 0.000 0.196
CD education -0.142 0.109 -1.302 0.193 -0.022
CC education -0.247 0.106 -2.320 0.020 -0.038
PASAT education -0.120 0.103 -1.169 0.242 -0.018
GPTL education -0.012 0.114 -0.109 0.913 -0.002
GPTR education -0.189 0.115 -1.636 0.102 -0.029
WLGT education 0.725 0.106 6.827 0.000 0.111
ACVL education 0.343 0.067 5.086 0.000 0.053
ACAL education 0.208 0.072 2.869 0.004 0.032

B is unidentified, which is unsurprising given that \(ge\) is a latent variable. The residualized models section (which includes models with \(ge\) as an observed variable/everything residualized for \(ge\), etc.) includes assessments of what this does. It does not change the qualitative result. It appears that B generates two negative ultra-Heywood cases with ACVL and ACAL, so I’ll prune these. Moreover, I’ll prune the insignificant paths in C. There is nothing to change about the A result (yet).

It appears that model B is misspecified thanks to the appearance of an ultra-Heywood case between education and \(gl\), where it’s extremely negatively associated with it (\(\Beta = -1.239\)). The only model making any sense at present is model A, since all of its paths remained significant. However, at this sample size, \(p = 0.04\) is actually evidence against a significant effect of \(ge\) on educational attainment due to Lindley’s paradox. With these caveats in mind, I will prune the insignificant paths to subtests for B and C and retain the path to \(gl\) from education in B.

B2.model <- '
ge =~ ACVE + ACAE + AFQT + GIT + PA

gl =~ WRAT + CVLT + WCST + WBD + WGI + CD + CC + PASAT + GPTL + GPTR + WLGT + ACVL + ACAL

gl + education ~ ge

gl + WRAT + CVLT + WCST + WBD + WGI + CD + CC + PASAT + GPTL + GPTR + WLGT ~ education

ACVE ~~ ACVL
ACAE ~~ ACAL
CD ~~ CC
GPTL ~~ GPTR

ACVE ~~ WRAT 
AFQT ~~ PA + WBD
PA ~~ WBD + CC
WRAT ~~ WGI + WLGT + ACVL
CC ~~ CVLT + WBD
WGI ~~ PASAT'

C2.model <- '
ge =~ ACVE + ACAE + AFQT + GIT + PA

gl =~ WRAT + CVLT + WCST + WBD + WGI + CD + CC + PASAT + GPTL + GPTR + WLGT + ACVL + ACAL

gl + education ~ ge

WRAT + WBD + WGI + CC + WLGT + ACVL + ACAL ~ education

ACVE ~~ ACVL
ACAE ~~ ACAL
CD ~~ CC
GPTL ~~ GPTR

ACVE ~~ WRAT 
AFQT ~~ PA + WBD
PA ~~ WBD + CC
WRAT ~~ WGI + WLGT + ACVL
CC ~~ CVLT + WBD
WGI ~~ PASAT'

B2.fit <- sem(B2.model, data = VES, std.lv = T)
C2.fit <- sem(C2.model, data = VES, std.lv = T)

round(cbind(JUSTG = fitMeasures(A.fit, FITM),
            GPLUS2 = fitMeasures(B2.fit, FITM),
            JUSTS2 = fitMeasures(C2.fit, FITM)), 3)
                    JUSTG     GPLUS2     JUSTS2
chisq            2456.636   2157.257   2162.577
df                135.000    124.000    129.000
npar               54.000     66.000     61.000
cfi                 0.952      0.958      0.958
rmsea               0.063      0.062      0.060
rmsea.ci.lower      0.061      0.059      0.058
rmsea.ci.upper      0.065      0.064      0.063
aic            595165.045 614309.694 614305.013
bic            595509.054 614730.150 614693.617

Model C still fits best between it and B, but more may need pruned.

parameterEstimates(B2.fit, stand = T) %>% 
  filter(op == "~") %>% 
  dplyr::select(Dependent = lhs, Independent = rhs, "Unstandardized Regression" = est, SE = se, Z = z, 'p-value' = pvalue, Beta = std.all) %>% 
  kable(digits = 3, format = "pandoc")
Dependent Independent Unstandardized Regression SE Z p-value Beta
gl ge 2.789 0.086 32.56 0.000 0.914
education ge 1.296 0.033 38.75 0.000 0.565
gl education 0.069 0.014 5.03 0.000 0.052
WRAT education 0.661 0.077 8.60 0.000 0.102
CVLT education -0.287 0.115 -2.50 0.013 -0.044
WCST education -0.131 0.113 -1.16 0.248 -0.020
WBD education -0.491 0.093 -5.30 0.000 -0.076
WGI education 1.045 0.084 12.45 0.000 0.160
CD education -0.293 0.112 -2.61 0.009 -0.046
CC education -0.416 0.110 -3.79 0.000 -0.065
PASAT education -0.330 0.106 -3.12 0.002 -0.051
GPTL education -0.116 0.117 -0.99 0.322 -0.018
GPTR education -0.298 0.119 -2.50 0.012 -0.046
WLGT education 0.570 0.109 5.21 0.000 0.087
parameterEstimates(C2.fit, stand = T) %>% 
  filter(op == "~") %>% 
  dplyr::select(Dependent = lhs, Independent = rhs, "Unstandardized Regression" = est, SE = se, Z = z, 'p-value' = pvalue, Beta = std.all) %>% 
  kable(digits = 3, format = "pandoc")
Dependent Independent Unstandardized Regression SE Z p-value Beta
gl ge 2.768 0.084 33.13 0.000 0.940
education ge 1.291 0.033 38.74 0.000 0.563
WRAT education 0.933 0.078 11.91 0.000 0.144
WBD education -0.245 0.087 -2.81 0.005 -0.038
WGI education 1.303 0.080 16.31 0.000 0.199
CC education -0.169 0.097 -1.75 0.081 -0.026
WLGT education 0.747 0.105 7.11 0.000 0.114
ACVL education 0.372 0.065 5.70 0.000 0.057
ACAL education 0.240 0.070 3.43 0.001 0.037

Some parameters need to be pruned from models B2 and C2.

Model B still generates a negative ultra-Heywood case with \(gl\), but this time it can’t be reasonably attributed to its other indicators. Model C has generated yet another insignificant effect of education on a subtest, so I’ll prune that too.

B3.model <- '
ge =~ ACVE + ACAE + AFQT + GIT + PA

gl =~ WRAT + CVLT + WCST + WBD + WGI + CD + CC + PASAT + GPTL + GPTR + WLGT + ACVL + ACAL

gl + education ~ ge

gl + WRAT + CVLT + WBD + WGI + CD + CC + PASAT + GPTR + WLGT ~ education

ACVE ~~ ACVL
ACAE ~~ ACAL
CD ~~ CC
GPTL ~~ GPTR

ACVE ~~ WRAT 
AFQT ~~ PA + WBD
PA ~~ WBD + CC
WRAT ~~ WGI + WLGT + ACVL
CC ~~ CVLT + WBD
WGI ~~ PASAT'

C3.model <- '
ge =~ ACVE + ACAE + AFQT + GIT + PA

gl =~ WRAT + CVLT + WCST + WBD + WGI + CD + CC + PASAT + GPTL + GPTR + WLGT + ACVL + ACAL

gl + education ~ ge

WRAT + WBD + WGI + WLGT + ACVL + ACAL ~ education

ACVE ~~ ACVL
ACAE ~~ ACAL
CD ~~ CC
GPTL ~~ GPTR

ACVE ~~ WRAT 
AFQT ~~ PA + WBD
PA ~~ WBD + CC
WRAT ~~ WGI + WLGT + ACVL
CC ~~ CVLT + WBD
WGI ~~ PASAT'

B3.fit <- sem(B3.model, data = VES, std.lv = T)
C3.fit <- sem(C3.model, data = VES, std.lv = T)

round(cbind(JUSTG = fitMeasures(A.fit, FITM),
            GPLUS2 = fitMeasures(B3.fit, FITM),
            JUSTS3 = fitMeasures(C3.fit, FITM)), 3)
                    JUSTG     GPLUS2     JUSTS3
chisq            2456.636   2159.496   2165.639
df                135.000    126.000    130.000
npar               54.000     64.000     60.000
cfi                 0.952      0.958      0.958
rmsea               0.063      0.061      0.060
rmsea.ci.lower      0.061      0.059      0.058
rmsea.ci.upper      0.065      0.063      0.062
aic            595165.045 614307.933 614306.075
bic            595509.054 614715.648 614688.308
parameterEstimates(B3.fit, stand = T) %>% 
  filter(op == "~") %>% 
  dplyr::select(Dependent = lhs, Independent = rhs, "Unstandardized Regression" = est, SE = se, Z = z, 'p-value' = pvalue, Beta = std.all) %>% 
  kable(digits = 3, format = "pandoc")
Dependent Independent Unstandardized Regression SE Z p-value Beta
gl ge 2.790 0.086 32.56 0.000 0.916
education ge 1.295 0.033 38.71 0.000 0.565
gl education 0.066 0.014 4.87 0.000 0.050
WRAT education 0.668 0.077 8.72 0.000 0.103
CVLT education -0.277 0.114 -2.42 0.015 -0.042
WBD education -0.479 0.092 -5.20 0.000 -0.074
WGI education 1.059 0.083 12.75 0.000 0.162
CD education -0.282 0.112 -2.52 0.012 -0.044
CC education -0.405 0.109 -3.71 0.000 -0.063
PASAT education -0.316 0.105 -3.01 0.003 -0.048
GPTR education -0.224 0.094 -2.38 0.018 -0.034
WLGT education 0.580 0.109 5.32 0.000 0.089
parameterEstimates(C3.fit, stand = T) %>% 
  filter(op == "~") %>% 
  dplyr::select(Dependent = lhs, Independent = rhs, "Unstandardized Regression" = est, SE = se, Z = z, 'p-value' = pvalue, Beta = std.all) %>% 
  kable(digits = 3, format = "pandoc")
Dependent Independent Unstandardized Regression SE Z p-value Beta
gl ge 2.760 0.083 33.21 0.000 0.940
education ge 1.290 0.033 38.71 0.000 0.563
WRAT education 0.939 0.078 11.99 0.000 0.145
WBD education -0.213 0.085 -2.49 0.013 -0.033
WGI education 1.312 0.080 16.47 0.000 0.201
WLGT education 0.752 0.105 7.16 0.000 0.115
ACVL education 0.379 0.065 5.83 0.000 0.058
ACAL education 0.248 0.070 3.56 0.000 0.038

No more paths require pruning by conventional standards, but, Lindley’s paradox is likely to affect the results since the sample is large. As such, it’s appropriate to prune based on a scaled critical value. For this, I use Naaman’s (2016) “almost-sure” scaling. Now, parameters with a \(Z\)-score below 4.09 are pruned. This means that for model A, the path from \(ge\) to educational attainment is removed.

NZ(4318, 2)
[1] 4.09
A2.model <- '
ge =~ ACVE + ACAE + AFQT + GIT + PA

gl =~ WRAT + CVLT + WCST + WBD + WGI + CD + CC + PASAT + GPTL + GPTR + WLGT + ACVL + ACAL

ge ~ gl

gl ~ education

ACVE ~~ ACVL
ACAE ~~ ACAL
CD ~~ CC
GPTL ~~ GPTR

ACVE ~~ WRAT 
AFQT ~~ PA + WBD
PA ~~ WBD + CC
WRAT ~~ WGI + WLGT + ACVL
CC ~~ CVLT + WBD
WGI ~~ PASAT'

B4.model <- '
ge =~ ACVE + ACAE + AFQT + GIT + PA

gl =~ WRAT + CVLT + WCST + WBD + WGI + CD + CC + PASAT + GPTL + GPTR + WLGT + ACVL + ACAL

gl + education ~ ge

gl + WRAT + WBD + WGI + WLGT ~ education

ACVE ~~ ACVL
ACAE ~~ ACAL
CD ~~ CC
GPTL ~~ GPTR

ACVE ~~ WRAT 
AFQT ~~ PA + WBD
PA ~~ WBD + CC
WRAT ~~ WGI + WLGT + ACVL
CC ~~ CVLT + WBD
WGI ~~ PASAT'

C4.model <- '
ge =~ ACVE + ACAE + AFQT + GIT + PA

gl =~ WRAT + CVLT + WCST + WBD + WGI + CD + CC + PASAT + GPTL + GPTR + WLGT + ACVL + ACAL

gl + education ~ ge

WRAT + WGI + WLGT + ACVL ~ education

ACVE ~~ ACVL
ACAE ~~ ACAL
CD ~~ CC
GPTL ~~ GPTR

ACVE ~~ WRAT 
AFQT ~~ PA + WBD
PA ~~ WBD + CC
WRAT ~~ WGI + WLGT + ACVL
CC ~~ CVLT + WBD
WGI ~~ PASAT'

A2.fit <- sem(A2.model, data = VES, std.lv = T)
B4.fit <- sem(B4.model, data = VES, std.lv = T)
C4.fit <- sem(C4.model, data = VES, std.lv = T)

round(cbind(JUSTG2 = fitMeasures(A2.fit, FITM),
            GPLUS4 = fitMeasures(B4.fit, FITM),
            JUSTS4 = fitMeasures(C4.fit, FITM)), 3)
                   JUSTG2     GPLUS4     JUSTS4
chisq            2460.669   2190.069   2186.998
df                136.000    131.000    132.000
npar               53.000     59.000     58.000
cfi                 0.952      0.957      0.957
rmsea               0.063      0.060      0.060
rmsea.ci.lower      0.061      0.058      0.058
rmsea.ci.upper      0.065      0.063      0.062
aic            595167.078 614328.505 614323.434
bic            595504.717 614704.367 614692.926

Models B and C are roughly tied in terms of absolute fit, but C is more parsimonious with not-significantly-worse exact fit.

parameterEstimates(A2.fit, stand = T) %>% 
  filter(op == "~") %>% 
  dplyr::select(Dependent = lhs, Independent = rhs, "Unstandardized Regression" = est, SE = se, Z = z, 'p-value' = pvalue, Beta = std.all) %>% 
  kable(digits = 3, format = "pandoc")
Dependent Independent Unstandardized Regression SE Z p-value Beta
ge gl 2.344 0.070 33.4 0 0.946
gl education 0.325 0.008 40.1 0 0.597
parameterEstimates(B4.fit, stand = T) %>% 
  filter(op == "~") %>% 
  dplyr::select(Dependent = lhs, Independent = rhs, "Unstandardized Regression" = est, SE = se, Z = z, 'p-value' = pvalue, Beta = std.all) %>% 
  kable(digits = 3, format = "pandoc")
Dependent Independent Unstandardized Regression SE Z p-value Beta
gl ge 2.795 0.086 32.55 0 0.923
education ge 1.287 0.033 38.48 0 0.561
gl education 0.049 0.013 3.75 0 0.037
WRAT education 0.705 0.075 9.35 0 0.109
WBD education -0.377 0.088 -4.26 0 -0.058
WGI education 1.099 0.081 13.55 0 0.168
WLGT education 0.634 0.107 5.91 0 0.097
parameterEstimates(C4.fit, stand = T) %>% 
  filter(op == "~") %>% 
  dplyr::select(Dependent = lhs, Independent = rhs, "Unstandardized Regression" = est, SE = se, Z = z, 'p-value' = pvalue, Beta = std.all) %>% 
  kable(digits = 3, format = "pandoc")
Dependent Independent Unstandardized Regression SE Z p-value Beta
gl ge 2.793 0.083 33.77 0 0.941
education ge 1.296 0.033 38.97 0 0.565
WRAT education 0.908 0.077 11.76 0 0.140
WGI education 1.264 0.078 16.29 0 0.194
WLGT education 0.727 0.105 6.93 0 0.111
ACVL education 0.339 0.063 5.40 0 0.052

It appears that model B is not viable for its theoretical backing, since it requires dropping the path from education to \(gl\).

B5.model <- '
ge =~ ACVE + ACAE + AFQT + GIT + PA

gl =~ WRAT + CVLT + WCST + WBD + WGI + CD + CC + PASAT + GPTL + GPTR + WLGT + ACVL + ACAL

gl + education ~ ge

WRAT + WBD + WGI + WLGT ~ education

ACVE ~~ ACVL
ACAE ~~ ACAL
CD ~~ CC
GPTL ~~ GPTR

ACVE ~~ WRAT 
AFQT ~~ PA + WBD
PA ~~ WBD + CC
WRAT ~~ WGI + WLGT + ACVL
CC ~~ CVLT + WBD
WGI ~~ PASAT'

B5.fit <- sem(B5.model, data = VES, std.lv = T)

round(cbind(JUSTG2 = fitMeasures(A2.fit, FITM),
            GPLUS5 = fitMeasures(B5.fit, FITM),
            JUSTS4 = fitMeasures(C4.fit, FITM)), 3)
                   JUSTG2     GPLUS5     JUSTS4
chisq            2460.669   2203.909   2186.998
df                136.000    132.000    132.000
npar               53.000     58.000     58.000
cfi                 0.952      0.957      0.957
rmsea               0.063      0.060      0.060
rmsea.ci.lower      0.061      0.058      0.058
rmsea.ci.upper      0.065      0.063      0.062
aic            595167.078 614340.345 614323.434
bic            595504.717 614709.837 614692.926
parameterEstimates(B5.fit, stand = T) %>% 
  filter(op == "~") %>% 
  dplyr::select(Dependent = lhs, Independent = rhs, "Unstandardized Regression" = est, SE = se, Z = z, 'p-value' = pvalue, Beta = std.all) %>% 
  kable(digits = 3, format = "pandoc")
Dependent Independent Unstandardized Regression SE Z p-value Beta
gl ge 2.877 0.086 33.52 0 0.945
education ge 1.300 0.033 39.13 0 0.567
WRAT education 0.756 0.073 10.39 0 0.117
WBD education -0.302 0.084 -3.57 0 -0.047
WGI education 1.175 0.077 15.29 0 0.180
WLGT education 0.677 0.105 6.46 0 0.104

Now, to perform an ANOVA on the final models. I will include B5 in the first ANOVA even though it’s a theoretically bankrupt model. In the second ANOVA, I’ll include B4 instead of B5, since it was the last theoretically admissible model, even though the path it offered was not significant. The important test here is the \(\chi^2\) exact-fit test. The same scaling will be used here.

anova(A2.fit, B5.fit, C4.fit)
Chi-Squared Difference Test

        Df    AIC    BIC Chisq Chisq diff Df diff          Pr(>Chisq)    
B5.fit 132 614340 614710  2204                                           
C4.fit 132 614323 614693  2187      -16.9       0                        
A2.fit 136 595167 595505  2461      273.7       4 <0.0000000000000002 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
anova(A2.fit, B4.fit, C4.fit)
Chi-Squared Difference Test

        Df    AIC    BIC Chisq Chisq diff Df diff          Pr(>Chisq)    
B4.fit 131 614329 614704  2190                                           
C4.fit 132 614323 614693  2187       -3.1       1                   1    
A2.fit 136 595167 595505  2461      273.7       4 <0.0000000000000002 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

A shift of 273.7 \(\chi^2\) is extremely significant, making model A2 less parsimonious than C4, which is the most parsimonious, leaving C4 the best fitting model. Since these models went through multiple stages of pruning, the use of AIC/BIC may not be clear. Anyone who disagrees should email me why. As I see it, these models were not theoretically preselected and the model with extremely high \(\chi^2\) relative to the rest - thanks to an implausible assumption, perhaps - should have the best AIC/BIC, despite failing to recover the data well. I would certainly like to see more data on this if anyone has it. Either way, the models to be contrasted are models of specific effects and effects directly on \(gl\). One way to make ground here is to conduct a power analysis, which I do below, but this may be superfluous since the rejection of the A2 model was so incredibly severe and my criteria were already adjusted to be quite stringent, allowing it a great deal of leeway.

In the accepted model, C, the effect seems to be relegated to the WRAT, WGI, WLGT, and ACVL subtests. It is clear based on the direction of effect for WBD, that the pruning might be helpful insofar as it removes an implausible effect (i.e., education worsening spatial ability). However, it is possible that there is attrition from education by level of spatial ability (to-do: cite the study on spatial ability and lower academic achievement James likes so much, and the articles in NBER/AEA on association of spatial ability and market returns; or, explain that this could be that spatial is just bad for achievement) or that education really does have a negative effect. As I show even further below, the effect of education on these subtests is in no small part to generate measurement variance.

EDUVESLATS <- list(
  ge = early_tests,
  gl = later_tests,
  education = c("WRAT", "WGI", "WLGT", "ACVL"))

semPaths(C4.fit, "model", "std", title = F, residuals = F, groups = "EDUVESLATS", pastel = T, mar = c(4, 1, 3, 1), intercepts = F, layout = "tree", bifactor = c("gl", "ge"), exoCov = F, curvePivot = T)

Power Analysis

  • Do Later

Residualization Path Model

  • Do Later

Ethnic Confounding

  • Do Later

MGCFA

  • Do Later

Indicator Means

  • Do Later

Intercepts

  • Do Later

Residual Variances

  • Do Later

LSEM

  • Do Later

MNLFA

  • Do Later

IQ Gains

  • Do Later

Naive and Proper g Effects?

  • Do Later

Income Gains

  • Do Later

Mediation by IQ?

  • Do Later

Mediation by Intelligence?

  • Do Later

Did it Affect Nerve Conduction Velocity? (Or Any Other Sensory Measure?)

  • Do Later

To-Do

  • Make a ‘To-Do’ list
  • Note Emil’s earlier investigation of the same dataset included both iterations of the ACB subtests in the earlier tests rather than in their proper locations, explaining his result
  • Goldberger and using gated/ungated \(p-values\)
  • Show lower initial approximate fit threshold models
  • Show triviality of overfitting a model for information theoretic fits

References

  • To-Do

Gunn, H. J., Grimm, K. J., & Edwards, M. C. (2019). Evaluation of Six Effect Size Measures of Measurement Non-Invariance for Continuous Outcomes. Structural Equation Modeling: A Multidisciplinary Journal, 0(0), 1-12. https://doi.org/10.1080/10705511.2019.1689507

Naaman, M. (2016). Almost sure hypothesis testing and a resolution of the Jeffreys-Lindley paradox. Electronic Journal of Statistics, 10(1), 1526-1550. https://doi.org/10.1214/16-EJS1146

Millsap, R. E., & Olivera-Aguilar, M. (2012). Investigating measurement invariance using confirmatory factor analysis. In R. H. Hoyle, Handbook of structural equation modeling (pp. 380-392). New York, NY: Guildford Press