Quantifies how much a violation of measurement invariance actually matters for an item, rather than only whether it is statistically detectable. A likelihood ratio or score test can flag a loading or intercept difference that is too small to change anyone's score in a meaningful way, and with a large sample size it usually will. The dMACS index of Nye and Drasgow (2011) answers the size question directly: it is the expected difference between the reference group's and the focal group's measurement equations for that item, averaged over the focal group's latent distribution and standardized by the pooled item standard deviation, so it reads on the familiar standardized mean difference scale. Input is either a fitted multiple group lavaan model (requires lavaan) or the loadings, intercepts, and pooled standard deviations a paper reports.
Usage
dmacs(
fit = NULL,
reference = NULL,
focal = NULL,
lambda_reference = NULL,
lambda_focal = NULL,
nu_reference = NULL,
nu_focal = NULL,
mean_focal = 0,
sd_focal = 1,
sd_pooled = NULL,
item_names = NULL
)Arguments
- fit
A fitted multiple group lavaan object carrying a mean structure, with the two groups' loadings and intercepts on a common metric (see Details). Supply either
fitor the parameter vectors, never both.- reference, focal
Which groups play the reference and focal roles, each given as a single group label or a single group index in
lavInspect(fit, "group.label"). When both areNULL(default) and the fit has exactly two groups, the first is the reference and the second the focal; with more than two groups they must be named.- lambda_reference, lambda_focal
Numeric vectors of unstandardized loadings, one per item, in the reference and focal groups. Any finite values are admissible.
- nu_reference, nu_focal
Numeric vectors of unstandardized intercepts, one per item, in the reference and focal groups, in the same item order as the loadings. Any finite values are admissible.
- mean_focal
Focal group latent mean \(\mu_F\) on the common metric, a single finite number (default
0, the usual identification in which the reference group's latent mean is fixed at zero). Used only on the parameter vector path; with afitit is read from the fit.- sd_focal
Focal group latent standard deviation \(\sigma_F\) on the common metric, a single positive number (default
1). Used only on the parameter vector path; with afitit is read from the fit.- sd_pooled
Pooled observed standard deviation of each item across the two groups, either one positive number applied to every item or one per item. Required on the parameter vector path; with a
fitit is computed from the group sample sizes and observed item variances.- item_names
Optional character vector of item labels, one per item. Defaults to the names carried by the parameter vectors, to the indicator names in the fit, or to
item_1,item_2, and so on.
Value
A wide data.frame (class dmar_tbl) with one row per
item and columns
itemItem label.
lambda_referenceReference group unstandardized loading.
lambda_focalFocal group unstandardized loading.
nu_referenceReference group unstandardized intercept.
nu_focalFocal group unstandardized intercept.
sd_pooledPooled observed standard deviation of the item.
dmacsThe dMACS effect size, nonnegative.
The returned object carries four attributes: "reference" and
"focal", the two group labels, and "mean_focal" and
"sd_focal", the focal group's latent mean and standard deviation
used in the integral (named by latent variable on the fit path).
Details
For item \(i\), let \(\nu_R\) and \(\lambda_R\) be the reference group's intercept and loading, let \(\nu_F\) and \(\lambda_F\) be the focal group's, and let the focal group's latent variable be \(\eta \sim N(\mu_F, \sigma_F^2)\) with density \(f_F\). Each group's measurement equation gives an expected item score at every value of \(\eta\), and dMACS is the root mean squared vertical distance between those two lines over the focal group's latent distribution, divided by the pooled item standard deviation: $$d_{MACS, i} = \frac{1}{SD_i} \sqrt{\int \left[ (\nu_R + \lambda_R \eta) - (\nu_F + \lambda_F \eta) \right]^2 f_F(\eta) \, d\eta}.$$
Writing \(a = \nu_R - \nu_F\) for the intercept difference and
\(b = \lambda_R - \lambda_F\) for the loading difference, the integrand is
\((a + b\eta)^2\) and the integral is the second moment of a linear
function of a normal variate, so it has the closed form
\(a^2 + 2ab\mu_F + b^2(\sigma_F^2 + \mu_F^2)\). No numerical integration
is performed. The standardizer is the pooled observed standard deviation of
the item,
$$SD_i = \sqrt{\frac{(n_R - 1)s_R^2 + (n_F - 1)s_F^2}{n_R + n_F - 2}},$$
the same pooling used by the standardized mean difference, which puts dMACS
on a scale a reader of smd already understands.
dMACS is a root mean square and so is nonnegative by construction; it carries no sign and is not given one here. The direction of the violation is read from the returned components: \(\nu_R - \nu_F\) says which group is scored higher at the mean of the latent variable, and \(\lambda_R - \lambda_F\) says in which group the item discriminates more sharply. When only the intercepts differ, the integral collapses to \(a^2\) and dMACS reduces to \(|a| / SD_i\), a plain standardized intercept difference.
The index is interpretable only when the two groups' loadings and
intercepts are expressed on a common metric. In practice that means a
partial invariance model in which a set of anchor items is constrained
equal across groups while the suspect items are freed, and the focal
group's latent mean and variance are freely estimated. A configural model,
which sets each group's latent scale separately, does not put the groups on
a common metric, and dMACS computed from one is not meaningful. The usual
workflow is therefore measurement_invariance to locate where
the ladder breaks, a partial invariance refit that frees the offending
parameters, and then dmacs() on that refit to judge whether the
violation is large enough to matter.
On the fit path each group's item variance is computed from the data in the fit with the usual \(n - 1\) divisor, using the number of nonmissing observations for that item in that group. When the model was fitted from sample moments rather than raw data, the sample covariances in the fit are used instead, rescaled to the \(n - 1\) divisor when the fit's likelihood option calls for it.
References
Meredith, W. (1993). Measurement invariance, factor analysis and factorial invariance. Psychometrika, 58(4), 525–543. doi:10.1007/BF02294825
Millsap, R. E. (2011). Statistical approaches to measurement invariance. Routledge.
Nye, C. D., Bradburn, J., Olenick, J., Bialko, C., & Drasgow, F. (2019). How big are my effects? Examining the magnitude of effect sizes in studies of measurement equivalence. Organizational Research Methods, 22(3), 678–709. doi:10.1177/1094428118761122
Nye, C. D., & Drasgow, F. (2011). Effect size indices for analyses of measurement equivalence: Understanding the practical importance of differences between groups. Journal of Applied Psychology, 96(5), 966–980. doi:10.1037/a0022955
See also
measurement_invariance for the invariance ladder
that locates a violation; smd for the standardized mean
difference whose pooling and scale dMACS borrows; cfa_1 for
the single group measurement model.
Other multivariate and latent variable methods:
average_variance_extracted(),
bifactor_indices(),
cfa_1(),
cfa_2(),
cfa_k(),
ci_eigenvalue(),
common_method_marker(),
common_method_single_factor(),
ecvi(),
htmt(),
irt_grm(),
irt_information(),
measurement_alignment(),
measurement_invariance(),
procrustes_phi(),
simple_structure()
Author
Ken Kelley kkelley@nd.edu
Examples
# Reported measurement equations: the two items share loadings, and the
# second item's intercept is 0.30 higher in the reference group. With no
# loading difference, dMACS is just 0.30 divided by the pooled SD.
dmacs(lambda_reference = c(0.80, 0.75), lambda_focal = c(0.80, 0.75),
nu_reference = c(2.00, 2.30), nu_focal = c(2.00, 2.00),
sd_pooled = c(1.20, 1.10), item_names = c("optimism", "worry"))
#> item lambda_reference lambda_focal nu_reference nu_focal sd_pooled dmacs
#> optimism 0.8 0.8 2 2 1.2 0
#> worry 0.75 0.75 2.3 2 1.1 0.273
# A partial invariance model for the four spatial tests at the two
# Holzinger and Swineford schools. The anchors are constrained equal; the
# cubes and lozenges tests are freed, so only those two can move.
data(holzinger_swineford)
items <- c("t1_visual_perception", "t2_cubes",
"t3_paper_form_board", "t4_lozenges")
model <- paste("spatial =~", paste(items, collapse = " + "))
fit <- lavaan::cfa(model, data = holzinger_swineford, group = "school",
group.equal = c("loadings", "intercepts"),
group.partial = c("spatial =~ t2_cubes", "t2_cubes ~ 1",
"spatial =~ t4_lozenges",
"t4_lozenges ~ 1"))
dmacs(fit)
#> item lambda_reference lambda_focal nu_reference nu_focal
#> t1_visual_perception 1 1 29.6 29.6
#> t2_cubes 0.495 0.52 23.9 24.8
#> t3_paper_form_board 0.308 0.308 14.2 14.2
#> t4_lozenges 1.28 1.37 19.9 15.8
#> sd_pooled dmacs
#> 7.02 0
#> 4.7 0.175
#> 2.83 0
#> 8.85 0.461
# The broom verbs: one row per item, and the group metadata.
generics::tidy(dmacs(fit))
#> term estimate lambda_reference lambda_focal nu_reference
#> 1 t1_visual_perception 0.0000000 1.0000000 1.0000000 29.56940
#> 2 t2_cubes 0.1754320 0.4953945 0.5199470 23.93590
#> 3 t3_paper_form_board 0.0000000 0.3084177 0.3084177 14.21526
#> 4 t4_lozenges 0.4606217 1.2796675 1.3720483 19.89744
#> nu_focal sd_pooled
#> 1 29.56940 7.016213
#> 2 24.75043 4.697740
#> 3 14.21526 2.834122
#> 4 15.83472 8.845986
generics::glance(dmacs(fit))
#> n_items reference focal mean_focal sd_focal
#> spatial 4 Pasteur Grant-White 0.09533115 4.444806