Machine learning desde cero · Lección 4.4 · 23 de 33 lecciones listas · 12 min
Ingeniería de características
En pocas palabras
La variedad 2 está en el centro del eje y ningún umbral la recorta. Una columna x² da 77,4% en vez de 60,4%; 200 columnas de ruido bajan kNN de 98,1% a 77,4%.
Calentamiento Dos preguntas de lecciones anteriores. Un minuto, y no bloquea la lección.
En la lección 4.3 cambiamos cómo se escriben las variables: la escala de los números y el código de las categorías. Hoy creamos variables nuevas a partir de las que ya tenemos. La ingeniería de características consiste en añadir columnas que muestran al modelo con más claridad lo que busca: un cuadrado, un cociente, una diferencia, los días desde un suceso. Una buena variable puede convertir un problema difícil en uno fácil. Muchas variables débiles pueden estropear un modelo que funcionaba.
Elige una respuesta y tu grado de seguridad.
Responde para desbloquear el experimento.
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: No, porque la variedad 2 está en el centro y tiene vinos de otras variedades a ambos lados
No. En el centro del eje, un umbral siempre deja una de las otras dos variedades del lado «variedad 2». El mejor umbral en los vinos de entrenamiento acierta un 61,6%, apenas más que el 60,0% de decir «otra variedad» para cada vino, y en los vinos de prueba exactamente lo mismo: 60,4%. La SVM lineal del lab no predice la variedad 2 en ningún sitio. Solo una columna nueva x² le permite recortar el intervalo central.
Pruébalo
- Empieza solo con x. ¿Dónde predice el modelo la variedad 2? ¿Cuál es la exactitud de prueba y de dónde sale?
- Añade la columna x². ¿Cómo es la frontera en el plano (x, x²) y cómo en el eje de flavonoides?
- Pasa al ruido. Baja el deslizador desde 200 columnas. ¿Cuándo reconoce kNN mejor los vinos apartados?
- Mira el contraste de distancias. ¿Qué pasa con la diferencia entre el vino más cercano y el más lejano cuando se acumulan columnas?
Cuando lo hayas comprobado en el lab, pongamos nombre a lo que ves.
La idea en palabras sencillas
Un modelo lineal sobre un eje solo sabe hacer una cosa: poner un umbral. La variedad 2 está en el centro del eje de flavonoides, así que un umbral no puede recortarla por ningún lado: como mucho separa una de las variedades vecinas. El mejor umbral así separa la variedad 3 y acierta un 61,6% en entrenamiento, mientras que decir «otra variedad» para cada vino acierta un 60,0%. La ganancia es mínima, y en la prueba desaparece. La SVM lineal del lab no predice la variedad 2 en ningún sitio y obtiene un 60,4%, la proporción de las otras variedades entre los 53 vinos de prueba. Añadamos la columna x², el cuadrado de los flavonoides estandarizados. Los vinos de ambos extremos del eje tienen un x² grande; los del centro, pequeño. El mismo modelo lineal traza ahora una recta en el plano (x, x²). En el eje de flavonoides son dos umbrales, un intervalo de 1,11 a 2,82. La exactitud sube al 77,4%. El modelo no cambió; cambió lo que recibe.
Pero más variables no significa mejor. kNN (k = 5) con 13 medidas químicas reconoce el 98,1% de los vinos apartados. Añadimos columnas de ruido puro, números aleatorios en la misma escala. Con 200 columnas así, la exactitud baja al 77,4%. Cada columna de ruido aporta a la distancia tanto como una medida real, así que los vinos «más cercanos» dejan de parecerse. Es la maldición de la dimensionalidad: en muchas dimensiones todos los puntos están casi igual de lejos unos de otros.
Jak to policzono
- Vinos: Wine (Aeberhard y Forina, 1992; UCI, licencia CC BY 4.0), 178 vinos, 13 medidas químicas, 3 variedades. Partición estratificada: 125 vinos para aprender, 53 para la prueba.
- Variable nueva: un modelo lineal (una máquina de vectores de soporte lineal, C = 1) sobre los flavonoides estandarizados, variedad 2 contra el resto. Flavonoides medios calculados con los 178 vinos.
- Ruido: kNN con k = 5 sobre las 13 medidas estandarizadas y de 0 a 200 columnas de números de una distribución normal (media 0, desviación estándar 1), generados con una semilla fija.
Por qué funciona
Un modelo lineal divide el espacio con una recta (con un plano en más dimensiones). Sobre un eje, una recta es un punto: un umbral. La columna x² añade un segundo eje. Los vinos de ambos extremos del eje de flavonoides quedan arriba en la parábola; los del centro, abajo. Ahora una recta puede cortar a la variedad 2 desde arriba. En otras 20 particiones de los vinos, sin x² la SVM lineal no predice ni una vez la variedad 2, y el mejor umbral único del entrenamiento solo supera a «siempre otra» en la prueba en 1 de 20. Con x² siempre recorta un intervalo: del 67,9 al 84,9% en la prueba.
Con el ruido pasa lo contrario. La distancia en kNN es una suma de diferencias al cuadrado de todas las columnas. Con 13 medidas, el vino de entrenamiento más lejano está de media un 296,5% más lejos que el más cercano. Con 200 columnas de ruido, solo un 25,7%. Las diferencias del ruido son aleatorias y hay muchas, así que ahogan las 13 diferencias reales. En 20 sorteos del ruido, 200 columnas dan del 64,2 al 83,0%, siempre por debajo del 98,1% sin ruido.
Un error frecuente
Verdadero o falso: «más variables dan un modelo mejor». Falso. Una variable ayuda cuando lleva información con una forma que el modelo sabe usar, como x² para la variedad 2. Las columnas sin información perjudican: 200 columnas de ruido bajan kNN del 98,1% al 77,4%. En el código de abajo la exactitud de kNN baja de 0,962 sin ruido a 0,689 con 200 columnas.
Una buena variable nueva suele salir de entender el problema: qué debería importar y con qué forma. Echar todo lo que se pueda es una invitación al ruido.
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.
Ideas clave
- Una variable con una buena forma convierte un problema difícil en uno fácil: x² sube la exactitud del 60,4% al 77,4%.
- Un modelo lineal con columnas nuevas sigue siendo lineal; lo que cambia es lo que recibe como entrada.
- Las columnas sin información perjudican: 200 columnas de ruido bajan kNN del 98,1% al 77,4%.
- En muchas dimensiones las distancias se igualan, así que los modelos basados en distancias son los que más pierden.
Más a fondo: fórmula, código, práctica
Las matemáticas
La variable nueva: z = (x − x̄) / s, y el modelo lineal recibe (z, z²). La frontera w₁ · z + w₂ · z² + b = 0 es una ecuación cuadrática en z, así que tiene hasta dos raíces: dos umbrales en el eje x y un intervalo entre ellos.
La distancia en kNN: d(a, b)² = Σⱼ (aⱼ − bⱼ)² sobre todas las columnas. Para m columnas de ruido de N(0, 1), cada una aporta de media 2 a d² (la varianza de la diferencia de dos números independientes), sea cual sea la variedad. Con m grande, la suma del ruido ahoga los 13 términos reales, y el contraste (d_max − d_min) / d_min disminuye.
En código (Python)
El mismo experimento en scikit-learn: un modelo lineal sobre los flavonoides sin x² y con x² en validación cruzada 10 × 5, luego kNN con las 13 medidas y un número creciente de columnas de ruido.
import numpy as np
from sklearn.datasets import load_wine
from sklearn.model_selection import cross_val_score, RepeatedStratifiedKFold
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler, PolynomialFeatures
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
wine = load_wine(as_frame=True)
x, is2 = wine.data[["flavanoids"]], (wine.target == 1).astype(int)
cv = RepeatedStratifiedKFold(n_splits=5, n_repeats=10, random_state=0)
line = make_pipeline(StandardScaler(), SVC(kernel="linear", C=1))
squared = make_pipeline(StandardScaler(), PolynomialFeatures(2, include_bias=False), StandardScaler(), SVC(kernel="linear", C=1)) # la columna nueva x²
a, b = cross_val_score(line, x, is2, cv=cv), cross_val_score(squared, x, is2, cv=cv)
print(f"cultivar 2 vs the rest from flavanoids, 10 x 5 CV: x only {a.mean():.3f}, x and x^2 {b.mean():.3f}; always 'other' {1 - is2.mean():.3f}")
print(f"x only predicts cultivar 2 for {line.fit(x, is2).predict(x).sum()} of {len(x)} wines; x and x^2 wins in {(b > a).sum()} of 50 folds")
X, y = wine.data.to_numpy(), wine.target.to_numpy()
noise = np.random.default_rng(0).normal(size=(len(X), 200)) # columnas de ruido puro
for m in [0, 10, 50, 200]:
acc = cross_val_score(make_pipeline(StandardScaler(), KNeighborsClassifier(5)), np.hstack([X, noise[:, :m]]), y, cv=cv)
print(f"kNN on 13 measurements + {m} noise columns: {acc.mean():.3f}")
Resultado
cultivar 2 vs the rest from flavanoids, 10 x 5 CV: x only 0.601, x and x^2 0.755; always 'other' 0.601
x only predicts cultivar 2 for 0 of 178 wines; x and x^2 wins in 49 of 50 folds
kNN on 13 measurements + 0 noise columns: 0.962
kNN on 13 measurements + 10 noise columns: 0.940
kNN on 13 measurements + 50 noise columns: 0.842
kNN on 13 measurements + 200 noise columns: 0.689
Las particiones y el ruido son distintos de los del lab, así que los números también difieren un poco. La imagen es la misma: sin x² el modelo no predice ni una vez la variedad 2 (0,601, lo mismo que «siempre otra»), con x² obtiene 0,755 y gana en 49 de 50 partes de validación. El ruido baja kNN de 0,962 a 0,689.
Descargar el notebook (.ipynb). Ábrelo en Jupyter o súbelo a Google Colab; descarga por sí solo los datos que falten.
Para profesionales
- En scikit-learn:
PolynomialFeatures(2)añade cuadrados y productos de pares de variables,SplineTransformercurvas suaves,FunctionTransformer(np.log1p)un logaritmo para variables con cola larga. Mételos enmake_pipeline, para que la validación cruzada vea todo el camino. - Las mejores variables salen de conocer el problema: un cociente (precio por metro cuadrado), una diferencia (días desde la última compra), una parte de la fecha (día de la semana). El modelo no las inventará si no recibe los ingredientes en bruto en una buena forma.
- Cuando hay muchas variables, selecciónalas dentro de cada partición (
SelectKBesten el pipeline) o usa un modelo con regularización (lección 3.4). Seleccionar variables con todos los datos antes de validar es una fuga (lección 4.5). - Los métodos de núcleo que conocerás con las máquinas de vectores de soporte calculan el resultado como si hubieran añadido esas columnas, pero sin construirlas explícitamente.
¿Te ha sido útil?
¡Gracias! Nos ayuda a mejorar.
Profundiza en el Atlas
Entradas de la enciclopedia sobre las ideas de esta lección: