「周末AI课堂」Boosting集成(代码篇)机器学习你会遇到的“坑”

「周末AI课堂」Boosting集成(代码篇)机器学习你会遇到的“坑”

在《bagging集成和stacking集成》中,我们曾经发现了无论是随机森林还是Extremely Randomized Trees,随着基学习器的增加,泛化误差都会趋于稳定。

「周末AI课堂」Boosting集成(代码篇)机器学习你会遇到的“坑”

图为随机森林的结果

「周末AI课堂」Boosting集成(代码篇)机器学习你会遇到的“坑”

图为Extremely Randomized Trees的结果

同时,我们也简单证明了boosting集成就不会遇到这样的问题,因为每一个基学习器都要针对上一轮学习器的结果进行优化,Adaboost的分类版本会更关注分类错误的样本,Gradient Boosting的回归版本会去继续优化Loss的负梯度。首先我们使用Adaboost适应IRIS数据,以决策树作为基学习器,我们在上一节的代码篇中得到了决策树的叶节点的最小样本为3,所以我们基学习器的minsamplesleaf也设置为3,进一步观察基学习器数量对泛化误差的影响:

import numpy as np

import matplotlib.pyplot as plt

import seaborn as sns

from sklearn import datasets

fromsklearn.model_selection import cross_validate

from sklearn.ensemble import AdaBoostClassifier as ABC

from sklearn.tree import DecisionTreeClassifieras DTC

iris = datasets.load_iris()

X = iris.data

y = iris.target

dtc=DTC(min_samples_leaf=3)

test_mse=[]

train_mse=[]

numbers=range(1,50)

for d in numbers:

clf=ABC(base_estimator=dtc,n_estimators=d)

clf_dict=cross_validate(clf,X,y,cv=10,scoring='accuracy',algorithm='SAMME')

test_mse.append(clf_dict['test_score'].mean())

train_mse.append(clf_dict['train_score'].mean())

sns.set(style='darkgrid')

plt.plot(numbers,train_mse,'b-.',label='Train Accuracy')

plt.plot(numbers,test_mse,'r-.',label='Test Accuracy')

plt.xlabel(' n estimators')

plt.ylabel('Accuracy')

plt.title('DecisionTree forAdaboost')

plt.legend()

plt.show()

「周末AI课堂」Boosting集成(代码篇)机器学习你会遇到的“坑”

如图,我们可以看到在一开始的时候测试准确率就非常高,添加了基学习器之后,测试准确率并没有增加。

回顾Adaboost的整个过程,一开始,我们使用学习器应用在全部数据上,训练完成后,我们利用错误率更新学习器的权重,并利用对应的损失更新样本的权重,如果一开始的时候,我们就利用一个强学习器,那么错误率本身就很低,继续添加学习器,测试准确率就不会变化。所以为了Adaboost显示出威力,我们在一开始的更合适的做法是,构建弱学习器。

我们的方法是限制决策树的最大深度为1,因为当决策树的深度为1的时候,只对属性进行了一次划分,一般而言效果都是差的。

....

dtc=DTC(max_depth=1)

....

「周末AI课堂」Boosting集成(代码篇)机器学习你会遇到的“坑”

从图中可以看出,随着基学习器数量的增加,测试准确率先急速上升,然后稳定。

我们还可以观察基学习器数量的增加,决策边界的变化:

import numpy as np

import matplotlib.pyplot as plt

from sklearn import datasets

from sklearn.ensemble import AdaBoostClassifier as ABC

from sklearn.tree import DecisionTreeClassifieras DTC

import seaborn as sns

iris = datasets.load_iris()

X = iris.data[:, :2]

y = iris.target

def make_meshgrid(x, y, h=.02):

x_min, x_max = x.min() -1, x.max() +1

y_min, y_max = y.min() -1, y.max() +1

xx, yy =np.meshgrid(np.arange(x_min, x_max, h),

np.arange(y_min,y_max, h))

return(xx, yy)

xx,yy=make_meshgrid(X[:,0],X[:,1])

dtc=DTC(max_depth=1)

numbers=[1,5,10,50]

sns.set(style='darkgrid')

for k,j in enumerate(numbers):

clf =ABC(base_estimator=dtc,n_estimators=j)

clf.fit(X,y)

Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])

Z = Z.reshape(xx.shape)

plt.subplot(len(numbers)/2,len(numbers)/2,k+1)

plt.contourf(xx,yy,Z,cmap=plt.cm.RdBu,alpha=0.6)

for i,v,l in [[0,'r','setosa'],[1,'g','vericolor'],[2,'b','virginica']]:

plt.scatter(X[y==i][:,0],X[y==i][:,1],c=v,label=l,edgecolor='k')

plt.title('$n=$%s'%j)

plt.legend()

plt.show()

「周末AI课堂」Boosting集成(代码篇)机器学习你会遇到的“坑”

从图中可以看出,当基学习器为1的时候,决策边界非常简单,因为只进行了一次划分,与理论相符。随着基学习器数量的增加,决策边界变得越来越复杂,直到基学习器数量为50的时候,甚至为左边的蓝点单独创立了规则。

此时,我们出现了一个矛盾的结果,根据决策边界,基学习器数量的增加会导致一定程度的过拟合,但根据测试集的表现,又未出现过拟合。那么,一个严肃的问题摆在我们面前,对于Adaboost,基学习器数量的增加是否会导致过拟合呢?甚至人们在有些情况下还会发现,训练误差为零的情况下,测试性能仍然能进一步提升。

一般认为,在bagging中,泛化误差的减小主要来源于方差的降低;在boosting中,泛化误差的减小主要来源于偏差的降低。前者更容易出现欠拟合,后者则更容易出现过拟合。根据我们原本的理论,基学习器数量的增加会增大模型的复杂度,势必会在某个节点出现过拟合,泛化误差下降,但从另一方面来说,Adaboost的对模型的加权平均,不能纠正错误的模型权重系数也会很小,对结果似乎也不会产生大的影响。

这个问题目前并没有得到彻底的解决,目前比较有说服力的是间隔理论(Margin theroy),所谓的Margin可以简单的理解为决策边界离样本的远近,因为虽然决策边界内包含了很多点,但离决策边界的远近程度却不一样,离得远的样本点不容易随着决策边界的变化而变化,而处在决策边界边缘的样本点却对变化非常敏感,所以即使训练误差为零,但泛化误差还有上升的空间,因为此时的优化过程是在扩大决策边界与样本的最小间隔,而利用传统的分析方法是无法看到这样的过程。从数学上来说,就是改变了泛化误差的上界。

按照这个理论,Adaboost训练集上的稳定,实际上却是在不断对决策边界进行调整,而Adaboost每次仅更新一个参数,也会让学习过程变得非常缓慢。

关于Gradient Boosting的实现较为简单,当我们使用决策树作为基学习器时,自然可以通过剪枝来限制每棵树的过拟合程度,我们前面的做法已经证明了在boosting中对单棵树做限制很可能是无效的,所以必须清楚两种正则化的手段:

  • 将普通的加性模型:

「周末AI课堂」Boosting集成(代码篇)机器学习你会遇到的“坑”

再次添加learning rate:

「周末AI课堂」Boosting集成(代码篇)机器学习你会遇到的“坑”

这样一种参数化的办法实际上是把调节了每棵树的影响,使得后面具有更大的学习空间。

  • subsampling:

借用了bagging中的Bootstrap做法,与bootstrap不同的是,它是不放回的采样。需要注意的是,每次迭代的时候,我们都会进行全新的不放回采样。这将有助于减小方差,降低过拟合的风险。

这两种正则化方式也被叫做shrinkage。我们试着对数据做梯度提升,并设置learning rate和subsampling,来观察对泛化性能的影响:

import numpy as np

import matplotlib.pyplot as plt

import seaborn as sns

from sklearn import ensemble

from sklearn import datasets

fromsklearn.model_selection import train_test_split

X, y =datasets.make_hastie_10_2(n_samples=12000, random_state=1)

X = X.astype(np.float32)

labels, y = np.unique(y,return_inverse=True)

X_train, X_test,y_train, y_test = train_test_split(

X, y, test_size=0.8,shuffle=False)

original_params = {'n_estimators': 1000, 'max_leaf_nodes': 4, 'max_depth': None,'random_state': 2,

'min_samples_split': 5}

sns.set(style='darkgrid')

for label, color, setting in [('No shrinkage', 'orange',

{'learning_rate': 1.0, 'subsample': 1.0}),

('learning_rate=0.1', 'turquoise',

{'learning_rate': 0.1, 'subsample': 1.0}),

('subsample=0.5', 'blue',

{'learning_rate': 1.0, 'subsample': 0.5}),

('learning_rate=0.1,subsample=0.5', 'gray',

{'learning_rate': 0.1, 'subsample': 0.5})]:

params =dict(original_params)

params.update(setting)

clf = ensemble.GradientBoostingClassifier(**params)

clf.fit(X_train, 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('Boosting Iterations')

plt.ylabel('Test Set Deviance')

plt.show()

「周末AI课堂」Boosting集成(代码篇)机器学习你会遇到的“坑”

如图,随着基学习器的增加,添加了subsampling和learning rate的曲线测试误差最终收敛到了一个很低的区间,没有添加任何正则化手段的提升树,在基学习器大约为200的时候就产生了微弱的过拟合。

「周末AI课堂」Boosting集成(代码篇)机器学习你会遇到的“坑”

读芯君开扒

课堂TIPS

• Adaboost为什么不会产生过拟合,仍然是一个具有挑战性的问题。而最近的研究也在表明,Adaboost不仅是降低了偏差,也降低了方差,因为在每一轮学习的过程中,每次进入学习器的样本的分布发生了变化,类似于bagging的采样过程,也是一种数据扰动。

• 在Adaboost中,我们也可以添加learning rate,只是在sklearn的Adaboost类中,learning rate默认为1,就相当于没有添加,我们在实际使用过程中可以自行更改。

• 我们在上一章节所讲授的Adaboost用于分类,gradient boosting用于回归,实际上,两者经过推广后都可以用于分类和回归任务。

「周末AI课堂」Boosting集成(代码篇)机器学习你会遇到的“坑”

作者:唐僧不用海飞丝

如需转载,请后台留言,遵守转载规范

相关推荐