【机器学习】基于GBDT的数据回归及python实现
本博文中GBDT(Gradient Boosting Decison Tree,梯度提升决策树)的决策树采用CART(Classification and Regression Tree,分类回归树)。CART主要参考 《python机器学习算法》,在这里就不赘述了,有需要的同学可以看大神的书。本博文首先介绍集成学习中的Boosting技术,然后介绍GBDT的原理及应用,在GBDT的应用部分重点介绍基于GBDT的数据回归技术,并顺便提及基于GBDT的数据分类思想(只需对回归做一点小的改进即可)。
一、Boosting技术
在面对一个复杂的问题时,我们可以训练多个模型,将这些模型的结果集成起来作为最终的结果,这种处理问题的思想被称为集成学习(参考资料【2】),集成学习分为两类:Bagging和Boosting。Bagging技术是指在样本中有放回的随机抽取几组样本数据,用这几组样本数据训练几个模型,最终由这几个模型投票决定分类结果或取均值得到回归结果,随机森林(参考资料【3】)就是一个典型的Bagging模型。Boosting技术同样是训练多个弱性能模型,但不同于Bagging技术中弱性能模型是并行且独立训练的,在Boosting中多个弱性能模型是串行的。Boosting对样本进行不同的赋值,对错误学习的样本的权重设置的较大,在后续的学习中集中处理难学的样本,最终得到一系列的预测结果,每个预测结果有一个权重。
二、GBDT原理与应用
2.1、GBDT思想
GBDT由两部分组成,分别是GB(Gradient Boosting)和DT(Decison Tree)。博文开头已经说明,DT采用CART的回归树。GB指的是沿着梯度方向,构造一系列的弱分类器函数,并以一定权重组合起来,形成最终决策的强分类器(参考资料【4】)。
2.2、基于GBDT的数据回归
假设总共有 个串行CART回归树模型,每个CART模型单独拿出来的预测结果为:
前 个模型串行在一起的预测结果为:
其中
假设样本标签为Y,前 个模型串行的预测输出与标签真实值之间的损失函数为:
当训练第 个回归树模型时,我们的目的是前 个模型串行预测输出与样本标签真实值之间的损失函数 最小。
为了训练出模型 ,GB方法利用最速下降的近似方法,即利用损失函数的负梯度在当前模型的值,作为回归问题中提升树算法的残差的近似值,去拟合当前的回归树模型。
表示求第 个回归树模型时,第 个样本特征对应的残差值。利用 去拟合第 个CART模型。
2.3、基于GBDT的数据分类
以GBDT二分类为例,样本类别为 ,将每一轮模型训练后的预测的结果利用sigmoid函数映射到0到1之间,最后预测值大于等于0.5的样本为类别1,预测值小于0.5的样本为类别0。
三、基于GBDT的数据回归的python实现
python代码与样本地址:https://github.com/shiluqiang/GBDT_regression
基于GBDT的数据回归中训练每一个CART模型,直接采用前面所有模型的串行输出与样本标签的残差为训练目标(参考资料【5】)。
GBDTpython代码如下
import CART_regression_tree
import numpy as np
def load_data(data_file):
'''导入训练数据
input: data_file(string):保存训练数据的文件
output: data(list):训练数据
'''
data_X = []
data_Y = []
f = open(data_file)
for line in f.readlines():
sample = []
lines = line.strip().split("\t")
data_Y.append(float(lines[-1]))
for i in range(len(lines) - 1):
sample.append(float(lines[i])) # 转换成float格式
data_X.append(sample)
f.close()
return data_X,data_Y
class GBDT_RT(object):
'''GBDT回归算法类
'''
def __init__(self):
self.trees = None ##用于存放GBDT的树
self.learn_rate = learn_rate ## 学习率,防止过拟合
self.init_value = None ##初始数值
self.fn = lambda x: x
def get_init_value(self,y):
'''计算初始数值为平均值
input:y(list):样本标签列表
output:average(float):样本标签的平均值
'''
average = sum(y)/len(y)
return average
def get_residuals(self,y,y_hat):
'''计算样本标签标签与预测列表的残差
input:y(list):样本标签列表
y_hat(list):预测标签列表
output:y_residuals(list):样本标签标签与预测列表的残差
'''
y_residuals = []
for i in range(len(y)):
y_residuals.append(y[i] - y_hat[i])
return y_residuals
def fit(self,data_X,data_Y,n_estimators,learn_rate,min_sample, min_err):
'''训练GBDT模型
input:self(object):GBDT_RT类
data_X(list):样本特征
data_Y(list):样本标签
n_estimators(int):GBDT中CART树的个数
learn_rate(float):学习率
min_sample(int):学习CART时叶节点的最小样本数
min_err(float):学习CART时最小方差
'''
## 初始化预测标签和残差
self.init_value = self.get_init_value(data_Y)
n = len(data_Y)
y_hat = [self.init_value] * n ##初始化预测标签
y_residuals = self.get_residuals(data_Y,y_hat)
self.trees = []
self.learn_rate = learn_rate
## 迭代训练GBDT
for j in range(n_estimators):
idx = range(n)
X_sub = [data_X[i] for i in idx] ## 样本特征列表
residuals_sub = [y_residuals[i] for i in idx] ## 标签残差列表
tree = CART_regression_tree.CART_RT(X_sub,residuals_sub, min_sample, min_err).fit()
res_hat = [] ##残差的预测值
for m in range(n):
res_hat.append(CART_regression_tree.predict(data_X[m],tree))
## 计算此时的预测值等于原预测值加残差预测值
y_hat = [y_hat[i] + self.learn_rate * res_hat[i] for i in idx]
y_residuals = self.get_residuals(data_Y,y_hat)
self.trees.append(tree)
def GBDT_predict(self,xi):
'''预测一个样本
'''
return self.fn(self.init_value + sum(self.learn_rate * CART_regression_tree.predict(xi,tree) for tree in self.trees))
def GBDT_predicts(self,X):
'''预测多个样本
'''
return [self.GBDT_predict(xi) for xi in X]
def error(Y_test,predict_results):
'''计算预测误差
input:Y_test(list):测试样本标签
predict_results(list):测试样本预测值
output:error(float):均方误差
'''
Y = np.mat(Y_test)
results = np.mat(predict_results)
error = np.square(Y - results).sum() / len(Y_test)
return error
if __name__ == '__main__':
print ("------------- 1.load data ----------------")
X_data,Y_data = load_data("sine.txt")
X_train = X_data[0:150]
Y_train = Y_data[0:150]
X_test = X_data[150:200]
Y_test = Y_data[150:200]
print('------------2.Parameters Setting-----------')
n_estimators = 4
learn_rate = 0.5
min_sample = 30
min_err = 0.3
print ("--------------3.build GBDT ---------------")
gbdt_rt = GBDT_RT()
gbdt_rt.fit(X_train,Y_train,n_estimators,learn_rate,min_sample, min_err)
print('-------------4.Predict Result--------------')
predict_results = gbdt_rt.GBDT_predicts(X_test)
print('--------------5.Predict Error--------------')
error = error(Y_test,predict_results)
print('Predict error is: ',error)
参考资料
1、《python机器学习算法》
2、https://blog.csdn.net/google19890102/article/details/46507387
3、https://blog.csdn.net/qq547276542/article/details/78304454
4、https://blog.csdn.net/legendavid/article/details/78904353
5、GBDT回归的原理及Python实现