Introducción
En este laboratorio, exploraremos el concepto de descomposición de sesgo-varianza y cómo se relaciona con estimadores individuales versus conjuntos de bagging. Usaremos scikit-learn para generar y visualizar problemas de regresión de juguete y comparar el error cuadrático medio esperado de un estimador individual versus un conjunto de bagging de árboles de decisión.
Consejos sobre la VM
Una vez que se haya iniciado la VM, haga clic en la esquina superior izquierda para cambiar a la pestaña Cuaderno y acceder a Jupyter Notebook para practicar.
A veces, es posible que tenga que esperar unos segundos a que Jupyter Notebook termine de cargarse. La validación de operaciones no se puede automatizar debido a las limitaciones de Jupyter Notebook.
Si tiene problemas durante el aprendizaje, no dude en preguntar a Labby. Deje comentarios después de la sesión y lo resolveremos rápidamente para usted.
Importar las bibliotecas necesarias
Primero, necesitamos importar las bibliotecas necesarias para generar datos, entrenar modelos y visualizar los resultados.
import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import BaggingRegressor
from sklearn.tree import DecisionTreeRegressor
Establecer los parámetros
Necesitamos establecer los parámetros que controlan el tamaño de los conjuntos de datos, el número de iteraciones y la desviación estándar del ruido.
n_repeat = 50 ## Número de iteraciones para calcular las expectativas
n_train = 50 ## Tamaño del conjunto de entrenamiento
n_test = 1000 ## Tamaño del conjunto de prueba
noise = 0.1 ## Desviación estándar del ruido
np.random.seed(0)
Generar datos
Generaremos un problema de regresión de juguete unidimensional usando una función conocida, y agregaremos ruido aleatorio a los conjuntos de entrenamiento y prueba. Generaremos múltiples conjuntos de entrenamiento para calcular el error cuadrático medio esperado.
def f(x):
x = x.ravel()
return np.exp(-(x**2)) + 1.5 * np.exp(-((x - 2) ** 2))
def generate(n_samples, noise, n_repeat=1):
X = np.random.rand(n_samples) * 10 - 5
X = np.sort(X)
if n_repeat == 1:
y = f(X) + np.random.normal(0.0, noise, n_samples)
else:
y = np.zeros((n_samples, n_repeat))
for i in range(n_repeat):
y[:, i] = f(X) + np.random.normal(0.0, noise, n_samples)
X = X.reshape((n_samples, 1))
return X, y
X_train = []
y_train = []
for i in range(n_repeat):
X, y = generate(n_samples=n_train, noise=noise)
X_train.append(X)
y_train.append(y)
X_test, y_test = generate(n_samples=n_test, noise=noise, n_repeat=n_repeat)
Definir los modelos para comparar
Definiremos dos modelos para comparar: un solo árbol de decisión y un conjunto de bagging de árboles de decisión.
estimators = [
("Tree", DecisionTreeRegressor()),
("Bagging(Tree)", BaggingRegressor(DecisionTreeRegressor())),
]
n_estimators = len(estimators)
Entrenar los modelos y calcular el error cuadrático medio esperado
Recorreremos los estimadores, los entrenaremos en los múltiples conjuntos de entrenamiento y calcularemos el error cuadrático medio esperado descomponiéndolo en términos de sesgo, varianza y términos de ruido. También graficaremos las predicciones de los modelos y la descomposición de sesgo-varianza.
plt.figure(figsize=(10, 8))
## Loop over estimators to compare
for n, (name, estimator) in enumerate(estimators):
## Compute predictions
y_predict = np.zeros((n_test, n_repeat))
for i in range(n_repeat):
estimator.fit(X_train[i], y_train[i])
y_predict[:, i] = estimator.predict(X_test)
## Bias^2 + Variance + Noise decomposition of the mean squared error
y_error = np.zeros(n_test)
for i in range(n_repeat):
for j in range(n_repeat):
y_error += (y_test[:, j] - y_predict[:, i]) ** 2
y_error /= n_repeat * n_repeat
y_noise = np.var(y_test, axis=1)
y_bias = (f(X_test) - np.mean(y_predict, axis=1)) ** 2
y_var = np.var(y_predict, axis=1)
print(
"{0}: {1:.4f} (error) = {2:.4f} (bias^2) "
" + {3:.4f} (var) + {4:.4f} (noise)".format(
name, np.mean(y_error), np.mean(y_bias), np.mean(y_var), np.mean(y_noise)
)
)
## Plot figures
plt.subplot(2, n_estimators, n + 1)
plt.plot(X_test, f(X_test), "b", label="$f(x)$")
plt.plot(X_train[0], y_train[0], ".b", label="LS ~ $y = f(x)+noise$")
for i in range(n_repeat):
if i == 0:
plt.plot(X_test, y_predict[:, i], "r", label=r"$\^y(x)$")
else:
plt.plot(X_test, y_predict[:, i], "r", alpha=0.05)
plt.plot(X_test, np.mean(y_predict, axis=1), "c", label=r"$\mathbb{E}_{LS} \^y(x)$")
plt.xlim([-5, 5])
plt.title(name)
if n == n_estimators - 1:
plt.legend(loc=(1.1, 0.5))
plt.subplot(2, n_estimators, n_estimators + n + 1)
plt.plot(X_test, y_error, "r", label="$error(x)$")
plt.plot(X_test, y_bias, "b", label="$bias^2(x)$"),
plt.plot(X_test, y_var, "g", label="$variance(x)$"),
plt.plot(X_test, y_noise, "c", label="$noise(x)$")
plt.xlim([-5, 5])
plt.ylim([0, 0.1])
if n == n_estimators - 1:
plt.legend(loc=(1.1, 0.5))
plt.subplots_adjust(right=0.75)
plt.show()
Interpretar los resultados
Podemos observar la descomposición de sesgo-varianza del error cuadrático medio esperado para cada modelo, así como las predicciones de los modelos. También podemos comparar el error total de los dos modelos y su compensación entre sesgo y varianza.
Resumen
En este laboratorio, exploramos el concepto de descomposición de sesgo-varianza y cómo se relaciona con estimadores individuales versus conjuntos de bagging. Generamos y visualizamos problemas de regresión de juguete usando scikit-learn, y comparamos el error cuadrático medio esperado de un solo árbol de decisión versus un conjunto de bagging de árboles de decisión. Encontramos que la compensación entre sesgo y varianza es mejor para el bagging, ya que aumenta ligeramente el término de sesgo pero permite una mayor reducción de la varianza, lo que resulta en un error cuadrático medio general más bajo.