2.6 - Notas de Luis - Primer modelo predictivo con scikit-learn¶
En este cuaderno, vamos a construir nuestro primer modelo predictivo utilizando la potente biblioteca scikit-learn de Python. Nos centraremos en la regresión lineal, un algoritmo fundamental en el aprendizaje automático, y veremos cómo scikit-learn simplifica el proceso de entrenamiento, evaluación y uso de modelos.
Es el compañero del cuaderno Regresión lineal desde cero: allí escribimos nosotros la regla de predicción, el coste y el bucle del descenso del gradiente; aquí ese trabajo lo hace la biblioteca. Para poder comprobar el resultado, usaremos datos generados a partir de una recta que elegimos nosotros, $y = 4 + 3x$, más un poco de ruido aleatorio. El modelo solo verá los puntos con ruido, así que, si funciona, debería recuperar una pendiente cercana a 3 y un término independiente cercano a 4.
A lo largo de este cuaderno, seguiremos estos pasos:
- Importación de las bibliotecas necesarias: cargaremos las herramientas de scikit-learn que necesitamos.
- Carga y preparación de los datos: generaremos datos sintéticos para nuestro ejemplo.
- División de los datos en conjuntos de entrenamiento y prueba: separaremos los datos para entrenar y evaluar el modelo de manera efectiva.
- Entrenamiento del modelo: ajustaremos el modelo de regresión lineal a nuestros datos de entrenamiento.
- Evaluación del modelo: mediremos el rendimiento del modelo con métricas estándar.
- Visualización de los resultados: representaremos los datos y la recta de regresión para entenderlo de forma visual.
- Uso del modelo para hacer predicciones: haremos predicciones con el modelo entrenado.
Paso 1: Importación de las bibliotecas necesarias¶
En esta sección, importaremos las funciones y clases esenciales de la biblioteca scikit-learn que necesitaremos para construir, entrenar, evaluar y utilizar nuestro modelo de regresión lineal.
# Importamos LinearRegression para construir el modelo
from sklearn.linear_model import LinearRegression
# Importamos train_test_split para dividir los datos en conjuntos de entrenamiento y prueba
from sklearn.model_selection import train_test_split
# Importamos mean_squared_error y r2_score para evaluar el modelo
from sklearn.metrics import mean_squared_error, r2_score
Paso 2: Carga y preparación de los datos¶
Para este ejemplo, generaremos un conjunto de datos sintéticos que simulan una relación lineal entre una variable independiente (X) y una variable dependiente (y), añadiendo un poco de ruido para hacer el ejemplo más realista. Esto nos permite controlar las características de los datos y entender mejor cómo funciona el modelo.
La recta que plantamos es $y = 4 + 3x$ (pendiente 3, término independiente 4) y el ruido sigue una distribución normal estándar (media 0 y desviación típica 1). Fíjate en la forma (m, 1): scikit-learn espera X como una tabla con una fila por ejemplo y una columna por característica.
import numpy as np
# Generar datos sintéticos
m = 50 # Número de datos de la muestra
np.random.seed(0) # Para reproducibilidad: los mismos números "aleatorios" en cada ejecución
X = 10 * np.random.rand(m, 1) # m puntos entre 0 y 10, con forma (50, 1)
y = 4 + 3 * X + np.random.randn(m, 1) # La recta plantada y = 4 + 3x, más ruido
Paso 3: División de los datos en conjuntos de entrenamiento y prueba¶
Es una práctica estándar en aprendizaje automático dividir los datos en dos conjuntos:
- Conjunto de entrenamiento: para entrenar el modelo.
- Conjunto de prueba: para evaluar su rendimiento en datos no vistos.
Tres divisiones habituales son 70/30, 75/25 y 80/20. Utilizaremos la división de 80% para entrenamiento y 20% para prueba.
Esto ayuda a detectar el sobreajuste y a obtener una estimación más realista de la capacidad de generalización del modelo. Utilizaremos la función train_test_split de scikit-learn para realizar esta división de forma sencilla.
# Dividir los datos en conjuntos de entrenamiento y prueba
# test_size=0.2 -> el 20% de las filas (10 de 50) va al conjunto de prueba
# random_state=0 -> la misma mezcla, y por tanto la misma división, en cada ejecución
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
print(f"Tamaño del conjunto de entrenamiento: {X_train.shape[0]}")
print(f"Tamaño del conjunto de prueba: {X_test.shape[0]}")
Tamaño del conjunto de entrenamiento: 40 Tamaño del conjunto de prueba: 10
Paso 4: Entrenamiento del modelo¶
Aquí es donde utilizamos la clase LinearRegression de scikit-learn. Crearemos una instancia de este modelo y lo "entrenaremos" con los datos del conjunto de entrenamiento (X_train e y_train). El método fit() se encargará de encontrar los coeficientes de la recta que mejor se ajusta a estos datos.
A diferencia de la versión desde cero, no hay tasa de aprendizaje ni número de iteraciones que elegir: para la regresión lineal, scikit-learn calcula directamente la solución de mínimos cuadrados. Lo que ha aprendido el modelo se guarda en atributos cuyo nombre termina en guion bajo: coef_ (el peso $w$, es decir, la pendiente) e intercept_ (el sesgo $b$).
# Crear una instancia del modelo de regresión lineal
model = LinearRegression()
# Entrenar el modelo con los datos de entrenamiento
model.fit(X_train, y_train)
print("Modelo entrenado con éxito.")
print(f"Coeficiente (peso): {model.coef_[0][0]:.4f}")
print(f"Término independiente (sesgo): {model.intercept_[0]:.4f}")
Modelo entrenado con éxito. Coeficiente (peso): 2.9820 Término independiente (sesgo): 4.0371
A partir de 40 puntos con ruido, el modelo ha recuperado casi exactamente la recta plantada: una pendiente de unos 2,98 (el valor real es 3) y un término independiente de unos 4,04 (el valor real es 4). Las pequeñas diferencias se deben al ruido.
Paso 5: Evaluación del modelo¶
Una vez entrenado el modelo, necesitamos evaluar cómo de bien funciona con datos que no ha visto durante el entrenamiento: el conjunto de prueba. En regresión, dos métricas habituales son:
- Error Cuadrático Medio (ECM): la media de las diferencias al cuadrado entre las predicciones y los valores reales. Cuanto más bajo, mejor. Elevar al cuadrado hace que los errores grandes cuenten más.
- Coeficiente de Determinación (R²): $R^2 = 1 - \frac{\sum (y - \hat{y})^2}{\sum (y - \bar{y})^2}$. Compara los errores del modelo con la dispersión de los valores alrededor de su media. $R^2 = 1$ es un ajuste perfecto y $R^2 = 0$ significa que el modelo no es mejor que predecir siempre la media.
# Realizar predicciones sobre el conjunto de prueba
y_pred = model.predict(X_test)
# Calcular el Error Cuadrático Medio (ECM)
mse = mean_squared_error(y_test, y_pred)
# Calcular el Coeficiente de Determinación (R²)
r2 = r2_score(y_test, y_pred)
print(f"Error Cuadrático Medio (ECM): {mse:.4f}")
print(f"Coeficiente de Determinación (R²): {r2:.4f}")
Error Cuadrático Medio (ECM): 0.8376 Coeficiente de Determinación (R²): 0.9757
# Comparar con el error sobre los datos de entrenamiento: valores parecidos indican que el modelo generaliza
train_mse = mean_squared_error(y_train, model.predict(X_train))
print(f"ECM de entrenamiento: {train_mse:.4f}")
print(f"ECM de prueba: {mse:.4f}")
ECM de entrenamiento: 0.8775 ECM de prueba: 0.8376
El ECM de prueba (unos 0,84) se parece a la varianza del ruido que añadimos (1, porque su desviación típica es 1): los errores del modelo son, sobre todo, ese ruido, que ninguna recta puede eliminar. Un R² de unos 0,98 sobre datos no vistos, y un error de entrenamiento del mismo tamaño que el de prueba, nos dicen que el modelo ha capturado la relación sin sobreajustarse.
Paso 6: Visualización de los resultados¶
La visualización es una herramienta muy potente para entender el ajuste del modelo. Representaremos los puntos de datos originales (entrenamiento y prueba) y la recta de regresión aprendida por el modelo. Así veremos cómo de bien representa la recta la relación entre X e y, y cómo se compara con los datos de prueba.
import matplotlib.pyplot as plt
# Visualizar los datos de entrenamiento y de prueba y la recta de regresión
plt.scatter(X_train, y_train, color='blue', label='Datos de entrenamiento')
plt.scatter(X_test, y_test, color='red', label='Datos de prueba')
plt.plot(X, model.predict(X), color='green', label='Recta de regresión')
plt.xlabel('X')
plt.ylabel('y')
plt.title('Regresión lineal con scikit-learn')
plt.legend()
plt.show()
Paso 7: Uso del modelo para hacer predicciones¶
Finalmente, utilizamos el modelo entrenado para hacer predicciones sobre nuevos valores de la variable independiente (X) que el modelo no ha visto antes. Esto simula cómo se usaría el modelo en un escenario real para predecir resultados futuros.
predict() espera la misma forma que X: una fila por ejemplo. Fíjate en el rango: los datos de entrenamiento solo cubrían valores de $x$ entre 0 y 10.
- Para $x = 2{,}5$, dentro de ese rango, el modelo está interpolando.
- Para $x = 15$, fuera de él, el modelo está extrapolando: simplemente prolonga la recta. Aquí la respuesta se acerca al valor real ($4 + 3 \cdot 15 = 49$) solo porque plantamos una recta perfecta; con datos reales nada garantiza que el patrón continúe más allá del rango con el que entrenamos.
# Usar el modelo para predecir con nuevos datos
X_new = np.array([[2.5], [15]]) # Dos nuevos valores de X, una fila cada uno
y_new_pred = model.predict(X_new)
for x, y_hat in zip(X_new, y_new_pred):
print(f"Predicción para X = {x[0]}: {y_hat[0]:.2f}")
print("(15 está fuera del rango 0-10 con el que entrenamos: extrapolación)")
Predicción para X = 2.5: 11.49 Predicción para X = 15.0: 48.77 (15 está fuera del rango 0-10 con el que entrenamos: extrapolación)
Conclusión¶
En este cuaderno hemos implementado un modelo de regresión lineal con la biblioteca scikit-learn. A diferencia de una implementación manual, scikit-learn simplifica mucho el proceso, porque ofrece herramientas eficientes y optimizadas para:
- La división de los datos:
train_test_splitfacilita separar los datos en conjuntos de entrenamiento y prueba, algo esencial para entrenar bien y evaluar de forma realista. - El entrenamiento del modelo:
LinearRegressionabstrae los detalles matemáticos y computacionales del entrenamiento y nos permite ajustar el modelo con una simple llamada afit(): sin tasa de aprendizaje, sin bucle y sin gradientes que escribir. - La evaluación del modelo: métricas como
mean_squared_erroryr2_scorenos dan una medida cuantitativa del rendimiento del modelo con datos no vistos.
El modelo ha recuperado la recta que plantamos (pendiente ≈ 3, término independiente ≈ 4), sus errores en el conjunto de prueba son del tamaño del ruido y sus errores de entrenamiento y de prueba son parecidos. La visualización confirma que la recta de regresión pasa tanto por los puntos de entrenamiento como por los de prueba.
En resumen, scikit-learn es una herramienta potente y fácil de usar para construir y evaluar modelos de aprendizaje automático, que acelera el desarrollo y nos permite centrarnos en interpretar los resultados y mejorar el modelo. Un buen siguiente paso es probar estas mismas llamadas con tus propios datos y con más de una característica.