之前介绍的PAC等学习模型主要基于弱可学习性的概念,这些模型中,集成中的每个学习算法只需要略优于随机猜测即可。例如,如果集成中的每个算法至少能正确分类51%的情况,就满足了弱学习的标准。这与PAC学习模型有所不同,后者要求算法具有较高的精度。尽管这类模型比随机算法更有效,但它们的适用范围相对有限。因此,我们需要建立一种超越单一弱学习规则的模型,Boosting在这种情况下应运而生。
Boosting是一种简单而强大的思想,它考虑了模型的训练误差,从而扩展了Bagging(包括随机森林和极端随机树)的方法。
例如,如果我们训练一个线性分类器,并发现它在某些特定实例上分类错误,我们可以在后续模型的训练过程中增加这些分类错误实例的副本数量。这样,我们期望新训练的模型在测试集上的表现会更好。通过增加分类错误实例的副本数量,数据集的平均值会向这些错误实例倾斜,迫使学习器更加关注这些难分类的样本。
在实践中,可以赋予分类错误实例更高的权重,并相应地调整模型(如在线性分类器中,可以采用加权平均的方法)。也就是说,在训练初期,数据集采用统一的权重;一旦发现错误分类的实例,就增加这些实例的权重。
AdaBoost是最流行的Boosting算法之一。它采用决策树分类器作为基础学习器,并针对不可分割的数据建立了决策边界。接下来,我们来看一个具体的代码示例:
```python import numpy as np import matplotlib.pyplot as plt from sklearn.tree import DecisionTreeClassifier from sklearn.datasets import make_blobs from sklearn.ensemble import AdaBoostClassifier
plotcolor = "br" plotstep = 0.02 class_names = "AB"
trees = DecisionTreeClassifier() ada_boost = AdaBoostClassifier()
x, y = makeblobs(nsamples=500, centers=2, randomstate=0, clusterstd=2) ada_boost.fit(x, y)
plt.figure(figsize=(10, 5))
plt.subplot(121) xmin, xmax = x[:, 0].min() - 1, x[:, 0].max() + 1 ymin, ymax = x[:, 1].min() - 1, x[:, 1].max() + 1 xx, yy = np.meshgrid(np.arange(xmin, xmax, plotstep), np.arange(ymin, ymax, plotstep)) z = adaboost.predict(np.c[xx.ravel(), yy.ravel()]) z = z.reshape(xx.shape) cs = plt.contourf(xx, yy, z, cmap=plt.cm.Paired) plt.axis("Tight")
for i, n, c in zip(range(2), classnames, plotcolor): idx = np.where(y == i) plt.scatter(x[idx, 0], x[idx, 1], c=c, cmap=plt.cm.Paired, label="Class %s" % n)
plt.title('AdaBoost 决策边界') classoutput = adaboost.decisionfunction(x) plotrange = (classoutput.min(), classoutput.max()) plt.subplot(122) for i, n, c in zip(range(2), classnames, plotcolor): plt.hist(classoutput[y == i], bins=20, range=plotrange, facecolor=c, label='Class %s' % n, alpha=.5)
x1, x2, y1, y2 = plt.axis() plt.axis((x1, x2, y1, y2)) plt.legend(loc='lower left') plt.ylabel('样本数') plt.xlabel('得分') plt.title('AdaBoost 决策得分') plt.show()
print("平均准确率={:.3f}".format(ada_boost.score(x, y))) ```
运行上述代码后,得到的结果如下:
梯度Boosting是一种非常有用的算法,适用于回归和分类任务。它的主要优势之一是能够自然处理混合数据类型,并且对离群点具有较好的鲁棒性。然而,由于其串行结构,梯度Boosting不适合并行技术,因此在处理大规模数据集时可能不如随机森林(RandomForestClassifier)高效。
梯度Boosting通常使用决策树作为弱学习器的集成,并对代价函数进行优化。下面是一个具体的例子,我们构建了一个梯度Boosting模型,并绘制了其累积损失随迭代次数的变化情况:
```python from sklearn import ensemble from sklearn import datasets from sklearn.modelselection import traintest_split import seaborn as sns
x, y = datasets.makemoons(nsamples=800, randomstate=1) x = x.astype(np.float32) labels, y = np.unique(y, returninverse=True) xtrain, xtest, ytrain, ytest = traintestsplit(x, y, test_size=0.3, shuffle=False)
originalparams = {'nestimators': 800, 'maxleafnodes': 4, 'maxdepth': None, 'randomstate': 2, 'minsamplessplit': 5}
sns.set(style='darkgrid')
for label, color, setting in [('无收缩', 'orange', {'learningrate': 1.0, 'subsample': 1.0}), ('learningrate=0.01', 'turquoise', {'learningrate': 0.01, 'subsample': 1.0}), ('subsample=0.05', 'blue', {'learningrate': 1.0, 'subsample': 0.05}), ('learningrate=0.1, subsample=0.05', 'gray', {'learningrate': 0.1, 'subsample': 0.05})]: params = dict(originalparams) params.update(setting) clf = ensemble.GradientBoostingClassifier(**params) clf.fit(xtrain, y_train)
# 计算测试误差
test_deviance = np.zeros((params['n_estimators'],), dtype=np.float64)
for i, y_pred in enumerate(clf.staged_decision_function(x_test)):
test_deviance[i] = clf.loss_(y_test, y_pred)
plt.plot((np.arange(test_deviance.shape[0]) + 1)[::5], test_deviance[::5], color=color, label=label)
plt.legend() plt.xlabel('提升迭代次数') plt.ylabel('测试集偏差') plt.show() ```
运行上述代码后,得到的结果如下:
从运行结果可以看出,随着基学习器数量的增加,采用子采样和学习速率调整的曲线在测试误差方面最终收敛到较低的区间。未采用任何正则化的提升树在约100个基学习器时仅产生轻微的过拟合现象。