一、XGBoost
1 基本思路
每个样本的预测值都是样本在每颗树叶子节点的分值之和。
每次添加一颗新树时,都会使得样本预测值与真实值之间的差值减少,即每增加一棵树,都是在弥补之前的差异。
2 原理
问题:如何添加新树,才能弥补差异?
2.1 目标函数构造
两个目标:
- 让预测值和真实值之前的差异loss最小
- 对于每棵树,添加惩罚项,防止过拟合和决策树过于复杂。
所以目标函数是所有样本损失函数的和加上每颗决策树惩罚项的和
T:表示每颗决策树叶子节点的数目
W:表示每颗决策树叶子节点的分数,即权重
2.2 求解目标函数
- loss部分泰勒展开:由于t时刻的预测值等于t-1时刻的预测值加上t时刻新决策树的叶子节点的分数,所以可以采用泰勒二次展开。
g为t-1时刻loss的一阶导数,h为二阶导数,他们其实都是常数项因子,t-1时刻loss在t时刻为常数,可以归到常数项 - 惩罚项部分:直接算t时刻决策树的惩罚项即可
- 从按样本统计到按叶子节点统计:对于损失函数而言,其针对的是每一个样本点求和,要将其转换为按叶子节点求和,只需要把在同一个叶子节点的样本点找出来,把他们的一阶、二阶导数分别相加,乘上共同的节点分值,就变成了该叶子节点的损失函数,再加起来就得到了总损失函数。将该损失函数与惩罚因子合并后可得如下目标函数。
- 目标函数求解:目标函数只有wj为变量,对其求梯度计算最小值,得最优的wj,即t时刻决策树叶子节点的权值。
2.3 树的内部如何分支
- 对于每个特征,要不要分:贪婪算法,将分支前叶子节点的最优目标函数与分支后左右叶子节点的最有目标函数之和做差,得到增益Gain,如果增益大于0,说明目标函数减小了,那么就要分支。
- 对于每个特征,从哪里分:首先要对该特征的n个值进行排序,然后尝试从任意两个值进行分支,有n-1钟可能,对所有的可能,计算增益Gain,然后从增益最大的地方分支。
3 优化点
- 快速停止:如果连续计算几次Gian都小于等于0,则提前停止分支。
- 步长收缩:每次加入新决策树后,不是直接把分支节点权重和之前的预测值相加得新预测值,而是将分支节点权重乘上一个收缩因子再去加之前的预测值,避免过拟合。
- 近似算法:对于每个特征,只考虑在分位点处进行分支。首先根据分位数提出候选分位点(Globel策略:学习每棵树前就提出候选分位点,因此需要较多得分位点、Local策略:每次分裂前重新计算,需要更多计算步骤),然后把连续型特征映射到这些候选分位点划分得Bins中,然后找到最佳分裂点。
- 加权分位数:分位数不能简单得按照样本个数来划分,而是要以二阶导数h作为权值来划分,这是因为对目标函数进行配方,可以看出h对loss有加权的作用,这样得到的候选分位点增益差值更大
- 稀疏感知算法:在构建树的节点的时候,只考虑非缺失值的数据遍历,并且为每个节点增加一个缺省方向,当样本的相应特征值缺失时,直接归为缺省方向。缺省方向的学习:分别枚举出特征缺省的样本归为左右分支后,左右分支各自增益,取增益大的为最优缺省方向。
4 代码实现
4.1 基础代码 – sklearn接口
分类
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
# read in the iris data
iris = load_iris()
X = iris.data
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
# 训练模型
model = xgb.XGBClassifier(max_depth=5, learning_rate=0.1, n_estimators=160, silent=True, objective='multi:softmax')
model.fit(X_train, y_train)
# 对测试集进行预测
ans = model.predict(X_test)
# 计算准确率
cnt1 = 0
cnt2 = 0
for i in range(len(y_test)):
if ans[i] == y_test[i]:
cnt1 += 1
else:
cnt2 += 1
print("Accuracy: %.2f %% " % (100 * cnt1 / (cnt1 + cnt2)))
# 显示重要特征
plot_importance(model)
plt.show()
回归
import xgboost as xgb
from xgboost import plot_importance
from matplotlib import pyplot as plt
from sklearn.model_selection import train_test_split
import csv
# 读取文件原始数据
X=[]
y=[]
csvFile = open(r"G:\训练小样本3_label.csv", "r")
reader = csv.reader(csvFile)
for item in reader:
item=[float(ii) for ii in item]
X.append(item)
# 把读取的数据转化成float格式
for