# =============================================================================
# COMPARATIVA: REGRESIÓN LOGÍSTICA vs REGRESIÓN LINEAL
# ¿En qué se diferencian? ¿Cuándo usar cada una?
# =============================================================================
#
# IDEA GENERAL DEL EJERCICIO:
# Tenemos 10 alumnos con sus horas de estudio.
# Vamos a entrenar DOS modelos distintos con los mismos datos:
#
# Modelo 1 — Regresión LOGÍSTICA:
# Pregunta: ¿Aprueba o suspende? → Responde con 0 o 1 (categoría)
#
# Modelo 2 — Regresión LINEAL:
# Pregunta: ¿Qué nota sacará? → Responde con un número decimal (valor continuo)
#
# Esto ilustra la diferencia clave entre CLASIFICACIÓN y REGRESIÓN en ML.
# =============================================================================
# ─────────────────────────────────────────────────────────────────────────────
# IMPORTACIONES
# ─────────────────────────────────────────────────────────────────────────────
import numpy as np
# numpy nos permite trabajar con arrays numéricos de forma eficiente.
# Lo usamos aquí para crear los datos de entrada y darles el formato correcto.
from sklearn.linear_model import LogisticRegression, LinearRegression
# De scikit-learn importamos los dos modelos que vamos a comparar:
# - LogisticRegression: clasifica (aprueba / suspende)
# - LinearRegression: predice un número continuo (la nota)
from sklearn.model_selection import train_test_split
# Herramienta para dividir los datos en entrenamiento y prueba.
# En este ejercicio no la usamos porque los datos son muy pocos (solo 10),
# pero se importa para recordar que en proyectos reales SIEMPRE hay que usarla.
from sklearn.metrics import accuracy_score
# Función para medir el porcentaje de aciertos de un clasificador.
# Igual que train_test_split, se importa como recordatorio de buenas prácticas,
# aunque en este ejercicio simplificado no la aplicamos.
# =============================================================================
# PASO 1 — PREPARAR LOS DATOS
# =============================================================================
# Horas de estudio de 10 alumnos (la variable de entrada, llamada X)
# Cada número representa cuántas horas estudió ese alumno.
X = np.array([1, 2, 2, 3, 4, 5, 6, 7, 8, 9]).reshape(-1, 1)
#
# ¿Qué hace .reshape(-1, 1)?
# ─────────────────────────
# scikit-learn espera que X tenga forma de TABLA (filas × columnas),
# aunque tengamos una sola columna.
#
# Sin reshape, X sería una lista plana: [1, 2, 2, 3, ...] → forma (10,)
# Con reshape(-1, 1), X se convierte en una columna vertical:
#
# [[1],
# [2],
# [2],
# [3], ← cada alumno ocupa una fila
# ...]
#
# El -1 le dice a numpy: "calcula tú cuántas filas hacen falta".
# El 1 indica que queremos 1 columna.
# Resultado: shape (10, 1) → 10 filas, 1 columna.
# Etiquetas para el Modelo 1 — Regresión LOGÍSTICA
# 0 = suspende, 1 = aprueba
y = np.array([0, 0, 0, 0, 0, 1, 1, 1, 1, 1])
#
# Alumno 1 estudió 1 hora → suspende (0)
# Alumno 2 estudió 2 horas → suspende (0)
# Alumno 3 estudió 2 horas → suspende (0)
# Alumno 4 estudió 3 horas → suspende (0)
# Alumno 5 estudió 4 horas → suspende (0)
# Alumno 6 estudió 5 horas → aprueba (1)
# Alumno 7 estudió 6 horas → aprueba (1)
# Alumno 8 estudió 7 horas → aprueba (1)
# Alumno 9 estudió 8 horas → aprueba (1)
# Alumno 10 estudió 9 horas → aprueba (1)
#
# El patrón es claro: a partir de 5 horas, los alumnos aprueban.
# El modelo logístico tiene que aprender ese umbral.
# =============================================================================
# PASO 2 — MODELO 1: REGRESIÓN LOGÍSTICA (clasificación)
# =============================================================================
#
# La regresión logística responde preguntas de tipo SÍ/NO, o en este caso
# APRUEBA/SUSPENDE. Internamente calcula la probabilidad de que el resultado
# sea 1 (aprueba), y si esa probabilidad supera el 50%, predice 1.
#
# Ejemplo: para un alumno con 3 horas podría calcular:
# probabilidad de aprobar = 15% → predice 0 (suspende)
#
# Para un alumno con 7 horas:
# probabilidad de aprobar = 92% → predice 1 (aprueba)
modelo = LogisticRegression()
# Creamos el modelo. Por ahora es una "caja vacía", aún no ha aprendido nada.
modelo.fit(X, y)
# .fit() es el entrenamiento.
# El modelo analiza todos los pares (horas_estudio, resultado)
# y ajusta sus parámetros internos para aprender el patrón:
# "a partir de X horas, la probabilidad de aprobar supera el 50%".
# ── Predicción con el Modelo 1 ────────────────────────────────────────────
print("=== MODELO 1: Regresión Logística (¿aprueba o suspende?) ===")
print(modelo.predict([[3]]))
# Le preguntamos al modelo: ¿un alumno que estudia 3 horas aprueba o suspende?
#
# [[3]] → los corchetes dobles son necesarios porque el modelo espera
# una tabla, no un número suelto. Es la misma lógica que el reshape anterior.
#
# Resultado esperado: [0] → el modelo predice que SUSPENDE.
# Esto tiene sentido: con solo 3 horas, los datos de entrenamiento
# mostraban que ese alumno suspendería.
print(modelo.predict_proba([[3]]))
# predict_proba nos da la probabilidad de cada clase, no solo la decisión.
# Devuelve dos números: [P(suspende), P(aprueba)]
# Por ejemplo: [0.82, 0.18] → 82% de probabilidad de suspender, 18% de aprobar.
# Útil cuando no queremos solo un sí/no, sino el grado de certeza del modelo.
# =============================================================================
# PASO 3 — DATOS PARA EL MODELO 2
# =============================================================================
# Notas numéricas de los mismos 10 alumnos (la nueva variable objetivo)
notas = np.array([3, 3, 4, 4, 5, 5, 6, 6, 8, 9])
#
# Alumno 1 (1 hora) → nota 3
# Alumno 2 (2 horas) → nota 3
# Alumno 3 (2 horas) → nota 4
# Alumno 4 (3 horas) → nota 4
# Alumno 5 (4 horas) → nota 5
# Alumno 6 (5 horas) → nota 5
# Alumno 7 (6 horas) → nota 6
# Alumno 8 (7 horas) → nota 6
# Alumno 9 (8 horas) → nota 8
# Alumno 10 (9 horas) → nota 9
#
# Aquí ya no es aprueba/suspende, sino la nota EXACTA.
# El modelo lineal tiene que aprender cuánto sube la nota por cada hora más.
# =============================================================================
# PASO 4 — MODELO 2: REGRESIÓN LINEAL (predicción de un valor continuo)
# =============================================================================
#
# La regresión lineal ajusta una LÍNEA RECTA a los datos.
# Busca la ecuación: nota = a × horas + b
#
# Donde:
# a (pendiente) = cuántos puntos sube la nota por cada hora extra
# b (intercepto) = nota base si el alumno estudiara 0 horas
#
# A diferencia del modelo logístico, la salida puede ser CUALQUIER número
# decimal: 4.2, 5.87, 7.3... No está limitada a 0 y 1.
modelo_2 = LinearRegression()
# Creamos el segundo modelo, también vacío de momento.
modelo_2.fit(X, notas)
# Entrenamos el modelo con las mismas horas de estudio (X)
# pero ahora la variable objetivo son las notas numéricas.
#
# Internamente calcula la recta que mejor se ajusta a los datos,
# minimizando el error total entre las notas reales y las predichas.
# ── Predicción con el Modelo 2 ────────────────────────────────────────────
print("\n=== MODELO 2: Regresión Lineal (¿qué nota sacará?) ===")
print(modelo_2.predict([[3]]))
# Le preguntamos: ¿qué nota obtendrá un alumno que estudia 3 horas?
#
# Resultado esperado: algo cercano a 4.0 o 4.2 (un número decimal).
# No devuelve 0 o 1, sino un valor numérico que representa la nota estimada.
# =============================================================================
# RESUMEN: ¿EN QUÉ SE DIFERENCIAN LOS DOS MODELOS?
# =============================================================================
#
# ┌──────────────────────┬─────────────────────┬──────────────────────────┐
# │ │ Regresión LOGÍSTICA │ Regresión LINEAL │
# ├──────────────────────┼─────────────────────┼──────────────────────────┤
# │ Tipo de problema │ Clasificación │ Regresión │
# │ Pregunta que responde│ ¿Categoría A o B? │ ¿Qué valor numérico? │
# │ Salida del modelo │ 0 o 1 (clase) │ Número decimal (nota) │
# │ En este ejercicio │ Suspende / Aprueba │ Nota entre 0 y 10 │
# │ Función interna │ Sigmoide (0 a 1) │ Recta y = ax + b │
# │ Métrica habitual │ Accuracy │ MSE, RMSE, R² │
# └──────────────────────┴─────────────────────┴──────────────────────────┘
#
# REGLA PRÁCTICA:
# → Si la respuesta es una CATEGORÍA (sí/no, color, especie...) → Logística
# → Si la respuesta es un NÚMERO CONTINUO (precio, temperatura...) → Lineal
# =============================================================================