梯度提升树的基本思想

目录

1. 梯度提升树 VS AdaBoost

2. GradientBoosting回归与分类的实现

2.1 GradientBoosting回归

2.2 GradientBoosting分类


1. 梯度提升树 VS AdaBoost

        梯度提升树(Gradient Boosting Decision Tree,GBDT)是提升法中的代表性算法,它即是当代强力的XGBoost、LGBM等算法的基石,也是工业界应用最多、在实际场景中表现最稳定的机器学习算法之一。在最初被提出来时,GBDT被写作梯度提升机器(Gradient Boosting Machine,GBM),它融合了Bagging与Boosting的思想、扬长避短,可以接受各类弱评估器作为输入,在后来弱评估器基本被定义为决策树后,才慢慢改名叫做梯度提升树。受Boosting算法首个发扬光大之作AdaBoost的启发,GBDT中自然也包含Boosting三要素:

        ① 损失函数𝐿(𝑥,𝑦):用以衡量模型预测结果与真实结果的差异

        ② 弱评估器𝑓(𝑥):(一般为)决策树,不同的boosting算法使用不同的建树过程

        ③ 综合集成结果𝐻(𝑥):即集成算法具体如何输出集成结果

同时,GBDT也遵循boosting算法的基本流程进行建模:

        依据上一个弱评估器f(x)_{t-1}的结果,计算损失函数L(x,y)
        并使用L(x,y)自适应地影响下一个弱评估器f(x)_{t}的构建。
        集成模型输出的结果,受到整体所有弱评估器f(x)_{0} ~ f(x)_{T}的影响。

但与AdaBoost不同的是,GBDT在整体建树过程中做出了以下几个关键的改变:

① 弱评估器

        GBDT的弱评估器输出类型不再与整体集成算法输出类型一致。对于AdaBoost或随机森林算法来说,当集成算法执行的是回归任务时,弱评估器也是回归器,当集成算法执行分类任务时,弱评估器也是分类器。但对于GBDT而言,无论GBDT整体在执行回归/分类/排序任务,弱评估器一定是回归器。GBDT通过sigmoid或softmax函数输出具体的分类结果,但实际弱评估器一定是回归器。

② 损失函数𝐿(𝑥,𝑦)

        在GBDT当中,损失函数范围不再局限于固定或单一的某个损失函数,而从数学原理上推广到了任意可微的函数。因此GBDT算法中可选的损失函数非常多,GBDT实际计算的数学过程也与损失函数的表达式无关。

③ 拟合残差

        GBDT依然自适应调整弱评估器的构建,但却不像AdaBoost一样通过调整数据分布来间接影响后续弱评估器。相对的,GBDT通过修改后续弱评估器的拟合目标来直接影响后续弱评估器的结构。具体地来说,在AdaBoost当中,每次建立弱评估器之前需要修改样本权重,且用于建立弱评估器的是样本𝑋以及对应的𝑦,在GBDT当中,我们不修改样本权重,但每次用于建立弱评估器的是样本𝑋以及当下集成输出H(x_{i})与真实标签𝑦的差异(y-H(x_{i}))。这个差异在数学上被称之为残差(Residual),因此GBDT不修改样本权重,而是通过拟合残差来影响后续弱评估器结构

④ 抽样思想

        GBDT加入了随机森林中随机抽样的思想,在每次建树之前,允许对样本和特征进行抽样来增大弱评估器之间的独立性(也因此可以有袋外数据集)。虽然Boosting算法不会大规模地依赖于类似于Bagging的方式来降低方差,但由于Boosting算法的输出结果是弱评估器结果的加权求和,因此Boosting原则上也可以获得由“平均”带来的小方差红利。当弱评估器表现不太稳定时,采用与随机森林相似的方式可以进一步增加Boosting算法的稳定性。

        除了以上四个改变之外,GBDT的求解流程与AdaBoost大致相同。sklearn当中集成了GBDT分类与GBDT回归,我们使用如下两个类来调用它们:

class sklearn.ensemble.GradientBoostingClassifier(*, loss='deviance', learning_rate=0.1, n_estimators=100, subsample=1.0, criterion='friedman_mse', min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_depth=3, min_impurity_decrease=0.0, init=None, random_state=None, max_features=None, verbose=0, max_leaf_nodes=None, warm_start=False, validation_fraction=0.1, n_iter_no_change=None, tol=0.0001, ccp_alpha=0.0)

class sklearn.ensemble.GradientBoostingRegressor(*, loss='squared_error', learning_rate=0.1, n_estimators=100, subsample=1.0, criterion='friedman_mse', min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_depth=3, min_impurity_decrease=0.0, init=None, random_state=None, max_features=None, alpha=0.9, verbose=0, max_leaf_nodes=None, warm_start=False, validation_fraction=0.1, n_iter_no_change=None, tol=0.0001, ccp_alpha=0.0)

比起AdaBoost,GBDT的超参数数量增加了不少,但与其他集成算法一样,GBDT回归器与GBDT分类器的超参数高度一致。

2. GradientBoosting回归与分类的实现

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.ensemble import GradientBoostingRegressor as GBR
from sklearn.ensemble import GradientBoostingClassifier as GBC
from sklearn.ensemble import AdaBoostRegressor as ABR
from sklearn.ensemble import RandomForestRegressor as RFR
from sklearn.model_selection import cross_validate, KFold
data = pd.read_csv(r"F:\\Jupyter Files\\机器学习进阶\\datasets\\House Price\\train_encode.csv",index_col=0)def RMSE(result,name):return abs(result[name].mean())

2.1 GradientBoosting回归

梯度提升回归树:

#回归数据
X = data.iloc[:,:-1]
y = data.iloc[:,-1]
gbr = GBR(random_state=1412) #实例化
cv = KFold(n_splits=5,shuffle=True,random_state=1412) #定义所需的交叉验证方式
result_gbdt = cross_validate(gbr,X,y,cv=cv,scoring="neg_root_mean_squared_error" #负根均方误差,return_train_score=True,verbose=True)
RMSE(result_gbdt,"train_score") #13990.790813889864
RMSE(result_gbdt,"test_score") #28783.954343252786

 梯度提升回归与其它算法的对比

import time
modelname = ["GBDT","RF","AdaBoost","RF-TPE","Ada-TPE"]models = [GBR(random_state=1412),RFR(random_state=1412),ABR(random_state=1412),RFR(n_estimators=89, max_depth=22, max_features=14, min_impurity_decrease=0,random_state=1412, verbose=False),ABR(n_estimators=39, learning_rate=0.94,loss="exponential",random_state=1412)]colors = ["green","gray","orange","red","blue"]for name,model in zip(modelname,models):start = time.time()result = cross_validate(model,X,y,cv=cv,scoring="neg_root_mean_squared_error",return_train_score=True,verbose=False)end = time.time()-startprint(name)print("\t train_score:{:.3f}".format(RMSE(result,"train_score")))print("\t test_score:{:.3f}".format(RMSE(result,"test_score")))print("\t time:{:.2f}s".format(end))print("\n")------------------------------------------------------------------------------
GBDTtrain_score:13990.791test_score:28783.954time:2.54sRFtrain_score:11177.272test_score:30571.267time:6.65sAdaBoosttrain_score:27062.107test_score:35345.931time:1.20sRF-TPEtrain_score:11208.818test_score:28346.673time:1.54sAda-TPEtrain_score:27401.542test_score:35169.730time:0.86s
算法RFAdaBoostGBDTRF
(TPE)
AdaBoost
(TPE)
5折验证
运行时间
6.65s1.20s2.54s1.54s0.86s
最优分数
(RMSE)
30571.26735345.93128783.95428346.67335169.730

首先来看默认参数下所有算法的表现。当不进行调参时,随机森林的运行时间最长、AdaBoost最快,GBDT居中,但考虑到AdaBoost的n_estimators参数的默认值为50,而GBDT和随机森林的n_estimators默认值都为100,可以认为AdaBoost的运行速度与GBDT相差不多。从结果来看,未调参状态下GBDT的结果是最好的,其结果甚至与经过TPE精密调参后的随机森林结果相差不多,而AdaBoost经过调参后没有太多改变,可以说AdaBoost极其缺乏调参空间、并且学习能力严重不足。

基于以上信息,我们可以观察三个算法的过拟合情况:

xaxis = range(1,6)
plt.figure(figsize=(8,6),dpi=80)for name,model,color in zip(modelname[:3],models[:3],colors[:3]):result = cross_validate(model,X,y,cv=cv,scoring="neg_root_mean_squared_error",return_train_score=True,verbose=False)plt.plot(xaxis,abs(result["train_score"]), color=color, label = name+"_Train")plt.plot(xaxis,abs(result["test_score"]), color=color, linestyle="--",label = name+"_Test")plt.xticks([1,2,3,4,5])
plt.xlabel("CVcounts",fontsize=16)
plt.ylabel("RMSE",fontsize=16)
plt.title("RF vs GBDT vs AdaBoost")
plt.legend()
plt.show()

不难发现,AdaBoost是过拟合程度最轻的,这也反映出它没有调参空间的事实,而GBDT与随机森林过拟合程度差不多,不过GBDT的过拟合程度相对较轻一些,这是因为Boosting算法的原理决定了Boosting算法更加不容易过拟合

绘制随机森林调参前后、以及AdaBoost调参前后的结果对比:

xaxis = range(1,6)
plt.figure(figsize=(8,6),dpi=80)for name,model,color in zip(modelname[2:5:2],models[2:5:2],colors[2:5:2]):result = cross_validate(model,X,y,cv=cv,scoring="neg_root_mean_squared_error",return_train_score=True,verbose=False)plt.plot(xaxis,abs(result["train_score"]), color=color, label = name+"_Train")plt.plot(xaxis,abs(result["test_score"]), color=color, linestyle="--",label = name+"_Test")plt.xticks([1,2,3,4,5])
plt.xlabel("CVcounts",fontsize=16)
plt.ylabel("RMSE",fontsize=16)
plt.title("AdaBoost vs AdaBoost-TPE")
plt.legend()
plt.show()
xaxis = range(1,6)
plt.figure(figsize=(8,6),dpi=80)for name,model,color in zip(modelname[1:4:2],models[1:4:2],colors[1:4:2]):result = cross_validate(model,X,y,cv=cv,scoring="neg_root_mean_squared_error",return_train_score=True,verbose=False)plt.plot(xaxis,abs(result["train_score"]), color=color, label = name+"_Train")plt.plot(xaxis,abs(result["test_score"]), color=color, linestyle="--",label = name+"_Test")plt.xticks([1,2,3,4,5])
plt.xlabel("CVcounts",fontsize=16)
plt.ylabel("RMSE",fontsize=16)
plt.title("RF vs RF-TPE")
plt.legend()
plt.show()

 AdaBoost在经过精密调参后,并没有太多改变,而随机森林调参后过拟合程度明显降低,测试集上的结果明显提升,这是随机森林在潜力和根本原则上都比AdaBoost要强大的表现。

GBDT在默认参数上的结果接近经过TPE调参后的随机森林,我们来看看这两个算法的对比:

xaxis = range(1,6)
plt.figure(figsize=(8,6),dpi=80)for name,model,color in zip(modelname[:5:3],models[:5:3],colors[:5:3]):result = cross_validate(model,X,y,cv=cv,scoring="neg_root_mean_squared_error",return_train_score=True,verbose=False,n_jobs=-1)plt.plot(xaxis,abs(result["train_score"]), color=color, label = name+"_Train")plt.plot(xaxis,abs(result["test_score"]), color=color, linestyle="--",label = name+"_Test")plt.xticks([1,2,3,4,5])
plt.xlabel("CVcounts",fontsize=16)
plt.ylabel("RMSE",fontsize=16)
plt.title("GBDT vs RF-TPE")
plt.legend()
plt.show()

 

不难发现,GBDT的过拟合程度是轻于优化后的随机森林的。并且,在大部分交叉验证的结果下,GBDT的效果都接近或好于优化后的随机森林。在cv=2时GBDT的表现远不如森林,一次糟糕的表现拉低了GBDT的整体表现,否则GBDT可能在默认参数上表现出比优化后的随机森林更好的结果。如果我们可以通过调参优化让GBDT的表现更加稳定,GBDT可能会出现惊人的表现。

2.2 GradientBoosting分类

#分类数据
X_clf = data.iloc[:,:-2]
y_clf = data.iloc[:,-2]
np.unique(y_clf) #6分类
-----------------------------------------
array([0., 1., 2., 3., 4., 5.])
#GBDT分类的实现
clf = GBC(random_state=1412) #实例化
cv = KFold(n_splits=5,shuffle=True,random_state=1412)
result_clf = cross_validate(clf,X_clf,y_clf,cv=cv,return_train_score=True,verbose=True)
result_clf
----------------------------------------------------------
{'fit_time': array([3.47425294, 3.40723777, 3.38023067, 3.39023256, 3.41823983]),'score_time': array([0.0040009 , 0.00400043, 0.00400066, 0.00300074, 0.00400186]),'test_score': array([0.89726027, 0.8869863 , 0.90410959, 0.8869863 , 0.90753425]),'train_score': array([0.99058219, 0.99315068, 0.99229452, 0.99143836, 0.99143836])}
# 准确率
result_clf["train_score"].mean()  # 0.9917808219178083
result_clf["test_score"].mean()   # 0.8965753424657535

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/8421.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

赛码-0726

01串的魔法 思路:虽然标着dp,其实是滑动窗口问题,dp 会超时 import java.util.*;public class Main {public static void main(String[] args) {Scanner scanner new Scanner(System.in);int n scanner.nextInt();int k scanner.nextInt…

帆软报表设计器设置步骤

1、连接工作目录(可以是远程服务器) 在打开的界面中设置具体的远程地址 一个报表文件可以有多个数据集、但是数据集依附于报表文件的存在,不能跨报表共享。 先补充这么多,有遇到问题再写一点。 (完)

指针易混淆概念:*p++,*(p++),++(*p)

(1)a[1]和&a[1] a[1]:二维数组的第二行元素,即a[1]是以a[1][0]开头的一维数组,类型是一级指针 &a[1]:二维数组的第二行元素的地址,类型是二级指针 (2)a1与*(a1&#xff09…

我的创作纪念日——暨成为创作者满1024日的总结

我的创作纪念日 机缘收获日常成就憧憬 机缘 最初写博客,是因为身边一个同事,写了几篇博客,然后给我臭摆,于是,不服输的自己也动手开始写了。之后,就逐渐写出惯性来了,现在每月4篇,基…

Cpp 01 — namespace命名空间、C++的输入与输出、缺省参数、函数重载、引用、隐式类型转换

前言:本文章主要用于个人复习,追求简洁,感谢大家的参考、交流和搬运,后续可能会继续修改和完善。 因为是个人复习,会有部分压缩和省略。 一、namespace命名空间 C使用命名空间(namespace)来避免命名冲突。 在定义一个…

最小生成树

最小生成树 1.朴素Primm~n^2稠密图 Part1:例题 给定一个 n 个点 m 条边的无向图,图中可能存在重边和自环,边权可能为负数。 求最小生成树的树边权重之和,如果最小生成树不存在则输出 impossible。 数据范围: 1≤n≤5001≤n≤…

STM32CUBUMX配置RS485(中断接收)--保姆级教程

———————————————————————————————————— ⏩ 大家好哇!我是小光,嵌入式爱好者,一个想要成为系统架构师的大三学生。 ⏩最近在开发一个STM32H723ZGT6的板子,使用STM32CUBEMX做了很多驱动&#x…

Vue mixin 混入

可以复用的组件,我们一般会抽离,写成公共的模块。 可以复用的方法,我们一般会抽离,写成公共的函数。 那么 在 Vue 中,如果 某几个组件实例 VueComponent 中、或者 整个 Vue 项目中 都存在相同的配置,那就…

格雷码(Gray Code)的构造

说明 Gray Code是一个数列集合,每个数使用二进位来表示,假设使用n位元来表示每个数好了,任两个数之间只有一个位元值不同,例如以下为3位元的Gray Code: 000 001 011 010 110 111 101 100 由定义可以知道,G…

firefox笔记-Centos7离线安装firefox

目前(2023-03-22 16:41:35)Centos7自带的firefox已经很新了是2020年的。主要原因是有个web项目,用2020年的firefox打不开。 发到互联网上是2023-07-24。 报错是js有问题,估计是搞前端的只做了chrome适应,没做firefox…

Spring使用注解进行对象装配(DI)

文章目录 一. 什么是对象装配二. 三种注入方式1. 属性注入2. 构造方法注入3. Setter注入 三. 三种注入方式的优缺点四. 综合练习 通过五大类注解可以更便捷的将对象存储到 Spring 中,同样也可以使用注解将已经储存的对象取出来,直接赋值到注解所在类的一…

软件应用开发的常见环境

一般来说,在小型项目中可能只有开发环境和生产环境;在中型项目中会有开发环境、staging environment、生产环境;在大型项目中会有开发环境、测试环境、staging environment、生产环境。 一、Dev Env / Development Environment 开发环境 开…

ATTO488 NHS ester ,新型亲水性荧光标记物,具有良好的水溶性

陕西新研博美生物科技有限公司MISS.wu小编(2023.7月26日)为大家整理以下的内容: Atto488-NHS是一种新型亲水性荧光标记物,具有良好的水溶性。这种染料表现得很浓吸收、高荧光量子产率以及优异的热稳定性和光稳定性。因此&#xff…

企业微信,阿里钉钉告警群机器人

链接:如何通过企业微信群接收报警通知_云监控-阿里云帮助中心

亚马逊、速卖通,阿里国际等平台测评如何用自养号测评补单

在电商领域,补单是一种常见的推广方式。它能够优化商品销售、留下优质评论、打压竞品和赶走跟卖等,具有很多好处。然而,补单也存在安全性问题,有些卖家找人补单后店铺反而出了问题。因此,了解测评系统是非常重要的的。…

Linux Shell 学习笔记二

#!/bin/bash# 当你遇到shell脚本异常时,加上此行set -euxo pipefail,会打印出执行过程并阻止脚本继续执行。 set -euo pipefail# 使用说明: # BACKUP<backup> NS<ns1,ns2,...> ./migrate-ack.sh # 其中BACKUP为velero backup的名称,可以通过 velero --kubecontextj…

ChatGPT | 使用自己Prompt替换LangChain默认Prompt

某些场景会要求ChatGPT重复处理同一个操作&#xff0c;要么在问题里面加入Prompt&#xff0c;要么用自己Prompt替换LangChain默认Prompt。 直接看看前后对比结果 LangChain默认的Prompt template"Use the following pieces of context to answer the users question. \n…

android9-android13 AMS演进初窥

目录 一&#xff1a;概览 WindowManagerService 基本介绍 ActivityManagerService 基本介绍 二&#xff1a;AMS及其关联的WMS中主要组件的类图和对像图 一&#xff1a;android 9中AMS/WMS的类图和对像图 二&#xff1a;android 10中AMS/WMS的类图和对像图 三&#xff1a…

关于应用在Google Play的元数据优化

应用标题中的关键词权重最大&#xff0c;其次是简短描述中的关键词&#xff0c;最后是长描述关键词&#xff0c;了解这些就能够很好的提高应用的可见度&#xff0c;下载量和整体成功率。 1&#xff0c;标题。 Google Play最多允许标题容纳30个字符&#xff0c;关键词的频率和密…

盘点!项目管理软件排行榜前十名

如今企业规模不断扩大&#xff0c;业务逐渐复杂化&#xff0c;项目管理已经成为现代企业管理中不可或缺的一环。作为协调管理者、团队成员和客户之间交流的工具&#xff0c;项目管理软件不仅可以提高工作效率&#xff0c;还可以提高项目成功的几率&#xff0c;对于企业具有重要…