Введение
В этом лабораторном занятии мы исследуем концепцию разложения смещения и дисперсии и то, как она связана с отдельными оценщиками по сравнению с ансамблями методом bagging. Мы будем использовать scikit-learn для генерации и визуализации примеров регрессионных задач и сравнивать ожидаемую среднеквадратичную ошибку отдельного оценщика и ансамбля деревьев решений методом bagging.
Советы по использованию ВМ
После запуска ВМ кликните в левом верхнем углу, чтобы переключиться на вкладку Notebook и получить доступ к Jupyter Notebook для практики.
Иногда вам может потребоваться подождать несколько секунд, пока Jupyter Notebook загрузится полностью. Валидация операций не может быть автоматизирована из-за ограничений Jupyter Notebook.
Если вы сталкиваетесь с проблемами во время обучения, не стесняйтесь обращаться к Labby. Оставьте отзыв после занятия, и мы оперативно решим проблему для вас.
Импортируем необходимые библиотеки
Сначала нам нужно импортировать необходимые библиотеки для генерации данных, обучения моделей и визуализации результатов.
import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import BaggingRegressor
from sklearn.tree import DecisionTreeRegressor
Задаем параметры
Нам нужно задать параметры, которые контролируют размер наборов данных, количество итераций и стандартное отклонение шума.
n_repeat = 50 ## Количество итераций для вычисления математических ожиданий
n_train = 50 ## Размер обучающего набора
n_test = 1000 ## Размер тестового набора
noise = 0.1 ## Стандартное отклонение шума
np.random.seed(0)
Генерируем данные
Мы сгенерируем задачу регрессии в 1D с использованием известной функции и добавим случайный шум в обучающие и тестовые наборы. Мы сгенерируем несколько обучающих наборов для вычисления ожидаемой среднеквадратичной ошибки.
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)
Определяем модели для сравнения
Мы определим две модели для сравнения: одно дерево решений и ансамбль деревьев решений методом bagging.
estimators = [
("Tree", DecisionTreeRegressor()),
("Bagging(Tree)", BaggingRegressor(DecisionTreeRegressor())),
]
n_estimators = len(estimators)
Обучаем модели и вычисляем ожидаемую среднеквадратичную ошибку
Мы будем перебирать оценщики, обучать их на нескольких обучающих наборах и вычислять ожидаемую среднеквадратичную ошибку, разлагая ее на слагаемые смещения, дисперсии и шума. Также построим графики предсказаний моделей и разложения на смещение и дисперсию.
plt.figure(figsize=(10, 8))
## Перебираем оценщики для сравнения
for n, (name, estimator) in enumerate(estimators):
## Вычисляем предсказания
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
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)
)
)
## Строим графики
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()
Интерпретируем результаты
Мы можем наблюдать разложение на смещение и дисперсию ожидаемой среднеквадратичной ошибки для каждой модели, а также предсказания моделей. Мы также можем сравнить общую ошибку двух моделей и их компромисс между смещением и дисперсией.
Резюме
В этом практическом занятии мы изучили концепцию разложения на смещение и дисперсию и то, как она связана с отдельными оценщиками по сравнению с ансамблями методом bagging. Мы сгенерировали и визуализировали задачи регрессии с использованием scikit - learn, и сравнили ожидаемую среднеквадратичную ошибку одного дерева решений и ансамбля деревьев решений методом bagging. Мы обнаружили, что компромисс между смещением и дисперсией лучше для bagging, так как он немного увеличивает слагаемое смещения, но позволяет более существенно уменьшить дисперсию, что приводит к более низкой общей среднеквадратичной ошибке.