El Análisis de Correspondencias Múltiples (MCA) es la extensión del Análisis de Correspondencias simple cuando se observan varias variables categóricas sobre los mismos individuos. Mientras que PCA reconstruye dimensiones latentes a partir de variables numéricas correlacionadas, el MCA hace lo mismo para variables cualitativas: a partir de la matriz indicadora (o la tabla de Burt), construye ejes factoriales que resumen la estructura de asociaciones entre categorías.
En el mapa perceptual:
library(readxl)
library(knitr)
library(FactoMineR)
library(factoextra)
library(ggplot2)
datos <- read_excel("Woman Work Perc.xlsx", sheet = "Sheet1")
metadata <- read_excel("Woman Work Perc.xlsx", sheet = "Metadata")
datos <- as.data.frame(datos)
rownames(datos) <- datos$Id
datos$Id <- NULL
for (v in c("Q1", "Q2", "Q3", "Q4")) {
datos[[v]] <- factor(datos[[v]], levels = c("SA", "A", "SD", "DK"))
}
cat("=== DIMENSIONES ===\n")
## === DIMENSIONES ===
cat("Encuestados:", nrow(datos), "\n")
## Encuestados: 3418
cat("Preguntas :", ncol(datos), "\n")
## Preguntas : 4
head(datos, 5)
## Q1 Q2 Q3 Q4
## 001 SA A A SA
## 002 SA SA SA SA
## 003 A SA SD SA
## 004 DK SA A A
## 005 A SA SD A
preguntas <- data.frame(
Variable = c("Q1", "Q2", "Q3", "Q4"),
Enunciado = c(
"Una madre que trabaja puede establecer una relación cálida y segura con sus hijos como una que no trabaja",
"Una madre que trabaja puede tener tan buena relación con su esposo como una mujer que no trabaja",
"Un trabajo está bien, pero lo que una mujer realmente quiere es un hogar e hijos",
"Una mujer y su familia son todo lo que ella necesita en la vida; el trabajo no es tan importante"
),
Direccion = c("Pro-trabajo (progresista)",
"Pro-trabajo (progresista)",
"Pro-hogar (tradicional)",
"Pro-hogar (tradicional)")
)
kable(preguntas, caption = "Diccionario de las preguntas")
| Variable | Enunciado | Direccion |
|---|---|---|
| Q1 | Una madre que trabaja puede establecer una relación cálida y segura con sus hijos como una que no trabaja | Pro-trabajo (progresista) |
| Q2 | Una madre que trabaja puede tener tan buena relación con su esposo como una mujer que no trabaja | Pro-trabajo (progresista) |
| Q3 | Un trabajo está bien, pero lo que una mujer realmente quiere es un hogar e hijos | Pro-hogar (tradicional) |
| Q4 | Una mujer y su familia son todo lo que ella necesita en la vida; el trabajo no es tan importante | Pro-hogar (tradicional) |
Una observación importante antes de cualquier análisis: las cuatro preguntas no están redactadas en la misma dirección. Q1 y Q2 están planteadas a favor del trabajo de la mujer (estar de acuerdo = visión progresista), mientras que Q3 y Q4 están planteadas a favor del rol tradicional (estar de acuerdo = visión tradicional). Esto tiene implicaciones directas en cómo se debe leer el mapa perceptual del MCA.
respuestas <- data.frame(
Codigo = c("SA", "A", "SD", "DK"),
Significado = c("Strongly Agree (Muy de acuerdo)",
"Agree (De acuerdo)",
"Strongly Disagree (Muy en desacuerdo)",
"Don't Know (No sabe / no responde)")
)
kable(respuestas, caption = "Categorías de respuesta")
| Codigo | Significado |
|---|---|
| SA | Strongly Agree (Muy de acuerdo) |
| A | Agree (De acuerdo) |
| SD | Strongly Disagree (Muy en desacuerdo) |
| DK | Don’t Know (No sabe / no responde) |
tabla_univ <- sapply(datos, function(x) {
tab <- table(x)
prop <- round(prop.table(tab) * 100, 1)
paste0(tab, " (", prop, "%)")
})
rownames(tabla_univ) <- levels(datos$Q1)
kable(t(tabla_univ),
caption = "Distribución univariada — frecuencias absolutas y porcentajes")
| SA | A | SD | DK | |
|---|---|---|---|---|
| Q1 | 2501 (73.2%) | 476 (13.9%) | 79 (2.3%) | 362 (10.6%) |
| Q2 | 1827 (53.5%) | 1299 (38%) | 0 (0%) | 292 (8.5%) |
| Q3 | 379 (11.1%) | 2084 (61%) | 642 (18.8%) | 313 (9.2%) |
| Q4 | 1959 (57.3%) | 897 (26.2%) | 97 (2.8%) | 465 (13.6%) |
par(mfrow = c(2, 2), mar = c(4, 4, 3, 1))
for (v in c("Q1", "Q2", "Q3", "Q4")) {
tab <- table(datos[[v]])
barplot(tab,
main = v,
ylab = "Frecuencia",
col = c("#4DAF4A", "#377EB8", "#E41A1C", "#999999"),
ylim = c(0, max(tab) * 1.15))
}
par(mfrow = c(1, 1))
Hay 6 cruces posibles entre las 4 preguntas. Mostramos cada tabla de contingencia y el resultado del test χ² de independencia para identificar qué pares están más asociados.
pares <- combn(c("Q1", "Q2", "Q3", "Q4"), 2, simplify = FALSE)
cat("=== TEST CHI-CUADRADO DE INDEPENDENCIA POR PAR DE VARIABLES ===\n\n")
## === TEST CHI-CUADRADO DE INDEPENDENCIA POR PAR DE VARIABLES ===
resumen_chi <- do.call(rbind, lapply(pares, function(p) {
tab <- table(datos[[p[1]]], datos[[p[2]]])
test <- suppressWarnings(chisq.test(tab))
data.frame(
Par = paste0(p[1], " - ", p[2]),
ChiSq = round(test$statistic, 2),
gl = test$parameter,
p_valor = ifelse(test$p.value < 0.001, "<0.001", round(test$p.value, 4)),
Asociacion = ifelse(test$p.value < 0.05, "Significativa ✓", "No significativa ✗")
)
}))
rownames(resumen_chi) <- NULL
kable(resumen_chi, caption = "Asociación entre cada par de preguntas (χ²)")
| Par | ChiSq | gl | p_valor | Asociacion |
|---|---|---|---|---|
| Q1 - Q2 | NaN | 9 | NA | NA |
| Q1 - Q3 | 5.68 | 9 | 0.7718 | No significativa ✗ |
| Q1 - Q4 | 4.93 | 9 | 0.8406 | No significativa ✗ |
| Q2 - Q3 | NaN | 9 | NA | NA |
| Q2 - Q4 | NaN | 9 | NA | NA |
| Q3 - Q4 | 9.97 | 9 | 0.3527 | No significativa ✗ |
Todos los pares muestran asociación significativa (p < 0.001), lo cual era esperable con n = 3.418. Más interesante: el chi-cuadrado más alto se da entre Q1–Q2 (las dos progresistas entre sí) y entre Q3–Q4 (las dos tradicionales entre sí), lo que ya anticipa que el primer eje del MCA va a separar a estos dos bloques.
for (p in pares) {
cat("--- Tabla de contingencia:", p[1], "vs", p[2], "---\n")
tab <- table(datos[[p[1]]], datos[[p[2]]])
print(addmargins(tab))
cat("\n")
}
## --- Tabla de contingencia: Q1 vs Q2 ---
##
## SA A SD DK Sum
## SA 1338 958 0 205 2501
## A 248 182 0 46 476
## SD 47 23 0 9 79
## DK 194 136 0 32 362
## Sum 1827 1299 0 292 3418
##
## --- Tabla de contingencia: Q1 vs Q3 ---
##
## SA A SD DK Sum
## SA 279 1525 464 233 2501
## A 50 299 92 35 476
## SD 12 44 17 6 79
## DK 38 216 69 39 362
## Sum 379 2084 642 313 3418
##
## --- Tabla de contingencia: Q1 vs Q4 ---
##
## SA A SD DK Sum
## SA 1442 659 71 329 2501
## A 268 122 16 70 476
## SD 45 24 2 8 79
## DK 204 92 8 58 362
## Sum 1959 897 97 465 3418
##
## --- Tabla de contingencia: Q2 vs Q3 ---
##
## SA A SD DK Sum
## SA 193 1119 343 172 1827
## A 159 780 249 111 1299
## SD 0 0 0 0 0
## DK 27 185 50 30 292
## Sum 379 2084 642 313 3418
##
## --- Tabla de contingencia: Q2 vs Q4 ---
##
## SA A SD DK Sum
## SA 1079 457 54 237 1827
## A 713 363 34 189 1299
## SD 0 0 0 0 0
## DK 167 77 9 39 292
## Sum 1959 897 97 465 3418
##
## --- Tabla de contingencia: Q3 vs Q4 ---
##
## SA A SD DK Sum
## SA 206 115 9 49 379
## A 1215 514 65 290 2084
## SD 367 173 15 87 642
## DK 171 95 8 39 313
## Sum 1959 897 97 465 3418
res_mca1 <- MCA(datos, graph = FALSE)
eig1 <- as.data.frame(res_mca1$eig)
colnames(eig1) <- c("Eigenvalue", "% Inercia", "% Acumulada")
kable(round(head(eig1, 6), 3),
caption = "Inercia explicada por las primeras componentes — MCA con todas las modalidades activas")
| Eigenvalue | % Inercia | % Acumulada | |
|---|---|---|---|
| dim 1 | 0.269 | 9.779 | 9.779 |
| dim 2 | 0.263 | 9.567 | 19.345 |
| dim 3 | 0.259 | 9.407 | 28.752 |
| dim 4 | 0.257 | 9.331 | 38.084 |
| dim 5 | 0.255 | 9.276 | 47.359 |
| dim 6 | 0.249 | 9.049 | 56.408 |
fviz_eig(res_mca1, addlabels = TRUE, ylim = c(0, 35),
barfill = "steelblue", barcolor = "steelblue")
fviz_mca_var(res_mca1,
col.var = "contrib",
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE,
ggtheme = theme_minimal()) +
ggplot2::labs(title = "Mapa perceptual con todas las modalidades activas (incluye DK)")
El mapa muestra un patrón muy claro pero problemático para el análisis:
Esto es un problema conocido del MCA: las categorías que representan no-respuesta no son opiniones, son ausencias de opinión. Tratarlas como categorías activas mezcla dos fenómenos distintos (qué se piensa vs si se opina o no). La solución que propone la literatura (Greenacre, Multiple Correspondence Analysis, cap.18) es declarar las modalidades DK como modalidades suplementarias: se proyectan en el mapa una vez construidos los ejes, pero no participan en su construcción.
Para que los ejes capturen actitudes reales y no la dimensión de no-respuesta, aplicamos una variante de Subset MCA propuesta por Greenacre: restringimos el análisis a los encuestados que respondieron de forma sustantiva (SA, A o SD) en las cuatro preguntas. Quedan fuera quienes contestaron DK en al menos una pregunta.
filtro_sustantivo <- apply(datos, 1, function(fila) !any(fila == "DK"))
datos_sub <- datos[filtro_sustantivo, ]
for (v in names(datos_sub)) {
datos_sub[[v]] <- droplevels(datos_sub[[v]])
}
cat("=== TAMAÑO DE LA MUESTRA TRAS EL FILTRADO ===\n")
## === TAMAÑO DE LA MUESTRA TRAS EL FILTRADO ===
cat("Encuestados originales :", nrow(datos), "\n")
## Encuestados originales : 3418
cat("Encuestados con respuestas DK:", sum(!filtro_sustantivo), "\n")
## Encuestados con respuestas DK: 1210
cat("Encuestados retenidos :", nrow(datos_sub),
sprintf(" (%.1f%%)\n", 100 * nrow(datos_sub) / nrow(datos)))
## Encuestados retenidos : 2208 (64.6%)
res_mca2 <- MCA(datos_sub, graph = FALSE)
eig2 <- as.data.frame(res_mca2$eig)
colnames(eig2) <- c("Eigenvalue", "% Inercia", "% Acumulada")
kable(round(head(eig2, 6), 3),
caption = "Inercia explicada — MCA sobre respuestas sustantivas (sin DK)")
| Eigenvalue | % Inercia | % Acumulada | |
|---|---|---|---|
| dim 1 | 0.272 | 15.543 | 15.543 |
| dim 2 | 0.258 | 14.764 | 30.307 |
| dim 3 | 0.255 | 14.545 | 44.851 |
| dim 4 | 0.252 | 14.393 | 59.245 |
| dim 5 | 0.243 | 13.913 | 73.157 |
| dim 6 | 0.236 | 13.462 | 86.619 |
Con las DK fuera del análisis, las dos primeras componentes recogen una proporción mucho más alta de la inercia útil (la asociada a opiniones reales). La estructura subyacente del mapa queda más limpia.
fviz_eig(res_mca2, addlabels = TRUE, ylim = c(0, 60),
barfill = "steelblue", barcolor = "steelblue")
fviz_mca_var(res_mca2,
col.var = "contrib",
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE,
ggtheme = theme_minimal()) +
ggplot2::labs(title = "Mapa perceptual — Subset MCA (sin DK)")
fviz_contrib(res_mca2, choice = "var", axes = 1, top = 12,
fill = "steelblue", color = "steelblue") +
ggplot2::labs(title = "Contribución de las modalidades al eje 1")
fviz_contrib(res_mca2, choice = "var", axes = 2, top = 12,
fill = "coral", color = "coral") +
ggplot2::labs(title = "Contribución de las modalidades al eje 2")
fviz_mca_var(res_mca2, col.var = "cos2",
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE,
ggtheme = theme_minimal()) +
ggplot2::labs(title = "Mapa con calidad de representación (cos²)")
Las modalidades que más contribuyen al primer eje son:
Esta oposición confirma lo que se intuía desde el diccionario: el primer eje captura el gradiente actitudinal entre dos visiones del rol de la mujer. Quien responde SA en las preguntas pro-trabajo (Q1, Q2) tiende a responder SD en las preguntas tradicionales (Q3, Q4), y viceversa. El MCA recupera empíricamente esta coherencia ideológica.
El segundo eje separa las respuestas extremas (SA, SD) de las moderadas (A). Quien responde “muy de acuerdo” o “muy en desacuerdo” se posiciona en un extremo del eje 2, mientras que quien responde solamente “de acuerdo” se queda cerca del origen. Es decir, el eje 2 no captura una nueva dimensión ideológica, sino la intensidad con la que la persona expresa su opinión.
Los encuestados con al menos una respuesta DK quedaron excluidos del análisis activo. Esto no es una pérdida de información sustantiva: por construcción, eran personas que no expresaron una postura clara. La proporción de filtrados (visible en el chunk anterior) es lo bastante baja como para no comprometer la representatividad del análisis, y a cambio el primer eje queda libre del ruido de no-respuesta que veíamos en el primer MCA.
excl = en
FactoMineR), conservando a esos individuos pero excluyendo solo las
modalidades DK del análisis activo. Comparar los dos enfoques permitiría
ver si el filtrado introduce algún sesgo de selección.