简介
在本实验中,我们将探讨偏差 - 方差分解的概念,以及它与单个估计器和装袋集成方法之间的关系。我们将使用 scikit-learn 来生成和可视化简单的回归问题,并比较单个估计器与决策树装袋集成方法的预期均方误差。
虚拟机使用提示
虚拟机启动完成后,点击左上角切换到笔记本标签页,以访问 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)
生成数据
我们将使用一个已知函数生成一个简单的一维回归问题,并向训练集和测试集中添加随机噪声。我们将生成多个训练集以计算预期均方误差。
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)
定义要比较的模型
我们将定义两个模型进行比较:一个单决策树模型和一个决策树装袋集成模型。
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)
## 均方误差的偏差^2 + 方差 + 噪声分解
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} (误差) = {2:.4f} (偏差^2) "
" + {3:.4f} (方差) + {4:.4f} (噪声)".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="最小二乘 ~ $y = f(x)+噪声$")
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="$误差 (x)$")
plt.plot(X_test, y_bias, "b", label="$偏差^2(x)$"),
plt.plot(X_test, y_var, "g", label="$方差 (x)$"),
plt.plot(X_test, y_noise, "c", label="$噪声 (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()
解释结果
我们可以观察到每个模型的预期均方误差的偏差 - 方差分解,以及模型的预测结果。我们还可以比较这两个模型的总误差以及它们在偏差和方差之间的权衡。
总结
在本实验中,我们探讨了偏差 - 方差分解的概念,以及它与单个估计器和装袋集成之间的关系。我们使用 scikit - learn 生成并可视化了简单的回归问题,并比较了单决策树与决策树装袋集成的预期均方误差。我们发现,对于装袋来说,偏差和方差之间的权衡更好,因为它略微增加了偏差项,但能更大程度地降低方差,从而导致总体均方误差更低。