2.6 - Notas de Luis - Nuestro primer modelo predictivo¶
Este documento detalla el desarrollo de nuestro primer proyecto de software de inteligencia artificial, centrado en la predicción de necesidades de mascarillas. El proceso se estructura en los siguientes pasos:
- Importación de bibliotecas necesarias.
- Preparación y preprocesamiento de los datos.
- Definición de los componentes del modelo.
- Implementación del bucle de entrenamiento.
- Visualización y análisis de los resultados.
- Aplicación del modelo para realizar predicciones.
Paso 1: Importación de bibliotecas necesarias¶
Para iniciar, procederemos a importar las bibliotecas de Python esenciales para este proyecto. Se han seleccionado dos bibliotecas principales por su idoneidad y simplicidad.
numpy: Biblioteca fundamental para la computación numérica en Python. Se utilizará para la manipulación de arreglos de datos y operaciones matemáticas.matplotlib: Biblioteca para la creación de visualizaciones estáticas, interactivas y animadas en Python. Se empleará para visualizar los datos y los resultados del modelo.
# Bloque de Código 1: Importando nuestras bibliotecas
import numpy as np
import matplotlib.pyplot as plt
# Una rápida impresión para confirmar que todo está cargado y listo. ¡Buena práctica!
print("Kit de herramientas listo. NumPy y Matplotlib están cargados y listos.")
Kit de herramientas listo. NumPy y Matplotlib están cargados y listos.
Paso 2: Preparación y preprocesamiento de los datos¶
Nuestro modelo necesita datos para aprender. Mientras Sophia y Ethan trabajan con la base de datos real del hospital, yo estoy creando un conjunto de datos "sintéticos". Actuará como si fuera real, imitando la relación entre pacientes (x) y mascarillas necesarias (y), pero con un toque aleatorio para que parezca real.
# Bloque de Código 2: Creando un conjunto de datos sintético y realista
# Estoy configurando una 'semilla aleatoria' aquí. Este es un paso crucial en la ingeniería de software
# para el aprendizaje automático. Asegura que nuestros números 'aleatorios' sean los mismos cada
# vez que ejecutamos este código, haciendo que nuestros resultados sean reproducibles.
np.random.seed(42)
# Simulemos datos para 50 días.
m = 50 # 'm' es el nombre de variable estándar para el número de ejemplos de entrenamiento.
# X = Número de Pacientes. Creemos 50 valores aleatorios entre 50 y 150.
# La forma (m, 1) lo convierte en un vector columna.
X = 50 + 100 * np.random.rand(m, 1)
# y = Número de Mascarillas Usadas.
# Creemos una relación: y = 25 (base) + 0.8 * X + algo de ruido aleatorio.
# Esto simula un escenario del mundo real donde la relación no es perfectamente lineal.
y = 25 + 0.8 * X + np.random.randn(m, 1) * 10
# Lo primero que debe hacer un desarrollador con los datos es mirarlos.
# Haagamos la gráfica para confirmar visualmente que se ven como esperamos.
plt.figure(figsize=(12, 7))
plt.scatter(X, y, label='Datos Diarios Simulados')
plt.title("Hospital Minermont - Datos Sintéticos")
plt.xlabel("Número de Pacientes (Característica X)")
plt.ylabel("Mascarillas Usadas (Objetivo y)")
plt.grid(True)
plt.legend()
plt.show()
Paso 3: Definición de los componentes del modelo¶
Marta nos dio el plano, ahora definamos las piezas centrales en nuestro código:
- La Hipótesis ($h(x)$): Esta es nuestra función de predicción. Para la regresión lineal, es solo la ecuación de una línea. La llamaré
prediction(). $$prediction(x) = w * x + b$$ $w$ (peso) y $b$ (sesgo) son los parámetros que nuestro modelo aprenderá. Estos son los "mandos" que ajustaremos. - La Función de Costo ($J(w, b$)): Esto nos dice como de "equivocadas" están las predicciones de nuestro modelo. Cuanto menor, mejor. Usaremos el Error Cuadrático Medio (MSE), una elección bastante estándar. $$cost = averageOf( (prediction - actualvalue)^2 )$$
- Descenso del Gradiente: Este es el proceso de aprendizaje en sí. Ajusta automáticamente $w$ y $b$ para minimizar el costo. Descubre la "pendiente" de la función de costo y da pasos cuesta abajo.
Paso 4: Implementación del bucle de entrenamiento¶
Este es el corazón de nuestro programa. Inicializaremos nuestros parámetros y luego ejecutaremos un bucle que los refinará repetidamente utilizando el Descenso del Gradiente.
Al tratarse de una muestra de datos muy pequeña con solo 50 elementos y para mantener el codigo senzillo, utilizaremos el descenso por lotes utilizando las 50 entradas en cada iteración.
# Bloque de Código 3: Construyendo y Entrenando el Modelo (con Detención Temprana)
# --- 1. Inicialización de Parámetros ---
# Necesitamos darle a nuestro modelo un punto de partida. Empecemos w y b en 0.
# Es una posición inicial simple y neutral.
w = 0.0
b = 0.0
# --- 2. Configuración de Hiperparámetros ---
# Estos son ajustes para el algoritmo de aprendizaje, no aprendidos de los datos.
# Tenemos que configurarlos nosotros mismos.
learning_rate = 0.0001 # Como de grande es el paso a dar en cada actualización. Un valor pequeño es más seguro.
num_iterations = 10000 # El número máximo de iteraciones.
alpha = 0.001 # Cambio mínimo en el costo para seguir adelante (umbral de detención temprana).
# --- 3. El Bucle de Entrenamiento ---
# Almacenaremos el costo en cada paso para observar cómo aprende nuestro modelo.
cost_log = []
print("Iniciando la secuencia de entrenamiento...")
for i in range(num_iterations):
# a) Realizar predicciones para TODOS nuestros puntos de datos con los w y b actuales.
y_pred = w * X + b
# b) Calcular el costo (MSE) para estas predicciones.
# Esto nos dice como de bien lo estamos haciendo en esta iteración.
cost = np.mean((y_pred - y)**2)
cost_log.append(cost)
# --- Condición de Detención Temprana ---
# Si el costo no ha cambiado mucho en comparación con el paso anterior,
# significa que hemos alcanzado una región plana, no estamos aprendiendo mucho más.
if i > 0 and abs(cost_log[-2] - cost_log[-1]) < alpha:
print(f"Deteniendo temprano en la iteración {i} debido a un pequeño cambio en el costo.")
break
# c) Calcular los gradientes. Este es el núcleo del aprendizaje.
# Estas fórmulas provienen de la derivada de cálculo de la función de costo.
# Nos dicen la pendiente de nuestra "colina" de costo para w y b.
dw = (1/m) * np.sum((y_pred - y) * X) # Gradiente para el peso
db = (1/m) * np.sum(y_pred - y) # Gradiente para el sesgo
# d) Actualizar los parámetros.
# Movemos w y b en la dirección *opuesta* a su gradiente.
# Este es el paso "cuesta abajo".
w = w - learning_rate * dw
b = b - learning_rate * db
# Un registro simple para monitorear el proceso en tiempo real.
# Imprimimos la evolución del error cada 100 iteraciones
# Empezamos imprimiendo la primera iteración ya que el error en 0 no es significativo al ser w y b aleatorios
if ((i-1) % 100) == 0:
print(f"Iteración {i}: Costo = {cost:.6f}")
# imprimir el número de iteraciones y el error final
print("\n--- Entrenamiento Completo ---")
print(f"Número de iteraciones: {i}")
print(f"Error final: {cost:.6f}")
print(f"Peso aprendido final (w): {w:.4f}")
print(f"Sesgo aprendido final (b): {b:.4f}")
Iniciando la secuencia de entrenamiento... Iteración 1: Costo = 149.453144 Iteración 101: Costo = 143.590561 Iteración 201: Costo = 143.488009 Iteración 301: Costo = 143.385628 Iteración 401: Costo = 143.283419 Iteración 501: Costo = 143.181381 Iteración 601: Costo = 143.079514 Iteración 701: Costo = 142.977817 Iteración 801: Costo = 142.876291 Iteración 901: Costo = 142.774934 Iteración 1001: Costo = 142.673747 Iteración 1101: Costo = 142.572729 Iteración 1201: Costo = 142.471881 Iteración 1301: Costo = 142.371201 Iteración 1401: Costo = 142.270689 Iteración 1501: Costo = 142.170346 Iteración 1601: Costo = 142.070171 Deteniendo temprano en la iteración 1657 debido a un pequeño cambio en el costo. --- Entrenamiento Completo --- Número de iteraciones: 1657 Error final: 142.014146 Peso aprendido final (w): 1.0363 Sesgo aprendido final (b): 0.3832
Paso 5: Visualización y análisis de los resultados¶
Okay, hemos construido el motor. Pero, ¿realmente está funcionando? En aprendizaje automático, tenemos que visualizar.
Primero, hagamos una gráfica de la curva de aprendizaje. Esto muestra cómo el costo disminuye con el tiempo. Si esta gráfica no baja, algo hemos hecho mal.
Luego, haremos la gráfica de la línea final que nuestro modelo aprendió sobre los datos originales. Esta es la verificación visual definitiva para ver como de bien se ajusta.
# Bloque de Código 4: Visualizando el Rendimiento del Modelo
# Crea una figura con dos gráficos lado a lado para un informe agradable.
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 7))
# elimina el primer valor del registro de costo, ya que en el primer paso w y b eran 0
# y este costo no es representativo
cost_log.pop(0)
# --- Gráfico 1: La Curva de Aprendizaje ---
ax1.plot(cost_log)
ax1.set_ylim(130, 160) # Establece el eje y a partir de los errores anteriores
ax1.set_title("Curva de Aprendizaje del Modelo")
ax1.set_xlabel("Iteración")
ax1.set_ylabel("Costo (Error Cuadrático Medio)")
ax1.grid(True)
# --- Gráfico 2: La Línea de Regresión Final ---
# Primero, añáde a la gráfica los puntos de datos originales
ax2.scatter(X, y, label='Datos Originales')
# Luego, añade a la gráfica la línea que nuestra el modelo aprendido
# Generamos los valores y para la línea usando nuestros w y b finales
ax2.plot(X, w * X + b, color='red', linewidth=3, label='Modelo Aprendido')
ax2.set_title("Ajuste del Modelo Final")
ax2.set_xlabel("Número de Pacientes")
ax2.set_ylabel("Mascarillas Usadas")
ax2.grid(True)
ax2.legend()
plt.show()
Paso 6: Aplicación del modelo para realizar predicciones¶
¡Muy bien, el objetivo era construir algo útil! Ahora que nuestro modelo está entrenado, usémoslo para predecir las necesidades de mascarillas para nuevos escenarios.
Esta es la recompensa: tomar nuestros w y b entrenados y conectarlos a nuestra ecuación de la recta.
# Bloque de Código 5: Haciendo una Predicción
# Digamos que queremos saber cuántas mascarillas debemos presupuestar si esperamos 100 pacientes mañana.
patients_tomorrow = 100
# Usamos nuestros w y b finales entrenados para calcular la predicción.
predicted_masks = w * patients_tomorrow + b
print("\n--- Haciendo una Nueva Predicción ---")
print(f"Para un día con {patients_tomorrow} pacientes...")
print(f"Nuestro modelo predice que necesitaremos aproximadamente {int(predicted_masks)} mascarillas.")
# Probemos otra para un día más tranquilo.
patients_quiet_day = 65
predicted_masks_quiet = w * patients_quiet_day + b
print(f"\nPara un día con {patients_quiet_day} pacientes...")
print(f"Nuestro modelo predice que necesitaremos aproximadamente {int(predicted_masks_quiet)} mascarillas.")
--- Haciendo una Nueva Predicción --- Para un día con 100 pacientes... Nuestro modelo predice que necesitaremos aproximadamente 104 mascarillas. Para un día con 65 pacientes... Nuestro modelo predice que necesitaremos aproximadamente 67 mascarillas.
Conclusión y Próximos Pasos¶
Hemos implementado con éxito un modelo predictivo inicial basado en regresión lineal para estimar la necesidad de mascarillas. Este enfoque fundamental, desarrollado desde cero.
Este primer prototipo, aunque conceptualmente simple, es robusto y escalable. Su implementación interna nos permite comprender a fondo su funcionamiento. Este modelo es el punto de partida para desarrollos más complejos y precisos.