1 Objetivo del análisis

Este documento ejecuta el script script SEM.R y explica cada salida y gráfica. Tiene tres objetivos:

  1. Evaluar la normalidad de los 11 indicadores observados, porque la estimación por Máxima Verosimilitud (ML) supone normalidad multivariada.
  2. Estimar el modelo clásico de Bollen (1989), que relaciona la industrialización de 1960 con la democracia política de 1960 y 1965.
  3. Comparar ML clásico con ML robusto (MLR), para ver si la falta de normalidad cambia las conclusiones.

Nota: el script original no produce gráficas. Las gráficas de este documento (histogramas, QQ-plots, diagrama de ruta y comparación de errores estándar) se añadieron para facilitar la interpretación. El código original se conserva sin cambios.

2 Librerías y datos

# 1. Cargar librerías necesarias
if(!require(lavaan)) install.packages("lavaan", dependencies = TRUE)
if(!require(psych)) install.packages("psych", dependencies = TRUE)

library(lavaan)
library(psych)

# Librerías adicionales solo para las gráficas
library(semPlot)

# 2. Cargar datos integrados en lavaan
datos_bollen <- PoliticalDemocracy
head(datos_bollen)
y1 y2 y3 y4 y5 y6 y7 y8 x1 x2 x3
2.50 0.000000 3.333333 0.000000 1.250000 0.000000 3.726360 3.333333 4.442651 3.637586 2.557615
1.25 0.000000 3.333333 0.000000 6.250000 1.100000 6.666666 0.736999 5.384495 5.062595 3.568079
7.50 8.800000 9.999998 9.199991 8.750000 8.094061 9.999998 8.211809 5.961005 6.255750 5.224433
8.90 8.800000 9.999998 9.199991 8.907948 8.127979 9.999998 4.615086 6.285998 7.567863 6.267495
10.00 3.333333 9.999998 6.666666 7.500000 3.333333 9.999998 6.666666 5.863631 6.818924 4.573679
7.50 3.333333 6.666666 6.666666 6.250000 1.100000 6.666666 0.368500 5.533389 5.135798 3.892270

La base PoliticalDemocracy tiene 75 países en desarrollo y 11 variables:

Variable Significado Constructo
x1 PIB per cápita (1960) ind60: industrialización 1960
x2 Consumo de energía per cápita (1960) ind60
x3 % de fuerza laboral en la industria (1960) ind60
y1 Libertad de prensa (1960) dem60: democracia 1960
y2 Libertad de oposición política (1960) dem60
y3 Elecciones justas (1960) dem60
y4 Efectividad del legislativo electo (1960) dem60
y5 – y8 Los mismos cuatro indicadores medidos en 1965 dem65: democracia 1965

3 Pregunta 1: ¿Los datos son normales?

3.1 Prueba de Shapiro-Wilk

variables <- c("x1", "x2", "x3", "y1", "y2", "y3", "y4", "y5", "y6", "y7", "y8")

shapiro_resultados <- sapply(datos_bollen[, variables], function(v) {
  test <- shapiro.test(v)
  c(W = round(test$statistic, 3), p_value = round(test$p.value, 5))
})
print("Resultados de la prueba de Shapiro-Wilk:")
[1] "Resultados de la prueba de Shapiro-Wilk:"
print(t(shapiro_resultados))
     W.W p_value
x1 0.975 0.14543
x2 0.976 0.17151
x3 0.973 0.11450
y1 0.932 0.00056
y2 0.831 0.00000
y3 0.855 0.00000
y4 0.899 0.00002
y5 0.960 0.01788
y6 0.811 0.00000
y7 0.872 0.00000
y8 0.901 0.00002

Cómo leerla. La hipótesis nula (H0) es que la variable sigue una distribución normal. Si p < 0.05, se rechaza la normalidad. El estadístico W vale 1 cuando el ajuste a la normal es perfecto, y valores más bajos indican mayor desviación.

Resultados:

  • x1, x2 y x3 (industrialización): p > 0.05 (0.145, 0.172 y 0.115). No se rechaza la normalidad. W ≈ 0.97.
  • Los ocho indicadores de democracia (y1–y8): todos tienen p < 0.05, así que ninguno es normal. Los casos más graves son y6 (W = 0.811), y2 (W = 0.831) y y3 (W = 0.855), con p ≈ 0. El caso más leve es y5 (p = 0.018).

Esto tiene sentido: las variables de democracia son escalas acotadas (de 0 a 10) donde muchos países se acumulan en los extremos (totalmente democráticos o totalmente autoritarios).

3.2 Asimetría y curtosis

print("Evaluación de Asimetría y Curtosis:")
[1] "Evaluación de Asimetría y Curtosis:"
describe(datos_bollen[, variables])[, c("mean", "sd", "skew", "kurtosis")]
mean sd skew kurtosis
x1 5.054384 0.7329043 0.2539241 -0.7538511
x2 4.792195 1.5106644 -0.3457856 -0.5708606
x3 3.557690 1.4057112 0.0838115 -0.9361009
y1 5.464667 2.6227020 -0.0914478 -1.1544702
y2 4.256443 3.9471276 0.3186940 -1.4672781
y3 6.563110 3.2808912 -0.5940263 -0.7191094
y4 4.452533 3.3494674 0.1177271 -1.2126786
y5 5.136252 2.6126022 -0.2279739 -0.7782401
y6 2.978074 3.3727326 0.8929756 -0.4688261
y7 6.196264 3.2862398 -0.5533005 -0.7337422
y8 4.043390 3.2455927 0.4455857 -0.9614966

Cómo leerla. skew es la asimetría y kurtosis es la curtosis en exceso, que vale 0 en una normal. Un criterio habitual (Kline; West, Finch y Curran) considera problemáticos los valores |asimetría| > 2 y |curtosis| > 7. Un criterio más estricto usa |valor| > 1.

Resultados:

  • Asimetría: todas las variables están entre −0.59 y 0.89, así que la asimetría es leve. La más asimétrica es y6 (0.89, cola a la derecha porque muchos países tienen valores bajos de libertad de oposición en 1965).
  • Curtosis: todos los valores son negativos (distribuciones platicúrticas, más “planas” que la normal). Destacan y2 (−1.47), y4 (−1.21) y y1 (−1.15), que superan |1|.

Conclusión: la no normalidad no viene de colas pesadas ni de asimetrías extremas. Viene de distribuciones aplanadas o bimodales, con valores agrupados en los extremos de la escala. Ningún valor pasa los umbrales severos (2 y 7), así que la desviación es moderada, pero los indicadores no son normales.

3.3 Gráficas: histogramas con curva normal

par(mfrow = c(3, 4), mar = c(4, 4, 2.5, 1))
for (v in variables) {
  x <- datos_bollen[[v]]
  hist(x, freq = FALSE, breaks = 10, col = "#9ecae1", border = "white",
       main = paste0(v, "  (p S-W = ", round(shapiro.test(x)$p.value, 3), ")"),
       xlab = v, ylab = "Densidad")
  lines(density(x), col = "#08519c", lwd = 2)
  curve(dnorm(x, mean(datos_bollen[[v]]), sd(datos_bollen[[v]])),
        add = TRUE, col = "#de2d26", lwd = 2, lty = 2)
}
plot.new()
legend("center", legend = c("Densidad empírica", "Normal teórica"),
       col = c("#08519c", "#de2d26"), lty = c(1, 2), lwd = 2, bty = "n")

Interpretación de la gráfica. Cada panel compara la forma real de los datos (línea azul continua) con la normal que tendría la misma media y desviación (línea roja discontinua).

  • En x1, x2 y x3 las dos curvas casi coinciden, lo que confirma su normalidad.
  • En y2, y4, y6 y y8 se ven barras altas en los extremos (cerca de 0 y de 10) y huecos en el centro, con una forma bimodal o en “U”. Esa forma explica la curtosis negativa: hay menos datos en el centro de lo que predice la normal.
  • En y3 y y7 hay acumulación en el extremo superior (10), un efecto techo: muchos países tenían elecciones calificadas como totalmente justas.

3.4 Gráficas: QQ-plots

par(mfrow = c(3, 4), mar = c(4, 4, 2.5, 1))
for (v in variables) {
  qqnorm(datos_bollen[[v]], main = v, pch = 19, col = "#3182bd80",
         xlab = "Cuantiles teóricos", ylab = "Cuantiles observados")
  qqline(datos_bollen[[v]], col = "#de2d26", lwd = 2)
}

Interpretación de la gráfica. Si una variable es normal, sus puntos caen sobre la línea roja.

  • x1–x3: los puntos siguen bien la línea.
  • y1–y8: aparecen tramos horizontales (muchos países con el mismo valor, por ejemplo 0 o 10) y una forma de “S” invertida en los extremos. Esa forma es la firma de la curtosis negativa: los extremos de los datos están más cerca del centro de lo que esperaría una normal, porque la escala está acotada.

3.5 Normalidad multivariada (Mardia)

ML necesita normalidad multivariada, no solo univariada. Como complemento se aplica la prueba de Mardia:

mardia(datos_bollen[, variables], plot = TRUE)

Call: mardia(x = datos_bollen[, variables], plot = TRUE)

Mardia tests of multivariate skew and kurtosis
Use describe(x) the to get univariate tests
n.obs = 75   num.vars =  11 
b1p =  26.47   skew =  330.9  with probability  <=  0.035
 small sample skew =  346.41  with probability <=  0.0083
b2p =  134.57   kurtosis =  -2.16  with probability <=  0.031

Interpretación:

  • Asimetría multivariada: p = 0.035 (0.008 con la corrección para muestras pequeñas), así que se rechaza la normalidad.
  • Curtosis multivariada: b2p = 134.57 frente a un valor esperado de 11·13 = 143 bajo normalidad, con p = 0.031. Es significativamente menor que la esperada, lo que coincide con la curtosis negativa univariada.
  • Gráfica: compara las distancias de Mahalanobis al cuadrado con los cuantiles de una ji-cuadrado. Los puntos se apartan de la diagonal en la parte alta, lo que indica que la distribución conjunta no es normal.

Conclusión de la Pregunta 1: los datos violan el supuesto de normalidad multivariada. Por eso conviene comparar la estimación ML clásica con una alternativa robusta (MLR), que corrige los errores estándar y el estadístico ji-cuadrado.

4 Especificación del modelo

# 4. Definición del Modelo SEM (Bollen, 1989)
modelo_bollen <- '
  # Modelo de Medida
  ind60 =~ x1 + x2 + x3
  dem60 =~ y1 + y2 + y3 + y4
  dem65 =~ y5 + y6 + y7 + y8

  # Modelo Estructural (Regresiones)
  dem60 ~ ind60
  dem65 ~ ind60 + dem60

  # Covarianzas Residuales entre Indicadores Repetidos
  y1 ~~ y5
  y2 ~~ y6
  y3 ~~ y7
  y4 ~~ y8
  y2 ~~ y4
  y6 ~~ y8
'

El modelo tiene tres partes:

  1. Modelo de medida (=~, “se mide por”): tres variables latentes, cada una medida por sus indicadores. La primera carga de cada factor (x1, y1, y5) se fija en 1 para darle escala a la latente.
  2. Modelo estructural (~, “se regresa sobre”): la industrialización de 1960 influye en la democracia de 1960. La democracia de 1965 depende de la industrialización y de la democracia de 1960 (efecto de estabilidad en el tiempo).
  3. Covarianzas residuales (~~):
    • y1–y5, y2–y6, y3–y7 y y4–y8 son el mismo indicador medido en dos años, así que comparten error específico del ítem.
    • y2–y4 y y6–y8 vienen de la misma fuente de datos (efecto de método).

Grados de libertad: hay 11·12/2 = 66 momentos observados y 31 parámetros libres, así que gl = 35. El modelo está sobreidentificado y se puede evaluar su ajuste.

5 Estimación ML clásica vs. MLR

# 5. Estimación Clásica (ML) vs. Estimación Robusta (MLR)
fit_ml  <- sem(modelo_bollen, data = datos_bollen, estimator = "ML")
fit_mlr <- sem(modelo_bollen, data = datos_bollen, estimator = "MLR")
  • ML: supone normalidad multivariada. Sus errores estándar salen de la matriz de información esperada.
  • MLR: produce las mismas estimaciones puntuales que ML. Lo que cambia es que corrige los errores estándar con el estimador “sándwich” de Huber-White y escala el ji-cuadrado con la corrección de Yuan-Bentler. Así las pruebas siguen siendo válidas aunque los datos no sean normales.

5.1 Diagrama de ruta del modelo estimado

semPaths(fit_ml, what = "std", whatLabels = "std", layout = "tree2",
         rotation = 2, edge.label.cex = 0.85, sizeMan = 6, sizeLat = 9,
         nCharNodes = 0, residuals = TRUE, intercepts = FALSE,
         edge.color = "black", style = "lisrel", curvePivot = TRUE,
         color = list(lat = "#c6dbef", man = "#fff7bc"),
         title = FALSE)
title("Diagrama de ruta (coeficientes estandarizados, ML)", line = 2)

Interpretación del diagrama:

  • Los óvalos (azules) son las variables latentes y los rectángulos (amarillos) son los indicadores observados.
  • Las flechas de los óvalos a los rectángulos son las cargas factoriales estandarizadas. Todas son altas: entre 0.87 y 0.97 para ind60 y entre 0.72 y 0.85 para los factores de democracia. Los indicadores miden bien sus constructos.
  • Las flechas entre óvalos son los efectos estructurales:
    • ind60 → dem60 = 0.45
    • ind60 → dem65 = 0.18
    • dem60 → dem65 = 0.89, el efecto más fuerte: la democracia es muy estable entre 1960 y 1965.
  • Las flechas curvas dobles entre indicadores son las covarianzas residuales especificadas.

6 Comparación de resultados

6.1 Ajuste global: ML clásico

cat("\n--- RESUMEN DE AJUSTE GLOBAL (ML CLÁSICO) ---\n")

--- RESUMEN DE AJUSTE GLOBAL (ML CLÁSICO) ---
summary(fit_ml, fit.measures = TRUE)
lavaan 0.7-2 ended normally after 68 iterations

  Estimator                                         ML
  Optimization method                           NLMINB
  Number of model parameters                        31

  Number of observations                            75

Model Test User Model:
                                                      
  Test statistic                                38.125
  Degrees of freedom                                35
  P-value (Chi-square)                           0.329

Model Test Baseline Model:

  Test statistic                               730.654
  Degrees of freedom                                55
  P-value                                        0.000

User Model versus Baseline Model:

  Comparative Fit Index (CFI)                    0.995
  Tucker-Lewis Index (TLI)                       0.993

Loglikelihood and Information Criteria:

  Loglikelihood user model (H0)              -1547.791
  Loglikelihood unrestricted model (H1)      -1528.728
                                                      
  Akaike (AIC)                                3157.582
  Bayesian (BIC)                              3229.424
  Sample-size adjusted Bayesian (SABIC)       3131.720

Root Mean Square Error of Approximation:

  RMSEA                                          0.035
  90 Percent confidence interval - lower         0.000
  90 Percent confidence interval - upper         0.092
  P-value H_0: RMSEA <= 0.050                    0.611
  P-value H_0: RMSEA >= 0.080                    0.114

Standardized Root Mean Square Residual:

  SRMR                                           0.044

Goodness of Fit Index:

  Goodness of Fit Index (GFI)                    1.000
  90 Percent confidence interval - lower         0.959
  90 Percent confidence interval - upper         1.000

Parameter Estimates:

  Standard errors                             Standard
  Information                                 Expected
  Information saturated (h1) model          Structured

Latent Variables:
                   Estimate  Std.Err  z-value  P(>|z|)
  ind60 =~                                            
    x1                1.000                           
    x2                2.180    0.139   15.742    0.000
    x3                1.819    0.152   11.967    0.000
  dem60 =~                                            
    y1                1.000                           
    y2                1.257    0.182    6.889    0.000
    y3                1.058    0.151    6.987    0.000
    y4                1.265    0.145    8.722    0.000
  dem65 =~                                            
    y5                1.000                           
    y6                1.186    0.169    7.024    0.000
    y7                1.280    0.160    8.002    0.000
    y8                1.266    0.158    8.007    0.000

Regressions:
                   Estimate  Std.Err  z-value  P(>|z|)
  dem60 ~                                             
    ind60             1.483    0.399    3.715    0.000
  dem65 ~                                             
    ind60             0.572    0.221    2.586    0.010
    dem60             0.837    0.098    8.514    0.000

Covariances:
                   Estimate  Std.Err  z-value  P(>|z|)
 .y1 ~~                                               
   .y5                0.624    0.358    1.741    0.082
 .y2 ~~                                               
   .y6                2.153    0.734    2.934    0.003
 .y3 ~~                                               
   .y7                0.795    0.608    1.308    0.191
 .y4 ~~                                               
   .y8                0.348    0.442    0.787    0.431
 .y2 ~~                                               
   .y4                1.313    0.702    1.871    0.061
 .y6 ~~                                               
   .y8                1.356    0.568    2.386    0.017

Variances:
                   Estimate  Std.Err  z-value  P(>|z|)
   .x1                0.082    0.019    4.184    0.000
   .x2                0.120    0.070    1.718    0.086
   .x3                0.467    0.090    5.177    0.000
   .y1                1.891    0.444    4.256    0.000
   .y2                7.373    1.374    5.366    0.000
   .y3                5.067    0.952    5.324    0.000
   .y4                3.148    0.739    4.261    0.000
   .y5                2.351    0.480    4.895    0.000
   .y6                4.954    0.914    5.419    0.000
   .y7                3.431    0.713    4.814    0.000
   .y8                3.254    0.695    4.685    0.000
    ind60             0.448    0.087    5.173    0.000
   .dem60             3.956    0.921    4.295    0.000
   .dem65             0.172    0.215    0.803    0.422

6.2 Ajuste global: ML robusto (MLR)

cat("\n--- RESUMEN DE AJUSTE GLOBAL (ML ROBUSTO) ---\n")

--- RESUMEN DE AJUSTE GLOBAL (ML ROBUSTO) ---
summary(fit_mlr, fit.measures = TRUE)
lavaan 0.7-2 ended normally after 68 iterations

  Estimator                                         ML
  Optimization method                           NLMINB
  Number of model parameters                        31

  Number of observations                            75

Model Test User Model:
                                              Standard      Scaled
  Test Statistic                                38.125      41.401
  Degrees of freedom                                35          35
  P-value (Chi-square)                           0.329       0.211
  Scaling correction factor                                  0.921
    Yuan-Bentler correction (Mplus variant)                       

Model Test Baseline Model:

  Test statistic                               730.654     702.841
  Degrees of freedom                                55          55
  P-value                                        0.000       0.000
  Scaling correction factor                                  1.040

User Model versus Baseline Model:

  Comparative Fit Index (CFI)                    0.995       0.990
  Tucker-Lewis Index (TLI)                       0.993       0.984
                                                                  
  Robust Comparative Fit Index (CFI)                         0.991
  Robust Tucker-Lewis Index (TLI)                            0.986

Loglikelihood and Information Criteria:

  Loglikelihood user model (H0)              -1547.791   -1547.791
  Scaling correction factor                                  1.012
      for the MLR correction                                      
  Loglikelihood unrestricted model (H1)      -1528.728   -1528.728
  Scaling correction factor                                  0.964
      for the MLR correction                                      
                                                                  
  Akaike (AIC)                                3157.582    3157.582
  Bayesian (BIC)                              3229.424    3229.424
  Sample-size adjusted Bayesian (SABIC)       3131.720    3131.720

Root Mean Square Error of Approximation:

  RMSEA                                          0.035       0.049
  90 Percent confidence interval - lower         0.000       0.000
  90 Percent confidence interval - upper         0.092       0.103
  P-value H_0: RMSEA <= 0.050                    0.611       0.474
  P-value H_0: RMSEA >= 0.080                    0.114       0.202
                                                                  
  Robust RMSEA                                               0.047
  90 Percent confidence interval - lower                     0.000
  90 Percent confidence interval - upper                     0.097
  P-value H_0: Robust RMSEA <= 0.050                         0.499
  P-value H_0: Robust RMSEA >= 0.080                         0.160

Standardized Root Mean Square Residual:

  SRMR                                           0.044       0.044

Goodness of Fit Index:

  Goodness of Fit Index (GFI)                    1.000            
  90 Percent confidence interval - lower         0.959            
  90 Percent confidence interval - upper         1.000            
                                                                  
  Robust GFI                                                 0.994
  90 Percent confidence interval - lower                     0.954
  90 Percent confidence interval - upper                     1.000

Parameter Estimates:

  Standard errors                             Sandwich
  Information bread                           Observed
  Observed information based on                Hessian

Latent Variables:
                   Estimate  Std.Err  z-value  P(>|z|)
  ind60 =~                                            
    x1                1.000                           
    x2                2.180    0.145   15.044    0.000
    x3                1.819    0.140   12.950    0.000
  dem60 =~                                            
    y1                1.000                           
    y2                1.257    0.150    8.392    0.000
    y3                1.058    0.130    8.107    0.000
    y4                1.265    0.146    8.661    0.000
  dem65 =~                                            
    y5                1.000                           
    y6                1.186    0.181    6.541    0.000
    y7                1.280    0.173    7.415    0.000
    y8                1.266    0.189    6.685    0.000

Regressions:
                   Estimate  Std.Err  z-value  P(>|z|)
  dem60 ~                                             
    ind60             1.483    0.342    4.332    0.000
  dem65 ~                                             
    ind60             0.572    0.225    2.546    0.011
    dem60             0.837    0.087    9.595    0.000

Covariances:
                   Estimate  Std.Err  z-value  P(>|z|)
 .y1 ~~                                               
   .y5                0.624    0.454    1.373    0.170
 .y2 ~~                                               
   .y6                2.153    0.862    2.497    0.013
 .y3 ~~                                               
   .y7                0.795    0.615    1.292    0.196
 .y4 ~~                                               
   .y8                0.348    0.434    0.803    0.422
 .y2 ~~                                               
   .y4                1.313    0.727    1.807    0.071
 .y6 ~~                                               
   .y8                1.356    0.738    1.837    0.066

Variances:
                   Estimate  Std.Err  z-value  P(>|z|)
   .x1                0.082    0.019    4.406    0.000
   .x2                0.120    0.073    1.652    0.099
   .x3                0.467    0.083    5.632    0.000
   .y1                1.891    0.477    3.965    0.000
   .y2                7.373    1.297    5.686    0.000
   .y3                5.067    1.086    4.665    0.000
   .y4                3.148    0.793    3.968    0.000
   .y5                2.351    0.605    3.885    0.000
   .y6                4.954    0.902    5.492    0.000
   .y7                3.431    0.622    5.520    0.000
   .y8                3.254    0.900    3.615    0.000
    ind60             0.448    0.073    6.149    0.000
   .dem60             3.956    0.916    4.320    0.000
   .dem65             0.172    0.227    0.759    0.448

En la salida de MLR, lavaan escribe Estimator ML, pero en Standard errors aparece Sandwich y el ji-cuadrado tiene una columna Scaled con la corrección Yuan-Bentler. Eso confirma que la estimación robusta se aplicó.

6.3 Tabla resumen de los índices de ajuste

ind_ml  <- fitMeasures(fit_ml,  c("chisq", "df", "pvalue", "cfi", "tli", "rmsea",
                                  "rmsea.ci.lower", "rmsea.ci.upper", "srmr"))
ind_mlr <- fitMeasures(fit_mlr, c("chisq.scaled", "df", "pvalue.scaled", "cfi.robust",
                                  "tli.robust", "rmsea.robust", "rmsea.ci.lower.robust",
                                  "rmsea.ci.upper.robust", "srmr"))
tabla_ajuste <- data.frame(
  Indice   = c("Chi-cuadrado", "gl", "p-valor", "CFI", "TLI", "RMSEA",
               "RMSEA IC90 inf.", "RMSEA IC90 sup.", "SRMR"),
  ML       = round(as.numeric(ind_ml), 3),
  MLR      = round(as.numeric(ind_mlr), 3),
  Criterio = c("—", "—", "> 0.05", "≥ 0.95", "≥ 0.95", "≤ 0.06",
               "—", "≤ 0.10", "≤ 0.08")
)
tabla_ajuste
Indice ML MLR Criterio
Chi-cuadrado 38.125 41.401 —
gl 35.000 35.000 —
p-valor 0.329 0.211 > 0.05
CFI 0.995 0.991 ≥ 0.95
TLI 0.993 0.986 ≥ 0.95
RMSEA 0.035 0.047 ≤ 0.06
RMSEA IC90 inf. 0.000 0.000 —
RMSEA IC90 sup. 0.092 0.097 ≤ 0.10
SRMR 0.044 0.044 ≤ 0.08

Interpretación del ajuste global:

Índice ML MLR Lectura
χ² (gl = 35) 38.13, p = 0.329 41.40, p = 0.211 No se rechaza H0: el modelo reproduce bien la matriz de covarianzas observada.
Factor de escala — 0.921 Es < 1, así que el χ² robusto es mayor (38.13 / 0.921 = 41.40). Esto ocurre con curtosis negativa: ML era algo optimista.
CFI / TLI 0.995 / 0.993 0.991 / 0.986 Ambos superan 0.95: ajuste excelente frente al modelo nulo.
RMSEA 0.035 [0.000, 0.092] 0.047 [0.000, 0.097] Está por debajo de 0.05: buen ajuste. El IC es amplio porque la muestra es pequeña (n = 75).
SRMR 0.044 0.044 Es menor que 0.08, así que los residuos son pequeños. No cambia con MLR porque no depende de la distribución.

Conclusión: el modelo ajusta bien con los dos estimadores. MLR empeora un poco los índices (es más conservador), pero ninguna conclusión cambia.

Otros elementos de la salida:

  • Baseline model (χ² = 730.65, gl = 55): es el modelo de independencia, donde todas las variables están incorreladas. Sirve de referencia para calcular CFI y TLI.
  • AIC/BIC (3157.6 / 3229.4): solo sirven para comparar modelos alternativos con los mismos datos. Por sí solos no indican si el ajuste es bueno.
  • Varianza residual de dem65 = 0.172 (p = 0.42): casi toda la varianza de dem65 queda explicada por el modelo (ver R² más abajo).

6.4 Parámetros y errores estándar

cat("\n--- PARÁMETROS Y ERRORES ESTÁNDAR: ML CLÁSICO ---\n")

--- PARÁMETROS Y ERRORES ESTÁNDAR: ML CLÁSICO ---
parameterEstimates(fit_ml)[1:15, c("lhs", "op", "rhs", "est", "se", "z", "pvalue")]
lhs op rhs est se z pvalue
ind60 =~ x1 1.0000000 0.0000000 NA NA
ind60 =~ x2 2.1803677 0.1385093 15.741673 0.0000000
ind60 =~ x3 1.8185113 0.1519581 11.967187 0.0000000
dem60 =~ y1 1.0000000 0.0000000 NA NA
dem60 =~ y2 1.2567465 0.1824396 6.888561 0.0000000
dem60 =~ y3 1.0577168 0.1513832 6.987017 0.0000000
dem60 =~ y4 1.2647865 0.1450062 8.722292 0.0000000
dem65 =~ y5 1.0000000 0.0000000 NA NA
dem65 =~ y6 1.1856963 0.1688104 7.023833 0.0000000
dem65 =~ y7 1.2795122 0.1599016 8.001871 0.0000000
dem65 =~ y8 1.2659470 0.1581111 8.006691 0.0000000
dem60 ~ ind60 1.4830005 0.3991486 3.715409 0.0002029
dem65 ~ ind60 0.5723362 0.2213138 2.586085 0.0097073
dem65 ~ dem60 0.8373448 0.0983510 8.513845 0.0000000
y1 ~~ y5 0.6236711 0.3583202 1.740541 0.0817641
cat("\n--- PARÁMETROS Y ERRORES ESTÁNDAR: ML ROBUSTO (MLR) ---\n")

--- PARÁMETROS Y ERRORES ESTÁNDAR: ML ROBUSTO (MLR) ---
parameterEstimates(fit_mlr)[1:15, c("lhs", "op", "rhs", "est", "se", "z", "pvalue")]
lhs op rhs est se z pvalue
ind60 =~ x1 1.0000000 0.0000000 NA NA
ind60 =~ x2 2.1803677 0.1449333 15.043938 0.0000000
ind60 =~ x3 1.8185113 0.1404273 12.949841 0.0000000
dem60 =~ y1 1.0000000 0.0000000 NA NA
dem60 =~ y2 1.2567465 0.1497619 8.391631 0.0000000
dem60 =~ y3 1.0577168 0.1304706 8.106933 0.0000000
dem60 =~ y4 1.2647865 0.1460343 8.660887 0.0000000
dem65 =~ y5 1.0000000 0.0000000 NA NA
dem65 =~ y6 1.1856963 0.1812746 6.540884 0.0000000
dem65 =~ y7 1.2795122 0.1725670 7.414582 0.0000000
dem65 =~ y8 1.2659470 0.1893766 6.684813 0.0000000
dem60 ~ ind60 1.4830005 0.3423342 4.332025 0.0000148
dem65 ~ ind60 0.5723362 0.2247623 2.546407 0.0108838
dem65 ~ dem60 0.8373448 0.0872734 9.594504 0.0000000
y1 ~~ y5 0.6236711 0.4543482 1.372672 0.1698543

Cómo leer las tablas. est es la estimación no estandarizada, se su error estándar, z = est/se el estadístico de Wald y pvalue prueba H0: parámetro = 0. Las filas 1, 4 y 8 tienen se = 0 y z = NA porque son las cargas fijadas en 1 para escalar cada latente.

Puntos clave:

  1. La columna est es idéntica en ML y MLR. Era lo esperado: MLR no cambia las estimaciones, solo su precisión.
  2. Cargas factoriales: todas son significativas (p < 0.001) con los dos métodos. Por ejemplo, x2 = 2.18: un aumento de 1 unidad en ind60 se asocia con 2.18 unidades más de consumo de energía.
  3. Efectos estructurales:
    • ind60 → dem60 = 1.483 (p < 0.001): los países más industrializados en 1960 eran más democráticos.
    • ind60 → dem65 = 0.572 (p ≈ 0.01): la industrialización tiene un efecto directo adicional en 1965, aun controlando la democracia previa.
    • dem60 → dem65 = 0.837 (p < 0.001): fuerte estabilidad temporal de la democracia.
  4. Covarianza residual y1 ~~ y5: con ML, p = 0.082. Con MLR el error estándar sube de 0.358 a 0.454 y p = 0.170. Ninguno de los dos es significativo al 5 %, pero MLR la aleja todavía más del umbral.

6.5 Gráfica: errores estándar ML vs. MLR

pe_ml  <- parameterEstimates(fit_ml)
pe_mlr <- parameterEstimates(fit_mlr)
comp <- data.frame(param = paste(pe_ml$lhs, pe_ml$op, pe_ml$rhs),
                   se_ml = pe_ml$se, se_mlr = pe_mlr$se,
                   p_ml = pe_ml$pvalue, p_mlr = pe_mlr$pvalue)
comp <- subset(comp, se_ml > 0)
comp$ratio <- comp$se_mlr / comp$se_ml
comp <- comp[order(comp$ratio), ]

par(mar = c(4.5, 10, 3, 2))
cols <- ifelse(comp$ratio > 1, "#de2d26", "#3182bd")
barplot(comp$ratio - 1, names.arg = comp$param, horiz = TRUE, las = 1,
        col = cols, border = NA, cex.names = 0.75,
        xlab = "Cambio relativo del error estándar (SE MLR / SE ML − 1)",
        main = "¿Cuánto cambia el error estándar al usar MLR?",
        axes = FALSE)
ejes <- seq(-0.3, 0.4, 0.1)
axis(1, at = ejes, labels = paste0(ejes * 100, "%"))
abline(v = 0, lwd = 2)
legend("bottomright", c("MLR mayor (ML subestimaba)", "MLR menor (ML sobreestimaba)"),
       fill = c("#de2d26", "#3182bd"), border = NA, bty = "n", cex = 0.85)

Interpretación de la gráfica. Cada barra muestra cuánto cambia el error estándar al pasar de ML a MLR.

  • Barras rojas (a la derecha): ML subestimaba la incertidumbre. Es el caso de y6 ~~ y8 (+30 %), y1 ~~ y5 (+27 %), las cargas de y8, y6 y y7 y la varianza de y8. En estos parámetros, confiar en ML lleva a falsos positivos (significancias infladas).
  • Barras azules (a la izquierda): ML sobreestimaba el error, así que era conservador. Es el caso de y2 (−18 %), y3 (−14 %), ind60 → dem60 (−14 %) y dem60 → dem65 (−11 %). Con MLR estos efectos salen aún más significativos.
  • Los cambios van en ambas direcciones: no hay un sesgo uniforme. Por eso no basta con “inflar” todos los errores y hace falta una corrección como la sándwich.
cambios <- comp[(comp$p_ml < 0.05) != (comp$p_mlr < 0.05),
                c("param", "se_ml", "se_mlr", "p_ml", "p_mlr")]
cambios[, -1] <- round(cambios[, -1], 3)
cambios
param se_ml se_mlr p_ml p_mlr
20 y6 ~~ y8 0.568 0.738 0.017 0.066

Parámetros cuya significancia cambia (α = 0.05): la tabla muestra que la covarianza y6 ~~ y8 es significativa con ML (p = 0.017) y deja de serlo con MLR (p = 0.066). Es la consecuencia práctica más importante de ignorar la no normalidad: con ML se habría concluido que existe un efecto de método entre y6 y y8 en 1965, y con la corrección robusta esa evidencia no alcanza.

6.6 Soluciones estandarizadas y R²

standardizedSolution(fit_ml)[1:14, c("lhs", "op", "rhs", "est.std", "pvalue")]
lhs op rhs est.std pvalue
ind60 =~ x1 0.9198529 0.0000000
ind60 =~ x2 0.9730326 0.0000000
ind60 =~ x3 0.8721386 0.0000000
dem60 =~ y1 0.8504259 0.0000000
dem60 =~ y2 0.7171221 0.0000000
dem60 =~ y3 0.7223496 0.0000000
dem60 =~ y4 0.8457095 0.0000000
dem65 =~ y5 0.8080175 0.0000000
dem65 =~ y6 0.7460071 0.0000000
dem65 =~ y7 0.8236734 0.0000000
dem65 =~ y8 0.8278413 0.0000000
dem60 ~ ind60 0.4467130 0.0000154
dem65 ~ ind60 0.1822593 0.0096761
dem65 ~ dem60 0.8852290 0.0000000
round(inspect(fit_ml, "r2"), 3)
   x1    x2    x3    y1    y2    y3    y4    y5    y6    y7    y8 dem60 dem65 
0.846 0.947 0.761 0.723 0.514 0.522 0.715 0.653 0.557 0.678 0.685 0.200 0.961 

Interpretación:

  • Cargas estandarizadas entre 0.72 y 0.97. Todos los indicadores son buenas medidas de su constructo (criterio habitual: > 0.70).
  • R² de los indicadores (fiabilidad individual): de 0.51 (y2) a 0.95 (x2). Por ejemplo, ind60 explica el 95 % de la varianza del consumo de energía.
  • R² de dem60 = 0.20: la industrialización explica el 20 % de la variabilidad en democracia de 1960. Es una relación real pero moderada, así que otros factores (cultura, historia, instituciones) también influyen.
  • R² de dem65 = 0.96: la democracia de 1965 está casi totalmente explicada por la de 1960 (β = 0.89) y la industrialización (β = 0.18). Esto refleja la gran inercia de los regímenes políticos en el corto plazo.

6.7 Efecto total de la industrialización sobre la democracia de 1965

modelo_efectos <- paste(modelo_bollen, '
  dem60 ~ a*ind60
  dem65 ~ c*ind60 + b*dem60
  indirecto := a*b
  total     := c + a*b
')
fit_ef <- sem(modelo_efectos, data = datos_bollen, estimator = "MLR")
subset(parameterEstimates(fit_ef, standardized = TRUE), op == ":=",
       select = c(lhs, est, se, z, pvalue, std.all))
lhs est se z pvalue std.all
35 indirecto 1.241783 0.3404644 3.647321 2.65e-04 0.3954433
36 total 1.814119 0.4019225 4.513604 6.40e-06 0.5777026

Interpretación. La industrialización afecta a la democracia de 1965 por dos vías:

  • Directa (c): β estandarizado = 0.18.
  • Indirecta a través de dem60 (a·b): β = 0.447 × 0.885 ≈ 0.40, significativa (p < 0.001).
  • Total ≈ 0.58: casi el 70 % del efecto de la industrialización sobre la democracia de 1965 pasa por el nivel de democracia previo.

7 Conclusiones

  1. Normalidad: los indicadores de industrialización (x1–x3) son normales, pero los ocho indicadores de democracia (y1–y8) no lo son (Shapiro-Wilk con p < 0.05, curtosis negativa y distribuciones bimodales por escalas acotadas). La prueba de Mardia confirma que no hay normalidad multivariada.
  2. Ajuste del modelo: el modelo de Bollen ajusta muy bien con ML (χ²(35) = 38.13, p = 0.33; CFI = 0.995; RMSEA = 0.035; SRMR = 0.044) y con MLR (χ²YB(35) = 41.40, p = 0.21; CFIrob = 0.991; RMSEArob = 0.047).
  3. ML vs. MLR: las estimaciones puntuales son idénticas. Los errores estándar cambian entre −18 % y +30 %, en ambas direcciones. El χ² robusto es algo mayor (factor de escala 0.921), así que ML era ligeramente optimista.
  4. Impacto sustantivo: los efectos estructurales (ind60 → dem60, ind60 → dem65, dem60 → dem65) y todas las cargas siguen siendo significativos con MLR. La única conclusión que cambia es la covarianza residual y6 ~~ y8, que deja de ser significativa.
  5. Conclusión teórica: la industrialización de 1960 favorece la democracia de forma directa e indirecta, y la democracia es muy estable entre 1960 y 1965.
  6. Recomendación metodológica: cuando los datos no son normales, como aquí, conviene reportar MLR (o bootstrap), porque sus errores estándar y su ji-cuadrado son válidos aunque no se cumpla el supuesto de normalidad.

8 Referencias

  • Bollen, K. A. (1989). Structural Equations with Latent Variables. Wiley.
  • Rosseel, Y. (2012). lavaan: An R package for structural equation modeling. Journal of Statistical Software, 48(2), 1–36.
  • Yuan, K.-H., & Bentler, P. M. (2000). Three likelihood-based methods for mean and covariance structure analysis with nonnormal missing data. Sociological Methodology, 30, 165–200.
  • Hu, L., & Bentler, P. M. (1999). Cutoff criteria for fit indexes in covariance structure analysis. Structural Equation Modeling, 6(1), 1–55.