和上一期讲的AdaBoost一样,Gradient Boosting 也是通过按顺序添加predictors 到集成中来工作。但是,并不像AdaBoost那样,在每次iteration的时候调整样本的权重,Gradient Boosting这个方法是使用新的predictor去拟合旧的predictor产生的的残差。也就是说在残差的基础上进行拟合,拟合完成后剩下的残差又可以用新的predictor来拟合,步骤如下:
第一步:使用DecisionTreeRegressor 来拟合训练集;
第二步:对于第一个predictor产生的残差用第二个DecisionTreeRegressor 来训练;
第三步:在第二个predictor产生的残差上面训练第三个regressor;
…
最后一步:们就会有一个包含n棵树的集合,它通过把所有的树的预测结果相加,从而对新的样本进行预测。
使用代码一步步实现上面的步骤
from sklearn.datasets import make_moons
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
产生一些数据样本点:
np.random.seed(42)
X=np.random.rand(100,1)-0.5
y=3*X[:,0]**2+0.05*np.random.randn(100)
数据点大致长下面这样子:
plt.scatter(X,y,c=y)
使用单棵最大深度为2的决策树:
from sklearn.tree import DecisionTreeRegressor
tree_reg1=DecisionTreeRegressor(max_depth=2)
y1=tree_reg1.fit(X,y).predict(X)
resid1=y-y1
resid1_pred=DecisionTreeRegressor(max_depth=2).fit(X,resid1).predict(X)
df1=pd.DataFrame({
"X":X[:,0],"y":y1+resid1_pred})
df1=df1.sort_values(by=['X'])
df2=pd.DataFrame({
"X":X[:,0],"y":resid1_pred})
df2=df2.sort_values(by=['X'])
fig,[ax1,ax2]=plt.subplots(1,2,figsize=(12,6))
ax1.plot(df1.X,df1.y,label='h(x)=h0(x)+h1(x)')
ax1.scatter(X,y,c=y,label='Training set')
ax1.legend()
#ax1.title('h(x)=h0(x)+h1(x)')
ax2.scatter(X,resid1,label='residual1')
ax2.plot(df2.X,df2.y,label='h1(x)')
ax2.legend()
#ax2.title('h1(x)')
使用决策树,设置max_depth=2,然后拟合预测得到单棵决策树的预测值y1,并且使用y-y1得到resid1,得到单棵决策树拟合一次后的残差,然后使用剩下的残差再进行拟合,拟合得到的结果用resid1_pred来表示,做出如图所示的结果。
下图中左图散点为原始的数据集,线段为为一棵决策树拟合的结果,右图散点为拟合一次残差的结果,线段为残差用单棵决策树拟合的结果。
然后我们再用最原始的y减去第一次预测得到的y1,再减去第一次残差拟合得到的预测值resid1_pred得到第二个残差resid2,然后再用第二个残差训练单棵决策树再进行预测,得到第二个残差的预测值resid2_pred。
resid2=y-y1-resid1_pred
resid2_pred=DecisionTreeRegressor(max_depth=2).fit(X,resid2).predict(X)
df1=pd.DataFrame({
"X":X[:,0],"y":y1+resid1_pred+resid2_pred})
df1=df1.sort_values(by=['X'])
df2=pd.DataFrame({
"X":X[:,0],"y":resid2_pred})
df2=df2.sort_values(by=['X'])
fig,[ax1,ax2]=plt.subplots(1,2,figsize=(12,6))
ax1.plot(df1.X,df1.y,label='h(x)=h0(x)+h1(x)+h2(x)')
ax1.scatter(X,y,c=y,label='Training set')
ax1.legend()
ax2