GBDT(Gradient Boosting Decision Tree)算法是一种强大的机器学习技术,广泛应用于分类、回归等任务。然而,为了充分发挥其性能,超参数的合理设置至关重要。超参数,如学习率、树的最大深度、子样本比例等,直接影响到模型的复杂度、训练速度和预测精度。因此,对GBDT算法的超参数进行细致的评估和调整,是确保模型性能达到最优的关键步骤。
弱评估器数量:参数n_estimators
n_estimators指的是集成算法中弱评估器的数量。对于Boosting算法来说,可以使用任意弱评估器,当然了默认的弱评估器还是决策树。GBDT算法无论是分类器还是回归器,默认弱评估器都是回归树。
X_c,y_c = load_wine(return_X_y=True,as_frame=True) #分类数据 X_r,y_r = fetch_california_housing(return_X_y=True,as_frame=True) #回归数据 clf = GBC(n_estimators=2).fit(X_c,y_c) reg = GBR(n_estimators=2).fit(X_r,y_r) clf.n_estimators_ 2 reg.n_estimators_ 2 clf.estimators_ array([[DecisionTreeRegressor(criterion='friedman_mse', max_depth=3, random_state=RandomState(MT19937) at 0x1083D8340), DecisionTreeRegressor(criterion='friedman_mse', max_depth=3, random_state=RandomState(MT19937) at 0x1083D8340), DecisionTreeRegressor(criterion='friedman_mse', max_depth=3, random_state=RandomState(MT19937) at 0x1083D8340)], [DecisionTreeRegressor(criterion='friedman_mse', max_depth=3, random_state=RandomState(MT19937) at 0x1083D8340), DecisionTreeRegressor(criterion='friedman_mse', max_depth=3, random_state=RandomState(MT19937) at 0x1083D8340), DecisionTreeRegressor(criterion='friedman_mse', max_depth=3, random_state=RandomState(MT19937) at 0x1083D8340)]], dtype=object) reg.estimators_ array([[DecisionTreeRegressor(criterion='friedman_mse', max_depth=3, random_state=RandomState(MT19937) at 0x1083D8340)], [DecisionTreeRegressor(criterion='friedman_mse', max_depth=3, random_state=RandomState(MT19937) at 0x1083D8340)]], dtype=object)
- 对于 GradientBoostingRegressor,因为处理的是回归问题,每个迭代步骤只构建一个回归树来预测连续的目标变量。所以,在回归器的 estimators_ 中有两个 DecisionTreeRegressor 实例,与指定的 n_estimators=2 相匹配。
- 对于 GradientBoostingClassifier,如果数据是多类别的(比如 wine 数据集可能有多个类别),则在每个提升迭代中,算法会为每个类别构建一个回归树来预测该类别的概率。因此,如果数据集有三个类别,每个迭代步骤将会构建三个树,每个树预测一个类别的概率。
- 如果是二分类则不会出现这种现象
出现这种情况的根本原因在于:GBDT的弱评估器为回归树,在实际调用GBDT来完成分类任务时,需要softmax函数或者sigmoid函数对回归树输出的结果进行处理。对于二分类来说,就是直接调用sigmoid函数,输出的概率值大于0.5就被预测为类别1 ,反之预测为类别0。
对于多分类来说,就比较复杂了。在多分类任务中,我们必须求解出所有标签类别所对应的概率,在所有这些概率当中,最大的概率所对应的标签才是多分类的预测标签。此时,我们需要softmax函数(归一化指数函数)帮助我们将回归值转化为概率。而**softmax函数是接受K个连续型结果,并输出K个相对概率的函数。所以在使用softmax之前我们需要准备每个类别的概率值,因此就需要建立同等数量的弱评估器。
不难发现,使用GBDT完成多分类任务时,计算量以及弱评估器数量都会远远超出二分类以及回归类问题。
参数n_estimators对模型效果的影响:
X,y = load_breast_cancer(return_X_y=True,as_frame=True) Xtrain,Xtest,Ytrain,Ytest = train_test_split(X,y,test_size=0.3,random_state=0) scores = [] for i in np.arange(1,300,10): gbc = GBC(n_estimators=i) s = cross_val_score(gbc,X,y,cv=5).mean() scores.append(s) print(f"当n_estimators={np.arange(1,300,10)[scores.index(max(scores))]}时,准确率取得最大值{max(scores)}") plt.plot(np.arange(1,300,10),scores,label = "GBDT") plt.show()
scores = [] for i in np.arange(1,50): gbc = GBC(n_estimators=i) s = cross_val_score(gbc,X,y,cv=5).mean() scores.append(s) print(f"当n_estimators={np.arange(1,50)[scores.index(max(scores))]}时,准确率取得最大值{max(scores)}") plt.plot(np.arange(1,50),scores,label = "GBDT") plt.show()
可以看出,随着参数n_estimators的增大,模型的效果是逐渐变好的。但是,n_estimators达到一定的程度之后,GBDT的精确性往往不在上升或开始波动,并且,n_estimators越大,需要的计算量和内存也越大,训练的时间也会越来越长。所以对于这个参数,我们是渴望在模型训练难度和模型效果之间取得平衡。
学习率:参数`learning_rate`
在Boosting集成算法中,集成算法最终的输出结果往往是多个弱评估器输出结果的加权平均结果。但是这个最终结果并不是在所有的弱评估器建好之后才统一加权求解的,而是在逐渐建立弱评估器的过程中就随着迭代不断计算出来的。
例如,对于样本x_i,集成算法当中一共有T棵树(也就是参数`n_estimators`的取值),现在正在建立第t个弱评估器,则第t个弱评估器上x_i的结果可以表示为f_t(x_i)。假设整个Boosting算法对样本x_i输出的结果为H(x_i),则该结果一般可以被表示为t=1~t=T过程当中,所有弱评估器结果的加权求和:
- 以上式子为boosting算法中计算方式的一般规则,并不是具体到某一个Boosting集成算法的具体公式。
plt.figure(figsize=(10,6)) for i in [3,10,50,100,200]: scores = [] for j in np.arange(0.001,0.5,0.01): gbc = GBC(n_estimators=i,learning_rate=j,random_state=0) s = cross_val_score(gbc,X,y,cv=5).mean() scores.append(s) plt.plot(np.arange(0.001,0.5,0.01),scores,label = f"n_estimators={i}") plt.legend()
初始预测结果的设置:参数init
- 传入实例的参数
from sklearn.metrics import mean_squared_error as MSE X,y = fetch_california_housing(return_X_y=True,as_frame=True) Xtrain,Xtest,Ytrain,Ytest = train_test_split(X,y,test_size=0.3,random_state=0) for init in [DTR(),RFR(),"zero",None]: reg = GBR(init = init,random_state=0) reg = reg.fit(Xtrain,Ytrain) MSE_train = MSE(Ytrain,reg.predict(Xtrain)) MSE_test = MSE(Ytest,reg.predict(Xtest)) print(f"{init}:") print(f"训练集MSE:{MSE_train}") print(f"测试集MSE:{MSE_test}") print("\n") zero: 训练集MSE:0.25572269323849983 测试集MSE:0.289857007749968 None: 训练集MSE:0.25572269022058913 测试集MSE:0.2897994977087412
- 不难发现,初始参数的具体输入会对模型的最终结果造成巨大影响,在init中输入训练好的模型会加重GBDT的过拟合,但同时也可能得到更好的测试集结果。
GBDT的6种损失函数:参数loss
GBDT算法的损失函数非常多,我们在调参的时候可以把损失函数作为需要调整的参数进行考量。在sklearn中,控制具体损失函数的参数为:loss。GBDT中的损失函数因GBDT具体执行的预测任务而存在区别,同时也因标签的分布而存在区别。
老版本
对于梯度提升分类树来说,loss的备选项有2种:{"deviance", "exponential"},默认值为"deviance"。
- "deviance":直译为偏差,特指逻辑回归的损失函数——**交叉熵损失**;
- "exponential":表示的是 指数损失函数。需要注意的是:此损失函数只能支持二分类数据**。
新版本
deviance ->log_loss
对于梯度提升回归树来说,loss的备选项有如下几种:
- “squared_error”:指回归的平方误差;
- “absolute_error”:指回归的绝对误差;
- “huber”:平方误差和绝对误差的结合(使用alpha进行调节);
- “quantile”:表示允许分位数回归(使用alpha 指定分位数)
其中的alpha
是需要我们自己设置的超参数,由参数alpha
控制。在huber损失中,alpha是阈值,在quantile损失中,alpha用于辅助计算损失函数的输出结果,默认为0.9。
=========更新警告=========
在sklearn1.0版本及后续版本当中,损失函数"ls"与"lad"被删除了,其中"ls"的功能被"squared_error"取代,而"lad"被"absolute_error"取代。如果你在运行代码时,发现你的参数默认值、参数名称与课件中不相同,或者在运行过程中出现报错、警告等现象,你可能需要更新你的sklearn。
=========================
GBDT是工业应用最广泛的模型,工业数据大部分都极度偏态、具有长尾,因此GBDT必须考虑离群值带来的影响。数据中的离群值会极大程度地影响模型地构建,当离群值在标签当中、而我们是依赖于减小损失函数来逐渐构建算法时,这种影响会前所未有地大。因此Boosting是天生更容易被离群值影响的模型、也更擅长学习离群值的模型。
举例来说,若离群值的标签为1000,大部分正常样本的标签在0.1~0.2之间,算法一定会异常努力地学习离群值的规律,因为将离群值预测错误会带来巨大的损失。在这种状况下,最终迭代出的算法可能是严重偏离大部分数据的规律的。同样,我们也会遇见很多离群值对我们很关键的业务场景:例如,电商中的金额离群用户可能是VIP用户,风控中信用分离群的用户可能是高风险用户,这种状况下我们反而更关注将离群值预测正确。不同的损失函数可以帮助我们解决不同的问题——
- 当高度关注离群值、并且希望努力将离群值预测正确时,选择平方误差squared_error
- 这在工业中是大部分的情况。在实际进行预测时,离群值往往比较难以预测,因此离群样本的预测值和真实值之间的差异一般会较大。MSE作为预测值和真实值差值的平方,会放大离群值的影响,会让算法更加向学习离群值的方向进化,这可以帮助算法更好地预测离群值。
- 努力排除离群值的影响、更关注非离群值的时候,选择绝对误差absolute_error
- MAE对一切样本都一视同仁,对所有的差异都只求绝对值,因此会保留样本差异最原始的状态。相比其MSE,MAE对离群值完全不敏感,这可以有效地降低GBDT在离群值上的注意力。
- 试图平衡离群值与非离群值、没有偏好时,选择huber或者quantile
- Huberloss损失结合了MSE与MAE,在Huber的公式中,当预测值与真实值的差异大于阈值时,则取绝对值,小于阈值时,则取平方。在真实数据中,部分离群值的差异会大于阈值,部分离群值的差异会小于阈值,因此比起全部取绝对值的MAE,Huberloss会将部分离群值的真实预测差异求平方,相当于放大了离群值的影响(但这种影响又不像在MSE那样大)。因此HuberLoss是位于MSE和MAE之间的、对离群值相对不敏感的损失。
GBDT算法超参数评估(二)+https://developer.aliyun.com/article/1544809?spm=a2c6h.13148508.setting.21.22454f0e4mZEBN