42  Reducción de Variables Categóricas y Prueba χ²

En la etapa de preprocesamiento y selección de características (feature selection), a menudo nos enfrentamos a conjuntos de datos con múltiples variables categóricas. Herramientas comunes como el coeficiente de correlación de Pearson o Spearman están diseñadas para variables numéricas (continuas u ordinales) y no son aplicables a variables categóricas nominales, donde no existe un orden inherente (por ejemplo, tipo de cliente, canal de compra o nivel educativo frente a abandono del servicio).

La redundancia entre variables categóricas tiene un costo concreto: si dos variables transmiten casi la misma información, o si un predictor no guarda relación con la variable objetivo (target), conservarlas infla la dimensionalidad del modelo. El efecto se multiplica con One-Hot Encoding, donde cada categoría añade una columna sin aportar necesariamente señal nueva.

Para ilustrarlo, utilizaremos un ejemplo didáctico inspirado en BigMart Sales: el tipo de tienda (Outlet_Type: Supermarket Type1, Grocery Store) y su tamaño (Outlet_Size: Medium, Small). ¿Están asociadas estas dos variables en la muestra imaginaria, o son independientes? Los conteos siguientes son inventados para aprender el método; no describen el conjunto de datos original.

42.1 Intuición: ¿qué esperaríamos si no hubiera relación?

Antes de cualquier fórmula, hagamos una predicción con proporciones. De 100 tiendas, 50 son Medium: la mitad. Si el tamaño no tuviera nada que ver con el tipo, la mitad de los 40 supermercados también debería ser Medium, es decir, unos 20. Observamos 30. Con las tiendas de abarrotes ocurre lo contrario: esperaríamos 30 medianas de 60 y observamos 20.

La prueba χ² formaliza exactamente esta comparación: construye la tabla que esperaríamos bajo independencia, mide cuánto se aleja la tabla observada en cada celda y pondera cada diferencia por el tamaño esperado (diez tiendas de diferencia pesan más si esperábamos 20 que si esperábamos 2000). Después pregunta si una distancia total así de grande sería rara si las variables fueran independientes.

42.2 Desarrollo manual paso a paso

Organizamos los 100 registros en una tabla de contingencia1 de \(2 \times 2\):

1 Tabla de contingencia: matriz de conteos en la que cada celda combina una categoría de la primera variable con otra de la segunda.

Outlet_Type Medium Small Total fila (\(R_i\))
Supermarket Type1 30 10 40
Grocery Store 20 40 60
Total columna (\(C_j\)) 50 50 100 (\(N\))

42.2.1 Frecuencias marginales

Los totales de fila (\(R_i\)) son 40 y 60; los de columna (\(C_j\)), 50 y 50; el total general (\(N\)) es 100. Divididos entre \(N\) son las proporciones marginales2, es decir, 40 % de supermercados y 50 % de tiendas medianas.

2 Distribución marginal: distribución de una sola variable obtenida al sumar la tabla sobre las categorías de la otra. Sus proporciones estiman \(P(X=x_i)\) y \(P(Y=y_j)\).

42.2.2 Frecuencias esperadas (\(E_{ij}\))

Bajo la hipótesis nula3 de independencia, la probabilidad de una celda es el producto de las probabilidades marginales, así que el conteo esperado es \(N\cdot\frac{R_i}{N}\cdot\frac{C_j}{N}\): \[ E_{ij} = \frac{R_i \cdot C_j}{N} \]

3 Hipótesis nula (\(H_0\)): afirmación que se supone cierta para calcular qué resultados serían esperables; aquí, que tipo y tamaño de tienda son independientes. La prueba no demuestra \(H_0\): solo evalúa si los datos son poco compatibles con ella.

  • \(E_{11}\) (Supermarket Type1, Medium): \(\frac{40 \cdot 50}{100} = 20\)
  • \(E_{12}\) (Supermarket Type1, Small): \(\frac{40 \cdot 50}{100} = 20\)
  • \(E_{21}\) (Grocery Store, Medium): \(\frac{60 \cdot 50}{100} = 30\)
  • \(E_{22}\) (Grocery Store, Small): \(\frac{60 \cdot 50}{100} = 30\)

La tabla esperada conserva los mismos totales de fila y columna que la observada; solo redistribuye los conteos como si no hubiera asociación.

42.2.3 Contribuciones a χ²

Cada celda aporta su diferencia al cuadrado, relativa a lo esperado: \[ \frac{(O_{ij} - E_{ij})^2}{E_{ij}} \]

  • Celda 1,1: \(\frac{(30 - 20)^2}{20} = \frac{100}{20} = 5.0\)
  • Celda 1,2: \(\frac{(10 - 20)^2}{20} = \frac{100}{20} = 5.0\)
  • Celda 2,1: \(\frac{(20 - 30)^2}{30} = \frac{100}{30} \approx 3.333\)
  • Celda 2,2: \(\frac{(40 - 30)^2}{30} = \frac{100}{30} \approx 3.333\)

Las cuatro diferencias valen \(\pm10\): en una tabla \(2\times2\) con márgenes fijos, si una celda sube diez, su vecina de fila y su vecina de columna deben bajar diez. Por eso solo hay un grado de libertad.

42.2.4 Estadístico χ²\(_{calc}\) y valor \(p\)

\[ \chi^2_{\text{calc}} = 5.0 + 5.0 + 3.333 + 3.333 = 16.667 \]

Los grados de libertad4 son \((r - 1)(c - 1) = (2 - 1)(2 - 1) = 1\). Si \(H_0\) fuera cierta, \(\chi^2_{\text{calc}}\) seguiría aproximadamente una distribución χ² con un grado de libertad5. El valor \(p\)6 es la probabilidad de obtener un estadístico al menos tan grande como el observado bajo esa distribución: \[ p = P\left(\chi^2_1 \ge 16.667\right) \approx 4.5\times10^{-5}. \]

4 Grados de libertad: número de conteos que pueden variar una vez fijados los totales de filas y columnas. En una tabla 2 × 2 queda uno.

5 Distribución χ² con \(k\) grados de libertad: distribución de la suma de los cuadrados de \(k\) variables normales estándar independientes. Tiene media \(k\) y varianza \(2k\); con \(k=1\) concentra la mayor parte de su masa cerca de cero, y \(P(\chi^2_1\ge3.841)=0.05\).

6 Valor \(p\): probabilidad, calculada suponiendo \(H_0\) cierta, de obtener un estadístico al menos tan extremo como el observado. No es la probabilidad de que \(H_0\) sea cierta ni mide el tamaño del efecto.

7 Nivel de significancia (\(\alpha\)): umbral fijado antes de mirar los datos para decidir cuándo rechazar \(H_0\). Es la probabilidad de rechazarla cuando en realidad es cierta (error de tipo I). El valor 0.05 es una convención, no una ley.

Con un nivel de significancia7 \(\alpha = 0.05\), el valor crítico es \(3.841\). Como \(16.667 > 3.841\) (equivalentemente, \(p<0.05\)), rechazamos la independencia en esta muestra ficticia. Esto aporta evidencia de asociación; no demuestra causalidad ni garantiza utilidad predictiva.

42.2.5 Fuerza de asociación: V de Cramér

El valor \(p\) cuantifica qué tan inusual sería una discrepancia como la observada bajo independencia8; no mide la fuerza de la asociación. Para ello dividimos χ² entre su máximo posible, \(N\cdot\min(r-1,c-1)\): \[ V = \sqrt{\frac{\chi^2}{N \cdot \min(r - 1, c - 1)}} = \sqrt{\frac{16.667}{100}} \approx 0.408 \]

8 Sensibilidad al tamaño de muestra (\(N\)): con muestras grandes, diferencias pequeñas pueden producir valores \(p\) bajos. Por eso conviene acompañar la prueba con un tamaño del efecto como V de Cramér.

En una tabla \(2\times2\) existe un atajo útil para comprobar el cálculo: \(V=|\phi|=\frac{|O_{11}O_{22}-O_{12}O_{21}|}{\sqrt{R_1R_2C_1C_2}}=\frac{|30\cdot40-10\cdot20|}{\sqrt{40\cdot60\cdot50\cdot50}}=\frac{1000}{2449.5}\approx0.408\).

Un experimento mental. Si multiplicamos todos los conteos por 10 (misma proporción en cada celda, \(N=1000\)), cada contribución se multiplica por 10: \(\chi^2=166.7\) y \(p\approx4\times10^{-38}\). Pero \(V\) sigue en \(0.408\), porque depende solo de las proporciones. Una muestra más grande vuelve más segura la conclusión, no más fuerte la asociación.

42.2.6 Ver la discrepancia antes de interpretar el resultado

Comparamos la tabla observada con la esperada en dos mapas de calor interactivos. Ambas usan el mismo rango numérico de color para facilitar la comparación entre celdas.

Código
import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots

observadas = np.array([[30, 10], [20, 40]])
esperadas = np.array([[20., 20.], [30., 30.]])
filas = ["Supermarket Type1", "Grocery Store"]
columnas = ["Medium", "Small"]

fig = make_subplots(rows=1, cols=2, subplot_titles=("Observadas", "Esperadas si fueran independientes"))
for posicion, (tabla, escala) in enumerate(((observadas, "Blues"), (esperadas, "Oranges")), start=1):
    fig.add_trace(go.Heatmap(z=tabla, x=columnas, y=filas, zmin=0, zmax=40,
                             colorscale=escala, showscale=False, text=tabla,
                             texttemplate="%{text}"), row=1, col=posicion)
fig.update_layout(title="Tipo y tamaño de tienda: datos didácticos", template="plotly_white", height=370)
fig.show()

La celda Supermarket Type1–Medium contiene 30 registros frente a 20 esperados. El contraste ocurre también en las otras tres celdas; ninguna por sí sola explica toda la decisión.

Código
residuos = (observadas - esperadas) / np.sqrt(esperadas)
fig = go.Figure(go.Heatmap(z=residuos, x=columnas, y=filas,
                           colorscale="RdBu_r", zmid=0, zmin=-2.5, zmax=2.5,
                           text=np.round(residuos, 2), texttemplate="%{text}",
                           colorbar=dict(title="Residuo")))
fig.update_layout(title="Residuos de Pearson: (observado − esperado) / √esperado",
                  template="plotly_white", height=370)
fig.show()

El signo muestra la dirección de la diferencia. El cuadrado de cada residuo es la contribución de esa celda al χ². No interpretes cada residuo como una prueba independiente sin ajustar por las comparaciones múltiples.

42.3 Formalización teórica y matemática

La base formal de esta prueba es la definición de independencia estadística9 para variables aleatorias categóricas \(X\) e \(Y\): \[ H_0:\; P(X = x_i, Y = y_j) = P(X = x_i) \cdot P(Y = y_j) \quad \forall i, j \]

9 Independencia estadística: conocer el valor de una variable no cambia las probabilidades de la otra: \(P(Y=y_j\mid X=x_i)=P(Y=y_j)\). Multiplicando por \(P(X=x_i)\) se obtiene la factorización de la probabilidad conjunta.

10 Estimador de máxima verosimilitud: valor de los parámetros que hace más probable la muestra observada bajo el modelo supuesto. Para proporciones de una distribución multinomial, coincide con la frecuencia relativa observada.

Las probabilidades marginales se estiman con las proporciones observadas, \(\hat p_{i\cdot}=R_i/N\) y \(\hat p_{\cdot j}=C_j/N\); son los estimadores de máxima verosimilitud10 bajo \(H_0\). De ahí \(E_{ij}=N\hat p_{i\cdot}\hat p_{\cdot j}=R_iC_j/N\).

El estadístico χ² de Pearson suma las discrepancias estandarizadas: \[ \chi^2 = \sum_{i=1}^r \sum_{j=1}^c \frac{(O_{ij} - E_{ij})^2}{E_{ij}} = \sum_{i,j} r_{ij}^2, \qquad r_{ij}=\frac{O_{ij}-E_{ij}}{\sqrt{E_{ij}}}. \]

Cada conteo es aproximadamente Poisson, con varianza cercana a su media \(E_{ij}\); por eso \(r_{ij}\) se comporta, para conteos grandes, como una variable normal estándar, y la suma de sus cuadrados como una χ². Las restricciones de los márgenes eliminan \(r+c-1\) grados de libertad de las \(rc\) celdas, lo que deja \(rc-(r+c-1)=(r-1)(c-1)\).

Dos propiedades explican el experimento mental anterior. Si todos los conteos se multiplican por \(k>0\): \[ \chi^2(kO)=k\,\chi^2(O), \qquad V(kO)=V(O). \]

42.3.1 Supuestos de validez

Las observaciones deben ser independientes: no se debe contar repetidamente la misma tienda como si fueran tiendas distintas. Como regla orientativa para la aproximación asintótica, revisa los criterios de Cochran11: ninguna celda esperada menor que 1 y, como máximo, el 20 % de las celdas esperadas menor que 5. En una tabla 2 × 2 esto suele implicar revisar con especial cuidado cualquier frecuencia esperada menor que 5.

11 Criterios de Cochran: Establecen las condiciones bajo las cuales la aproximación asintótica a la distribución χ² es fiable. Principalmente, requieren que no más del 20% de las celdas tengan frecuencias esperadas menores a 5, y que ninguna celda tenga una frecuencia esperada menor a 1.

42.3.2 Corrección por continuidad de Yates

En tablas de \(2 \times 2\) puede utilizarse la corrección de Yates12: resta \(0.5\) a cada \(|O_{ij}-E_{ij}|\) antes de elevar al cuadrado. En nuestro ejemplo, \(\chi^2_{\text{Yates}}=9.5^2(2/20+2/30)=15.04\). No es obligatoria por el solo hecho de tener una tabla 2 × 2: informa si se aplicó y usa el mismo criterio al comparar resultados.

12 Corrección de continuidad de Yates: ajuste conservador para la aproximación de conteos discretos por una distribución continua en tablas 2 × 2. Puede reducir potencia; no reemplaza automáticamente una prueba exacta en tablas pequeñas.

42.3.3 Prueba exacta de Fisher

Cuando la aproximación χ² es dudosa en una tabla 2 × 2, la prueba exacta de Fisher13 calcula el valor \(p\) sin aproximaciones: fija los márgenes y enumera todas las tablas posibles con su probabilidad hipergeométrica. Para nuestra tabla da \(p\approx8.3\times10^{-5}\), del mismo orden que la aproximación. También debemos ser cautos con conclusiones basadas en datos agregados debido a la paradoja de Simpson14.

13 Prueba exacta de Fisher: prueba para tablas 2 × 2 que calcula probabilidades condicionadas a los márgenes mediante la distribución hipergeométrica, sin depender de la aproximación χ².

14 Paradoja de Simpson: Ocurre cuando una tendencia aparece en diferentes grupos de datos pero desaparece o se invierte cuando estos grupos se combinan. Es un riesgo al analizar tablas de contingencia agregadas sin controlar por variables de confusión subyacentes.

42.4 Laboratorio interactivo: de la tabla observada a la distribución nula

Objetivo. Ver la independencia como una comparación de proporciones, distinguir significación estadística de fuerza de asociación y entender de dónde sale el valor \(p\).

  1. Con el ejemplo inicial, comprueba en el mosaico que las barras no se cortan en la línea punteada (la proporción de Medium que esperaríamos bajo independencia). Verifica \(\chi^2\approx16.67\), \(V\approx0.408\) y \(p\approx4.5\times10^{-5}\).
  2. Pulsa «Simular bajo H₀». Cada barra del histograma resume tablas generadas sin asociación con el mismo \(N\). ¿Qué fracción supera el χ² observado? Compárala con el valor \(p\) teórico.
  3. Carga «Asociación débil» (25, 15, 25, 35). Predice χ² y V antes de mirar. Luego mueve «Multiplicar la muestra» hasta ×10: anota cómo cambian χ², \(p\) y V.
  4. Carga «Celdas escasas» (2, 0, 1, 3). Explica por qué el aviso de Cochran aparece y compara el valor \(p\) de χ² con el de Fisher.

Laboratorio · Prueba de independencia

Outlet_Type × Outlet_Size: ¿cuánto se aleja lo observado de lo esperado?

Escribe conteos enteros no negativos o usa un caso predefinido. Todo se recalcula en el navegador.

Casos predefinidos

Conteos observados Oij (antes de multiplicar)

MediumSmallTotal Supermarket Type1 Grocery Store Total

Celda por celda (con la muestra multiplicada)

Mosaico: proporción de Medium en cada tipo

MediumSmallcorte esperado bajo H₀
χ² (gl = 1)
Valor p (aprox. χ²)
Valor p (Fisher exacto)
V de Cramér

¿Qué χ² aparecen cuando no hay asociación?

χ² de tablas simuladasdensidad χ² con 1 glχ² observado

Pulsa el botón para generar tablas con los mismos márgenes esperados y ninguna asociación.

Comprobación. Con 25, 15, 25, 35 obtendrás \(\chi^2\approx4.17\), \(p\approx0.041\) y \(V\approx0.204\): hay evidencia al 5 %, pero la asociación es la mitad de fuerte que en el ejemplo inicial. Multiplicar por 10 da \(\chi^2\approx41.7\) con la misma \(V\). En la tabla escasa, χ² sugiere \(p\approx0.083\) pero Fisher da \(p=0.40\): la aproximación no es fiable con tan pocos datos.

Interpretación para entregar. Escribe dos frases: una sobre la evidencia de asociación (valor \(p\) y prueba usada) y otra sobre su magnitud (V). Añade una tercera sobre qué aprendiste del experimento «multiplicar la muestra» para leer resultados con miles de registros.

42.5 Mejores prácticas en la industria

TipMejores prácticas en la industria

Cardinalidad y tamaño del efecto. Una variable con muchas categorías puede producir celdas escasas. Agrupa categorías infrecuentes solo si existe una justificación semántica y define la regla con los datos de entrenamiento. Compara el valor \(p\) con V de Cramér y el rendimiento del modelo: una muestra grande puede detectar asociaciones de poca utilidad práctica. La información mutua15 es otra medida posible, pero también requiere controlar el sesgo que introduce la cardinalidad.

15 Información mutua: medida de dependencia basada en cuánto reduce conocer una variable la incertidumbre sobre otra.

ImportanteRegla de oro en producción

Prevención de fuga de datos. Si usas la relación con la variable objetivo para seleccionar predictores, aprende la selección dentro de cada partición de entrenamiento y evalúala en datos separados. Si solo exploras asociación entre dos columnas, registra igualmente la procedencia de los datos y evita convertir un hallazgo exploratorio en una regla de producción sin validación.

42.6 Implementación computacional y selección de variables

Comprobamos los cuatro conteos ficticios de BigMart. scipy.stats.chi2_contingency usa por defecto una corrección en tablas 2 × 2; la desactivamos para reproducir el cálculo manual.

Código
import pandas as pd
import scipy.stats as stats

tabla_cont = pd.DataFrame(
    [[30, 10], [20, 40]],
    index=["Supermarket Type1", "Grocery Store"],
    columns=["Medium", "Small"]
)
chi2_stat, p_val, dof, ex = stats.chi2_contingency(tabla_cont, correction=False)
v_cramer = (chi2_stat / (tabla_cont.to_numpy().sum() * min(
    tabla_cont.shape[0] - 1, tabla_cont.shape[1] - 1
))) ** 0.5
print(tabla_cont)
print(f"χ² = {chi2_stat:.3f}; p = {p_val:.6f}; gl = {dof}; V = {v_cramer:.3f}")
print("Esperadas:", ex)
assert abs(chi2_stat - 16.6666667) < 1e-5
assert abs(v_cramer - 0.4082483) < 1e-5
                   Medium  Small
Supermarket Type1      30     10
Grocery Store          20     40
χ² = 16.667; p = 0.000045; gl = 1; V = 0.408
Esperadas: [[20. 20.]
 [30. 30.]]

La tabla describe asociación entre dos predictores; por sí sola no indica cuál mejorará las predicciones de ventas. Para seleccionar variables con un objetivo y, se necesita un procedimiento supervisado dentro de las particiones de entrenamiento. Además, sklearn.feature_selection.chi2 calcula una prueba de puntuación para características no negativas frente a clases; su resultado no equivale automáticamente a la prueba de independencia sobre una tabla de contingencia ni a V de Cramér.

42.6.1 Visualizar redundancia entre predictores

En este ejemplo pequeño añadimos una categoría Outlet_Region inventada para ilustrar una tercera variable; los valores no representan datos reales.

Código
import numpy as np
import plotly.express as px

registros = []
for (tipo, tamano), n in tabla_cont.stack().items():
    for i in range(n):
        registros.append((tipo, tamano, "Norte" if i % 3 else "Sur"))
muestra = pd.DataFrame(registros, columns=["Outlet_Type", "Outlet_Size", "Outlet_Region"])

def cramer_v(tabla):
    if min(tabla.shape) < 2:
        return float("nan")
    estadistico = stats.chi2_contingency(tabla, correction=False)[0]
    return np.sqrt(estadistico / (tabla.to_numpy().sum() * min(
        tabla.shape[0] - 1, tabla.shape[1] - 1
    )))

variables = muestra.columns.tolist()
matriz_v = pd.DataFrame(index=variables, columns=variables, dtype=float)
for a in variables:
    for b in variables:
        matriz_v.loc[a, b] = 1.0 if a == b else cramer_v(pd.crosstab(muestra[a], muestra[b]))

fig = px.imshow(matriz_v, text_auto=".2f", zmin=0, zmax=1,
                color_continuous_scale="Blues",
                title="V de Cramér entre predictores (ejemplo ficticio)")
fig.update_layout(template="plotly_white", height=430)
fig.show()

Comprobación. El valor para Outlet_Type y Outlet_Size debe ser 0.408. Las asociaciones entre predictores sugieren redundancia posible; decídela mediante validación del modelo, costo de captura y estabilidad temporal.