前面对GBDT的算法原理进行了描述,通过前文了解到GBDT是以回归树为基分类器的集成学习模型,既可以做分类,也可以做回归,由于GBDT设计很多CART决策树相关内容,就暂不对其算法流程进行实现,本节就根据具体数据,直接利用Python自带的Sklearn工具包对GBDT进行实现。


  数据集采用之前决策树中的红酒数据集,之前的数据集我们做了类别的处理(将连续的数据删除了,且小批量数据进行了合并),这里做同样的处理,将其看为一个多分类问题。

  首先依旧是读取数据,并对数据进行检查和预处理,这里就不再赘述,所得数据情况如下:

wine_df = pd.read_csv('./winequality-red.csv', delimiter=';', encoding='utf-8')
columns_name = list(wine_df.columns)
for name in columns_name:
q1, q2, q3 = wine_df[name].quantile([0.25, 0.5, 0.75])
IQR = q3 - q1
lower_cap = q1 - 1.5 * IQR
upper_cap = q3 + 1.5 * IQR
wine_df[name] = wine_df[name].apply(lambda x: upper_cap if x > upper_cap else (lower_cap if (x < lower_cap) else x))


sns.countplot(wine_df['quality'])
wine_df.describe()

  接下来就是先导入使用GBDT所需要用到的工具包:

# 这里采用的是回归,因此是GradientBoostingRegressor,如果是分类则使用GradientBoostingClassifier
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import mean_squared_error
from sklearn import metrics
from sklearn.model_selection import train_test_split import matplotlib.pyplot as plt

  然后依旧是对数据进行切分,将数据分为训练集和测试集:

trainX, testX, trainY, testY = train_test_split(wine_df.drop(['quality']), wine_df['quality'], test_size=0.3, random_state=22)

  然后就是建立模型:

model = GradientBoostingClssifier()

  这里模型就有很多可选参数,用于调整模型,下面进行具体介绍:

  首先是Boosting的框架的参数,这里在使用GradientBoostingRegressor和GradientBoostingClassifier是一样的,具体包括:

  • n_estimators:弱分类器的最大迭代次数,也就是多少个弱分类器组成,默认值为100。当该值越小时容易欠拟合,太大又会过拟合;
  • learning_rate:学习率,这在前面原理部分有进行介绍,默认值为1,较小的learning_rate意味着步长较小,需要更多的分类器才能够达到效果,通常需要与上面n_eatimators结合共同调参;
  • subsample:这也是一种正则化的方法,在正则化中有提到过,取值为(0,1],默认值为1,即不进行子采样;
  • init:初始化的弱分类器,即f0(x),默认为采用训练样本初始化的分类回归预测,若赋予值需要根据一定的先验知识或者预拟合;
  • loss:即损失函数,在原理篇介绍过相关损失函数,对于分类和回归中损失函数是不相同的:
    • 在分类模型中,有对数似然损失函数“deviance”和指数损失函数“exponential”,默认为对数似然损失函数,一般选择默认,因为选择指数损失函数“exponential”又退回到AdaBoost了;
    • 在回归模型中,有方差损失“ls”、绝对损失“lad”、Huber损失“huber”和分位数损失“quantile”,默认为均方差损失“ls”,一般来说,数据的噪音不多,采用均方差损失即可,噪音点较多,则推荐使用抗噪能力较强的Huber损失,如果需要对训练集进行分段预测时则采用分位数损失“quantile”;
  • alpha:这个参数只存在于GradientBoostingRegressor中,当使用Huber损失和分位数损失时,需要指定分位数的值,默认为0.9,如果噪音数据较多,可以适当降低这个值。

  然后就是弱分类器有关的参数值,弱分类器采用的CART回归树,决策树中的相关参数在决策树实现部分已经进行介绍,这里主要对其中一些重要的参数再进行解释:

  • max_features:划分树时所用到的最大特征数,默认为None,即使用全部的特征,当取值为“log2”时,划分时使用log2N个特征,如果是“sqrt”和“auto”则分别对应着最多考虑√N¯个特征,如果是整数,则代表考虑特征的绝对数,如果是浮点数,则代表考虑总特征数的百分比。一般来说样本总特征数小于50,直接采用50即可,当样本特征数量较大时,再考虑其他特征数;
  • max_depth:每个弱分类器的最大深度,默认为不输入,树的深度为3,一般对于数据较少或者特征较少,该值不需要输入,当样本数量和特征数量过于庞大,推荐使用最大深度限制,一般选择10~100;
  • min_samples_split:内部节点再划分所需最小的样本数,它限制了子树进一步划分的条件,如果节点的样本数小于min_samples_split则不再进行分裂。默认值为2,若样本数量较大,则推荐增大该值;
  • min_samples_leaf:叶子节点最小样本数,该值限定了叶子节点的最小样本数,默认值为1,如果叶子节点样本数量小于该值,则会和兄弟节点一起被剪枝,如果样本量巨大,则推荐增加该值;
  • min_weight_fraction_leaf:叶子节点最小样本权重和,该值限制了叶子节点所有样本权重和的最小值,若小于该值,则会和兄弟节点被剪枝,默认值为0,即不考虑权重。当样本分类问题中类别分布偏差较大,则会引入样本权重,需要调整该值;
  • max_leaf_nodes:最大叶子节点数,通过限制最大叶子结点数防止过拟合,默认为None。如果加入了限制,则算法会建立在最大叶子节点数内最优的决策树,当样本特征数量过多的话,可以限制该值;
  • min_impurity_split:节点划分最小不纯度,这个值限定了决策树的生长,若节点的不纯度(即基尼系数)小于这个值,则该节点不再生长,即为叶子结点,默认值为1e-7,一般不推荐修改。

  上述即为模型的主要参数,这里首先全部使用默认值,对样本进行训练:

model.fit(trainX, trainY)
print("模型在训练集上分数为%s"%model.score(trainX, trainY))
pred_prob = model.predict_proba(trainX)
print('AUC:', metrics.roc_auc_score(np.array(trainY), pred_prob, multi_class='ovo'))

  模型在训练集上分数为0.8817106460418562
  AUC: 0.9757763363472337

  可以看到在训练集上AUC表现还不错,模型的分数但并不高,尝试调整训练参数,首先对于迭代次数和学习率共同进行调整:

param_test1 = {'n_estimators': range(10, 501, 10), 'learning_rate': np.linspace(0.1, 1, 10)}
gsearch = GridSearchCV(estimator=GradientBoostingClassifier(learning_rate=1,
min_samples_split=2,
min_samples_leaf=1,
max_depth=3,
max_features=None,
subsample=0.8,
), param_grid=param_test1, cv=5)
gsearch.fit(trainX, trainY) means = gsearch.cv_results_['mean_test_score']
params = gsearch.cv_results_['params']
for i in range(len(means)):
print(params[i], means[i]) print(gsearch.best_params_)
print(gsearch.best_score_) # {'learning_rate': 0.2, 'n_estimators': 100}

找出最好的n_estimators=100和learning_rate=0.2,将其定下来,带回模型,再次验证:

model = GradientBoostingClassifier(n_estimators=100, learning_rate=0.2,subsample=0.8)
model.fit(trainX, trainY)
print("模型在训练集上分数为%s"%model.score(trainX, trainY))
pred_prob = model.predict_proba(trainX)
print('AUC:', metrics.roc_auc_score(np.array(trainY), pred_prob, multi_class='ovo'))

  模型在训练集上分数为0.9663330300272975
  AUC: 0.9977791940084874

  可以看到拟合效果已经很好了,再次调整参数,接下来调整弱分类器中的参数,max_depth和min_samples_split:

param_test1 = {'max_depth': range(1, 6, 1), 'min_samples_split': range(1, 101, 10)}
gsearch2 = GridSearchCV(estimator=GradientBoostingClassifier(n_estimators=100,
learning_rate=0.2,
max_features=None,
min_samples_leaf=1,
subsample=0.8,
), param_grid=param_test1, cv=5)
gsearch2.fit(trainX, trainY)
means = gsearch2.cv_results_['mean_test_score']
params = gsearch2.cv_results_['params']
for i in range(len(means)):
print(params[i], means[i]) print(gsearch2.best_params_)
print(gsearch2.best_score_)

  找出了树的最大深度为5,由于最小样本划分数量同叶子节点最小样本数量有一定关系,暂时不能定下min_samples_split,将其同min_samples_leaf共同调整:

param_test1 = {'min_samples_leaf': range(1, 101, 10), 'min_samples_split': range(1, 101, 10)}
gsearch3 = GridSearchCV(estimator=GradientBoostingClassifier(n_estimators=100,
learning_rate=0.2,
max_features=None,
max_depth=5,
subsample=0.8,
), param_grid=param_test1, cv=5)
gsearch3.fit(trainX, trainY)
means = gsearch3.cv_results_['mean_test_score']
params = gsearch3.cv_results_['params']
for i in range(len(means)):
print(params[i], means[i]) print(gsearch3.best_params_)
print(gsearch3.best_score_) # {'min_samples_leaf': 21, 'min_samples_split': 41}

  可以找出最小样本划分数量21和叶子节点最小数量,我们将这些参数再带回模型:

model = GradientBoostingClassifier(n_estimators=100, learning_rate=0.2, max_depth=5, min_samples_leaf=21, min_samples_split=41, subsample=0.8)
model.fit(trainX, trainY)
print("模型在训练集上分数为%s"%model.score(trainX, trainY))
pred_prob = model.predict_proba(trainX)
print('AUC:', metrics.roc_auc_score(np.array(trainY), pred_prob, multi_class='ovo'))

  模型在训练集上分数为1.0
  AUC: 1.0

  可以看到在训练集上已经完美拟合了,但为了验证模型,我们需要再分离出一部分用于验证模型的数据集:

validX, tX, validY, tY = train_test_split(testX, testY, test_size=0.2)

  然后使用验证集,验证模型:

print("模型在测试集上分数为%s"%metrics.accuracy_score(validY, model.predict(validX)))
pred_prob = model.predict_proba(validX)
print('AUC test:', metrics.roc_auc_score(np.array(validY), pred_prob, multi_class='ovo'))
  

  模型在测试集上分数为0.726790450928382
  AUC test: 0.8413890948027345

  可以看到模型在验证集上表现并不是很好,上面模型存在一定的过拟合问题,继续调整参数,通过调整max_features来提高模型的泛华能力:

param_test1 = {'max_features': range(3, 12, 1)}
gsearch4 = GridSearchCV(estimator=GradientBoostingClassifier(n_estimators=100,
learning_rate=0.2,
min_samples_leaf=21,
min_samples_split=41,
max_depth=5,
subsample=0.8,
), param_grid=param_test1, cv=5)
gsearch4.fit(trainX, trainY)
means = gsearch4.cv_results_['mean_test_score']
params = gsearch4.cv_results_['params']
for i in range(len(means)):
print(params[i], means[i]) print(gsearch4.best_params_)
print(gsearch4.best_score_) # {'max_features': 5}

  进一步调整subsamples:

param_test1 = {'subsample': np.linspace(0.1, 1, 10)}
gsearch5 = GridSearchCV(estimator=GradientBoostingClassifier(n_estimators=100,
learning_rate=0.2,
min_samples_leaf=21,
min_samples_split=41,
max_depth=5,
max_features=5
), param_grid=param_test1, cv=5)
gsearch5.fit(trainX, trainY)
means = gsearch5.cv_results_['mean_test_score']
params = gsearch5.cv_results_['params']
for i in range(len(means)):
print(params[i], means[i]) print(gsearch5.best_params_)
print(gsearch5.best_score_) # {'subsample': 0.7}

  到这里基本主要参数都进行了调整,带回到模型中:

model = GradientBoostingClassifier(n_estimators=100, learning_rate=0.2, max_depth=5, min_samples_leaf=21, min_samples_split=41, max_features=5, subsample=0.7)
model.fit(trainX, trainY)
print("模型在训练集上分数为%s"%model.score(trainX, trainY))
pred_prob = model.predict_proba(trainX)
print('AUC:', metrics.roc_auc_score(np.array(trainY), pred_prob, multi_class='ovo'))

  模型在训练集上分数为0.9990900818926297
  AUC: 0.9999992641648271

  有略微下降,因为通过提高模型的泛华能力,会增大模型的偏差,然后利用验证集验证模型:

print("模型在测试集上分数为%s"%metrics.accuracy_score(validY, model.predict(validX)))
pred_prob = model.predict_proba(validX)
print('AUC test:', metrics.roc_auc_score(np.array(validY), pred_prob, multi_class='ovo')) 模型在测试集上分数为0.7161803713527851
AUC test: 0.8429467644071055

  进一步将模型的迭代次数增加一倍,学习率减半:

model = GradientBoostingClassifier(n_estimators=200, learning_rate=0.1, max_depth=5, min_samples_leaf=21, min_samples_split=41, max_features=5, subsample=0.7)
model.fit(trainX, trainY)
print("模型在训练集上分数为%s"%model.score(trainX, trainY))
pred_prob = model.predict_proba(trainX)
print('AUC:', metrics.roc_auc_score(np.array(trainY), pred_prob, multi_class='ovo'))
# validX, tX, validY, tY = train_test_split(testX, testY, test_size=0.2)
print("模型在测试集上分数为%s"%metrics.accuracy_score(validY, model.predict(validX)))
pred_prob = model.predict_proba(validX)
print('AUC test:', metrics.roc_auc_score(np.array(validY), pred_prob, multi_class='ovo'))

  模型在训练集上分数为0.9990900818926297
  AUC: 1.0

  模型在测试集上分数为0.7427055702917772
  AUC test: 0.851199242237048

  可以看到模型泛化能力有略微增强,可以尝试进一步上述步骤,当迭代次数增加到一定程度,学习率减小到一定程度,模型泛化能力下降,可能是由于步长过小导致拟合和泛化能力下降。

  以上就是GBDT的一个实例和参数调整过程,这里使用的是CvGrid网格遍历搜索调参的方法,从结果来看并不理想,可能是由于样本分布的问题,还有就是在进行数据处理的时候采用了replace直接更改了样本的标签,在测试集中这部分数据可能会预测错误。 后面会继续查找原因,调整数据集再次进行训练。


本例仅作为一个调参的学习过程,主要对GBDT中的参数有一个初步的了解,也是刚开始学习调参的方法,参数设置的也比较粗糙,后续会找一些新的数据集进一步对调参进行学习。

【Python机器学习实战】决策树与集成学习(五)——集成学习(3)GBDT应用实例的更多相关文章

  1. 【Python机器学习实战】决策树和集成学习(一)

    摘要:本部分对决策树几种算法的原理及算法过程进行简要介绍,然后编写程序实现决策树算法,再根据Python自带机器学习包实现决策树算法,最后从决策树引申至集成学习相关内容. 1.决策树 决策树作为一种常 ...

  2. 机器学习实战(Machine Learning in Action)学习笔记————03.决策树原理、源码解析及测试

    机器学习实战(Machine Learning in Action)学习笔记————03.决策树原理.源码解析及测试 关键字:决策树.python.源码解析.测试作者:米仓山下时间:2018-10-2 ...

  3. Python 机器学习实战 —— 监督学习(下)

    前言 近年来AI人工智能成为社会发展趋势,在IT行业引起一波热潮,有关机器学习.深度学习.神经网络等文章多不胜数.从智能家居.自动驾驶.无人机.智能机器人到人造卫星.安防军备,无论是国家级军事设备还是 ...

  4. Python 机器学习实战 —— 无监督学习(上)

    前言 在上篇<Python 机器学习实战 -- 监督学习>介绍了 支持向量机.k近邻.朴素贝叶斯分类 .决策树.决策树集成等多种模型,这篇文章将为大家介绍一下无监督学习的使用.无监督学习顾 ...

  5. Python 机器学习实战 —— 监督学习(上)

    前言 近年来AI人工智能成为社会发展趋势,在IT行业引起一波热潮,有关机器学习.深度学习.神经网络等文章多不胜数.从智能家居.自动驾驶.无人机.智能机器人到人造卫星.安防军备,无论是国家级军事设备还是 ...

  6. Python 机器学习实战 —— 无监督学习(下)

    前言 在上篇< Python 机器学习实战 -- 无监督学习(上)>介绍了数据集变换中最常见的 PCA 主成分分析.NMF 非负矩阵分解等无监督模型,举例说明使用使用非监督模型对多维度特征 ...

  7. python机器学习实战(一)

    python机器学习实战(一) 版权声明:本文为博主原创文章,转载请指明转载地址 www.cnblogs.com/fydeblog/p/7140974.html  前言 这篇notebook是关于机器 ...

  8. python机器学习实战(二)

    python机器学习实战(二) 版权声明:本文为博主原创文章,转载请指明转载地址 http://www.cnblogs.com/fydeblog/p/7159775.html 前言 这篇noteboo ...

  9. python机器学习实战(四)

    python机器学习实战(三) 版权声明:本文为博主原创文章,转载请指明转载地址 www.cnblogs.com/fydeblog/p/7364317.html 前言 这篇notebook是关于机器学 ...

  10. 机器学习实战(Machine Learning in Action)学习笔记————09.利用PCA简化数据

    机器学习实战(Machine Learning in Action)学习笔记————09.利用PCA简化数据 关键字:PCA.主成分分析.降维作者:米仓山下时间:2018-11-15机器学习实战(Ma ...

随机推荐

  1. 从零开始了解kubernetes

    kubernetes 已经成为容器编排领域的王者,它是基于容器的集群编排引擎,具备扩展集群.滚动升级回滚.弹性伸缩.自动治愈.服务发现等多种特性能力. 本文将带着大家快速了解 kubernetes , ...

  2. idea创建普通Web项目lib目录无法输出,tomcat不报错问题

    idea创建普通Web项目lib目录无法输出,tomcat不报错问题 idea版本:2021.2 tomcat版本:9.0.50 项目结构 创建一个普普通通的web项目,目录结构大概就是这样 . ├─ ...

  3. SQL语句(三)分组函数和分组查询

    目录 一.分组函数 特点 1. 各函数的简单使用 2. 搭配distinct的使用 3. COUNT 统计行数 4. 和分组函数一同查询的字段要求是group by后的字段 二.分组查询 1. 简单应 ...

  4. linux中的防火墙netfilter iptables

    目录 一.Linux防火墙基础 1.1 ptables的表.链结构 1.2 数据包控制的匹配流程 二.编写防火墙规则 1.iptables的安装 2.1 基本语法.控制类型 一般在生产环境中设置网络型 ...

  5. 从Python到Go:初学笔记

    本文记录了我在学习Go的过程时的一些笔记,主要是比较Python和Go之间的差异并作简单描述,以此使Python程序员对Go语言的特性有简略的了解.初学难免有纰漏,欢迎各位批评指正补充交流,谢谢. 数 ...

  6. JVM 内存分配、调优案例

    内存分配 对象优先在Eden区分配 大多数情况下,对象在新生代Eden区中分配.当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC. HotSpot虚拟机提供了-XX:+PrintG ...

  7. kong整合Cosul实践(3)

    1. 准备工作: 需要.netcore或者java程序一套,引入consul第三方包 我这里搭建了一个.netcore的webapi项目,引入Consul第三方包,网上可查资料一堆 环境需要kong, ...

  8. C#10在List, Queue 以及Stack中使用EnsureCapacity方法来提升性能

    简介 在今天的文章中,我们将介绍 C# 10 中引入的一项新功能.这是已添加到 List.Queue 和 Stack 集合中的 EnsureCapacity 方法.我们将讨论为什么我们应该使用这个方法 ...

  9. noip22

    T1 考试的时候打的特殊性质分,然而暴力竟然写假了. 正解: 显然是个贪心,要最大化 \(a_{\min}\times b_{\min}\),肯定是要删掉若干个 \(a\) 最小,\(b\) 最小的矩 ...

  10. [1.1W字] 复习: CSS 9个背景属性&6种渐变函数, 学会可以手写实现AI中强大的"任意渐变"! #Archives009

    Title/ CSS Background&Gradient完全指南 #Archives009 序: 关于 background 属性, 了解点CSS的人总会知道个大概. 但是你肯定多半还有点 ...