Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anterior Revisión previa
clase:ia:saa:6_optimizacion_modelo:sobreajuste [2023/02/20 08:23]
cesguiro borrado
— (actual)
Línea 1: Línea 1:
-====== 06 - Sobreajuste y subajuste ====== 
- 
-En temas anteriores vimos la regresión polinomial. Vamos a construir datos con un polinomio de grado 2: 
- 
-<sxh python> 
-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_squared_error 
-from sklearn.preprocessing import PolynomialFeatures 
-</sxh> 
- 
-<sxh python> 
-m = 100 
-X = 6 * np.random.rand(m, 1) -3 
-y = 0.5 * X**2 + X + 2 +np.random.rand(m, 1) 
-</sxh> 
- 
-Mostramos los datos en una gráfica: 
- 
-{{:clase:ia:saa:6_optimizacion_modelo:output.png?400|}} 
- 
-Separamos los datos en entrenamiento y test y mostramos los datos de entrenamiento en una gráfica: 
- 
-<sxh> 
-X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3) 
-</sxh>  
- 
-{{:clase:ia:saa:6_optimizacion_modelo:output2.png?400|}} 
- 
-Creamos un modelo de regresión lineal simple: 
- 
-<sxh python> 
-model = LinearRegression() 
- 
-model.fit(X_train, y_train) 
- 
-y_predict = model.predict(X_train) 
-</sxh> 
- 
-{{:clase:ia:saa:6_optimizacion_modelo:output3_1.png?400|}} 
- 
-Como vemos, la recta no se ajusta de forma óptima a nuestros datos. Vamos a ver el MSE de entrenamiento y de test: 
- 
-<sxh python> 
-rmse = mean_squared_error(y_true = y_train, y_pred = y_predict) 
-print("MSE entrenamiento: %.2f" % rmse) 
- 
-y_predict = model.predict(X_test) 
-rmse = mean_squared_error(y_true = y_test, y_pred = y_predict) 
-print("MSE test: %.2f" % rmse) 
-</sxh> 
- 
-<sxh base> 
-MSE entrenamiento: 1.56 
-MSE test: 1.49 
-</sxh> 
- 
-Nuestro modelo no es capaz de adecuarse correctamente a los datos.  Lo que está haciendo es **subajustando** los datos (**underfitting**). 
- 
-Vamos a crear ahora un modelo de regresión polinomial de grado 2: 
- 
-<sxh python> 
-poly_features = PolynomialFeatures(degree = 2) 
-X_poly = poly_features.fit_transform(X_train) 
- 
-model.fit(X_poly, y_train) 
- 
-y_predict = model.predict(X_poly) 
-</sxh> 
- 
-{{:clase:ia:saa:6_optimizacion_modelo:output3.png?400|}} 
- 
-Ahora sí que nuestro modelo se ajusta a los datos. Si miramos el MSE de entrenamiento y de test vemos que mejora mucho el rendimiento: 
- 
-<sxh python> 
-rmse = mean_squared_error(y_true = y_train, y_pred = y_predict) 
-print("MSE entrenamiento: %.2f" % rmse) 
- 
-X_poly = poly_features.transform(X_test) 
-y_predict = model.predict(X_poly) 
-rmse = mean_squared_error(y_true = y_test, y_pred = y_predict) 
-print("MSE test: %.2f" % rmse) 
-</sxh> 
- 
-<sxh base> 
-MSE entrenamiento: 0.08 
-MSE test: 0.07 
-</sxh> 
- 
-¿Que pasaría si aumentáramos el grado de polinomio? Por ejemplo, a 35: 
- 
-<sxh python> 
-poly_features = PolynomialFeatures(degree = 35) 
-X_poly = poly_features.fit_transform(X_train) 
- 
-model.fit(X_poly, y_train) 
- 
-y_predict = model.predict(X_poly) 
-</sxh> 
- 
-{{:clase:ia:saa:6_optimizacion_modelo:output4.png?400|}} 
- 
-Parece que no ajusta mal del todo en la mayoría de datos. Vamos a ver el MSE de entrenamiento y error: 
- 
-<sxh python> 
-rmse = mean_squared_error(y_true = y_train, y_pred = y_predict) 
-print("MSE entrenamiento: %.2f" % rmse) 
- 
-X_poly = poly_features.transform(X_test) 
-y_predict = model.predict(X_poly) 
-rmse = mean_squared_error(y_true = y_test, y_pred = y_predict) 
-print("MSE test: %.2f" % rmse) 
-</sxh> 
- 
-<sxh base> 
-MSE entrenamiento: 0.17 
-MSE test: 46545.50 
-</sxh> 
- 
-¿Qué está pasando? Nuestro modelo funciona bastante bien con los datos de entrenamiento (mucho mejor que con una regresión lineal simple), pero no generaliza nada bien. Ésto ocurre porque el modelo está **sobreajustando** mucho los datos (**overfitting**). 
- 
-Obviamente, en nuestro caso está claro que el modelo que mejor se ajusta a nuestros datos es el segundo (el de grado 2), ya que hemos creado nosotros los datos con un polinomio de grado 2. Pero, en general, no sabemos que función ha generado los datos, con lo que no tenemos modo de saber, a priori, como de complejo tiene que ser nuestro modelo. ¿Cómo puedo saber si el modelo está sobreajustando o subajustando los datos? 
- 
-Una forma de saberlo es utilizando la validación cruzada. Si un modelo tiene un buen rendimiento con los datos de entrenamiento pero malo con los de validación, está sobreajustando. Si se tiene un mal rendimiento en ambos casos, está subajustando. 
- 
-Otra forma de saberlo es fijarse en las curvas de aprendizaje. Por ejemplo, vamos a crear una función que muestre el RMSE en función del tamaño del conjunto de entrenamiento: 
- 
-<sxh python> 
-def plot_learning_curves(model, X, y): 
-    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2) 
-    train_errors, test_errors = [], [] 
-    for m in range(1, len(X_train)): 
-        model.fit(X_train[:m], y_train[:m]) 
-        y_train_predict = model.predict(X_train[:m]) 
-        y_test_predict = model.predict(X_test) 
-        train_errors.append(mean_squared_error(y_train[:m], y_train_predict, squared = False)) 
-        test_errors.append(mean_squared_error(y_test, y_test_predict, squared = False)) 
- 
-    figure = plt.figure(figsize = (15, 10)) 
-    axes = figure.add_subplot() 
-    _ = axes.plot(train_errors, "r-+", linewidth = 1, label = "train") 
-    _ = axes.plot(test_errors, "b-", linewidth = 1, label = "test") 
-    axes.set_ylim(ymin=0,ymax=3) 
-    axes.legend(fontsize=15,facecolor='#CDCDCD',labelcolor="#000000") 
-    axes.set_xlabel('Tamaño conjunto entrenamiento', fontsize=25,labelpad=20) 
-    axes.set_ylabel('RMSE', fontsize=25,labelpad=20) 
-</sxh> 
- 
-Nuestra función recibe un modelo y unos datos (X, y). Separa en entrenamiento y test y va entrenando el modelo con un conjunto de entrenamiento cada vez más grande. Por último, muestra el gráfico. 
- 
-Aplicamos la función al primer modelo (regresión lineal simple): 
- 
-<sxh python> 
-model  = LinearRegression() 
-plot_learning_curves(model, X, y) 
-</sxh> 
- 
-{{:clase:ia:saa:6_optimizacion_modelo:output5.png?400|}} 
- 
-Si nos fijamos en el rendimiento de los datos de entrenamiento, vemos que cuando hay una o dos instancias, el modelo ajusta perfectamente. A medida que vamos aumentando el tamaño del conjunto de entrenamiento, el error va aumentando, hasta llegar a una especie de meseta. En los datos de test, nuestro modelo es incapaz de ajustar cuando hay pocos datos. Si aumentamos el tamaño de los datos de entrenamiento, va mejorando el rendimiento hasta llegar a otra meseta cerca de la otra curva. Esta gráfica es típica de modelo subajustados. Ambas curvas están cerca, han llegado a una meseta y el error es bastante elevado. 
- 
-Vamos ahora con el segundo modelo (polinomio de grado 2): 
- 
-<sxh python> 
-poly_features = PolynomialFeatures(degree = 2) 
-X_poly = poly_features.fit_transform(X) 
- 
-plot_learning_curves(model, X_poly, y) 
-</sxh> 
- 
-{{:clase:ia:saa:6_optimizacion_modelo:output6.png?400|}} 
- 
-En este caso, las curvas están más cerca y el error es mucho menor. Nuestro modelo está funcionando de manera correcta. 
- 
-Último modelo (polinomio de grado 35): 
- 
-<sxh python> 
-poly_features = PolynomialFeatures(degree = 35) 
-X_poly = poly_features.fit_transform(X) 
- 
-plot_learning_curves(model, X_poly, y) 
-</sxh> 
- 
-{{:clase:ia:saa:6_optimizacion_modelo:output7.png?400|}} 
- 
-Aquí vemos que el error de entrenamiento va aumentando poco a poco, pero se mantiene bastante bajo. Sin embargo, el error de test se mantiene muy alto y las curvas están muy separadas. Obviamente, si aumentáramos el tamaño de los datos de entrenamiento las dos curvas se acercarían cada vez más. Esta gráfica es típica de modelo sobreajustados. 
- 
-Otra forma de intentar evitar el sobreajuste es, como veremos en el punto siguiente, la **regularización**. 
  
  • clase/ia/saa/6_optimizacion_modelo/sobreajuste.1676877783.txt.gz
  • Última modificación: 2023/02/20 08:23
  • por cesguiro