决策树集成-梯度提升决策树

基础概念

集成

集成是合并多个机器学习模型来构建更强大模型的方法。在机器学习算法中有许多模型属于这一类,但已证明有两种集成模型对大量分类和回归的数据集都是有效的,二者都以决策树为基础,分别是随机森林(random forest)梯度提升决策树(gradiet boosted decision tree)

之前已经讲解过了随机森林(决策树集成-随机森林之分类实操),这次讲解梯度提升决策树。在了解梯度提升决策树之前,建议先去看一下我的另外两篇讲解决策树的文章决策树算法之讲解实操(上)决策树算法之讲解实操(下),重复的东西,我这里就不在赘述了。

思想简介

在之前的一篇文章决策树算法之讲解实操(上)中我们提到过,决策树的一个主要缺点在于经常对训练数据过拟合。那么除了随机森林之外,梯度提升回归树就是解决这个问题的另一种方法。

梯度提升回归树是通过合并多个决策树来构建一个更为强大的模型。虽然名字中含有”回归”,但是这个模型既可以用于回归也可以用于分类。与随机森林的方法不同,梯度提升采用连续的方式构造树,每颗树都试图纠正前一棵树的错误.默认情况下,梯度提升回归树中没有随机化,而是用到了强预剪枝。梯度提升树通常使用深度很小(1到5之间)的树,这样模型占用的内存更少,预测速度也更快.

梯度提升树背后的主要思想是合并许多简单的模型(在这个语境中叫做弱学习器),比如深度较小的树.每棵树只能对部分数据作出好的预测,因此,添加的树越来越多,可以不断迭代,提高性能.

梯度提升树经常是机器学习竞赛的优胜者,并广泛应用于业界.与随机森林相比,它通常对参数的设置更为敏感,但如果参数设置正确的话,模型精度会更高.

实操建模

数据是一份红酒质量分类的数据集,通过各个维度来判断红酒质量,之前在决策树算法之讲解实操(上)中已经讲解使用过了,这里就不多在赘述了,我们直接建模,代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import pandas as pd
import numpy as np
import winreg
from sklearn.model_selection import train_test_split
from sklearn.ensemble import GradientBoostingClassifier#梯度提升回归树
from sklearn.metrics import accuracy_score
###################
real_address = winreg.OpenKey(winreg.HKEY_CURRENT_USER,r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders',)
file_address=winreg.QueryValueEx(real_address, "Desktop")[0]
file_address+='\\'
file_origin=file_address+"\\源数据-分析\\winequality-red.csv"###https://www.kaggle.com/uciml/red-wine-quality-cortez-et-al-2009
red_wine=pd.read_csv(file_origin)
#设立桌面绝对路径,读取源数据文件,这样将数据直接下载到桌面上就可以了,省得还要去找
###################
train=red_wine.drop(["quality"],axis=1)
X_train,X_test,y_train,y_test=train_test_split(train,red_wine["quality"],random_state=1)
###考虑到接下来可能需要进行其他的操作,所以定了一个随机种子,保证接下来的train和test是同一组数
gbcf=GradientBoostingClassifier(random_state=1)
gbcf.fit(X_train,y_train)
print("梯度提升回归树训练模型评分:"+str(accuracy_score(y_train,gbcf.predict(X_train))))
print("梯度提升回归树待测模型评分:"+str(accuracy_score(y_test,gbcf.predict(X_test))))

结果如下所示:

在这里插入图片描述

下面是之前的文章中单棵决策树建立的模型结果:

在这里插入图片描述

二者相比可以看出,梯度提升树的模型精度要比单棵树的要好一点,过拟合现象也比之前要减轻很多。
接下来我们了解一下梯度提升树的主要模型参数。

模型参数

在梯度提升回归树中,我们主要会用到三个模型参数n_estimators(树的个数),max_depth(树的深度),learning_rate(学习率),至于其它的参数,一般情况下直接默认就好。

max_depth:用于降低每棵树的复杂度.一般来说,梯度提升模型的max_depth通常设置得很小,一般不超过5.
接下来我们来调节这个参数,提高模型精度,代码及结果如下所示:

1
2
3
4
5
6
result_1=pd.DataFrame(columns=["决策树深度(max_depth)","梯度提升回归树待测模型评分"])
for i in range(1,5):
gbcf=GradientBoostingClassifier(max_depth=i,random_state=1)
gbcf.fit(X_train,y_train)
result_1=result_1.append([{"决策树深度(max_depth)":i,"梯度提升回归树待测模型评分":accuracy_score(y_test,gbcf.predict(X_test))}])
result_1[result_1["梯度提升回归树待测模型评分"]==result_1["梯度提升回归树待测模型评分"].max()]

在这里插入图片描述

可以看到当我们设定参数max_depth为4的时候,模型精度可以达到66.5%左右,较之前的结果提高了一些。

梯度提升树模型的另外两个主要参数包括树的数量n_estimators学习率learn_rate,后者用于控制每棵树对前一棵树的错误纠正程度.这两个参数高度相关,因为learning_rate越低,就需要更多的树来构建具有相似复杂度的模型.随机森林的n_estimators值总是越大越好,但是梯度提升不同,增大n_estimators会导致模型更加复杂,进而可能导致过拟合.通常的做法是根据时间和内存的预算选择合适的n_estimators,然后对不同的learning_rate进行遍历.

这两个参数的调节代码及结果如下所示:

1
2
3
4
5
6
result_2=pd.DataFrame(columns=["集成树的个数(n_estimators)","梯度提升回归树待测模型评分"])
for i in range(1,500,10):
gbcf=GradientBoostingClassifier(max_depth=4,n_estimators=i,random_state=1)
gbcf.fit(X_train,y_train)
result_2=result_2.append([{"集成树的个数(n_estimators)":i,"梯度提升回归树待测模型评分":accuracy_score(y_test,gbcf.predict(X_test))}])
result_2[result_2["梯度提升回归树待测模型评分"]==result_2["梯度提升回归树待测模型评分"].max()]

在这里插入图片描述

n_estimators的调节结果如上图所示,那么接下来我们在上面的参数基础上继续调节学习率:

1
2
3
4
5
6
7
result_3=pd.DataFrame(columns=["学习率(learning_rate)","梯度提升回归树待测模型评分"])
for i in range(1,10):
m=i/10
gbcf=GradientBoostingClassifier(max_depth=4,n_estimators=161,learning_rate=m,random_state=1)
gbcf.fit(X_train,y_train)
result_3=result_3.append([{"学习率(learning_rate)":m,"梯度提升回归树待测模型评分":accuracy_score(y_test,gbcf.predict(X_test))}])
result_3[result_3["梯度提升回归树待测模型评分"]==result_3["梯度提升回归树待测模型评分"].max()]

在这里插入图片描述

接下来,我们还可以对学习率的参数调节进行进一步的区间划分,代码及结果如下所示:

1
2
3
4
5
6
7
result_4=pd.DataFrame(columns=["学习率(learning_rate)","梯度提升回归树待测模型评分"])
for i in range(1,20):
m=i/100
gbcf=GradientBoostingClassifier(max_depth=4,n_estimators=161,learning_rate=m,random_state=1)
gbcf.fit(X_train,y_train)
result_4=result_4.append([{"学习率(learning_rate)":m,"梯度提升回归树待测模型评分":accuracy_score(y_test,gbcf.predict(X_test))}])
result_4[result_4["梯度提升回归树待测模型评分"]==result_4["梯度提升回归树待测模型评分"].max()]

在这里插入图片描述

至此,这个模型的参数就调节完毕了.
(ps:为了提高模型精度,参数是可以进行更近一步的调节,不过剩下的就需要朋友们自行探索了)

分析特征重要性

与随机森林类似,梯度提升树也可以给出特征重要性,代码及结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from sklearn.ensemble import RandomForestClassifier
import seaborn as sns
import matplotlib.pyplot as plt
plt.style.use("fivethirtyeight")
sns.set_style({'font.sans-serif':['SimHei','Arial']})
%matplotlib inline
gbcf=GradientBoostingClassifier(max_depth=4,random_state=1)###梯度提升回归树
forest=RandomForestClassifier(max_depth=4,random_state=1)###随机森林分类器
gbcf_prediction=gbcf.fit(X_train,y_train)
forest_prediction=forest.fit(X_train,y_train)
fig= plt.subplots(figsize=(20,15))
fig1 = plt.subplot(211)
plt.title('梯度提升回归树特征重要性',fontsize=20)
plt.bar(train.columns,gbcf_prediction.feature_importances_,0.4,color="blue")
plt.legend()
fig2=plt.subplot(212)
plt.title('随机森林特征重要性',fontsize=20)
plt.bar(train.columns,forest_prediction.feature_importances_,0.4,color="green")
plt.legend()
plt.xticks(fontsize=13)

在这里插入图片描述

如上图所示,在保证树的深度参数(max_depth)相同的情况下,梯度提升树的特征重要性与随机森林的特征重要性有些相似,实际上在某些数据集中,梯度提升树可能会完全忽略某些特征.

优缺点

梯度提升决策树是监督学习中最强大也是最常用的模型之一.其主要缺点是需要仔细调参,而且训练的时间可能会比较长.与其他基于树的模型类似,这一算法不需要对数据进行缩放就可以表现得很好,而且也适用于二元特征与连续特征同时存在的数据集.但它也通常不适用于高维稀疏数据.

由于梯度提升和随机森林两种方法在类似的数据上表现的都很好,因此一种常用的方法就是先尝试随机森林,它的鲁棒性很好.如果随机森林效果很好,但预测时间太长,或者机器学习模型精度小数点后第二位的提高也很重要,那么切换成梯度提升通常会有用.

有很多地方做的不是很好,欢迎网友来提出建议,也希望可以遇到些朋友来一起交流讨论。