文章目录
XGBoost库实际上就是对GBDT 算法的一种优化的实现,XGBoost是机器学习中准确率最高的算法了,下面我将详细介绍XGBoost库的使用。
XGBoost有两种类型的Python API,一种是原生的,一种是为了方便 sklearn 库的开发人员设计的 sklearn 风格的API,在这里我会简单介绍下原生API的流程和参数,更加推荐大家使用sklearn风格的API。
1. 原生API
1.1 读取数据
import xgboost as xgb
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import numpy as np
# 使用sklearn的数据集生成函数
from sklearn.datasets._samples_generator import make_classification
# X为样本特征,y为样本类别输出, 共10000个样本,每个样本20个特征,输出有2个类别,没有冗余特征,每个类别一个簇
X, y = make_classification(n_samples=10000, n_features=20, n_redundant=0,
n_clusters_per_class=1, n_classes=2, flip_y=0.1)
# 分割训练集测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)
dtrain = xgb.DMatrix(X_train,y_train)
dtest = xgb.DMatrix(X_test,y_test)
1.2 设置参数
XGBoost 的参数设置采用的是键值对,即 key : value
的形式,设置如下:
params = {
'booster': 'gbtree',
'objective': 'binary:logistic',# 二分类的问题
'gamma': 0.1, # 用于控制是否后剪枝的参数,越大越保守,一般0.1、0.2这样子。
'max_depth': 12, # 构建树的深度,越大越容易过拟合
'lambda': 2, # 控制模型复杂度的权重值的L2正则化项参数,参数越大,模型越不容易过拟合。
'subsample': 0.7, # 随机采样训练样本
'colsample_bytree': 0.7, # 生成树时进行的列采样
'min_child_weight': 3, # 最小子节点的权重
'verbosity': 2, # 设置成2则输出详细信息
'eta': 0.001, # 如同学习率
'seed': 1000,
'nthread': 4, # cpu 线程数
}
注意, objective
中写了二分类问题后,就不能再写问题的分类数量 num_class=2
了,否则会报错。
1.3 训练模型
# 迭代的次数
num_rounds = 100
model = xgb.train(params, dtrain, num_rounds)
1.4 模型预测
# 对测试集进行预测
y_pred = model.predict(dtest)
y_pred = (y_pred > 0.5).astype(np.int32)
accuracy = accuracy_score(y_test,y_pred)
print("accuarcy: %.2f%%" % (accuracy*100.0))
1.5 保存、读取模型
# 保存模型
model.save_model('0001.model')
# 加载保存的模型:
bst = xgb.Booster({'nthread': 4}) # init model
bst.load_model('0001.model') # load data
2. sklearn风格API
对sklearn不清楚的朋友可以看我的上一篇博文对sklearn了解一下。
XGBoost在sklearn风格中的参数可以直接在初始化类时就写进去,如sklearn的逻辑回归参数形式 LogisticRegression(solver='saga', multi_class='auto', random_state=42, max_iter=10000)
一样。
2.1 sklearn风格分类
我们这里对sklearn中的鸢尾花数据集进行分类,代码如下:
from sklearn.datasets import load_iris
import xgboost as xgb
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=1234565) # 数据集分割
# 训练模型
model = xgb.XGBClassifier(max_depth=5, learning_rate=0.1, n_estimators=160, silent=True, objective='multi:softmax')
model.fit(X_train, y_train)
# 对测试集进行预测
y_pred = model.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test,y_pred)
print("accuarcy: %.2f%%" % (accuracy*100.0))
可以看到,XGBoost 完美的融入到了 sklearn 的流程当中,sklearn使用不同的算法只需要将初始化的估计器改个名字就行,这对XGBoost也是一样的。
2.2 sklearn风格回归
这里我们使用sklearn数据集中的波士顿房价来当做示例。
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.datasets import load_boston
boston = load_boston()
X,y = boston.data,boston.target
# XGBoost训练过程
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
model = xgb.XGBRegressor(max_depth=5, learning_rate=0.1, n_estimators=160, silent=True, objective='reg:gamma')
model.fit(X_train, y_train)
# 对测试集进行预测
ans = model.predict(X_test)
2.3 XGBoost 参数说明
XGBoost在原生API以及sklearn风格中的参数如下所示。
sklearn API参数 | 原生API参数 | 默认值 | 含义 | 说明 |
---|---|---|---|---|
n_estimators | num_round | 子学习器个数 | boosting框架下的子学习器数量。在原生API中,该参数在train方法中定义,也即最大迭代次数 | |
learning_rate | eta | 0.3 | 学习率 | 用于限制子学习器的过拟合,提高模型的泛化能力,与n_estimators配合使用 |
verbosity | verbosity | 1 | 是否输出详细信息,2是输出详细信息,1是偶尔输出,0是不输出 | |
subsample | eta | 0.3 | 样本子采样数 | 用于限制子学习器的过拟合,提高模型的泛化能力,与n_estimators配合使用 |
max_depth | max_depth | 6 | 树的最大深度 | 对基学习器函数空间的正则化,一种预修剪手段 |
objective | objective | 损失函数 | 自定义的损失函数,通过申明合适的损失函数来处理分类、回归和排序问题。常见的方法包括线性回归‘reg:linear’、逻辑回归’reg:logistic’、二分类逻辑回归’binary:logistic’,多分类’multi:softmax’,平方误差reg:squarederror 等 | |
booster | booster | gbtree | 基学习器类型 | xgboost中采用的基学习器,如梯度提升树’gbtree’,梯度提升线性模型’gblinear’等 |
gamma | gamma | 0 | 分裂阈值 | 即最小损失分裂,用来控制分裂遵循的结构分数提升下限阈值。 |
min_child_weight | gamin_child_weightma | 叶子节点最小权重 | 叶子节点允许的最小权重值(即节点中所有样本的二阶导数值之和),可视为是对叶子节点的正则化,是一种后剪枝的手段。 | |
reg_alpha | alpha | 0 | L1正则化系数 | 对集成模型进行L1正则化(以子节点的个数为约束)的系数 |
reg_lambda | lambda | 0 | L2正则化系数 | 对集成模型进行L2正则化(以子节点权重w的平方和为约束)的系数 |
nthread | n_jobs | 最大并发线程数 | 最大并发线程数 | |
random_state | seed | 随机种子 | 控制模型的随机性。 | |
missing | missing | None | 为缺失值进行标注。默认为None,即标注为np.nan。 |
除了上述模型,在xgboost的 fit
方法中,还涉及到几个重要参数:
(1)sample_weight
:表示样本权重
(2)eval_set
:在训练的同时进行验证的数据集
(3)eval_metric
:验证集的评价指标
(4)early_stopping_rounds
: 根据模型在验证集表现的早停轮数阈值。具体而言,若模型在连续early_stopping_rounds
次迭代过程中,其在eval_set上的eval_metric并无提升,则模型停止迭代。
3. XGBoost 调参
XGBoost 的调参主要集中在以下几个参数,未提到的参数都可以使用系统的默认值。
objective
在回归问题objective
一般使用reg:squarederror
,即MSE均方误差。二分类问题一般使用binary:logistic
, 多分类问题一般使用multi:softmax
。max_depth
控制树结构的深度,数据少或者特征少的时候可以不管这个值。如果模型样本量多,特征也多的情况下,需要限制这个最大深度,具体的取值一般要网格搜索调参。常用3-10
之间。min_child_weight
最小的子节点权重阈值,如果某个树节点的权重小于这个阈值,则不会再分裂子树,即这个树节点就是叶子节点。这个值需要网格搜索寻找最优值.gamma
XGBoost的决策树分裂所带来的损失减小阈值。这个值也需要网格搜索寻找最优值。subsample
选择小于1的比例可以减少方差,即防止过拟合,但是会增加样本拟合的偏差,因此取值不能太低。初期可以取值1,如果发现过拟合后可以网格搜索调参找一个相对小一些的值,典型的范围在0.5-0.9
之间n_estimators
`n_estimators则是非常重要的要调的参数,它关系到我们XGBoost模型的复杂度,因为它代表了我们决策树弱学习器的个数。这个参数对应sklearn GBDT的n_estimators。n_estimators太小,容易欠拟合,n_estimators太大,模型会过于复杂,一般需要调参选择一个适中的数值。learning_rate
学习率,理想的学习率一般在0.05-0.3
之间,一般情况为0.1,。colsample_bytree
用来控制每棵随机采样的列数的占比(每一列是一个特征)。 典型值:0.5-1
之间。reg_lambda
权重的L2正则化项。(和Ridge regression类似)。这个参数是用来控制XGBoost的正则化部分的。这个参数在减少过拟合上很有帮助。reg_alpha
权重的L1正则化项。(和Lasso regression类似)。 可以应用在很高维度的情况下,使得算法的速度更快。
上面这些参数都是需要调参的,不过一般先调 max_depth
,min_child_weight
和 gamma
。如果发现有过拟合的情况下,再尝试调后面几个参数。
以下为一个网格搜索的例子:
import xgboost as xgb
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score
train_data = pd.read_csv('train.csv') # 读取数据
y = train_data.pop('30').values # 用pop方式将训练数据中的标签值y取出来,作为训练目标,这里的‘30’是标签的列名
col = train_data.columns
x = train_data[col].values # 剩下的列作为训练数据
train_x, valid_x, train_y, valid_y = train_test_split(x, y, test_size=0.333, random_state=0) # 分训练集和验证集
# 这里不需要Dmatrix
parameters = {
'max_depth': [5, 10, 15, 20, 25],
'learning_rate': [0.01, 0.02, 0.05, 0.1, 0.15],
'n_estimators': [500, 1000, 2000, 3000, 5000],
'min_child_weight': [0, 2, 5, 10, 20],
'max_delta_step': [0, 0.2, 0.6, 1, 2],
'subsample': [0.6, 0.7, 0.8, 0.85, 0.95],
'colsample_bytree': [0.5, 0.6, 0.7, 0.8, 0.9],
'reg_alpha': [0, 0.25, 0.5, 0.75, 1],
'reg_lambda': [0.2, 0.4, 0.6, 0.8, 1],
'scale_pos_weight': [0.2, 0.4, 0.6, 0.8, 1]
}
xlf = xgb.XGBClassifier(max_depth=10,
learning_rate=0.01,
n_estimators=2000,
verbosity=2,
objective='binary:logistic',
nthread=-1,
gamma=0,
min_child_weight=1,
max_delta_step=0,
subsample=0.85,
colsample_bytree=0.7,
colsample_bylevel=1,
reg_alpha=0,
reg_lambda=1,
scale_pos_weight=1,
seed=1440,
missing=None)
# 有了gridsearch我们便不需要fit函数
gsearch = GridSearchCV(xlf, param_grid=parameters, scoring='accuracy', cv=3)
gsearch.fit(train_x, train_y)
print("Best score: %0.3f" % gsearch.best_score_)
print("Best parameters set:")
best_parameters = gsearch.best_estimator_.get_params()
for param_name in sorted(parameters.keys()):
print("\t%s: %r" % (param_name, best_parameters[param_name]))
Reference
[1] https://blog.youkuaiyun.com/guofei_fly/article/details/103569388
[2] https://www.cnblogs.com/pinard/p/11114748.html
[3] https://www.jianshu.com/p/1100e333fcab
[4] https://cloud.tencent.com/developer/article/2070965
[5] https://zhuanlan.zhihu.com/p/143009353?utm_source=ZHShareTargetIDMore