ML Atlas

Machine learning desde cero · Lección 4.2 · 21 de 33 lecciones listas · 12 min

Datos faltantes

En pocas palabras

Elimina las filas con huecos y quedan 333 de 344 pingüinos. Si a los más pesados les falta el IMC, la media en los huecos debilita la relación con la diabetes.

Calentamiento Dos preguntas de lecciones anteriores. Un minuto, y no bloquea la lección.
De la lección 4.1: Exploración: mira antes de modelar Verdadero o falso: «los estadísticos descriptivos bastan, dibujar los datos es perder el tiempo».

Ver la respuesta

Respuesta correcta: Falso, porque los mismos números pueden esconder un arco, grupos o un punto lejano

En el cuarteto los mismos números esconden cuatro imágenes distintas, y en 342 pingüinos una correlación tiene el signo contrario al de cada especie. Un dibujo lo muestra enseguida.

De la lección 3.6: Parada temprana ¿En qué se basa la parada temprana para decidir cuándo detener el entrenamiento?

Ver la respuesta

Respuesta correcta: En la pérdida de validación: se para cuando deja de bajar

La pérdida de entrenamiento baja casi hasta el final, incluso cuando la red aprende ruido. La pérdida de validación, calculada con datos de fuera del entrenamiento, sube cuando el modelo empieza a sobreajustar.

En la lección 4.1 miramos los datos antes de construir un modelo. Hoy, lo que los datos no contienen. Un dato faltante es una celda vacía de la tabla: alguien no midió, no lo anotó o no quiso decirlo. La mayoría de los modelos no acepta una celda vacía, así que hay que hacer algo con ella. Hay dos salidas sencillas: eliminar la fila o escribir algún valor en el hueco, lo que se llama imputar los valores faltantes.

Predice y comprueba La tabla de pingüinos tiene 344 filas. Falta el sexo de 11 pingüinos, y cada una de las cuatro medidas (dos del pico, la aleta, la masa) de 2. Eliminas toda fila en la que falte algo. ¿Cuántos pingüinos quedan?
¿Qué tan seguro estás?

Experimento interactivo

Este experimento interactivo funciona en un navegador con JavaScript activado. El texto que lo rodea describe lo que muestra.

Ver la respuesta

Respuesta correcta: 333, porque los 2 pingüinos sin medidas están entre los 11 a los que falta el sexo

Quedan 333. Las celdas vacías de las medidas están en las mismas 2 filas, y a esos pingüinos también les falta el sexo. Así que eliminas 11 filas, no 19 ni 13. Antes de contar las pérdidas, mira en qué filas están los huecos.

Pruébalo

  • Empieza por los pingüinos. ¿A cuántos les falta el sexo y a cuántos las medidas? ¿Son las mismas filas?
  • El modelo debe predecir la masa a partir de las otras tres medidas. ¿Necesita el sexo? ¿Cuántos pingüinos quedan si eliminas solo las filas sin las columnas del modelo?
  • Pasa a la diabetes. Aquí falta el IMC de los pacientes más pesados. Rellena el hueco con la media: ¿la relación entre el IMC y la progresión de la enfermedad se debilita o se refuerza?
  • Añade la columna «falta» y compara el R² en validación cruzada. Luego cambia a pacientes al azar. ¿Qué cambia?

Cuando lo hayas comprobado en el lab, pongamos nombre a lo que ves.

La idea en palabras sencillas

Eliminar una fila con un hueco es sencillo, pero cuesta. En los pingüinos, las filas con algún hueco son 11 de 344, así que quedan 333. Un modelo que predice la masa a partir de las medidas del pico y la aleta nunca lee el sexo. Si eliminas solo las filas a las que faltan columnas del modelo, quedan 342. Elimina filas por las columnas que de verdad usas.

La pregunta más importante es a quién le faltan los datos. En el conjunto de diabetes los 442 pacientes tienen su IMC, así que el lab lo oculta a propósito en 110 de ellos. Una vez al azar, otra en los 110 más pesados, es decir, en todos los que tienen un IMC de al menos 29,4. Ese hueco no es aleatorio. Los pacientes sin IMC tienen una progresión media de la enfermedad de 209, y los demás de 133. El simple hecho de que falte el IMC dice algo del paciente.

Cuando escribes en el hueco la media de los demás pacientes (24,3), las 110 personas con más progresión caen en un IMC medio. La correlación del IMC con la progresión de la enfermedad baja de 0,586 a 0,352: la relación se debilita. La recta del modelo no se vuelve más plana, porque la fijan los pacientes con IMC; empeora el ajuste, porque los 110 puntos rellenados quedan lejos de la recta. El R² de una regresión lineal en validación cruzada baja de 0,328 a 0,106. Ayuda una columna extra 0/1 «faltaba el IMC». El modelo da entonces al propio hueco un peso de 76 puntos de progresión, y el R² vuelve a 0,284. Con huecos aleatorios esta columna no aporta nada: 0,264 frente a 0,267 con solo la media.

Jak to policzono
  • Pingüinos: Palmer Penguins (Gorman, Williams y Fraser, 2014; paquete palmerpenguins: Horst, Hill y Gorman, 2020), licencia CC0. 344 filas, huecos reales: el sexo en 11 (Adelie 6, Gentoo 5), las cuatro medidas en los mismos 2 pingüinos.
  • Diabetes: Diabetes (Efron, Hastie, Johnstone y Tibshirani, 2004), incluido en scikit-learn con licencia BSD-3-Clause. 442 pacientes, progresión de la enfermedad al cabo de un año. El IMC está en los datos para todos; los huecos de 110 pacientes los hicimos nosotros: al azar o en los 110 con el IMC más alto.
  • Modelo: regresión lineal de la progresión de la enfermedad sobre el IMC (con la columna de hueco, sobre el IMC y esa columna), validación cruzada en 5 partes repetida 10 veces. La media para rellenar se calcula con los pacientes que tienen IMC; en la validación cruzada, en cada partición, solo con la parte de entrenamiento, como SimpleImputer en un pipeline.

Por qué funciona

La media rellenada está en el centro del eje del IMC, pero pertenece a pacientes de su extremo derecho. Su progresión es alta, así que al rellenar aparece una columna vertical de puntos altos sobre un IMC medio. Esa columna no añade nada a la variación conjunta del IMC y la progresión. Frente a los pacientes que tienen IMC (correlación 0,459), solo añade variación a la progresión, así que la correlación baja a 0,352. Frente a los datos completos (0,586), estos 110 pacientes pierden su parte de la variación conjunta: tenían un IMC alto y una progresión alta, y ahora están en el centro del eje. La desviación estándar del IMC se reduce de 4,4 a 2,3, porque 110 valores están en un solo punto.

Eliminar a esos pacientes tampoco arregla nada. Queda una nube sin su extremo derecho, y la correlación en los 332 restantes es 0,459 en vez de 0,586. Además, para 110 pacientes el modelo no da ninguna respuesta. La columna de hueco funciona porque da al modelo un peso propio para el grupo cuyo IMC no conocemos. Ese grupo difiere en progresión de la enfermedad, así que el peso lleva esa diferencia a las predicciones. Cuando el hueco es aleatorio, el grupo sin IMC no difiere del resto (156 frente a 151) y el peso no tiene nada que llevar.

Un error frecuente

Verdadero o falso: «rellena los huecos con la media y listo». Falso. La media reduce la dispersión de la columna y finge que el hueco nunca existió. Cuando el hueco depende del propio valor, como aquí en los más pesados, la media deforma la relación: la correlación baja de 0,586 a 0,352 y el R² de 0,328 a 0,106. La columna «falta» devuelve el R² a 0,284. En el código de abajo gana a la media sola en 48 de 50 partes de validación.

La media y eliminar filas están bien cuando los huecos son pocos y aleatorios. Pero antes comprueba si las filas con hueco difieren del resto.

Test

Tres preguntas para comprobar lo aprendido. Elige una respuesta o despliega la solución bajo cada pregunta. Con el teclado: las flechas eligen, Enter o Espacio confirma.

1. En la tabla de pingüinos falta el sexo de 11, y las medidas de 2 de esos mismos pingüinos. ¿Cuántos quedan tras eliminar toda fila con un hueco?
Ver la respuesta

Respuesta correcta: 333, porque los 2 pingüinos sin medidas están entre los 11 pingüinos sin sexo

Las medidas que faltan están en 2 filas a las que también les falta el sexo. Eliminas 11 filas, y de 344 quedan 333.

2. Falta el IMC de los 110 pacientes más pesados. ¿Qué hace rellenar con la media de los demás?
Ver la respuesta

Respuesta correcta: Debilita la relación IMC–enfermedad, porque los más enfermos caen en un IMC medio

La correlación baja de 0,586 a 0,352. 110 pacientes con mucha progresión están en un solo punto: en la media de 24,3.

3. Verdadero o falso: «rellena los huecos con la media y listo».
Ver la respuesta

Respuesta correcta: Falso, porque la media reduce la dispersión y oculta un hueco que puede significar algo

En los más pesados el R² baja de 0,328 a 0,106. La columna «falta» devuelve 0,284, porque el propio hueco dice algo del paciente.

Ideas clave

  • Elimina filas por las columnas que usas: quedan 342 pingüinos en vez de 333.
  • Antes de hacer nada con los huecos, comprueba si las filas con hueco difieren del resto.
  • La media en los huecos reduce la dispersión y, con huecos no aleatorios, debilita la relación: una correlación de 0,586 baja a 0,352.
  • Una columna 0/1 «falta» deja al modelo usar la información que lleva el propio hueco: R² 0,284 en vez de 0,106.

Más a fondo: fórmula, código, práctica

Las matemáticas

Rellenar con la media: x̃ᵢ = x̄_obs para los pacientes con hueco, x̃ᵢ = xᵢ para el resto. Los puntos rellenados tienen x̃ᵢ − x̄ = 0, así que no añaden nada a la covarianza Σ (x̃ᵢ − x̄)(yᵢ − ȳ) ni a la varianza Σ (x̃ᵢ − x̄)², pero añaden (yᵢ − ȳ)² a la varianza de y. Frente a solo los pacientes con IMC, la suma Σ (x̃ᵢ − x̄)(yᵢ − ȳ) no cambia mientras la varianza de y crece, así que la correlación r = cov(x̃, y) / (s_x̃ · s_y) baja (0,459 → 0,352). Frente a los datos completos, la varianza de y es la misma; baja la covarianza, porque los puntos rellenados ya no aportan sus términos grandes y positivos (0,586 → 0,352).

La columna de hueco: ŷ = a + b · x̃ + c · m, donde m = 1 cuando faltaba el IMC y m = 0 en otro caso. Para un paciente con hueco el modelo predice a + b · x̄_obs + c, así que c desplaza a todo el grupo sin IMC. Aquí c = 76 con los huecos en los más pesados.

En código (Python)

El mismo experimento en pandas y scikit-learn: los huecos de la tabla de pingüinos, luego el IMC oculto en 110 pacientes al azar y en los 110 más pesados, la media en los huecos y la media con una columna de hueco en validación cruzada 10 × 5.

import numpy as np
import pandas as pd
from sklearn.datasets import load_diabetes
from sklearn.model_selection import cross_val_score, RepeatedKFold
from sklearn.linear_model import LinearRegression
from sklearn.impute import SimpleImputer
from sklearn.pipeline import make_pipeline

df = pd.read_csv("data/raw/penguins.csv")
gaps = df.isna().sum()
print(f"{len(df)} penguins; missing: " + ", ".join(f"{c} {n}" for c, n in gaps[gaps > 0].items()))
measured = df.dropna(subset=["bill_length_mm", "bill_depth_mm", "flipper_length_mm", "body_mass_g"])  # elimina solo las filas sin las columnas del modelo
print(f"dropna() leaves {len(df.dropna())}; dropping only rows without measurements leaves {len(measured)}")
X, y = load_diabetes(return_X_y=True, as_frame=True, scaled=False)
bmi, y = X.bmi.to_numpy(), y.to_numpy()
heavy = bmi >= np.sort(bmi)[-110]  # los 110 más pesados: IMC de al menos 29,4
rnd = np.zeros(len(bmi), bool)
rnd[np.random.default_rng(0).choice(len(bmi), 110, replace=False)] = True  # 110 al azar
cv = RepeatedKFold(n_splits=5, n_repeats=10, random_state=0)
r2 = lambda model, Z: cross_val_score(model, Z, y, cv=cv, scoring="r2")
print(f"{len(bmi)} patients, BMI vs progression: r {np.corrcoef(bmi, y)[0, 1]:.3f}, CV R2 {r2(LinearRegression(), bmi[:, None]).mean():.3f}")
for name, miss in [("random", rnd), ("heaviest", heavy)]:
    hidden = np.where(miss, np.nan, bmi)[:, None]
    filled = np.where(miss, bmi[~miss].mean(), bmi)  # la media solo de los pacientes con IMC
    mean_r2 = r2(make_pipeline(SimpleImputer(), LinearRegression()), hidden)  # la media se aprende en cada partición, solo con su parte de entrenamiento
    flag_r2 = r2(make_pipeline(SimpleImputer(add_indicator=True), LinearRegression()), hidden)  # segunda columna: 1 = faltaba el IMC
    print(f"BMI hidden for 110 {name}: progression {y[miss].mean():.0f} vs {y[~miss].mean():.0f}; mean fill: r {np.corrcoef(filled, y)[0, 1]:.3f}, CV R2 {mean_r2.mean():.3f}; mean + flag: CV R2 {flag_r2.mean():.3f}")
print(f"heaviest: mean + flag beats the mean alone in {(flag_r2 > mean_r2).sum()} of 50 folds")

Resultado

344 penguins; missing: bill_length_mm 2, bill_depth_mm 2, flipper_length_mm 2, body_mass_g 2, sex 11
dropna() leaves 333; dropping only rows without measurements leaves 342
442 patients, BMI vs progression: r 0.586, CV R2 0.332
BMI hidden for 110 random: progression 159 vs 150; mean fill: r 0.503, CV R2 0.241; mean + flag: CV R2 0.239
BMI hidden for 110 heaviest: progression 209 vs 133; mean fill: r 0.352, CV R2 0.112; mean + flag: CV R2 0.289
heaviest: mean + flag beats the mean alone in 48 of 50 folds

Los pacientes al azar y las particiones son distintos de los del lab, así que los números también difieren un poco. La imagen es la misma: quedan 333 o 342 pingüinos, la media en los más pesados baja la correlación a 0,352 y la columna de hueco sube el R² de 0,112 a 0,289. Con huecos aleatorios la columna no ayuda: 0,239 frente a 0,241.

Para profesionales
  • En scikit-learn: SimpleImputer(strategy="mean") o "median", y con add_indicator=True obtienes la columna de hueco de una vez. Mételo en make_pipeline, para que la media se calcule solo con la parte de entrenamiento de cada partición.
  • df.isna().sum() y df[df.x.isna()].describe() muestran cuántos huecos hay y si las filas con hueco difieren del resto. Es lo primero que hay que comprobar antes de elegir un método.
  • IterativeImputer y KNNImputer predicen el valor que falta a partir de otras columnas. Ayudan cuando los huecos dependen de otras columnas, pero no recuperan un hueco que depende del propio valor oculto; entonces la columna de hueco importa más.
  • Los árboles de HistGradientBoostingClassifier manejan los huecos por sí mismos: en cada división aprenden hacia qué lado enviar las filas con hueco.

Profundiza en el Atlas

Entradas de la enciclopedia sobre las ideas de esta lección: