Lección 19 de 29Módulo 4: Estadística Aplicada

19. Correlaciones y Regresión Lineal

Análisis de correlaciones, regresión simple y múltiple

30 minutos

Descubre cómo identificar relaciones entre variables y predecir comportamientos futuros usando correlaciones y regresión lineal. Estas técnicas son fundamentales para análisis predictivo y toma de decisiones basada en datos.

¿Por qué correlaciones y regresión son cruciales?

En el mundo del análisis de datos, entender las relaciones entre variables es esencial para:

  • Predecir comportamientos: ¿Cómo afecta el gasto en marketing a las ventas?
  • Identificar drivers de negocio: ¿Qué factores impulsan la retención de clientes?
  • Optimizar recursos: ¿Dónde invertir para maximizar resultados?
  • Validar hipótesis: ¿Existe realmente una relación entre dos variables?

Caso real: E-commerce Analytics

Imagina que trabajas en un e-commerce y necesitas responder:

  • ¿El tiempo en la página aumenta las conversiones?
  • ¿El número de productos vistos predice el valor del carrito?
  • ¿Las visitas desde redes sociales convierten mejor que las orgánicas?

Correlaciones y regresión te dan respuestas cuantificables a estas preguntas.

Correlación: Midiendo relaciones entre variables

¿Qué es la correlación?

La correlación mide la fuerza y dirección de la relación lineal entre dos variables continuas. Se expresa con el coeficiente de correlación de Pearson (r), que va de -1 a +1:

  • r = +1: Correlación positiva perfecta (cuando una sube, la otra también)
  • r = 0: Sin correlación (variables independientes)
  • r = -1: Correlación negativa perfecta (cuando una sube, la otra baja)

Cálculo de correlaciones con Pandas

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# Datos de un e-commerce (simulados pero realistas)
np.random.seed(42)
n_users = 500

data = pd.DataFrame({
    'tiempo_pagina_min': np.random.normal(5, 2, n_users),
    'productos_vistos': np.random.randint(1, 20, n_users),
    'sesiones_ultimo_mes': np.random.randint(1, 15, n_users),
    'valor_carrito': np.random.normal(150, 50, n_users),
    'edad': np.random.randint(18, 65, n_users)
})

# Agregar relación artificial: más productos vistos = mayor valor carrito
data['valor_carrito'] = data['valor_carrito'] + (data['productos_vistos'] * 8)

# Calcular correlación entre dos variables
correlacion = data['productos_vistos'].corr(data['valor_carrito'])
print(f"Correlación productos vistos vs. valor carrito: {correlacion:.3f}")
# Output: Correlación productos vistos vs. valor carrito: 0.827

Matriz de correlaciones

Para analizar múltiples variables simultáneamente, usa una matriz de correlaciones:

# Matriz de correlaciones completa
correlation_matrix = data.corr()
print(correlation_matrix)

# Visualización con heatmap
plt.figure(figsize=(10, 8))
sns.heatmap(correlation_matrix,
            annot=True,          # Mostrar valores
            cmap='coolwarm',     # Colores: rojo=positivo, azul=negativo
            center=0,            # Centrar en cero
            vmin=-1, vmax=1,     # Rango -1 a 1
            square=True,         # Celdas cuadradas
            linewidths=0.5)
plt.title('Matriz de Correlaciones - E-commerce Metrics', fontsize=14, weight='bold')
plt.tight_layout()
plt.savefig('correlation_matrix.png', dpi=300)
plt.show()

Interpretación de correlaciones

# Encontrar las correlaciones más fuertes con valor_carrito
correlaciones_carrito = correlation_matrix['valor_carrito'].sort_values(ascending=False)
print("Correlaciones con valor_carrito:\n")
print(correlaciones_carrito)

# Interpretación automática
def interpretar_correlacion(r):
    """Interpreta el coeficiente de correlación"""
    r_abs = abs(r)
    if r_abs >= 0.7:
        fuerza = "fuerte"
    elif r_abs >= 0.4:
        fuerza = "moderada"
    elif r_abs >= 0.2:
        fuerza = "débil"
    else:
        fuerza = "muy débil o inexistente"

    direccion = "positiva" if r > 0 else "negativa"
    return f"Correlación {fuerza} {direccion} (r={r:.3f})"

# Análisis automático
for variable, valor in correlaciones_carrito.items():
    if variable != 'valor_carrito':
        print(f"{variable}: {interpretar_correlacion(valor)}")

⚠️ Advertencia: Correlación NO implica causalidad. Que dos variables estén correlacionadas no significa que una cause la otra. Puede haber una tercera variable (confounding variable) que afecte a ambas.

Regresión Lineal Simple

Concepto fundamental

La regresión lineal modela la relación entre:

  • Variable dependiente (Y): Lo que queremos predecir (ej: ventas)
  • Variable independiente (X): Lo que usamos para predecir (ej: gasto en marketing)

La ecuación es: Y = β₀ + β₁X + ε

Donde:

  • β₀ (intercept): Valor de Y cuando X = 0
  • β₁ (slope): Cambio en Y por cada unidad de cambio en X
  • ε (error): Residuo no explicado por el modelo

Implementación con Scikit-learn

from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score, mean_squared_error, mean_absolute_error

# Preparar datos
X = data[['productos_vistos']]  # Variable independiente (debe ser 2D)
y = data['valor_carrito']        # Variable dependiente (1D)

# Crear y entrenar modelo
modelo = LinearRegression()
modelo.fit(X, y)

# Coeficientes del modelo
print(f"Intercepto (β₀): ${modelo.intercept_:.2f}")
print(f"Pendiente (β₁): ${modelo.coef_[0]:.2f}")
print(f"\nInterpretación:")
print(f"Por cada producto adicional visto, el valor del carrito aumenta ${modelo.coef_[0]:.2f}")

# Predicciones
y_pred = modelo.predict(X)

# Métricas de evaluación
r2 = r2_score(y, y_pred)
rmse = np.sqrt(mean_squared_error(y, y_pred))
mae = mean_absolute_error(y, y_pred)

print(f"\nMétricas del modelo:")
print(f"R² (varianza explicada): {r2:.3f} ({r2*100:.1f}%)")
print(f"RMSE (error promedio): ${rmse:.2f}")
print(f"MAE (error absoluto): ${mae:.2f}")

Visualización de regresión

# Scatter plot con línea de regresión
plt.figure(figsize=(10, 6))
plt.scatter(X, y, alpha=0.5, label='Datos reales')
plt.plot(X, y_pred, color='red', linewidth=2, label='Línea de regresión')
plt.xlabel('Productos Vistos', fontsize=12)
plt.ylabel('Valor del Carrito ($)', fontsize=12)
plt.title('Regresión Lineal: Productos Vistos vs. Valor Carrito', fontsize=14, weight='bold')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('regresion_lineal.png', dpi=300)
plt.show()

# Análisis de residuos (importante para validar el modelo)
residuos = y - y_pred

fig, axes = plt.subplots(1, 2, figsize=(14, 5))

# Gráfico 1: Residuos vs. predicciones
axes[0].scatter(y_pred, residuos, alpha=0.5)
axes[0].axhline(y=0, color='red', linestyle='--', linewidth=2)
axes[0].set_xlabel('Valores Predichos')
axes[0].set_ylabel('Residuos')
axes[0].set_title('Residuos vs. Predicciones')
axes[0].grid(True, alpha=0.3)

# Gráfico 2: Distribución de residuos
axes[1].hist(residuos, bins=30, edgecolor='black')
axes[1].set_xlabel('Residuos')
axes[1].set_ylabel('Frecuencia')
axes[1].set_title('Distribución de Residuos')
axes[1].grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig('analisis_residuos.png', dpi=300)
plt.show()

💡 Tip: Un buen modelo tiene residuos distribuidos aleatoriamente alrededor de cero (sin patrones). Si ves patrones en los residuos, el modelo lineal puede no ser apropiado.

Regresión Lineal Múltiple

Múltiples predictores

En la realidad, las predicciones dependen de múltiples factores. La regresión múltiple usa varias variables independientes:

Y = β₀ + β₁X₁ + β₂X₂ + β₃X₃ + ... + ε

# Regresión múltiple: predecir valor_carrito con múltiples variables
X_multiple = data[['productos_vistos', 'tiempo_pagina_min', 'sesiones_ultimo_mes']]
y = data['valor_carrito']

# Crear y entrenar modelo
modelo_multiple = LinearRegression()
modelo_multiple.fit(X_multiple, y)

# Coeficientes
print("Coeficientes del modelo múltiple:")
print(f"Intercepto: ${modelo_multiple.intercept_:.2f}\n")

for i, col in enumerate(X_multiple.columns):
    print(f"{col}: ${modelo_multiple.coef_[i]:.2f}")
    print(f"  → Interpretación: Por cada unidad adicional, el carrito aumenta ${modelo_multiple.coef_[i]:.2f}\n")

# Predicciones y métricas
y_pred_multiple = modelo_multiple.predict(X_multiple)
r2_multiple = r2_score(y, y_pred_multiple)
rmse_multiple = np.sqrt(mean_squared_error(y, y_pred_multiple))

print(f"\nComparación de modelos:")
print(f"Modelo simple (1 variable) - R²: {r2:.3f}, RMSE: ${rmse:.2f}")
print(f"Modelo múltiple (3 variables) - R²: {r2_multiple:.3f}, RMSE: ${rmse_multiple:.2f}")
print(f"Mejora en R²: {(r2_multiple - r2)*100:.1f}%")

Importancia de variables

# Crear DataFrame con importancia de variables
importancias = pd.DataFrame({
    'Variable': X_multiple.columns,
    'Coeficiente': modelo_multiple.coef_,
    'Coef_Absoluto': np.abs(modelo_multiple.coef_)
}).sort_values('Coef_Absoluto', ascending=False)

print("\nImportancia de variables (por magnitud de coeficiente):")
print(importancias)

# Visualización
plt.figure(figsize=(10, 6))
plt.barh(importancias['Variable'], importancias['Coeficiente'])
plt.xlabel('Coeficiente')
plt.title('Impacto de cada variable en el Valor del Carrito', fontsize=14, weight='bold')
plt.grid(True, alpha=0.3, axis='x')
plt.tight_layout()
plt.savefig('importancia_variables.png', dpi=300)
plt.show()

Proyecto práctico: Análisis de conversión de marketing

Caso de uso real

Eres analista en una empresa de SaaS. Tu objetivo: predecir el valor de vida del cliente (LTV) basado en métricas de onboarding.

# Dataset simulado de clientes SaaS
np.random.seed(123)
n_clientes = 1000

saas_data = pd.DataFrame({
    'dias_trial': np.random.randint(7, 31, n_clientes),
    'features_usados': np.random.randint(1, 15, n_clientes),
    'sesiones_onboarding': np.random.randint(1, 10, n_clientes),
    'soporte_tickets': np.random.randint(0, 8, n_clientes),
    'ltv': np.random.normal(1200, 400, n_clientes)
})

# Agregar relaciones realistas
saas_data['ltv'] = (
    saas_data['ltv'] +
    (saas_data['features_usados'] * 50) +
    (saas_data['sesiones_onboarding'] * 80) -
    (saas_data['soporte_tickets'] * 30)
)

# 1. Análisis de correlaciones
print("=== ANÁLISIS DE CORRELACIONES ===\n")
correlaciones_ltv = saas_data.corr()['ltv'].sort_values(ascending=False)
print(correlaciones_ltv)

# Visualizar
plt.figure(figsize=(10, 6))
sns.heatmap(saas_data.corr(), annot=True, cmap='RdYlGn', center=0, square=True)
plt.title('Correlaciones - Métricas de Onboarding vs. LTV', fontsize=14, weight='bold')
plt.tight_layout()
plt.savefig('correlaciones_saas.png', dpi=300)
plt.show()

# 2. Regresión múltiple para predecir LTV
X_saas = saas_data[['dias_trial', 'features_usados', 'sesiones_onboarding', 'soporte_tickets']]
y_saas = saas_data['ltv']

modelo_ltv = LinearRegression()
modelo_ltv.fit(X_saas, y_saas)
y_pred_saas = modelo_ltv.predict(X_saas)

# Resultados
print("\n=== MODELO PREDICTIVO DE LTV ===\n")
print(f"R² del modelo: {r2_score(y_saas, y_pred_saas):.3f}")
print(f"RMSE: ${np.sqrt(mean_squared_error(y_saas, y_pred_saas)):.2f}\n")

print("Coeficientes (impacto en LTV):")
for col, coef in zip(X_saas.columns, modelo_ltv.coef_):
    print(f"  {col}: ${coef:+.2f}")

# 3. Predicción para un nuevo cliente
nuevo_cliente = pd.DataFrame({
    'dias_trial': [21],
    'features_usados': [8],
    'sesiones_onboarding': [5],
    'soporte_tickets': [2]
})

ltv_predicho = modelo_ltv.predict(nuevo_cliente)[0]
print(f"\n=== PREDICCIÓN NUEVO CLIENTE ===")
print(f"LTV estimado: ${ltv_predicho:,.2f}")

# 4. Insights accionables
print("\n=== RECOMENDACIONES ESTRATÉGICAS ===")
coef_features = modelo_ltv.coef_[1]
coef_sesiones = modelo_ltv.coef_[2]
coef_tickets = modelo_ltv.coef_[3]

print(f"✅ Incrementar features usados: +${coef_features:.2f} LTV por feature")
print(f"✅ Más sesiones de onboarding: +${coef_sesiones:.2f} LTV por sesión")
print(f"⚠️ Reducir tickets de soporte: {coef_tickets:.2f} LTV por ticket (negativo)")

Validación del modelo: Train/Test Split

División de datos para evitar overfitting

from sklearn.model_selection import train_test_split

# Dividir datos: 80% entrenamiento, 20% prueba
X_train, X_test, y_train, y_test = train_test_split(
    X_saas, y_saas,
    test_size=0.2,     # 20% para testing
    random_state=42    # Reproducibilidad
)

# Entrenar solo con datos de entrenamiento
modelo_validado = LinearRegression()
modelo_validado.fit(X_train, y_train)

# Evaluar en datos de entrenamiento
y_train_pred = modelo_validado.predict(X_train)
r2_train = r2_score(y_train, y_train_pred)
rmse_train = np.sqrt(mean_squared_error(y_train, y_train_pred))

# Evaluar en datos de prueba (¡datos que el modelo nunca vio!)
y_test_pred = modelo_validado.predict(X_test)
r2_test = r2_score(y_test, y_test_pred)
rmse_test = np.sqrt(mean_squared_error(y_test, y_test_pred))

print("=== VALIDACIÓN DEL MODELO ===\n")
print(f"Datos de Entrenamiento:")
print(f"  R²: {r2_train:.3f}")
print(f"  RMSE: ${rmse_train:.2f}\n")

print(f"Datos de Prueba:")
print(f"  R²: {r2_test:.3f}")
print(f"  RMSE: ${rmse_test:.2f}\n")

# Detectar overfitting
diferencia_r2 = r2_train - r2_test
if diferencia_r2 > 0.1:
    print("⚠️ ALERTA: Posible overfitting (diferencia R² > 0.1)")
else:
    print("✅ Modelo generaliza bien a datos nuevos")

💡 Tip profesional: Siempre divide tus datos en train/test. Un modelo que solo fue evaluado con los datos de entrenamiento puede estar "memorizando" en lugar de "aprendiendo patrones generales".

Ejercicios prácticos

Ejercicio 1: Análisis de tienda online

Tienes datos de una tienda online. Analiza las correlaciones y crea un modelo predictivo.

# Dataset de práctica
ejercicio_data = pd.DataFrame({
    'visitas_mes': np.random.randint(10, 200, 300),
    'productos_carrito': np.random.randint(1, 15, 300),
    'descuento_promedio': np.random.uniform(0, 30, 300),
    'email_opens': np.random.randint(0, 20, 300),
    'compras_anteriores': np.random.randint(0, 50, 300),
    'ventas_mes': np.random.normal(500, 200, 300)
})

# Agregar relación realista
ejercicio_data['ventas_mes'] = (
    ejercicio_data['ventas_mes'] +
    (ejercicio_data['visitas_mes'] * 2) +
    (ejercicio_data['productos_carrito'] * 15) +
    (ejercicio_data['compras_anteriores'] * 10)
)

# TU TURNO:
# 1. Calcula la matriz de correlaciones
# 2. Identifica las 3 variables más correlacionadas con ventas_mes
# 3. Crea un modelo de regresión múltiple
# 4. Calcula R² y RMSE
# 5. Predice ventas para: visitas=100, productos_carrito=5, descuento=15%, email_opens=10, compras_anteriores=20

# SOLUCIÓN (no mirar hasta intentarlo):
# correlaciones = ejercicio_data.corr()['ventas_mes'].sort_values(ascending=False)
# X = ejercicio_data[['visitas_mes', 'productos_carrito', 'compras_anteriores']]
# y = ejercicio_data['ventas_mes']
# modelo = LinearRegression().fit(X, y)
# prediccion = modelo.predict([[100, 5, 20]])

Ejercicio 2: Validación rigurosa

# TU TURNO:
# 1. Divide ejercicio_data en train (70%) y test (30%)
# 2. Entrena el modelo solo con train
# 3. Evalúa R² y RMSE en ambos conjuntos
# 4. Determina si hay overfitting
# 5. Visualiza predicciones vs. valores reales

Limitaciones de la regresión lineal

Cuándo NO usar regresión lineal

  1. Relaciones no lineales: Si la relación es curva/exponencial
  2. Outliers extremos: Afectan mucho el modelo
  3. Multicolinealidad: Variables predictoras muy correlacionadas entre sí
  4. Heterocedasticidad: Varianza no constante de residuos
# Detección de multicolinealidad
from scipy.stats import pearsonr

def detectar_multicolinealidad(df, umbral=0.8):
    """Detecta variables altamente correlacionadas entre sí"""
    correlaciones_altas = []
    cols = df.columns

    for i in range(len(cols)):
        for j in range(i+1, len(cols)):
            r, p = pearsonr(df[cols[i]], df[cols[j]])
            if abs(r) > umbral:
                correlaciones_altas.append({
                    'var1': cols[i],
                    'var2': cols[j],
                    'correlacion': r
                })

    return pd.DataFrame(correlaciones_altas)

# Ejemplo
multicolinealidad = detectar_multicolinealidad(X_saas)
if len(multicolinealidad) > 0:
    print("⚠️ ALERTA: Multicolinealidad detectada:")
    print(multicolinealidad)
else:
    print("✅ No hay multicolinealidad significativa")

Resumen de la lección

Correlación mide la fuerza y dirección de relaciones lineales (r de -1 a +1) ✅ Regresión lineal simple predice una variable con un predictor (Y = β₀ + β₁X) ✅ Regresión múltiple usa múltiples predictores para mejores predicciones ✅ indica % de varianza explicada (0.7+ es bueno, 0.9+ es excelente) ✅ Train/Test Split valida que el modelo generaliza a datos nuevos ✅ Análisis de residuos valida supuestos del modelo lineal ✅ Correlación ≠ Causalidad (¡siempre recordar!)

Próximos pasos

En la siguiente lección dominarás Testing de Hipótesis, donde aprenderás a:

  • Realizar t-tests para comparar grupos
  • Interpretar p-valores correctamente
  • Aplicar chi-cuadrado y ANOVA
  • Validar tus hallazgos con rigor estadístico

🎯 Próxima lección: 20. Testing de Hipótesis

¿Listo para validar tus hallazgos con testing estadístico riguroso? ¡Nos vemos en la siguiente lección! 📊

¿Completaste esta lección?

Marca esta lección como completada. Tu progreso se guardará en tu navegador.