26/12/25
Abstract
En Rpubs:: toc se pueden ver otros documentos de posible interés.
Este capítulo presenta una aplicación empírica de la invarianza de medida en el marco de los modelos factoriales confirmatorios multigrupo (MG-CFA), utilizando ejemplos reproducibles en R. El objetivo es mostrar, paso a paso, cómo evaluar si un conjunto de ítems mide los mismos constructos latentes de forma equivalente entre grupos, antes de realizar comparaciones sustantivas.
En particular, la invarianza métrica evalúa si las cargas factoriales son equivalentes entre grupos, de modo que una unidad de cambio en el factor latente represente el mismo cambio esperado en los indicadores observados, independientemente del grupo. La evaluación empírica se realiza mediante comparaciones entre modelos anidados, avanzando progresivamente desde la invarianza configural hasta la métrica, escalar y, cuando sea pertinente, estricta, incluyendo la posibilidad de invarianza parcial.
Los fundamentos conceptuales, la formulación matemática y la interpretación sustantiva de cada nivel de invarianza se desarrollan en el capítulo teórico previo:
Se recomienda revisar ese documento antes de abordar la presente aplicación, ya que allí se discuten los supuestos, el sentido de las restricciones y el tipo de inferencia que es válida en cada nivel. En lo que sigue, el énfasis estará puesto en la implementación en R y en la lectura e interpretación práctica de los resultados.
A lo largo de este capítulo se emplean paquetes de R para:
Especificar modelos CFA multigrupo.
Evaluar sistemáticamente la invarianza de medida.
Apoyar diagnósticos previos en escalas ordinales.
Presentar resultados de forma clara en tablas y figuras.
Estos paquetes se cargarán al inicio del capítulo y se utilizarán de manera progresiva a lo largo de la aplicación, conforme se vayan especificando los modelos CFA multigrupo, evaluando los distintos niveles de invarianza y presentando los resultados obtenidos.
library(lavaan) # CFA y modelos SEM multigrupo
library(semTools) # funciones auxiliares para invarianza de medida
library(psych) # diagnósticos y apoyo exploratorio previo
library(polycor) # correlaciones policóricas para ítems ordinales
library(lsm) # acceso al conjunto de datos survey
library(dplyr) # manipulación de datos
library(knitr) # tablas en R Markdown
library(kableExtra) # formato avanzado de tablas
library(ggplot2) # visualización
library(stringr) # operaciones de cadenas comunes
En particular:
lavaan: desarrollado por Rossel (2012). Se utiliza para especificar y estimar modelos factoriales confirmatorios (CFA) y modelos de ecuaciones estructurales (SEM) multigrupo, permitiendo evaluar tanto la invarianza de medida (cargas, interceptos y residuos) como la invarianza estructural (regresiones, varianzas y covarianzas latentes) entre grupos. Para una introducción práctica al paquete, puede consultarse el tutorial oficial disponible en: https://lavaan.ugent.be/tutorial
semTools: proporciona funciones auxiliares para la evaluación sistemática de la invarianza de medida, incluyendo comparaciones entre modelos configural, métrico, escalar y estricto.
psych: se emplea como apoyo para análisis exploratorios previos y para evaluar la coherencia interna de las escalas antes del análisis multigrupo.
polycor: permite calcular correlaciones policóricas, necesarias cuando los ítems son ordinales, como ocurre con muchas escalas psicológicas y educativas.
lsm: desarrollado por Villalba JL, Llinás HJ y Fabregas OJ (2025), es una contribución propia que puede descargarse desde el repositorio oficial de CRAN. Se utiliza exclusivamente como fuente de datos reales, a través del conjunto survey, que sirve como base empírica para los ejemplos y ejercicios del capítulo.
knitr y kableExtra: se emplean para la presentación ordenada y formateada de tablas y resultados.
ggplot2: se utiliza para la visualización de resultados y diagnósticos intermedios.
string: se emplea para hacer operaciones de cadenas.
A medida que avance el capítulo, se explicará el propósito de cada función utilizada y la interpretación de sus resultados, priorizando siempre el sentido estadístico y sustantivo por encima del uso técnico del software.
Antes de presentar la aplicación empírica, es importante recordar brevemente la lógica secuencial que guía la evaluación de la invarianza de medida en modelos CFA multigrupo.
La estrategia seguida en este capítulo consiste en ajustar y comparar una serie de modelos anidados, en el siguiente orden:
Modelo configural, que evalúa si la estructura factorial es la misma en todos los grupos.
Modelo métrico, que impone igualdad en las cargas factoriales y permite comparar relaciones estructurales.
Modelo escalar, que añade igualdad en los interceptos y habilita la comparación de medias latentes.
Modelo estricto (cuando es pertinente), que incorpora igualdad en las varianzas residuales.
Modelos de invarianza parcial, cuando alguna de las restricciones completas no se sostiene empíricamente.
En cada etapa, la decisión sobre la invarianza se basa en la comparación del ajuste entre modelos, considerando tanto índices globales como cambios en el ajuste (por ejemplo, ΔCFI y ΔRMSEA), así como la coherencia sustantiva de las restricciones impuestas.
get_group_partial_target()A lo largo del capítulo se evaluarán distintos niveles de invarianza en modelos CFA y SEM multigrupo. En varias etapas, los modelos completos de invarianza (métrica, escalar o estructural) pueden no sostenerse empíricamente, lo que obliga a considerar versiones parciales del modelo.
En este contexto, surgen dos preguntas recurrentes:
¿Qué restricción específica está generando el deterioro del ajuste?
¿Qué tipo de parámetro conviene revisar o liberar en cada etapa del análisis?
Para responder estas preguntas de manera sistemática y reproducible, en este capítulo se utilizará una función auxiliar que automatiza el diagnóstico local de invarianza a partir de score tests.
Esta función se define una sola vez y se reutiliza a lo largo de todos los ejemplos, permitiendo mantener una lógica coherente entre modelos y evitar decisiones ad hoc.
La función get_group_partial_target() se utiliza para:
Identificar restricciones de igualdad con evidencia de misfit local.
Traducir automáticamente dichas restricciones a la sintaxis requerida por group.partial en lavaan.
Controlar explícitamente qué tipo de parámetros se evalúan en cada etapa del análisis (target).
De este modo, el diagnóstico local se mantiene alineado con el nivel de invarianza que se está evaluando (medición vs. estructura), evitando interpretaciones cruzadas entre parámetros de distinta naturaleza.
En términos pedagógicos, esta función cumple el rol de un “asistente metodológico”: no toma decisiones por el investigador, pero ayuda a ver con claridad dónde mirar.
En lo que sigue, la función get_group_partial_target() se utilizará como apoyo sistemático para identificar y evaluar posibles violaciones locales de invarianza en cada nivel del análisis multigrupo, siempre en coherencia con el tipo de restricciones que se estén contrastando.
Cabe destacar que la función puede devolver un conjunto vacío (character(0)), lo cual se interpreta como ausencia de evidencia suficiente para liberar restricciones del tipo evaluado bajo el umbral definido.
# ============================================================
# get_group_partial_target()
# - Identifica restricciones candidatas (lavTestScore $uni)
# - Mapea labels -> parámetros (parTable)
# - Devuelve group_partial con sintaxis lavaan
# - Permite controlar QUÉ tipo de parámetros liberar con:
# target = c("intercepts","loadings","residuals","lv.variances",
# "lv.covariances","regressions")
# ============================================================
library(dplyr)
get_group_partial_target <- function(fit,
score_obj,
x2_cut = 5,
top_n = 1,
target = c("intercepts",
"loadings",
"residuals",
"lv.variances",
"lv.covariances",
"regressions")) {
target <- unique(target)
# --- helpers -----------------------------------------------------------
is_indicator <- function(x) grepl("^x[0-9]+$", x)
# classify a mapped parameter into a target category
classify_target <- function(lhs, op, rhs) {
if (op == "~1") {
if (is_indicator(lhs)) return("intercepts")
# latent means (lhs is factor name) are not included by default
return(NA_character_)
}
if (op == "=~") return("loadings")
if (op == "~") return("regressions")
if (op == "~~") {
# residual variances/covariances for indicators
if (is_indicator(lhs) || is_indicator(rhs)) return("residuals")
# latent variances vs latent covariances
if (lhs == rhs) return("lv.variances")
return("lv.covariances")
}
NA_character_
}
# build lavaan syntax for group.partial
make_gp <- function(lhs, op, rhs) {
if (op == "~1") return(paste0(lhs, "~1"))
if (op == "=~") return(paste0(lhs, "=~", rhs))
if (op == "~") return(paste0(lhs, "~", rhs))
if (op == "~~") return(paste0(lhs, "~~", rhs))
NA_character_
}
# --- 1) univariate score tests table -----------------------------------
uni_tbl <- score_obj$uni %>%
as.data.frame() %>%
filter(op == "==") %>% # equality constraints (label == label)
arrange(desc(X2)) %>%
filter(X2 > x2_cut)
if (nrow(uni_tbl) == 0) {
return(list(
group_partial = character(0),
target_used = target,
uni_tbl = uni_tbl,
top_rows = uni_tbl,
labels_to_free = character(0),
mapped = data.frame(),
mapped_filtered = data.frame(),
note = "No equality constraints above x2_cut."
))
}
# --- 2) take top_n rows -------------------------------------------------
top_rows <- uni_tbl %>% slice_head(n = top_n)
# --- 3) extract labels involved ----------------------------------------
labels_to_free <- top_rows %>%
select(lhs, rhs) %>%
unlist(use.names = FALSE) %>%
unique()
# --- 4) map labels -> actual parameters --------------------------------
param <- as.data.frame(parTable(fit))
mapped <- param %>%
filter(label %in% labels_to_free) %>%
select(id, lhs, op, rhs, group, label, plabel)
if (nrow(mapped) == 0) {
return(list(
group_partial = character(0),
target_used = target,
uni_tbl = uni_tbl,
top_rows = top_rows,
labels_to_free = labels_to_free,
mapped = mapped,
mapped_filtered = mapped,
note = "Labels found in score tests but not found in parTable()."
))
}
# --- 5) classify and filter by target ----------------------------------
mapped2 <- mapped %>%
mutate(target_class = mapply(classify_target, lhs, op, rhs))
mapped_filtered <- mapped2 %>%
filter(target_class %in% target)
# --- 6) build group.partial vector -------------------------------------
group_partial <- mapped_filtered %>%
mutate(gp = mapply(make_gp, lhs, op, rhs)) %>%
filter(!is.na(gp)) %>%
distinct(gp) %>%
pull(gp)
note <- if (length(group_partial) == 0) {
paste0(
"No parameters matching target found. ",
"Top mapped ops: {", paste(unique(mapped$op), collapse = ", "), "}. ",
"Targets requested: {", paste(target, collapse = ", "), "}."
)
} else {
paste0("Candidates produced for targets: {", paste(target, collapse = ", "), "}.")
}
list(
group_partial = group_partial,
target_used = target,
uni_tbl = uni_tbl,
top_rows = top_rows,
labels_to_free = labels_to_free,
mapped = mapped2,
mapped_filtered = mapped_filtered,
note = note
)
}
# ============================================================
# Examples (copy/paste patterns)
# ============================================================
## A) Only intercepts (like M3 partial scalar)
# res_int <- get_group_partial_target(
# fit = model_scalar_a,
# score_obj = score_obj,
# x2_cut = 5,
# top_n = 1,
# target = "intercepts"
# )
# res_int$group_partial
## B) Only loadings (useful when score points to "=~")
# res_load <- get_group_partial_target(
# fit = model_structural,
# score_obj = score_obj,
# x2_cut = 5,
# top_n = 1,
# target = "loadings"
# )
# res_load$group_partial
## C) Structural level: latent variances + covariances only
# res_lv <- get_group_partial_target(
# fit = model_structural,
# score_obj = score_obj,
# x2_cut = 5,
# top_n = 3,
# target = c("lv.variances", "lv.covariances")
# )
# res_lv$group_partial
## D) Residuals only
# res_resid <- get_group_partial_target(
# fit = model_structural,
# score_obj = score_obj,
# x2_cut = 5,
# top_n = 3,
# target = "residuals"
# )
# res_resid$group_partial
## E) Regressions only (SEM multi-group)
# res_reg <- get_group_partial_target(
# fit = model_sem_equal_reg,
# score_obj = score_obj,
# x2_cut = 5,
# top_n = 3,
# target = "regressions"
# )
# res_reg$group_partial
En esta sección se presenta una aplicación empírica completa de la evaluación de la invarianza de medida mediante modelos factoriales confirmatorios multigrupo (MG-CFA). El objetivo principal es ilustrar, paso a paso, cómo evaluar si un mismo instrumento mide constructos latentes de manera equivalente entre grupos, antes de realizar comparaciones sustantivas sobre relaciones estructurales o medias latentes.
En estudios educativos y psicológicos es frecuente comparar grupos definidos por características institucionales, sociales o demográficas (por ejemplo, tipo de escuela, género o nivel educativo). Sin embargo, dichas comparaciones solo son válidas si se garantiza que los instrumentos utilizados operan de forma equivalente en todos los grupos considerados.
En este ejemplo se evalúa si un conjunto de pruebas cognitivas mide los mismos constructos latentes en dos grupos de estudiantes pertenecientes a diferentes tipos de escuela. El interés central no es únicamente estimar un modelo factorial, sino verificar empíricamente la invarianza de medida, comenzando por la invarianza configural y avanzando hacia niveles más restrictivos, en particular la invarianza métrica.
Se utiliza el conjunto de datos clásico de Holzinger y Swineford (1939), ampliamente empleado en la literatura metodológica para ilustrar modelos factoriales confirmatorios y análisis multigrupo.
head(HolzingerSwineford1939)
## id sex ageyr agemo school grade x1 x2 x3 x4 x5 x6
## 1 1 1 13 1 Pasteur 7 3.333333 7.75 0.375 2.333333 5.75 1.2857143
## 2 2 2 13 7 Pasteur 7 5.333333 5.25 2.125 1.666667 3.00 1.2857143
## 3 3 2 13 1 Pasteur 7 4.500000 5.25 1.875 1.000000 1.75 0.4285714
## 4 4 1 13 2 Pasteur 7 5.333333 7.75 3.000 2.666667 4.50 2.4285714
## 5 5 2 12 2 Pasteur 7 4.833333 4.75 0.875 2.666667 4.00 2.5714286
## 6 6 2 14 1 Pasteur 7 5.333333 5.00 2.250 1.000000 3.00 0.8571429
## x7 x8 x9
## 1 3.391304 5.75 6.361111
## 2 3.782609 6.25 7.916667
## 3 3.260870 3.90 4.416667
## 4 3.000000 5.30 4.861111
## 5 3.695652 6.30 5.916667
## 6 4.347826 6.65 7.500000
La vista preliminar de las primeras observaciones permite identificar el tipo general de información contenida en la base de datos, incluyendo variables demográficas, una variable de agrupación y puntuaciones en pruebas cognitivas.
El estudio original contiene puntuaciones de pruebas de capacidad mental aplicadas a 301 estudiantes de séptimo y octavo grado pertenecientes a dos escuelas distintas: Pasteur y Grant-White. En la versión completa del estudio se incluyen 26 pruebas; sin embargo, gran parte de la literatura utiliza un subconjunto reducido de 15 variables, que es el que se emplea en esta aplicación.
dim(HolzingerSwineford1939)
## [1] 301 15
La dimensión del conjunto de datos confirma que se dispone de 301 observaciones y 15 variables, lo cual resulta adecuado para ilustrar procedimientos de análisis factorial confirmatorio y evaluación de invarianza multigrupo.
Adicionalmente, el conjunto de datos presenta las siguientes características clave para el análisis de invarianza de medida:
Dos grupos, definidos por la variable school (Pasteur y Grant-White), que actúa como variable de agrupación en el análisis multigrupo.
Tres constructos latentes teóricamente definidos:
visual: habilidades de percepción visual.
textual: habilidades verbales.
speed: rapidez en tareas cognitivas.
Nueve indicadores observados, distribuidos equitativamente en tres ítems por cada factor latente.
A continuación se muestran los nombres de todas las variables incluidas en el conjunto de datos:
names(HolzingerSwineford1939)
## [1] "id" "sex" "ageyr" "agemo" "school" "grade" "x1" "x2"
## [9] "x3" "x4" "x5" "x6" "x7" "x8" "x9"
Las variables pueden agruparse conceptualmente de la siguiente forma:
Variables de identificación y contexto:
id: identificador del estudiante.
school: escuela (group 1 = Pasteur o group 2 = Grant-White).
grade: grado escolar.
Variables demográficas:
sex: género (1 = Male o 2 = Female).
ageyr: edad (parte del año).
agemo: edad (parte del mes).
Indicadores cognitivos utilizados en el modelo factorial:
Factor visual: habilidades de percepción y razonamiento visual
x1: percepción visual
x2: cubos
x3: pastillas
Factor textual : habilidades verbales y de comprensión lingüística
x4: comprensión de párrafos
x5: completar oraciones
x6: significado de la palabra
Factor speed: rapidez en tareas cognitivas simples
x7: adición acelerada
x8: conteo acelerado de puntos
x9: discriminación acelerada de letras mayúsculas rectas y curvas
Finalmente, se inspecciona la estructura interna del conjunto de datos para identificar el tipo de cada variable (numérica, factor, carácter), información relevante para la correcta especificación del modelo CFA multigrupo:
str(HolzingerSwineford1939)
## 'data.frame': 301 obs. of 15 variables:
## $ id : int 1 2 3 4 5 6 7 8 9 11 ...
## $ sex : int 1 2 2 1 2 2 1 2 2 2 ...
## $ ageyr : int 13 13 13 13 12 14 12 12 13 12 ...
## $ agemo : int 1 7 1 2 2 1 1 2 0 5 ...
## $ school: Factor w/ 2 levels "Grant-White",..: 2 2 2 2 2 2 2 2 2 2 ...
## $ grade : int 7 7 7 7 7 7 7 7 7 7 ...
## $ x1 : num 3.33 5.33 4.5 5.33 4.83 ...
## $ x2 : num 7.75 5.25 5.25 7.75 4.75 5 6 6.25 5.75 5.25 ...
## $ x3 : num 0.375 2.125 1.875 3 0.875 ...
## $ x4 : num 2.33 1.67 1 2.67 2.67 ...
## $ x5 : num 5.75 3 1.75 4.5 4 3 6 4.25 5.75 5 ...
## $ x6 : num 1.286 1.286 0.429 2.429 2.571 ...
## $ x7 : num 3.39 3.78 3.26 3 3.7 ...
## $ x8 : num 5.75 6.25 3.9 5.3 6.3 6.65 6.2 5.15 4.65 4.55 ...
## $ x9 : num 6.36 7.92 4.42 4.86 5.92 ...
Esta inspección confirma la presencia de variables categóricas (por ejemplo, school) y variables numéricas correspondientes a los indicadores observados, lo cual resulta fundamental para la correcta definición del modelo de medición y del análisis multigrupo posterior.
Estos datos son especialmente adecuados para ilustrar la evaluación de la invarianza de medida, ya que permiten examinar si la estructura factorial y la relación entre ítems y factores se mantiene estable entre contextos educativos distintos, antes de realizar comparaciones sustantivas entre grupos.
Antes de proceder a la especificación del modelo factorial y al análisis de invarianza de medida, se presentan algunas tablas descriptivas básicas con el único propósito de explorar la distribución de las variables de contexto y demográficas incluidas en el conjunto de datos. Estas tablas permiten:
Verificar la codificación de las variables.
Identificar el tamaño de los grupos potenciales para el análisis multigrupo.
Detectar posibles desbalances extremos que puedan afectar la estabilidad de los modelos posteriores.
Cabe resaltar que estos descriptivos no tienen un objetivo inferencial, ni sustituyen el análisis factorial confirmatorio, sino que cumplen una función exploratoria y de control preliminar.
table(HolzingerSwineford1939$sex)
##
## 1 2
## 146 155
table(HolzingerSwineford1939$school)
##
## Grant-White Pasteur
## 145 156
table(HolzingerSwineford1939$grade)
##
## 7 8
## 157 143
table(HolzingerSwineford1939$ageyr)
##
## 11 12 13 14 15 16
## 8 101 110 55 20 7
table(HolzingerSwineford1939$agemo)
##
## 0 1 2 3 4 5 6 7 8 9 10 11
## 22 31 26 26 27 27 21 25 26 23 19 28
HolzingerSwineford1939 %>%
select(x1:x9) %>%
gather("Variable", "value") %>%
group_by(Variable) %>%
summarise(Mean=mean(value, na.rm=TRUE),
SD=sd(value, na.rm=TRUE),
min=min(value, na.rm=TRUE),
max=max(value, na.rm=TRUE),
'% Missing'=100*length(which(is.na(value)))/n()) %>%
kable(digits=2, format="pandoc", caption="Descriptive Statistics for Observed Variables")
| Variable | Mean | SD | min | max | % Missing |
|---|---|---|---|---|---|
| x1 | 4.94 | 1.17 | 0.67 | 8.50 | 0 |
| x2 | 6.09 | 1.18 | 2.25 | 9.25 | 0 |
| x3 | 2.25 | 1.13 | 0.25 | 4.50 | 0 |
| x4 | 3.06 | 1.16 | 0.00 | 6.33 | 0 |
| x5 | 4.34 | 1.29 | 1.00 | 7.00 | 0 |
| x6 | 2.19 | 1.10 | 0.14 | 6.14 | 0 |
| x7 | 4.19 | 1.09 | 1.30 | 7.43 | 0 |
| x8 | 5.53 | 1.01 | 3.05 | 10.00 | 0 |
| x9 | 5.37 | 1.01 | 2.78 | 9.25 | 0 |
A partir de estas distribuciones, se confirma que la variable school define dos grupos claramente diferenciados, lo que la convierte en una elección natural para ilustrar el análisis de invarianza de medida en los apartados siguientes.
El primer paso en la evaluación de la invarianza de medida consiste en especificar un modelo factorial confirmatorio (CFA) que represente la relación entre los ítems observados y los constructos latentes de interés.
En este ejemplo se consideran tres factores latentes (visual, textual y speed), cada uno medido mediante tres indicadores observados.
lavaanEn el paquete lavaan, los modelos de medición se especifican mediante una sintaxis basada en ecuaciones estructurales. En particular:
El operador =~ indica una relación de medición, es decir, que un factor latente explica un conjunto de variables observadas.
Las variables a la izquierda de =~ representan constructos latentes.
Las variables a la derecha representan indicadores observados.
Por ejemplo, la expresión:
visual =~ x1 + x2 + x3
indica que el factor latente visual se mide a través de los ítems x1, x2 y x3. Las cargas factoriales asociadas a estas relaciones se estiman a partir de los datos, salvo aquellas que se fijan para garantizar la identificabilidad del modelo (por ejemplo, fijando una carga factorial a 1 en cada factor).
A partir de esta sintaxis, el modelo factorial propuesto para el estudio de Holzinger y Swineford (1939) se especifica como sigue:
library(lavaan)
HS.model <- '
visual =~ x1 + x2 + x3
textual =~ x4 + x5 + x6
speed =~ x7 + x8 + x9
'
Este modelo se ajusta inicialmente sin considerar restricciones entre grupos, con el fin de evaluar su ajuste global y establecer una base para los análisis de invarianza multigrupo que se presentan a continuación.
Una vez especificado el modelo factorial, el primer paso en la evaluación de la invarianza de medida consiste en ajustar el modelo configural multigrupo. Este modelo establece el punto de partida obligatorio para cualquier análisis de invarianza.
El modelo configural evalúa si la estructura factorial básica es la misma en todos los grupos, sin imponer restricciones de igualdad sobre los parámetros del modelo.
En este caso, el modelo CFA definido previamente se ajusta de forma simultánea en los dos grupos definidos por la variable school.
model_configuralEl modelo configural se estima mediante la función cfa() del paquete lavaan:
model_configural <- cfa(HS.model, data = HolzingerSwineford1939, group = "school")
En este código:
HS.model contiene la especificación del modelo factorial, definida previamente mediante la sintaxis de lavaan, donde se establece qué indicadores observados miden cada factor latente.
data = HolzingerSwineford1939 indica el conjunto de datos sobre el cual se estima el modelo.
group = "school" especifica que el modelo debe ajustarse en un marco multigrupo, estimando el modelo por separado para cada nivel de la variable school, en este caso las escuelas Pasteur y Grant-White.
Por defecto, cuando se utiliza el argumento group sin imponer restricciones adicionales, lavaan asume un modelo configural, lo que implica que:
Se ajusta el mismo patrón factorial en todos los grupos (mismo número de factores y misma asignación de ítems a factores).
Las cargas factoriales, los interceptos y las varianzas residuales se estiman libremente en cada grupo.
No se imponen restricciones de igualdad sobre ningún parámetro entre grupos.
En consecuencia, este modelo permite evaluar exclusivamente si la estructura conceptual del constructo es comparable entre grupos, sin asumir todavía equivalencia cuantitativa de los parámetros.
model_configuralLa salida que se obtiene con
model_configural
es como se muestra abajo:
## lavaan 0.6-19 ended normally after 57 iterations
##
## Estimator ML
## Optimization method NLMINB
## Number of model parameters 60
##
## Number of observations per group:
## Pasteur 156
## Grant-White 145
##
## Model Test User Model:
##
## Test statistic 115.851
## Degrees of freedom 48
## P-value (Chi-square) 0.000
## Test statistic for each group:
## Pasteur 64.309
## Grant-White 51.542
model_configuralEl ajuste del modelo configural se estimó correctamente, como lo indica el mensaje:
lavaan 0.6-19 ended normally after 57 iterations
Esto confirma que el algoritmo de optimización convergió sin problemas, por lo que los resultados obtenidos son numéricamente estables y pueden interpretarse con confianza.
En la cabecera del output del modelo configural se reporta información relevante sobre el procedimiento de estimación utilizado por lavaan:
Estimator ML
Optimization method NLMINB
Number of model parameters 60
Estimator: ML
El modelo fue estimado mediante Máxima Verosimilitud (Maximum Likelihood, ML). Este estimador asume que las variables observadas siguen, al menos aproximadamente, una distribución normal multivariada y es el método estándar en modelos CFA y SEM continuos.
En este ejemplo, el uso de ML es coherente con la naturaleza aproximadamente continua de las puntuaciones de las pruebas cognitivas incluidas en el estudio.
Optimization method: NLMINB
El algoritmo de optimización utilizado es NLMINB, un método numérico eficiente para la minimización de funciones no lineales con restricciones.
Este algoritmo es el optimizador por defecto de lavaan y se encarga de encontrar los valores de los parámetros que maximizan la función de verosimilitud del modelo. El hecho de que el modelo haya convergido indica que este proceso fue exitoso.
Number of model parameters: 60
Este valor indica que el modelo configural estima 60 parámetros libres en total, considerando simultáneamente ambos grupos. Dado que en el modelo configural las cargas factoriales, los interceptos, las varianzas residuales, las varianzas y covarianzas latentes se estiman libremente en cada grupo, el número de parámetros es relativamente elevado. Este aspecto es clave, ya que en los modelos posteriores (métrico, escalar y estricto) el número de parámetros disminuirá a medida que se impongan restricciones de igualdad entre grupos.
La comparación del número de parámetros entre modelos anidados es fundamental para comprender los cambios en los índices de ajuste y en los criterios de información (AIC, BIC).
El modelo se ajustó simultáneamente en dos grupos definidos por la variable school:
Number of observations per group:
Pasteur 156
Grant-White 145
Ambos grupos presentan tamaños muestrales similares, lo cual es deseable en análisis multigrupo, ya que reduce problemas de inestabilidad o dominancia de un grupo sobre el otro.
La salida reporta información bajo Model Test User Model:
Model Test User Model:
Test statistic 115.851
Degrees of freedom 48
P-value (Chi-square) 0.000
En este caso, el estadístico χ² reportado corresponde a un contraste de ajuste exacto del modelo configural. Formalmente, las hipótesis evaluadas son:
Hipótesis nula (H₀): El modelo configural reproduce exactamente la matriz de covarianzas poblacional en todos los grupos, es decir, no existen discrepancias entre las covarianzas observadas y las covarianzas implícitas por el modelo.
Hipótesis alternativa (H₁): El modelo configural no reproduce exactamente la matriz de covarianzas poblacional; existen discrepancias sistemáticas entre el modelo y los datos.
El estadístico χ² = 115.851 con 48 grados de libertad y p < 0.001 conduce al rechazo de H₀, indicando que el modelo no presenta un ajuste exacto. Sin embargo, este resultado debe interpretarse con cautela, ya que el test χ² es altamente sensible al tamaño muestral y a pequeñas discrepancias entre el modelo y los datos, siendo frecuente su rechazo en modelos CFA con muestras moderadas o grandes.
Por esta razón, en la evaluación del modelo configural no se toma una decisión exclusivamente con base en el χ², sino que se consideran índices de ajuste aproximado (CFI, RMSEA, SRMR), que se analizan en conjunto.
El output también reporta el estadístico χ² estimado por separado en cada grupo:
Test statistic for each group:
Pasteur 64.309
Grant-White 51.542
En este caso,
Pasteur: χ² = 64.309
Grant-White: χ² = 51.542
Desde el punto de vista inferencial, estos estadísticos χ² por grupo evalúan las mismas hipótesis de ajuste exacto (H₀ vs. H₁), pero de forma independiente en cada grupo. El hecho de que ambos valores sean del mismo orden de magnitud sugiere que:
El modelo presenta un comportamiento estructural comparable en Pasteur y Grant-White, reforzando la plausibilidad del modelo configural como punto de partida.
Es decir, en ambos grupos, el modelo presenta discrepancias con los datos observados, aunque de magnitud comparable, lo cual sugiere que la estructura factorial propuesta funciona de manera similar en ambos contextos educativos.
En conjunto, estos resultados permiten concluir que:
El modelo configural es estimable y estable en ambos grupos.
La estructura factorial básica (tres factores y patrón de cargas) es conceptualmente plausible en Pasteur y Grant-White.
A pesar del rechazo del ajuste exacto según χ², el modelo puede considerarse un punto de partida válido para continuar con la evaluación de la invarianza de medida, siempre que los índices de ajuste aproximado sean aceptables.
Este resultado satisface el objetivo del modelo configural: verificar que los constructos latentes tienen la misma forma conceptual en todos los grupos, lo cual es una condición necesaria para avanzar hacia la evaluación de la invarianza métrica.
En esta etapa, el criterio central no es la perfección del ajuste, sino la plausibilidad estructural del modelo en todos los grupos, la cual se evalúa principalmente mediante índices de ajuste aproximado y no únicamente a través del test χ².
Es importante enfatizar que este resultado no autoriza todavía ninguna comparación cuantitativa entre grupos; únicamente establece que los constructos están definidos de manera conceptualmente equivalente.
summaryUna vez estimado el modelo configural, se obtiene un resumen detallado de los resultados mediante:
summary(model_configural, fit.measures = TRUE)
## lavaan 0.6-19 ended normally after 57 iterations
##
## Estimator ML
## Optimization method NLMINB
## Number of model parameters 60
##
## Number of observations per group:
## Pasteur 156
## Grant-White 145
##
## Model Test User Model:
##
## Test statistic 115.851
## Degrees of freedom 48
## P-value (Chi-square) 0.000
## Test statistic for each group:
## Pasteur 64.309
## Grant-White 51.542
##
## Model Test Baseline Model:
##
## Test statistic 957.769
## Degrees of freedom 72
## P-value 0.000
##
## User Model versus Baseline Model:
##
## Comparative Fit Index (CFI) 0.923
## Tucker-Lewis Index (TLI) 0.885
##
## Loglikelihood and Information Criteria:
##
## Loglikelihood user model (H0) -3682.198
## Loglikelihood unrestricted model (H1) -3624.272
##
## Akaike (AIC) 7484.395
## Bayesian (BIC) 7706.822
## Sample-size adjusted Bayesian (SABIC) 7516.536
##
## Root Mean Square Error of Approximation:
##
## RMSEA 0.097
## 90 Percent confidence interval - lower 0.075
## 90 Percent confidence interval - upper 0.120
## P-value H_0: RMSEA <= 0.050 0.001
## P-value H_0: RMSEA >= 0.080 0.897
##
## Standardized Root Mean Square Residual:
##
## SRMR 0.068
##
## Parameter Estimates:
##
## Standard errors Standard
## Information Expected
## Information saturated (h1) model Structured
##
##
## Group 1 [Pasteur]:
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|)
## visual =~
## x1 1.000
## x2 0.394 0.122 3.220 0.001
## x3 0.570 0.140 4.076 0.000
## textual =~
## x4 1.000
## x5 1.183 0.102 11.613 0.000
## x6 0.875 0.077 11.421 0.000
## speed =~
## x7 1.000
## x8 1.125 0.277 4.057 0.000
## x9 0.922 0.225 4.104 0.000
##
## Covariances:
## Estimate Std.Err z-value P(>|z|)
## visual ~~
## textual 0.479 0.106 4.531 0.000
## speed 0.185 0.077 2.397 0.017
## textual ~~
## speed 0.182 0.069 2.628 0.009
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|)
## .x1 4.941 0.095 52.249 0.000
## .x2 5.984 0.098 60.949 0.000
## .x3 2.487 0.093 26.778 0.000
## .x4 2.823 0.092 30.689 0.000
## .x5 3.995 0.105 38.183 0.000
## .x6 1.922 0.079 24.321 0.000
## .x7 4.432 0.087 51.181 0.000
## .x8 5.563 0.078 71.214 0.000
## .x9 5.418 0.079 68.440 0.000
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .x1 0.298 0.232 1.286 0.198
## .x2 1.334 0.158 8.464 0.000
## .x3 0.989 0.136 7.271 0.000
## .x4 0.425 0.069 6.138 0.000
## .x5 0.456 0.086 5.292 0.000
## .x6 0.290 0.050 5.780 0.000
## .x7 0.820 0.125 6.580 0.000
## .x8 0.510 0.116 4.406 0.000
## .x9 0.680 0.104 6.516 0.000
## visual 1.097 0.276 3.967 0.000
## textual 0.894 0.150 5.963 0.000
## speed 0.350 0.126 2.778 0.005
##
##
## Group 2 [Grant-White]:
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|)
## visual =~
## x1 1.000
## x2 0.736 0.155 4.760 0.000
## x3 0.925 0.166 5.583 0.000
## textual =~
## x4 1.000
## x5 0.990 0.087 11.418 0.000
## x6 0.963 0.085 11.377 0.000
## speed =~
## x7 1.000
## x8 1.226 0.187 6.569 0.000
## x9 1.058 0.165 6.429 0.000
##
## Covariances:
## Estimate Std.Err z-value P(>|z|)
## visual ~~
## textual 0.408 0.098 4.153 0.000
## speed 0.276 0.076 3.639 0.000
## textual ~~
## speed 0.222 0.073 3.022 0.003
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|)
## .x1 4.930 0.095 51.696 0.000
## .x2 6.200 0.092 67.416 0.000
## .x3 1.996 0.086 23.195 0.000
## .x4 3.317 0.093 35.625 0.000
## .x5 4.712 0.096 48.986 0.000
## .x6 2.469 0.094 26.277 0.000
## .x7 3.921 0.086 45.819 0.000
## .x8 5.488 0.087 63.174 0.000
## .x9 5.327 0.085 62.571 0.000
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .x1 0.715 0.126 5.676 0.000
## .x2 0.899 0.123 7.339 0.000
## .x3 0.557 0.103 5.409 0.000
## .x4 0.315 0.065 4.870 0.000
## .x5 0.419 0.072 5.812 0.000
## .x6 0.406 0.069 5.880 0.000
## .x7 0.600 0.091 6.584 0.000
## .x8 0.401 0.094 4.249 0.000
## .x9 0.535 0.089 6.010 0.000
## visual 0.604 0.160 3.762 0.000
## textual 0.942 0.152 6.177 0.000
## speed 0.461 0.118 3.910 0.000
A diferencia del simple llamado a model_configural, esta salida incorpora índices globales de ajuste y criterios de comparación que serán fundamentales en las etapas posteriores del análisis de invarianza.
El argumento fit.measures = TRUE solicita que, además de las estimaciones de los parámetros, se reporten los principales índices de ajuste global, los cuales permiten evaluar si el modelo reproduce razonablemente la matriz de covarianzas observada en cada grupo.
En lo que sigue se describen únicamente los componentes no interpretados previamente, o aquellos que adquieren relevancia específica en esta etapa.
La salida de lavaan incluye también el Model Test Baseline Model, correspondiente a un modelo de referencia extremadamente restrictivo, conocido como modelo de independencia.
Model Test Baseline Model:
Test statistic 957.769
Degrees of freedom 72
P-value 0.000
En este modelo:
Todas las variables observadas se asumen no correlacionadas entre sí.
No se especifican factores latentes.
Solo se estiman medias e interceptos.
Las hipótesis asociadas a este contraste son:
H₀ (baseline): Las variables observadas son independientes entre sí.
H₁: Existen relaciones entre las variables observadas.
El valor χ² = 957.769 con 72 grados de libertad y p < 0.001 indica que el modelo de independencia es claramente inadecuado, lo cual es esperable en datos psicológicos reales. Este resultado no se interpreta de forma sustantiva, sino que cumple una función comparativa.
El modelo base es fundamental porque sirve como punto de comparación para los índices incrementales de ajuste, en particular, se obtienen los valores estimados de CFI y TLI:
User Model versus Baseline Model:
Comparative Fit Index (CFI) 0.923
Tucker-Lewis Index (TLI) 0.885
Estos índices evalúan cuánto mejora el modelo propuesto respecto al modelo de independencia. Valores cercanos a 1 indican que el modelo configural representa una mejora sustancial frente a un escenario sin estructura factorial.
La sección Loglikelihood and Information Criteria reporta los valores de la función de verosimilitud para dos modelos y los valores de criterios de información:
Loglikelihood and Information Criteria:
Loglikelihood user model (H0) -3682.198
Loglikelihood unrestricted model (H1) -3624.272
Akaike (AIC) 7484.395
Bayesian (BIC) 7706.822
Sample-size adjusted Bayesian (SABIC) 7516.536
Loglikelihood user model (H₀) = −3682.198, el cual corresponde al valor de la log-verosimilitud \(\cal{L}_{H_0}\) del modelo configural especificado.
Loglikelihood unrestricted model (H₁) = −3624.272, el cual corresponde al \(\cal{L}_{H_1}\) del modelo saturado. Reproduce perfectamente los datos y sirve como referencia teórica de ajuste máximo.
La diferencia entre estos valores está directamente relacionada con el estadístico χ² del modelo, ya que:
\[ \chi^2 = 2 \left(\cal{L}_{H_1} - \cal{L}_{H_0} \right) \]
A partir de estas log-verosimilitudes se derivan los criterios de información AIC, BIC y SABIC, que penalizan la complejidad del modelo y serán útiles para comparar modelos anidados en los siguientes niveles de invarianza..
La salida incluye también índices de ajuste aproximado:
Root Mean Square Error of Approximation:
RMSEA 0.097
90 Percent confidence interval - lower 0.075
90 Percent confidence interval - upper 0.120
P-value H_0: RMSEA <= 0.050 0.001
P-value H_0: RMSEA >= 0.080 0.897
Standardized Root Mean Square Residual:
SRMR 0.068
RMSEA (Root Mean Square Error of Approximation), acompañado de su intervalo de confianza al 90% y pruebas asociadas (que permite evaluar la
precisión de la estimación). Evalúa el grado de desajuste aproximado del modelo por grado de libertad, bajo la idea de que todo modelo es una aproximación a la realidad. Umbrales de interpretación habituales:
RMSEA ≤ 0.05: ajuste bueno.
0.05 < RMSEA ≤ 0.08: ajuste aceptable.
0.08 < RMSEA ≤ 0.10: ajuste mediocre.
RMSEA > 0.10: ajuste pobre.
SRMR (Standardized Root Mean Square Residual), que resume la magnitud promedio de los residuos estandarizados. Resume la magnitud promedio de los residuos estandarizados, es decir, qué tan bien el modelo reproduce las covarianzas observadas. Umbrales de interpretación habituales:
SRMR ≤ 0.08: ajuste bueno.
0.08 < SRMR ≤ 0.10: ajuste aceptable.
SRMR > 0.10: ajuste deficiente.
El SRMR es especialmente útil en modelos multigrupo y es poco sensible al tamaño muestral, lo que lo convierte en un buen complemento del RMSEA. Estos índices permiten evaluar el ajuste del modelo desde una perspectiva aproximada, menos sensible al tamaño muestral que el test χ².
Parameter EstimatesAntes de listar las estimaciones por grupo, summary() presenta un breve bloque descriptivo que indica cómo fueron calculados los errores estándar y qué tipo de información se utilizó durante la estimación:
Parameter Estimates:
Standard errors Standard
Information Expected
Information saturated (h1) model Structured
Este bloque no contiene parámetros, sino que describe las opciones metodológicas utilizadas por lavaan. Su interpretación es la siguiente:
Standard errors: Standard. Los errores estándar se calcularon bajo supuestos estándar de máxima verosimilitud (ML), es decir, asumiendo normalidad multivariada y tamaño muestral suficiente.
Information: Expected. Se utilizó la matriz de información esperada (Fisher information) para calcular los errores estándar. Esta es la opción por defecto y suele ser más estable que la información observada en muestras moderadas.
Information saturated (h1) model: Structured. Indica que el modelo saturado de referencia (H1) respeta la estructura multigrupo del modelo, lo cual es coherente con la estimación en SEM multigrupo.
Nota pedagógica
Este bloque sirve para verificar cómo se estimaron los parámetros, pero no requiere interpretación sustantiva. Su función principal es documentar las decisiones técnicas adoptadas por el software durante la estimación.
summary (estimaciones por grupo)Finalmente, summary() reporta las estimaciones de los parámetros del modelo por separado para cada grupo, en este caso Pasteur y Grant-White. Esta salida suele resultar difícil de interpretar en una primera lectura, ya que utiliza operadores y convenciones propias de la sintaxis SEM. A continuación se explican sus componentes principales.
La salida se organiza por grupos:
Group 1 [Pasteur]:
Group 2 [Grant-White]:
En esta parte de la salida, summary() reporta las estimaciones de parámetros por grupo (cargas, interceptos, varianzas y covarianzas) para Pasteur y Grant-White.
Group 1 [Pasteur]:
Estimate Std.Err z-value P(>|z|)
Latent Variables: . . . .
Covariances: . . . .
Intercepts: . . . .
Variances: . . . .
Group 2 [Grant-White]:
Estimate Std.Err z-value P(>|z|)
Latent Variables: . . . .
Covariances: . . . .
Intercepts: . . . .
Variances: . . . .
En el modelo configural, estas estimaciones se interpretan de forma descriptiva. Sin realizar aún comparaciones cuantitativas entre grupos, se debe verificar que:
Las cargas sean razonables.
El patrón factorial sea coherente.
No existan anomalías evidentes.
Esto indica que todos los parámetros que siguen se estiman de forma independiente en cada grupo, como corresponde al modelo configural.
Como puede verse en el bloque anterior, en todas las secciones aparecen las mismas columnas:
Estimate: estimación puntual del parámetro.
Std.Err: error estándar.
z-value: estadístico de prueba \(Z=\frac{\text{Estimate}}{\text{Std.Error}}\).
P(>|z|): valor p asociado.
En el modelo configural, estos valores se usan como diagnóstico, no como base para inferencias comparativas entre grupos.
=~El bloque Latent Variables contiene las cargas factoriales. El operador =~ se lee como “es medido por”. Por ejemplo:
visual =~ x1 + x2 + x3
indica que el factor latente visual explica los indicadores observados x1, x2 y x3. En la salida:
Latent Variables:
Estimate Std.Err z-value P(>|z|)
visual =~
x1 1.000
x2 0.394 0.122 3.220 0.001
x3 0.570 0.140 4.076 0.000
En lo anterior:
El valor 1.000 corresponde a la carga fijada para identificar la escala del factor (ítem de referencia).
Las demás cargas (0.394 y 0.570) se estiman libremente.
Estimate es la estimación puntual de la carga.
Std.Err, z-value y P(>|z|) corresponden al contraste estadístico de si la carga es distinta de cero.
En el modelo configural, estas cargas se interpretan de forma descriptiva, verificando que:
Tengan el signo esperado,
Sean de magnitud razonable,
Mantengan un patrón coherente con la teoría.
Se resalta que no se comparan aún entre grupos.
~~El bloque Covariances reporta las covarianzas entre factores latentes. El operador ~~ se interpreta como “covaría con”. Una parte de la salida es:
Covariances:
Estimate Std.Err z-value P(>|z|)
visual ~~
textual 0.408 0.098 4.153 0.000
speed 0.276 0.076 3.639 0.000
textual ~~
speed 0.222 0.073 3.022 0.003
Por ejemplo:
visual ~~ textual
indica la covarianza entre los factores visual y textual. Estas covarianzas:
Se estiman libremente en cada grupo (Estimate).
Permiten evaluar si los factores están relacionados.
No se comparan cuantitativamente entre grupos en el modelo configural.
.El bloque Intercepts reporta los interceptos de los indicadores observados:
Intercepts:
Estimate Std.Err z-value P(>|z|)
.x1 4.930 0.095 51.696 0.000
.x2 6.200 0.092 67.416 0.000
.x3 1.996 0.086 23.195 0.000
.x4 3.317 0.093 35.625 0.000
.x5 4.712 0.096 48.986 0.000
.x6 2.469 0.094 26.277 0.000
.x7 3.921 0.086 45.819 0.000
.x8 5.488 0.087 63.174 0.000
.x9 5.327 0.085 62.571 0.000
La notación .x1, .x2, etc., indica el intercepto del ítem correspondiente. Por ejemplo:
Intercept Estimate
.x1 4.930
representa el valor estimado de x1 cuando el factor latente es cero. En el modelo configural:
Los interceptos se estiman libremente en cada grupo,
No se interpretan comparativamente.
Su función principal es preparar el terreno para la evaluación de la invarianza escalar.
.El bloque Variances contiene dos tipos de varianzas:
Varianzas residuales de los ítems: representan la variabilidad del indicador no explicada por el factor, indicadas en el bloque:
Variances:
Estimate Std.Err z-value P(>|z|)
.x1 0.715 0.126 5.676 0.000
.x2 0.899 0.123 7.339 0.000
.x3 0.557 0.103 5.409 0.000
.x4 0.315 0.065 4.870 0.000
.x5 0.419 0.072 5.812 0.000
.x6 0.406 0.069 5.880 0.000
.x7 0.600 0.091 6.584 0.000
.x8 0.401 0.094 4.249 0.000
.x9 0.535 0.089 6.010 0.000
Varianzas de los factores latentes: representan la variabilidad del constructo latente en cada grupo, indicadas en el bloque:
Variances:
Estimate Std.Err z-value P(>|z|)
. . . . .
. . . . .
visual 0.604 0.160 3.762 0.000
textual 0.942 0.152 6.177 0.000
speed 0.461 0.118 3.910 0.000
En el modelo configural:
Todas estas varianzas se estiman libremente.
Su inspección permite detectar valores problemáticos (muy pequeños, negativos, no significativos).
Pero no habilitan comparaciones entre grupos.
En resumen, en el modelo configural las estimaciones por grupo se utilizan para:
Verificar que el modelo es estimable en todos los grupos,
Confirmar que el patrón factorial es razonable,
Detectar anomalías evidentes (cargas negativas inesperadas, varianzas problemáticas, etc.).
No se realizan todavía:
Comparaciones de cargas,
Comparaciones de interceptos,
Ni comparaciones de varianzas entre grupos.
Estas comparaciones solo serán válidas una vez se impongan las restricciones correspondientes en los modelos de invarianza métrica y escalar.
summary (lectura recomendada)Una lectura práctica y ordenada de esta salida suele seguir este flujo:
Verificar que el modelo convergió (...ended normally...).
Revisar el tamaño de muestra por grupo.
Evaluar el ajuste global (CFI, TLI, RMSEA, SRMR y χ²).
Examinar los criterios de información (AIC, BIC y SABIC) como referencia comparativa.
Confirmar que las cargas factoriales y el patrón general son razonables en cada grupo, antes de pasar al siguiente nivel de invarianza.
parTableparTableAdemás del resumen habitual (summary()), los parámetros del modelo configural pueden inspeccionarse directamente mediante la función parTable(), la cual devuelve la tabla interna de parámetros que lavaan utiliza para estimar el modelo:
param<-parTable(model_configural)
param
## id lhs op rhs user block group free ustart exo label plabel start
## 1 1 visual =~ x1 1 1 1 0 1 0 .p1. 1.000
## 2 2 visual =~ x2 1 1 1 1 NA 0 .p2. 0.769
## 3 3 visual =~ x3 1 1 1 2 NA 0 .p3. 1.186
## 4 4 textual =~ x4 1 1 1 0 1 0 .p4. 1.000
## 5 5 textual =~ x5 1 1 1 3 NA 0 .p5. 1.237
## 6 6 textual =~ x6 1 1 1 4 NA 0 .p6. 0.865
## 7 7 speed =~ x7 1 1 1 0 1 0 .p7. 1.000
## 8 8 speed =~ x8 1 1 1 5 NA 0 .p8. 1.227
## 9 9 speed =~ x9 1 1 1 6 NA 0 .p9. 0.827
## 10 10 x1 ~~ x1 0 1 1 7 NA 0 .p10. 0.698
## 11 11 x2 ~~ x2 0 1 1 8 NA 0 .p11. 0.752
## 12 12 x3 ~~ x3 0 1 1 9 NA 0 .p12. 0.673
## 13 13 x4 ~~ x4 0 1 1 10 NA 0 .p13. 0.660
## 14 14 x5 ~~ x5 0 1 1 11 NA 0 .p14. 0.854
## 15 15 x6 ~~ x6 0 1 1 12 NA 0 .p15. 0.487
## 16 16 x7 ~~ x7 0 1 1 13 NA 0 .p16. 0.585
## 17 17 x8 ~~ x8 0 1 1 14 NA 0 .p17. 0.476
## 18 18 x9 ~~ x9 0 1 1 15 NA 0 .p18. 0.489
## 19 19 visual ~~ visual 0 1 1 16 NA 0 .p19. 0.050
## 20 20 textual ~~ textual 0 1 1 17 NA 0 .p20. 0.050
## 21 21 speed ~~ speed 0 1 1 18 NA 0 .p21. 0.050
## 22 22 visual ~~ textual 0 1 1 19 NA 0 .p22. 0.000
## 23 23 visual ~~ speed 0 1 1 20 NA 0 .p23. 0.000
## 24 24 textual ~~ speed 0 1 1 21 NA 0 .p24. 0.000
## 25 25 x1 ~1 0 1 1 22 NA 0 .p25. 4.941
## 26 26 x2 ~1 0 1 1 23 NA 0 .p26. 5.984
## 27 27 x3 ~1 0 1 1 24 NA 0 .p27. 2.487
## 28 28 x4 ~1 0 1 1 25 NA 0 .p28. 2.823
## 29 29 x5 ~1 0 1 1 26 NA 0 .p29. 3.995
## 30 30 x6 ~1 0 1 1 27 NA 0 .p30. 1.922
## 31 31 x7 ~1 0 1 1 28 NA 0 .p31. 4.432
## 32 32 x8 ~1 0 1 1 29 NA 0 .p32. 5.563
## 33 33 x9 ~1 0 1 1 30 NA 0 .p33. 5.418
## 34 34 visual ~1 0 1 1 0 0 0 .p34. 0.000
## 35 35 textual ~1 0 1 1 0 0 0 .p35. 0.000
## 36 36 speed ~1 0 1 1 0 0 0 .p36. 0.000
## 37 37 visual =~ x1 1 2 2 0 1 0 .p37. 1.000
## 38 38 visual =~ x2 1 2 2 31 NA 0 .p38. 0.896
## 39 39 visual =~ x3 1 2 2 32 NA 0 .p39. 1.155
## 40 40 textual =~ x4 1 2 2 0 1 0 .p40. 1.000
## 41 41 textual =~ x5 1 2 2 33 NA 0 .p41. 0.991
## 42 42 textual =~ x6 1 2 2 34 NA 0 .p42. 0.962
## 43 43 speed =~ x7 1 2 2 0 1 0 .p43. 1.000
## 44 44 speed =~ x8 1 2 2 35 NA 0 .p44. 1.282
## 45 45 speed =~ x9 1 2 2 36 NA 0 .p45. 0.895
## 46 46 x1 ~~ x1 0 2 2 37 NA 0 .p46. 0.659
## 47 47 x2 ~~ x2 0 2 2 38 NA 0 .p47. 0.613
## 48 48 x3 ~~ x3 0 2 2 39 NA 0 .p48. 0.537
## 49 49 x4 ~~ x4 0 2 2 40 NA 0 .p49. 0.629
## 50 50 x5 ~~ x5 0 2 2 41 NA 0 .p50. 0.671
## 51 51 x6 ~~ x6 0 2 2 42 NA 0 .p51. 0.640
## 52 52 x7 ~~ x7 0 2 2 43 NA 0 .p52. 0.531
## 53 53 x8 ~~ x8 0 2 2 44 NA 0 .p53. 0.547
## 54 54 x9 ~~ x9 0 2 2 45 NA 0 .p54. 0.526
## 55 55 visual ~~ visual 0 2 2 46 NA 0 .p55. 0.050
## 56 56 textual ~~ textual 0 2 2 47 NA 0 .p56. 0.050
## 57 57 speed ~~ speed 0 2 2 48 NA 0 .p57. 0.050
## 58 58 visual ~~ textual 0 2 2 49 NA 0 .p58. 0.000
## 59 59 visual ~~ speed 0 2 2 50 NA 0 .p59. 0.000
## 60 60 textual ~~ speed 0 2 2 51 NA 0 .p60. 0.000
## 61 61 x1 ~1 0 2 2 52 NA 0 .p61. 4.930
## 62 62 x2 ~1 0 2 2 53 NA 0 .p62. 6.200
## 63 63 x3 ~1 0 2 2 54 NA 0 .p63. 1.996
## 64 64 x4 ~1 0 2 2 55 NA 0 .p64. 3.317
## 65 65 x5 ~1 0 2 2 56 NA 0 .p65. 4.712
## 66 66 x6 ~1 0 2 2 57 NA 0 .p66. 2.469
## 67 67 x7 ~1 0 2 2 58 NA 0 .p67. 3.921
## 68 68 x8 ~1 0 2 2 59 NA 0 .p68. 5.488
## 69 69 x9 ~1 0 2 2 60 NA 0 .p69. 5.327
## 70 70 visual ~1 0 2 2 0 0 0 .p70. 0.000
## 71 71 textual ~1 0 2 2 0 0 0 .p71. 0.000
## 72 72 speed ~1 0 2 2 0 0 0 .p72. 0.000
## est se
## 1 1.000 0.000
## 2 0.394 0.122
## 3 0.570 0.140
## 4 1.000 0.000
## 5 1.183 0.102
## 6 0.875 0.077
## 7 1.000 0.000
## 8 1.125 0.277
## 9 0.922 0.225
## 10 0.298 0.232
## 11 1.334 0.158
## 12 0.989 0.136
## 13 0.425 0.069
## 14 0.456 0.086
## 15 0.290 0.050
## 16 0.820 0.125
## 17 0.510 0.116
## 18 0.680 0.104
## 19 1.097 0.276
## 20 0.894 0.150
## 21 0.350 0.126
## 22 0.479 0.106
## 23 0.185 0.077
## 24 0.182 0.069
## 25 4.941 0.095
## 26 5.984 0.098
## 27 2.487 0.093
## 28 2.823 0.092
## 29 3.995 0.105
## 30 1.922 0.079
## 31 4.432 0.087
## 32 5.563 0.078
## 33 5.418 0.079
## 34 0.000 0.000
## 35 0.000 0.000
## 36 0.000 0.000
## 37 1.000 0.000
## 38 0.736 0.155
## 39 0.925 0.166
## 40 1.000 0.000
## 41 0.990 0.087
## 42 0.963 0.085
## 43 1.000 0.000
## 44 1.226 0.187
## 45 1.058 0.165
## 46 0.715 0.126
## 47 0.899 0.123
## 48 0.557 0.103
## 49 0.315 0.065
## 50 0.419 0.072
## 51 0.406 0.069
## 52 0.600 0.091
## 53 0.401 0.094
## 54 0.535 0.089
## 55 0.604 0.160
## 56 0.942 0.152
## 57 0.461 0.118
## 58 0.408 0.098
## 59 0.276 0.076
## 60 0.222 0.073
## 61 4.930 0.095
## 62 6.200 0.092
## 63 1.996 0.086
## 64 3.317 0.093
## 65 4.712 0.096
## 66 2.469 0.094
## 67 3.921 0.086
## 68 5.488 0.087
## 69 5.327 0.085
## 70 0.000 0.000
## 71 0.000 0.000
## 72 0.000 0.000
Esta tabla contiene todas las especificaciones del modelo, incluyendo cargas factoriales, varianzas, covarianzas, interceptos y medias latentes, desglosadas por grupo.
parTableA continuación se describen las columnas de parTable():
names(param)
## [1] "id" "lhs" "op" "rhs" "user" "block" "group" "free"
## [9] "ustart" "exo" "label" "plabel" "start" "est" "se"
id: identificador único de cada parámetro dentro del modelo.
lhs (left-hand side): variable del lado izquierdo del parámetro (por ejemplo, un factor latente como visual o una variable observada como x1).
op: operador que indica el tipo de relación:
=~ : carga factorial,
~~ : varianza o covarianza,
~1 : intercepto (o media latente si lhs es un factor).
rhs (right-hand side): variable del lado derecho del parámetro.
user: indica si el parámetro fue especificado explícitamente por el usuario en la sintaxis del modelo (user = 1) o si fue añadido automáticamente por lavaan para completar el modelo (user = 0).
block: identifica el bloque del modelo al que pertenece el parámetro. En SEM multigrupo, cada bloque corresponde a una combinación específica de grupo y tipo de ecuación utilizada internamente por lavaan. En realidad, esta columna no tiene interpretación sustantiva, sino que indica cómo lavaan organiza internamente el modelo para la estimación.Por ejemplo, en la tabla parTable() se observan filas como:
Parámetros del tipo visual =~ x1, visual =~ x2, visual =~ x3 con group = 1 y block = 1, los cuales pertenecen al bloque de medición
del factor visual en el primer grupo.
Parámetros del tipo x1 ~~ x1, x2 ~~ x2 aparecen en bloques distintos, ya que corresponden a varianzas residuales de variables diferentes.
En el segundo grupo (group = 2), los mismos tipos de parámetros aparecen asociados a bloques diferentes, reflejando que cada grupo tiene su propia representación interna del modelo.
group: grupo al que pertenece el parámetro (1 = primer grupo, 2 = segundo grupo).
free: indicador del estado del parámetro:
free=0 = parámetro fijo. Significa que el valor del parámetro no se estima con los datos o que el valor ya está impuesto por el modelo. Por ejemplo, en la tabla vemos:visual =~ x1 free = 0 start = 1.000
Esto quiere decir que la carga de x1 sobre visual está fijada en 1.000. No se estima (por eso, free = 0).
free>0 = parámetro libre a estimar. Por ejemplo, si se ve free = 12, no significa que el parámetro vale 12, sino que es el parámetro libre número 12 que el algoritmo estima.ustart (user start): valor inicial definido por el usuario para el parámetro de la fila correspondeinte, en caso de haberlo especificado. Si no se define, suele aparecer como NA. Por ejemplo, consideremos esta fila: visual =~ x2 ustart = NA. En este caso, el parámetro es la carga factorial de x2 sobre visual. No se indicó ningún valor inicial en la sintaxis. Por eso, lavaan asignó automáticamente un valor inicial (aparece en start). Por eso ustart = NA. Entonces, se vería visual =~ x1 ustart = 0.5si el modelo fuese:HS.model <- 'visual =~ 0.5*x1 + x2 + x3'
exo: indica si la variable asociada al parámetro es tratada como exógena (exo = 1) o endógena (exo = 0). En modelos CFA estándar, la mayoría de variables observadas se tratan como endógenas.
label: etiqueta interna del parámetro, utilizada para imponer restricciones de igualdad entre grupos. La columna labelse usa cuando se quiere que varios parámetros compartan el mismo valor y si dos filas tienen el mismo label, lavaan las trata como un solo parámetro común. Por ejemplo, supongamos que se quiere que la carga de x2 sea igual en ambos grupos:
visual =~ c(a, a)*x2
En parTable() se vería algo así:
lhs op rhs group label
visual =~ x2 1 a
visual =~ x2 2 a
plabel (parameter label): etiqueta interna única utilizada por lavaan para identificar el parámetro durante la estimación. A diferencia de label, esta etiqueta es siempre única, incluso cuando se imponen restricciones de igualdad. Cada fila tiene su propio plabel (incluso cuando dos parámetros son forzados a ser iguales (label igual),
cada uno conserva su propio plabel). Considere este ejemplo:lhs op rhs group label plabel
visual =~ x2 1 a .p2.
visual =~ x2 2 a .p38.
Aquí label = a indica mismos valores (igualdad) y plabel = .p2. y .p38., parámetros distintos en la estructura interna.
start: valor inicial utilizado por el algoritmo de estimación.
est y se: estimación final del parámetro y su error estándar.
parTableEn el modelo configural se observa que:
Cada grupo tiene su propia estructura de parámetros, lo cual es coherente con la definición de la invarianza configural (misma forma del modelo, pero sin restricciones de igualdad).
Las cargas factoriales fijadas en 1.00 (por ejemplo, visual =~ x1, textual =~ x4, speed =~ x7) cumplen la función de identificación de la escala de los factores latentes.
Las filas con operador ~~ corresponden a varianzas (cuando lhs \(=\) rhs) y covarianzas (cuando lhs \(\ne\) rhs).
Las filas con operador ~1 y lhs igual a una variable observada representan interceptos; cuando lhs es un factor latente, representan medias latentes.
Las medias latentes de los factores aparecen fijadas en 0.00 en ambos grupos, lo cual es consistente con la identificación del modelo configural antes de introducir comparaciones de medias.
La función parTable() no está pensada para la interpretación sustantiva directa, sino para entender cómo lavaan codifica internamente el modelo.
Sin embargo, resulta extremadamente útil para:
Comprender la lógica de las restricciones de igualdad.
Verificar qué parámetros están fijos o libres.
Conectar la sintaxis del modelo con los resultados numéricos.
Por esta razón, parTable() es una herramienta clave para el estudio rigurosode la invarianza factorial y el SEM multigrupo.
En el modelo configural se asume que:
La estructura factorial (número de factores y patrón de cargas) es idéntica en ambos grupos.
Las cargas factoriales, los interceptos y las varianzas residuales se estiman libremente en cada grupo.
No se imponen restricciones de igualdad entre grupos.
Por lo tanto, este modelo responde a la pregunta fundamental:
¿El constructo tiene la misma forma conceptual en todos los grupos?
Un ajuste global adecuado del modelo configural indica que los ítems se organizan de manera similar en torno a los factores latentes en ambos grupos, lo cual constituye una condición necesaria para avanzar hacia niveles más restrictivos de invarianza.
En este sentido, el modelo configural evalúa la equivalencia cualitativa del constructo entre grupos, pero no su equivalencia cuantitativa.
Es importante destacar que, aun cuando el modelo configural presente un buen ajuste:
No es válido comparar medias latentes entre grupos.
No es válido comparar relaciones estructurales (por ejemplo, regresiones o correlaciones) entre factores.
No se puede asumir equivalencia métrica de los ítems (cargas factoriales comparables).
En otras palabras, el modelo configural únicamente establece que la estructura del modelo de medición es comparable, pero no que los parámetros tengan el mismo significado cuantitativo entre grupos.
Estas limitaciones inferenciales son precisamente las que motivan el paso al siguiente nivel del análisis de invarianza.
Una vez verificado que el modelo configural presenta un ajuste aceptable, el siguiente paso consiste en evaluar la invarianza métrica, imponiendo restricciones de igualdad sobre las cargas factoriales entre grupos.
Esto permitirá examinar si los ítems mantienen el mismo significado métrico y habilitará la comparación de relaciones estructurales entre los factores latentes.
En la siguiente sección se presenta el modelo métrico multigrupo y su comparación con el modelo configural.
Una vez verificada la plausibilidad estructural del modelo configural, el siguiente paso en el análisis de invarianza de medida consiste en evaluar la invarianza métrica.
La invarianza métrica examina si las cargas factoriales son equivalentes entre grupos, lo cual implica que una unidad de cambio en el factor latente representa el mismo cambio esperado en los indicadores observados en todos los grupos.
Este nivel de invarianza es un requisito fundamental para:
Comparar relaciones estructurales entre factores.
Interpretar asociaciones de manera equivalente entre grupos.
model_metric (estimación del modelo)La invarianza métrica se evalúa imponiendo restricciones de igualdad sobre las cargas factoriales entre grupos, mediante el argumento group.equal = "loadings":
model_metric <- cfa(HS.model, data = HolzingerSwineford1939,
group = "school",
group.equal = c("loadings")
)
model_metric
En este código:
group.equal = c("loadings") fuerza a que todas las cargas factoriales sean iguales en los grupos Pasteur y Grant-White.
Los interceptos, varianzas residuales y covarianzas latentes siguen estimándose libremente en cada grupo.
Este modelo es más restrictivo que el configural y, por tanto, está anidado dentro de él. El output que se obtiene es:
## lavaan 0.6-19 ended normally after 42 iterations
##
## Estimator ML
## Optimization method NLMINB
## Number of model parameters 60
## Number of equality constraints 6
##
## Number of observations per group:
## Pasteur 156
## Grant-White 145
##
## Model Test User Model:
##
## Test statistic 124.044
## Degrees of freedom 54
## P-value (Chi-square) 0.000
## Test statistic for each group:
## Pasteur 68.825
## Grant-White 55.219
summary (estimaciones por grupo)Una vez estimado el modelo métrico, se obtiene un resumen detallado mediante
summary(model_metric, fit.measures = TRUE)
## lavaan 0.6-19 ended normally after 42 iterations
##
## Estimator ML
## Optimization method NLMINB
## Number of model parameters 60
## Number of equality constraints 6
##
## Number of observations per group:
## Pasteur 156
## Grant-White 145
##
## Model Test User Model:
##
## Test statistic 124.044
## Degrees of freedom 54
## P-value (Chi-square) 0.000
## Test statistic for each group:
## Pasteur 68.825
## Grant-White 55.219
##
## Model Test Baseline Model:
##
## Test statistic 957.769
## Degrees of freedom 72
## P-value 0.000
##
## User Model versus Baseline Model:
##
## Comparative Fit Index (CFI) 0.921
## Tucker-Lewis Index (TLI) 0.895
##
## Loglikelihood and Information Criteria:
##
## Loglikelihood user model (H0) -3686.294
## Loglikelihood unrestricted model (H1) -3624.272
##
## Akaike (AIC) 7480.587
## Bayesian (BIC) 7680.771
## Sample-size adjusted Bayesian (SABIC) 7509.514
##
## Root Mean Square Error of Approximation:
##
## RMSEA 0.093
## 90 Percent confidence interval - lower 0.071
## 90 Percent confidence interval - upper 0.114
## P-value H_0: RMSEA <= 0.050 0.001
## P-value H_0: RMSEA >= 0.080 0.845
##
## Standardized Root Mean Square Residual:
##
## SRMR 0.072
##
## Parameter Estimates:
##
## Standard errors Standard
## Information Expected
## Information saturated (h1) model Structured
##
##
## Group 1 [Pasteur]:
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|)
## visual =~
## x1 1.000
## x2 (.p2.) 0.599 0.100 5.979 0.000
## x3 (.p3.) 0.784 0.108 7.267 0.000
## textual =~
## x4 1.000
## x5 (.p5.) 1.083 0.067 16.049 0.000
## x6 (.p6.) 0.912 0.058 15.785 0.000
## speed =~
## x7 1.000
## x8 (.p8.) 1.201 0.155 7.738 0.000
## x9 (.p9.) 1.038 0.136 7.629 0.000
##
## Covariances:
## Estimate Std.Err z-value P(>|z|)
## visual ~~
## textual 0.416 0.097 4.271 0.000
## speed 0.169 0.064 2.643 0.008
## textual ~~
## speed 0.176 0.061 2.882 0.004
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|)
## .x1 4.941 0.093 52.991 0.000
## .x2 5.984 0.100 60.096 0.000
## .x3 2.487 0.094 26.465 0.000
## .x4 2.823 0.093 30.371 0.000
## .x5 3.995 0.101 39.714 0.000
## .x6 1.922 0.081 23.711 0.000
## .x7 4.432 0.086 51.540 0.000
## .x8 5.563 0.078 71.087 0.000
## .x9 5.418 0.079 68.153 0.000
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .x1 0.551 0.137 4.010 0.000
## .x2 1.258 0.155 8.117 0.000
## .x3 0.882 0.128 6.884 0.000
## .x4 0.434 0.070 6.238 0.000
## .x5 0.508 0.082 6.229 0.000
## .x6 0.266 0.050 5.294 0.000
## .x7 0.849 0.114 7.468 0.000
## .x8 0.515 0.095 5.409 0.000
## .x9 0.658 0.096 6.865 0.000
## visual 0.805 0.171 4.714 0.000
## textual 0.913 0.137 6.651 0.000
## speed 0.305 0.078 3.920 0.000
##
##
## Group 2 [Grant-White]:
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|)
## visual =~
## x1 1.000
## x2 (.p2.) 0.599 0.100 5.979 0.000
## x3 (.p3.) 0.784 0.108 7.267 0.000
## textual =~
## x4 1.000
## x5 (.p5.) 1.083 0.067 16.049 0.000
## x6 (.p6.) 0.912 0.058 15.785 0.000
## speed =~
## x7 1.000
## x8 (.p8.) 1.201 0.155 7.738 0.000
## x9 (.p9.) 1.038 0.136 7.629 0.000
##
## Covariances:
## Estimate Std.Err z-value P(>|z|)
## visual ~~
## textual 0.437 0.099 4.423 0.000
## speed 0.314 0.079 3.958 0.000
## textual ~~
## speed 0.226 0.072 3.144 0.002
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|)
## .x1 4.930 0.097 50.763 0.000
## .x2 6.200 0.091 68.379 0.000
## .x3 1.996 0.085 23.455 0.000
## .x4 3.317 0.092 35.950 0.000
## .x5 4.712 0.100 47.173 0.000
## .x6 2.469 0.091 27.248 0.000
## .x7 3.921 0.086 45.555 0.000
## .x8 5.488 0.087 63.257 0.000
## .x9 5.327 0.085 62.786 0.000
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .x1 0.645 0.127 5.084 0.000
## .x2 0.933 0.121 7.732 0.000
## .x3 0.605 0.096 6.282 0.000
## .x4 0.329 0.062 5.279 0.000
## .x5 0.384 0.073 5.270 0.000
## .x6 0.437 0.067 6.576 0.000
## .x7 0.599 0.090 6.651 0.000
## .x8 0.406 0.089 4.541 0.000
## .x9 0.532 0.086 6.202 0.000
## visual 0.722 0.161 4.490 0.000
## textual 0.906 0.136 6.646 0.000
## speed 0.475 0.109 4.347 0.000
summaryEsta salida permite:
Verificar que el modelo métrico converge correctamente.
Evaluar el ajuste global del modelo bajo las nuevas restricciones.
Examinar las estimaciones de parámetros, teniendo en cuenta que las cargas factoriales son ahora comunes a ambos grupos.
Preparar la comparación formal con el modelo configural.
A partir de la salida del modelo métrico, se destacan los siguientes elementos relevantes:
El mensaje lavaan 0.6-19 ended normally after 42 iterations indica que el algoritmo de optimización convergió sin problemas, confirmando que el modelo métrico es numéricamente estable.
El modelo fue estimado mediante: Estimator: ML (Máxima Verosimilitud) y Optimization method: NLMINB. Estos aspectos son consistentes con el modelo configural, lo que facilita la comparación entre modelos.
La línea Number of equality constraints: 6 indica que se impusieron seis restricciones de igualdad, correspondientes a las cargas factoriales libres que ahora se estiman como iguales entre grupos. Este elemento distingue claramente al modelo métrico del modelo configural.
El modelo métrico presenta los siguientes índices globales de ajuste: χ² = 124.044, gl = 54, CFI = 0.921, RMSEA = 0.093 y SRMR = 0.072. Estos valores muestran un ligero deterioro del ajuste respecto al modelo configural, lo cual es esperable al imponer restricciones adicionales. La evaluación de si este deterioro es sustantivo se realiza mediante la comparación formal entre modelos.
parTableLos paraámetros del modelo configural también se pueden visualizar a través de esta tabla:
param<-parTable(model_metric)
param
## id lhs op rhs user block group free ustart exo label plabel start
## 1 1 visual =~ x1 1 1 1 0 1 0 .p1. 1.000
## 2 2 visual =~ x2 1 1 1 1 NA 0 .p2. .p2. 0.769
## 3 3 visual =~ x3 1 1 1 2 NA 0 .p3. .p3. 1.186
## 4 4 textual =~ x4 1 1 1 0 1 0 .p4. 1.000
## 5 5 textual =~ x5 1 1 1 3 NA 0 .p5. .p5. 1.237
## 6 6 textual =~ x6 1 1 1 4 NA 0 .p6. .p6. 0.865
## 7 7 speed =~ x7 1 1 1 0 1 0 .p7. 1.000
## 8 8 speed =~ x8 1 1 1 5 NA 0 .p8. .p8. 1.227
## 9 9 speed =~ x9 1 1 1 6 NA 0 .p9. .p9. 0.827
## 10 10 x1 ~~ x1 0 1 1 7 NA 0 .p10. 0.698
## 11 11 x2 ~~ x2 0 1 1 8 NA 0 .p11. 0.752
## 12 12 x3 ~~ x3 0 1 1 9 NA 0 .p12. 0.673
## 13 13 x4 ~~ x4 0 1 1 10 NA 0 .p13. 0.660
## 14 14 x5 ~~ x5 0 1 1 11 NA 0 .p14. 0.854
## 15 15 x6 ~~ x6 0 1 1 12 NA 0 .p15. 0.487
## 16 16 x7 ~~ x7 0 1 1 13 NA 0 .p16. 0.585
## 17 17 x8 ~~ x8 0 1 1 14 NA 0 .p17. 0.476
## 18 18 x9 ~~ x9 0 1 1 15 NA 0 .p18. 0.489
## 19 19 visual ~~ visual 0 1 1 16 NA 0 .p19. 0.050
## 20 20 textual ~~ textual 0 1 1 17 NA 0 .p20. 0.050
## 21 21 speed ~~ speed 0 1 1 18 NA 0 .p21. 0.050
## 22 22 visual ~~ textual 0 1 1 19 NA 0 .p22. 0.000
## 23 23 visual ~~ speed 0 1 1 20 NA 0 .p23. 0.000
## 24 24 textual ~~ speed 0 1 1 21 NA 0 .p24. 0.000
## 25 25 x1 ~1 0 1 1 22 NA 0 .p25. 4.941
## 26 26 x2 ~1 0 1 1 23 NA 0 .p26. 5.984
## 27 27 x3 ~1 0 1 1 24 NA 0 .p27. 2.487
## 28 28 x4 ~1 0 1 1 25 NA 0 .p28. 2.823
## 29 29 x5 ~1 0 1 1 26 NA 0 .p29. 3.995
## 30 30 x6 ~1 0 1 1 27 NA 0 .p30. 1.922
## 31 31 x7 ~1 0 1 1 28 NA 0 .p31. 4.432
## 32 32 x8 ~1 0 1 1 29 NA 0 .p32. 5.563
## 33 33 x9 ~1 0 1 1 30 NA 0 .p33. 5.418
## 34 34 visual ~1 0 1 1 0 0 0 .p34. 0.000
## 35 35 textual ~1 0 1 1 0 0 0 .p35. 0.000
## 36 36 speed ~1 0 1 1 0 0 0 .p36. 0.000
## 37 37 visual =~ x1 1 2 2 0 1 0 .p37. 1.000
## 38 38 visual =~ x2 1 2 2 31 NA 0 .p2. .p38. 0.896
## 39 39 visual =~ x3 1 2 2 32 NA 0 .p3. .p39. 1.155
## 40 40 textual =~ x4 1 2 2 0 1 0 .p40. 1.000
## 41 41 textual =~ x5 1 2 2 33 NA 0 .p5. .p41. 0.991
## 42 42 textual =~ x6 1 2 2 34 NA 0 .p6. .p42. 0.962
## 43 43 speed =~ x7 1 2 2 0 1 0 .p43. 1.000
## 44 44 speed =~ x8 1 2 2 35 NA 0 .p8. .p44. 1.282
## 45 45 speed =~ x9 1 2 2 36 NA 0 .p9. .p45. 0.895
## 46 46 x1 ~~ x1 0 2 2 37 NA 0 .p46. 0.659
## 47 47 x2 ~~ x2 0 2 2 38 NA 0 .p47. 0.613
## 48 48 x3 ~~ x3 0 2 2 39 NA 0 .p48. 0.537
## 49 49 x4 ~~ x4 0 2 2 40 NA 0 .p49. 0.629
## 50 50 x5 ~~ x5 0 2 2 41 NA 0 .p50. 0.671
## 51 51 x6 ~~ x6 0 2 2 42 NA 0 .p51. 0.640
## 52 52 x7 ~~ x7 0 2 2 43 NA 0 .p52. 0.531
## 53 53 x8 ~~ x8 0 2 2 44 NA 0 .p53. 0.547
## 54 54 x9 ~~ x9 0 2 2 45 NA 0 .p54. 0.526
## 55 55 visual ~~ visual 0 2 2 46 NA 0 .p55. 0.050
## 56 56 textual ~~ textual 0 2 2 47 NA 0 .p56. 0.050
## 57 57 speed ~~ speed 0 2 2 48 NA 0 .p57. 0.050
## 58 58 visual ~~ textual 0 2 2 49 NA 0 .p58. 0.000
## 59 59 visual ~~ speed 0 2 2 50 NA 0 .p59. 0.000
## 60 60 textual ~~ speed 0 2 2 51 NA 0 .p60. 0.000
## 61 61 x1 ~1 0 2 2 52 NA 0 .p61. 4.930
## 62 62 x2 ~1 0 2 2 53 NA 0 .p62. 6.200
## 63 63 x3 ~1 0 2 2 54 NA 0 .p63. 1.996
## 64 64 x4 ~1 0 2 2 55 NA 0 .p64. 3.317
## 65 65 x5 ~1 0 2 2 56 NA 0 .p65. 4.712
## 66 66 x6 ~1 0 2 2 57 NA 0 .p66. 2.469
## 67 67 x7 ~1 0 2 2 58 NA 0 .p67. 3.921
## 68 68 x8 ~1 0 2 2 59 NA 0 .p68. 5.488
## 69 69 x9 ~1 0 2 2 60 NA 0 .p69. 5.327
## 70 70 visual ~1 0 2 2 0 0 0 .p70. 0.000
## 71 71 textual ~1 0 2 2 0 0 0 .p71. 0.000
## 72 72 speed ~1 0 2 2 0 0 0 .p72. 0.000
## 73 73 .p2. == .p38. 2 0 0 0 NA 0 0.000
## 74 74 .p3. == .p39. 2 0 0 0 NA 0 0.000
## 75 75 .p5. == .p41. 2 0 0 0 NA 0 0.000
## 76 76 .p6. == .p42. 2 0 0 0 NA 0 0.000
## 77 77 .p8. == .p44. 2 0 0 0 NA 0 0.000
## 78 78 .p9. == .p45. 2 0 0 0 NA 0 0.000
## est se
## 1 1.000 0.000
## 2 0.599 0.100
## 3 0.784 0.108
## 4 1.000 0.000
## 5 1.083 0.067
## 6 0.912 0.058
## 7 1.000 0.000
## 8 1.201 0.155
## 9 1.038 0.136
## 10 0.551 0.137
## 11 1.258 0.155
## 12 0.882 0.128
## 13 0.434 0.070
## 14 0.508 0.082
## 15 0.266 0.050
## 16 0.849 0.114
## 17 0.515 0.095
## 18 0.658 0.096
## 19 0.805 0.171
## 20 0.913 0.137
## 21 0.305 0.078
## 22 0.416 0.097
## 23 0.169 0.064
## 24 0.176 0.061
## 25 4.941 0.093
## 26 5.984 0.100
## 27 2.487 0.094
## 28 2.823 0.093
## 29 3.995 0.101
## 30 1.922 0.081
## 31 4.432 0.086
## 32 5.563 0.078
## 33 5.418 0.079
## 34 0.000 0.000
## 35 0.000 0.000
## 36 0.000 0.000
## 37 1.000 0.000
## 38 0.599 0.100
## 39 0.784 0.108
## 40 1.000 0.000
## 41 1.083 0.067
## 42 0.912 0.058
## 43 1.000 0.000
## 44 1.201 0.155
## 45 1.038 0.136
## 46 0.645 0.127
## 47 0.933 0.121
## 48 0.605 0.096
## 49 0.329 0.062
## 50 0.384 0.073
## 51 0.437 0.067
## 52 0.599 0.090
## 53 0.406 0.089
## 54 0.532 0.086
## 55 0.722 0.161
## 56 0.906 0.136
## 57 0.475 0.109
## 58 0.437 0.099
## 59 0.314 0.079
## 60 0.226 0.072
## 61 4.930 0.097
## 62 6.200 0.091
## 63 1.996 0.085
## 64 3.317 0.092
## 65 4.712 0.100
## 66 2.469 0.091
## 67 3.921 0.086
## 68 5.488 0.087
## 69 5.327 0.085
## 70 0.000 0.000
## 71 0.000 0.000
## 72 0.000 0.000
## 73 0.000 0.000
## 74 0.000 0.000
## 75 0.000 0.000
## 76 0.000 0.000
## 77 0.000 0.000
## 78 0.000 0.000
anova()La evaluación formal de la invarianza métrica se realiza comparando el modelo configural y el modelo métrico mediante un test de diferencia de χ² para modelos anidados, utilizando la función anova():
anova(model_configural, model_metric)
Este contraste evalúa si la imposición de igualdad en las cargas factoriales produce un deterioro significativo del ajuste. Formalmente, las hipótesis evaluadas son:
H₀: Las cargas factoriales son iguales entre grupos (el modelo métrico no empeora el ajuste respecto al configural).
H₁: Al menos una carga factorial difiere entre grupos (el modelo métrico empeora significativamente el ajuste).
La salida del contraste entre modelos es:
##
## Chi-Squared Difference Test
##
## Df AIC BIC Chisq Chisq diff RMSEA Df diff Pr(>Chisq)
## model_configural 48 7484.4 7706.8 115.85
## model_metric 54 7480.6 7680.8 124.04 8.1922 0.049272 6 0.2244
En una tabla más limpia:
Chi-Squared Difference Test
Df AIC BIC Chisq Chisq diff RMSEA Df diff Pr(>Chisq)
M1: model_configural 48 7484.4 7706.8 115.85
M2: model_metric 54 7480.6 7680.8 124.04 8.1922 0.049272 6 0.2244
La diferencia entre modelos es: Δχ² = 8.19, Δgl = 6 y p-valor = 0.224. Dado que el p-valor es claramente mayor que 0.05, no se rechaza la hipótesis nula, lo que indica que la restricción de igualdad en las cargas factoriales no produce un deterioro estadísticamente significativo del ajuste.
Dado que el test χ² de diferencia es altamente sensible al tamaño muestral, la decisión sobre la invarianza métrica no debe basarse exclusivamente en su p-valor.
En la práctica, la evaluación se realiza considerando de manera conjunta los siguientes criterios:
Δχ² no significativo, como en este caso (valor p = 0.224).
Cambios pequeños en los índices de ajuste aproximado, especialmente:
ΔCFI < 0.01
ΔRMSEA < 0.015 (criterio complementario).
Coherencia sustantiva del modelo, es decir, estabilidad conceptual del patrón factorial y plausibilidad teórica de las restricciones impuestas.
Si los cambios en los índices de ajuste entre el modelo configural y el modelo métrico son pequeños y se mantienen dentro de estos umbrales, se concluye que la restricción de igualdad en las cargas factoriales es aceptable.
En este ejemplo, el RMSEA asociado al test de diferencia es aproximadamente 0.049, lo cual indica que el deterioro del ajuste es pequeño y compatible con la aceptación de la invarianza métrica.
Dado que el modelo métrico no presenta un deterioro significativo del ajuste respecto al modelo configural, se concluye que la invarianza métrica es aceptable.
En términos sustantivos, esto implica que:
Las cargas factoriales son equivalentes entre grupos.
Los ítems mantienen el mismo significado métrico en Pasteur y Grant-White.
Es válido comparar relaciones estructurales entre los factores latentes, tales como regresiones y covarianzas.
Sin embargo, es importante destacar que todavía no es válido comparar medias latentes entre grupos, ya que este tipo de inferencia requiere un nivel adicional de equivalencia: la invarianza escalar.
En situaciones en las que el modelo métrico no se sostiene, es posible explorar la invarianza métrica parcial, liberando aquellas cargas factoriales que presentan evidencia de no invarianza, generalmente guiándose por los índices de modificación.
Este enfoque permite conservar la comparabilidad del constructo, siempre que la mayoría de las cargas factoriales permanezcan invariantes, y constituye una estrategia aceptada en aplicaciones empíricas reales.
Habiendo establecido la equivalencia métrica del modelo de medición, el siguiente paso consiste en evaluar la invarianza escalar, imponiendo restricciones adicionales sobre los interceptos de los ítems.
En la siguiente sección se presenta el modelo escalar multigrupo y su comparación con el modelo métrico.
La invarianza métrica es un requisito esencial para interpretar relaciones estructurales entre constructos latentes en estudios comparativos.
Garantiza que los factores latentes poseen el mismo significado métrico en todos los grupos analizados.
Su evaluación se realiza mediante CFA multigrupo, a través de la comparación de modelos anidados.
La invarianza métrica no autoriza comparaciones de medias latentes, pero sí comparaciones de regresiones, correlaciones y varianzas latentes.
En aplicaciones empíricas, la invarianza métrica parcial constituye una alternativa válida y conceptualmente sólida cuando la invarianza completa no se cumple.
Una vez establecida la invarianza métrica, el siguiente paso es evaluar la invarianza escalar, condición necesaria para comparar medias latentes entre grupos. Esta etapa introduce restricciones adicionales sobre los interceptos de los ítems, y constituye el puente natural hacia análisis SEM multigrupo (por ejemplo, comparación de medias latentes y de parámetros estructurales).
model_scalar) y summary()Para evaluar la invarianza escalar, se restringen como iguales entre grupos:
Las cargas factoriales (como en el modelo métrico).
Los interceptos de los ítems.
model_scalar_a <- cfa(HS.model, data = HolzingerSwineford1939,
group = "school",
group.equal = c("loadings", "intercepts")
)
summary(model_scalar_a, fit.measures = TRUE)
El objeto model_scalar_a representa un modelo de invarianza escalar completa, en el cual se asume que las cargas factoriales y los interceptos de todos los ítems son iguales entre los grupos definidos por la variable school.
Desde un punto de vista conceptual, este modelo implica que:
Los ítems miden los factores latentes de la misma manera en ambos grupos (invarianza métrica), y
Para un mismo nivel del constructo latente, los ítems presentan el mismo nivel esperado de respuesta en ambos grupos (invarianza escalar).
La estimación de este modelo constituye un paso intermedio fundamental dentro de la jerarquía de pruebas de invarianza. Su objetivo principal no es necesariamente ser aceptado como modelo final, sino servir como referencia para evaluar si la hipótesis de igualdad total de interceptos es compatible con los datos.
En este sentido, model_scalar_a establece el punto de partida para decidir si es necesario avanzar hacia modelos de invarianza escalar parcial, liberando interceptos específicos que puedan estar generando falta de ajuste.
summary()La salida del salida del summary() es:
## lavaan 0.6-19 ended normally after 60 iterations
##
## Estimator ML
## Optimization method NLMINB
## Number of model parameters 63
## Number of equality constraints 15
##
## Number of observations per group:
## Pasteur 156
## Grant-White 145
##
## Model Test User Model:
##
## Test statistic 164.103
## Degrees of freedom 60
## P-value (Chi-square) 0.000
## Test statistic for each group:
## Pasteur 90.210
## Grant-White 73.892
##
## Model Test Baseline Model:
##
## Test statistic 957.769
## Degrees of freedom 72
## P-value 0.000
##
## User Model versus Baseline Model:
##
## Comparative Fit Index (CFI) 0.882
## Tucker-Lewis Index (TLI) 0.859
##
## Loglikelihood and Information Criteria:
##
## Loglikelihood user model (H0) -3706.323
## Loglikelihood unrestricted model (H1) -3624.272
##
## Akaike (AIC) 7508.647
## Bayesian (BIC) 7686.588
## Sample-size adjusted Bayesian (SABIC) 7534.359
##
## Root Mean Square Error of Approximation:
##
## RMSEA 0.107
## 90 Percent confidence interval - lower 0.088
## 90 Percent confidence interval - upper 0.127
## P-value H_0: RMSEA <= 0.050 0.000
## P-value H_0: RMSEA >= 0.080 0.989
##
## Standardized Root Mean Square Residual:
##
## SRMR 0.082
##
## Parameter Estimates:
##
## Standard errors Standard
## Information Expected
## Information saturated (h1) model Structured
##
##
## Group 1 [Pasteur]:
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|)
## visual =~
## x1 1.000
## x2 (.p2.) 0.576 0.101 5.713 0.000
## x3 (.p3.) 0.798 0.112 7.146 0.000
## textual =~
## x4 1.000
## x5 (.p5.) 1.120 0.066 16.965 0.000
## x6 (.p6.) 0.932 0.056 16.608 0.000
## speed =~
## x7 1.000
## x8 (.p8.) 1.130 0.145 7.786 0.000
## x9 (.p9.) 1.009 0.132 7.667 0.000
##
## Covariances:
## Estimate Std.Err z-value P(>|z|)
## visual ~~
## textual 0.410 0.095 4.293 0.000
## speed 0.178 0.066 2.687 0.007
## textual ~~
## speed 0.180 0.062 2.900 0.004
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|)
## .x1 (.25.) 5.001 0.090 55.760 0.000
## .x2 (.26.) 6.151 0.077 79.905 0.000
## .x3 (.27.) 2.271 0.083 27.387 0.000
## .x4 (.28.) 2.778 0.087 31.953 0.000
## .x5 (.29.) 4.035 0.096 41.858 0.000
## .x6 (.30.) 1.926 0.079 24.426 0.000
## .x7 (.31.) 4.242 0.073 57.975 0.000
## .x8 (.32.) 5.630 0.072 78.531 0.000
## .x9 (.33.) 5.465 0.069 79.016 0.000
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .x1 0.555 0.139 3.983 0.000
## .x2 1.296 0.158 8.186 0.000
## .x3 0.944 0.136 6.929 0.000
## .x4 0.445 0.069 6.430 0.000
## .x5 0.502 0.082 6.136 0.000
## .x6 0.263 0.050 5.264 0.000
## .x7 0.888 0.120 7.416 0.000
## .x8 0.541 0.095 5.706 0.000
## .x9 0.654 0.096 6.805 0.000
## visual 0.796 0.172 4.641 0.000
## textual 0.879 0.131 6.694 0.000
## speed 0.322 0.082 3.914 0.000
##
##
## Group 2 [Grant-White]:
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|)
## visual =~
## x1 1.000
## x2 (.p2.) 0.576 0.101 5.713 0.000
## x3 (.p3.) 0.798 0.112 7.146 0.000
## textual =~
## x4 1.000
## x5 (.p5.) 1.120 0.066 16.965 0.000
## x6 (.p6.) 0.932 0.056 16.608 0.000
## speed =~
## x7 1.000
## x8 (.p8.) 1.130 0.145 7.786 0.000
## x9 (.p9.) 1.009 0.132 7.667 0.000
##
## Covariances:
## Estimate Std.Err z-value P(>|z|)
## visual ~~
## textual 0.427 0.097 4.417 0.000
## speed 0.329 0.082 4.006 0.000
## textual ~~
## speed 0.236 0.073 3.224 0.001
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|)
## .x1 (.25.) 5.001 0.090 55.760 0.000
## .x2 (.26.) 6.151 0.077 79.905 0.000
## .x3 (.27.) 2.271 0.083 27.387 0.000
## .x4 (.28.) 2.778 0.087 31.953 0.000
## .x5 (.29.) 4.035 0.096 41.858 0.000
## .x6 (.30.) 1.926 0.079 24.426 0.000
## .x7 (.31.) 4.242 0.073 57.975 0.000
## .x8 (.32.) 5.630 0.072 78.531 0.000
## .x9 (.33.) 5.465 0.069 79.016 0.000
## visual -0.148 0.122 -1.211 0.226
## textual 0.576 0.117 4.918 0.000
## speed -0.177 0.090 -1.968 0.049
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .x1 0.654 0.128 5.094 0.000
## .x2 0.964 0.123 7.812 0.000
## .x3 0.641 0.101 6.316 0.000
## .x4 0.343 0.062 5.534 0.000
## .x5 0.376 0.073 5.133 0.000
## .x6 0.437 0.067 6.559 0.000
## .x7 0.625 0.095 6.574 0.000
## .x8 0.434 0.088 4.914 0.000
## .x9 0.522 0.086 6.102 0.000
## visual 0.708 0.160 4.417 0.000
## textual 0.870 0.131 6.659 0.000
## speed 0.505 0.115 4.379 0.000
Ella permite:
Verificar que el modelo escalar converge correctamente.
Evaluar el ajuste global del modelo bajo las nuevas restricciones (interceptos invariantes).
Preparar la comparación formal con el modelo métrico mediante anova().
summary()A partir del output correspondiente, se destacan los siguientes elementos relevantes.
El mensaje lavaan 0.6-19 ended normally after 60 iterations confirma que el algoritmo de optimización convergió correctamente, por lo que el modelo escalar es estimable y numéricamente estable.
El procedimiento de estimación se mantiene consistente con los modelos anteriores (Estimator: ML y Optimization method: NLMINB), lo cual facilita la comparación directa de ajuste entre niveles de invarianza.
En el output aparece Number of equality constraints: 15, lo cual indica que, además de las restricciones impuestas en el modelo métrico, ahora se agregan restricciones adicionales correspondientes a los interceptos (parámetros del tipo x ~ 1) para hacerlos iguales entre grupos. Esto distingue al modelo escalar del modelo métrico.
En este caso, el modelo escalar reporta (entre otros):
χ² = 164.103, gl = 60, p < 0.001
CFI = 0.882
RMSEA = 0.107
SRMR = 0.082
Estos valores muestran un deterioro apreciable del ajuste respecto al modelo métrico, lo cual es esperable cuando las restricciones de interceptos no son compatibles con los datos. La decisión formal se realiza con el test de diferencia y con criterios prácticos basados en cambios de ajuste.
<
El summary() presenta las estimaciones del modelo por grupo (Pasteur y Grant-White), lo cual permite una lectura preliminar de similitudes y diferencias bajo las restricciones impuestas.
Las cargas factoriales aparecen con las mismas etiquetas en ambos grupos (por ejemplo, .p2., .p3., .p5.), reflejando que estas han sido forzadas a ser iguales entre grupos, de acuerdo con la invarianza métrica previamente establecida.
De forma análoga, los interceptos de los ítems (.x1, .x2, …, .x9) presentan valores idénticos en ambos grupos, lo cual operacionaliza la hipótesis de invarianza escalar completa.
En contraste, otros parámetros no restringidos, como las covarianzas y varianzas, pueden presentar diferencias numéricas entre grupos, ya que en este modelo no se ha impuesto invarianza estructural.
Desde una perspectiva comparativa, esta salida indica que el modelo asume explícitamente la igualdad de niveles observados esperados entre grupos para todos los ítems, condicionados al mismo nivel del factor latente. Sin embargo, el deterioro del ajuste global sugiere que esta igualdad no es plenamente compatible con los datos, lo que apunta a la existencia de diferencias sistemáticas de nivel entre grupos en algunos indicadores.
En consecuencia, aunque el summary() confirma que las restricciones se están aplicando correctamente en ambos grupos, también anticipa —antes del test formal con anova()— que la hipótesis de invarianza escalar completa es demasiado restrictiva y debe ser refinada mediante un enfoque de invarianza escalar parcial.
anova()La evaluación formal de la invarianza escalar se realiza comparando el modelo métrico y el modelo escalar mediante un test de diferencia de χ² (modelos anidados), utilizando la función anova():
anova(model_metric, model_scalar_a)
##
## Chi-Squared Difference Test
##
## Df AIC BIC Chisq Chisq diff RMSEA Df diff Pr(>Chisq)
## model_metric 54 7480.6 7680.8 124.04
## model_scalar_a 60 7508.6 7686.6 164.10 40.059 0.19421 6 4.435e-07
##
## model_metric
## model_scalar_a ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Reuniendo los pruebas de comparación con los modelos anteriores:
Chi-Squared Difference Test
Model (versus) Df AIC BIC Chisq Chisq diff RMSEA Df diff Pr(>Chisq)
M1: configural 48 7484.4 7706.8 115.85
M2: metric (M1) 54 7480.6 7680.8 124.04 8.1922 0.049272 6 0.2244
M3a: scalar_a (M2) 60 7508.6 7686.6 164.10 40.0590 0.19421 6 4.435e-07 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Este contraste evalúa si imponer igualdad en los interceptos produce un deterioro significativo del ajuste.
En este ejemplo, el resultado fue: Δχ² = 40.059 con Δgl = 6 y p-valor = 4.435e-07, lo cual indica que el modelo escalar empeora significativamente respecto al modelo métrico. En consecuencia, la invarianza escalar completa no se sostiene, justificando la exploración de modelos de invarianza escalar parcial.
Cuando la invarianza escalar completa no se cumple, esto sugiere que:
Algunos ítems presentan sesgos aditivos (interceptos distintos entre grupos).
Por tanto, los grupos tienden a responder sistemáticamente más alto o más bajo en ciertos ítems, incluso controlando el nivel del factor latente.
En estas condiciones, no es apropiado proceder directamente a comparar medias latentes bajo el modelo escalar completo, ya que las diferencias observadas podrían reflejar no solo diferencias en el factor, sino también diferencias en interceptos.
En aplicaciones empíricas reales, la invarianza escalar completa suele ser difícil de sostener, especialmente cuando se comparan grupos heterogéneos. En estos casos, se recurre al concepto de invarianza escalar parcial, cuyo objetivo es preservar la comparabilidad de las medias latentes liberando únicamente aquellos interceptos que generan un deterioro sustantivo del ajuste.
De acuerdo con Byrne, Shavelson y Muthén (1989), la comparación de medias latentes sigue siendo válida siempre que, para cada factor, se mantengan al menos dos interceptos invariantes, lo cual garantiza la identificación adecuada del factor en la comparación entre grupos.
Este enfoque permite un equilibrio entre rigor estadístico y realismo empírico, evitando el rechazo innecesario de modelos conceptualmente sólidos.
El procedimiento estándar para especificar un modelo de invarianza escalar parcial consta de tres pasos conceptuales:
Identificar, mediante lavTestScore(), qué restricciones de igualdad sobre los interceptos contribuyen al mal ajuste del modelo escalar.
Mapear dichas restricciones a los interceptos de ítems específicos (por ejemplo, x3~1, x7~1).
Reestimar el modelo especificando esos interceptos como no invariantes mediante el argumento group.partial = c("x3~1", "x7~1").
Nota importante:
La función lavTestScore() no libera parámetros automáticamente; su función es estrictamente diagnóstica.
La función lavTestScore() implementa tests de puntuación (score tests) dentro del marco de modelos SEM estimados con lavaan.
Estos tests se basan en el principio del multiplicador de Lagrange y permiten evaluar si liberar determinadas restricciones mejoraría significativamente el ajuste del modelo sin necesidad de reestimar múltiples modelos exploratorios.
Existen dos modos conceptualmente distintos de uso:
Evaluar la liberación de parámetros fijados a cero, mediante el argumento add.
Evaluar restricciones de igualdad existentes, mediante el argumento release.
Estos dos modos no pueden utilizarse simultáneamente. En el contexto de la invarianza escalar, el interés se centra en el segundo caso: evaluar restricciones de igualdad impuestas sobre los interceptos entre grupos.
lavTestScore()La función lavTestScore() devuelve un objeto de clase lavaan.scoretest que puede contener hasta cuatro componentes principales, dependiendo de las opciones utilizadas en la llamada a la función. Se resalta el hecho de que el argumento epc = TRUE solicita el cálculo de los cambios esperados en los parámetros, lo cual resulta fundamental para decidir qué interceptos conviene liberar desde un punto de vista sustantivo.
score_obj <- lavTestScore(model_scalar_a, epc = TRUE)
score_obj
## $test
##
## total score test:
##
## test X2 df p.value
## 1 score 46.956 15 0
##
## $uni
##
## univariate score tests:
##
## lhs op rhs X2 df p.value
## 1 .p2. == .p38. 0.306 1 0.580
## 2 .p3. == .p39. 1.636 1 0.201
## 3 .p5. == .p41. 2.744 1 0.098
## 4 .p6. == .p42. 2.627 1 0.105
## 5 .p8. == .p44. 0.027 1 0.871
## 6 .p9. == .p45. 0.004 1 0.952
## 7 .p25. == .p61. 5.847 1 0.016
## 8 .p26. == .p62. 6.863 1 0.009
## 9 .p27. == .p63. 19.193 1 0.000
## 10 .p28. == .p64. 2.139 1 0.144
## 11 .p29. == .p65. 1.563 1 0.211
## 12 .p30. == .p66. 0.032 1 0.857
## 13 .p31. == .p67. 15.021 1 0.000
## 14 .p32. == .p68. 4.710 1 0.030
## 15 .p33. == .p69. 1.498 1 0.221
##
## $epc
##
## expected parameter changes (epc) and expected parameter values (epv):
##
## lhs op rhs block group free label plabel est epc epv
## 1 visual =~ x1 1 1 0 .p1. 1.000 NA NA
## 2 visual =~ x2 1 1 1 .p2. .p2. 0.576 -0.136 0.440
## 3 visual =~ x3 1 1 2 .p3. .p3. 0.798 -0.216 0.582
## 4 textual =~ x4 1 1 0 .p4. 1.000 NA NA
## 5 textual =~ x5 1 1 3 .p5. .p5. 1.120 0.074 1.194
## 6 textual =~ x6 1 1 4 .p6. .p6. 0.932 -0.049 0.883
## 7 speed =~ x7 1 1 0 .p7. 1.000 NA NA
## 8 speed =~ x8 1 1 5 .p8. .p8. 1.130 0.038 1.168
## 9 speed =~ x9 1 1 6 .p9. .p9. 1.009 0.006 1.015
## 10 x1 ~~ x1 1 1 7 .p10. 0.555 -0.151 0.405
## 11 x2 ~~ x2 1 1 8 .p11. 1.296 0.030 1.327
## 12 x3 ~~ x3 1 1 9 .p12. 0.944 0.089 1.034
## 13 x4 ~~ x4 1 1 10 .p13. 0.445 -0.003 0.443
## 14 x5 ~~ x5 1 1 11 .p14. 0.502 -0.041 0.461
## 15 x6 ~~ x6 1 1 12 .p15. 0.263 0.027 0.291
## 16 x7 ~~ x7 1 1 13 .p16. 0.888 0.006 0.894
## 17 x8 ~~ x8 1 1 14 .p17. 0.541 -0.010 0.531
## 18 x9 ~~ x9 1 1 15 .p18. 0.654 0.005 0.658
## 19 visual ~~ visual 1 1 16 .p19. 0.796 0.198 0.994
## 20 textual ~~ textual 1 1 17 .p20. 0.879 0.000 0.879
## 21 speed ~~ speed 1 1 18 .p21. 0.322 -0.010 0.312
## 22 visual ~~ textual 1 1 19 .p22. 0.410 0.037 0.447
## 23 visual ~~ speed 1 1 20 .p23. 0.178 0.013 0.191
## 24 textual ~~ speed 1 1 21 .p24. 0.180 -0.003 0.177
## 25 x1 ~1 1 1 22 .p25. .p25. 5.001 -0.060 4.941
## 26 x2 ~1 1 1 23 .p26. .p26. 6.151 -0.167 5.984
## 27 x3 ~1 1 1 24 .p27. .p27. 2.271 0.216 2.487
## 28 x4 ~1 1 1 25 .p28. .p28. 2.778 0.045 2.823
## 29 x5 ~1 1 1 26 .p29. .p29. 4.035 -0.040 3.995
## 30 x6 ~1 1 1 27 .p30. .p30. 1.926 -0.003 1.922
## 31 x7 ~1 1 1 28 .p31. .p31. 4.242 0.190 4.432
## 32 x8 ~1 1 1 29 .p32. .p32. 5.630 -0.067 5.563
## 33 x9 ~1 1 1 30 .p33. .p33. 5.465 -0.048 5.418
## 34 visual ~1 1 1 0 .p34. 0.000 NA NA
## 35 textual ~1 1 1 0 .p35. 0.000 NA NA
## 36 speed ~1 1 1 0 .p36. 0.000 NA NA
## 37 visual =~ x1 2 2 0 .p37. 1.000 NA NA
## 38 visual =~ x2 2 2 31 .p2. .p38. 0.576 0.119 0.695
## 39 visual =~ x3 2 2 32 .p3. .p39. 0.798 0.065 0.863
## 40 textual =~ x4 2 2 0 .p40. 1.000 NA NA
## 41 textual =~ x5 2 2 33 .p5. .p41. 1.120 -0.142 0.978
## 42 textual =~ x6 2 2 34 .p6. .p42. 0.932 0.031 0.963
## 43 speed =~ x7 2 2 0 .p43. 1.000 NA NA
## 44 speed =~ x8 2 2 35 .p8. .p44. 1.130 0.118 1.247
## 45 speed =~ x9 2 2 36 .p9. .p45. 1.009 0.097 1.106
## 46 x1 ~~ x1 2 2 37 .p46. 0.654 0.048 0.701
## 47 x2 ~~ x2 2 2 38 .p47. 0.964 -0.023 0.941
## 48 x3 ~~ x3 2 2 39 .p48. 0.641 -0.013 0.628
## 49 x4 ~~ x4 2 2 40 .p49. 0.343 -0.027 0.316
## 50 x5 ~~ x5 2 2 41 .p50. 0.376 0.061 0.437
## 51 x6 ~~ x6 2 2 42 .p51. 0.437 -0.026 0.411
## 52 x7 ~~ x7 2 2 43 .p52. 0.625 0.027 0.652
## 53 x8 ~~ x8 2 2 44 .p53. 0.434 -0.019 0.415
## 54 x9 ~~ x9 2 2 45 .p54. 0.522 -0.006 0.516
## 55 visual ~~ visual 2 2 46 .p55. 0.708 -0.085 0.623
## 56 textual ~~ textual 2 2 47 .p56. 0.870 0.073 0.943
## 57 speed ~~ speed 2 2 48 .p57. 0.505 -0.075 0.430
## 58 visual ~~ textual 2 2 49 .p58. 0.427 -0.004 0.423
## 59 visual ~~ speed 2 2 50 .p59. 0.329 -0.042 0.286
## 60 textual ~~ speed 2 2 51 .p60. 0.236 -0.008 0.228
## 61 x1 ~1 2 2 52 .p25. .p61. 5.001 0.061 5.062
## 62 x2 ~1 2 2 53 .p26. .p62. 6.151 0.143 6.294
## 63 x3 ~1 2 2 54 .p27. .p63. 2.271 -0.160 2.111
## 64 x4 ~1 2 2 55 .p28. .p64. 2.778 -0.056 2.722
## 65 x5 ~1 2 2 56 .p29. .p65. 4.035 0.092 4.127
## 66 x6 ~1 2 2 57 .p30. .p66. 1.926 -0.030 1.896
## 67 x7 ~1 2 2 58 .p31. .p67. 4.242 -0.145 4.097
## 68 x8 ~1 2 2 59 .p32. .p68. 5.630 0.078 5.708
## 69 x9 ~1 2 2 60 .p33. .p69. 5.465 0.057 5.522
## 70 visual ~1 2 2 61 .p70. -0.148 0.015 -0.133
## 71 textual ~1 2 2 62 .p71. 0.576 0.019 0.596
## 72 speed ~1 2 2 63 .p72. -0.177 0.001 -0.176
## sepc.lv sepc.all sepc.nox
## 1 NA NA NA
## 2 -0.121 -0.097 -0.097
## 3 -0.193 -0.160 -0.160
## 4 NA NA NA
## 5 0.069 0.055 0.055
## 6 -0.046 -0.045 -0.045
## 7 NA NA NA
## 8 0.022 0.022 0.022
## 9 0.004 0.004 0.004
## 10 -0.555 -0.411 -0.411
## 11 1.296 0.831 0.831
## 12 0.944 0.650 0.650
## 13 -0.445 -0.336 -0.336
## 14 -0.502 -0.313 -0.313
## 15 0.263 0.256 0.256
## 16 0.888 0.734 0.734
## 17 -0.541 -0.568 -0.568
## 18 0.654 0.666 0.666
## 19 1.000 1.000 1.000
## 20 -1.000 -1.000 -1.000
## 21 -1.000 -1.000 -1.000
## 22 0.044 0.044 0.044
## 23 0.025 0.025 0.025
## 24 -0.006 -0.006 -0.006
## 25 -0.060 -0.052 -0.052
## 26 -0.167 -0.134 -0.134
## 27 0.216 0.179 0.179
## 28 0.045 0.039 0.039
## 29 -0.040 -0.031 -0.031
## 30 -0.003 -0.003 -0.003
## 31 0.190 0.173 0.173
## 32 -0.067 -0.069 -0.069
## 33 -0.048 -0.048 -0.048
## 34 NA NA NA
## 35 NA NA NA
## 36 NA NA NA
## 37 NA NA NA
## 38 0.100 0.091 0.091
## 39 0.054 0.052 0.052
## 40 NA NA NA
## 41 -0.133 -0.109 -0.109
## 42 0.029 0.027 0.027
## 43 NA NA NA
## 44 0.084 0.081 0.081
## 45 0.069 0.068 0.068
## 46 0.654 0.480 0.480
## 47 -0.964 -0.804 -0.804
## 48 -0.641 -0.587 -0.587
## 49 -0.343 -0.283 -0.283
## 50 0.376 0.256 0.256
## 51 -0.437 -0.366 -0.366
## 52 0.625 0.553 0.553
## 53 -0.434 -0.403 -0.403
## 54 -0.522 -0.504 -0.504
## 55 -1.000 -1.000 -1.000
## 56 1.000 1.000 1.000
## 57 -1.000 -1.000 -1.000
## 58 -0.005 -0.005 -0.005
## 59 -0.071 -0.071 -0.071
## 60 -0.012 -0.012 -0.012
## 61 0.061 0.052 0.052
## 62 0.143 0.130 0.130
## 63 -0.160 -0.153 -0.153
## 64 -0.056 -0.051 -0.051
## 65 0.092 0.076 0.076
## 66 -0.030 -0.027 -0.027
## 67 -0.145 -0.136 -0.136
## 68 0.078 0.075 0.075
## 69 0.057 0.056 0.056
## 70 0.018 0.018 0.018
## 71 0.021 0.021 0.021
## 72 0.001 0.001 0.001
$test: test global de puntuación (multivariado)Este componente corresponde al test global de score, también conocido como test LM multivariado.
Evalúa la hipótesis nula de que todas las restricciones de igualdad impuestas en el modelo escalar son válidas simultáneamente.
Las hipótesis evaluadas son:
H₀: el modelo escalar es válido (todas las restricciones de igualdad del modelo escalar son válidas).
H₁: al menos una restricción de igualdad no es compatible con los datos.
Cuando este test es significativo, se concluye que el modelo escalar completo no se sostiene, pero no se identifica aún qué restricción específica falla.
$uni: tests de puntuación univariadosEste componente contiene los tests LM univariados, equivalentes conceptualmente a los índices de modificación, pero aplicados específicamente a restricciones de igualdad.
Cada fila evalúa una restricción individual (por ejemplo, un intercepto igualado entre grupos).
Valores altos de χ² identifican candidatos claros a ser liberados en un modelo de invarianza escalar parcial.
$epc: cambios esperados en los parámetrosLos Expected Parameter Changes (EPC) indican:
Cuánto cambiaría un parámetro si se libera la restricción correspondiente (epc).
Cuál sería el valor estimado del parámetro una vez liberada la restricción (epv).
Además, presenta versiones estandarizadas del EPC (sepc.lv, sepc.all, sepc.nox), útiles para evaluar la magnitud práctica del
cambio.
Estos valores permiten evaluar no solo la significancia estadística, sino también la magnitud sustantiva del cambio esperado.
lavTestScore(...)Como ya explicamos anteriormente, con lavaan, se procede de la siguiente manera:
score_obj <- lavTestScore(model_scalar_a, epc = TRUE)
A continuación, interpretaremos la salida de cada componente de score_obj.
score_obj$testLa salida del componente $test corresponde al test global de puntuación:
score_obj$test
##
## total score test:
##
## test X2 df p.value
## 1 score 46.956 15 0
En este caso:
χ² = 46.956
gl = 15
p-valor < 0.001
Este resultado indica que al menos uno de los interceptos igualados entre grupos no cumple el supuesto de invarianza escalar, por lo que se justifica avanzar hacia un modelo de invarianza escalar parcial.
Una vez rechazado el test global, el siguiente paso consiste en examinar los tests univariados (score_obj$uni) y los cambios esperados en los parámetros (score_obj$epc), que indican qué restricciones individuales contribuyen más al deterioro del ajuste:
score_obj$uniLa salida de $uni muestra una tabla que presenta los resultados de las pruebas score univariadas, los cuales son utilizadas para evaluar si una restricción específica de igualdad entre parámetros es consistente con los datos.
score_obj$uni
##
## univariate score tests:
##
## lhs op rhs X2 df p.value
## 1 .p2. == .p38. 0.306 1 0.580
## 2 .p3. == .p39. 1.636 1 0.201
## 3 .p5. == .p41. 2.744 1 0.098
## 4 .p6. == .p42. 2.627 1 0.105
## 5 .p8. == .p44. 0.027 1 0.871
## 6 .p9. == .p45. 0.004 1 0.952
## 7 .p25. == .p61. 5.847 1 0.016
## 8 .p26. == .p62. 6.863 1 0.009
## 9 .p27. == .p63. 19.193 1 0.000
## 10 .p28. == .p64. 2.139 1 0.144
## 11 .p29. == .p65. 1.563 1 0.211
## 12 .p30. == .p66. 0.032 1 0.857
## 13 .p31. == .p67. 15.021 1 0.000
## 14 .p32. == .p68. 4.710 1 0.030
## 15 .p33. == .p69. 1.498 1 0.221
Nota interpretativa sobre la tabla de univariate score tests.
La tabla contiene las siguientes columnas:
names(score_obj$uni )
## [1] "lhs" "op" "rhs" "X2" "df" "p.value"
Se interpretan de la siguiente forma:
lhs y rhs: etiquetas internas (plabel) de los dos parámetros cuya igualdad está siendo evaluada. Estas etiquetas ya fueron explicadas previamente en la sección dedicada a parTable().
op: operador de igualdad (==), que indica la restricción de igualdad impuesta entre ambos parámetros.
X2: estadístico chi-cuadrado del score test, que mide el incremento esperado del ajuste si se libera la restricción.
df: grados de libertad asociados a la prueba (en este caso, 1).
p.value: valor p de la prueba; valores pequeños indican que la restricción de igualdad es incompatible con los datos. La regla práctica de decisión es:
p-valor ≥ 0.05: la restricción es aceptable.
p-valor < 0.05: la restricción es problemática y candidata a liberarse.
En consecuencia, valores elevados de X2 y valores p pequeños señalan restricciones candidatas a ser liberadas en el proceso de invarianza factorial parcial.
Interpretación de los score tests univariados.
La tabla de score tests univariados muestra, para cada restricción de igualdad entre grupos, el efecto que tendría liberar únicamente esa restricción, manteniendo todas las demás constantes. Cada fila responde a la pregunta:
¿Se justifica estadísticamente mantener esta restricción de igualdad entre grupos?
Ejemplos de interpretación.
Restricciones aceptables (no problemáticas):
Para .p2. == .p38., tenemos que el valor p = 0.580. Por lo tanto, no existe evidencia estadística de que esta restricción viole la invarianza. Es decir, mantenerla no produce un deterioro significativo del ajuste del modelo.
Este comportamiento se observa también en restricciones como: .p3. == .p39., .p8. == .p44., .p9. == .p45. y .p30. == .p66., entre otros.
Restricciones claramente problemáticas:
Para .p27. == .p63., se tiene X² = 19.193, p < 0.001. Por lo tanto, forzar esta igualdad entre grupos genera un deterioro significativo del ajuste global. Esta restricción es una fuerte candidata a ser liberada.
Lo mismo ocurre con: .p31. == .p67. (\(p < 0.001\)), .p26. == .p62. (\(p = 0.0094\)) y .p25. == .p61. (\(p = 0.016\)), entre otros.
Casos intermedios (zona gris):
.p32. == .p68., se tiene que el valor p = 0.030. Entonces, existe evidencia moderada contra la restricción. es decir, su liberación puede considerarse, especialmente si tiene relevancia sustantiva.Interpretación global.
En conjunto, los score tests indican que:
La mayoría de las restricciones de igualdad son estadísticamente aceptables.
Un subconjunto reducido de restricciones contribuye de manera relevante al mal ajuste del modelo escalar.
Esto justifica avanzar hacia un modelo de invarianza escalar parcial, liberando únicamente aquellas restricciones identificadas como problemáticas.
Nota pedagógica
Los score tests univariados permiten localizar con precisión las fuentes del mal ajuste, evitando la liberación indiscriminada de parámetros y preservando la parsimonia del modelo.
score_obj$epcLa salida score_obj$epc muestra los cambios esperados en los parámetros si una restricción de igualdad fuese liberada. Esta información complementa los score tests y ayuda a decidir qué restricción relajar en un modelo de invarianza parcial.
score_obj$epc
##
## expected parameter changes (epc) and expected parameter values (epv):
##
## lhs op rhs block group free label plabel est epc epv
## 1 visual =~ x1 1 1 0 .p1. 1.000 NA NA
## 2 visual =~ x2 1 1 1 .p2. .p2. 0.576 -0.136 0.440
## 3 visual =~ x3 1 1 2 .p3. .p3. 0.798 -0.216 0.582
## 4 textual =~ x4 1 1 0 .p4. 1.000 NA NA
## 5 textual =~ x5 1 1 3 .p5. .p5. 1.120 0.074 1.194
## 6 textual =~ x6 1 1 4 .p6. .p6. 0.932 -0.049 0.883
## 7 speed =~ x7 1 1 0 .p7. 1.000 NA NA
## 8 speed =~ x8 1 1 5 .p8. .p8. 1.130 0.038 1.168
## 9 speed =~ x9 1 1 6 .p9. .p9. 1.009 0.006 1.015
## 10 x1 ~~ x1 1 1 7 .p10. 0.555 -0.151 0.405
## 11 x2 ~~ x2 1 1 8 .p11. 1.296 0.030 1.327
## 12 x3 ~~ x3 1 1 9 .p12. 0.944 0.089 1.034
## 13 x4 ~~ x4 1 1 10 .p13. 0.445 -0.003 0.443
## 14 x5 ~~ x5 1 1 11 .p14. 0.502 -0.041 0.461
## 15 x6 ~~ x6 1 1 12 .p15. 0.263 0.027 0.291
## 16 x7 ~~ x7 1 1 13 .p16. 0.888 0.006 0.894
## 17 x8 ~~ x8 1 1 14 .p17. 0.541 -0.010 0.531
## 18 x9 ~~ x9 1 1 15 .p18. 0.654 0.005 0.658
## 19 visual ~~ visual 1 1 16 .p19. 0.796 0.198 0.994
## 20 textual ~~ textual 1 1 17 .p20. 0.879 0.000 0.879
## 21 speed ~~ speed 1 1 18 .p21. 0.322 -0.010 0.312
## 22 visual ~~ textual 1 1 19 .p22. 0.410 0.037 0.447
## 23 visual ~~ speed 1 1 20 .p23. 0.178 0.013 0.191
## 24 textual ~~ speed 1 1 21 .p24. 0.180 -0.003 0.177
## 25 x1 ~1 1 1 22 .p25. .p25. 5.001 -0.060 4.941
## 26 x2 ~1 1 1 23 .p26. .p26. 6.151 -0.167 5.984
## 27 x3 ~1 1 1 24 .p27. .p27. 2.271 0.216 2.487
## 28 x4 ~1 1 1 25 .p28. .p28. 2.778 0.045 2.823
## 29 x5 ~1 1 1 26 .p29. .p29. 4.035 -0.040 3.995
## 30 x6 ~1 1 1 27 .p30. .p30. 1.926 -0.003 1.922
## 31 x7 ~1 1 1 28 .p31. .p31. 4.242 0.190 4.432
## 32 x8 ~1 1 1 29 .p32. .p32. 5.630 -0.067 5.563
## 33 x9 ~1 1 1 30 .p33. .p33. 5.465 -0.048 5.418
## 34 visual ~1 1 1 0 .p34. 0.000 NA NA
## 35 textual ~1 1 1 0 .p35. 0.000 NA NA
## 36 speed ~1 1 1 0 .p36. 0.000 NA NA
## 37 visual =~ x1 2 2 0 .p37. 1.000 NA NA
## 38 visual =~ x2 2 2 31 .p2. .p38. 0.576 0.119 0.695
## 39 visual =~ x3 2 2 32 .p3. .p39. 0.798 0.065 0.863
## 40 textual =~ x4 2 2 0 .p40. 1.000 NA NA
## 41 textual =~ x5 2 2 33 .p5. .p41. 1.120 -0.142 0.978
## 42 textual =~ x6 2 2 34 .p6. .p42. 0.932 0.031 0.963
## 43 speed =~ x7 2 2 0 .p43. 1.000 NA NA
## 44 speed =~ x8 2 2 35 .p8. .p44. 1.130 0.118 1.247
## 45 speed =~ x9 2 2 36 .p9. .p45. 1.009 0.097 1.106
## 46 x1 ~~ x1 2 2 37 .p46. 0.654 0.048 0.701
## 47 x2 ~~ x2 2 2 38 .p47. 0.964 -0.023 0.941
## 48 x3 ~~ x3 2 2 39 .p48. 0.641 -0.013 0.628
## 49 x4 ~~ x4 2 2 40 .p49. 0.343 -0.027 0.316
## 50 x5 ~~ x5 2 2 41 .p50. 0.376 0.061 0.437
## 51 x6 ~~ x6 2 2 42 .p51. 0.437 -0.026 0.411
## 52 x7 ~~ x7 2 2 43 .p52. 0.625 0.027 0.652
## 53 x8 ~~ x8 2 2 44 .p53. 0.434 -0.019 0.415
## 54 x9 ~~ x9 2 2 45 .p54. 0.522 -0.006 0.516
## 55 visual ~~ visual 2 2 46 .p55. 0.708 -0.085 0.623
## 56 textual ~~ textual 2 2 47 .p56. 0.870 0.073 0.943
## 57 speed ~~ speed 2 2 48 .p57. 0.505 -0.075 0.430
## 58 visual ~~ textual 2 2 49 .p58. 0.427 -0.004 0.423
## 59 visual ~~ speed 2 2 50 .p59. 0.329 -0.042 0.286
## 60 textual ~~ speed 2 2 51 .p60. 0.236 -0.008 0.228
## 61 x1 ~1 2 2 52 .p25. .p61. 5.001 0.061 5.062
## 62 x2 ~1 2 2 53 .p26. .p62. 6.151 0.143 6.294
## 63 x3 ~1 2 2 54 .p27. .p63. 2.271 -0.160 2.111
## 64 x4 ~1 2 2 55 .p28. .p64. 2.778 -0.056 2.722
## 65 x5 ~1 2 2 56 .p29. .p65. 4.035 0.092 4.127
## 66 x6 ~1 2 2 57 .p30. .p66. 1.926 -0.030 1.896
## 67 x7 ~1 2 2 58 .p31. .p67. 4.242 -0.145 4.097
## 68 x8 ~1 2 2 59 .p32. .p68. 5.630 0.078 5.708
## 69 x9 ~1 2 2 60 .p33. .p69. 5.465 0.057 5.522
## 70 visual ~1 2 2 61 .p70. -0.148 0.015 -0.133
## 71 textual ~1 2 2 62 .p71. 0.576 0.019 0.596
## 72 speed ~1 2 2 63 .p72. -0.177 0.001 -0.176
## sepc.lv sepc.all sepc.nox
## 1 NA NA NA
## 2 -0.121 -0.097 -0.097
## 3 -0.193 -0.160 -0.160
## 4 NA NA NA
## 5 0.069 0.055 0.055
## 6 -0.046 -0.045 -0.045
## 7 NA NA NA
## 8 0.022 0.022 0.022
## 9 0.004 0.004 0.004
## 10 -0.555 -0.411 -0.411
## 11 1.296 0.831 0.831
## 12 0.944 0.650 0.650
## 13 -0.445 -0.336 -0.336
## 14 -0.502 -0.313 -0.313
## 15 0.263 0.256 0.256
## 16 0.888 0.734 0.734
## 17 -0.541 -0.568 -0.568
## 18 0.654 0.666 0.666
## 19 1.000 1.000 1.000
## 20 -1.000 -1.000 -1.000
## 21 -1.000 -1.000 -1.000
## 22 0.044 0.044 0.044
## 23 0.025 0.025 0.025
## 24 -0.006 -0.006 -0.006
## 25 -0.060 -0.052 -0.052
## 26 -0.167 -0.134 -0.134
## 27 0.216 0.179 0.179
## 28 0.045 0.039 0.039
## 29 -0.040 -0.031 -0.031
## 30 -0.003 -0.003 -0.003
## 31 0.190 0.173 0.173
## 32 -0.067 -0.069 -0.069
## 33 -0.048 -0.048 -0.048
## 34 NA NA NA
## 35 NA NA NA
## 36 NA NA NA
## 37 NA NA NA
## 38 0.100 0.091 0.091
## 39 0.054 0.052 0.052
## 40 NA NA NA
## 41 -0.133 -0.109 -0.109
## 42 0.029 0.027 0.027
## 43 NA NA NA
## 44 0.084 0.081 0.081
## 45 0.069 0.068 0.068
## 46 0.654 0.480 0.480
## 47 -0.964 -0.804 -0.804
## 48 -0.641 -0.587 -0.587
## 49 -0.343 -0.283 -0.283
## 50 0.376 0.256 0.256
## 51 -0.437 -0.366 -0.366
## 52 0.625 0.553 0.553
## 53 -0.434 -0.403 -0.403
## 54 -0.522 -0.504 -0.504
## 55 -1.000 -1.000 -1.000
## 56 1.000 1.000 1.000
## 57 -1.000 -1.000 -1.000
## 58 -0.005 -0.005 -0.005
## 59 -0.071 -0.071 -0.071
## 60 -0.012 -0.012 -0.012
## 61 0.061 0.052 0.052
## 62 0.143 0.130 0.130
## 63 -0.160 -0.153 -0.153
## 64 -0.056 -0.051 -0.051
## 65 0.092 0.076 0.076
## 66 -0.030 -0.027 -0.027
## 67 -0.145 -0.136 -0.136
## 68 0.078 0.075 0.075
## 69 0.057 0.056 0.056
## 70 0.018 0.018 0.018
## 71 0.021 0.021 0.021
## 72 0.001 0.001 0.001
¿Qué representan las columnas principales?
La tabla contiene las siguientes columnas:
names(score_obj$epc)
## [1] "lhs" "op" "rhs" "block" "group" "free"
## [7] "label" "plabel" "est" "epc" "epv" "sepc.lv"
## [13] "sepc.all" "sepc.nox"
A continuación, se describe cada una de ellas:
lhs, op, rhs: identifican el parámetro del modelo (ya explicadas previamente en parTable()).
group: grupo al que pertenece el parámetro (1 = grupo de referencia, 2 = grupo comparado).
est: estimación actual del parámetro bajo la restricción de igualdad.
Las columnas block, free, label, plabel ya fueron explicadas en secciones anteriores y se utilizan principalmente para el control interno del modelo por parte de lavaan.
epc (expected parameter change): cambio esperado en la estimación si la restricción se libera.
Un EPC cercano a 0 indica que liberar la restricción no cambiaría sustancialmente el parámetro.
Un EPC grande (en valor absoluto) sugiere que la restricción está forzando artificialmente la igualdad entre grupos.
El signo del EPC indica la dirección del cambio esperado:
EPC positivo: el parámetro aumentaría.
EPC negativo: el parámetro disminuiría.
Por ejemplo, en el grupo 1, una parte de la salida es:
lhs op rhs block group free label plabel est epc epv sepc.lv sepc.all sepc.nox
10 x1 ~~ x1 1 1 7 .p10. 0.555 -0.151 0.405 -0.555 -0.411 -0.411
27 x3 ~1 1 1 24 .p27. .p27. 2.271 0.216 2.487 0.216 0.179 0.179
En la fila 27, el modelo obliga a que el intercepto de x3 sea igual en ambos grupos. Bajo esa restricción, la estimación es est=2.271. El valor EPC = 0.216 significa que si libero esta restricción, el intercepto de x3 aumentaría aproximadamente en 0.216 unidades. Este resultado es coherente con un score test significativo y sugiere que el intercepto de x3 no es invariante entre grupos.
En la fila 10, la estimación es est=0.555. El valor negativo EPC = -0.151 significa que al liberar la restricción, este parámetro disminuiría aproximadamente en 0.151 unidades.
epv (expected parameter value): valor esperado del parámetro tras liberar la restricción, calculado como \(\text{epv} = \text{est} + \text{epc}\). Para el ejemplo anterior:
Fila 27: Si no obligamos a que los grupos tengan el mismo intercepto en x3, el valor esperado sería 2.487.
Fila 10: Al liberar la restricción, el valor esperado del parámetro correspondiente sería 0.405.
sepc.lv, sepc.all, sepc.nox: representan EPC estandarizados, es decir, el mismo expected parameter change expresado en distintas escalas para facilitar la comparación entre parámetros.
sepc.lv (standardized EPC - latent variable scale): EPC estandarizado en la escala del factor latente. Es útil cuando se desea
interpretar el cambio relativo al constructo latente.
sepc.all (fully standardized EPC): EPC completamente estandarizado, comparable a un z-score o a una **diferencia
en desviaciones estándar. Es el más utilizado para evaluar la magnitud del cambio esperado.
sepc.nox (standardized EPC, no exogenous variables): EPC estandarizado ignorando variables exógenas. En modelos CFA sin
variables exógenas explícitas (como en este ejemplo), sepc.nox coincide numéricamente con sepc.all.
Por ejemplo, en la Fila 27, epc = 0.216, sepc.all = 0.179 y sepc.nox = 0.179. Es decir, si se libera esta restricción, se espera que el parámetro cambie aproximadamente 0.18 desviaciones estándar, lo que corresponde a un cambio pequeño a moderado.
Una regla orientativa es:
sepc ≈ 0.10 implica un cambio pequeño.
sepc ≈ 0.20 implica un cambio pequeño-moderado.
sepc ≥ 0.40 implica un cambio grande.
¿Por qué sepc.nox es igual a sepc.all?
En este modelo, no hay variables exógenas (es un CFA puro). Por tanto, la estandarización con y sin exógenas produce el mismo resultado. De ahí que sepc.all = sepc.nox en la mayoría de las filas.
¿Por qué algunos valores aparecen como NA?
Los valores NA aparecen cuando:
El parámetro está fijado por identificación (por ejemplo, cargas fijadas en 1).
El parámetro no se estima libremente, por lo que no tiene sentido calcular un cambio esperado ni su versión estandarizada.
Ejemplos típicos.
Cargas factoriales de referencia (= 1.000).
Medias latentes fijadas en 0 en el grupo de referencia.
Nota pedagógica.
Los EPC estandarizados no sirven para decidir si liberar una restricción (eso lo hace el score test), sino para evaluar:
Qué tan grande sería el cambio si la restricción se liberara
Por esta razón, los score tests y los EPCs deben interpretarse de forma complementaria, no aislada.
El score test indica si una restricción debe revisarse.
El EPC indica cuánto y en qué dirección cambiaría el parámetro al liberarla.
Los EPC no prueban hipótesis; indican qué restricciones están forzando artificialmente el modelo y en qué magnitud cambiarían los parámetros si se liberan.
Por esta razón, ambos resultados deben interpretarse de forma conjunta en el análisis de invarianza factorial parcial.
score_obj$uniEn score_obj$uni se ordenan los valores de χ² (X2) de mayor a menor:
score_obj$uni %>%
as.data.frame() %>%
dplyr::arrange(desc(X2)) %>%
dplyr::filter(X2 > 5) %>%
kable(caption = "Mayores valores de χ² en los tests de puntuación univariados")
| lhs | op | rhs | X2 | df | p.value |
|---|---|---|---|---|---|
| .p27. | == | .p63. | 19.192500 | 1 | 0.0000118 |
| .p31. | == | .p67. | 15.021446 | 1 | 0.0001063 |
| .p26. | == | .p62. | 6.863266 | 1 | 0.0087986 |
| .p25. | == | .p61. | 5.847258 | 1 | 0.0156013 |
Al observar los resultados, se identifica que la restricción:
.p27. == .p63.
presenta el mayor incremento en χ² (a saber, χ² ≈ 19.2), lo que sugiere que la igualdad de estos interceptos entre grupos no es compatible con los datos, y que su liberación podría mejorar sustancialmente el ajuste del modelo.
score_obj$epc)Además de los tests univariados de χ² (score_obj$uni), una forma complementaria y muy informativa de identificar interceptos problemáticos es examinar los Expected Parameter Changes (EPC) contenidos en score_obj$epc.
En este contexto, los EPC indican cuánto cambiaría un intercepto si se liberara la restricción de igualdad correspondiente.
Para facilitar la interpretación, se procede de la siguiente manera:
Se consideran únicamente los interceptos de ítems observados (op == "~1").
Se excluyen interceptos de variables latentes.
Se ordenan los EPC por su valor absoluto, ya que interesa la magnitud del cambio esperado, independientemente de su signo.
Para identificar qué interceptos de los ítems observados son los principales responsables del desajuste del modelo escalar, se analizan los expected parameter changes (EPC) asociados a los score tests. El siguiente código filtra exclusivamente interceptos de ítems y los ordena según la magnitud del cambio esperado.
score_obj$uni %>%
as.data.frame() %>%
dplyr::arrange(desc(X2)) %>%
dplyr::filter(X2 > 5) %>%
kable(caption = "Mayores valores de χ² en los tests de puntuación univariados")
¿Qué hace exactamente filter?
El filtro cumple dos funciones simultáneas:
op == "~1". Selecciona únicamente parámetros de tipo intercepto. En SEM, el operador ~1 representa:
Interceptos de variables observadas (ítems).
O medias latentes (cuando lhs corresponde a un factor latente).
grepl("^x[0-9]+$", lhs). Esta expresión utiliza una expresión regular (regular expression) para filtrar solo los nombres de las variables (las filas) donde el nombre del parámetro (lhs, left-hand side, lado izquierdo de un parámetro) sea exactamente un ítem observado del tipo x1, x2, …, x9. Es decir, su objetivo es identificar únicamente ítems observados, cuyos nombres siguen el patrón x1, x2, …, x9. Esto permite excluir explícitamente:
Medias latentes (visual, textual, speed)
Otros parámetros que no son relevantes para evaluar invarianza escalar.
El patrón se interpreta carácter por carácter:
^ indica el inicio del texto. Garantiza que el nombre comience exactamente con lo que sigue.
x especifica que el nombre debe iniciar con la letra x.
[0-9]+ representa uno o más dígitos (0, 1, 2, …, 9). El símbolo + indica “al menos un dígito”, permitiendo nombres como x1, x12, x103, etc.
$ indica el final del texto. Garantiza que no haya caracteres adicionales después del número.
¿Qué nombres selecciona este patrón?
Coincide con:
x1, x2, x3
x9
x10, x12
No coincide con:
visual, textual, speed (factores latentes)
.x1, x1. (nombres con prefijos o sufijos)
x1_std, x1_t1 (nombres extendidos)
y1, item1 (otros esquemas de nomenclatura)
¿Por qué es importante este filtro en invarianza escalar?
En modelos de invarianza escalar, las violaciones más comunes se presentan en:
Los interceptos de los ítems observados.
No en las medias latentes.
Este filtro permite:
Excluir automáticamente medias latentes (visual, textual, speed).
Evitar confundir interceptos de ítems con otros parámetros.
Focalizar el análisis EPC en parámetros sustantivamente relevantes.
Interpretación conjunta.
En conjunto, el filtro selecciona exclusivamente los interceptos de los ítems observados, que son precisamente los parámetros que con mayor frecuencia violan la invarianza escalar** en modelos multigrupo. Este paso garantiza que las decisiones de liberar restricciones se basen únicamente en parámetros sustantivamente relevantes para la comparación entre grupos.
¿Por qué se utiliza el valor absoluto del EPC?
El signo del EPC indica la dirección del cambio (aumento o disminución del intercepto), pero no su relevancia práctica.
En la evaluación de invarianza escalar parcial, el interés principal radica en identificar:
¿Qué interceptos experimentarían los cambios más grandes si se liberara la restricción de igualdad?
Por esta razón, los EPC se ordenan por |epc|, priorizando la magnitud del impacto sobre la dirección del cambio.
score_obj$epc| lhs | op | rhs | block | group | free | label | plabel | est | epc | epv | sepc.lv | sepc.all | sepc.nox |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| x3 | ~1 | 1 | 1 | 24 | .p27. | .p27. | 2.271215 | 0.2159645 | 2.487179 | 0.2159645 | 0.1792267 | 0.1792267 | |
| x7 | ~1 | 1 | 1 | 28 | .p31. | .p31. | 4.242128 | 0.1901460 | 4.432274 | 0.1901460 | 0.1728078 | 0.1728078 | |
| x2 | ~1 | 1 | 1 | 23 | .p26. | .p26. | 6.151206 | -0.1672313 | 5.983974 | -0.1672313 | -0.1338858 | -0.1338858 | |
| x3 | ~1 | 2 | 2 | 54 | .p27. | .p63. | 2.271215 | -0.1601965 | 2.111019 | -0.1601965 | -0.1533055 | -0.1533055 | |
| x7 | ~1 | 2 | 2 | 58 | .p31. | .p67. | 4.242128 | -0.1448595 | 4.097269 | -0.1448595 | -0.1362693 | -0.1362693 | |
| x2 | ~1 | 2 | 2 | 53 | .p26. | .p62. | 6.151206 | 0.1426411 | 6.293847 | 0.1426411 | 0.1302791 | 0.1302791 | |
| x5 | ~1 | 2 | 2 | 56 | .p29. | .p65. | 4.034724 | 0.0922230 | 4.126947 | 0.0922230 | 0.0761256 | 0.0761256 | |
| x8 | ~1 | 2 | 2 | 59 | .p32. | .p68. | 5.630458 | 0.0779868 | 5.708445 | 0.0779868 | 0.0751001 | 0.0751001 | |
| x8 | ~1 | 1 | 1 | 29 | .p32. | .p32. | 5.630458 | -0.0673171 | 5.563141 | -0.0673171 | -0.0689926 | -0.0689926 | |
| x1 | ~1 | 2 | 2 | 52 | .p25. | .p61. | 5.001404 | 0.0609867 | 5.062390 | 0.0609867 | 0.0522628 | 0.0522628 | |
| x1 | ~1 | 1 | 1 | 22 | .p25. | .p25. | 5.001404 | -0.0601643 | 4.941239 | -0.0601643 | -0.0517496 | -0.0517496 | |
| x9 | ~1 | 2 | 2 | 60 | .p33. | .p69. | 5.465289 | 0.0571736 | 5.522463 | 0.0571736 | 0.0561619 | 0.0561619 | |
| x4 | ~1 | 2 | 2 | 55 | .p28. | .p64. | 2.777936 | -0.0563349 | 2.721601 | -0.0563349 | -0.0511455 | -0.0511455 | |
| x9 | ~1 | 1 | 1 | 30 | .p33. | .p33. | 5.465289 | -0.0475542 | 5.417735 | -0.0475542 | -0.0479921 | -0.0479921 | |
| x4 | ~1 | 1 | 1 | 25 | .p28. | .p28. | 2.777936 | 0.0447136 | 2.822650 | 0.0447136 | 0.0388466 | 0.0388466 | |
| x5 | ~1 | 1 | 1 | 26 | .p29. | .p29. | 4.034724 | -0.0395313 | 3.995192 | -0.0395313 | -0.0311992 | -0.0311992 | |
| x6 | ~1 | 2 | 2 | 57 | .p30. | .p66. | 1.925624 | -0.0296913 | 1.895932 | -0.0296913 | -0.0271857 | -0.0271857 | |
| x6 | ~1 | 1 | 1 | 27 | .p30. | .p30. | 1.925624 | -0.0034624 | 1.922161 | -0.0034624 | -0.0034165 | -0.0034165 |
Columnas clave en score_obj$epc: label y plabel
En la salida de score_obj$epc, aparecen dos columnas fundamentales para interpretar las restricciones de igualdad:
label: etiqueta del parámetro en un grupo (por ejemplo, .p27. en la cuarta fila)
plabel: etiqueta del parámetro “pareado” bajo una restricción (por ejemplo, .p63. en la cuarta fila)
Estas columnas permiten identificar explícitamente qué parámetros están forzados a ser iguales entre grupos.
Por ejemplo, si se mira esta cuarta fila (resumen conceptual):
lhs = x3, op = ~1, group = 2,
label = .p27.,
plabel = .p63.
Eso indica que:
.p27. es el intercepto de x3 en un grupo.
.p63. es el parámetro con el cual está igualado bajo la restricción. Es decir, corresponde al intercepto del mismo ítem en el otro grupo.
Ambos están forzados a ser iguales, lo que define la restricción: .p27. == .p63.
Filas que sí y que no representan restricciones de invarianza
Es crucial distinguir entre dos tipos de filas que aparecen en score_obj$epc:
Filas con label == plabel
Representan parámetros no restringidos (por ejemplo, interceptos del grupo de referencia).
No corresponden a restricciones de igualdad.
No deben liberarse, incluso si su EPC es grande.
Filas con label ≠ plabel
Representan interceptos igualados entre grupos.
Corresponden a restricciones reales de invarianza escalar.
Son las candidatas válidas para liberar en un modelo de invarianza escalar parcial.
Por tanto, aunque una fila con label == plabel aparezca en los primeros lugares al ordenar por |epc|, no debe interpretarse como evidencia de no invarianza.
Conexión con la especificación del modelo escalar parcial
Una vez identificada una restricción problemática del tipo .p27. == .p63., el paso final no consiste en liberar etiquetas, sino en liberar el intercepto del ítem correspondiente en la sintaxis del modelo. Por ejemplo, debemos revisar .p27. y .p63. cuál ítem corresponde al intercepto. Se explicará a continuación.
Las expresiones del tipo .p27. y .p63. no son arbitrarias: corresponden a etiquetas internas de lavaan que identifican parámetros específicos del modelo. El número que aparece en la etiqueta (por ejemplo, 63 en .p63.) indica directamente la fila correspondiente en la tabla de parámetros del modelo (parTable()):
param<-parTable(model_scalar_a)
param
## id lhs op rhs user block group free ustart exo label plabel start
## 1 1 visual =~ x1 1 1 1 0 1 0 .p1. 1.000
## 2 2 visual =~ x2 1 1 1 1 NA 0 .p2. .p2. 0.769
## 3 3 visual =~ x3 1 1 1 2 NA 0 .p3. .p3. 1.186
## 4 4 textual =~ x4 1 1 1 0 1 0 .p4. 1.000
## 5 5 textual =~ x5 1 1 1 3 NA 0 .p5. .p5. 1.237
## 6 6 textual =~ x6 1 1 1 4 NA 0 .p6. .p6. 0.865
## 7 7 speed =~ x7 1 1 1 0 1 0 .p7. 1.000
## 8 8 speed =~ x8 1 1 1 5 NA 0 .p8. .p8. 1.227
## 9 9 speed =~ x9 1 1 1 6 NA 0 .p9. .p9. 0.827
## 10 10 x1 ~~ x1 0 1 1 7 NA 0 .p10. 0.698
## 11 11 x2 ~~ x2 0 1 1 8 NA 0 .p11. 0.752
## 12 12 x3 ~~ x3 0 1 1 9 NA 0 .p12. 0.673
## 13 13 x4 ~~ x4 0 1 1 10 NA 0 .p13. 0.660
## 14 14 x5 ~~ x5 0 1 1 11 NA 0 .p14. 0.854
## 15 15 x6 ~~ x6 0 1 1 12 NA 0 .p15. 0.487
## 16 16 x7 ~~ x7 0 1 1 13 NA 0 .p16. 0.585
## 17 17 x8 ~~ x8 0 1 1 14 NA 0 .p17. 0.476
## 18 18 x9 ~~ x9 0 1 1 15 NA 0 .p18. 0.489
## 19 19 visual ~~ visual 0 1 1 16 NA 0 .p19. 0.050
## 20 20 textual ~~ textual 0 1 1 17 NA 0 .p20. 0.050
## 21 21 speed ~~ speed 0 1 1 18 NA 0 .p21. 0.050
## 22 22 visual ~~ textual 0 1 1 19 NA 0 .p22. 0.000
## 23 23 visual ~~ speed 0 1 1 20 NA 0 .p23. 0.000
## 24 24 textual ~~ speed 0 1 1 21 NA 0 .p24. 0.000
## 25 25 x1 ~1 0 1 1 22 NA 0 .p25. .p25. 4.941
## 26 26 x2 ~1 0 1 1 23 NA 0 .p26. .p26. 5.984
## 27 27 x3 ~1 0 1 1 24 NA 0 .p27. .p27. 2.487
## 28 28 x4 ~1 0 1 1 25 NA 0 .p28. .p28. 2.823
## 29 29 x5 ~1 0 1 1 26 NA 0 .p29. .p29. 3.995
## 30 30 x6 ~1 0 1 1 27 NA 0 .p30. .p30. 1.922
## 31 31 x7 ~1 0 1 1 28 NA 0 .p31. .p31. 4.432
## 32 32 x8 ~1 0 1 1 29 NA 0 .p32. .p32. 5.563
## 33 33 x9 ~1 0 1 1 30 NA 0 .p33. .p33. 5.418
## 34 34 visual ~1 0 1 1 0 0 0 .p34. 0.000
## 35 35 textual ~1 0 1 1 0 0 0 .p35. 0.000
## 36 36 speed ~1 0 1 1 0 0 0 .p36. 0.000
## 37 37 visual =~ x1 1 2 2 0 1 0 .p37. 1.000
## 38 38 visual =~ x2 1 2 2 31 NA 0 .p2. .p38. 0.896
## 39 39 visual =~ x3 1 2 2 32 NA 0 .p3. .p39. 1.155
## 40 40 textual =~ x4 1 2 2 0 1 0 .p40. 1.000
## 41 41 textual =~ x5 1 2 2 33 NA 0 .p5. .p41. 0.991
## 42 42 textual =~ x6 1 2 2 34 NA 0 .p6. .p42. 0.962
## 43 43 speed =~ x7 1 2 2 0 1 0 .p43. 1.000
## 44 44 speed =~ x8 1 2 2 35 NA 0 .p8. .p44. 1.282
## 45 45 speed =~ x9 1 2 2 36 NA 0 .p9. .p45. 0.895
## 46 46 x1 ~~ x1 0 2 2 37 NA 0 .p46. 0.659
## 47 47 x2 ~~ x2 0 2 2 38 NA 0 .p47. 0.613
## 48 48 x3 ~~ x3 0 2 2 39 NA 0 .p48. 0.537
## 49 49 x4 ~~ x4 0 2 2 40 NA 0 .p49. 0.629
## 50 50 x5 ~~ x5 0 2 2 41 NA 0 .p50. 0.671
## 51 51 x6 ~~ x6 0 2 2 42 NA 0 .p51. 0.640
## 52 52 x7 ~~ x7 0 2 2 43 NA 0 .p52. 0.531
## 53 53 x8 ~~ x8 0 2 2 44 NA 0 .p53. 0.547
## 54 54 x9 ~~ x9 0 2 2 45 NA 0 .p54. 0.526
## 55 55 visual ~~ visual 0 2 2 46 NA 0 .p55. 0.050
## 56 56 textual ~~ textual 0 2 2 47 NA 0 .p56. 0.050
## 57 57 speed ~~ speed 0 2 2 48 NA 0 .p57. 0.050
## 58 58 visual ~~ textual 0 2 2 49 NA 0 .p58. 0.000
## 59 59 visual ~~ speed 0 2 2 50 NA 0 .p59. 0.000
## 60 60 textual ~~ speed 0 2 2 51 NA 0 .p60. 0.000
## 61 61 x1 ~1 0 2 2 52 NA 0 .p25. .p61. 4.930
## 62 62 x2 ~1 0 2 2 53 NA 0 .p26. .p62. 6.200
## 63 63 x3 ~1 0 2 2 54 NA 0 .p27. .p63. 1.996
## 64 64 x4 ~1 0 2 2 55 NA 0 .p28. .p64. 3.317
## 65 65 x5 ~1 0 2 2 56 NA 0 .p29. .p65. 4.712
## 66 66 x6 ~1 0 2 2 57 NA 0 .p30. .p66. 2.469
## 67 67 x7 ~1 0 2 2 58 NA 0 .p31. .p67. 3.921
## 68 68 x8 ~1 0 2 2 59 NA 0 .p32. .p68. 5.488
## 69 69 x9 ~1 0 2 2 60 NA 0 .p33. .p69. 5.327
## 70 70 visual ~1 0 2 2 61 NA 0 .p70. 0.000
## 71 71 textual ~1 0 2 2 62 NA 0 .p71. 0.000
## 72 72 speed ~1 0 2 2 63 NA 0 .p72. 0.000
## 73 73 .p2. == .p38. 2 0 0 0 NA 0 0.000
## 74 74 .p3. == .p39. 2 0 0 0 NA 0 0.000
## 75 75 .p5. == .p41. 2 0 0 0 NA 0 0.000
## 76 76 .p6. == .p42. 2 0 0 0 NA 0 0.000
## 77 77 .p8. == .p44. 2 0 0 0 NA 0 0.000
## 78 78 .p9. == .p45. 2 0 0 0 NA 0 0.000
## 79 79 .p25. == .p61. 2 0 0 0 NA 0 0.000
## 80 80 .p26. == .p62. 2 0 0 0 NA 0 0.000
## 81 81 .p27. == .p63. 2 0 0 0 NA 0 0.000
## 82 82 .p28. == .p64. 2 0 0 0 NA 0 0.000
## 83 83 .p29. == .p65. 2 0 0 0 NA 0 0.000
## 84 84 .p30. == .p66. 2 0 0 0 NA 0 0.000
## 85 85 .p31. == .p67. 2 0 0 0 NA 0 0.000
## 86 86 .p32. == .p68. 2 0 0 0 NA 0 0.000
## 87 87 .p33. == .p69. 2 0 0 0 NA 0 0.000
## est se
## 1 1.000 0.000
## 2 0.576 0.101
## 3 0.798 0.112
## 4 1.000 0.000
## 5 1.120 0.066
## 6 0.932 0.056
## 7 1.000 0.000
## 8 1.130 0.145
## 9 1.009 0.132
## 10 0.555 0.139
## 11 1.296 0.158
## 12 0.944 0.136
## 13 0.445 0.069
## 14 0.502 0.082
## 15 0.263 0.050
## 16 0.888 0.120
## 17 0.541 0.095
## 18 0.654 0.096
## 19 0.796 0.172
## 20 0.879 0.131
## 21 0.322 0.082
## 22 0.410 0.095
## 23 0.178 0.066
## 24 0.180 0.062
## 25 5.001 0.090
## 26 6.151 0.077
## 27 2.271 0.083
## 28 2.778 0.087
## 29 4.035 0.096
## 30 1.926 0.079
## 31 4.242 0.073
## 32 5.630 0.072
## 33 5.465 0.069
## 34 0.000 0.000
## 35 0.000 0.000
## 36 0.000 0.000
## 37 1.000 0.000
## 38 0.576 0.101
## 39 0.798 0.112
## 40 1.000 0.000
## 41 1.120 0.066
## 42 0.932 0.056
## 43 1.000 0.000
## 44 1.130 0.145
## 45 1.009 0.132
## 46 0.654 0.128
## 47 0.964 0.123
## 48 0.641 0.101
## 49 0.343 0.062
## 50 0.376 0.073
## 51 0.437 0.067
## 52 0.625 0.095
## 53 0.434 0.088
## 54 0.522 0.086
## 55 0.708 0.160
## 56 0.870 0.131
## 57 0.505 0.115
## 58 0.427 0.097
## 59 0.329 0.082
## 60 0.236 0.073
## 61 5.001 0.090
## 62 6.151 0.077
## 63 2.271 0.083
## 64 2.778 0.087
## 65 4.035 0.096
## 66 1.926 0.079
## 67 4.242 0.073
## 68 5.630 0.072
## 69 5.465 0.069
## 70 -0.148 0.122
## 71 0.576 0.117
## 72 -0.177 0.090
## 73 0.000 0.000
## 74 0.000 0.000
## 75 0.000 0.000
## 76 0.000 0.000
## 77 0.000 0.000
## 78 0.000 0.000
## 79 0.000 0.000
## 80 0.000 0.000
## 81 0.000 0.000
## 82 0.000 0.000
## 83 0.000 0.000
## 84 0.000 0.000
## 85 0.000 0.000
## 86 0.000 0.000
## 87 0.000 0.000
Por tanto, para identificar qué parámetro representa .p63., se consulta la fila 63de la tabla de parámetros del modelo escalar:
id <- 63
param[id:id, 1:3]
## id lhs op
## 63 63 x3 ~1
Esta operación permite mapear la etiqueta interna .p63. al parámetro correspondiente. Si se consulta la fila 27, obtendremos el mismo resultado.
id <- 27
param[id:id, 1:3]
## id lhs op
## 27 27 x3 ~1
En cualquier caso, se observa que el parámetro identificado es el intercepto del ítem x3, es decir, x3~1. En consecuencia, este intercepto debe especificarse como no invariante en la reestimación del modelo de invarianza escalar parcial. O sea, la especificación correcta es: group.partial = "x3~1". De esta forma, se rompe la igualdad entre grupos para ese intercepto, manteniendo el resto de las restricciones y preservando la comparabilidad de las medias latentes.
score_obj$uniEl bloque de abjo automatiza completamente la identificación de interceptos a liberar en un modelo de invarianza escalar parcial:
Se ordenan los tests de puntuación univariados (score_obj$uni) por el valor de χ² y se selecciona la restricción más problemática.
Se selecciona solamente la primera fila, la cual contiene la restricción con mayor valor de χ².
Se extraen automáticamente las etiquetas internas (.p..) involucradas en dicha restricción.
Estas etiquetas se mapean a parámetros reales del modelo usando parTable().
Se conservan únicamente los interceptos de ítems (x? ~ 1), descartando parámetros que no corresponden a interceptos observados.
Se construye el vector group_partial, que puede usarse directamente en la reestimación del modelo escalar parcial.
De esta forma, se evita la selección manual de identificadores y se garantiza un procedimiento reproducible, transparente y pedagógicamente claro.
# 1) Tabla univariada (score tests) ordenada
uni_tbl <- score_obj$uni %>%
as.data.frame() %>%
filter(op == "==") %>% # restricciones de igualdad (labels .p.. == .p..)
arrange(desc(X2)) %>% # mayor χ² primero
filter(X2 > 5) # umbral práctico
kable(uni_tbl, caption = "Mayores valores de χ² en los tests univariados (lavTestScore)")
# 2) Tomar SOLO la restricción con mayor X2 (la primera fila)
top_row <- uni_tbl %>% slice(1)
# 3) Extraer SOLO los dos labels involucrados en esa restricción
labels_to_free <- top_row %>%
select(lhs, rhs) %>%
unlist(use.names = FALSE) %>%
unique()
# 4) Mapear labels -> parámetros reales con parTable()
param <- as.data.frame(parTable(model_scalar_a))
mapped <- param %>%
filter(label %in% labels_to_free) %>%
select(id, lhs, op, rhs, group, label, plabel)
kable(mapped, caption = "Mapeo automático: labels (.p..) -> parámetros reales (parTable)")
# 5) De ese mapeo, quedarnos solo con interceptos de ítems: x? ~1
mapped_intercepts <- mapped %>%
filter(op == "~1", grepl("^x[0-9]+$", lhs)) %>%
arrange(lhs, group)
kable(mapped_intercepts, caption = "Interceptos (~1) implicados en las restricciones seleccionadas")
# 6) Vector final para group.partial
group_partial <- mapped_intercepts %>%
distinct(lhs) %>%
mutate(gp = paste0(lhs, "~1")) %>%
pull(gp)
group_partial
## [1] "x3~1"
Con el fin de evitar pasos manuales, reducir errores y reutilizar el procedimiento en otros análisis, se define la siguiente función.
Esta función automatiza el proceso de:
Identificar la restricción de igualdad más problemática (mayor χ²).
Mapear sus labels internos (.p..)** a los parámetros reales del modelo.
Construir automáticamente el vector group.partial necesario para especificar un modelo escalar parcial.
get_group_partial <- function(fit, score_obj, x2_cut = 5, top_n = 1, show_tables = TRUE) {
# 1) Tabla univariada: quedarse solo con restricciones de igualdad (.p.. == .p..)
uni_tbl <- score_obj$uni %>%
as.data.frame() %>%
dplyr::filter(op == "==") %>%
dplyr::arrange(dplyr::desc(X2)) %>%
dplyr::filter(X2 > x2_cut)
if (nrow(uni_tbl) == 0) {
warning("No hay restricciones con X2 > x2_cut. Devuelvo group_partial vacío.")
return(list(
group_partial = character(0),
uni_tbl = uni_tbl,
top_rows = uni_tbl,
labels_to_free = character(0),
mapped = data.frame(),
mapped_intercepts = data.frame()
))
}
# 2) Tomar las top_n restricciones con mayor X2
top_rows <- uni_tbl %>% dplyr::slice(1:top_n)
# 3) Extraer labels (.p..) implicados en esas restricciones
labels_to_free <- top_rows %>%
dplyr::select(lhs, rhs) %>%
unlist(use.names = FALSE) %>%
unique()
# 4) Mapear labels -> parámetros reales usando parTable()
param <- as.data.frame(lavaan::parTable(fit))
mapped <- param %>%
dplyr::filter(label %in% labels_to_free) %>%
dplyr::select(id, lhs, op, rhs, group, label, plabel)
# 5) Conservar solo interceptos de ítems: x? ~ 1
mapped_intercepts <- mapped %>%
dplyr::filter(op == "~1", grepl("^x[0-9]+$", lhs)) %>%
dplyr::arrange(lhs, group)
# 6) Vector final para group.partial
group_partial <- mapped_intercepts %>%
dplyr::distinct(lhs) %>%
dplyr::mutate(gp = paste0(lhs, "~1")) %>%
dplyr::pull(gp)
# 7) Mostrar tablas (opcional)
if (isTRUE(show_tables)) {
knitr::kable(uni_tbl, caption = "Ranking (X2): restricciones de igualdad (score tests univariados)")
knitr::kable(top_rows, caption = "Restricción(es) seleccionada(s): top_n por X2")
knitr::kable(mapped, caption = "Mapeo: labels (.p..) → parámetros reales (parTable)")
knitr::kable(mapped_intercepts, caption = "Interceptos (~1) implicados (ítems x?)")
}
return(list(
group_partial = group_partial,
uni_tbl = uni_tbl,
top_rows = top_rows,
labels_to_free = labels_to_free,
mapped = mapped,
mapped_intercepts = mapped_intercepts
))
}
¿Qué hace exactamente esta función?
De forma resumida, la función:
Busca las restricciones de igualdad que más deterioran el ajuste (χ² alto).
Identifica los labels internos (.p27. == .p63.).
Traduce esos labels a interceptos reales de ítems (por ejemplo, x3 ~ 1).
Devuelve directamente el vector requerido por group.partial.
Todo esto se realiza sin inspeccionar manualmente IDs ni tablas internas.
Uso práctico.
group <- get_group_partial(fit = model_scalar_a,
score_obj = score_obj,
x2_cut = 5,
top_n = 1
)
group
## $group_partial
## [1] "x3~1"
##
## $uni_tbl
## lhs op rhs X2 df p.value
## 1 .p27. == .p63. 19.192500 1 1.181768e-05
## 2 .p31. == .p67. 15.021446 1 1.062963e-04
## 3 .p26. == .p62. 6.863266 1 8.798561e-03
## 4 .p25. == .p61. 5.847258 1 1.560134e-02
##
## $top_rows
## lhs op rhs X2 df p.value
## 1 .p27. == .p63. 19.1925 1 1.181768e-05
##
## $labels_to_free
## [1] ".p27." ".p63."
##
## $mapped
## id lhs op rhs group label plabel
## 1 27 x3 ~1 1 .p27. .p27.
## 2 63 x3 ~1 2 .p27. .p63.
##
## $mapped_intercepts
## id lhs op rhs group label plabel
## 1 27 x3 ~1 1 .p27. .p27.
## 2 63 x3 ~1 2 .p27. .p63.
group$group_partial
## [1] "x3~1"
get_group_partial_target()Con esta función, obtenemos exactamente el mismo resultado.
group <- get_group_partial_target(fit = model_scalar_a,
score_obj = score_obj,
x2_cut = 5,
top_n = 1,
target="intercepts"
)
group
## $group_partial
## x3
## "x3~1"
##
## $target_used
## [1] "intercepts"
##
## $uni_tbl
## lhs op rhs X2 df p.value
## 1 .p27. == .p63. 19.192500 1 1.181768e-05
## 2 .p31. == .p67. 15.021446 1 1.062963e-04
## 3 .p26. == .p62. 6.863266 1 8.798561e-03
## 4 .p25. == .p61. 5.847258 1 1.560134e-02
##
## $top_rows
## lhs op rhs X2 df p.value
## 1 .p27. == .p63. 19.1925 1 1.181768e-05
##
## $labels_to_free
## [1] ".p27." ".p63."
##
## $mapped
## id lhs op rhs group label plabel target_class
## 1 27 x3 ~1 1 .p27. .p27. intercepts
## 2 63 x3 ~1 2 .p27. .p63. intercepts
##
## $mapped_filtered
## id lhs op rhs group label plabel target_class
## 1 27 x3 ~1 1 .p27. .p27. intercepts
## 2 63 x3 ~1 2 .p27. .p63. intercepts
##
## $note
## [1] "Candidates produced for targets: {intercepts}."
group$group_partial
## x3
## "x3~1"
x3~1En este paso se evalúa la invarianza escalar (igualdad de cargas factoriales e interceptos entre grupos), permitiendo que un intercepto varíe entre grupos mediante group.partial. El procedimiento es análogo a los pasos anteriores:
Ajustar el modelo escalar parcial.
Revisar un resumen del modelo, verificando que los índices globales de ajuste sean aceptables.
Compararlo con el modelo métrico mediante un test χ² de diferencia (modelos anidados).
Utilizar score tests (lavTestScore) para identificar qué restricción de igualdad genera mayor desajuste y, por tanto, cuál podría liberarse a continuación.
# 1. Ajustar el modelo parcial
model_scalar_bp <- cfa(HS.model, data = HolzingerSwineford1939,
group = "school",
group.equal = c("loadings", "intercepts"),
group.partial = c("x3~1")
)
# 2. Resumen del modelo
summary(model_scalar_bp, fit.measures = TRUE)
# 3. Comparación de modelos anidados
anova(model_metric, model_scalar_bp)
# 4. Prueba score
score_obj <- lavTestScore(model_scalar_bp, epc = TRUE)
# 4a. Primera forma
group <- get_group_partial(fit = model_scalar_bp,
score_obj = score_obj,
x2_cut = 5,
top_n = 1
)
# 4b. Segunda forma
group <- get_group_partial_target(fit = model_scalar_bp,
score_obj = score_obj,
x2_cut = 5,
top_n = 1,
target="intercepts"
)
group
group$group_partial
En las siguientes secciones, se interpretan las salidas correspondientes.
summary()Se obtiene la siguiente salida:
## lavaan 0.6-19 ended normally after 63 iterations
##
## Estimator ML
## Optimization method NLMINB
## Number of model parameters 63
## Number of equality constraints 14
##
## Number of observations per group:
## Pasteur 156
## Grant-White 145
##
## Model Test User Model:
##
## Test statistic 144.579
## Degrees of freedom 59
## P-value (Chi-square) 0.000
## Test statistic for each group:
## Pasteur 79.471
## Grant-White 65.108
##
## Model Test Baseline Model:
##
## Test statistic 957.769
## Degrees of freedom 72
## P-value 0.000
##
## User Model versus Baseline Model:
##
## Comparative Fit Index (CFI) 0.903
## Tucker-Lewis Index (TLI) 0.882
##
## Loglikelihood and Information Criteria:
##
## Loglikelihood user model (H0) -3696.561
## Loglikelihood unrestricted model (H1) -3624.272
##
## Akaike (AIC) 7491.123
## Bayesian (BIC) 7672.771
## Sample-size adjusted Bayesian (SABIC) 7517.371
##
## Root Mean Square Error of Approximation:
##
## RMSEA 0.098
## 90 Percent confidence interval - lower 0.078
## 90 Percent confidence interval - upper 0.119
## P-value H_0: RMSEA <= 0.050 0.000
## P-value H_0: RMSEA >= 0.080 0.932
##
## Standardized Root Mean Square Residual:
##
## SRMR 0.077
##
## Parameter Estimates:
##
## Standard errors Standard
## Information Expected
## Information saturated (h1) model Structured
##
##
## Group 1 [Pasteur]:
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|)
## visual =~
## x1 1.000
## x2 (.p2.) 0.606 0.101 5.988 0.000
## x3 (.p3.) 0.791 0.109 7.264 0.000
## textual =~
## x4 1.000
## x5 (.p5.) 1.120 0.066 16.964 0.000
## x6 (.p6.) 0.932 0.056 16.604 0.000
## speed =~
## x7 1.000
## x8 (.p8.) 1.129 0.145 7.788 0.000
## x9 (.p9.) 1.008 0.131 7.667 0.000
##
## Covariances:
## Estimate Std.Err z-value P(>|z|)
## visual ~~
## textual 0.404 0.095 4.248 0.000
## speed 0.177 0.066 2.679 0.007
## textual ~~
## speed 0.180 0.062 2.900 0.004
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|)
## .x1 (.25.) 4.914 0.092 53.532 0.000
## .x2 (.26.) 6.087 0.079 77.018 0.000
## .x3 2.487 0.094 26.476 0.000
## .x4 (.28.) 2.778 0.087 31.953 0.000
## .x5 (.29.) 4.035 0.096 41.856 0.000
## .x6 (.30.) 1.926 0.079 24.426 0.000
## .x7 (.31.) 4.242 0.073 57.966 0.000
## .x8 (.32.) 5.631 0.072 78.521 0.000
## .x9 (.33.) 5.465 0.069 79.039 0.000
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .x1 0.560 0.137 4.084 0.000
## .x2 1.267 0.156 8.107 0.000
## .x3 0.879 0.128 6.854 0.000
## .x4 0.446 0.069 6.431 0.000
## .x5 0.502 0.082 6.131 0.000
## .x6 0.263 0.050 5.261 0.000
## .x7 0.888 0.120 7.415 0.000
## .x8 0.540 0.095 5.703 0.000
## .x9 0.654 0.096 6.808 0.000
## visual 0.797 0.170 4.694 0.000
## textual 0.879 0.131 6.693 0.000
## speed 0.323 0.082 3.914 0.000
##
##
## Group 2 [Grant-White]:
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|)
## visual =~
## x1 1.000
## x2 (.p2.) 0.606 0.101 5.988 0.000
## x3 (.p3.) 0.791 0.109 7.264 0.000
## textual =~
## x4 1.000
## x5 (.p5.) 1.120 0.066 16.964 0.000
## x6 (.p6.) 0.932 0.056 16.604 0.000
## speed =~
## x7 1.000
## x8 (.p8.) 1.129 0.145 7.788 0.000
## x9 (.p9.) 1.008 0.131 7.667 0.000
##
## Covariances:
## Estimate Std.Err z-value P(>|z|)
## visual ~~
## textual 0.426 0.097 4.412 0.000
## speed 0.327 0.082 3.993 0.000
## textual ~~
## speed 0.236 0.073 3.222 0.001
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|)
## .x1 (.25.) 4.914 0.092 53.532 0.000
## .x2 (.26.) 6.087 0.079 77.018 0.000
## .x3 1.956 0.108 18.178 0.000
## .x4 (.28.) 2.778 0.087 31.953 0.000
## .x5 (.29.) 4.035 0.096 41.856 0.000
## .x6 (.30.) 1.926 0.079 24.426 0.000
## .x7 (.31.) 4.242 0.073 57.966 0.000
## .x8 (.32.) 5.631 0.072 78.521 0.000
## .x9 (.33.) 5.465 0.069 79.039 0.000
## visual 0.051 0.129 0.392 0.695
## textual 0.576 0.117 4.918 0.000
## speed -0.177 0.090 -1.968 0.049
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .x1 0.651 0.127 5.135 0.000
## .x2 0.939 0.122 7.723 0.000
## .x3 0.603 0.096 6.255 0.000
## .x4 0.343 0.062 5.535 0.000
## .x5 0.376 0.073 5.133 0.000
## .x6 0.437 0.067 6.559 0.000
## .x7 0.624 0.095 6.568 0.000
## .x8 0.433 0.088 4.906 0.000
## .x9 0.523 0.086 6.109 0.000
## visual 0.716 0.160 4.476 0.000
## textual 0.870 0.131 6.659 0.000
## speed 0.505 0.115 4.381 0.000
El modelo escalar parcial converge correctamente tras 63 iteraciones, estimando 63 parámetros con 14 restricciones de igualdad, lo cual refleja la imposición de cargas factoriales e interceptos invariantes, excepto el intercepto liberado (x3~1).
Desde el punto de vista del ajuste global, el modelo presenta:
χ²(59) = 144.58, p < 0.001, lo que indica discrepancias residuales esperables en muestras moderadas.
CFI = 0.903 y TLI = 0.882, valores cercanos pero ligeramente por debajo de los umbrales convencionales (≈ 0.95).
RMSEA = 0.098 (IC 90%: 0.078–0.119), superior al criterio estricto de buen ajuste, aunque consistente con un ajuste moderado.
SRMR = 0.077, dentro de rangos aceptables.
En cuanto a la estructura del modelo, las cargas factoriales permanecen iguales entre grupos, confirmando la invarianza métrica previamente establecida. El intercepto de x3 es el único que difiere entre grupos, evidenciando que este indicador presenta diferencias sistemáticas de nivel entre escuelas.
Las covarianzas entre factores latentes son significativas en ambos grupos, lo que indica relaciones sustantivas entre las dimensiones visual, textual y speed. Asimismo, las varianzas residuales y latentes son estadísticamente significativas, lo que respalda la estabilidad del modelo en cada grupo.
En conjunto, el summary() sugiere que, aunque el modelo escalar parcial mejora respecto al escalar estricto, la invarianza escalar completa aún no se alcanza, justificando el uso de score tests para identificar interceptos adicionales candidatos a ser liberados.
anova()Se obtiene:
##
## Chi-Squared Difference Test
##
## Df AIC BIC Chisq Chisq diff RMSEA Df diff Pr(>Chisq)
## model_metric 54 7480.6 7680.8 124.04
## model_scalar_bp 59 7491.1 7672.8 144.58 20.535 0.14368 5 0.0009912
##
## model_metric
## model_scalar_bp ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Reuniendo los resultados de los anovas anteriores:
Chi-Squared Difference Test
Model (versus) Df AIC BIC Chisq Chisq diff RMSEA Df diff Pr(>Chisq)
M1: configural 48 7484.4 7706.8 115.85
M2: metric (M1) 54 7480.6 7680.8 124.04 8.1922 0.049272 6 0.2244
M3a: scalar_a (M2) 60 7508.6 7686.6 164.10 40.0590 0.19421 6 4.435e-07 ***
M3b: scalar_bp (M2) 59 7491.1 7672.8 144.58 20.5350 0.143680 5 0.0009912 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Interpretación breve.
Aun liberando el intercepto de x3 (x3~1), el modelo escalar parcial sigue siendo significativamente peor que el modelo métrico (Δχ² = 20.535, Δgl = 5, p ≈ 0.001).
Esto indica que la invarianza escalar completa no se cumple todavía, por lo que podrían requerirse más liberaciones de interceptos.
A continuación se calculan los score tests con EPCs y se utiliza get_group_partial() para identificar automáticamente la restricción más crítica (mayor estadístico χ² por encima de un umbral) candidata a liberarse. La salida es:
## $group_partial
## x7
## "x7~1"
##
## $target_used
## [1] "intercepts"
##
## $uni_tbl
## lhs op rhs X2 df p.value
## 1 .p31. == .p67. 15.0234 1 0.0001061866
##
## $top_rows
## lhs op rhs X2 df p.value
## 1 .p31. == .p67. 15.0234 1 0.0001061866
##
## $labels_to_free
## [1] ".p31." ".p67."
##
## $mapped
## id lhs op rhs group label plabel target_class
## 1 31 x7 ~1 1 .p31. .p31. intercepts
## 2 67 x7 ~1 2 .p31. .p67. intercepts
##
## $mapped_filtered
## id lhs op rhs group label plabel target_class
## 1 31 x7 ~1 1 .p31. .p31. intercepts
## 2 67 x7 ~1 2 .p31. .p67. intercepts
##
## $note
## [1] "Candidates produced for targets: {intercepts}."
## x7
## "x7~1"
Interpretación breve.
El mayor valor del score test corresponde al intercepto de x7, cuya restricción de igualdad entre grupos (parámetros .p31. y .p67.) es la principal fuente de desajuste (X² ≈ 15.02).
En consecuencia, si se continúa con el procedimiento iterativo de invarianza escalar parcial, el siguiente paso natural sería liberar el intercepto x7~1 entre grupos.
x3~1 y x7~1En este tercer intento se evalúa nuevamente la invarianza escalar, manteniendo la igualdad de cargas factoriales e interceptos entre grupos, pero permitiendo que dos interceptos varíen entre grupos (x3~1 y x7~1). El procedimiento es análogo a los pasos anteriores:
Ajustar el modelo escalar parcial con dos interceptos liberados.
Revisar el resumen del modelo, verificando la mejora en los índices de ajuste global.
Compararlo con el modelo métrico mediante un test χ² de diferencia (modelos anidados).
Aplicar score tests (lavTestScore) para confirmar si existen restricciones adicionales que deban ser liberadas.
# 1. Ajustar el modelo parcial
model_scalar_cp <- cfa(HS.model, data = HolzingerSwineford1939,
group = "school",
group.equal = c("loadings", "intercepts"),
group.partial = c("x3~1", "x7~1")
)
# 2. Resumen del modelo
summary(model_scalar_cp, fit.measures = TRUE)
# 3. Comparación de modelos anidados
anova(model_metric, model_scalar_cp)
# 4. Prueba score
score_obj <- lavTestScore(model_scalar_cp, epc = TRUE)
# 4a. Primera forma
group <- get_group_partial(fit = model_scalar_cp,
score_obj = score_obj,
x2_cut = 5,
top_n = 1
)
# 4b. Segunda forma
group <- get_group_partial_target(fit = model_scalar_cp,
score_obj = score_obj,
x2_cut = 5,
top_n = 1,
target="intercepts"
)
group
group$group_partial
summary()La salida se puede visualizar a continuación:
## lavaan 0.6-19 ended normally after 61 iterations
##
## Estimator ML
## Optimization method NLMINB
## Number of model parameters 63
## Number of equality constraints 13
##
## Number of observations per group:
## Pasteur 156
## Grant-White 145
##
## Model Test User Model:
##
## Test statistic 129.422
## Degrees of freedom 58
## P-value (Chi-square) 0.000
## Test statistic for each group:
## Pasteur 71.170
## Grant-White 58.253
##
## Model Test Baseline Model:
##
## Test statistic 957.769
## Degrees of freedom 72
## P-value 0.000
##
## User Model versus Baseline Model:
##
## Comparative Fit Index (CFI) 0.919
## Tucker-Lewis Index (TLI) 0.900
##
## Loglikelihood and Information Criteria:
##
## Loglikelihood user model (H0) -3688.983
## Loglikelihood unrestricted model (H1) -3624.272
##
## Akaike (AIC) 7477.966
## Bayesian (BIC) 7663.322
## Sample-size adjusted Bayesian (SABIC) 7504.750
##
## Root Mean Square Error of Approximation:
##
## RMSEA 0.090
## 90 Percent confidence interval - lower 0.070
## 90 Percent confidence interval - upper 0.111
## P-value H_0: RMSEA <= 0.050 0.001
## P-value H_0: RMSEA >= 0.080 0.805
##
## Standardized Root Mean Square Residual:
##
## SRMR 0.073
##
## Parameter Estimates:
##
## Standard errors Standard
## Information Expected
## Information saturated (h1) model Structured
##
##
## Group 1 [Pasteur]:
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|)
## visual =~
## x1 1.000
## x2 (.p2.) 0.606 0.101 5.988 0.000
## x3 (.p3.) 0.791 0.109 7.259 0.000
## textual =~
## x4 1.000
## x5 (.p5.) 1.120 0.066 16.960 0.000
## x6 (.p6.) 0.932 0.056 16.606 0.000
## speed =~
## x7 1.000
## x8 (.p8.) 1.200 0.155 7.741 0.000
## x9 (.p9.) 1.041 0.136 7.635 0.000
##
## Covariances:
## Estimate Std.Err z-value P(>|z|)
## visual ~~
## textual 0.404 0.095 4.247 0.000
## speed 0.168 0.064 2.647 0.008
## textual ~~
## speed 0.172 0.060 2.882 0.004
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|)
## .x1 (.25.) 4.914 0.092 53.538 0.000
## .x2 (.26.) 6.087 0.079 76.999 0.000
## .x3 2.487 0.094 26.474 0.000
## .x4 (.28.) 2.778 0.087 31.953 0.000
## .x5 (.29.) 4.035 0.096 41.861 0.000
## .x6 (.30.) 1.926 0.079 24.425 0.000
## .x7 4.432 0.086 51.533 0.000
## .x8 (.32.) 5.569 0.074 75.328 0.000
## .x9 (.33.) 5.409 0.070 77.182 0.000
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .x1 0.560 0.137 4.086 0.000
## .x2 1.267 0.156 8.105 0.000
## .x3 0.879 0.128 6.850 0.000
## .x4 0.446 0.069 6.432 0.000
## .x5 0.502 0.082 6.132 0.000
## .x6 0.263 0.050 5.258 0.000
## .x7 0.850 0.114 7.471 0.000
## .x8 0.516 0.095 5.429 0.000
## .x9 0.656 0.096 6.852 0.000
## visual 0.796 0.170 4.691 0.000
## textual 0.879 0.131 6.693 0.000
## speed 0.304 0.078 3.918 0.000
##
##
## Group 2 [Grant-White]:
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|)
## visual =~
## x1 1.000
## x2 (.p2.) 0.606 0.101 5.988 0.000
## x3 (.p3.) 0.791 0.109 7.259 0.000
## textual =~
## x4 1.000
## x5 (.p5.) 1.120 0.066 16.960 0.000
## x6 (.p6.) 0.932 0.056 16.606 0.000
## speed =~
## x7 1.000
## x8 (.p8.) 1.200 0.155 7.741 0.000
## x9 (.p9.) 1.041 0.136 7.635 0.000
##
## Covariances:
## Estimate Std.Err z-value P(>|z|)
## visual ~~
## textual 0.426 0.097 4.412 0.000
## speed 0.312 0.079 3.955 0.000
## textual ~~
## speed 0.223 0.071 3.163 0.002
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|)
## .x1 (.25.) 4.914 0.092 53.538 0.000
## .x2 (.26.) 6.087 0.079 76.999 0.000
## .x3 1.955 0.108 18.170 0.000
## .x4 (.28.) 2.778 0.087 31.953 0.000
## .x5 (.29.) 4.035 0.096 41.861 0.000
## .x6 (.30.) 1.926 0.079 24.425 0.000
## .x7 3.992 0.094 42.478 0.000
## .x8 (.32.) 5.569 0.074 75.328 0.000
## .x9 (.33.) 5.409 0.070 77.182 0.000
## visual 0.051 0.129 0.393 0.695
## textual 0.576 0.117 4.918 0.000
## speed -0.071 0.089 -0.800 0.424
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .x1 0.651 0.127 5.138 0.000
## .x2 0.939 0.122 7.721 0.000
## .x3 0.603 0.096 6.248 0.000
## .x4 0.343 0.062 5.532 0.000
## .x5 0.377 0.073 5.136 0.000
## .x6 0.437 0.067 6.556 0.000
## .x7 0.599 0.090 6.655 0.000
## .x8 0.407 0.089 4.570 0.000
## .x9 0.531 0.086 6.186 0.000
## visual 0.715 0.160 4.473 0.000
## textual 0.870 0.131 6.659 0.000
## speed 0.475 0.109 4.344 0.000
El modelo escalar parcial converge adecuadamente tras 61 iteraciones, estimando 63 parámetros con 13 restricciones de igualdad. En comparación con el modelo model_scalar_cp, se observa una mejora clara en el ajuste global, reflejada en:
χ²(58) = 129.42, p < 0.001.
CFI = 0.919 y TLI = 0.900, valores superiores a los obtenidos en el modelo anterior.
RMSEA = 0.090 (IC 90%: 0.070–0.111), indicando un ajuste moderado pero aceptable.
SRMR = 0.073, dentro de rangos adecuados.
Las cargas factoriales permanecen invariantes entre grupos, confirmando la invarianza métrica, mientras que las diferencias de nivel entre grupos se concentran únicamente en los interceptos de x3 y x7.
anova()La salida es:
##
## Chi-Squared Difference Test
##
## Df AIC BIC Chisq Chisq diff RMSEA Df diff Pr(>Chisq)
## model_metric 54 7480.6 7680.8 124.04
## model_scalar_cp 58 7478.0 7663.3 129.42 5.3789 0.04786 4 0.2506
Reuniendo los resultados de los anovas anteriores:
Chi-Squared Difference Test
Model (versus) Df AIC BIC Chisq Chisq diff RMSEA Df diff Pr(>Chisq)
M1: configural 48 7484.4 7706.8 115.85
M2: metric (M1) 54 7480.6 7680.8 124.04 8.1922 0.049272 6 0.2244
M3a: scalar_a (M2) 60 7508.6 7686.6 164.10 40.0590 0.19421 6 4.435e-07 ***
M3b: scalar_bp (M2) 59 7491.1 7672.8 144.58 20.5350 0.143680 5 0.0009912 ***
M3c: scalar_cp (M2) 58 7478.0 7663.3 129.42 5.3789 0.04786 4 0.2506
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Interpretación breve.
El test de diferencia χ² entre el modelo métrico y el modelo escalar parcial M3c (model_scalar_cp) no resulta significativo (Δχ² = 5.38, Δgl = 4, p-valor = 0.251).
Esto indica que, al liberar los interceptos de x3 y x7, el modelo escalar parcial no presenta un deterioro significativo del ajuste respecto al modelo métrico.
El modelo M3b (model_scalar_bp) se utilizó como paso intermedio para identificar interceptos no invariantes mediante pruebas score. La inferencia final sobre la invarianza escalar se realizó comparando el modelo métrico con el modelo escalar parcial final M3c (model_scalar_cp), el cual no mostró un deterioro significativo del ajuste. En consecuencia, M3c se adopta como el modelo definitivo para los análisis posteriores.
A continuación se calculan los score tests con EPCs y se utiliza get_group_partial() con el objetivo de verificar si persisten violaciones locales a la invarianza escalar. La salida es:
## $group_partial
## character(0)
##
## $target_used
## [1] "intercepts"
##
## $uni_tbl
## [1] lhs op rhs X2 df p.value
## <0 rows> (or 0-length row.names)
##
## $top_rows
## [1] lhs op rhs X2 df p.value
## <0 rows> (or 0-length row.names)
##
## $labels_to_free
## character(0)
##
## $mapped
## data frame with 0 columns and 0 rows
##
## $mapped_filtered
## data frame with 0 columns and 0 rows
##
## $note
## [1] "No equality constraints above x2_cut."
## character(0)
Interpretación breve.
La aplicación de lavTestScore() y get_group_partial() no identifica restricciones adicionales candidatas a ser liberadas (group_partial = character(0)), lo que indica la ausencia de violaciones locales relevantes a la invarianza escalar bajo el umbral definido.
El modelo model_scalar_cp puede considerarse el modelo final de invarianza escalar parcial, ya que alcanza un equilibrio adecuado entre parsimonia, ajuste global y consistencia estadística, sin evidencia que justifique la liberación de interceptos adicionales.
Aceptar invarianza escalar parcial implica que:
La mayoría de los interceptos son equivalentes entre grupos.
La comparación de medias latentes puede realizarse de forma defendible, siempre que el modelo esté correctamente identificado (por ejemplo, manteniendo al menos dos interceptos invariantes por factor).
En este ejemplo, la evidencia empírica sugiere que la no invarianza se concentra en interceptos específicos (x3 y x7), mientras que el resto del modelo mantiene suficiente estabilidad para permitir inferencias comparativas válidas sobre las medias latentes.
Una vez establecida la invarianza escalar (completa o parcial), se habilita el análisis de medias latentes y, posteriormente, la evaluación de restricciones en parámetros estructurales dentro de un modelo de ecuaciones estructurales (SEM) multigrupo.
En la siguiente sección se puede:
Fijar una media latente de referencia (por ejemplo, 0 en un grupo).
Estimar la diferencia de medias latentes en el otro grupo.
Extender el análisis hacia restricciones estructurales (por ejemplo, igualdad de regresiones, covarianzas o varianzas latentes).
Una vez establecida la invarianza escalar (completa o parcial), es posible comparar las medias de los factores latentes entre grupos. A diferencia de las medias observadas, las medias latentes:
En SEM multigrupo, esta escala se define fijando la media latente en uno de los grupos, usualmente a cero.
Por defecto, en modelos SEM multigrupo, lavaan fija las medias latentes del primer grupo en cero con fines de identificación. En este ejemplo:
Grupo de referencia (grupo 1, g1): Pasteur
Grupo comparado (grupo 2, g2): Grant-White
Como consecuencia de esta restricción de identificación, las medias latentes estimadas para el segundo grupo se interpretan como diferencias de medias latentes respecto al grupo de referencia:
\[ \mu_{g1} = 0 \quad \Rightarrow \quad \hat{\mu}_{g2} = \mu_{g2} - \mu_{g1} = \mu_{g2} \]
Un valor significativo de \(\hat{\mu}_{g2}\) indica que la media latente del grupo comparado es estadísticamente diferente de la del grupo de referencia. Dado que \(\mu_{g1}\) se fija en cero por identificación, el parámetro \(\hat{\mu}_{g2}\) se interpreta directamente como una diferencia de medias latentes entre grupos.
Por ejemplo, si para un factor latente se obtiene \(\hat{\mu}_{g2} = 0.60\) con \(p < 0.05\), esto implica que el grupo \(g2\) presenta una media latente 0.60 unidades mayor que el grupo de referencia. De manera análoga, un valor negativo indica una media latente menor en el grupo comparado.
Cabe destacar que la comparación de medias latentes no se realiza mediante medias observadas, sino a través de parámetros estimados del modelo, cuya interpretación depende directamente de las restricciones de identificación impuestas.
En SEM multigrupo:
La media latente del grupo de referencia se fija en \(0\).
La media latente del otro grupo se estima libremente.
Este valor estimado, \(\hat{\mu}_{g2}\), no es una media absoluta, sino una diferencia de medias latentes respecto al grupo de referencia.
Por tanto:
Si \(\hat{\mu}_{g2} = 0\), no existe diferencia en la media latente entre grupos.
Si \(\hat{\mu}_{g2} \neq 0\), sí existe diferencia en la media latente entre grupos.
Comentario.
Para comprender la comparación de medias latentes en SEM multigrupo, resulta útil pensar en una línea de referencia, donde la media latente del grupo de referencia se fija en cero por razones de identificación:
\[ \underbrace{0}_{\text{Referencia (g1)}} \quad \longrightarrow\quad \underbrace{\hat{\mu}_{\text{g2}}}_{\text{Diferencia latente}} \]
Nota pedagógica final.
En SEM multigrupo, no se comparan medias observadas, sino parámetros latentes del modelo. Por ello, la interpretación de las medias latentes depende directamente del grupo elegido como referencia y de las restricciones de identificación impuestas.
En modelos SEM multigrupo, la identificación del modelo se logra fijando las medias latentes del grupo de referencia en cero. Por defecto, lavaan utiliza el primer grupo como referencia. No obstante, es posible cambiar explícitamente el grupo de referencia para facilitar la interpretación de las diferencias de medias latentes.
La forma más sencilla y transparente de cambiar el grupo de referencia consiste en reordenar los niveles de la variable que define los grupos antes de ajustar el modelo.
# Ver niveles actuales
levels(HolzingerSwineford1939$school)
# Cambiar el grupo de referencia
HolzingerSwineford1939$school <- relevel(HolzingerSwineford1939$school, ref = "Grant-White")
# Verificar nuevo orden
levels(HolzingerSwineford1939$school)
A partir de este momento:
Grant-White será el grupo de referencia (medias latentes = 0).
Las medias latentes estimadas corresponderán ahora a diferencias respecto a Grant-White.
Una vez redefinido el grupo de referencia, se reestima el modelo de medición manteniendo las mismas restricciones de invarianza escalar parcial.
model_latent_means_ref2 <- cfa(HS.model, data = HolzingerSwineford1939,
group = "school",
group.equal = c("loadings", "intercepts"),
group.partial = c("x3~1", "x7~1"),
meanstructure = TRUE
)
summary(model_latent_means_ref2, fit.measures = TRUE)
Al cambiar el grupo de referencia:
Los signos de las medias latentes pueden invertirse.
La magnitud y significancia permanecen iguales.
La comparación se expresa ahora como:
\[ \mu_{\text{Pasteur}} - \mu_{\text{Grant-White}} \]
Esto permite evaluar explícitamente las diferencias desde la perspectiva del grupo que se desee utilizar como referencia.
Cambiar el grupo de referencia no altera el ajuste del modelo ni las conclusiones sustantivas, pero sí facilita la interpretación de los resultados en contextos docentes o aplicados, especialmente cuando se desea enfatizar un grupo específico.
El grupo de referencia fija sus medias latentes en cero.
Las medias latentes estimadas en los demás grupos representan diferencias respecto a ese grupo.
El grupo de referencia puede cambiarse reordenando los niveles del factor de agrupación.
La comparación de medias latentes se formaliza mediante la siguiente prueba de hipótesis (g1 = referencia, g2 = comparación):
\[ H_0:\ \mu_{\text{grupo }2} - \mu_{\text{grupo }1} = 0 \quad \text{versus} \quad H_1:\ \mu_{\text{grupo }2} - \mu_{\text{grupo }1} \neq 0 \]
En lavaan, esta prueba se implementa mediante un estadístico Wald tipo \(Z\), el cual se reporta en el summary() del modelo (bajo la sección
Intercepts para los factores latentes del grupo no de referencia).
Interpretación estadística
Un valor positivo de \(\hat{\mu}_{g2}\) y estadísticamente significativo (p-valor<0.05) indica que el grupo comparado (g2) presenta una media latente mayor que el grupo de referencia (g1).
Un valor negativo de \(\hat{\mu}_{g2}\) y estadísticamente significativo (p-valor<0.05) indica que el grupo comparado (g2) presenta una media latente menor que el grupo de referencia (g1).
Un valor no significativo de \(\hat{\mu}_{g2}\) (aproximadamente igual a cero, p-valor > 0.05) indica ausencia de diferencias latentes estadísticamente detectables entre los grupos.
Antes de estimar las medias latentes, es importante verificar que el grupo de referencia corresponda al definido por defecto en lavaan. En caso de haber modificado previamente el orden de los grupos, se restablece a continuación el grupo de referencia original.
# Ver niveles actuales de la variable de grupo
levels(HolzingerSwineford1939$school)
# Restablecer el grupo de referencia por defecto (Pasteur)
HolzingerSwineford1939$school <- relevel(HolzingerSwineford1939$school, ref = "Pasteur")
# Verificar el nuevo orden de los grupos
levels(HolzingerSwineford1939$school)
Una vez definido correctamente el grupo de referencia, se estima el modelo incluyendo explícitamente la estructura de medias latentes, lo cual se logra mediante el argumento meanstructure = TRUE:
model_latent_means <- cfa(HS.model, data = HolzingerSwineford1939,
group = "school",
group.equal = c("loadings", "intercepts"),
group.partial = c("x3~1", "x7~1"),
meanstructure = TRUE
)
summary(model_latent_means, fit.measures = TRUE)
## lavaan 0.6-19 ended normally after 61 iterations
##
## Estimator ML
## Optimization method NLMINB
## Number of model parameters 63
## Number of equality constraints 13
##
## Number of observations per group:
## Pasteur 156
## Grant-White 145
##
## Model Test User Model:
##
## Test statistic 129.422
## Degrees of freedom 58
## P-value (Chi-square) 0.000
## Test statistic for each group:
## Pasteur 71.170
## Grant-White 58.253
##
## Model Test Baseline Model:
##
## Test statistic 957.769
## Degrees of freedom 72
## P-value 0.000
##
## User Model versus Baseline Model:
##
## Comparative Fit Index (CFI) 0.919
## Tucker-Lewis Index (TLI) 0.900
##
## Loglikelihood and Information Criteria:
##
## Loglikelihood user model (H0) -3688.983
## Loglikelihood unrestricted model (H1) -3624.272
##
## Akaike (AIC) 7477.966
## Bayesian (BIC) 7663.322
## Sample-size adjusted Bayesian (SABIC) 7504.750
##
## Root Mean Square Error of Approximation:
##
## RMSEA 0.090
## 90 Percent confidence interval - lower 0.070
## 90 Percent confidence interval - upper 0.111
## P-value H_0: RMSEA <= 0.050 0.001
## P-value H_0: RMSEA >= 0.080 0.805
##
## Standardized Root Mean Square Residual:
##
## SRMR 0.073
##
## Parameter Estimates:
##
## Standard errors Standard
## Information Expected
## Information saturated (h1) model Structured
##
##
## Group 1 [Pasteur]:
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|)
## visual =~
## x1 1.000
## x2 (.p2.) 0.606 0.101 5.988 0.000
## x3 (.p3.) 0.791 0.109 7.259 0.000
## textual =~
## x4 1.000
## x5 (.p5.) 1.120 0.066 16.960 0.000
## x6 (.p6.) 0.932 0.056 16.606 0.000
## speed =~
## x7 1.000
## x8 (.p8.) 1.200 0.155 7.741 0.000
## x9 (.p9.) 1.041 0.136 7.635 0.000
##
## Covariances:
## Estimate Std.Err z-value P(>|z|)
## visual ~~
## textual 0.404 0.095 4.247 0.000
## speed 0.168 0.064 2.647 0.008
## textual ~~
## speed 0.172 0.060 2.882 0.004
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|)
## .x1 (.25.) 4.914 0.092 53.538 0.000
## .x2 (.26.) 6.087 0.079 76.999 0.000
## .x3 2.487 0.094 26.474 0.000
## .x4 (.28.) 2.778 0.087 31.953 0.000
## .x5 (.29.) 4.035 0.096 41.861 0.000
## .x6 (.30.) 1.926 0.079 24.425 0.000
## .x7 4.432 0.086 51.533 0.000
## .x8 (.32.) 5.569 0.074 75.328 0.000
## .x9 (.33.) 5.409 0.070 77.182 0.000
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .x1 0.560 0.137 4.086 0.000
## .x2 1.267 0.156 8.105 0.000
## .x3 0.879 0.128 6.850 0.000
## .x4 0.446 0.069 6.432 0.000
## .x5 0.502 0.082 6.132 0.000
## .x6 0.263 0.050 5.258 0.000
## .x7 0.850 0.114 7.471 0.000
## .x8 0.516 0.095 5.429 0.000
## .x9 0.656 0.096 6.852 0.000
## visual 0.796 0.170 4.691 0.000
## textual 0.879 0.131 6.693 0.000
## speed 0.304 0.078 3.918 0.000
##
##
## Group 2 [Grant-White]:
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|)
## visual =~
## x1 1.000
## x2 (.p2.) 0.606 0.101 5.988 0.000
## x3 (.p3.) 0.791 0.109 7.259 0.000
## textual =~
## x4 1.000
## x5 (.p5.) 1.120 0.066 16.960 0.000
## x6 (.p6.) 0.932 0.056 16.606 0.000
## speed =~
## x7 1.000
## x8 (.p8.) 1.200 0.155 7.741 0.000
## x9 (.p9.) 1.041 0.136 7.635 0.000
##
## Covariances:
## Estimate Std.Err z-value P(>|z|)
## visual ~~
## textual 0.426 0.097 4.412 0.000
## speed 0.312 0.079 3.955 0.000
## textual ~~
## speed 0.223 0.071 3.163 0.002
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|)
## .x1 (.25.) 4.914 0.092 53.538 0.000
## .x2 (.26.) 6.087 0.079 76.999 0.000
## .x3 1.955 0.108 18.170 0.000
## .x4 (.28.) 2.778 0.087 31.953 0.000
## .x5 (.29.) 4.035 0.096 41.861 0.000
## .x6 (.30.) 1.926 0.079 24.425 0.000
## .x7 3.992 0.094 42.478 0.000
## .x8 (.32.) 5.569 0.074 75.328 0.000
## .x9 (.33.) 5.409 0.070 77.182 0.000
## visual 0.051 0.129 0.393 0.695
## textual 0.576 0.117 4.918 0.000
## speed -0.071 0.089 -0.800 0.424
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .x1 0.651 0.127 5.138 0.000
## .x2 0.939 0.122 7.721 0.000
## .x3 0.603 0.096 6.248 0.000
## .x4 0.343 0.062 5.532 0.000
## .x5 0.377 0.073 5.136 0.000
## .x6 0.437 0.067 6.556 0.000
## .x7 0.599 0.090 6.655 0.000
## .x8 0.407 0.089 4.570 0.000
## .x9 0.531 0.086 6.186 0.000
## visual 0.715 0.160 4.473 0.000
## textual 0.870 0.131 6.659 0.000
## speed 0.475 0.109 4.344 0.000
Nota técnica.
En lavaan, la función cfa() incluye por defecto la estructura de medias (meanstructure = TRUE). Por esta razón, especificar explícitamente este argumento no altera los resultados del modelo. Las medias latentes se estiman automáticamente y aparecen en el summary() bajo la sección Intercepts para los factores latentes del grupo que no es de referencia (grupo 2).
La comparación de medias latentes en SEM multigrupo depende de la correcta identificación del modelo y de la invarianza escalar, no de la inclusión explícita del argumento meanstructure cuando se utiliza cfa().
summary()?En la salida del summary(), las medias latentes aparecen bajo el encabezado Intercepts (asociadas directamente a los factores latentes) y solo para el grupo que no es de referencia (Group 2 = Grand-White):
Group 2 [Grand-White]:
Intercepts:
Estimate Std.Error z-value P(>|z|)
. . . . .
. . . . .
visual 0.051 0.129 0.393 0.695
textual 0.576 0.117 4.918 0.000
speed -0.071 0.089 -0.800 0.424
Cada valor corresponde a una diferencia de media latente respecto al grupo de referencia (Pasteur).
Para facilitar la interpretación pedagógica, las medias latentes pueden extraerse directamente desde el objeto lavaan.
# Extraer parámetros estimados
param <- parameterEstimates(model_latent_means)
# Filtrar medias latentes (factores latentes, operador ~1)
latent_means <- param %>% dplyr::filter(op == "~1", lhs %in% c("visual", "textual", "speed"))
latent_means
La idea es sencilla:
parameterEstimates() devuelve todos los parámetros estimados del modelo (cargas, interceptos, varianzas, covarianzas, medias latentes, etc.).
En SEM, el operador ~1 representa un intercepto.
Si lhs es una variable observada (p. ej., x1), x1 ~1 es el intercepto de x1.
Si lhs es un factor latente (p. ej., visual), visual ~1 es la media latente del factor.
Filtramos solo las filas donde op == "~1" y lhs corresponde a los factores latentes de interés (visual, textual, speed).
La salida correspondiente a las medias latentes estimadas es la siguiente:
## lhs op rhs block group label est se z pvalue ci.lower ci.upper
## 1 visual ~1 1 1 0.000 0.000 NA NA 0.000 0.000
## 2 textual ~1 1 1 0.000 0.000 NA NA 0.000 0.000
## 3 speed ~1 1 1 0.000 0.000 NA NA 0.000 0.000
## 4 visual ~1 2 2 0.051 0.129 0.393 0.695 -0.203 0.304
## 5 textual ~1 2 2 0.576 0.117 4.918 0.000 0.347 0.806
## 6 speed ~1 2 2 -0.071 0.089 -0.800 0.424 -0.246 0.104
A continuación, la misma información se presenta en una tabla resumen, lo que facilita su interpretación:
latent_means %>%
dplyr::select(lhs, group, est, se, z, pvalue) %>%
dplyr::rename(Factor = lhs,
Grupo = group,
Media_latente = est,
Error_Est = se,
z_value = z,
p_value = pvalue
) %>%
kable(align = "ccccc",
caption = "Diferencias de medias latentes respecto al grupo de referencia 1. Aquí: g1=Pasteur, g2=Grand-White") %>%
kable_styling(full_width = FALSE)
| Factor | Grupo | Media_latente | Error_Est | z_value | p_value |
|---|---|---|---|---|---|
| visual | 1 | 0.0000000 | 0.0000000 | NA | NA |
| textual | 1 | 0.0000000 | 0.0000000 | NA | NA |
| speed | 1 | 0.0000000 | 0.0000000 | NA | NA |
| visual | 2 | 0.0508172 | 0.1294233 | 0.3926429 | 0.6945832 |
| textual | 2 | 0.5763200 | 0.1171844 | 4.9180611 | 0.0000009 |
| speed | 2 | -0.0714642 | 0.0892939 | -0.8003259 | 0.4235220 |
La tabla resultante incluye (entre otras columnas) la siguiente información:
lhs: parámetro del lado izquierdo; en este contexto, corresponde al factor latente cuya media se está evaluando.
group: grupo al que corresponde el parámetro (g1 = grupo de referencia, g2 = grupo comparado).
est: estimación de la media latente del factor.
se: error estándar asociado a la estimación.
z y pvalue: estadístico y valor p de la prueba Wald para la hipótesis nula \(H_0:\ \mu_{\text{g2}} - \mu_{\text{g1}} = 0\).
ci.lower, ci.upper: límites inferior y superior del intervalo de confianza para la estimación de la media latente.
est=0.00 y con se = 0.00 porque están fijadas a cero por identificación. Por esta razón, los estadísticos z y pvalue toman el valor NA: no se realiza una prueba estadística, ya que el parámetro no fue estimado, sino impuesto por el modelo.Grupo 2 (Grant-White, comparado). La hipóstesis nula es \(H_0:\ \mu_{\text{g2}} - \mu_{\text{g1}} = 0\). Además, las medias latentes estimadas para este grupo se interpretan como diferencias respecto al grupo de referencia:
visual: \(\hat{\mu}_{\text{g2}} = 0.051 > 0\), valor \(p = 0.695\). Por lo tanto, no hay evidencia de una diferencia latente estadísticamente significativa en el factor visual.
textual: \(\hat{\mu}_{\text{g2}} = 0.576 > 0\), valor \(p < 0.001\). Con este resultado, el grupo Grant-White presenta una media latente significativamente mayor que el grupo Pasteur en el factor textual.
speed: \(\hat{\mu}_{\text{g2}} = -0.071\), valor \(p = 0.424\). Con ello, concluimos que no hay evidencia de una diferencia latente estadísticamente significativa en el factor speed.
Además, los intervalos de confianza confirman estas conclusiones:
Para textual, el IC \(=[0.347, 0.806]\) del 95% para \(\mu_{\text{g2}} - \mu_{\text{g1}}\) no incluye el valor 0. Esto respalda la existencia de una diferencia latente significativa.
Para visual y speed, los intervalos de confianza incluyen el valor 0, indicando ausencia de diferencias latentes estadísticamente detectables.
Una vez establecida la invarianza de medida (al menos hasta el nivel métrico o escalar, completa o parcial), es posible evaluar la invarianza estructural.
En términos prácticos, esto implica imponer (o contrastar) restricciones de igualdad entre grupos sobre parámetros del nivel latente, tales como:
Varianzas de los factores latentes (dispersión de los constructos).
Covarianzas (o correlaciones) entre factores latentes (asociación entre constructos).
Coeficientes estructurales (regresiones entre factores o hacia variables dependientes), cuando se especifica un modelo SEM.
En esta sección se ilustra el caso más habitual: la invarianza de varianzas y covarianzas latentes, partiendo de un modelo escalar parcial previamente aceptado (aquí: model_scalar_cp).
Nota conceptual.
Restringir lv.variances evalúa si la variabilidad del constructo es comparable entre grupos.
Restringir lv.covariances evalúa si la relación entre constructos mantiene la misma magnitud entre grupos.
En esta etapa se evalúa la invarianza estructural a nivel latente, partiendo de un modelo que ya alcanzó invarianza escalar parcial. En particular, se mantiene la igualdad de cargas factoriales e interceptos entre grupos, permitiendo que dos interceptos varíen entre escuelas (x3~1 y x7~1). Posteriormente, se imponen restricciones adicionales sobre la estructura latente, evaluando la igualdad de varianzas y covarianzas de los factores.
El procedimiento es análogo al aplicado en los niveles previos de invarianza:
Ajustar el modelo multigrupo imponiendo igualdad de cargas, interceptos (con liberación parcial) y restricciones sobre varianzas y covarianzas latentes.
Revisar el resumen del modelo (summary()), verificando convergencia e índices de ajuste global (CFI, TLI, RMSEA, SRMR).
Comparar el modelo estructural con el modelo escalar parcial final (model_scalar_cp) mediante un test χ² de diferencia (anova()), dado que se trata de modelos anidados.
Aplicar score tests (lavTestScore) para detectar posibles violaciones locales asociadas a restricciones específicas y evaluar si conviene liberar algún parámetro adicional.
A continuación se ajusta un modelo multigrupo imponiendo:
Igualdad de cargas (loadings).
Igualdad de interceptos (intercepts) con invarianza escalar parcial (liberando x3~1 y x7~1).
Igualdad de varianzas residuales (residuals).
Igualdad de varianzas latentes (lv.variances).
Igualdad de covarianzas latentes (lv.covariances).
# 1. Ajustar el modelo
model_structur_a <- cfa(HS.model, data = HolzingerSwineford1939,
group = "school",
group.equal = c("loadings",
"intercepts",
"residuals",
"lv.variances",
"lv.covariances"
),
group.partial = c("x3~1", "x7~1")
)
# 2. Resumen del modelo
summary(model_structur_a, fit.measures = TRUE)
# 3. Comparación de modelos anidados
anova(model_scalar_cp, model_structur_a)
# 4. Prueba score (verificación local)
score_obj <- lavTestScore(model_structur_a, epc = TRUE)
# 4b. Solo válido segunda forma
group <- get_group_partial_target(
fit = model_structur_a,
score_obj = score_obj,
x2_cut = 5,
top_n = 1,
target="loadings"
)
group
group$group_partial
summary()La salida es:
## lavaan 0.6-19 ended normally after 59 iterations
##
## Estimator ML
## Optimization method NLMINB
## Number of model parameters 63
## Number of equality constraints 28
##
## Number of observations per group:
## Pasteur 156
## Grant-White 145
##
## Model Test User Model:
##
## Test statistic 153.258
## Degrees of freedom 73
## P-value (Chi-square) 0.000
## Test statistic for each group:
## Pasteur 81.641
## Grant-White 71.617
##
## Model Test Baseline Model:
##
## Test statistic 957.769
## Degrees of freedom 72
## P-value 0.000
##
## User Model versus Baseline Model:
##
## Comparative Fit Index (CFI) 0.909
## Tucker-Lewis Index (TLI) 0.911
##
## Loglikelihood and Information Criteria:
##
## Loglikelihood user model (H0) -3700.901
## Loglikelihood unrestricted model (H1) -3624.272
##
## Akaike (AIC) 7471.802
## Bayesian (BIC) 7601.551
## Sample-size adjusted Bayesian (SABIC) 7490.551
##
## Root Mean Square Error of Approximation:
##
## RMSEA 0.085
## 90 Percent confidence interval - lower 0.066
## 90 Percent confidence interval - upper 0.104
## P-value H_0: RMSEA <= 0.050 0.002
## P-value H_0: RMSEA >= 0.080 0.696
##
## Standardized Root Mean Square Residual:
##
## SRMR 0.086
##
## Parameter Estimates:
##
## Standard errors Standard
## Information Expected
## Information saturated (h1) model Structured
##
##
## Group 1 [Pasteur]:
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|)
## visual =~
## x1 1.000
## x2 (.p2.) 0.599 0.102 5.847 0.000
## x3 (.p3.) 0.789 0.111 7.079 0.000
## textual =~
## x4 1.000
## x5 (.p5.) 1.124 0.066 17.112 0.000
## x6 (.p6.) 0.935 0.056 16.768 0.000
## speed =~
## x7 1.000
## x8 (.p8.) 1.186 0.162 7.303 0.000
## x9 (.p9.) 1.066 0.146 7.280 0.000
##
## Covariances:
## Estimate Std.Err z-value P(>|z|)
## visual ~~
## textual (.22.) 0.403 0.070 5.751 0.000
## speed (.23.) 0.244 0.054 4.528 0.000
## textual ~~
## speed (.24.) 0.196 0.048 4.049 0.000
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|)
## .x1 (.25.) 4.912 0.092 53.595 0.000
## .x2 (.26.) 6.074 0.077 78.473 0.000
## .x3 2.487 0.088 28.188 0.000
## .x4 (.28.) 2.784 0.086 32.312 0.000
## .x5 (.29.) 4.029 0.096 41.986 0.000
## .x6 (.30.) 1.927 0.081 23.820 0.000
## .x7 4.432 0.085 52.360 0.000
## .x8 (.32.) 5.568 0.077 72.219 0.000
## .x9 (.33.) 5.411 0.074 73.380 0.000
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .x1 (.10.) 0.603 0.105 5.732 0.000
## .x2 (.11.) 1.111 0.101 11.020 0.000
## .x3 (.12.) 0.745 0.086 8.701 0.000
## .x4 (.13.) 0.383 0.047 8.095 0.000
## .x5 (.14.) 0.438 0.057 7.650 0.000
## .x6 (.15.) 0.352 0.042 8.305 0.000
## .x7 (.16.) 0.735 0.076 9.625 0.000
## .x8 (.17.) 0.482 0.073 6.574 0.000
## .x9 (.18.) 0.579 0.070 8.300 0.000
## visual (.19.) 0.754 0.136 5.548 0.000
## textual (.20.) 0.885 0.103 8.621 0.000
## speed (.21.) 0.383 0.083 4.587 0.000
##
##
## Group 2 [Grant-White]:
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|)
## visual =~
## x1 1.000
## x2 (.p2.) 0.599 0.102 5.847 0.000
## x3 (.p3.) 0.789 0.111 7.079 0.000
## textual =~
## x4 1.000
## x5 (.p5.) 1.124 0.066 17.112 0.000
## x6 (.p6.) 0.935 0.056 16.768 0.000
## speed =~
## x7 1.000
## x8 (.p8.) 1.186 0.162 7.303 0.000
## x9 (.p9.) 1.066 0.146 7.280 0.000
##
## Covariances:
## Estimate Std.Err z-value P(>|z|)
## visual ~~
## textual (.22.) 0.403 0.070 5.751 0.000
## speed (.23.) 0.244 0.054 4.528 0.000
## textual ~~
## speed (.24.) 0.196 0.048 4.049 0.000
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|)
## .x1 (.25.) 4.912 0.092 53.595 0.000
## .x2 (.26.) 6.074 0.077 78.473 0.000
## .x3 1.957 0.111 17.606 0.000
## .x4 (.28.) 2.784 0.086 32.312 0.000
## .x5 (.29.) 4.029 0.096 41.986 0.000
## .x6 (.30.) 1.927 0.081 23.820 0.000
## .x7 3.993 0.102 39.290 0.000
## .x8 (.32.) 5.568 0.077 72.219 0.000
## .x9 (.33.) 5.411 0.074 73.380 0.000
## visual 0.049 0.129 0.381 0.703
## textual 0.575 0.118 4.885 0.000
## speed -0.072 0.089 -0.809 0.418
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .x1 (.10.) 0.603 0.105 5.732 0.000
## .x2 (.11.) 1.111 0.101 11.020 0.000
## .x3 (.12.) 0.745 0.086 8.701 0.000
## .x4 (.13.) 0.383 0.047 8.095 0.000
## .x5 (.14.) 0.438 0.057 7.650 0.000
## .x6 (.15.) 0.352 0.042 8.305 0.000
## .x7 (.16.) 0.735 0.076 9.625 0.000
## .x8 (.17.) 0.482 0.073 6.574 0.000
## .x9 (.18.) 0.579 0.070 8.300 0.000
## visual (.19.) 0.754 0.136 5.548 0.000
## textual (.20.) 0.885 0.103 8.621 0.000
## speed (.21.) 0.383 0.083 4.587 0.000
El modelo model_structural_a converge normalmente tras 59 iteraciones, estimando 63 parámetros con 28 restricciones de igualdad. Los índices principales reportados son:
χ²(73) = 153.26, p < 0.001.
CFI = 0.909; TLI = 0.911.
RMSEA = 0.085 (IC 90%: 0.066–0.104).
SRMR = 0.086.
Bajo este modelo, las covarianzas latentes entre visual, textual y speed quedan forzadas a ser iguales en ambos grupos (se observa el mismo valor estimado en cada grupo para .22., .23., .24.), y lo mismo ocurre con las varianzas latentes (.19., .20., .21.).
En otras palabras: además de la invarianza de medida, aquí se está asumiendo que la dispersión de cada factor latente y la asociación entre factores también son comparables entre escuelas.
anova()El contraste relevante es comparar el modelo escalar parcial final (model_scalar_cp) contra el modelo estructural (model_structural_a), ya que se trata de modelos anidados y la diferencia proviene de agregar restricciones sobre la estructura latente. La salida correspondiente es:
##
## Chi-Squared Difference Test
##
## Df AIC BIC Chisq Chisq diff RMSEA Df diff Pr(>Chisq)
## model_scalar_cp 58 7478.0 7663.3 129.42
## model_structur_a 73 7471.8 7601.6 153.26 23.836 0.062562 15 0.06793
##
## model_scalar_cp
## model_structur_a .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Reuniendo los resultados de los anovas anteriores:
Chi-Squared Difference Test
Model (versus) Df AIC BIC Chisq Chisq diff RMSEA Df diff Pr(>Chisq)
M1: configural 48 7484.4 7706.8 115.85
M2: metric (M1) 54 7480.6 7680.8 124.04 8.1922 0.049272 6 0.2244
M3a: scalar_a (M2) 60 7508.6 7686.6 164.10 40.0590 0.19421 6 4.435e-07 ***
M3b: scalar_bp (M2) 59 7491.1 7672.8 144.58 20.5350 0.143680 5 0.0009912 ***
M3c: scalar_cp (M2) 58 7478.0 7663.3 129.42 5.3789 0.04786 4 0.2506
M4a structur_a (M3c) 73 7471.8 7601.6 153.26 23.836 0.062562 15 0.06793 .
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Interpretación breve (con base en la salida obtenida).
El test de diferencia χ² entre model_scalar_cp y model_structur_a es Δχ² = 23.84, Δgl = 15 y p = 0.0679. Dado que el valor p > 0.05, no se observa un deterioro estadísticamente significativo del ajuste al imponer igualdad de varianzas y covarianzas latentes entre grupos.
En consecuencia, la evidencia empírica apoya (al menos de forma razonable) la invarianza estructural de segundo orden para varianzas y covarianzas latentes, condicionada a la invarianza de medida parcial previamente establecida.
Nota pedagógica.
Aunque el valor p = 0.0679 es cercano al umbral convencional de 0.05, en contextos aplicados suele interpretarse como evidencia a favor de la invariancia, especialmente cuando la caída en índices de ajuste incremental (CFI, TLI) no es drástica. En este caso, los resultados sugieren que las restricciones estructurales son defendibles desde el punto de vista estadístico y sustantivo.
lavTestScore)Aunque el ajuste global y el test de diferencia sugieren que las restricciones estructurales son plausibles, es recomendable realizar una verificación local para identificar si alguna restricción específica introduce misfit localizado.
Prueba score (verificación local)
## $group_partial
## textual
## "textual=~x6"
##
## $target_used
## [1] "loadings"
##
## $uni_tbl
## lhs op rhs X2 df p.value
## 1 .p6. == .p42. 5.320106 1 0.02108072
##
## $top_rows
## lhs op rhs X2 df p.value
## 1 .p6. == .p42. 5.320106 1 0.02108072
##
## $labels_to_free
## [1] ".p6." ".p42."
##
## $mapped
## id lhs op rhs group label plabel target_class
## 1 6 textual =~ x6 1 .p6. .p6. loadings
## 2 42 textual =~ x6 2 .p6. .p42. loadings
##
## $mapped_filtered
## id lhs op rhs group label plabel target_class
## 1 6 textual =~ x6 1 .p6. .p6. loadings
## 2 42 textual =~ x6 2 .p6. .p42. loadings
##
## $note
## [1] "Candidates produced for targets: {loadings}."
## textual
## "textual=~x6"
Interpretación breve (con base en la salida)
El procedimiento identifica una restricción candidata para ser liberada bajo el umbral definido:
textual =~ x6Esta sugerencia proviene de un score test univariado con estadístico:
.p6. == .p42. con χ² = 5.32 (valor p = 0.021).El mapeo de parámetros indica que esta restricción corresponde a la carga factorial del ítem x6 en el factor textual, impuesta como igual entre grupos:
Grupo 1: textual =~ x6 (etiqueta .p6.).
Grupo 2: textual =~ x6 (etiqueta .p42.).
En consecuencia, el diagnóstico local sugiere una posible no invarianza métrica localizada en la carga de x6.
Lectura práctica
A nivel global, el modelo con restricciones estructurales no presenta un deterioro significativo del ajuste
(Δχ² = 23.84, Δgl = 15, valor p = 0.0679).
A nivel local, se detecta una señal moderada de tensión asociada a una carga factorial específica (x6), y no a las varianzas o covarianzas latentes.
Dado que el objetivo principal de este bloque es la evaluación de la estructura latente, esta señal puede:
Reportarse como un chequeo diagnóstico adicional (sin necesidad de modificar el modelo), o
Explorarse mediante un refinamiento opcional del modelo.
x6 para afinar el modeloCon fines ilustrativos, puede considerarse un paso adicional análogo al realizado en la invarianza escalar parcial. En este modelo alternativo se mantiene la invarianza estructural (varianzas y covarianzas latentes iguales entre grupos), pero se libera la restricción de igualdad en la carga factorial textual =~ x6, identificada previamente mediante score tests.
Este refinamiento permite evaluar si una relajación puntual de la invarianza métrica mejora el ajuste del modelo, sin comprometer la comparabilidad de la estructura latente global.
El argumento group.partial permite liberar restricciones específicas utilizando la sintaxis de parámetros de lavaan.
Para cargas factoriales, la sintaxis general es: factor =~ indicador.
En este caso, se libera la carga textual =~ x6, manteniendo las demás restricciones estructurales.
model_structur_bp <- cfa(HS.model, data = HolzingerSwineford1939,
group = "school",
group.equal = c("loadings",
"intercepts",
"residuals",
"lv.variances",
"lv.covariances"
),
group.partial = c("x3~1", "x7~1", # interceptos ya liberados (escalar parcial)
"textual=~x6" # liberar la carga sugerida por score test
)
)
summary(model_structur_bp, fit.measures = TRUE)
anova(model_structur_a, model_structur_bp)
La salida de summary() es:
## lavaan 0.6-19 ended normally after 63 iterations
##
## Estimator ML
## Optimization method NLMINB
## Number of model parameters 63
## Number of equality constraints 27
##
## Number of observations per group:
## Pasteur 156
## Grant-White 145
##
## Model Test User Model:
##
## Test statistic 147.866
## Degrees of freedom 72
## P-value (Chi-square) 0.000
## Test statistic for each group:
## Pasteur 78.500
## Grant-White 69.366
##
## Model Test Baseline Model:
##
## Test statistic 957.769
## Degrees of freedom 72
## P-value 0.000
##
## User Model versus Baseline Model:
##
## Comparative Fit Index (CFI) 0.914
## Tucker-Lewis Index (TLI) 0.914
##
## Loglikelihood and Information Criteria:
##
## Loglikelihood user model (H0) -3698.205
## Loglikelihood unrestricted model (H1) -3624.272
##
## Akaike (AIC) 7468.409
## Bayesian (BIC) 7601.865
## Sample-size adjusted Bayesian (SABIC) 7487.694
##
## Root Mean Square Error of Approximation:
##
## RMSEA 0.084
## 90 Percent confidence interval - lower 0.064
## 90 Percent confidence interval - upper 0.103
## P-value H_0: RMSEA <= 0.050 0.003
## P-value H_0: RMSEA >= 0.080 0.639
##
## Standardized Root Mean Square Residual:
##
## SRMR 0.085
##
## Parameter Estimates:
##
## Standard errors Standard
## Information Expected
## Information saturated (h1) model Structured
##
##
## Group 1 [Pasteur]:
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|)
## visual =~
## x1 1.000
## x2 (.p2.) 0.597 0.102 5.835 0.000
## x3 (.p3.) 0.785 0.111 7.067 0.000
## textual =~
## x4 1.000
## x5 (.p5.) 1.124 0.065 17.165 0.000
## x6 0.837 0.068 12.255 0.000
## speed =~
## x7 1.000
## x8 (.p8.) 1.187 0.163 7.300 0.000
## x9 (.p9.) 1.065 0.146 7.279 0.000
##
## Covariances:
## Estimate Std.Err z-value P(>|z|)
## visual ~~
## textual (.22.) 0.403 0.070 5.740 0.000
## speed (.23.) 0.244 0.054 4.527 0.000
## textual ~~
## speed (.24.) 0.194 0.048 4.009 0.000
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|)
## .x1 (.25.) 4.915 0.092 53.705 0.000
## .x2 (.26.) 6.076 0.077 78.634 0.000
## .x3 2.489 0.088 28.246 0.000
## .x4 (.28.) 2.800 0.084 33.470 0.000
## .x5 (.29.) 4.047 0.093 43.457 0.000
## .x6 (.30.) 1.915 0.078 24.696 0.000
## .x7 4.434 0.085 52.401 0.000
## .x8 (.32.) 5.570 0.077 72.264 0.000
## .x9 (.33.) 5.412 0.074 73.492 0.000
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .x1 (.10.) 0.600 0.106 5.683 0.000
## .x2 (.11.) 1.112 0.101 11.028 0.000
## .x3 (.12.) 0.747 0.086 8.722 0.000
## .x4 (.13.) 0.382 0.047 8.114 0.000
## .x5 (.14.) 0.437 0.057 7.676 0.000
## .x6 (.15.) 0.341 0.041 8.259 0.000
## .x7 (.16.) 0.735 0.076 9.622 0.000
## .x8 (.17.) 0.481 0.074 6.543 0.000
## .x9 (.18.) 0.580 0.070 8.316 0.000
## visual (.19.) 0.758 0.136 5.553 0.000
## textual (.20.) 0.892 0.103 8.639 0.000
## speed (.21.) 0.383 0.083 4.587 0.000
##
##
## Group 2 [Grant-White]:
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|)
## visual =~
## x1 1.000
## x2 (.p2.) 0.597 0.102 5.835 0.000
## x3 (.p3.) 0.785 0.111 7.067 0.000
## textual =~
## x4 1.000
## x5 (.p5.) 1.124 0.065 17.165 0.000
## x6 1.033 0.071 14.640 0.000
## speed =~
## x7 1.000
## x8 (.p8.) 1.187 0.163 7.300 0.000
## x9 (.p9.) 1.065 0.146 7.279 0.000
##
## Covariances:
## Estimate Std.Err z-value P(>|z|)
## visual ~~
## textual (.22.) 0.403 0.070 5.740 0.000
## speed (.23.) 0.244 0.054 4.527 0.000
## textual ~~
## speed (.24.) 0.194 0.048 4.009 0.000
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|)
## .x1 (.25.) 4.915 0.092 53.705 0.000
## .x2 (.26.) 6.076 0.077 78.634 0.000
## .x3 1.960 0.111 17.679 0.000
## .x4 (.28.) 2.800 0.084 33.470 0.000
## .x5 (.29.) 4.047 0.093 43.457 0.000
## .x6 (.30.) 1.915 0.078 24.696 0.000
## .x7 3.994 0.102 39.317 0.000
## .x8 (.32.) 5.570 0.077 72.264 0.000
## .x9 (.33.) 5.412 0.074 73.492 0.000
## visual 0.046 0.129 0.355 0.722
## textual 0.549 0.114 4.805 0.000
## speed -0.073 0.089 -0.825 0.410
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .x1 (.10.) 0.600 0.106 5.683 0.000
## .x2 (.11.) 1.112 0.101 11.028 0.000
## .x3 (.12.) 0.747 0.086 8.722 0.000
## .x4 (.13.) 0.382 0.047 8.114 0.000
## .x5 (.14.) 0.437 0.057 7.676 0.000
## .x6 (.15.) 0.341 0.041 8.259 0.000
## .x7 (.16.) 0.735 0.076 9.622 0.000
## .x8 (.17.) 0.481 0.074 6.543 0.000
## .x9 (.18.) 0.580 0.070 8.316 0.000
## visual (.19.) 0.758 0.136 5.553 0.000
## textual (.20.) 0.892 0.103 8.639 0.000
## speed (.21.) 0.383 0.083 4.587 0.000
El modelo model_structur_bp muestra una mejora clara en los índices de ajuste global en comparación con el modelo estructural completamente restringido (model_structur_a). En particular, se observa:
Un incremento del CFI, que pasa aproximadamente de 0.89 a 0.91.
Una reducción del RMSEA, que disminuye de valores cercanos a 0.10 a aproximadamente 0.084.
Estos cambios indican que la liberación de la carga factorial x6 permite capturar una fuente localizada de misfit, sin modificar de manera sustantiva la estructura latente común entre los grupos analizados.
anova()Es metodológicamente apropiado aplicar un test de diferencia χ² mediante anova() cuando:
Los modelos son anidados (M4a ⊂ M4b) porque M4b (invarianza estructural parcial):
Mantiene todas las restricciones anteriores.
Excepto una: libera la igualdad de la carga textual =~ x6.
Por lo tanto, M4b es un modelo menos restringido, y M4a se obtiene como un caso especial de M4b al imponer nuevamente esa igualdad.
Se desea evaluar si la liberación de una restricción específica produce una mejora estadísticamente significativa del ajuste.
En este caso, esa función produce la siguiente salida:
##
## Chi-Squared Difference Test
##
## Df AIC BIC Chisq Chisq diff RMSEA Df diff Pr(>Chisq)
## model_structur_bp 72 7468.4 7601.9 147.87
## model_structur_a 73 7471.8 7601.6 153.26 5.3926 0.17084 1 0.02022
##
## model_structur_bp
## model_structur_a *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
En una salida más clara, tenemos:
Reuniendo los resultados de los anovas anteriores:
Chi-Squared Difference Test
Model (versus) Df AIC BIC Chisq Chisq diff RMSEA Df diff Pr(>Chisq)
M1: configural 48 7484.4 7706.8 115.85
M2: metric (M1) 54 7480.6 7680.8 124.04 8.1922 0.049272 6 0.2244
M3a: scalar_a (M2) 60 7508.6 7686.6 164.10 40.0590 0.19421 6 4.435e-07 ***
M3b: scalar_bp (M2) 59 7491.1 7672.8 144.58 20.5350 0.143680 5 0.0009912 ***
M3c: scalar_cp (M2) 58 7478.0 7663.3 129.42 5.3789 0.04786 4 0.2506
M4a structur_a (M3c) 73 7471.8 7601.6 153.26 23.836 0.062562 15 0.06793 .
(M4b) 73 7471.8 7601.6 153.26 5.3926 0.17084 1 0.02022 *
M4b: structur_bp 72 7468.4 7601.9 147.87
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
En este caso, el test de diferencia arroja: Δχ² = 5.39, Δgl = 1 y valor p = 0.020, lo que indica que la liberación de la carga textual =~ x6 produce una mejora significativa del ajuste.
El modelo estructural M4a (model_structur_a) puede compararse directamente con el modelo escalar parcial M3c, ya que ambos modelos son anidados (\(\text{M3c} \subset \text{M4a}\)). En particular, M4a conserva todas las restricciones de medición de M3c y añade únicamente restricciones adicionales a nivel latente, concretamente la igualdad de varianzas y covarianzas entre grupos.
M4a = M3c + restricciones estructurales adicionales
Por ello, la comparación mediante un test χ² de diferencia (anova) entre M3c y M4a es estadísticamente válida e interpretable, y permite evaluar formalmente la hipótesis de invarianza estructural.
En cambio, el modelo M4b (model_structur_bp) no debe compararse directamente con el modelo escalar parcial M3c (model_scalar_cp) mediante un test χ² de diferencia, ya que ambos modelos no son anidados. En particular, M4b introduce simultáneamente dos tipos de cambios respecto a M3c:
Incorpora restricciones estructurales adicionales que no están presentes en M3c, a saber:
Igualdad de las varianzas latentes entre grupos (lv.variances), lo que evalúa si la dispersión de los constructos es comparable entre escuelas.
Igualdad de las covarianzas latentes entre grupos (lv.covariances), lo que evalúa si la asociación entre los factores latentes mantiene la misma magnitud en ambos grupos.
Relaja una restricción de medición previamente impuesta, al liberar la carga factorial textual =~ x6.
Debido a esta combinación de restricciones nuevas y liberaciones simultáneas, M4b no puede obtenerse de M3c únicamente mediante la imposición de restricciones adicionales. En consecuencia, no se cumple la condición de anidamiento requerida para aplicar un test χ² de diferencia directo.
En consecuencia, la evaluación del modelo M4b se realiza:
En términos conceptuales, M3c controla cómo se mide el constructo, mientras que M4b evalúa además cómo varía y cómo se relaciona entre grupos, permitiendo un refinamiento localizado de la medición.
Con base en la:
Comparación anidada anova(model_scalar_cp, model_structur_a) con \(p = 0.0679\), y
Ausencia de sugerencias automáticas adicionales
(group_partial = character(0)),
el modelo model_structur_a constituye un candidato razonable para invarianza estructural, en términos de:
Varianzas latentes invariantes, y
Covarianzas latentes invariantes,
manteniendo la invarianza escalar parcial previamente establecida (con liberación de x3~1 y x7~1).
Como verificación adicional, los score tests sugieren una tensión localizada en la carga de x6, lo cual puede reportarse como un hallazgo secundario o bien explorarse mediante un refinamiento opcional del modelo (M4b) si el objetivo es maximizar la consistencia local del ajuste.
Una vez establecidas:
el siguiente paso natural en el análisis SEM multigrupo consiste en evaluar si las relaciones estructurales entre los factores latentes son comparables entre grupos.
Hasta este punto, el análisis se ha centrado en modelos CFA multigrupo, donde el interés principal es cómo se miden los constructos. A partir de aquí, el foco se desplaza hacia cómo los constructos se relacionan entre sí, lo que requiere la especificación explícita de regresiones latentes.
Por esta razón, se pasa del uso de la función cfa() a la función sem() del paquete lavaan.
Nota conceptual.
cfa() es una función especializada para modelos de medición (sin relaciones estructurales).
sem() es una función más general que permite especificar simultáneamente el modelo de medición y el modelo estructural (regresiones entre factores o hacia variables dependientes).
En presencia de regresiones latentes, el uso de sem() es conceptualmente más apropiado, aunque ambas funciones pertenecen al mismo paquete (lavaan) y comparten gran parte de su sintaxis.
El objetivo en esta etapa es evaluar si los coeficientes de regresión entre factores latentes son equivalentes entre grupos. Para ello, se adopta nuevamente una estrategia basada en modelos anidados, análoga a la utilizada en los niveles previos de invarianza.
El procedimiento consiste en:
Especificar un modelo de ecuaciones estructurales (SEM) que combine medición y relaciones causales entre factores.
Ajustar un modelo SEM libre, en el que las regresiones estructurales pueden diferir entre grupos.
Ajustar un modelo SEM restringido, imponiendo la igualdad de dichas regresiones entre grupos.
Comparar ambos modelos mediante un test χ² de diferencia (anova()).
Si la imposición de igualdad en las regresiones no produce un deterioro significativo del ajuste, se concluye que existe invarianza de las regresiones estructurales.
En el siguiente ejemplo se especifica un modelo de ecuaciones estructurales (SEM) que mantiene la misma estructura factorial utilizada en los modelos CFA previos, pero añade explícitamente una relación estructural entre factores latentes.
El siguiente bloque de código ilustra paso a paso la especificación del modelo SEM, el ajuste de las versiones multigrupo con y sin igualdad en las regresiones, y la evaluación formal de la invarianza estructural mediante un test de diferencia.
#1. SEM model (medición + estructura)
sem_model <- '
visual =~ x1 + x2 + x3
textual =~ x4 + x5 + x6
speed =~ x7 + x8 + x9
# relaciones estructurales
textual ~ visual + speed
'
#2. Modelo SEM libre (regresiones no igualadas)
model_sem_free <- sem(sem_model, data = HolzingerSwineford1939,
group = "school",
group.equal = c("loadings", "intercepts"),
group.partial = c("x3~1", "x7~1")
)
summary(model_sem_free)
#3. Modelo SEM restringido (regresiones invariantes)
model_sem_equal_reg <- sem(sem_model, data = HolzingerSwineford1939,
group = "school",
group.equal = c("loadings", "intercepts", "regressions"),
group.partial = c("x3~1", "x7~1")
)
summary(model_sem_equal_reg)
#4. Comparación anova
anova(model_sem_free, model_sem_equal_reg)
En el bloque 1 del código se define el modelo teórico completo mediante sintaxis lavaan:
=~ define relaciones de medición, es decir, especifica qué ítems observados cargan sobre cada factor latente. Por ejemplo,`visual =~ x1 + x2 + x3`
indica que el constructo latente visual se mide a través de los ítems x1, x2 y x3.
~ define relaciones estructurales de regresión entre variables latentes u observadas. En este caso,`textual ~ visual + speed`
indica que el factor latente textual es explicado (regresionado) por los factores visual y speed.
De este modo, el modelo combina un:
Modelo de medición (CFA), y
Modelo estructural (regresiones entre factores),
lo que justifica el uso de la función sem() en lugar de cfa().
A partir de este modelo teórico, se ajustan dos versiones multigrupo con el fin de evaluar la invarianza de las regresiones estructurales:
Un modelo libre, en el que los coeficientes de regresión pueden estimarse de manera independiente en cada grupo (bloque 2 del código).
Un modelo restringido, en el que los coeficientes de regresión se imponen como iguales entre grupos (bloque 3 del código).
La comparación formal entre ambos modelos mediante un test χ² de diferencia (anova) permite evaluar si la imposición de igualdad en las regresiones estructurales produce (o no) un deterioro significativo del ajuste, proporcionando así evidencia empírica sobre la invarianza de las relaciones estructurales (bloque 4 del código).
En este modelo (model_sem_free), se mantienen las restricciones de medición ya establecidas (cargas e interceptos, con invarianza escalar parcial), pero las regresiones latentes se estiman libremente en cada grupo. La salida correspondiente es:
## lavaan 0.6-19 ended normally after 59 iterations
##
## Estimator ML
## Optimization method NLMINB
## Number of model parameters 63
## Number of equality constraints 13
##
## Number of observations per group:
## Pasteur 156
## Grant-White 145
##
## Model Test User Model:
##
## Test statistic 129.422
## Degrees of freedom 58
## P-value (Chi-square) 0.000
## Test statistic for each group:
## Pasteur 71.170
## Grant-White 58.253
##
## Parameter Estimates:
##
## Standard errors Standard
## Information Expected
## Information saturated (h1) model Structured
##
##
## Group 1 [Pasteur]:
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|)
## visual =~
## x1 1.000
## x2 (.p2.) 0.606 0.101 5.988 0.000
## x3 (.p3.) 0.791 0.109 7.259 0.000
## textual =~
## x4 1.000
## x5 (.p5.) 1.120 0.066 16.960 0.000
## x6 (.p6.) 0.932 0.056 16.606 0.000
## speed =~
## x7 1.000
## x8 (.p8.) 1.200 0.155 7.741 0.000
## x9 (.p9.) 1.041 0.136 7.635 0.000
##
## Regressions:
## Estimate Std.Err z-value P(>|z|)
## textual ~
## visual 0.439 0.123 3.572 0.000
## speed 0.324 0.192 1.687 0.092
##
## Covariances:
## Estimate Std.Err z-value P(>|z|)
## visual ~~
## speed 0.168 0.064 2.647 0.008
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|)
## .x1 (.25.) 4.914 0.092 53.538 0.000
## .x2 (.26.) 6.087 0.079 76.999 0.000
## .x3 2.487 0.094 26.474 0.000
## .x4 (.28.) 2.778 0.087 31.953 0.000
## .x5 (.29.) 4.035 0.096 41.861 0.000
## .x6 (.30.) 1.926 0.079 24.425 0.000
## .x7 4.432 0.086 51.533 0.000
## .x8 (.32.) 5.569 0.074 75.328 0.000
## .x9 (.33.) 5.409 0.070 77.182 0.000
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .x1 0.560 0.137 4.086 0.000
## .x2 1.267 0.156 8.105 0.000
## .x3 0.879 0.128 6.850 0.000
## .x4 0.446 0.069 6.432 0.000
## .x5 0.502 0.082 6.132 0.000
## .x6 0.263 0.050 5.258 0.000
## .x7 0.850 0.114 7.471 0.000
## .x8 0.516 0.095 5.429 0.000
## .x9 0.656 0.096 6.852 0.000
## visual 0.796 0.170 4.691 0.000
## .textual 0.646 0.109 5.916 0.000
## speed 0.304 0.078 3.918 0.000
##
##
## Group 2 [Grant-White]:
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|)
## visual =~
## x1 1.000
## x2 (.p2.) 0.606 0.101 5.988 0.000
## x3 (.p3.) 0.791 0.109 7.259 0.000
## textual =~
## x4 1.000
## x5 (.p5.) 1.120 0.066 16.960 0.000
## x6 (.p6.) 0.932 0.056 16.606 0.000
## speed =~
## x7 1.000
## x8 (.p8.) 1.200 0.155 7.741 0.000
## x9 (.p9.) 1.041 0.136 7.635 0.000
##
## Regressions:
## Estimate Std.Err z-value P(>|z|)
## textual ~
## visual 0.548 0.157 3.497 0.000
## speed 0.110 0.168 0.651 0.515
##
## Covariances:
## Estimate Std.Err z-value P(>|z|)
## visual ~~
## speed 0.312 0.079 3.955 0.000
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|)
## .x1 (.25.) 4.914 0.092 53.538 0.000
## .x2 (.26.) 6.087 0.079 76.999 0.000
## .x3 1.955 0.108 18.170 0.000
## .x4 (.28.) 2.778 0.087 31.953 0.000
## .x5 (.29.) 4.035 0.096 41.861 0.000
## .x6 (.30.) 1.926 0.079 24.425 0.000
## .x7 3.992 0.094 42.478 0.000
## .x8 (.32.) 5.569 0.074 75.328 0.000
## .x9 (.33.) 5.409 0.070 77.182 0.000
## visual 0.051 0.129 0.393 0.695
## .textual 0.556 0.114 4.896 0.000
## speed -0.071 0.089 -0.800 0.424
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .x1 0.651 0.127 5.138 0.000
## .x2 0.939 0.122 7.721 0.000
## .x3 0.603 0.096 6.248 0.000
## .x4 0.343 0.062 5.532 0.000
## .x5 0.377 0.073 5.136 0.000
## .x6 0.437 0.067 6.556 0.000
## .x7 0.599 0.090 6.655 0.000
## .x8 0.407 0.089 4.570 0.000
## .x9 0.531 0.086 6.186 0.000
## visual 0.715 0.160 4.473 0.000
## .textual 0.612 0.108 5.694 0.000
## speed 0.475 0.109 4.344 0.000
Interpretación del modelo SEM libre
El modelo SEM libre (model_sem_free) converge adecuadamente, lo que indica que la especificación del modelo es estimable y numéricamente estable bajo las restricciones de medición previamente establecidas.
A nivel estructural, las estimaciones muestran que:
En ambos grupos, el factor visual ejerce un efecto positivo y estadísticamente significativo sobre textual, lo que sugiere una relación consistente entre estos constructos.
El efecto de speed sobre textuales más débil y no resulta estadísticamente significativo en ninguno de los grupos, aunque la magnitud del coeficiente difiere entre escuelas.
Dado que en este modelo las regresiones se estiman libremente por grupo, estas diferencias descriptivas en los coeficientes estructurales no implican aún evidencia formal de no invarianza, sino que reflejan variación empírica preliminar entre grupos.
En consecuencia, este modelo cumple el rol de línea base estructural, a partir de la cual se evaluará formalmente la hipótesis de invarianza de regresiones mediante la comparación con el modelo restringido.
En este segundo modelo (model_sem_equal_reg), además de las restricciones de medición, se impone la igualdad de los coeficientes de regresión entre los factores latentes en ambos grupos. La salida correspondiente es:
## lavaan 0.6-19 ended normally after 66 iterations
##
## Estimator ML
## Optimization method NLMINB
## Number of model parameters 63
## Number of equality constraints 15
##
## Number of observations per group:
## Pasteur 156
## Grant-White 145
##
## Model Test User Model:
##
## Test statistic 130.132
## Degrees of freedom 60
## P-value (Chi-square) 0.000
## Test statistic for each group:
## Pasteur 71.443
## Grant-White 58.689
##
## Parameter Estimates:
##
## Standard errors Standard
## Information Expected
## Information saturated (h1) model Structured
##
##
## Group 1 [Pasteur]:
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|)
## visual =~
## x1 1.000
## x2 (.p2.) 0.605 0.101 5.991 0.000
## x3 (.p3.) 0.788 0.109 7.254 0.000
## textual =~
## x4 1.000
## x5 (.p5.) 1.122 0.066 16.969 0.000
## x6 (.p6.) 0.932 0.056 16.584 0.000
## speed =~
## x7 1.000
## x8 (.p8.) 1.195 0.155 7.703 0.000
## x9 (.p9.) 1.058 0.139 7.620 0.000
##
## Regressions:
## Estimate Std.Err z-value P(>|z|)
## textual ~
## visual (.10.) 0.477 0.101 4.725 0.000
## speed (.11.) 0.211 0.124 1.699 0.089
##
## Covariances:
## Estimate Std.Err z-value P(>|z|)
## visual ~~
## speed 0.175 0.063 2.771 0.006
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|)
## .x1 (.25.) 4.914 0.092 53.592 0.000
## .x2 (.26.) 6.087 0.079 77.155 0.000
## .x3 2.487 0.094 26.479 0.000
## .x4 (.28.) 2.778 0.087 31.990 0.000
## .x5 (.29.) 4.034 0.096 41.852 0.000
## .x6 (.30.) 1.926 0.079 24.450 0.000
## .x7 4.432 0.086 51.404 0.000
## .x8 (.32.) 5.569 0.074 75.540 0.000
## .x9 (.33.) 5.410 0.071 76.653 0.000
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .x1 0.561 0.134 4.178 0.000
## .x2 1.271 0.156 8.121 0.000
## .x3 0.885 0.128 6.917 0.000
## .x4 0.445 0.069 6.430 0.000
## .x5 0.500 0.082 6.114 0.000
## .x6 0.264 0.050 5.273 0.000
## .x7 0.855 0.114 7.476 0.000
## .x8 0.519 0.095 5.465 0.000
## .x9 0.646 0.096 6.738 0.000
## visual 0.792 0.166 4.759 0.000
## .textual 0.647 0.109 5.962 0.000
## speed 0.305 0.078 3.916 0.000
##
##
## Group 2 [Grant-White]:
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|)
## visual =~
## x1 1.000
## x2 (.p2.) 0.605 0.101 5.991 0.000
## x3 (.p3.) 0.788 0.109 7.254 0.000
## textual =~
## x4 1.000
## x5 (.p5.) 1.122 0.066 16.969 0.000
## x6 (.p6.) 0.932 0.056 16.584 0.000
## speed =~
## x7 1.000
## x8 (.p8.) 1.195 0.155 7.703 0.000
## x9 (.p9.) 1.058 0.139 7.620 0.000
##
## Regressions:
## Estimate Std.Err z-value P(>|z|)
## textual ~
## visual (.10.) 0.477 0.101 4.725 0.000
## speed (.11.) 0.211 0.124 1.699 0.089
##
## Covariances:
## Estimate Std.Err z-value P(>|z|)
## visual ~~
## speed 0.311 0.078 3.964 0.000
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|)
## .x1 (.25.) 4.914 0.092 53.592 0.000
## .x2 (.26.) 6.087 0.079 77.155 0.000
## .x3 1.956 0.107 18.263 0.000
## .x4 (.28.) 2.778 0.087 31.990 0.000
## .x5 (.29.) 4.034 0.096 41.852 0.000
## .x6 (.30.) 1.926 0.079 24.450 0.000
## .x7 3.992 0.094 42.436 0.000
## .x8 (.32.) 5.569 0.074 75.540 0.000
## .x9 (.33.) 5.410 0.071 76.653 0.000
## visual 0.050 0.130 0.389 0.697
## .textual 0.567 0.111 5.113 0.000
## speed -0.072 0.089 -0.804 0.422
##
## Variances:
## Estimate Std.Err z-value P(>|z|)
## .x1 0.643 0.127 5.067 0.000
## .x2 0.936 0.122 7.705 0.000
## .x3 0.601 0.097 6.213 0.000
## .x4 0.346 0.062 5.558 0.000
## .x5 0.372 0.073 5.088 0.000
## .x6 0.439 0.067 6.571 0.000
## .x7 0.602 0.090 6.687 0.000
## .x8 0.424 0.089 4.764 0.000
## .x9 0.520 0.086 6.079 0.000
## visual 0.726 0.159 4.559 0.000
## .textual 0.621 0.105 5.933 0.000
## speed 0.468 0.108 4.322 0.000
Interpretación del modelo SEM con regresiones invariantes
El modelo SEM con regresiones invariantes (model_sem_equal_reg) también converge adecuadamente, lo que confirma que la imposición de igualdad en los coeficientes estructurales es compatible con los datos bajo las restricciones de medición previamente establecidas.
En este modelo:
Los coeficientes de regresión de visual y speed sobre textual son idénticos en ambos grupos, al estar sujetos a restricciones de igualdad.
El efecto de visual sobre textual es positivo y estadísticamente significativo, indicando una relación estructural robusta y estable entre grupos.
El efecto de speed sobre textual es de menor magnitud y no alcanza significación estadística, pero su estimación es consistente entre escuelas.
Desde el punto de vista interpretativo, este modelo plantea explícitamente la hipótesis de que las relaciones estructurales entre los factores latentes son invariantes entre grupos, es decir, que los mecanismos subyacentes que vinculan visual y speed con textual operan de la misma forma en ambas escuelas.
Este modelo constituye, por tanto, la versión restringida que será comparada formalmente con el modelo SEM libre para evaluar la hipótesis de invarianza de regresiones estructurales mediante un test χ² de diferencia.
La salida del test χ² de diferencia es la siguiente:
##
## Chi-Squared Difference Test
##
## Df AIC BIC Chisq Chisq diff RMSEA Df diff Pr(>Chisq)
## model_sem_free 58 7478.0 7663.3 129.42
## model_sem_equal_reg 60 7474.7 7652.6 130.13 0.70972 0 2 0.7013
En una tabla más organizada:
Chi-Squared Difference Test
Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
model_sem_free 58 7478.0 7663.3 129.42
model_sem_equal_reg 60 7474.7 7652.6 130.13 0.7097 2 0.7013
Interpretación de la comparación SEM
El test de diferencia χ² indica que imponer igualdad en las regresiones latentes no produce un deterioro estadísticamente significativo del ajuste:
\(\Delta \chi^2 = 0.71\)
\(\Delta gl = 2\)
\(p = 0.701\)
Dado que el valor p es claramente mayor que 0.05, no se rechaza la hipótesis de igualdad de las regresiones entre grupos.
En consecuencia, la evidencia empírica respalda la invarianza de las relaciones estructurales, lo que sugiere que:
La influencia de visual y speed sobre textual es comparable entre escuelas, y
Las diferencias observadas entre grupos no se deben a cambios en la estructura de las relaciones latentes, sino a otros componentes del modelo que ya han sido controlados en las etapas previas del análisis.
En términos conceptuales, esta etapa completa la jerarquía del análisis multigrupo:
Los modelos CFA (configural, métrico, escalar y estructural) evalúan cómo se mide el constructo y cómo se distribuye a nivel latente.
Los modelos SEM multigrupo permiten evaluar cómo los constructos se relacionan entre sí mediante regresiones latentes.
Una vez establecida la invarianza de las regresiones estructurales, las comparaciones sustantivas entre grupos pueden interpretarse con un mayor grado de confianza.
En modelos de ecuaciones estructurales multigrupo, la invarianza métrica constituye el requisito mínimo para comparar:
Relaciones causales entre constructos.
Efectos directos e indirectos.
Coeficientes de regresión estructural.
Por su parte, la invarianza escalar es necesaria cuando el análisis incluye:
Comparación de medias latentes.
Evaluación de diferencias de nivel entre grupos.
Estas condiciones aseguran que las comparaciones estructurales y de nivel se realicen sobre constructos que mantienen el mismo significado empírico entre grupos.
Sin invarianza métrica: no comparar relaciones estructurales.
Sin invarianza escalar: no comparar medias latentes.
Con invarianza escalar parcial: comparaciones válidas, pero con cautela e interpretación contextual.
La evaluación de la invarianza de medida en CFA y SEM multigrupo sigue una lógica jerárquica:
Configural: misma estructura factorial entre grupos.
Métrica: mismo significado del constructo (cargas invariantes).
Escalar: comparación válida de medias latentes (interceptos invariantes).
Estricta: comparación válida de puntuaciones observadas (residuos invariantes).
Estructural: comparación de relaciones causales entre grupos.
Cada nivel amplía el tipo de inferencias sustantivas que pueden realizarse de manera válida.
La evaluación de la invarianza de medida no es un procedimiento técnico accesorio, sino un fundamento epistemológico de la comparación entre grupos.
En ausencia de invarianza, las diferencias empíricas observadas pueden reflejar artefactos de medición y no diferencias reales en los constructos de interés.
En este sentido, la invarianza métrica y escalar constituyen el puente natural entre el modelo de medición y el modelo estructural, consolidando la validez de las inferencias en estudios comparativos y en modelos SEM multigrupo.
Este conjunto de ejercicios enfatiza que la evaluación de escalas no se agota en la fiabilidad interna. La validez de las comparaciones entre grupos depende críticamente de la invarianza de medida, que conecta el modelo de medición con la inferencia sustantiva en estudios comparativos y modelos SEM multigrupo.
El objetivo de esta sección es que el estudiante:
Comprenda conceptualmente la invarianza de medida.
Implemente pruebas de invarianza métrica mediante CFA multigrupo.
Interprete resultados estadísticos y sustantivos.
Reflexione sobre las implicaciones de la invarianza (o su ausencia) en estudios comparativos y modelos SEM.
Para el contexto del estudio, se dispone de una base de datos con respuestas a una batería de ítems aplicados a estudiantes pertenecientes a distintos grupos. Se asume que los ítems miden constructos latentes de naturaleza psicológica y educativa (Visual, Textual y Speed). El interés principal es evaluar si estos constructos se miden de forma equivalente entre los grupos definidos, antes de realizar comparaciones sustantivas.
Explique con sus propias palabras qué significa que un instrumento sea invariante entre grupos.
Explique por qué no es válido comparar medias o relaciones entre grupos sin evaluar previamente la invarianza de medida.
Describa brevemente las diferencias conceptuales entre:
Invarianza configural.
Invarianza métrica.
Invarianza escalar.
Invarianza estricta.
Indique qué tipo de comparaciones (medias, regresiones, correlaciones) son válidas en cada nivel de invarianza.
Considere el siguiente modelo de medición con tres factores latentes y nueve indicadores.
Escriba el modelo CFA en sintaxis lavaan.
Justifique la asignación de los ítems a cada factor desde un punto de vista conceptual.
Explique por qué este modelo debe evaluarse primero por separado en cada grupo.
Ajuste un modelo CFA multigrupo sin restricciones de igualdad.
Examine los principales índices de ajuste global del modelo.
Indique si el modelo presenta un ajuste aceptable en ambos grupos.
Explique qué implicaría un mal ajuste a este nivel de invarianza.
Justifique por qué en este modelo no se estiman diferencias de medias latentes entre grupos.
Ajuste un modelo CFA multigrupo imponiendo igualdad en las cargas factoriales.
Compare el ajuste del modelo métrico con el modelo configural.
Analice los cambios en los siguientes índices de ajuste:
Interprete si puede asumirse invarianza métrica.
Explique qué implica la invarianza métrica respecto al significado de los constructos latentes.
Indique qué tipo de análisis comparativos ya son válidos en este punto.
Suponga que el modelo métrico presenta un deterioro sustancial del ajuste.
Explique conceptualmente qué significa la no invarianza métrica.
Utilice los índices de modificación para identificar cargas factoriales problemáticas.
Discuta posibles causas sustantivas de la no invarianza (culturales, educativas o cognitivas).
Ajuste un modelo con invarianza métrica parcial, liberando las cargas identificadas como no invariantes.
Compare el ajuste del modelo parcial con el modelo métrico completo.
Discuta si es legítimo continuar el análisis bajo invarianza parcial.
Explique bajo qué condiciones teóricas y empíricas la invarianza parcial es aceptable.
Analice cómo la invarianza parcial afecta la interpretación de los resultados.
Ajuste un modelo CFA multigrupo con igualdad en cargas factoriales e interceptos.
Compare el ajuste del modelo escalar con el modelo métrico.
Interprete los cambios observados en los índices de ajuste.
Indique si es válido comparar medias latentes entre grupos.
Explique las implicaciones de la no invarianza escalar.
Identifique interceptos no invariantes mediante índices de modificación.
Ajuste un modelo con invarianza escalar parcial.
Analice las medias latentes estimadas bajo este modelo.
Explique cómo cambia la interpretación de las diferencias entre grupos.
Discuta qué riesgos existirían si se ignorara la no invarianza escalar.
Explique conceptualmente la diferencia entre invarianza escalar e invarianza estricta.
Ajuste un modelo CFA multigrupo con igualdad en las varianzas residuales.
Compare el ajuste con el modelo escalar parcial.
Indique si es apropiado utilizar puntuaciones observadas.
Discuta en qué contextos la invarianza estricta es realmente necesaria.
Explique qué se entiende por invarianza estructural.
Ajuste un modelo donde se restrinjan:
Discuta si estas restricciones son empíricamente sostenibles.
Explique por qué la invarianza métrica es un requisito mínimo para comparar relaciones estructurales entre grupos.
Redacte un breve texto (máx. 1 página) donde discuta:
Por qué la invarianza de medida es un problema epistemológico y no solo técnico.
Las consecuencias de ignorar la no invarianza de medida.
La importancia de la invarianza en estudios comparativos y longitudinales.
Suponga que los mismos ítems se aplican a los mismos individuos en dos momentos temporales.
Explique cómo se reinterpretan los niveles de invarianza en un contexto longitudinal.
Discuta por qué la invarianza escalar es crucial para interpretar el cambio.
Compare conceptualmente la invarianza longitudinal con la invarianza multigrupo.
lsm::survey)En estos ejercicios se utilizará el mismo conjunto de datos empleado en los capítulos de consistencia interna y CFA. El objetivo es evaluar si las escalas analizadas se miden de forma equivalente entre distintos grupos.
Use el conjunto de datos lsm::survey para realizar los ejercicios del 13 al 23. Este es un data frame que se encuentra dentro del paquete lsm (Villalba J., Llinás H. y Fabregas O., 2025). Contiene 800 observaciones y 66 variables. La descripción detallada de las variables puede consultarse aquí.
En general, el conjunto de datos incluye escalas psicológicas y educativas medidas mediante ítems Likert y ordinales, así como variables sociodemográficas que permiten definir grupos de comparación.
#library(lsm)
datos <- lsm::survey
names(datos)
## [1] "Observation" "ID" "Gender" "Like" "Age"
## [6] "Smoke" "Height" "Weight" "BMI" "School"
## [11] "SES" "Enrollment" "Score" "MotherHeight" "MotherAge"
## [16] "MotherCHD" "FatherHeight" "FatherAge" "FatherCHD" "Status"
## [21] "SemAcum" "Exam1" "Exam2" "Exam3" "Exam4"
## [26] "ExamAcum" "Definitive" "Expense" "Income" "Gas"
## [31] "Course" "Law" "Economic" "Race" "Region"
## [36] "EMO1" "EMO2" "EMO3" "EMO4" "EMO5"
## [41] "GOAL1" "GOAL2" "GOAL3" "Pre_STAT1" "Pre_STAT2"
## [46] "Pre_STAT3" "Pre_STAT4" "Post_STAT1" "Post_STAT2" "Post_STAT3"
## [51] "Post_STAT4" "Pre_IDARE1" "Pre_IDARE2" "Pre_IDARE3" "Pre_IDARE4"
## [56] "Pre_IDARE5" "Post_IDARE1" "Post_IDARE2" "Post_IDARE3" "Post_IDARE4"
## [61] "Post_IDARE5" "PSICO1" "PSICO2" "PSICO3" "PSICO4"
## [66] "PSICO5"
Antes de comenzar, identifique al menos una variable de agrupación, por ejemplo:
Justifique la elección del grupo desde un punto de vista teórico y sustantivo.
Considere la escala STAT (Pre_STAT1 a Pre_STAT4).
Explique por qué no es suficiente haber evaluado alfa y omega para comparar esta escala entre grupos.
Defina con sus palabras qué significa invarianza de medida.
Explique la diferencia conceptual entre:
Para los ítems Pre_STAT1 a Pre_STAT4:
Proponga un modelo CFA unidimensional.
Ajuste el modelo por separado en cada grupo definido.
Analice el ajuste global en cada grupo.
Discuta si el modelo es conceptualmente razonable en todos los grupos.
Ajuste un modelo CFA multigrupo sin imponer restricciones de igualdad.
Examine los índices de ajuste global.
Responda:
Ajuste un modelo CFA multigrupo imponiendo igualdad en las cargas factoriales.
Compare el modelo métrico con el modelo configural.
Analice los cambios en:
Interprete si puede asumirse invarianza métrica.
Indique qué comparaciones ya serían válidas en este punto.
Suponga que la invarianza métrica no se cumple completamente.
Explique qué significa sustantivamente que una carga factorial no sea invariante.
Utilice índices de modificación para identificar ítems problemáticos.
Discuta posibles razones psicológicas o educativas para esta no invarianza.
Ajuste un modelo con invarianza métrica parcial, liberando las cargas no invariantes.
Compare el ajuste con el modelo métrico completo.
Discuta:
Considere ahora la escala PSICO (PSICO1 a PSICO5).
Ajuste un modelo CFA multigrupo con igualdad en cargas e interceptos.
Compare el modelo con el modelo métrico.
Indique si es válido comparar medias latentes.
Explique qué tipo de sesgos pueden reflejarse en la no invarianza escalar.
Identifique interceptos no invariantes mediante índices de modificación.
Ajuste un modelo con invarianza escalar parcial.
Analice las medias latentes estimadas.
Discuta cómo la corrección por invarianza parcial afecta las conclusiones.
Considere los resultados obtenidos previamente para alfa y omega.
Discuta por qué una escala con alta fiabilidad puede no ser invariante.
Explique la relación entre:
Redacte un texto breve donde discuta:
Por qué la invarianza de medida es un problema epistemológico y no solo técnico.
Qué riesgos existen al comparar grupos sin evaluar invarianza.
Cómo se integran:
Consultar el documento RPubs :: Análisis multivariado (bibliografía).
If you found any ERRORS or have SUGGESTIONS, please report them to my email. Thanks.