alignment_check: Alignment Ratio Check for ICM-CFA Specification

View source: R/alignment_check.R

alignment_checkR Documentation

Alignment Ratio Check for ICM-CFA Specification

Description

Tests whether a standard CFA (ICM-CFA) is appropriately specified by computing alignment ratios from the manifest correlation matrix. Based on Mehrvarz & Rouder (2026), who prove that in a correctly specified ICM-CFA, alignment ratios must be invariant across all admissible item quadruples, with the common value equal to the squared latent correlation phi^2.

Usage

alignment_check(
  data,
  clusters,
  cfa_fit = NULL,
  is_cor = FALSE,
  min_within_r = 0.05,
  log_sd_thresholds = c(slight = 0.64, moderate = 1.6)
)

Arguments

data

A data.frame or matrix of observed scores. May also be a correlation matrix (set is_cor = TRUE).

clusters

A named character vector mapping item names to factor names. Example: c(y1 = "F1", y2 = "F1", y3 = "F2", y4 = "F2"). Alternatively, a named list: list(F1 = c("y1","y2"), F2 = c("y3","y4")).

cfa_fit

Optional. A fitted lavaan CFA object. When supplied, CFA-estimated latent correlations are compared against the alignment-implied phi to quantify inflation.

is_cor

Logical. Is data already a correlation matrix? Default FALSE.

min_within_r

Numeric. Alignment ratios whose denominator contains a within-cluster correlation below this value are excluded (near-zero within-cluster correlations make ratios numerically unstable). Default 0.05.

log_sd_thresholds

Named numeric vector of log-scale SD cutoffs for the slight / moderate / high misalignment classification. Defaults to the empirical terciles reported by Mehrvarz & Rouder (2026, p.24): c(slight = 0.64, moderate = 1.6). Values of s = \mathrm{sd}( \log Q) below slight indicate an ICM-CFA approximately consistent with the data; above moderate indicate substantial misspecification.

Details

Interpreting the log-scale dispersion (sd of log Q)

s = \mathrm{sd}(\log Q) is the primary diagnostic. The log scale is natural because alignment ratios are multiplicative objects. Mehrvarz & Rouder (2026, p.24) report empirical terciles of s from their bifactor misalignment simulation:

  • s < 0.64 – Slight misalignment. ICM-CFA is approximately consistent with the data; latent correlations are roughly trustworthy.

  • s 0.64-1.6 – Moderate misalignment. ICM-CFA is partially misspecified; interpret latent correlations with caution.

  • s > 1.6 – High misalignment (top tercile of the paper's simulation, up to ~4.4). ICM-CFA is substantially misspecified and latent correlations are likely inflated. Consider ESEM.

These cutpoints are the 33rd and 66th percentiles of s observed by Mehrvarz & Rouder across a broad range of simulated loading configurations (with \mathrm{sd}(\log \kappa_j) \in [0, 3]), not hard decision boundaries; adjust log_sd_thresholds if your application calls for stricter or looser cutoffs.

Types of misspecification detected

  • Misassignment: items are assigned to the wrong cluster. Mehrvarz & Rouder prove this necessarily inflates phi. The alignment ratios split into three plateaus at phi^2, 1, and 1/phi^2.

  • Misalignment: cluster assignments are correct but cross-loadings exist (or the proportionality constraint is violated in a bifactor-like DGP). The ratios are dispersed rather than invariant.

Number of alignment ratios per pair

Mehrvarz & Rouder (2026, p.14) count one alignment ratio per admissible index quadruple: n_Q = \binom{m_A}{2}\binom{m_B}{2}. Because each unordered quadruple \{\ell, \ell'\} \times \{k, k'\} admits two between-cluster matchings ((\ell,k)/(\ell',k') and (\ell,k')/(\ell',k)), both of which equal \varphi^2 under correctly specified ICM-CFA but diverge under misspecification, this function records both matchings per quadruple – yielding 2 \binom{m_A} {2}\binom{m_B}{2} ratios in all_ratios – to maximise the information available for the dispersion diagnostic.

Value

An object of class "alignment_check" (a list) containing:

pair_results

A data.frame with one row per factor pair, giving: geometric mean of alignment ratios, log-scale SD, implied phi, CFA-estimated phi (if supplied), inflation percentage, and verdict.

all_ratios

A named list of raw alignment ratio vectors, one element per factor pair.

recommendation

Character string: overall recommendation.

cor_matrix

The manifest correlation matrix used.

clusters

Resolved cluster assignments (named list).

call

The matched call.

What are alignment ratios?

For any two items \ell, \ell' in cluster A and two items k, k' in cluster B, the alignment ratio is:

Q(\ell, \ell', k, k') = \frac{r_{\ell k} \cdot r_{\ell' k'}}{r_{\ell \ell'} \cdot r_{k k'}}

Under a correctly specified ICM-CFA, all such ratios equal phi^2 and lie in [0, 1] (Mehrvarz & Rouder, 2026, Eq. 5). Dispersion in the ratios – measured by their log-scale standard deviation s = \mathrm{sd}(\log Q) – signals misspecification: either misassignment (items in the wrong cluster) or misalignment (cross-loadings exist but are fixed to zero).

References

Mehrvarz, M., & Rouder, J. N. (2026). The geometry and brittleness of latent correlations in confirmatory factor analysis.

See Also

esem for the recommended follow-up under moderate or high misalignment.

Examples

data("HolzingerSwineford1939", package = "lavaan")
d <- HolzingerSwineford1939[, paste0("x", 1:9)]

# Vector form of cluster assignment
clusters <- c(
  x1 = "Visual",  x2 = "Visual",  x3 = "Visual",
  x4 = "Textual", x5 = "Textual", x6 = "Textual",
  x7 = "Speed",   x8 = "Speed",   x9 = "Speed"
)


# Run alignment check (data only)
check <- alignment_check(d, clusters)
print(check)

# Run with a fitted CFA to quantify inflation
cfa_model <- "
  Visual  =~ x1 + x2 + x3
  Textual =~ x4 + x5 + x6
  Speed   =~ x7 + x8 + x9
"
cfa_fit <- lavaan::cfa(cfa_model, data = d, std.lv = TRUE)
check   <- alignment_check(d, clusters, cfa_fit = cfa_fit)
print(check)



bifactory documentation built on Oct. 28, 2026, 1:06 a.m.