NUCBA
18 de marzo de 2026
IA

Tu primer modelo de ML siempre falla: cómo evitar los errores

Los primeros modelos de machine learning son un desastre. Overfitting, datos sucios, métricas confusas. Te muestro cómo entrenar uno que funcione.

NUCBA

NUCBA

6 min de lectura

Entrenar tu primer modelo de machine learning es como aprender a manejar: vas a chocar varias veces antes de salir a la ruta. La diferencia es que acá no hay instructor al lado diciéndote "frená".

La realidad es que el 80% de los primeros modelos terminan sobreajustados, con métricas engañosas o directamente prediciendo cualquier cosa. No es tu culpa - es que nadie te cuenta los errores típicos antes de que te los encuentres.

Por qué fallan los primeros modelos de ML

Antes de tocar código, entendé los tres problemas más comunes:

Overfitting desde el día uno: Tu modelo memoriza los datos de entrenamiento en lugar de aprender patrones generales. Es como estudiar de memoria las respuestas del examen del año pasado.

Datos sin limpiar: Valores faltantes, outliers extremos, features que no aportan nada. Tu modelo va a aprender ruido en lugar de señal.

Métricas que mienten: Una accuracy del 95% suena genial hasta que descubrís que tu dataset tiene 95% de una sola clase.

Dataset real: precios de casas en Boston

Vamos a usar el dataset de precios de viviendas de Boston. Es perfecto para empezar porque:

  • Tiene problemas reales (outliers, correlaciones raras)
  • Es pequeño (506 registros)
  • La variable target es continua (precio en miles de dólares)
import pandas as pd
import numpy as np
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error, r2_score
import matplotlib.pyplot as plt

# Cargamos el dataset
boston = load_boston()
X = pd.DataFrame(boston.data, columns=boston.feature_names)
y = boston.target

# Primer vistazo a los datos
print(f"Shape del dataset: {X.shape}")
print(f"Precio promedio: ${y.mean():.2f}k")
print(f"Features: {list(X.columns)}")

Explorá los datos antes que nada

Este es el error número uno: saltar directo al modelo. Necesitás entender qué estás modelando.

# Estadísticas básicas
print(X.describe())

# Buscamos valores faltantes
print("Valores nulos por columna:")
print(X.isnull().sum())

# Distribución del target
plt.figure(figsize=(10, 4))
plt.subplot(1, 2, 1)
plt.hist(y, bins=30, alpha=0.7)
plt.title('Distribución de precios')
plt.xlabel('Precio (miles de USD)')

plt.subplot(1, 2, 2)
plt.boxplot(y)
plt.title('Boxplot de precios')
plt.show()

# Correlación con el target
correlations = X.corrwith(pd.Series(y, name='price')).sort_values(ascending=False)
print("\nCorrelaciones más fuertes:")
print(correlations.head())
print(correlations.tail())

Lo que vas a encontrar:

  • Algunos outliers en precios (casas de +40k cuando el promedio es 22k)
  • La feature RM (promedio de habitaciones) correlaciona fuerte con el precio
  • LSTAT (% población de bajos ingresos) correlaciona negativo

Preparación de datos sin drama

Acá es donde la mayoría se complica con transformaciones innecesarias. Mantené la lógica simple:

# Split básico
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# Escalado - importante para algunos algoritmos
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# Convertimos de vuelta a DataFrame para mantener los nombres
X_train_scaled = pd.DataFrame(X_train_scaled, columns=X.columns)
X_test_scaled = pd.DataFrame(X_test_scaled, columns=X.columns)

print(f"Train set: {X_train_scaled.shape}")
print(f"Test set: {X_test_scaled.shape}")

¿Por qué StandardScaler? Features como CHAS (cerca del río) son binarias (0 o 1), mientras que DIS (distancia a centros de empleo) va de 1 a 12. Sin escalado, el modelo va a darle más peso a las features con valores más grandes.

Tu primer modelo que no sea un desastre

Random Forest es tu amigo para empezar. Es robusto, maneja outliers bien y no necesita tanto tuning.

# Modelo básico
rf = RandomForestRegressor(
    n_estimators=100,
    random_state=42,
    max_depth=10  # Evitamos overfitting
)

# Entrenamiento
rf.fit(X_train_scaled, y_train)

# Predicciones
y_train_pred = rf.predict(X_train_scaled)
y_test_pred = rf.predict(X_test_scaled)

# Métricas
train_mse = mean_squared_error(y_train, y_train_pred)
test_mse = mean_squared_error(y_test, y_test_pred)
train_r2 = r2_score(y_train, y_train_pred)
test_r2 = r2_score(y_test, y_test_pred)

print(f"Train MSE: {train_mse:.2f}")
print(f"Test MSE: {test_mse:.2f}")
print(f"Train R²: {train_r2:.3f}")
print(f"Test R²: {test_r2:.3f}")

Cómo saber si tu modelo funciona

Las métricas te van a confundir al principio. Acá está lo que realmente importa:

MSE (Mean Squared Error): Si el MSE de test es mucho mayor que el de train, tenés overfitting. Una diferencia del 20-30% es normal.

R² Score: Qué porcentaje de la varianza explica tu modelo. 0.7+ está bien para un primer modelo.

# Visualización clave: predicho vs real
plt.figure(figsize=(10, 4))

plt.subplot(1, 2, 1)
plt.scatter(y_train, y_train_pred, alpha=0.6)
plt.plot([y_train.min(), y_train.max()], [y_train.min(), y_train.max()], 'r--')
plt.xlabel('Precio real')
plt.ylabel('Precio predicho')
plt.title('Train Set')

plt.subplot(1, 2, 2)
plt.scatter(y_test, y_test_pred, alpha=0.6)
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--')
plt.xlabel('Precio real')
plt.ylabel('Precio predicho')
plt.title('Test Set')

plt.tight_layout()
plt.show()

# Feature importance
importances = pd.DataFrame({
    'feature': X.columns,
    'importance': rf.feature_importances_
}).sort_values('importance', ascending=False)

print("\nFeatures más importantes:")
print(importances.head())

Errores que vas a cometer (y cómo evitarlos)

Error 1: No usar random_state

# MAL
rf = RandomForestRegressor(n_estimators=100)

# BIEN
rf = RandomForestRegressor(n_estimators=100, random_state=42)

Sin random_state, cada run te va a dar resultados diferentes.

Error 2: Evaluar solo en train

# MAL - solo mirás train
train_score = rf.score(X_train, y_train)

# BIEN - comparás train vs test
train_score = rf.score(X_train_scaled, y_train)
test_score = rf.score(X_test_scaled, y_test)
print(f"Diferencia: {abs(train_score - test_score):.3f}")

Error 3: Hiperparámetros extremos

# MAL - overfitting garantizado
rf = RandomForestRegressor(n_estimators=1000, max_depth=None)

# BIEN - conservador para empezar
rf = RandomForestRegressor(n_estimators=100, max_depth=10)

Próximos pasos sin morir

Cuando tengas este modelo funcionando, podés:

  1. Probar otros algoritmos: LinearRegression, XGBoost
  2. Feature engineering: Crear nuevas variables combinando existentes
  3. Cross-validation: Para estar más seguro de tus métricas
  4. Hyperparameter tuning: Pero recién después de dominar lo básico

Tu primer modelo no va a ser perfecto. El objetivo es que funcione y que entiendas por qué. Una vez que controlés este flujo básico, podés empezar a optimizar.

Preguntas frecuentes

¿Por qué Random Forest y no regresión lineal? Random Forest maneja automáticamente interacciones entre features y es más resistente a outliers. Para empezar, es más fácil de usar.

¿Cuándo sé que tengo overfitting? Cuando tu R² en train es 0.95+ pero en test baja a 0.70 o menos. También si el MSE de test es más del doble que el de train.

¿Necesito más datos siempre? No siempre. Si tu modelo ya está sobreajustado, más datos pueden ayudar. Pero mejor entendé bien los datos que tenés antes de buscar más.

¿Te gustó este artículo?

Descubre nuestros cursos y carreras para llevar tus habilidades al siguiente nivel.