【机器学习笔记28】GBDT提升树

【参考资料】
【1】《统计学习方法》8.4
【2】lightgbm源码 LightGBM/examples/python-guide/simple_example

备注:近期用到lightbgm,回过头再好好看看提升树方面的知识点:)

一 Adaboost算法

输入: 训练数据集T={(x1,y1),(x2,y2),...,(xN,yN)}T=\{(x_1, y_1), (x_2, y_2),...,(x_N, y_N)\}其中xiXRnx_i \in X \subseteq R^nyiY={1,1}y_i \in Y = \{-1, 1\}

第一步: 初始化训练数据的权值分布,有:
D1=(w11,....,w1i,...,w1N)D_1=(w_{11}, ...., w_{1i}, ..., w_{1N}),其中w1i=1Nw_{1i}= \dfrac{1}{N},表示第一次划分训练数据,将其划分为N份,每份的全职为1/N。

第二步:基于划分完的训练数据进行训练

2.1 对划分出的每份训练数据计算一个基本分类器Gm(x)G_m(x)
2.2 计算Gm(x)G_m(x)的训练误差:
em=P(Gm(xi)yi)=i=1NwmiI(Gm(xi)yi)e_m=P(G_m(x_i) \ne y_i)=\sum\limits_{i=1}^{N}w_{mi}I(G_m(x_i) \ne y_i)
2.3 计算Gm(x)G_m(x)的系数
am=12log1emema_m=\dfrac{1}{2}log\dfrac{1 - e_m}{e_m}
2.4 更新训练数据集的权值
Dm+1=(wm+1,1,...,wm+1,N)D_{m+1}=(w_{m+1, 1}, ..., w_{m+1, N})
wm+1,i=wmiZmexp(amyiGm(xi))w_{m+1, i}=\dfrac{w_{mi}}{Z_m}exp(-a_my_iG_m(x_i))
其中Z是规范化因子Zm=i=1Nwmiexp(amyiGm(xi))Z_m=\sum\limits_{i=1}^{N}w_{mi}exp(-a_my_iG_m(x_i))

第三步: 构建一个基本分类器的线性组合
f(x)=m=1MamGm(x)f(x)=\sum\limits_{m=1}^{M}a_mG_m(x)

二 提升树

提升树的模型定义如下:
fM(x)=m=1MT(x;Θm)f_M(x)=\sum\limits_{m=1}^{M}T(x;\Theta_m),表示M个子树分类器,Θm\Theta_m是这个分类树的参数,M为树的个数

第一步:初始化f0(x)=0f_0(x)=0
第二步:对M个子树计算残差:
2.1 对于训练数据划分的J个不相交的区域,某棵树(回归树)可以表示为
T(x;Θ)=j=1JcjI(xRj)T(x;\Theta)=\sum\limits_{j=1}^{J}c_jI(x \in R_j),这里cjc_j是该树在这个区域输出的常量

备注:这里的算法依次计算1~M棵决策树,每棵决策树都会遍历J个区域计算损失

2.2 计算残差
rmi=yifm1(xi)r_{mi}=y_i - f_{m-1}(x_i),备注:从m-1次计算第m次
第三步:将残差作为训练数据进行下一次分割,学习成一个新的回归树;
第四步:fM(X)=m=1MT(x;Θm)f_M(X)=\sum\limits_{m=1}^{M}T(x;\Theta_m)

举例

《统计学习方法》例题8.2

【机器学习笔记28】GBDT提升树

第一步:考虑分割点1.5, 2.5, …,9.5,依据下述公式计算损失最小:
minc1R1(yic1)2+minc2R2(yic2)2\min_{c1}\sum\limits_{R_1}(y_i - c_1)^2 + \min_{c2}\sum\limits_{R_2}(y_i - c_2)^2,得到结果如下:
【机器学习笔记28】GBDT提升树

由上表可知,这一次最优分割在6.5,即R1={1,2,3,4,5,6}R2={7,8,9}R_1=\{1,2,3,4,5,6\} \quad R_2=\{7,8,9\},相应的c1=6.24c2=8.91c_1=6.24 \quad c_2=8.91

此时得到回归树f1(x)=T1(x)f_1(x)=T_1(x)
T1(x)={6.24,x<6.58.91,x6.5 T_1(x) = \begin{cases} 6.24, & x < 6.5 \\ 8.91, & x \ge 6.5 \end{cases}

第二步:计算上面这课回归树的残差值
【机器学习笔记28】GBDT提升树

第三步:在此残差值基础上继续计算后续的决策树,例如:
【机器学习笔记28】GBDT提升树

第四步: 将各个决策树累加起来形成最终的决策树
f6(x)=T1(x)+Tx(x)+...+T6(x)f_6(x)=T_1(x) + T_x(x) + ... + T_6(x)

三 梯度提升

梯度提升树是将残差值得计算方法做了修改,利用损失函数的负梯度在当前模型下的值作为残差值得近似,如下:
[L(y,f(xi)f(xi)]f(x)=fm1(x)-[\dfrac{\partial L(y, f(x_i)}{\partial f(x_i)}]_{f(x)=f_{m-1}(x)}

四 GBT回归的例子(基于lightbgm)
# -*- coding: utf-8 -*-
import numpy  as np
import matplotlib.pyplot as plt
import lightgbm as lgb
import pandas as pd
from sklearn.model_selection import train_test_split

train = pd.read_csv('../01.data/datasets/studentscores.csv', header=None, sep=',', dtype=float)
test = pd.read_csv('../01.data/datasets/test.csv', header=None, sep=',', dtype=float)


"""
由学习时间和性别来预测分数,随机构造的数据完全没有意思。。。。。。。
2.5,21,1
5.1,47,1
3.2,27,0
8.5,75,0
3.5,30,1
"""

x_train = train.drop(1, axis=1)
y_train = train.drop([0,2], axis=1)
x_test  = test.drop(1, axis=1)
y_test  = test.drop([0,2], axis=1)

lgb_train = lgb.Dataset(x_train, y_train)
lgb_eval = lgb.Dataset(x_test, y_test, reference=lgb_train)


params = {
    'boosting_type': 'gbdt',
    'objective': 'regression',   
    'metric': {'l2', 'l1'},
    'num_leaves': 16,
    'learning_rate': 0.05,
     'min_data':1, #数据量太少的时候加这个参数
    'feature_fraction': 0.9,
    'bagging_fraction': 0.8,
    'bagging_freq': 5,
    'verbose': 0
}

print('Starting training...')

# train
gbm = lgb.train(params,
                lgb_train,
                num_boost_round=4,
                valid_sets=lgb_eval,
                early_stopping_rounds=2)

y_pred = gbm.predict(x_test, num_iteration=gbm.best_iteration)

from sklearn.metrics import mean_squared_error

print('The rmse of prediction is:', mean_squared_error(y_test, y_pred) ** 0.5) #The rmse of prediction is: 23.752816735400195