Parte 3 - Análisis de Correspondencias Simple (CA)
Introducción
El análisis de correspondencias (CA) es una técnica de interdependencia cuyo objetivo es la representación geométrica de las relaciones bidimensionales derivadas de una tabla de contingencia.
El análisis de correspondencias trabaja con variables categóricas o no métricas (frecuencias, recuentos) y permite pasar del aparente caos de una tabla muy grande para que visualmente se aprecien relaciones entre los datos a la claridad de un mapa. Su principal ventaja es que ayuda a visualizar la asociación o similitud entre los niveles de las variables de fila y columna basándose en el concepto de distancia (distancia \(\chi^2\)).
Antes de adentrarnos en el desarrollo de la técnica, vamos a recordar, ajustar unos conceptos ya conocidos, pero que aquí toman una gran relevancia para el entendimiento de la técnica.
Tabla de frecuencias
Antes de abordar la ejecución matemática y visual del análisis de correspondencias, es fundamental repasar cuatro conceptos estadísticos sobre los que se asiente esta técnica:
- Frecuencia observada y esperada: la frecuencia observada es el recuento real de casos empíricos en la tabla de contingencia (las respuestas directas de la encuesta). La frecuencia esperada, por su parte, es el recuento teórico que debería encontrarse en cada celda si no existiera absolutamente ninguna relación (independencia estadística) entre las variables de fila y columna.
- Residuo: es la diferencia matemática entre lo observado en la realidad y lo esperado de forma teórica. Un residuo positivo señala una “atracción” o asociación mayor de lo normal entre dos categorías, mientras que un residuo negativo indica una falta de vinculación o “repulsión”.
- Prueba \(\chi^2\) (Chi-cuadrado): es el contraste estadístico que evalúa el conjunto total de los residuos de la tabla. Permite confirmar si las discrepancias entre lo observado y lo esperado son lo suficientemente grandes como para descartar que sean fruto del azar, validando así que existe una asociación significativa en el mercado.
Mapa cartesiano
Por otro lado, tenemos los mapas:
- Un mapa cartesiano: consiste en la proyección geométrica bidimensional (el plano formado por los ejes coordenados) de las relaciones ocultas en la tabla de contingencia. En este mapa, la inercia y los residuos se traducen en distancias y ángulos, lo que permite leer visualmente el posicionamiento competitivo de forma intuitiva.
Algunas consideraciones sobre la representación gráfica de dos variables en un plano cartesiano. Un mapa cartesiano tiene dos ejes principales. Si hablamos de geografía:
- X -> latitud
- Y -> longitud
X no tiene por qué estar medida en la misma escala que Y, de modo que solo se interpretan distancias relativas, no valores absolutos.
Bien a título de ejemplo y como ilustración de lo que luego veremos, vamos a reflexionar sobre este ejemplo. Pensemos en un mapa geográfico …
- ¿Qué muestra? Distancias
- ¿Qué unidad de medida presenta? kilómetros pero con gradaciones
- ¿Podríamos a partir de las distancias kilométricas crear un mapa?
Es el ejemplo clásico de “a partir de las distancias entre ciudades, reconstruir su mapa”:
Existe una función denominada stats::cmdscale() (escalado multidimensional o MDS) permite reconstruir un mapa de posiciones relativas a partir, únicamente, de una matriz de distancias entre puntos.
$names
[1] "points" "eig" "x" "ac" "GOF"
Una vez tenemos las coordenadas, que es la parte mágica de cálculo, ya todo es más simple. Solo debemos buscar la forma de hacer un gráfico de puntos X,Y.
Estamos listos, hemos sentado las bases para entender nuestra primera técnica avanzada.
La práctica del CA
Supongamos la siguiente situación para la empresa imaginaria HATCO, donde existe un problema desde la perspectiva del Director de Marketing de HATCO, que ha identificado 9 competidores principales (empresas A a I) y ha pedido a sus clientes que asocien a estas empresas (incluyendo HATCO) con 8 atributos competitivos:
x1: Rapidez del serviciox2: Nivel de preciosx3: Flexibilidad de preciosx4: Imagen del fabricantex5: Calidad del serviciox6: Imagen de los vendedoresx7: Calidad del productox8: Tamaño de la empresa
Cómo resultado de eestio, ¿qué tenemos? una tabla de frecuencias de este modo.
Las preguntas estratégicas que plantea el caso son:
- ¿Quiénes son los verdaderos competidores de HATCO?
- ¿En qué se diferencia HATCO?
- ¿Existe algún hueco de mercado sin cubrir?
Conviene ser cuidadoso respecto al sentido del análisis en función de la representación de los datos. En este ejemplo conviene verificar teóricamente que:
- los poseedores de los atributos son comparables respecto a esos atributos;
- las empresas A, B, …, I son efectivamente competidoras de HATCO;
- su diferenciación se basa en los atributos x1 a x8;
- el listado de atributos es exhaustivo y no deja fuera ninguno relevante para la caracterización de las empresas.
Carga de los datos en forma de tabla
A continuación se cargan las librerías necesarias y se construye la matriz de datos. En este caso, los cálculos del análisis de correspondencias se realizarán con el paquete ca (escuela de Greenacre)Una de las necesidades de este paquete es que el input sea una tabla. No basta con que sea un dataframe. Este se debe convertir a objeto de clase table.
# Build the HATCO contingency table directly as a matrix (attributes x companies)
hatco_table <- read_csv("data/hatco_table.csv")
# Need to adapt dataframe to table
hatco_table <- hatco_table %>%
column_to_rownames(var = "atributo") %>% # use first column as rownames
as.matrix() %>%
as.table()
# Show the object as table
hatco_table hatco A B C D E F G H I
x1 16 13 8 13 9 17 15 16 6 12
x2 14 14 10 11 11 14 12 13 10 14
x3 6 6 14 10 11 8 7 4 14 4
x4 15 18 9 2 3 15 16 7 8 8
x5 15 14 6 4 4 15 14 13 7 13
x6 7 18 13 4 9 16 14 5 4 16
x7 4 3 1 13 9 6 3 18 2 10
x8 15 16 15 11 11 14 16 12 14 14
Prueba de homogeneidad (Chi-cuadrado)
Antes de crear el mapa y adentrarnos en lo que es el CA, es necesario confirmar empíricamente que existe dependencia estadística entre las filas (atributos) y las columnas (empresas). La hipótesis nula (\(H_0\)) es la independencia: las empresas no se diferencian por estos atributos. Recordemos que esta prueba ya la hemos visto anteriormente como la forma en la que el investigador determina que las columnas y las filas de una tabla de contingencia y por tanto que las dos dimensiones medidas no son independientes. Si rechazamos la (\(H_0\)), estaremos afirmando que existe una relación de dependencia entre las dos dimensiones.
# Chi-square test of homogeneity on the contingency table
chi2_homogeneity <- stats::chisq.test(hatco_table)
cat("Chi-square test - Test de homogeneidad: \n")
print(chi2_homogeneity)Chi-square test - Test de homogeneidad:
Pearson's Chi-squared test
data: hatco_table
X-squared = 122.6, df = 63, p-value = 1.033e-05
Como nos iremos acostumbrando en todas las pruebas que hagamos, al obtener un p-value < 0.05, se rechaza \(H_0\), por lo que existe una asociación significativa entre las marcas y los atributos, y puede procederse a crear el mapa. Si no pudiera rechazarse la \(H_0\), ¿convendría seguir adelante? No hay una respuesta única: es probable que no aparezcan relaciones de mucho peso, pero las relaciones se representarían en el plano de igual forma.
🤔 ¿Qué marcas o qué atributos determinan las diferencias? Esta es la primera pregunta a resolver, y la respuesta comienza con el análisis de los residuos.
Análisis de residuos y su tipología
Una vez confirmado que existe una relación significativa, el primer paso es explorar los residuos. Estos representan la diferencia entre las frecuencias observadas en la muestra y las frecuencias que se esperarían encontrar si las variables fueran totalmente independientes (frecuencias esperadas).
Recordemos que tenemos creado el objeto ch2_homogeneity que tiene diferentes resultados que no hemos explorado. Uno de ellos son las frecuencias esperadas.
# Expected frequency
chi2_homogeneity$expected hatco A B C D E F
x1 13.513514 14.98237 11.163337 9.988249 9.841363 15.423032 14.247944
x2 13.297297 14.74266 10.984724 9.828437 9.683901 15.176263 14.019976
x3 9.081081 10.06816 7.501763 6.712103 6.613396 10.364277 9.574618
x4 10.918919 12.10576 9.019976 8.070505 7.951821 12.461810 11.512338
x5 11.351351 12.58519 9.377203 8.390129 8.266745 12.955347 11.968273
x6 11.459459 12.70505 9.466510 8.470035 8.345476 13.078731 12.082256
x7 7.459459 8.27027 6.162162 5.513514 5.432432 8.513514 7.864865
x8 14.918919 16.54054 12.324324 11.027027 10.864865 17.027027 15.729730
G H I
x1 12.925969 9.547591 13.366627
x2 12.719154 9.394830 13.152761
x3 8.686251 6.415981 8.982374
x4 10.444183 7.714454 10.800235
x5 10.857814 8.019976 11.227967
x6 10.961222 8.096357 11.334900
x7 7.135135 5.270270 7.378378
x8 14.270270 10.540541 14.756757
El siguiente paso, responde a la definicion de residuo directo. Diferencia entre la frecuencia observada y la esperada.
# Direct residuals: observed - expected
chi2_homogeneity$observed - chi2_homogeneity$expected hatco A B C D E
x1 2.48648649 -1.98237368 -3.16333725 3.01175088 -0.84136310 1.57696827
x2 0.70270270 -0.74265570 -0.98472385 1.17156287 1.31609871 -1.17626322
x3 -3.08108108 -4.06815511 6.49823737 3.28789659 4.38660400 -2.36427732
x4 4.08108108 5.89424207 -0.01997650 -6.07050529 -4.95182139 2.53819036
x5 3.64864865 1.41480611 -3.37720329 -4.39012926 -4.26674501 2.04465335
x6 -4.45945946 5.29494712 3.53349001 -4.47003525 0.65452409 2.92126910
x7 -3.45945946 -5.27027027 -5.16216216 7.48648649 3.56756757 -2.51351351
x8 0.08108108 -0.54054054 2.67567568 -0.02702703 0.13513514 -3.02702703
F G H I
x1 0.75205640 3.07403055 -3.54759107 -1.36662750
x2 -2.01997650 0.28084606 0.60517039 0.84723854
x3 -2.57461810 -4.68625147 7.58401880 -4.98237368
x4 4.48766157 -3.44418331 0.28554642 -2.80023502
x5 2.03172738 2.14218566 -1.01997650 1.77203290
x6 1.91774383 -5.96122209 -4.09635723 4.66509988
x7 -4.86486486 10.86486486 -3.27027027 2.62162162
x8 0.27027027 -2.27027027 3.45945946 -0.75675676
Para identificar con precisión qué celdas concretas generan la asociación, se calculan los residuos estandarizados. Estos residuos funcionan como una puntuación Z, lo que permite realizar comparaciones estadísticas directas entre celdas:
# Raw residuals from the chi-square object
round(chi2_homogeneity$residuals, 3) hatco A B C D E F G H I
x1 0.676 -0.512 -0.947 0.953 -0.268 0.402 0.199 0.855 -1.148 -0.374
x2 0.193 -0.193 -0.297 0.374 0.423 -0.302 -0.539 0.079 0.197 0.234
x3 -1.022 -1.282 2.373 1.269 1.706 -0.734 -0.832 -1.590 2.994 -1.662
x4 1.235 1.694 -0.007 -2.137 -1.756 0.719 1.323 -1.066 0.103 -0.852
x5 1.083 0.399 -1.103 -1.516 -1.484 0.568 0.587 0.650 -0.360 0.529
x6 -1.317 1.486 1.148 -1.536 0.227 0.808 0.552 -1.801 -1.440 1.386
x7 -1.267 -1.833 -2.080 3.188 1.531 -0.861 -1.735 4.067 -1.425 0.965
x8 0.021 -0.133 0.762 -0.008 0.041 -0.734 0.068 -0.601 1.066 -0.197
Cuando estos residuos se corrigen de un determinado modo, se da lugar a una puntuación Z directa donde:
- Valores > 1.96: Indican que la frecuencia observada es significativamente superior a la esperada (hay “exceso” de casos en esa celda).
- Valores < -1.96: Indican que la frecuencia observada es significativamente inferior a la esperada (hay “defecto” de casos en esa celda).
Estos valores permiten señalar las celdas que realmente “rompen” la hipótesis de independencia con un nivel de confianza del 95%.
La corrección de Haberman (1973) ajusta el residuo de Pearson estandarizado dividiéndolo por su error estándar real, que es menor que 1 (de ahí que el residuo estandarizado simple infravalore la significatividad). Esta es la corrección que hace que el residuo siga aproximadamente una distribución normal estándar (0, 1), por lo que el criterio de “significativo si |valor| > 1.96” solo es válido sobre $stdres, no sobre $residuals.
# Standardized residuals, rounded for easier interpretation
round(chi2_homogeneity$stdres, 3) hatco A B C D E F G H I
x1 0.775 -0.591 -1.074 1.076 -0.303 0.464 0.229 0.978 -1.293 -0.428
x2 0.221 -0.223 -0.337 0.421 0.476 -0.349 -0.620 0.090 0.222 0.267
x3 -1.140 -1.440 2.619 1.394 1.872 -0.826 -0.931 -1.769 3.282 -1.853
x4 1.393 1.923 -0.007 -2.373 -1.949 0.818 1.497 -1.199 0.114 -0.960
x5 1.225 0.454 -1.234 -1.688 -1.651 0.648 0.666 0.733 -0.400 0.598
x6 -1.491 1.692 1.286 -1.711 0.252 0.922 0.626 -2.032 -1.601 1.567
x7 -1.399 -2.038 -2.273 3.467 1.664 -0.960 -1.922 4.481 -1.546 1.065
x8 0.024 -0.155 0.873 -0.009 0.047 -0.856 0.079 -0.693 1.211 -0.228
Masas y perfiles: la base del cálculo de distancias
Antes de que el algoritmo calcule los ejes del mapa, el análisis de correspondencias transforma las frecuencias absolutas (los recuentos) en frecuencias relativas.
Para entender de dónde salen las coordenadas, conviene definir tres conceptos estructurales:
- Masa (Mass): es la importancia relativa o el “peso” de cada categoría respecto al total de la muestra (porcentaje sobre el gran total). En el mapa, una categoría con mucha masa tiene mayor capacidad para “tirar” del centro de gravedad hacia sí misma. Existen masas de fila (peso de cada atributo) y masas de columna (peso de cada empresa).
- Perfil de fila (Row profile): muestra cómo se distribuyen las respuestas de un atributo específico entre todas las marcas. Se calcula dividiendo la frecuencia de cada celda entre el total de su fila (es el equivalente al porcentaje de fila). La suma de cada perfil de fila siempre es 1 (o 100%).
- Perfil de columna (Column profile): indica cómo se compone la valoración de una marca específica a través de todos los atributos. Se calcula dividiendo la celda entre el total de su columna (porcentaje de columna).
Si el perfil de de una marca es idéntico al perfil medio del mercado, esa marca se sitúa exactamente en el centro del mapa (0,0).
En el análisis de correspondencias, la famosa “distancia \(\chi^2\)” no es más que la diferencia matemática entre el perfil de una categoría y el perfil promedio (su masa).
A continuación se obtienen estos cálculos matriciales en R utilizando la función prop.table() sobre la tabla de contingencia original:
Estos cálculos no son necesarios, pues los ofrecerá también el modelo (con otro formato), pero de alguna forma quiero que se entienda cual es su origen.
# View input table
hatco_table
margin.table(hatco_table)
# 1. Calculate and display masses (marginal proportions)
# Row masses: weight of each attribute
row_masses <- prop.table(margin.table(hatco_table, 1))
cat("\n\n\n--- Row Masses (Attributes) ---\n")
round(row_masses, 3)
# Column masses: weight of each company
col_masses <- prop.table(margin.table(hatco_table, 2))
cat("\n\n\n--- Column Masses (Companies) ---\n")
round(col_masses, 3)
# 2. Calculate row profiles (sum of each row = 1)
# margin = 1 indicates calculations across rows
row_profiles <- prop.table(hatco_table, margin = 1)
cat("\n\n\n--- Row Profiles | rows sum 1---\n")
round(row_profiles, 3)
# 3. Calculate column profiles (sum of each column = 1)
# margin = 2 indicates calculations down columns
col_profiles <- prop.table(hatco_table, margin = 2)
cat("\n\n\n--- Column Profiles | columns sum 1---\n")
round(col_profiles, 3) hatco A B C D E F G H I
x1 16 13 8 13 9 17 15 16 6 12
x2 14 14 10 11 11 14 12 13 10 14
x3 6 6 14 10 11 8 7 4 14 4
x4 15 18 9 2 3 15 16 7 8 8
x5 15 14 6 4 4 15 14 13 7 13
x6 7 18 13 4 9 16 14 5 4 16
x7 4 3 1 13 9 6 3 18 2 10
x8 15 16 15 11 11 14 16 12 14 14
[1] 851
--- Row Masses (Attributes) ---
x1 x2 x3 x4 x5 x6 x7 x8
0.147 0.145 0.099 0.119 0.123 0.125 0.081 0.162
--- Column Masses (Companies) ---
hatco A B C D E F G H I
0.108 0.120 0.089 0.080 0.079 0.123 0.114 0.103 0.076 0.107
--- Row Profiles | rows sum 1---
hatco A B C D E F G H I
x1 0.128 0.104 0.064 0.104 0.072 0.136 0.120 0.128 0.048 0.096
x2 0.114 0.114 0.081 0.089 0.089 0.114 0.098 0.106 0.081 0.114
x3 0.071 0.071 0.167 0.119 0.131 0.095 0.083 0.048 0.167 0.048
x4 0.149 0.178 0.089 0.020 0.030 0.149 0.158 0.069 0.079 0.079
x5 0.143 0.133 0.057 0.038 0.038 0.143 0.133 0.124 0.067 0.124
x6 0.066 0.170 0.123 0.038 0.085 0.151 0.132 0.047 0.038 0.151
x7 0.058 0.043 0.014 0.188 0.130 0.087 0.043 0.261 0.029 0.145
x8 0.109 0.116 0.109 0.080 0.080 0.101 0.116 0.087 0.101 0.101
--- Column Profiles | columns sum 1---
hatco A B C D E F G H I
x1 0.174 0.127 0.105 0.191 0.134 0.162 0.155 0.182 0.092 0.132
x2 0.152 0.137 0.132 0.162 0.164 0.133 0.124 0.148 0.154 0.154
x3 0.065 0.059 0.184 0.147 0.164 0.076 0.072 0.045 0.215 0.044
x4 0.163 0.176 0.118 0.029 0.045 0.143 0.165 0.080 0.123 0.088
x5 0.163 0.137 0.079 0.059 0.060 0.143 0.144 0.148 0.108 0.143
x6 0.076 0.176 0.171 0.059 0.134 0.152 0.144 0.057 0.062 0.176
x7 0.043 0.029 0.013 0.191 0.134 0.057 0.031 0.205 0.031 0.110
x8 0.163 0.157 0.197 0.162 0.164 0.133 0.165 0.136 0.215 0.154
Vistos por tanto los cálculos que en una tabla se pueden hacer, pasamos a realizar la estimación del modelo y a al aplicación de una primera modelización.
Estimación del modelo y resultados
El paquete ca, correspondence analysis, ofrece una salida de resultados basada en la escuela francesa, desarrollada por Michael Greenacre, uno de los autores que más ha contribuido al desarrollo de esta técnica.
# Execute Correspondence Analysis
ca_greenacre <- ca::ca(hatco_table)
# Display the summary (inertia, chi-square, and decomposition)
# This provides the 'scree plot' information in table format
summary(ca_greenacre)
Principal inertias (eigenvalues):
dim value % cum% scree plot
1 0.076541 53.1 53.1 *************
2 0.047813 33.2 86.3 ********
3 0.015291 10.6 96.9 ***
4 0.002658 1.8 98.8
5 0.000806 0.6 99.3
6 0.000576 0.4 99.7
7 0.000381 0.3 100.0
-------- -----
Total: 0.144066 100.0
Rows:
name mass qlt inr k=1 cor ctr k=2 cor ctr
1 | x1 | 147 619 41 | 107 289 22 | 115 330 40 |
2 | x2 | 145 527 8 | 61 469 7 | -21 58 1 |
3 | x3 | 99 991 231 | 23 2 1 | -578 989 689 |
4 | x4 | 119 901 132 | -356 789 196 | 133 111 44 |
5 | x5 | 123 816 70 | -106 138 18 | 235 677 142 |
6 | x6 | 125 372 129 | -232 358 87 | 46 14 6 |
7 | x7 | 81 991 367 | 792 961 665 | 139 30 33 |
8 | x8 | 162 772 22 | -43 93 4 | -115 678 45 |
Columns:
name mass qlt inr k=1 cor ctr k=2 cor ctr
1 | hatc | 108 433 62 | -130 206 24 | 137 228 42 |
2 | A | 120 928 86 | -283 772 125 | 127 156 40 |
3 | B | 89 942 115 | -233 294 63 | -346 648 224 |
4 | C | 80 975 180 | 535 882 299 | -174 93 50 |
5 | D | 79 863 88 | 268 445 74 | -260 418 111 |
6 | E | 123 812 29 | -124 456 25 | 110 356 31 |
7 | F | 114 954 52 | -232 810 80 | 98 144 23 |
8 | G | 103 963 204 | 465 762 292 | 239 201 123 |
9 | H | 76 797 128 | -109 49 12 | -425 748 289 |
10 | I | 107 446 56 | 65 55 6 | 171 390 66 |
La salida de este comando permite validar si el mapa obtenido es una representación fiel de la realidad o si se está perdiendo demasiada información.
Bloque de inercia (Principal Inertias)
Esta tabla inicial indica cuántas “capas” de información (dimensiones) tiene la tabla y cuánta importancia tiene cada una.
dim(Dimension): El número del eje. El primer eje (1) siempre es el que más información captura, el segundo (2) el siguiente, y así sucesivamente.value(Eigenvalue/Inercia): Es el valor propio de la dimensión. Representa la cantidad de varianza (inercia) que ese eje es capaz de explicar de la tabla original.%(Percentage of inertia): indica la proporción de la inercia total que captura ese eje. En investigación de mercados, se busca que los dos primeros ejes sumen un porcentaje elevado (idealmente > 70-80%).cum%(Cumulative percentage): la suma acumulada de los porcentajes anteriores. Ayuda a decidir cuántas dimensiones son necesarias para entender el fenómeno.scree plot: Una representación visual (histograma de puntos) de la importancia relativa de cada eje.
Bloque de filas y columnas (Rows / Columns)
Esta sección es crucial para entender el comportamiento de cada marca o atributo individualmente. Ambos bloques tienen las mismas columnas:
mass(Masa): Indica el peso relativo del punto en la muestra total. Una masa de0.150significa que esa categoría representa el 15% de los datos. Los puntos con mucha masa tienen más “fuerza” para atraer los ejes hacia ellos.qlt(Quality): es la calidad de representación (de 0 a 1000). Indica qué tan bien representado está ese punto en el mapa actual (usualmente las dos primeras dimensiones). Si un punto tiene unqltmuy bajo (ej. < 100), su posición en el gráfico es engañosa y no deben extraerse conclusiones estratégicas sobre él.inr(Inertia): es la contribución del punto a la inercia total de la tabla. Indica cuánto “caos” o diferenciación aporta ese punto específico al mercado. Una marca muy distinta al resto tendrá uninralto.k=1, k=2(Coordinates): Son las coordenadas exactas del punto en el eje 1 y eje 2. Es lo que R utiliza para dibujar el punto en el mapa cartesiano.cor(Correlation / Cos²): Mide la asociación entre el punto y el eje específico. Uncoralto en el eje 1 significa que ese punto es el que mejor define lo que ese eje representa (ej. el eje del precio).ctr(Contribution): indica cuánto contribuye ese punto a la construcción de ese eje concreto. Ayuda a ponerle “nombre” a los ejes (ej. “si las marcas con másctren el eje 1 son las más caras, ese eje puede denominarse ‘eje de precio’”).
Al analizar la tabla, conviene seguir este orden lógico:
- Revisar el
%acumulado para saber si un mapa de 2 dimensiones es suficiente. - Observar el
qltde las marcas de interés; si es alto, puede confiarse en su posición en el mapa. - Utilizar el
ctrpara identificar qué variables son las responsables de que el mapa tenga esa forma y no otra.
Visualización
El paquete ca incluye su propia función plot(), que permite un control muy preciso sobre el escalado (simétrico, asimétrico, etc.) de los ejes visuales. Dado que se va a representar un mapa cartesiano, es importante conocer primero las coordenadas; no se entra aquí en el detalle del cálculo matemático para su obtención.
# Inspect the column and row coordinates computed by ca()
cat("\n\n")
cat("Coordenadas de columna ============================:\n")
ca_greenacre$colcoord
cat("\n\n")
cat("Coordenadas de fila ===============================:\n")
ca_greenacre$rowcoord
cat("\n\n")
cat("\n\nRetenemos solo las que nos interesan ...\n\n")
# Inspect the column and row coordinates computed by ca() only Dim 1 & 2
cat("Coordenadas de columna 1 & 2 ======================:\n")
ca_greenacre$colcoord[,1:2]
cat("\n\n")
cat("Coordenadas de fila 1 & 2 =========================:\n")
ca_greenacre$rowcoord[,1:2]
Coordenadas de columna ============================:
Dim1 Dim2 Dim3 Dim4 Dim5 Dim6
hatco -0.4703327 0.6261240 -1.6935356 0.29465670 -1.7292066 0.4655331
A -1.0217346 0.5801388 0.5338336 -0.07823246 1.1100906 1.6894406
B -0.8432000 -1.5832948 0.7964316 0.26209544 0.2874627 -0.1659282
C 1.9333842 -0.7935744 -0.1648613 1.59150233 -0.5015929 1.0023065
D 0.9699347 -1.1891134 1.1762320 0.24157388 -0.3215290 0.1038722
E -0.4498224 0.5024514 0.2356379 1.01941582 0.2256877 -2.0473172
F -0.8381141 0.4468266 -0.2145714 0.65967745 0.3110986 0.1309981
G 1.6806871 1.0920696 -0.6758338 -0.77145803 1.5096436 -0.3224750
H -0.3922857 -1.9443407 -1.6117961 -1.83337906 0.3985224 -0.4838085
I 0.2334232 0.7842522 1.4674729 -1.62005491 -1.4611537 -0.1711086
Dim7
hatco -0.4460250
A -1.1173385
B 1.3363279
C 0.3955033
D -1.4550986
E -0.9157056
F 1.6885279
G 0.4368324
H -0.4346288
I 0.5078109
Coordenadas de fila ===============================:
Dim1 Dim2 Dim3 Dim4 Dim5 Dim6
x1 0.38833337 0.52453784 -0.48064888 2.0327480 -0.7993536 -0.3021486
x2 0.21906639 -0.09762105 -0.05138317 -0.4795627 -1.3748826 0.7323587
x3 0.08369285 -2.64119673 -0.34019450 0.2493870 0.6347806 -1.2085960
x4 -1.28554439 0.61037038 -0.89764463 0.4026826 1.7762794 0.8684848
x5 -0.38378371 1.07394894 -0.73674199 -1.3240795 -0.2697071 -1.8311119
x6 -0.83693026 0.21106121 2.47591880 0.1896399 0.1476687 -0.2958822
x7 2.86346220 0.63690241 0.48320469 -0.4465221 1.4975360 0.2144778
x8 -0.15394237 -0.52485592 -0.23761538 -0.7752912 -0.3939105 1.2342381
Dim7
x1 0.53731697
x2 -1.78938738
x3 -0.32626826
x4 -0.72333444
x5 0.28708482
x6 0.08839279
x7 -0.08239776
x8 1.59105249
Retenemos solo las que nos interesan ...
Coordenadas de columna 1 & 2 ======================:
Dim1 Dim2
hatco -0.4703327 0.6261240
A -1.0217346 0.5801388
B -0.8432000 -1.5832948
C 1.9333842 -0.7935744
D 0.9699347 -1.1891134
E -0.4498224 0.5024514
F -0.8381141 0.4468266
G 1.6806871 1.0920696
H -0.3922857 -1.9443407
I 0.2334232 0.7842522
Coordenadas de fila 1 & 2 =========================:
Dim1 Dim2
x1 0.38833337 0.52453784
x2 0.21906639 -0.09762105
x3 0.08369285 -2.64119673
x4 -1.28554439 0.61037038
x5 -0.38378371 1.07394894
x6 -0.83693026 0.21106121
x7 2.86346220 0.63690241
x8 -0.15394237 -0.52485592
Conocidas las coordenadas, se representa el mapa visual.
# Generate the base plot using the ca package, with arrows for rows and columns
plot(ca_greenacre,
main = "Mapa simétrico con vectores (paquete ca)",
map = "symmetric",
col = c("steelblue", "orange"),
col.lab = c("steelblue", "orange"),
arrows = c(TRUE, TRUE) # TRUE for rows, TRUE for columns
)Interpretación estratégica:
Al observar el mapa, el punto IDEAL suele situarse cerca del origen. Esto ocurre porque un perfil que es “bueno en todo” no presenta sesgo hacia ninguna dimensión específica: no es especialmente “barato” ni especialmente “rápido” en comparación con el resto, sino que es máximo en todos los atributos. Para HATCO, la clave no es estar necesariamente cerca del centro (donde el IDEAL se ubica por equilibrio), sino verificar que el ángulo formado entre el vector de HATCO y el del IDEAL sea lo más pequeño posible en las dimensiones que el mercado más valora.
Decálogo de interpretación del análisis de correspondencias
Al interpretar el mapa cartesiano, se aplican estas reglas fundamentales:
- El origen (0,0): representa el “perfil promedio” del mercado. Los puntos cercanos al centro son poco discriminatorios (no destacan especialmente en nada o son percibidos como la media del sector).
- Distancia al origen: cuanto más lejos está una marca o un atributo del centro, más fuerte es su diferenciación y más contribuye a la inercia del modelo.
- Proximidad intra-grupo: la proximidad física entre dos marcas (puntos del mismo color) indica que los consumidores las perciben como similares y, por tanto, como competidores directos.
- Ángulos inter-grupo (Regla de Oro): para relacionar una marca con un atributo, no basta con mirar la distancia física; se observa el ángulo que forman al trazar líneas desde el origen (0,0):
- Ángulo agudo (< 90º): fuerte asociación positiva (ej. HATCO y la empresa A están muy asociadas a los atributos x4 y x6).
- Ángulo recto (90º): independencia. La marca no destaca ni a favor ni en contra de ese atributo.
- Ángulo obtuso/llano (≈ 180º): oposición o asociación negativa. La marca se define por carecer de ese atributo (ej. la empresa G está diametralmente opuesta al atributo x3).
- Calidad de representación (
qlt): antes de interpretar la posición de un punto, conviene comprobar su calidad. Un punto mal representado en el plano bidimensional puede situarse en un lugar engañoso. Como norma general, no deben extraerse conclusiones sobre puntos conqlt< 100. - Contribución a los ejes (
ctr): los puntos con mayorctren un eje son los que “dan forma” a ese eje y permiten nombrarlo. Identificarlos es el primer paso para interpretar qué concepto subyace en cada dimensión. - Los ejes no tienen escala única: las coordenadas de filas y columnas no están en la misma unidad. La distancia entre una marca y un atributo solo puede interpretarse con la regla del ángulo, no midiendo píxeles en el mapa.
- Simetría del mapa: el mapa simétrico (
map = "symmetric") es el estándar en investigación de mercados porque coloca filas y columnas en el mismo espacio visual. Es el más intuitivo para el cliente, aunque no permite comparar distancias euclídeas entre filas y columnas directamente. - Número de dimensiones: la decisión sobre cuántos ejes retener debe basarse en el porcentaje de inercia acumulado. Un mapa de dos dimensiones que explica más del 80% de la inercia es una representación fiel; por debajo del 60%, conviene reportar con cautela.
- El mapa es un resumen, no la verdad absoluta: el análisis de correspondencias reduce la realidad multidimensional a un plano. Siempre puede existir información relevante en las dimensiones no representadas. El mapa debe complementarse con la lectura de los estadísticos numéricos (
summary()), especialmente elqlty elctr.
Diagnóstico estratégico para HATCO
A partir del mapa obtenido, pueden identificarse los siguientes patrones:
- El eje del prestigio (X-Dimensión 1 — derecha): HATCO, A, E y F dominan el cuadrante asociado a la imagen del fabricante (x4), calidad de servicio (x5) e imagen de vendedores (x6). Son las marcas premium. HATCO debe proteger esta reputación como ventaja competitiva sostenible.
- El eje de eficiencia de producto (XDimensión 1 — izquierda): la empresa G domina en solitario la calidad pura del producto (x7), distanciándose de la “imagen comercial”. Representa un posicionamiento técnico claramente diferenciado.
- El eje del precio (Y-Dimensión 2 — abajo): las empresas B y H compiten puramente en flexibilidad de precios (x3), siendo las opciones “negociadoras” o económicas del mercado.
- Oportunidades de mercado: los cuadrantes con escasa presencia de marcas pero con atributos relevantes señalan huecos estratégicos que HATCO podría evaluar para una extensión de su propuesta de valor.
Puntos suplementarios
En la investigación estratégica, a menudo resulta necesario proyectar perfiles teóricos (como el “servicio ideal” o un “competidor de referencia”) sin que estos influyan en la construcción de los ejes. En el paquete ca, esto se gestiona mediante los argumentos supcol (para columnas suplementarias) o suprow (para filas suplementarias).
A continuación se proyecta un “Competidor IDEAL” para visualizar la distancia entre la percepción actual de HATCO y la perfección teórica. El IDEAL se define como un perfil de columna con el valor máximo posible en todos los atributos (15 menciones en cada atributo), de modo que no presenta ningún sesgo hacia ninguna dimensión particular.
# Add a supplementary column 'IDEAL' with equal mentions across all attributes
hatco_extended <- as.table(matrix(
c(
16, 13, 8, 13, 9, 17, 15, 16, 6, 12, 15, #x1
14, 14, 10, 11, 11, 14, 12, 13, 10, 14, 15, #x2
6, 6, 14, 10, 11, 8, 7, 4, 14, 4, 15, #x3
15, 18, 9, 2, 3, 15, 16, 7, 8, 8, 15, #x4
15, 14, 6, 4, 4, 15, 14, 13, 7, 13, 15, #x5
7, 18, 13, 4, 9, 16, 14, 5, 4, 16, 15, #x6
4, 3, 1, 13, 9, 6, 3, 18, 2, 10, 15, #x7
15, 16, 15, 11, 11, 14, 16, 12, 14, 14, 15 #x8
),
nrow = 8,
byrow = TRUE,
dimnames = list(
c("x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8"),
c("hatco", "A", "B", "C", "D", "E", "F", "G", "H", "I", "IDEAL")
)
)
)
hatco_extended hatco A B C D E F G H I IDEAL
x1 16 13 8 13 9 17 15 16 6 12 15
x2 14 14 10 11 11 14 12 13 10 14 15
x3 6 6 14 10 11 8 7 4 14 4 15
x4 15 18 9 2 3 15 16 7 8 8 15
x5 15 14 6 4 4 15 14 13 7 13 15
x6 7 18 13 4 9 16 14 5 4 16 15
x7 4 3 1 13 9 6 3 18 2 10 15
x8 15 16 15 11 11 14 16 12 14 14 15
# Estimate the model identifying the 11th column as supplementary
# The algorithm ignores this column for inertia calculation but projects it afterwards
ca_sup <- ca::ca(hatco_extended, supcol = 11)
# Summary including supplementary points
# 'IDEAL' appears in a separate section of the output
summary(ca_sup)
Principal inertias (eigenvalues):
dim value % cum% scree plot
1 0.076541 53.1 53.1 *************
2 0.047813 33.2 86.3 ********
3 0.015291 10.6 96.9 ***
4 0.002658 1.8 98.8
5 0.000806 0.6 99.3
6 0.000576 0.4 99.7
7 0.000381 0.3 100.0
-------- -----
Total: 0.144066 100.0
Rows:
name mass qlt inr k=1 cor ctr k=2 cor ctr
1 | x1 | 147 619 41 | 107 289 22 | 115 330 40 |
2 | x2 | 145 527 8 | 61 469 7 | -21 58 1 |
3 | x3 | 99 991 231 | 23 2 1 | -578 989 689 |
4 | x4 | 119 901 132 | -356 789 196 | 133 111 44 |
5 | x5 | 123 816 70 | -106 138 18 | 235 677 142 |
6 | x6 | 125 372 129 | -232 358 87 | 46 14 6 |
7 | x7 | 81 991 367 | 792 961 665 | 139 30 33 |
8 | x8 | 162 772 22 | -43 93 4 | -115 678 45 |
Columns:
name mass qlt inr k=1 cor ctr k=2 cor ctr
1 | hatc | 108 433 62 | -130 206 24 | 137 228 42 |
2 | A | 120 928 86 | -283 772 125 | 127 156 40 |
3 | B | 89 942 115 | -233 294 63 | -346 648 224 |
4 | C | 80 975 180 | 535 882 299 | -174 93 50 |
5 | D | 79 863 88 | 268 445 74 | -260 418 111 |
6 | E | 123 812 29 | -124 456 25 | 110 356 31 |
7 | F | 114 954 52 | -232 810 80 | 98 144 23 |
8 | G | 103 963 204 | 465 762 292 | 239 201 123 |
9 | H | 76 797 128 | -109 49 12 | -425 748 289 |
10 | I | 107 446 56 | 65 55 6 | 171 390 66 |
11 | (*)IDEA | <NA> 289 <NA> | 112 274 <NA> | -26 15 <NA> |
Visualización del posicionamiento IDEAL
Al graficar, el paquete ca diferencia automáticamente los puntos activos de los suplementarios (generalmente mediante símbolos o colores distintos) para que el analista no olvide que ese punto no ha sido considerado en el cómputo del mapa, sino que solo ha sido “invitado” a la representación”.
# Plot with supplementary point
plot(ca_sup,
main = "Mapa con punto suplementario IDEAL",
col = c("steelblue", "orange", "seagreen"),
col.lab = c("steelblue", "orange"),
map = "symmetric",
arrows = c(TRUE, TRUE)
)El análisis de correspondencias no es un fin en sí mismo, sino una herramienta de diálogo con el cliente. El mapa traduce la complejidad de una tabla de contingencia en un lenguaje visual inmediato, permitiendo en segundos a la pregunta más importante de cualquier estrategia competitiva: ¿quién es esta empresa para sus clientes y quiénes son sus verdaderos rivales?