🎯 Objetivo del Post: Dominarás la regresión lineal, el algoritmo más fundamental del Machine Learning, desde conceptos básicos hasta implementación práctica con código.
📈 ¿Qué es la Regresión Lineal?
Imagina que tienes un conjunto de puntos en una hoja de papel y quieres dibujar la línea recta que mejor los atraviese. Esa línea representa una relación entre dos variables. La regresión lineal hace exactamente eso, pero con matemáticas precisas y datos reales.
La regresión lineal es un método estadístico que:
- 🎯 Encuentra la línea recta que mejor se ajusta a un conjunto de datos
- 🔮 Permite predecir valores futuros basándose en esta relación
- 🧮 Utiliza matemáticas simples pero poderosas
- 🚀 Es la base de algoritmos más complejos
🚀 ¿Por qué Empezar con Regresión Lineal?
- 🧠 Simplicidad: Es fácil de entender e implementar (perfecto para principiantes)
- 💬 Interpretabilidad: Los resultados son fáciles de explicar a cualquier audiencia
- 🏗️ Base sólida: Muchos algoritmos avanzados se basan en estos conceptos
- 🎯 Efectividad: A menudo funciona mejor de lo esperado en problemas reales
- ⚡ Velocidad: Es computacionalmente eficiente (milisegundos vs. minutos)
Regresión Lineal Simple: Una Variable
El Concepto Básico
En regresión lineal simple, tenemos:
- Variable independiente (X): La característica que usamos para predecir
- Variable dependiente (y): Lo que queremos predecir
- Relación lineal: y = mx + b
Para nuestro proyecto de autos:
- X: Año del auto
- y: Precio del auto
- Relación: Precio = m × Año + b
La Ecuación de la Línea
y = mx + b
Donde:
- m: Pendiente (slope) - cuánto cambia y por cada unidad de x
- b: Intercepto (intercept) - valor de y cuando x = 0
- x: Variable independiente
- y: Variable dependiente
Ejemplo Práctico
Si tenemos la ecuación: Precio = 1000 × Año + 5000
- Un auto del 2020:
Precio = 1000 × 2020 + 5000 = $2,025,000
- Un auto del 2015:
Precio = 1000 × 2015 + 5000 = $2,020,000
- Un auto del 2010:
Precio = 1000 × 2010 + 5000 = $2,015,000
Interpretación:
- La pendiente (1000) significa que por cada año más nuevo, el precio aumenta $1,000
- El intercepto (5000) sería el precio teórico de un auto del año 0 (no tiene sentido práctico)
Regresión Lineal Múltiple: Varias Variables
¿Por qué Necesitamos Múltiples Variables?
En la vida real, el precio de un auto no depende solo del año. También importan:
- Kilometraje
- Marca
- Modelo
- Tipo de transmisión
- Estado del vehículo
La Ecuación Múltiple
y = b₀ + b₁x₁ + b₂x₂ + b₃x₃ + ... + bₙxₙ
Para nuestro proyecto de autos:
Precio = b₀ + b₁×Año + b₂×Kilometraje + b₃×Edad + b₄×Marca_BMW + b₅×Marca_Toyota + ...
Donde:
- b₀: Intercepto (precio base)
- b₁, b₂, b₃...: Coeficientes para cada variable
- x₁, x₂, x₃...: Valores de cada característica
Forma Vectorial: Matemáticas Elegantes
¿Por qué Forma Vectorial?
La forma vectorial nos permite:
- Escribir ecuaciones de manera compacta
- Usar operaciones matriciales eficientes
- Implementar algoritmos de manera elegante
- Escalar a millones de datos
Representación Vectorial
En lugar de escribir:
y = b₀ + b₁x₁ + b₂x₂ + b₃x₃ + ... + bₙxₙ
Escribimos:
y = Xw
Donde:
- X: Matriz de características (m × n)
- w: Vector de pesos (n × 1)
- y: Vector de predicciones (m × 1)
Ejemplo Concreto
Si tenemos 3 autos y 2 características (año, kilometraje):
X = [[2020, 25000], # Auto 1: año 2020, 25,000 km
[2019, 30000], # Auto 2: año 2019, 30,000 km
[2021, 20000]] # Auto 3: año 2021, 20,000 km
w = [1000, -0.5] # Pesos: año=1000, kilometraje=-0.5
y = Xw = [2020×1000 + 25000×(-0.5), # = 2007500
2019×1000 + 30000×(-0.5), # = 2004000
2021×1000 + 20000×(-0.5)] # = 2011000
Implementación Práctica
Paso 1: Preparar los Datos
import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import StandardScaler
# Cargar datos
df = pd.read_csv('car_data_limpio.csv')
# Preparar características numéricas
features = ['año', 'kilometraje', 'edad_auto']
X = df[features]
y = df['precio']
print("Forma de X:", X.shape)
print("Forma de y:", y.shape)
print("\nPrimeras 5 filas de X:")
print(X.head())
Paso 2: Implementación Manual de Regresión Lineal
class LinearRegressionManual:
def __init__(self):
self.weights = None
self.bias = None
def fit(self, X, y):
"""Entrenar el modelo usando la ecuación normal"""
# Agregar columna de unos para el bias
X_with_bias = np.column_stack([np.ones(X.shape[0]), X])
# Calcular pesos usando ecuación normal: w = (X^T X)^-1 X^T y
XtX = np.dot(X_with_bias.T, X_with_bias)
XtX_inv = np.linalg.inv(XtX)
Xty = np.dot(X_with_bias.T, y)
weights_with_bias = np.dot(XtX_inv, Xty)
# Separar bias y pesos
self.bias = weights_with_bias[0]
self.weights = weights_with_bias[1:]
return self
def predict(self, X):
"""Hacer predicciones"""
return np.dot(X, self.weights) + self.bias
# Usar nuestro modelo manual
modelo_manual = LinearRegressionManual()
modelo_manual.fit(X, y)
print("Pesos aprendidos:")
for i, feature in enumerate(features):
print(f"{feature}: {modelo_manual.weights[i]:.2f}")
print(f"Bias: {modelo_manual.bias:.2f}")
Paso 3: Usando scikit-learn
# Usar la implementación de scikit-learn
modelo_sklearn = LinearRegression()
modelo_sklearn.fit(X, y)
print("Pesos de scikit-learn:")
for i, feature in enumerate(features):
print(f"{feature}: {modelo_sklearn.coef_[i]:.2f}")
print(f"Intercepto: {modelo_sklearn.intercept_:.2f}")
# Verificar que son iguales
print(f"\n¿Son iguales? {np.allclose(modelo_manual.weights, modelo_sklearn.coef_)}")
La Ecuación Normal: La Matemática Detrás
¿Qué es la Ecuación Normal?
La ecuación normal es una fórmula matemática que nos da la solución exacta para encontrar los mejores pesos en regresión lineal.
Fórmula: w = (X^T X)^(-1) X^T y
Donde:
- X: Matriz de características
- X^T: Transpuesta de X
- y: Vector de valores objetivo
- w: Vector de pesos óptimos
¿Por qué Funciona?
La ecuación normal encuentra los pesos que minimizan la suma de errores cuadrados:
SSE = Σ(y_i - ŷ_i)² = Σ(y_i - (w₀ + w₁x₁ + w₂x₂ + ...))²
Ventajas y Desventajas
Ventajas:
- Solución exacta: No necesita iteraciones
- Matemáticamente elegante: Una sola fórmula
- Determinística: Siempre da el mismo resultado
Desventajas:
- Computacionalmente costosa: O(n³) para matrices grandes
- Problemas numéricos: Con matrices mal condicionadas
- No escalable: Para datasets muy grandes
Visualización de Resultados
Paso 1: Predicciones vs Valores Reales
import matplotlib.pyplot as plt
# Hacer predicciones
y_pred = modelo_sklearn.predict(X)
# Crear gráfico de dispersión
plt.figure(figsize=(10, 6))
plt.scatter(y, y_pred, alpha=0.5, color='blue')
plt.plot([y.min(), y.max()], [y.min(), y.max()], 'r--', lw=2)
plt.xlabel('Precio Real ($)')
plt.ylabel('Precio Predicho ($)')
plt.title('Precio Real vs Predicho')
plt.grid(True, alpha=0.3)
# Calcular R²
from sklearn.metrics import r2_score
r2 = r2_score(y, y_pred)
plt.text(0.05, 0.95, f'R² = {r2:.3f}', transform=plt.gca().transAxes,
bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))
plt.show()
Paso 2: Residuos (Errores)
# Calcular residuos
residuos = y - y_pred
# Gráfico de residuos
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
plt.scatter(y_pred, residuos, alpha=0.5, color='green')
plt.axhline(y=0, color='r', linestyle='--')
plt.xlabel('Precio Predicho ($)')
plt.ylabel('Residuos ($)')
plt.title('Gráfico de Residuos')
plt.grid(True, alpha=0.3)
plt.subplot(1, 2, 2)
plt.hist(residuos, bins=30, alpha=0.7, color='orange')
plt.xlabel('Residuos ($)')
plt.ylabel('Frecuencia')
plt.title('Distribución de Residuos')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
Interpretación de Resultados
Coeficientes y su Significado
# Crear DataFrame con coeficientes
coef_df = pd.DataFrame({
'Característica': features,
'Coeficiente': modelo_sklearn.coef_,
'Significado': [
'Por cada año más nuevo, el precio aumenta $' + f'{modelo_sklearn.coef_[0]:,.0f}',
'Por cada km adicional, el precio disminuye $' + f'{abs(modelo_sklearn.coef_[1]):.2f}',
'Por cada año de edad, el precio disminuye $' + f'{abs(modelo_sklearn.coef_[2]):,.0f}'
]
})
print("Interpretación de Coeficientes:")
print(coef_df)
Ejemplo de Predicción
# Ejemplo: Predecir precio de un auto específico
auto_ejemplo = {
'año': 2020,
'kilometraje': 25000,
'edad_auto': 4
}
# Convertir a array
X_ejemplo = np.array([list(auto_ejemplo.values())])
# Hacer predicción
precio_predicho = modelo_sklearn.predict(X_ejemplo)[0]
print(f"\nEjemplo de Predicción:")
print(f"Auto: Año {auto_ejemplo['año']}, {auto_ejemplo['kilometraje']:,} km")
print(f"Precio predicho: ${precio_predicho:,.2f}")
# Mostrar contribución de cada característica
contribuciones = modelo_sklearn.coef_ * X_ejemplo[0]
print(f"\nContribuciones:")
for i, feature in enumerate(features):
print(f"{feature}: ${contribuciones[i]:,.2f}")
print(f"Intercepto: ${modelo_sklearn.intercept_:,.2f}")
print(f"Total: ${modelo_sklearn.intercept_ + contribuciones.sum():,.2f}")
Limitaciones de la Regresión Lineal
1. Asume Relación Lineal
- No puede capturar relaciones no lineales
- Ejemplo: La depreciación de autos no es lineal
2. Sensible a Outliers
- Un auto muy caro puede sesgar toda la línea
- Necesita detección y manejo de outliers
3. Multicolinealidad
- Si dos características están muy correlacionadas, los coeficientes pueden ser inestables
- Ejemplo: Año y edad del auto están perfectamente correlacionadas
4. No Maneja Variables Categóricas Directamente
- Necesita codificación (one-hot encoding)
- Ejemplo: Marca = ["Toyota", "BMW", "Honda"]
Mejores Prácticas
1. Verificar Supuestos
# Verificar linealidad
plt.figure(figsize=(15, 5))
for i, feature in enumerate(features):
plt.subplot(1, 3, i+1)
plt.scatter(X[feature], y, alpha=0.5)
plt.xlabel(feature)
plt.ylabel('Precio')
plt.title(f'Precio vs {feature}')
plt.tight_layout()
plt.show()
2. Normalizar Variables
# Normalizar características
scaler = StandardScaler()
X_normalizado = scaler.fit_transform(X)
# Entrenar modelo con datos normalizados
modelo_normalizado = LinearRegression()
modelo_normalizado.fit(X_normalizado, y)
print("Coeficientes normalizados:")
print(modelo_normalizado.coef_)
3. Validación Cruzada
from sklearn.model_selection import cross_val_score
# Validación cruzada
scores = cross_val_score(modelo_sklearn, X, y, cv=5, scoring='r2')
print(f"R² promedio: {scores.mean():.3f} (+/- {scores.std() * 2:.3f})")
Conclusión
La regresión lineal es el fundamento de muchos algoritmos de Machine Learning. Aunque simple, es poderosa y nos enseña conceptos importantes:
- Interpretabilidad: Cada coeficiente tiene significado
- Eficiencia: Rápida de entrenar y predecir
- Base sólida: Para algoritmos más complejos
Puntos clave:
- La forma vectorial hace el código más elegante
- La ecuación normal da la solución exacta
- Los coeficientes son interpretables
- Siempre verifica los supuestos del modelo
En el siguiente post, exploraremos cómo evaluar qué tan bien funciona nuestro modelo usando métricas como RMSE y cómo crear un modelo baseline para comparar.
¿Has usado regresión lineal antes? ¿Qué variables crees que serían más importantes para predecir el precio de un auto?
Top comments (0)