Modelos de ML: Por Qué Tu Predicción Es Buena… Hasta Que No Lo Es


Una inmersión técnica en el verdadero trabajo de un Data Scientist: Feature Engineering, Pipelines y Métricas de Negocio.

Te paso algo que vivimos todos los días en la industria: hay una abrumadora diferencia entre saber escribir model.fit(X, y) en un Jupyter Notebook y construir un sistema de Machine Learning que realmente genere confianza en una reunión de directores.

La mayoría de los tutoriales te enseñan a predecir el precio de una casa en Boston o clasificar flores de Iris. Son ejercicios académicos. Pero en el mundo real, los datos son sucios, los requerimientos cambian y tu modelo, en producción, falla silenciosamente.

Hoy vamos a dejar de lado los “Hello World”. Vamos a ver por qué tu modelo fallaría mañana si solo entrenas hoy, y cómo usar Scikit-Learn como un ingeniero de datos profesional, no como un hobbyista.



El Escenario Realista

Imaginemos que somos el equipo de Data de una inmobiliaria en Buenos Aires. Nos piden un modelo para estimar el precio de venta (precio_final) de un departamento.

Tenemos datos que parecen simples, pero tienen trampas:

  • m2_totales: El tamaño real.
  • barrio: Categórico (Palermo, Recoleta, etc.).
  • antiguedad: En años.
  • tiene_pileta: 0 o 1.
  • fecha_venta: Un timestamp.



1. La Trampa: El Modelo que Vemos en YouTube

Si hacemos lo básico, importamos Pandas, limpiamos un nulo y hacemos un LinearRegression o RandomForest rápido.

El problema:

  1. Si entra un dato nuevo sin escalar, el modelo se vuelve loco.
  2. Si olvidamos One-Hot Encoding en el barrio, el modelo se rompe.
  3. Si el modelo aprende a predecir “basura” (Data Leakage), parecerá perfecto en desarrollo, pero perderá plata en la realidad.



2. La Solución Profesional: Pipelines y Preprocesamiento

En Python Baires enseñamos que la clave del éxito no es el algoritmo (todos usan Random Forest), sino la tubería (Pipeline) que limpia y prepara los datos. Usaremos ColumnTransformer y Pipeline de Scikit-Learn para automatizar el caos.

Primero, generemos datos sucios (como los que encontrarás en la vida real):

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score

# --- 1. SIMULACIÓN DE DATOS SUCIOS ---
np.random.seed(42)
n_muestras = 1000

data = {
    'm2_totales': np.random.normal(70, 30, n_muestras).astype(float),
    'barrio': np.random.choice(['Palermo', 'Recoleta', 'Caballito', 'Almagro'], n_muestras),
    'antiguedad': np.random.randint(0, 60, n_muestras).astype(float),
    'tiene_pileta': np.random.choice([0, 1], n_muestras, p=[0.7, 0.3]),
}

df = pd.DataFrame(data)

# Introducimos errores humanos (nulos, outliers)
df.loc[5:15, 'm2_totales'] = np.nan 
df.loc[20:25, 'antiguedad'] = np.nan
df.loc[30, 'barrio'] = 'sin dato' # Categoría sucia
df.loc[35, 'antiguedad'] = 150  # Outlier imposible

# Generamos el target (y) AÑADIENDO RUIDO A UNA OPERACIÓN LÓGICA
# Nota: Rellenamos nulos en la generación para evitar NaNs en 'y', 
# pero en el Pipeline se manejarán de nuevo para demostrar el flujo real.
df['precio_final'] = (df['m2_totales'].fillna(0) * 2500 + 
                      df['antiguedad'].fillna(0) * -100 + 
                      df['tiene_pileta'] * 15000 + 
                      np.random.normal(0, 20000, n_muestras))

# --- 2. SEPARACIÓN Y VALIDACIÓN INICIAL ---
# Garantizamos que el target 'y' no tenga NaNs antes de empezar
df = df.dropna(subset=['precio_final'])

X = df.drop('precio_final', axis=1)
y = df['precio_final']

# Hacemos el split DE INMEDIATO para evitar Data Leakage
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

print("Datos listos. Observa la columna 'barrio' y los NaN en m2:")
print(X_train.head())
Enter fullscreen mode

Exit fullscreen mode



3. Diseñando el Flujo de Trabajo (Workflow)

Aquí es donde demostramos autoridad. En lugar de limpiar el DataFrame manualmente, creamos un objeto que encapsula la lógica.

Nuestro flujo debe hacer tres cosas:

  1. Imputar valores numéricos: (Ej. llenar los NaN de m2 con la mediana).
  2. Escalar valores numéricos: (Estandarización para que antiguedad no tenga peso por ser un número grande).
  3. Procesar categóricos: (Convertir ‘Palermo’, ‘Recoleta’ en números binarios).
# 1. Definimos qué columnas son qué
numeric_features = ['m2_totales', 'antiguedad', 'tiene_pileta']
categorical_features = ['barrio']

# 2. Creamos los "tubos" de procesamiento
# Para números: rellenamos nulos y escalamos
numeric_transformer = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='median')), # Llena nulos con mediana
    ('scaler', StandardScaler()) # Estandariza
])

# Para categorías: rellenamos nulos y hacemos One-Hot Encoding
categorical_transformer = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='most_frequent')), # Maneja strings
    ('encoder', OneHotEncoder(handle_unknown='ignore'))
])

# 3. Juntamos todo en un ColumnTransformer
preprocessor = ColumnTransformer(
    transformers=[
        ('num', numeric_transformer, numeric_features),
        ('cat', categorical_transformer, categorical_features)
    ])

# 4. Construimos el Pipeline final (Preprocesador + Modelo)
full_pipeline = Pipeline(steps=[
    ('preprocessor', preprocessor),
    ('regressor', RandomForestRegressor(n_estimators=100, random_state=42, n_jobs=-1))
])

# Entrenamos (esto transforma y entrena en un solo paso)
full_pipeline.fit(X_train, y_train)

# Predicciones
y_pred = full_pipeline.predict(X_test)
Enter fullscreen mode

Exit fullscreen mode



4. No Engañes al Negocio: Evaluación Correcta

En un tutorial básico te dirían solo el R2. En la industria, nos importa el error en plata.

  • MAE (Error Absoluto Medio): “En promedio, nuestro modelo se equivoca en X pesos.”
  • RMSE (Error Cuadrático Medio): Penaliza mucho más los errores grandes (fundamental si no quieres que el modelo se equivoque grotescamente en casos raros).
mae = mean_absolute_error(y_test, y_pred)
rmse = np.sqrt(mean_squared_error(y_test, y_pred))
r2 = r2_score(y_test, y_pred)

print(f"\n--- REPORTE DE NEGOCIO ---")
print(f"R2 Score: {r2:.3f} (Explica el {r2*100:.1f}% de la varianza del precio)")
print(f"MAE: ${mae:,.0f} (Error promedio absoluto)")
print(f"RMSE: ${rmse:,.0f} (Desviación del error)")

# Demostración de uso final
print(f"\n--- PREDICCIÓN DE EJEMPLO ---")
ejemplo = pd.DataFrame({
    'm2_totales': [85.0],
    'barrio': ['Palermo'],
    'antiguedad': [10.0],
    'tiene_pileta': [1]
})
precio_estimado = full_pipeline.predict(ejemplo)[0]
print(f"Un depto en Palermo de 85m2 con pileta se estima en: ${precio_estimado:,.0f}")
Enter fullscreen mode

Exit fullscreen mode

¿Qué significa esto para tu jefe?
Si el MAE es 15.000 pesos, significa que, en promedio, el modelo se equiv oca ese monto. Si el RMSE es 50.000, significa que hay casos donde el error es muchísimo mayor (quizás departamentos de lujo donde el modelo no aprendió bien).



La Brecha de Conocimiento (Y por qué estás leyendo esto)

Lo que acabamos de ver es el estándar mínimo de calidad para un modelo que entre en producción. Pero…

  • No vimos Optimización de Hiperparámetros: (GridSearch, RandomizedSearch) para tunear el modelo.
  • No vimos Despliegue (Deployment): (¿Cómo expones esto como una API REST con FastAPI o Flask para que la inmobiliaria lo use en su web?).
  • No vimos Deep Learning: (Cuando los problemas tienen patrones mucho más complejos que una regresión lineal).

Estos son los saltos que separan a un Programador Junior de Python de un Senior Data Scientist.



El Siguiente Paso

Copiar código de un blog es fácil. Entender por qué ese código falla cuando cambias el tamaño del dataset o cuando entran datos nuevos de una fuente distinta… eso es lo que define tu carrera.

Si querés dejar de ser el “chico de Python” que arregla scripts y empezar a diseñar soluciones de IA que transforman empresas, en Python Baires tenemos el curso de Machine Learning más completo del mercado local.

Aprendés con expertos que trabajan en la industria desde los fundamentos (como viste hoy) hasta modelos avanzados y despliegue en la nube.

No es solo aprender a codear. Es aprender a resolver.

Mirá el programa completo y reservá tu lugar:
👉 https://www.python-baires.ar/Curso-ml.html



Source link