# machine-learning-clasico-con-python
Machine Learning con scikit-learn y XGBoost
Volver a la portada del cursoNotebook: del CSV sucio a un Pipeline sin fuga de datos
Sección 2 · Preparación de datos y pipelines
Del CSV sucio a un Pipeline sin fuga de datos
Este notebook integra todo el módulo de preparación de datos. Parte del CSV sucio de PyRitmo y termina en un Pipeline que imputa, codifica, escala y entrena sin dejar que el test se cuele en ningún paso. Esta guía acompaña al notebook csv-sucio-a-pipeline: qué hace cada sección y qué cifra debes encontrar.
1. El CSV sucio
Con generar_canciones (semilla 42) y ensuciar (semilla 7) se obtienen 1525 filas: 25 repetidas, 86 faltantes en tempo_bpm y 60 en seguidores_miles, 17 escrituras distintas para 5 géneros y 19 duraciones que vinieron en milisegundos.
2. Limpieza que no aprende de los datos
Quitar duplicados, unificar "POP" y "pop " y dividir entre 1000 las duraciones imposibles son reglas fijas: no calculan nada a partir de los datos y se pueden aplicar antes de partir, igual que en la lectura de datos sucios. Quedan 1500 canciones, 5 géneros y los faltantes reales (85 y 59), que no se rellenan aquí.
3. La regla de oro: fit en train, transform en el resto
Todo lo que aprende algo de los datos (la mediana para imputar, la media y la desviación para escalar, las categorías del one-hot) se ajusta solo con train y después se aplica a test y a las canciones futuras. La forma de cumplirlo sin pensar en cada paso es ponerlos dentro de un pipeline.
Para imputar las numéricas se usa la mediana: en seguidores_miles la media de train (231.9 mil) es 2.6 veces la mediana (88.2 mil) por culpa de unos pocos artistas enormes. Para el género, la categoría más frecuente.
4. El objeto pre y el pipeline
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
numericas = Pipeline([("imputar", SimpleImputer(strategy="median")),
("escalar", StandardScaler())])
categoricas = Pipeline([("imputar", SimpleImputer(strategy="most_frequent")),
("onehot", OneHotEncoder(handle_unknown="ignore", sparse_output=False))])
pre = ColumnTransformer([("num", numericas, NUMERICAS), ("cat", categoricas, CATEGORICAS)])
pipe = Pipeline([("pre", pre), ("modelo", LogisticRegression(max_iter=2000))])
pipe.fit(X_tr, y_tr)
Qué buscar: accuracy en test de 0.808 contra 0.725 del Dummy, y AUC de 0.847. El test tenía faltantes y el pipeline los rellenó con las medianas aprendidas en train (103 bpm y 88.2 mil seguidores), que se leen con named_steps. handle_unknown="ignore" evita que un género nuevo rompa la predicción.
5. La fuga, medida
Una celda imputa y escala con todo el dataset antes de partir y compara contra el pipeline correcto: AUC 0.8476 contra 0.8474. Aquí la diferencia es mínima, porque con 1500 canciones la mediana y la desviación casi no cambian por incluir el test. El procedimiento sigue siendo incorrecto: en producción no tendrás el test para calcular nada, y la cifra reportada debe salir del mismo proceso que usarás después.
La fuga se vuelve grave cuando el paso que se ajusta con todo aprende de y. El notebook lo muestra con 1000 columnas de puro ruido: elegir las 20 «mejores» con SelectKBest usando todo el dataset da un AUC de validación cruzada de 0.688, como si el ruido predijera el Top 50; con la selección dentro del pipeline da 0.54, cerca del azar, que es la verdad.
6. Nombres de columnas y salida en pandas
get_feature_names_out() devuelve las 14 columnas que recibe el modelo: 9 numéricas escaladas y 5 de género. Con set_output(transform="pandas"), transform devuelve un DataFrame con esos nombres, útil para revisar qué le llega al modelo. Este mismo pre se reutiliza en los notebooks siguientes.
7. Errores comunes
- Llamar
fit_transformsobre test: el escalador aprendería las medias del test. - Imputar o escalar antes de partir.
- Elegir columnas con todo el dataset y después validar.
- Usar la media para imputar columnas con atípicos fuertes.
8. Ejercicios
- Agregar
SelectKBest(f_classif, k=8)entreprey la logística: accuracy 0.808 (con 5 columnas baja a 0.803). - Imputar las numéricas con la media: 0.811. Unas milésimas de diferencia son ruido en 375 canciones.
- Predecir una canción con género
"cumbia", que no existía en train: sus 5 columnas de género quedan en cero y el modelo no se rompe.
Las soluciones están al final del notebook.