返回主目录
返回集成学习目录
上一章:机器篇——集成学习(六) 细说 GBDT 算法
下一章:机器篇——集成学习(八) 细说 ball49_pred 项目(彩票预测)
本小节,细说 XGBoost 算法,下一小节细说 ball49_pred 项目
论文参考以下链接: XGBoost: A Scalable Tree Boosting System
二. 具体算法
7. XGBoost 算法(Extreme Gradient Boostin, XGBoost)
XGBoost 是 GB 算法的一种高效实现。XGBoost 中的基学习器除了可以是 CART(gbtree),也可以是线性分类器(gblinear)。
(1). XGBoost 是一种监督学习算法,它实现了一个称为增强的过程,以产生准确的模型。
监督学习的常用目标函数,通常包含两个部分:训练误差 + 正则化
:为损失函数,度量模型预测值和真实值的误差。
平方损失函数:
交叉熵损失函数:
为分类数,特别地,当 时,为 二分类的交叉熵损失函数:
logistic 损失函数:
:为正则化项,度量模型的复杂度,避免过拟合。常用的正则化有 正则化。
正则:
正则:
(2). 模型融合
一棵 CART 往往过于简单,而无法有效地进行预测,因此更加高效的是使用多个 CART 进行融合,使用集成的方法提升预测效果。
①. 假设有两棵回归树,进行融合预测结果,公式为:
:为树的棵数
:为第 棵树对于输入 输出的得分
:为相应函数
:为相应函数空间
②. 目标函数:
:为损失函数。
(3). 模型训练
①. 假设每次迭代生成一棵树,则训练目标函数可以写成:
:为第 步迭代的预测值。
②. 迭代关系:
③. 训练目标函数可以写成:
对于第 步来说, 是已知的,则:
④. 如果 使用平方损失函数,则
其中,对于第 步来说, 也是常数。
则目标函数可化为:
:为残差。
⑤. 泰勒展开
a. 泰勒展开公式:
在 处有 阶导数
b. 目标函数:
令 , 则
c. 其中 和 为常数项。
由于目标是让这个目标函数最小化,所以常数项并没有什么用,去掉常数项后,得到的目标函数:
⑥. 对于平方损失函数
(4). 模型正则化项
①. 如何衡量一棵树的正则化项,为此,首先对 CART 树作另一番定义:
②. 定义的解释
一棵树有 个叶子节点,这 个叶子节点的值组成了一个 维向量 , 是一个映射,用来将样本映射成 1 到 的某个值。也就是把它分到某个叶子节点, 其实就代表了 CART 树的结构。 自然就是这棵树对样本 的预测值了。
③. XGBoost 的正则化项
a. 和 为 XGBoost 中的两个超参
b. 越大,表示越希望获得结构简单的树,因为此时对较多叶子节点的树惩罚越大。
c. 越大,也是希望获得结构越简单的树,因为此时对 惩罚越大。
(5). 简化目标函数
①. 令
②. 对于第 棵 CART 树的某一个确定的结构(可用 表示),所有的 和 都是正确的。而且 中各叶子节点的值 之间是相互独立的。因此,可求出各个叶子节点的最佳值以及此时目标函数的值:
:最佳树结构的最佳叶子权重
:为学习率
:为反向梯度
的最佳值就是负的梯度乘以一个权重系数,该系数类似于随机梯度下降中的学习率。当 越大时,这个系数越小,也就是学习率越小; 越大,代表在该点附近梯度变化非常剧烈。
:表示这棵树的结构有多好。值越小,代表的结构越好。也就是说,它是衡量第 棵 CART 树的结构好坏的标准。该值仅仅是用来衡量结构的好坏,与叶子节点的值可是无关的。 和 和 和 有关,而它们又和树的结构 有关,与叶子节点的值没有任何关系。
(6). 最优目标函数
在实践中,贪婪地种植这棵树
①. 从树深度为 0
②. 对每棵树的叶子节点尝试添加分裂。目标是添加拆分后的变化。
③. 对于每个节点,枚举所有特性。
④. 时间复杂度增加树的深度
:为左子树节点的分数
:为右子树节点的分数
:为不分割时树节点的分数
:为加入新的叶子节点引入的复杂度代价。
Gain 值为分裂后的值减去分裂前的值。
(7). XGBoost 的小结
①. XGBoost 是对 GBDT 进行的优化。GBDT 在优化中只用到了一阶导数信息,而 XGBoost 则对代价函数进行了二阶泰勒展开,并同时用到了一阶和二阶导数,所以 XGBoost 的效率相较于 GBDT 大大的提高,并且 XGBoost 由于可以并行计算一阶和二阶导数,所以 XGBoost 可以并行建树。
②. XGBoost 的代价函数里加入了正则项,用于控制模型的复杂度。
③. 对于缺失值的处理。对于特征的值有缺失的样本,XGBoost 可以自动学习出它的分裂方向。XGBoost 对于缺失值能预先学习一个默认的分裂方向。
(8). 代码演示
代码的操作和之前的 随机森林,GBDT 一样的,利用网格搜索,寻找出较优的参数,来进行模型训练,预测。
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
# ============================================
# @Time : 2020/01/14 21:50
# @Author : WanDaoYi
# @FileName : xgboost_demo.py
# ============================================import os
import numpy as np
import pandas as pd
from sklearn import metrics
from sklearn.model_selection import GridSearchCV, train_test_split
from xgboost.sklearn import XGBClassifierimport matplotlib.pyplot as plt
import matplotlib
# 用于解决画图中文乱码
font = {"family": "SimHei"}
matplotlib.rc("font", **font)class XGBoostDemo(object):def __init__(self):self.base_path = os.getcwd()self.data_path_last = "data_info/car.csv"self.data_path = os.path.join(self.base_path, self.data_path_last)self.x_train, self.x_val, self.y_train, self.y_val = self.read_data()pass# 获取数据集def read_data(self):# 读取数据文件data_info = pd.read_csv(self.data_path, encoding="gbk")print(data_info.head())print("data_info_shape: {}".format(data_info.shape))# 划分数据为训练集和验证集x = data_info.values[:, : -1]y = data_info.values[:, -1]x_train, x_val, y_train, y_val = train_test_split(x, y, test_size=0.3)print("x_train_shape: {}".format(x_train.shape))return x_train, x_val, y_train, y_valpassdef best_estimators_depth(self):# np.arange 可以生成 float 类型,range 只能生成 int 类型best_param = {'n_estimators': range(10, 201, 5),'max_depth': range(1, 20, 1)}best_gsearch = GridSearchCV(estimator=XGBClassifier(learning_rate=0.1,gamma=0,subsample=0.8,colsample_bytree=0.8,objective='binary:logistic',nthread=4,min_child_weight=5,seed=27),param_grid=best_param, scoring='roc_auc', iid=False, cv=10)best_gsearch.fit(self.x_train, self.y_train)print("best_param:{0}".format(best_gsearch.best_params_))print("best_score:{0}".format(best_gsearch.best_score_))# best_param: {'max_depth': 7, 'n_estimators': 45}# best_score: 0.9627551020408163return best_gsearch.best_params_passdef best_lr_gamma(self):# np.arange 可以生成 float 类型,range 只能生成 int 类型best_param = {'learning_rate': np.arange(0.1, 1.1, 0.1),'gamma': np.arange(0.1, 5.1, 0.2)}best_gsearch = GridSearchCV(estimator=XGBClassifier(n_estimators=45,max_depth=7,# learning_rate=0.1,# gamma=0,subsample=0.8,colsample_bytree=0.8,objective='binary:logistic',nthread=4,min_child_weight=5,seed=27),param_grid=best_param, scoring='roc_auc', iid=False, cv=10)best_gsearch.fit(self.x_train, self.y_train)print("best_param:{0}".format(best_gsearch.best_params_))print("best_score:{0}".format(best_gsearch.best_score_))# best_param: {'gamma': 4.500000000000001, 'learning_rate': 0.6}# best_score: 0.9671996144784749return best_gsearch.best_params_passdef best_subsmaple_bytree(self):# np.arange 可以生成 float 类型,range 只能生成 int 类型# 调整subsample(行),colsample_bytree(列)best_param = {'subsample': np.arange(0.1, 1.1, 0.1),'colsample_bytree': np.arange(0.1, 1.1, 0.1)}best_gsearch = GridSearchCV(estimator=XGBClassifier(n_estimators=45,max_depth=7,learning_rate=0.6,gamma=4.5,# subsample=1.0,# colsample_bytree=0.8,objective='binary:logistic',nthread=4,min_child_weight=5,seed=27),param_grid=best_param, scoring='roc_auc', iid=False, cv=10)best_gsearch.fit(self.x_train, self.y_train)print("best_param:{0}".format(best_gsearch.best_params_))print("best_score:{0}".format(best_gsearch.best_score_))# best_param: {'colsample_bytree': 0.8, 'subsample': 0.9}# best_score: 0.9680867346938775return best_gsearch.best_params_passdef best_nthread_weight(self):# np.arange 可以生成 float 类型,range 只能生成 int 类型best_param = {'nthread': range(1, 20, 1),'min_child_weight': range(1, 20, 1)}best_gsearch = GridSearchCV(estimator=XGBClassifier(n_estimators=45,max_depth=7,learning_rate=0.1,gamma=4.3,subsample=0.9,colsample_bytree=0.8,objective='binary:logistic',# nthread=4,# min_child_weight=5,seed=27),param_grid=best_param, scoring='roc_auc', iid=False, cv=10)best_gsearch.fit(self.x_train, self.y_train)print("best_param:{0}".format(best_gsearch.best_params_))print("best_score:{0}".format(best_gsearch.best_score_))# best_param: {'min_child_weight': 2, 'nthread': 1}# best_score: 0.9648386521025202return best_gsearch.best_params_passdef best_seek(self):# np.arange 可以生成 float 类型,range 只能生成 int 类型best_param = {'seed': range(1, 500, 1)}best_gsearch = GridSearchCV(estimator=XGBClassifier(n_estimators=45,max_depth=7,learning_rate=0.1,gamma=4.3,subsample=0.9,colsample_bytree=0.8,nthread=1,min_child_weight=2,# seed=27,objective='binary:logistic'),param_grid=best_param, scoring='roc_auc', iid=False, cv=10)best_gsearch.fit(self.x_train, self.y_train)print("best_param:{0}".format(best_gsearch.best_params_))print("best_score:{0}".format(best_gsearch.best_score_))# best_param: {'seed': 134}# best_score: 0.9773406154065825return best_gsearch.best_params_pass# 较好的 模型参数 进行训练def best_param_xgboost(self):best_model = XGBClassifier(n_estimators=45,max_depth=7,learning_rate=0.1,gamma=4.3,subsample=0.9,colsample_bytree=0.8,nthread=1,min_child_weight=2,seed=134,objective='binary:logistic')best_model.fit(self.x_train, self.y_train)y_pred = best_model.predict(self.x_val)acc_score = metrics.accuracy_score(self.y_val, y_pred)print("acc_score: {}".format(acc_score))print("score: {}".format(best_model.score(self.x_val, self.y_val)))print("AUC Score: {}".format(metrics.roc_auc_score(self.y_val, y_pred)))y_proba = best_model.predict_proba(self.x_val)# 预测为 0 的概率y_zero = y_proba[:, 0]# 预测为 1 的概率y_one = y_proba[:, 1]print("AUC Score2: {}".format(metrics.roc_auc_score(self.y_val, y_one)))# 得到误判率、命中率、门限fpr, tpr, thresholds = metrics.roc_curve(self.y_val, y_one)# 计算aucroc_auc = metrics.auc(fpr, tpr)# 对ROC曲线图正常显示做的参数设定# 用来正常显示中文标签, 上面设置过# plt.rcParams['font.sans-serif'] = ['SimHei']# 用来正常显示负号plt.rcParams['axes.unicode_minus'] = Falseplt.plot(fpr, tpr, label='{0}_AUC = {1:.5f}'.format("xgboost", roc_auc))plt.title('ROC曲线')plt.xlim([-0.05, 1.05])plt.ylim([-0.05, 1.05])plt.legend(loc='lower right')plt.plot([0, 1], [0, 1], 'r--')plt.ylabel('命中率: TPR')plt.xlabel('误判率: FPR')plt.show()passif __name__ == "__main__":demo = XGBoostDemo()# demo.best_estimators_depth()# demo.best_lr_gamma()# demo.best_subsmaple_bytree()# demo.best_nthread_weight()# demo.best_seek()demo.best_param_xgboost()pass
在代码中,我们不难发现,xgboost 利用 二阶求导,迭代次数明显下降了很多,而且,精度也提高了。xgboost,在目前的这集成学习里面,算是比较顶级的方法。所以,在生产当中,如果需要用到机器学习中的集成学习方法,我们一般优先选择 xgboost 算法来对业务进行实现。
在接下来下一章,我将用实例,讲解现实生产中,用xgboost 进行 训练和预测。
返回主目录
返回集成学习目录
上一章:机器篇——集成学习(六) 细说 GBDT 算法
下一章:机器篇——集成学习(八) 细说 ball49_pred 项目(彩票预测)