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)")
Ejemplo regresión lineal
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
# 1. DATOS: horas de estudio y notas de 20 estudiantes
horas = np.array([[ 1. ], [ 1.47368421], [ 1.94736842], [ 2.42105263], [ 2.89473684], [ 3.36842105], [ 3.84210526], [ 4.31578947], [ 4.78947368], [ 5.26315789], [ 5.73684211], [ 6.21052632]
, [ 6.68421053], [ 7.15789474], [ 7.63157895], [ 8.10526316], [ 8.57894737], [ 9.05263158], [ 9.52631579], [10. ]])
notas = np.array([ 2.84835708, 2.95718364, 3.77647585, 4.6404623, 4.18818647, 4.61451047
, 5.94750114, 5.96792789, 5.77578912, 6.70812212, 6.63144905, 7.05660881
, 7.83677061, 7.18546514, 7.70596214, 8.71359308, 8.91463707, 10.00449209
, 9.81967217, 9.99384815])
# 2. DIVISION TRAIN / TEST (70% entrenamiento, 30% test)
X_train, X_test, y_train, y_test = train_test_split(
horas, notas, test_size=0.3,random_state=42
)
print(f"Datos de entrenamiento: {len(X_train)} muestras")
print(f"Datos de test: {len(X_test)} muestras")
# 3. ENTRENAMIENTO: el modelo aprende con X_train
modelo = LinearRegression()
modelo.fit(X_train, y_train) # Aqui ocurre el aprendizaje
print(f"\nEcuacion aprendida:")
print(f" nota = {modelo.coef_[0]:.3f} * horas + {modelo.intercept_:.3f}")
# 4. PREDICCION en datos de test (datos nunca vistos)
y_pred = modelo.predict(X_test)
# 5. EVALUACION con metricas
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)")
# 6. VISUALIZACION: entrenamiento vs test
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
axes[0].scatter(X_train, y_train, color="steelblue", label="Train")
axes[0].plot(horas, modelo.predict(horas), "r-", label="Modelo")
axes[0].set_title("Fase de Entrenamiento")
axes[0].set_xlabel("Horas"); axes[0].set_ylabel("Nota")
axes[0].legend()
axes[1].scatter(X_test, y_test, color="orange", label="Test")
axes[1].plot(horas, modelo.predict(horas), "r-", label="Modelo")
axes[1].set_title(f"Fase de Test (R2={r2:.2f})")
axes[1].set_xlabel("Horas"); axes[1].set_ylabel("Nota")
axes[1].legend()
plt.tight_layout()
plt.show()
Ejemplos pandas
import pandas as pd
df = pd.read_csv("ventas_alimentacion.csv", index_col=0)
print(df)
# Estadísticas por ciudad
print(df.sum()) # total ventas por ciudad
print(df.mean()) # media por ciudad
print(df.max()) # máximo por ciudad
datos = {
"Madrid": [12450, 8760, 11230, 9340, 14560, 10870, 6540, 7890],
"Barcelona": [9870, 7540, 8650, 7120, 11230, 12340, 5120, 6540],
"Valencia": [7340, 5980, 6780, 8450, 8760, 7650, 4870, 5230],
"Sevilla": [8920, 6120, 7450, 9210, 9870, 8430, 5340, 4980],
"Zaragoza": [4120, 3870, 4560, 3980, 5120, 3760, 2980, 3240],
"Bilbao": [5630, 4920, 6120, 4760, 7340, 9120, 3870, 4560],
"Málaga": [6780, 4560, 5340, 7890, 6540, 8760, 4120, 3870],
"Murcia": [3940, 3210, 4120, 5340, 4870, 4230, 2760, 2980],
}
indice = [
"Aceite de oliva",
"Pan y bollería",
"Leche y lácteos",
"Frutas y verduras",
"Carne y charcutería",
"Pescado y marisco",
"Pasta, arroz y legumbres",
"Conservas y enlatados",
]
df = pd.DataFrame(datos, index=indice)
print(df)
import pandas as pd
# ─────────────────────────────────────────────
# DATAFRAME DE EJEMPLO
# ─────────────────────────────────────────────
data = {
"Madrid": [12450, 8760, 11230, 9340, 14560, 10870],
"Barcelona": [ 9870, 7540, 8650, 7120, 11230, 12340],
"Valencia": [ 7340, 5980, 6780, 8450, 8760, 7650],
"Sevilla": [ 8920, 6120, 7450, 9210, 9870, 8430],
"Bilbao": [ 5630, 4920, 6120, 4760, 7340, 9120],
"Murcia": [ 3940, 3210, 4120, 5340, 4870, 4230],
}
indice = [
"Aceite de oliva",
"Pan y bollería",
"Leche y lácteos",
"Frutas y verduras",
"Carne y charcutería",
"Pescado y marisco",
]
df = pd.DataFrame(data, index=indice)
print(df)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 1 — .loc[] → celda exacta por nombre
# ══════════════════════════════════════════════════════════════════
# .loc usa ETIQUETAS (nombres reales de filas y columnas).
# Sintaxis: df.loc["nombre_fila", "nombre_columna"]
resultado = df.loc["Leche y lácteos", "Madrid"]
print("1) .loc celda exacta:")
print(resultado) # 11230
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 2 — .iloc[] → celda exacta por posición numérica
# ══════════════════════════════════════════════════════════════════
# .iloc usa POSICIONES enteras (0-based, igual que las listas).
# Fila 1 = "Pan y bollería", columna 2 = "Valencia"
resultado = df.iloc[1, 2]
print("2) .iloc celda exacta:")
print(resultado) # 5980
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 3 — df["columna"] → columna completa (una Serie)
# ══════════════════════════════════════════════════════════════════
# Con un solo corchete y el nombre de columna obtienes una Serie.
# La Serie conserva el índice original del DataFrame.
resultado = df["Barcelona"]
print("3) Columna completa con df['col']:")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 4 — .loc["fila"] → fila completa por nombre
# ══════════════════════════════════════════════════════════════════
# Al pasar solo un nombre de fila, .loc devuelve una Serie
# donde el índice son los nombres de las columnas.
resultado = df.loc["Frutas y verduras"]
print("4) Fila completa con .loc:")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 5 — .iloc[:, col] → columna completa por posición
# ══════════════════════════════════════════════════════════════════
# El ":" significa "todas las filas".
# La columna 3 corresponde a "Sevilla" (0=Madrid, 1=Barcelona, ...)
resultado = df.iloc[:, 3]
print("5) Columna por posición con .iloc[:, 3]:")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 6 — .loc[inicio:fin] → rango de filas por nombre
# ══════════════════════════════════════════════════════════════════
# Con .loc los rangos son INCLUSIVOS en ambos extremos,
# es decir, se incluyen tanto "Pan y bollería" como "Frutas y verduras".
resultado = df.loc["Pan y bollería":"Frutas y verduras"]
print("6) Rango de filas con .loc (inclusivo):")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 7 — .iloc[inicio:fin] → rango de filas por posición
# ══════════════════════════════════════════════════════════════════
# Con .iloc los rangos son EXCLUSIVOS en el extremo derecho,
# igual que los slices de Python. iloc[2:5] devuelve filas 2, 3 y 4.
resultado = df.iloc[2:5]
print("7) Rango de filas con .iloc (exclusivo en el extremo derecho):")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 8 — .iloc[f1:f2, c1:c2] → submatriz por posición
# ══════════════════════════════════════════════════════════════════
# Selecciona filas 0, 1, 2 (0:3 → exclusivo en 3)
# y columnas 1, 2, 3 (1:4 → exclusivo en 4)
resultado = df.iloc[0:3, 1:4]
print("8) Submatriz con .iloc[0:3, 1:4]:")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 9 — .loc[rango_filas, lista_columnas]
# ══════════════════════════════════════════════════════════════════
# Combina un rango de filas (por nombre) con una lista de columnas
# específicas. Muy útil para extraer subconjuntos concretos.
resultado = df.loc["Aceite de oliva":"Leche y lácteos", ["Madrid", "Bilbao"]]
print("9) Rango de filas + columnas específicas con .loc:")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 10 — df[df["col"] > valor] → filtrado booleano
# ══════════════════════════════════════════════════════════════════
# La expresión df["Madrid"] > 10000 genera una Serie de True/False.
# Al pasarla al DataFrame, devuelve solo las filas donde es True.
resultado = df[df["Madrid"] > 10000]
print("10) Máscara booleana — ventas en Madrid > 10.000 €:")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 11 — .loc[condición, columnas] → filtro + selección
# ══════════════════════════════════════════════════════════════════
# Combina un filtro booleano con selección de columnas concretas.
# Primero filtra las filas y luego escoge qué columnas mostrar.
resultado = df.loc[df["Barcelona"] > 9000, ["Barcelona", "Madrid"]]
print("11) .loc con condición y selección de columnas:")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 12 — df[["c1", "c2", ...]] → varias columnas a la vez
# ══════════════════════════════════════════════════════════════════
# Con DOBLE corchete se pasa una lista de nombres.
# El resultado es un DataFrame (no una Serie), aunque elijas 1 columna.
resultado = df[["Madrid", "Sevilla", "Murcia"]]
print("12) Varias columnas con doble corchete:")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 13 — .iat[] → celda por posición (versión rápida)
# ══════════════════════════════════════════════════════════════════
# .iat es equivalente a .iloc para UN ÚNICO valor escalar.
# Es más eficiente que .iloc en DataFrames grandes porque
# no construye objetos intermedios.
resultado = df.iat[4, 0]
print("13) .iat — celda por posición (rápido):")
print(resultado) # 14560 (fila 4 = "Carne", col 0 = "Madrid")
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 14 — .at[] → celda por etiqueta (versión rápida)
# ══════════════════════════════════════════════════════════════════
# .at es equivalente a .loc para UN ÚNICO valor escalar.
# Más rápido que .loc cuando solo necesitas un dato concreto.
resultado = df.at["Pescado y marisco", "Bilbao"]
print("14) .at — celda por etiqueta (rápido):")
print(resultado) # 9120
import pandas as pd
# ─────────────────────────────────────────────
# DATAFRAME DE EJEMPLO
# ─────────────────────────────────────────────
data = {
"Madrid": [12450, 8760, 11230, 9340, 14560, 10870],
"Barcelona": [ 9870, 7540, 8650, 7120, 11230, 12340],
"Valencia": [ 7340, 5980, 6780, 8450, 8760, 7650],
"Sevilla": [ 8920, 6120, 7450, 9210, 9870, 8430],
"Bilbao": [ 5630, 4920, 6120, 4760, 7340, 9120],
"Murcia": [ 3940, 3210, 4120, 5340, 4870, 4230],
}
indice = [
"Aceite de oliva",
"Pan y bollería",
"Leche y lácteos",
"Frutas y verduras",
"Carne y charcutería",
"Pescado y marisco",
]
df = pd.DataFrame(data, index=indice)
print(df)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 1 — df["col"] > valor → máscara booleana simple
# ══════════════════════════════════════════════════════════════════
# Una comparación sobre una columna devuelve una Serie de True/False.
# Al pasarla al DataFrame, actúa como "filtro de filas".
# Solo se muestran las filas donde la condición es verdadera.
mascara = df["Madrid"] > 10000
resultado = df[mascara]
print("1) Máscara booleana simple — Madrid > 10 000 €:")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 2 — & (AND) → dos condiciones simultáneas
# ══════════════════════════════════════════════════════════════════
# Para combinar condiciones usa & (AND) o | (OR).
# IMPORTANTE: cada condición debe ir entre paréntesis porque
# & tiene mayor precedencia que > y <.
resultado = df[(df["Madrid"] > 9000) & (df["Barcelona"] > 9000)]
print("2) Dos condiciones con & (AND) — Madrid > 9 000 y Barcelona > 9 000:")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 3 — | (OR) → al menos una condición verdadera
# ══════════════════════════════════════════════════════════════════
# Con | basta con que UNA de las condiciones sea True.
# Aquí: filas donde Bilbao supera 8 000 O Murcia supera 5 000.
resultado = df[(df["Bilbao"] > 8000) | (df["Murcia"] > 5000)]
print("3) Dos condiciones con | (OR) — Bilbao > 8 000 o Murcia > 5 000:")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 4 — ~ → negación de una máscara
# ══════════════════════════════════════════════════════════════════
# El operador ~ invierte una máscara booleana (True → False y viceversa).
# Equivale al NOT lógico: devuelve las filas que NO cumplen la condición.
resultado = df[~(df["Valencia"] > 7000)]
print("4) Negación con ~ — filas donde Valencia NO supera 7 000 €:")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 5 — .isin() → filtrar por lista de valores
# ══════════════════════════════════════════════════════════════════
# .isin(lista) devuelve True en las filas cuyo valor está en la lista.
# Muy útil cuando tienes un conjunto de etiquetas permitidas.
categorias_interes = ["Aceite de oliva", "Carne y charcutería", "Pescado y marisco"]
resultado = df[df.index.isin(categorias_interes)]
print("5) .isin() — solo categorías de interés:")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 6 — .query() → filtrar con expresión de texto
# ══════════════════════════════════════════════════════════════════
# .query() acepta una cadena de texto con la condición en lenguaje
# casi natural. Más legible para condiciones complejas.
# Nota: si el nombre de columna tiene espacios, usa backticks (`col`).
resultado = df.query("Madrid > 10000 and Sevilla > 8000")
print("6) .query() — Madrid > 10 000 y Sevilla > 8 000:")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 7 — .filter(items=) → seleccionar columnas por nombre
# ══════════════════════════════════════════════════════════════════
# .filter() selecciona columnas (o filas con axis=0) por nombre exacto.
# No filtra por valores, sino por NOMBRE de columna.
resultado = df.filter(items=["Madrid", "Barcelona", "Murcia"])
print("7) .filter(items=) — columnas Madrid, Barcelona y Murcia:")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 8 — .filter(like=) → columnas cuyo nombre contiene texto
# ══════════════════════════════════════════════════════════════════
# like= selecciona columnas cuyo nombre CONTIENE la subcadena dada.
# axis=1 indica que buscamos en columnas; axis=0 buscaría en el índice.
resultado = df.filter(like="a", axis=1) # columnas que contienen "a"
print("8) .filter(like='a') — columnas que contienen la letra 'a':")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 9 — .filter(regex=) → columnas por expresión regular
# ══════════════════════════════════════════════════════════════════
# regex= permite filtrar columnas cuyo nombre cumple un patrón regex.
# Aquí seleccionamos columnas que empiezan por 'M', 'B' o 'S'.
resultado = df.filter(regex="^(M|B|S)", axis=1)
print("9) .filter(regex=) — columnas que empiezan por M, B o S:")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 10 — .loc[condición, columnas] → filtro fila + columnas
# ══════════════════════════════════════════════════════════════════
# .loc admite una máscara booleana como selector de filas Y una lista
# de columnas como segundo argumento. El resultado es un sub-DataFrame.
resultado = df.loc[df["Bilbao"] > 6000, ["Bilbao", "Madrid", "Murcia"]]
print("10) .loc con condición + columnas — Bilbao > 6 000, ver Bilbao/Madrid/Murcia:")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 11 — .where() → mantiene forma, enmascara con NaN
# ══════════════════════════════════════════════════════════════════
# A diferencia de los filtros anteriores, .where() conserva el shape
# original del DataFrame. Las celdas que NO cumplen la condición
# se sustituyen por NaN (o por el valor que indiques en `other=`).
resultado = df.where(df > 8000)
print("11) .where(df > 8000) — valores < 8 000 sustituidos por NaN:")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 12 — .mask() → inverso de .where()
# ══════════════════════════════════════════════════════════════════
# .mask() es el opuesto de .where(): enmascara con NaN las celdas
# que SÍ cumplen la condición, manteniendo las que no la cumplen.
resultado = df.mask(df > 8000)
print("12) .mask(df > 8000) — valores > 8 000 sustituidos por NaN:")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 13 — filtro por índice con .str → texto en el índice
# ══════════════════════════════════════════════════════════════════
# Si el índice es de tipo cadena, puedes usar .str para filtrarlo.
# .str.contains() busca una subcadena; .str.startswith() un prefijo.
resultado = df[df.index.str.contains("y")]
print("13) Filtro de texto en el índice — categorías que contienen 'y':")
print(resultado)
print()
# ══════════════════════════════════════════════════════════════════
# MÉTODO 14 — .nlargest() / .nsmallest() → top N por columna
# ══════════════════════════════════════════════════════════════════
# .nlargest(n, columna) devuelve las n filas con mayor valor en
# la columna indicada, ordenadas de mayor a menor.
# .nsmallest(n, columna) hace lo mismo para los menores valores.
resultado = df.nlargest(3, "Madrid")
print("14) .nlargest(3, 'Madrid') — top 3 categorías en Madrid:")
print(resultado)
print()
resultado = df.nsmallest(3, "Murcia")
print(" .nsmallest(3, 'Murcia') — bottom 3 categorías en Murcia:")
print(resultado)
print()