Ejemplo completo

# =============================================================================
#  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)")