# fundamentos-de-scikit-learn
Fundamentos de Scikit-learn
Volver a la portada del cursoTransformación de Datos
Sección 2 · Preprocesamiento de Datos
Transformación de datos
Un modelo de scikit-learn solo acepta números, sin huecos. La tabla de PyEnvíos tiene de las dos cosas que estorban: 101 entregas sin peso_kg, 62 sin zona, y tres columnas de texto (zona, transporte, dia). Antes de entrenar hay que convertir esa tabla en una matriz numérica completa. Scikit-learn lo hace con transformadores: objetos que aprenden algo de los datos con fit y lo aplican con transform.
La regla de oro: fit en train, transform en todo lo demás
Un transformador aprende parámetros: una mediana, una lista de categorías, una media. Esos parámetros deben salir solo del conjunto de entrenamiento. Si se calculan con todos los datos, el modelo ve información del examen antes de presentarlo; eso se llama fuga de datos y produce métricas demasiado optimistas. La documentación de scikit-learn lo resume así: nunca llames fit sobre los datos de prueba. Por eso primero se parte (train 1500, test 500) y después se ajusta:
from sklearn.impute import SimpleImputer
imp = SimpleImputer(strategy="median")
imp.fit(X_tr[["peso_kg"]])
print(imp.statistics_) # [1.81]
peso_te = imp.transform(X_te[["peso_kg"]])
La mediana de train es 1.81 kg; con las 2000 filas sería 1.84. La diferencia es pequeña aquí, pero el principio no cambia: el test se rellena con lo que se aprendió en train, igual que un pedido nuevo mañana.
Imputar faltantes con SimpleImputer
strategy="median" sirve para numéricas con atípicos; "mean" para numéricas simétricas; "most_frequent" para categóricas (en train, la zona más común es Centro); "constant" con fill_value cuando el faltante tiene un significado propio, como «sin zona». El valor aprendido queda en statistics_.
Categorías a columnas: OneHotEncoder
Un modelo no sabe qué es «bicicleta». OneHotEncoder crea una columna 0/1 por categoría: transporte se convierte en 3 columnas, transporte_bicicleta, transporte_camioneta y transporte_moto.
from sklearn.preprocessing import OneHotEncoder
ohe = OneHotEncoder(handle_unknown="ignore", sparse_output=False)
ohe.fit(X_tr[["transporte"]])
print(ohe.get_feature_names_out())
nuevo = pd.DataFrame({"transporte": ["dron"]})
print(ohe.transform(nuevo)) # [[0. 0. 0.]]
Con el valor por omisión, handle_unknown="error", una categoría que no apareció en train («dron») lanza ValueError: Found unknown categories. Con "ignore" la fila queda en ceros y el modelo sigue funcionando.
Cuándo usar OrdinalEncoder
OrdinalEncoder asigna un entero por categoría en una sola columna. Solo tiene sentido si las categorías tienen orden y se lo das explícito, por ejemplo OrdinalEncoder(categories=[DIAS]) convierte lun, vie y dom en 0, 4 y 6. Sin categories, el orden es alfabético (dom = 0, jue = 1, lun = 2…) y no el de la semana. Para categorías sin orden, como la zona, usa one-hot. Los modelos de árboles toleran mejor los códigos ordinales.
Todo junto: ColumnTransformer
Cada tipo de columna necesita su propio tratamiento. ColumnTransformer aplica un transformador a cada grupo y concatena los resultados:
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
num = make_pipeline(SimpleImputer(strategy="median"),
StandardScaler())
cat = make_pipeline(SimpleImputer(strategy="most_frequent"),
OneHotEncoder(handle_unknown="ignore"))
pre = ColumnTransformer([("num", num, NUMERICAS),
("cat", cat, CATEGORICAS)])
Xt = pre.fit_transform(X_tr)
print(Xt.shape) # (1500, 21)
print(pre.get_feature_names_out()[:3])
Las 9 columnas originales se convierten en 21: 6 numéricas, 5 de zona, 3 de transporte y 7 de día. get_feature_names_out devuelve los nombres con el prefijo de cada rama, como num__distancia_km o cat__zona_Centro; los usarás para leer los coeficientes del modelo. pre.transform(X_te) devuelve (500, 21) sin ningún faltante.
Salida como DataFrame
Por omisión los transformadores devuelven arreglos de NumPy. Con set_config(transform_output="pandas") devuelven DataFrames con esos mismos nombres de columna, más fáciles de revisar. Ojo: la salida pandas no admite matrices dispersas, y OneHotEncoder es disperso por omisión; hay que pasarle sparse_output=False.
Trampas comunes
- Ajustar con todos los datos.
fit_transform(X)antes de partir filtra información del test. - Volver a ajustar en test.
fit_transform(X_te)calcula otra mediana y otras categorías; en test solo vatransform. - Olvidar
handle_unknown="ignore". El modelo falla con la primera categoría nueva en producción. - Codificar ordinal algo sin orden. Inventa distancias entre zonas que no existen.
- Usar la respuesta como columna.
minutosno entra enX: es justo lo que definetarde.
El notebook transformacion-de-datos repite cada paso con la salida a la vista. Desde aquí, pre es la pieza fija del curso: en la próxima sección se le añade un modelo al final.