# =============================================================================
# EJERCICIO GUIADO: Regresión Lineal Multivariable
# Dataset: Propinas en un restaurante (tips)
# Nivel: Principiante / Intermedio
# =============================================================================
#
# CONTEXTO DEL PROBLEMA
# ─────────────────────
# En el ejercicio anterior usamos solo el total de la cuenta para predecir
# la propina. ¡Pero hay más información disponible!
#
# PREGUNTA: ¿Podemos predecir mejor la propina usando VARIAS variables?
#
# Esto es lo que hace la REGRESIÓN LINEAL MULTIVARIABLE:
# aprender cómo influye cada variable de entrada en la propina.
#
# La fórmula pasa de tener una sola X a varias:
#
# tip = b₀ + b₁×total_bill + b₂×size
#
# donde cada bᵢ (coeficiente) indica cuánto influye esa variable.
#
# Al final del ejercicio sabrás:
# · Seleccionar múltiples variables numéricas
# · Normalizar los datos para que las variables estén en la misma escala
# · Entrenar un modelo de regresión multivariable
# · Comparar su rendimiento con el modelo simple anterior
# · Interpretar los coeficientes de cada variable
# · Predecir la propina para una comanda nueva con múltiples datos
#
# VARIABLES DEL DATASET
# ─────────────────────
# total_bill → importe total de la cuenta en dólares [numérica]
# tip → propina dejada por el cliente [numérica, objetivo]
# sex → sexo del cliente que paga [categórica]
# smoker → si la mesa es de fumadores [categórica]
# day → día de la semana [categórica]
# time → Lunch / Dinner [categórica]
# size → número de personas en la mesa [numérica]
#
# En este ejercicio usaremos: total_bill y size.
#
# =============================================================================
# ─────────────────────────────────────────────────────────────────────────────
# PASO 0 — IMPORTACIONES
# ─────────────────────────────────────────────────────────────────────────────
#
# Ejecuta este bloque primero. Si alguna librería no está instalada:
# pip install seaborn scikit-learn matplotlib
import seaborn as sns
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import StandardScaler # ← nueva importación
from sklearn.metrics import (
r2_score,
mean_absolute_error,
mean_squared_error,
root_mean_squared_error
)
# ─────────────────────────────────────────────────────────────────────────────
# PASO 1 — CARGAR EL DATASET
# ─────────────────────────────────────────────────────────────────────────────
#
# Cargamos el mismo dataset de propinas que en el ejercicio anterior.
print("=" * 60)
print(" PASO 1: Carga del dataset")
print("=" * 60)
df = sns.load_dataset("tips")
# ─────────────────────────────────────────────────────────────────────────────
# PASO 3 — SELECCIONAR X e y
# ─────────────────────────────────────────────────────────────────────────────
#
# Ahora X tiene DOS columnas (de ahí el nombre "multivariable"):
# X = [total_bill, size]
# y = tip (lo mismo que antes)
#
# 💡 PISTA: Usa doble corchete para seleccionar varias columnas:
# X = df[["total_bill", "size"]]
#
# 🛠️ TU TURNO:
# 1. Define X con las dos variables indicadas.
# 2. Define y como la columna "tip".
# 3. Imprime X.shape e y.shape.
# ¿Qué diferencia ves en X respecto al ejercicio de regresión simple?
print("\n" + "=" * 60)
print(" PASO 3: Seleccionar X e y")
print("=" * 60)
# --- ESCRIBE TU CÓDIGO AQUÍ ---
X = df[["total_bill", "size"]] # ¿Qué variables? total_bill y size
y = df["tip"]
# ─────────────────────────────────────────────────────────────────────────────
# PASO 4 — DIVIDIR EN ENTRENAMIENTO Y TEST
# ─────────────────────────────────────────────────────────────────────────────
#
# Dividimos ANTES de normalizar para evitar "data leakage":
# si normalizamos con todos los datos, el modelo vería información
# del conjunto de test durante el entrenamiento (hace trampa).
#
# Orden correcto: dividir → normalizar con train → aplicar a test.
#
# 💡 PISTA: train_test_split(X, y, test_size=0.2, random_state=42)
#
# 🛠️ TU TURNO:
# Aplica train_test_split y guarda los cuatro conjuntos:
# X_train, X_test, y_train, y_test
# Imprime cuántas filas tiene cada parte.
print("\n" + "=" * 60)
print(" PASO 4: División train / test (80% / 20%)")
print("=" * 60)
# --- ESCRIBE TU CÓDIGO AQUÍ -
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# ─────────────────────────────────────────────────────────────────────────────
# PASO 5 — NORMALIZACIÓN (StandardScaler)
# ─────────────────────────────────────────────────────────────────────────────
#
# PROBLEMA: total_bill va de 3 a 51 $, pero size va de 1 a 6 personas.
# Son escalas muy distintas. Si no normalizamos, el modelo puede dar
# más "peso" a total_bill simplemente porque sus valores son más grandes,
# no porque sea más importante.
#
# StandardScaler convierte cada variable para que tenga:
# · media = 0
# · desviación típica = 1
#
# Fórmula: z = (x − media) / desviación_típica
#
# ⚠️ REGLA IMPORTANTE: el scaler se "aprende" (fit) SOLO con X_train.
# Luego se aplica (transform) tanto a X_train como a X_test.
# Nunca hagas fit con X_test: estarías mirando datos que no deberías ver.
#
# 💡 PISTA:
# scaler = StandardScaler()
# X_train_sc = scaler.fit_transform(X_train) # aprende Y transforma
# X_test_sc = scaler.transform(X_test) # solo transforma
#
# 🛠️ TU TURNO:
# 1. Crea el scaler y aplícalo según el ejemplo de arriba.
# 2. Imprime la media y desviación típica que aprendió el scaler.
# Pista: scaler.mean_ y scaler.scale_
# 3. Comprueba que X_train_sc tiene media ≈ 0 y std ≈ 1 por columna.
# Pista: pd.DataFrame(X_train_sc, columns=X.columns).describe().round(2)
print("\n" + "=" * 60)
print(" PASO 5: Normalización con StandardScaler")
print("=" * 60)
# --- ESCRIBE TU CÓDIGO AQUÍ ---
scaler = StandardScaler()
X_train_sc = scaler.fit_transform(X_train)
X_test_sc = scaler.transform(X_test)
# ─────────────────────────────────────────────────────────────────────────────
# PASO 6 — ENTRENAR EL MODELO
# ─────────────────────────────────────────────────────────────────────────────
#
# Entrenamos con X_train_sc (los datos normalizados), no con X_train.
#
# Con dos variables normalizadas, la fórmula aprendida será:
# tip = b₀ + b₁×total_bill_sc + b₂×size_sc
#
# Ahora los coeficientes b₁ y b₂ SÍ son directamente comparables:
# el mayor indica la variable que más influye en la propina.
#
# 💡 PISTA:
# modelo = LinearRegression()
# modelo.fit(X_train_sc, y_train)
#
# 🛠️ TU TURNO:
# 1. Crea el modelo y entrénalo con los datos normalizados.
# 2. Imprime los coeficientes junto al nombre de cada variable.
# Pista: zip(X.columns, modelo.coef_)
# 3. ¿Qué variable tiene el coeficiente más alto?
# Después de normalizar, eso sí que indica cuál importa más.
print("\n" + "=" * 60)
print(" PASO 6: Entrenamiento del modelo")
print("=" * 60)
# --- ESCRIBE TU CÓDIGO AQUÍ ---
modelo = LinearRegression()
modelo.fit(X_train_sc, y_train)
# ─────────────────────────────────────────────────────────────────────────────
# PASO 7 — EVALUAR EL MODELO
# ─────────────────────────────────────────────────────────────────────────────
#
# Calcula las predicciones sobre X_test_sc y luego las tres métricas:
# · R² → ¿qué porcentaje de la variación explica el modelo?
# · MAE → error medio en dólares
# · RMSE → igual que MAE pero penaliza más los errores grandes
#
# 💡 PISTA: El modelo simple (solo total_bill, sin normalizar) obtenía R² ≈ 0.46.
# ¿Mejora al usar dos variables normalizadas?
#
# 🛠️ TU TURNO:
# 1. Obtén y_pred con modelo.predict(X_test_sc).
# 2. Calcula r2, mae y rmse.
# 3. Imprime los resultados y compáralos con el modelo simple.
print("\n" + "=" * 60)
print(" PASO 7: Evaluación del modelo")
print("=" * 60)
# --- ESCRIBE TU CÓDIGO AQUÍ ---
y_pred = modelo.predict(X_test_sc)
r2 = r2_score(y_test, y_pred)
mae = mean_absolute_error(y_test, y_pred)
rmse = root_mean_squared_error(y_test, y_pred)
print(f" R² = {r2:.4f}")
print(f" MAE = {mae:.4f} $")
print(f" RMSE = {rmse:.4f} $")
print("\n ¿Mejoró respecto al modelo simple (R² ≈ 0.46)?")
Regresión lineal multivariable
import numpy as np # Operaciones numéricas y arrays
import pandas as pd # Manejo de tablas de datos (DataFrames)
import matplotlib.pyplot as plt # Gráficas
from sklearn.model_selection import train_test_split # Dividir datos en tren/test
from sklearn.linear_model import LinearRegression # Nuestro modelo
from sklearn.preprocessing import StandardScaler # Normalizar datos
from sklearn.metrics import mean_squared_error, r2_score
np.random.seed(42) # Fijamos semilla para reproducibilidad
n = 200 # Número de pisos en nuestro dataset
# Cada columna representa una característica del piso
data = pd.DataFrame({
'metros2' : np.random.randint(30, 150, n), # Entre 30 y 150 m²
'habitaciones': np.random.randint(1, 6, n), # Entre 1 y 5 habitaciones
'planta' : np.random.randint(0, 10, n), # Entre planta 0 y 9
'antiguedad' : np.random.randint(0, 50, n), # Años de antigüedad
})
# Fórmula ficticia para el precio (así sabemos cuál es la verdad)
# precio = 50k + 2000×m² + 8000×hab + 500×planta - 300×antigüedad + ruido
ruido = np.random.normal(0, 10000, n) # Variación aleatoria realista
data['precio'] = (
50000
+ 2000 * data['metros2']
+ 8000 * data['habitaciones']
+ 500 * data['planta']
- 300 * data['antiguedad']
+ ruido
)
print(data.head()) # Ver las primeras filas
# Aquí tenemos un dataset de 200 pisos con sus precios aleatorio pero siguiendo
# una fórmula que podemos predecir
# ─── Separar variables de entrada (X) y salida (y) ─────────────
X = data.drop(columns=['precio']) # Todo excepto el precio
y = data['precio'] # Solo el precio (lo que queremos predecir)
# ─── Dividir en entrenamiento (80%) y test (20%) ─────────────
X_train, X_test, y_train, y_test = train_test_split(
X, y, # Datos de entrada y salida
test_size=0.2, # 20% para test
random_state=42 # Semilla para resultados reproducibles
)
print(f'Datos de entrenamiento: {len(X_train)} pisos')
print(f'Datos de test: {len(X_test)} pisos')
# → Datos de entrenamiento: 160 pisos
# → Datos de test: 40 pisos
# ─── Normalizar los datos ──────────────────────────────────────
scaler = StandardScaler() # Creamos el normalizador
# fit_transform: aprende la media y std DE LOS DATOS DE ENTRENAMIENTO
# y luego transforma. NUNCA uses fit en los datos de test.
X_train_scaled = scaler.fit_transform(X_train)
# transform solo: aplica la misma transformación al test
# (sin volver a aprender — eso sería trampa)
X_test_scaled = scaler.transform(X_test)
modelo = LinearRegression() # Instanciar el modelo
# .fit() es donde ocurre el 'aprendizaje':
# el modelo encuentra los mejores coeficientes β
modelo.fit(X_train_scaled, y_train)
# Ver los coeficientes aprendidos
print('Intercepto (β₀):', modelo.intercept_)
for nombre, coef in zip(X.columns, modelo.coef_):
print(f' {nombre:<15}: {coef:>10.2f}')
y_pred = modelo.predict(X_test_scaled) # Predicciones
# R² (R-cuadrado): qué porcentaje de la variación explica el modelo
# Va de 0 a 1. Cuanto más cerca de 1, mejor.
r2 = r2_score(y_test, y_pred)
# RMSE: error promedio en las mismas unidades que y (euros)
# Fácil de interpretar: 'me equivoco en promedio X euros'
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
print(f'R² = {r2:.4f}') # p.ej. R² = 0.9812
print(f'RMSE = {rmse:.2f} €') # p.ej. RMSE = 9.847,23 €
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# --- Gráfico 1: Predicciones vs Valores reales ---
axes[0].scatter(y_test, y_pred, alpha=0.5, color='steelblue')
# La línea perfecta (y = x) sirve como referencia visual
axes[0].plot([y_test.min(), y_test.max()],
[y_test.min(), y_test.max()], 'r--', label='Predicción perfecta')
axes[0].set_xlabel('Precio real (€)')
axes[0].set_ylabel('Precio predicho (€)')
axes[0].set_title(f'Predicciones vs. Valores reales\nR² = {r2:.4f}')
axes[0].legend()
# --- Gráfico 2: Residuos (errores del modelo) ---
residuos = y_test - y_pred # Diferencia entre real y predicho
axes[1].scatter(y_pred, residuos, alpha=0.5, color='coral')
axes[1].axhline(0, color='black', linestyle='--') # Línea en 0
axes[1].set_xlabel('Precio predicho (€)')
axes[1].set_ylabel('Residuo (real - predicho)')
axes[1].set_title('Análisis de Residuos\n(idealmente dispersos sin patrón)')
plt.tight_layout() # Ajusta márgenes automáticamente
plt.savefig('resultados_regresion.png', dpi=150, bbox_inches='tight')
plt.show()
# ─── Predecir el precio de un piso nuevo ───────────────────────
# Creamos un DataFrame con las características del piso nuevo
# ¡Importante: usar los mismos nombres de columna que en el entrenamiento!
piso_nuevo = pd.DataFrame([{
'metros2' : 90, # 90 metros cuadrados
'habitaciones': 3, # 3 habitaciones
'planta' : 5, # Planta 5
'antiguedad' : 10, # 10 años de antigüedad
}])
# Normalizar usando el MISMO scaler que entrenamos (no fit_transform)
piso_nuevo_scaled = scaler.transform(piso_nuevo)
# Predecir
precio_estimado = modelo.predict(piso_nuevo_scaled)[0]
print(f'Precio estimado: {precio_estimado:,.0f} €')
# → Precio estimado: 250.500 € (resultado aproximado)
Gráficos
import matplotlib.pyplot as plt
# --- DATOS ---
# Estos son los datos que queremos representar.
# Cada elemento de 'ventas' corresponde a un mes.
meses = ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun']
ventas = [120, 145, 132, 178, 165, 200]
ventas2 = [150, 125, 162, 128, 105, 230]
# plt.subplots() crea dos cosas a la vez:
# fig → la figura (el lienzo completo)
# ax → los ejes (la zona de dibujo)
fig, ax = plt.subplots()
# --- DIBUJAR LA LÍNEA ---
# ax.plot(eje_x, eje_y) dibuja la línea.
# color → color de la línea (nombre o código hex)
# linewidth → grosor de la línea
# marker → símbolo en cada punto ('o' = círculo)
ax.plot(meses, ventas, color='blueviolet', linewidth=2, marker='p',label="Tienda A")
ax.plot(meses, ventas2,mfc='green', color='tomato', linewidth=2, marker='s', linestyle='--', label="Tienda B")
ax.legend(loc='upper left', fontsize=10)
# --- ETIQUETAS Y TÍTULO ---
ax.set_title('Ventas mensuales') # Título de la gráfica
ax.set_xlabel('Mes') # Etiqueta del eje horizontal
ax.set_ylabel('Unidades vendidas') # Etiqueta del eje vertical
# --- CUADRÍCULA ---
# La cuadrícula facilita leer los valores.
# linestyle='--' → líneas discontinuas
# alpha=0.4 → 40% de opacidad (líneas sutiles)
ax.grid(True, linestyle='--', alpha=0.4)
# --- MOSTRAR ---
plt.tight_layout() # Ajusta márgenes automáticamente
plt.savefig('ejemplo.png', dpi=150, bbox_inches='tight')
# plt.show() abre la ventana y muestra el resultado
plt.show()
Ejercicio métricas
# ================================================================
# EJERCICIO PRÁCTICO: Evaluación de Modelos de Predicción
# de Ventas con Métricas de Regresión
# ================================================================
#
# CONTEXTO:
# Una cafetería registró sus ventas diarias (en €) durante
# 30 días. Dos modelos intentaron predecir esas ventas:
# - Modelo A: regresión lineal simple
# - Modelo B: red neuronal experimental
#
# Tu misión: calcular las métricas, interpretar los resultados
# y decidir qué modelo recomendarías al dueño de la cafetería.
#
# ================================================================
import numpy as np
import matplotlib.pyplot as plt
# ----------------------------------------------------------------
# DATOS: 30 días de ventas reales y predicciones de cada modelo
# ----------------------------------------------------------------
dias = list(range(1, 31)) # Días del mes (1 al 30)
# Ventas reales registradas en la caja (en €)
ventas_reales = [
312, 298, 341, 287, 305, 198, 210, # Semana 1 (fin de semana bajo)
330, 315, 352, 298, 341, 215, 224, # Semana 2
345, 318, 361, 302, 349, 231, 228, # Semana 3
358, 334, 372, 315, 360, 244, 237, # Semana 4
365, 348 # Últimos 2 días del mes
]
# Predicciones del Modelo A (regresión lineal, más estable)
predicciones_modelo_A = [
308, 301, 338, 291, 309, 205, 214,
325, 318, 347, 303, 338, 221, 220,
340, 322, 355, 308, 344, 226, 232,
352, 330, 368, 319, 355, 240, 242,
361, 344
]
# Predicciones del Modelo B (sobreajustado en semanas centrales)
predicciones_modelo_B = [
295, 275, 360, 270, 325, 185, 240,
310, 340, 330, 285, 365, 200, 245,
325, 340, 340, 290, 370, 210, 255,
340, 350, 350, 300, 385, 225, 265,
350, 335
]
# ================================================================
# SECCIÓN 1 — CÁLCULO DE MÉTRICAS
# ================================================================
# Completa cada celda marcada con ??? usando sklearn o numpy.
# Pista: todas las funciones están en sklearn.metrics
# Documentación: https://scikit-learn.org/stable/modules/model_evaluation.html
# ================================================================
from sklearn.metrics import mean_squared_error # MSE
from sklearn.metrics import mean_absolute_error # MAE
from sklearn.metrics import root_mean_squared_error # RMSE
from sklearn.metrics import r2_score # R²
print("=" * 55)
print(" MÉTRICAS DE EVALUACIÓN — VENTAS 30 DÍAS")
print("=" * 55)
# ---- 1.1 MSE -----------------------------------------------
# Pista: mean_squared_error(valores_reales, valores_predichos)
# Un MSE menor indica mejor ajuste.
# ¿Qué ocurre si un día el modelo falla por 50 €?
# Ese error pesa 50² = 2500 en el MSE.
mse_A = ??? # Calcula el MSE del Modelo A
mse_B = ??? # Calcula el MSE del Modelo B
print(f"\nMSE → Modelo A: {mse_A:.2f} | Modelo B: {mse_B:.2f}")
# ---- 1.2 MAE -----------------------------------------------
# Pista: mean_absolute_error(valores_reales, valores_predichos)
# A diferencia del MSE, todos los errores pesan igual.
# Un MAE de 15 significa: "me equivoco ~15 € por día de media".
mae_A = ??? # Calcula el MAE del Modelo A
mae_B = ??? # Calcula el MAE del Modelo B
print(f"MAE → Modelo A: {mae_A:.2f} | Modelo B: {mae_B:.2f}")
# ---- 1.3 RMSE ----------------------------------------------
# Pista: root_mean_squared_error(valores_reales, valores_predichos)
# Es la raíz cuadrada del MSE → devuelve el error en euros (€),
# igual que los datos originales. Más fácil de interpretar.
rmse_A = ??? # Calcula el RMSE del Modelo A
rmse_B = ??? # Calcula el RMSE del Modelo B
print(f"RMSE → Modelo A: {rmse_A:.2f} | Modelo B: {rmse_B:.2f}")
# ---- 1.4 R² ------------------------------------------------
# Pista: r2_score(valores_reales, valores_predichos)
# Mide qué porcentaje de la variación en ventas explica el modelo.
# R² = 1 → perfecto | R² = 0 → igual que predecir siempre la media.
r2_A = ??? # Calcula el R² del Modelo A
r2_B = ??? # Calcula el R² del Modelo B
print(f"R² → Modelo A: {r2_A:.4f} | Modelo B: {r2_B:.4f}")
print("\n" + "=" * 55)
# ================================================================
# SECCIÓN 2 — GRÁFICA DE AJUSTE
# ================================================================
# Aquí tienes la estructura completa de la gráfica.
# Descomentar el bloque cuando tengas las métricas calculadas.
# ================================================================
# x = np.array(dias)
# fig, axes = plt.subplots(2, 1, figsize=(14, 9))
# fig.suptitle("Comparativa de Modelos — Ventas Diarias Cafetería", fontsize=14, fontweight="bold")
#
# # --- Subgráfica superior: líneas de ajuste ---
# ax1 = axes[0]
# ax1.plot(x, ventas_reales, "o-", color="#2C3E50", lw=2.5, ms=5, label="Ventas Reales")
# ax1.plot(x, predicciones_modelo_A,"s--", color="#2980B9", lw=1.8, ms=4, label=f"Modelo A (RMSE={rmse_A:.1f} €)")
# ax1.plot(x, predicciones_modelo_B,"^--", color="#E74C3C", lw=1.8, ms=4, label=f"Modelo B (RMSE={rmse_B:.1f} €)")
# ax1.fill_between(x, ventas_reales, predicciones_modelo_A, alpha=0.12, color="#2980B9")
# ax1.fill_between(x, ventas_reales, predicciones_modelo_B, alpha=0.12, color="#E74C3C")
# ax1.set_ylabel("Ventas (€)")
# ax1.set_xticks(x)
# ax1.set_xticklabels([f"D{d}" for d in dias], fontsize=7, rotation=45)
# ax1.legend(); ax1.grid(True, linestyle="--", alpha=0.4)
#
# # --- Subgráfica inferior: error absoluto por día ---
# error_A = [abs(r - p) for r, p in zip(ventas_reales, predicciones_modelo_A)]
# error_B = [abs(r - p) for r, p in zip(ventas_reales, predicciones_modelo_B)]
# ancho = 0.35
# ax2 = axes[1]
# ax2.bar(x - ancho/2, error_A, width=ancho, color="#2980B9", alpha=0.8, label="Error diario Modelo A")
# ax2.bar(x + ancho/2, error_B, width=ancho, color="#E74C3C", alpha=0.8, label="Error diario Modelo B")
# ax2.axhline(y=mae_A, color="#1A5276", linestyle="--", lw=1.5, label=f"MAE Modelo A = {mae_A:.1f} €")
# ax2.axhline(y=mae_B, color="#922B21", linestyle="--", lw=1.5, label=f"MAE Modelo B = {mae_B:.1f} €")
# ax2.set_xlabel("Día del mes")
# ax2.set_ylabel("Error absoluto (€)")
# ax2.set_xticks(x)
# ax2.set_xticklabels([f"D{d}" for d in dias], fontsize=7, rotation=45)
# ax2.legend(); ax2.grid(True, axis="y", linestyle="--", alpha=0.4)
#
# plt.tight_layout()
# plt.savefig("ajuste_ventas.png", dpi=150, bbox_inches="tight")
# plt.show()
# ================================================================
# SECCIÓN 3 — PREGUNTAS DE REFLEXIÓN
# ================================================================
# Responde a continuación como comentarios de Python (#).
# No hay una única respuesta correcta; razona tu decisión.
# ================================================================
# PREGUNTA 1 ── ¿Qué modelo tiene menor MSE?
# ¿Por qué crees que el MSE es más sensible a errores grandes
# que el MAE? Piensa en qué ocurre matemáticamente al elevar al
# cuadrado un error de 50 € frente a uno de 5 €.
#
# Tu respuesta:
#
# ─────────────────────────────────────────────────────────────
# PREGUNTA 2 ── Si el MAE de ambos modelos fuese muy similar
# pero el MSE fuese muy distinto, ¿qué nos estaría indicando
# sobre la distribución de los errores de cada modelo?
# Pista: piensa en días concretos donde un modelo falla mucho.
#
# Tu respuesta:
#
# ─────────────────────────────────────────────────────────────
# PREGUNTA 3 ── El dueño de la cafetería puede asumir errores
# pequeños cotidianos, pero le resulta muy perjudicial quedarse
# sin stock un día puntual por una predicción muy mala.
# ¿Qué métrica debería priorizar para elegir el modelo?
# ¿MSE/RMSE o MAE? Justifica tu respuesta.
#
# Tu respuesta:
#
# ─────────────────────────────────────────────────────────────
# PREGUNTA 4 ── Interpreta el valor de R² de cada modelo.
# ¿Un R² de 0.95 significa que el modelo predice bien siempre?
# ¿Podría haber algún día donde falle mucho y aun así tener
# un R² alto globalmente?
#
# Tu respuesta:
#
# ─────────────────────────────────────────────────────────────
# PREGUNTA 5 ── DECISIÓN FINAL
# Con los valores que has calculado, ¿qué modelo recomendarías
# al dueño de la cafetería y por qué?
# Menciona al menos dos métricas en tu argumento.
#
# Tu respuesta:
#
# ================================================================
# FIN DEL EJERCICIO
# ================================================================
Comparaciones métricas
# =============================================================
# COMPARACIÓN DE MÉTRICAS ENTRE DOS MODELOS
# =============================================================
# Este script compara las predicciones de dos modelos frente
# a los valores reales usando MSE, MAE y RMSE, y genera una
# gráfica para visualizar el ajuste de cada modelo.
# =============================================================
# Valores predichos por cada modelo para 4 observaciones
modelo1 = [20, 22, 23, 24] # Modelo 1: predicciones más conservadoras
modelo2 = [21, 24, 26, 24] # Modelo 2: predicciones más variables
real = [21, 24, 20, 31] # Valores reales que queremos acertar
# -------------------------------------------------------------
# MSE — Error Cuadrático Medio
# Eleva cada error al cuadrado antes de promediar, por lo que
# penaliza más los errores grandes. Unidades: valor² (ej: €²)
# -------------------------------------------------------------
from sklearn.metrics import mean_squared_error
mse1 = mean_squared_error(real, modelo1) # MSE del modelo 1
mse2 = mean_squared_error(real, modelo2) # MSE del modelo 2
print(f"MSE → Modelo1: {mse1:.2f} | Modelo2: {mse2:.2f}")
# -------------------------------------------------------------
# MAE — Error Absoluto Medio
# Promedio de los errores en valor absoluto. No penaliza tanto
# los errores grandes; más robusto ante outliers. Unidades: las
# mismas que los datos originales.
# -------------------------------------------------------------
from sklearn.metrics import mean_absolute_error
mae1 = mean_absolute_error(real, modelo1)
mae2 = mean_absolute_error(real, modelo2)
print(f"MAE → Modelo1: {mae1:.2f} | Modelo2: {mae2:.2f}")
# -------------------------------------------------------------
# RMSE — Raíz del Error Cuadrático Medio
# Es la raíz cuadrada del MSE. Devuelve el error en las mismas
# unidades que los datos originales, siendo más interpretable
# que el MSE pero manteniendo la penalización de errores grandes.
# -------------------------------------------------------------
from sklearn.metrics import root_mean_squared_error
rmse1 = root_mean_squared_error(real, modelo1)
rmse2 = root_mean_squared_error(real, modelo2)
print(f"RMSE → Modelo1: {rmse1:.2f} | Modelo2: {rmse2:.2f}")
# =============================================================
# GRÁFICA: Ajuste de los modelos a los datos reales
# =============================================================
import matplotlib.pyplot as plt
import numpy as np
# Eje X: índices de las 4 observaciones (puntos de tiempo o muestras)
x = np.arange(1, len(real) + 1) # [1, 2, 3, 4]
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
fig.suptitle("Ajuste de Modelos vs. Datos Reales", fontsize=15, fontweight="bold", y=1.01)
# ---- Colores ----
COLOR_REAL = "#2C3E50"
COLOR_M1 = "#2980B9"
COLOR_M2 = "#E74C3C"
COLOR_ERROR1 = "#AED6F1"
COLOR_ERROR2 = "#F1948A"
# ----------------------------------------------------------
# Subgráfica izquierda: líneas de los tres conjuntos
# ----------------------------------------------------------
ax1 = axes[0]
ax1.plot(x, real, "o-", color=COLOR_REAL, linewidth=2.5, markersize=8, label="Valores Reales", zorder=3)
ax1.plot(x, modelo1, "s--", color=COLOR_M1, linewidth=2, markersize=7, label=f"Modelo 1 (MSE={mse1:.1f})")
ax1.plot(x, modelo2, "^--", color=COLOR_M2, linewidth=2, markersize=7, label=f"Modelo 2 (MSE={mse2:.1f})")
# Sombrear el área de error de cada modelo respecto a los reales
ax1.fill_between(x, real, modelo1, alpha=0.15, color=COLOR_M1, label="Error Modelo 1")
ax1.fill_between(x, real, modelo2, alpha=0.15, color=COLOR_M2, label="Error Modelo 2")
ax1.set_title("Líneas de ajuste y área de error", fontsize=12)
ax1.set_xlabel("Observación")
ax1.set_ylabel("Valor")
ax1.set_xticks(x)
ax1.set_xticklabels([f"Obs {i}" for i in x])
ax1.legend(fontsize=9)
ax1.grid(True, linestyle="--", alpha=0.5)
ax1.set_ylim(15, 36)
# ----------------------------------------------------------
# Subgráfica derecha: barras comparativas de métricas
# ----------------------------------------------------------
ax2 = axes[1]
metricas = ["MSE", "MAE", "RMSE"]
valores_m1 = [mse1, mae1, rmse1]
valores_m2 = [mse2, mae2, rmse2]
ancho = 0.3
pos = np.arange(len(metricas))
bars1 = ax2.bar(pos - ancho/2, valores_m1, width=ancho, color=COLOR_M1,
label="Modelo 1", edgecolor="white", linewidth=0.8)
bars2 = ax2.bar(pos + ancho/2, valores_m2, width=ancho, color=COLOR_M2,
label="Modelo 2", edgecolor="white", linewidth=0.8)
# Etiquetar el valor encima de cada barra
for bar in bars1:
ax2.text(bar.get_x() + bar.get_width() / 2, bar.get_height() + 0.2,
f"{bar.get_height():.2f}", ha="center", va="bottom", fontsize=9, color=COLOR_M1, fontweight="bold")
for bar in bars2:
ax2.text(bar.get_x() + bar.get_width() / 2, bar.get_height() + 0.2,
f"{bar.get_height():.2f}", ha="center", va="bottom", fontsize=9, color=COLOR_M2, fontweight="bold")
ax2.set_title("Comparativa de métricas de error", fontsize=12)
ax2.set_ylabel("Valor del error")
ax2.set_xticks(pos)
ax2.set_xticklabels(metricas, fontsize=11)
ax2.legend(fontsize=10)
ax2.grid(True, axis="y", linestyle="--", alpha=0.5)
plt.tight_layout()
plt.savefig("ajuste_modelos.png", dpi=150, bbox_inches="tight")
plt.show()
print("Gráfica guardada en ajuste_modelos.png")
MSE
predicho=[20,22,23,24]
real=[21,24,20,31]
total=0
for i in range(4):
total+=(predicho[i]-real[i])**2
mse=total/4
print(mse)
import numpy as np
pred=np.array(predicho)
obs=np.array(real)
cuadraticos=(pred-real)**2
print(cuadraticos)
mse=np.mean(cuadraticos)
print(mse)
from sklearn.metrics import mean_squared_error
mse=mean_squared_error(real,pred)
print(mse)
Y más regresiones
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
metros_cuadrados = [
40, 42, 45, 48, 50, 52, 55, 58, 60, 62,
65, 68, 70, 72, 75, 78, 80, 82, 85, 88,
90, 92, 95, 98, 100, 102, 105, 108, 110, 112,
115, 118, 120, 122, 125, 128, 130, 132, 135, 138,
140, 142, 145, 148, 150, 152, 155, 158, 160, 165
]
precio_miles_euros = [
120, 125, 128, 135, 140, 145, 150, 158, 160, 168,
175, 180, 185, 190, 198, 205, 210, 215, 223, 230,
235, 240, 248, 255, 260, 265, 273, 280, 285, 290,
298, 305, 310, 315, 323, 330, 335, 340, 348, 355,
360, 365, 373, 380, 385, 390, 398, 405, 410, 425
]
x = np.array(metros_cuadrados).reshape(-1, 1)
y = np.array(precio_miles_euros)
# Datos de entrenamiento y pruebas (split)
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=42)
# Crear modelo y entrenar (fit)
model = LinearRegression()
model.fit(X_train, y_train)
print(f"Pendiente {model.coef_} intercepto {model.intercept_}")
# Predecir datos de test
y_pred = model.predict(X_test)
print(y_test)
print(y_pred.round(0))
# Métricas de errores
print(mean_absolute_error(y_test, y_pred))
print(mean_squared_error(y_test, y_pred))
print(r2_score(y_test, y_pred))
Ejercicio regresión
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
metros_cuadrados = [
40, 42, 45, 48, 50, 52, 55, 58, 60, 62,
65, 68, 70, 72, 75, 78, 80, 82, 85, 88,
90, 92, 95, 98, 100, 102, 105, 108, 110, 112,
115, 118, 120, 122, 125, 128, 130, 132, 135, 138,
140, 142, 145, 148, 150, 152, 155, 158, 160, 165
]
precio_miles_euros = [
120, 125, 128, 135, 140, 145, 150, 158, 160, 168,
175, 180, 185, 190, 198, 205, 210, 215, 223, 230,
235, 240, 248, 255, 260, 265, 273, 280, 285, 290,
298, 305, 310, 315, 323, 330, 335, 340, 348, 355,
360, 365, 373, 380, 385, 390, 398, 405, 410, 425
]
x = np.array(metros_cuadrados).reshape(-1, 1)
y = np.array(precio_miles_euros)
# Datos de entrenamiento y pruebas (split)
# Crear modelo y entrenar (fit)
# Predecir datos de test
# Métricas de errores
Ejemplo regresión
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
anuncios=[1,2,3,4,5]
# Datos perfectos
ventas=[5,8,11,14,17]
# Datos más reales
ventas=[5,7,12,14,16]
x = np.array(anuncios).reshape(-1, 1)
y = np.array(ventas)
modelo = LinearRegression()
modelo.fit(x, y)
print(f"Coeficiente {modelo.coef_} intercepto {modelo.intercept_}")
fig, axes = plt.subplots(1, 1, figsize=(10, 8))
axes.scatter(anuncios, ventas, color="steelblue", label="Datos")
axes.plot(x, modelo.predict(x), "r-", label="Modelo")
axes.set_title("Relación entre anuncios y ventas")
axes.set_xlabel("Anuncios"); axes.set_ylabel("Ventas")
axes.legend()
plt.tight_layout()
plt.show()
Probar regresión
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
# DATOS
x = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30
]
y = [
96, 92, 91, 87, 86, 82, 80, 78, 74, 72,
69, 68, 64, 61, 60, 56, 54, 51, 49, 45,
43, 40, 38, 35, 33, 29, 28, 24, 23, 19
]
x = np.array(x).reshape(-1, 1)
y = np.array(y)
# SPLIT
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size = 0.2, random_state = 42)
# ENTRENAMIENTO
modelo=LinearRegression()
modelo.fit(X_train, y_train)
# PREDICCION
y_pred = modelo.predict(X_test)
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"\nResultados en el conjunto de TEST:")
print(f" MAE = {mae:.3f} (error medio absoluto)")
print(f" RMSE = {rmse:.3f} (raiz error cuadratico)")
print(f" R2 = {r2:.3f} (coef. determinacion)")