一、GBDT原理与应用
1.1 原理
GBDT由两部分组成,分别是GB(Gradient Boosting)和DT(Decison Tree)。DT采用CART的回归树,GB指的是沿着梯度方向,构造一系列的弱分类器函数,并以一定权重组合起来,形成最终决策的强分类器。
GBDT是一种基于集成思想的决策树模型,本质是基于残差学习。
特点在于:可处理各种类型的数据;有着较高的准确率;对异常值的鲁棒性强;不能并行训练数据
GBDT采用加法模型,通过不断减小训练过程产生的残差,以此对数据进行回归或分类。GBDT进行多轮迭代,每轮迭代产生一个弱分类器CART回归树,该分类器是在上一轮分类器的残差结果基础上训练得到的。对弱分类器的要求是低方差、高偏差(低方差保证模型不会过拟合+高偏差在训练过程中会减小,以此提高精度)。为了使损失函数尽可能快地减小,用损失函数的负梯度作为残差的近似值,然后去拟合CART回归树。
1.2 应用
基于GBDT的数据回归
基于GBDT的数据分类
代码实现
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 #定义lambda函数,相当于把值赋给self.fn
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)
二、XGBOOST
三个核心部分:集成算法本身,用于集成的弱评估器,以及应用中的其他过程。
2.1 XGBOOST的重要参数
1.eta[默认0.3]
通过为每一颗树增加权重,提高模型的鲁棒性。
典型值为0.01-0.2。
2.min_child_weight[默认1]
决定最小叶子节点样本权重和。
这个参数可以避免过拟合。当它的值较大时,可以避免模型学习到局部的特殊样本。
但是如果这个值过高,则会导致模型拟合不充分。
3.max_depth[默认6]
这个值也是用来避免过拟合的。max_depth越大,模型会学到更具体更局部的样本。
典型值:3-10
4.max_leaf_nodes
树上最大的节点或叶子的数量。
可以替代max_depth的作用。
这个参数的定义会导致忽略max_depth参数。
5.gamma[默认0]
在节点分裂时,只有分裂后损失函数的值下降了,才会分裂这个节点。Gamma指定了节点分裂所需的最小损失函数下降值。 这个参数的值越大,算法越保守。这个参数的值和损失函数息息相关。
6.max_delta_step[默认0]
这参数限制每棵树权重改变的最大步长。如果这个参数的值为0,那就意味着没有约束。如果它被赋予了某个正值,那么它会让这个算法更加保守。
但是当各类别的样本十分不平衡时,它对分类问题是很有帮助的。
7.subsample[默认1]
这个参数控制对于每棵树,随机采样的比例。
减小这个参数的值,算法会更加保守,避免过拟合。但是,如果这个值设置得过小,它可能会导致欠拟合。
典型值:0.5-1
8.colsample_bytree[默认1]
用来控制每棵随机采样的列数的占比(每一列是一个特征)。
典型值:0.5-1
9.colsample_bylevel[默认1]
用来控制树的每一级的每一次分裂,对列数的采样的占比。
subsample参数和colsample_bytree参数可以起到相同的作用,一般用不到。
10.lambda[默认1]
权重的L2正则化项。(和Ridge regression类似)。
这个参数是用来控制XGBoost的正则化部分的。虽然大部分数据科学家很少用到这个参数,但是这个参数在减少过拟合上还是可以挖掘出更多用处的。
11.alpha[默认1]
权重的L1正则化项。(和Lasso regression类似)。
可以应用在很高维度的情况下,使得算法的速度更快。
12.scale_pos_weight[默认1]
在各类别样本十分不平衡时,把这个参数设定为一个正值,可以使算法更快收敛。
2.2 XGBoost原理
XGBoost底层实现了GBDT算法,并对GBDT算法做了一系列优化:
对目标函数进行了泰勒展示的二阶展开,可以更加高效拟合误差。
提出了一种估计分裂点的算法加速CART树的构建过程,同时可以处理稀疏数据。
提出了一种树的并行策略加速迭代。
为模型的分布式算法进行了底层优化。
下面使用sklearn接口下的xgboost帮助我们处理分类问题
iris数据集算是多分类,注意一下使用的目标函数objective='multi:softmax’
from sklearn.datasets import load_iris
import xgboost as xgb
from xgboost import plot_importance
from matplotlib import pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# 加载样本数据集
iris = load_iris()
X, y = iris.data, iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=12343)
# 训练模型
model = xgb.XGBClassifier(max_depth=5, learning_rate=0.1, n_estimators=160, silent=True, objective='multi:softmax')
model.fit(X_train, y_train)
# max_depth:构建树的深度,越大越容易过拟合
# silent=, 设置成1则没有运行信息输出,最好是设置为0,是否在运行升级时打印消息
# 对测试集进行预测
y_pred = model.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print('accuracy:%2.f%%' % (accuracy * 100))
# 显示重要特征
plot_importance(model)
plt.show()