赞
踩
XGBoost是eXtreme Gradient Boosting的缩写,它是一个十分强大的Boosting算法工具包。XGBoost在并行计算效率、缺失值解决、抑制过拟合、预测泛化能力上都变现十分优良。
XGBoost安装基于pip就能够轻松实现:
pip install xgboost
应用XGBoost的第一步,需要加载所需的数据成为工具库所能支持的格式形态。XGBoost可以加载多种数据格式的数据用于训练建模:
XGBoost的SKLearn接口也支持对于Dataframe格式的数据。
下面是不同格式的数据,XGBoost的加载方式。
加载libsvm格式的数据:
dtrain1 = xgb.DMatrix('train.svm.txt')
加载二进制的缓存文件:
dtrain2 = xgb.DMatrix('train.svm.buffer')
加载numpy的数组:
data = np.random.rand(5,10) # 5 entities, each contains 10 features
label = np.random.randint(2, size=5) # binary target
dtrain = xgb.DMatrix( data, label=label)
将scipy.sparse格式的数据转化为 DMatrix 格式:
csr = scipy.sparse.csr_matrix( (dat, (row,col)) )
dtrain = xgb.DMatrix( csr )
将DMatrix格式的数据保存成XGBoost的二进制格式,在下次加载时可以提高加载速度,使用方式如下:
dtrain = xgb.DMatrix('train.svm.txt')
dtrain.save_binary("train.buffer")
可以用如下方式处理DMatrix中的缺失值:
dtrain = xgb.DMatrix( data, label=label, missing = -999.0)
当需要给样本设置权重时,可以用如下方式:
w = np.random.rand(5,1)
dtrain = xgb.DMatrix( data, label=label, missing = -999.0, weight=w)
XGBoost内置了建模方式,有如下的数据格式与核心训练方法:
下面是官方的一个简单示例,演示了读取libsvm格式数据(成DMatrix格式)并指定参数建模的过程。
# 导入工具库 import numpy as np import scipy.sparse import pickle import xgboost as xgb # 从libsvm文件中读取数据,做二分类 # 数据是libsvm的格式,如下样本格式 #1 3:1 10:1 11:1 21:1 30:1 34:1 36:1 40:1 41:1 53:1 58:1 65:1 69:1 77:1 86:1 88:1 92:1 95:1 102:1 105:1 117:1 124:1 #0 3:1 10:1 20:1 21:1 23:1 34:1 36:1 39:1 41:1 53:1 56:1 65:1 69:1 77:1 86:1 88:1 92:1 95:1 102:1 106:1 116:1 120:1 #0 1:1 10:1 19:1 21:1 24:1 34:1 36:1 39:1 42:1 53:1 56:1 65:1 69:1 77:1 86:1 88:1 92:1 95:1 102:1 106:1 116:1 122:1 dtrain = xgb.DMatrix('./data/agaricus.txt.train') dtest = xgb.DMatrix('./data/agaricus.txt.test') # 超参数设定 # 主要是树深、学习率、目标函数 param = {'max_depth':2, 'eta':1, 'silent':1, 'objective':'binary:logistic' } # 设定watchlist用于建模过程中观测模型状态 watchlist = [(dtest,'eval'), (dtrain,'train')] num_round = 2 bst = xgb.train(param, dtrain, num_round, watchlist) # 使用模型预测 preds = bst.predict(dtest) # 判断准确率 labels = dtest.get_label() print('错误率为%f' % \ (sum(1 for i in range(len(preds)) if int(preds[i]>0.5)!=labels[i]) /float(len(preds)))) # 模型存储 bst.save_model('./model/0001.model')
输出为:
[0] eval-error:0.042831 train-error:0.046522
[1] eval-error:0.021726 train-error:0.022263
错误率为0.021726
下面的例子,输入的数据源是csv文件,我们使用大家熟悉的pandas工具库把数据读取为Dataframe格式,再构建Dmatrix格式输入,后续使用内置建模方式进行训练。
# 皮马印第安人糖尿病数据集 包含很多字段:怀孕次数 口服葡萄糖耐量试验中血浆葡萄糖浓度 舒张压(mm Hg) 三头肌组织褶厚度(mm)
# 2小时血清胰岛素(μU/ ml) 体重指数(kg/(身高(m)^2) 糖尿病系统功能 年龄(岁)
import pandas as pd
data = pd.read_csv('./data/Pima-Indians-Diabetes.csv')
data.head()
# 导入工具库 import numpy as np import pandas as pd import pickle import xgboost as xgb from sklearn.model_selection import train_test_split # 用pandas读入数据 data = pd.read_csv('./data/Pima-Indians-Diabetes.csv') # 做数据切分 train, test = train_test_split(data) # 转换成Dmatrix格式 feature_columns = ['Pregnancies', 'Glucose', 'BloodPressure', 'SkinThickness', 'Insulin', 'BMI', 'DiabetesPedigreeFunction', 'Age'] target_column = 'Outcome' # 取出Dataframe的numpy数组值去初始化DMatrix对象 xgtrain = xgb.DMatrix(train[feature_columns].values, train[target_column].values) xgtest = xgb.DMatrix(test[feature_columns].values, test[target_column].values) #参数设定 param = {'max_depth':5, 'eta':0.1, 'silent':1, 'subsample':0.7, 'colsample_bytree':0.7, 'objective':'binary:logistic' } # 设定watchlist用于查看模型状态 watchlist = [(xgtest,'eval'), (xgtrain,'train')] num_round = 10 bst = xgb.train(param, xgtrain, num_round, watchlist) # 使用模型预测 preds = bst.predict(xgtest) # 判断准确率 labels = xgtest.get_label() print('错误类为%f' % \ (sum(1 for i in range(len(preds)) if int(preds[i]>0.5)!=labels[i]) /float(len(preds)))) # 模型存储 bst.save_model('./model/0002.model')
输出为:
[0] eval-error:0.354167 train-error:0.194444
[1] eval-error:0.34375 train-error:0.170139
[2] eval-error:0.322917 train-error:0.170139
[3] eval-error:0.28125 train-error:0.161458
[4] eval-error:0.302083 train-error:0.147569
[5] eval-error:0.286458 train-error:0.138889
[6] eval-error:0.296875 train-error:0.142361
[7] eval-error:0.291667 train-error:0.144097
[8] eval-error:0.302083 train-error:0.130208
[9] eval-error:0.291667 train-error:0.130208
错误类为0.291667
XGBoost也支持用SKLearn中统一的预估器形态接口进行建模,如下为典型的参考案例,对于读取为Dataframe格式的训练集和测试集,可以直接使用XGBoost初始化XGBClassifier进行fit拟合训练。使用方法与接口,和SKLearn中其他预估器一致。
# 导入工具库 import numpy as np import pandas as pd import pickle import xgboost as xgb from sklearn.model_selection import train_test_split # 用pandas读入数据 data = pd.read_csv('./data/Pima-Indians-Diabetes.csv') # 做数据切分 train, test = train_test_split(data) # 特征列 feature_columns = ['Pregnancies', 'Glucose', 'BloodPressure', 'SkinThickness', 'Insulin', 'BMI', 'DiabetesPedigreeFunction', 'Age'] # 标签列 target_column = 'Outcome' # 初始化模型 xgb_classifier = xgb.XGBClassifier(n_estimators=20,\ max_depth=4, \ learning_rate=0.1, \ subsample=0.7, \ colsample_bytree=0.7, \ eval_metric='error') # Dataframe格式数据拟合模型 xgb_classifier.fit(train[feature_columns], train[target_column]) # 使用模型预测 preds = xgb_classifier.predict(test[feature_columns]) # 判断准确率 print('错误类为%f' %((preds!=test[target_column]).sum()/float(test_y.shape[0]))) # 模型存储 joblib.dump(xgb_classifier, './model/0003.model')
输出为:
错误类为0.265625
['./model/0003.model']
在运行XGBoost之前,必须设置三种类型参数:general parameters,booster parameters和task parameters:
objective [ default=reg:linear ]
base_score [ default=0.5 ]
eval_metric [ default according to objective ]
seed [ default=0 ]
随机数的种子。缺省值为0
XGBoost自带实验与调参的一些方法,如下为交叉验证方法xgb.cv。
xgb.cv(param, dtrain, num_round, nfold=5,metrics={'error'}, seed = 0)
我们可以把数据建模过程中的一些设置加到交叉验证环节里,比如对于不同类别的样本加权,可以参考下列代码示例:
# 计算正负样本比,调整样本权重
def fpreproc(dtrain, dtest, param):
label = dtrain.get_label()
ratio = float(np.sum(label == 0)) / np.sum(label==1)
param['scale_pos_weight'] = ratio
return (dtrain, dtest, param)
# 先做预处理,计算样本权重,再做交叉验证
xgb.cv(param, dtrain, num_round, nfold=5,
metrics={'auc'}, seed = 0, fpreproc = fpreproc)
XGBoost支持在训练过程中,自定义损失函数和评估准则,其中损失函数的定义需要返回损失函数一阶和二阶导数的计算方法,评估准则部分需要对数据的label和预估值进行计算。其中损失函数用于训练过程中的树结构学习,而评估准则很多时候是用在验证集上进行效果评估。
print('使用自定义损失函数进行交叉验证') # 自定义损失函数,需要提供损失函数的一阶导和二阶导 def logregobj(preds, dtrain): labels = dtrain.get_label() preds = 1.0 / (1.0 + np.exp(-preds)) grad = preds - labels hess = preds * (1.0-preds) return grad, hess # 自定义评估准则,评估预估值和标准答案之间的差距 def evalerror(preds, dtrain): labels = dtrain.get_label() return 'error', float(sum(labels != (preds > 0.0))) / len(labels) watchlist = [(dtest,'eval'), (dtrain,'train')] param = {'max_depth':3, 'eta':0.1, 'silent':1} num_round = 5 # 自定义损失函数训练 bst = xgb.train(param, dtrain, num_round, watchlist, logregobj, evalerror) # 交叉验证 xgb.cv(param, dtrain, num_round, nfold = 5, seed = 0, obj = logregobj, feval=evalerror)
输出为:
使用自定义损失函数进行交叉验证
[0] eval-rmse:0.306901 train-rmse:0.306164 eval-error:0.518312 train-error:0.517887
[1] eval-rmse:0.179189 train-rmse:0.177278 eval-error:0.518312 train-error:0.517887
[2] eval-rmse:0.172565 train-rmse:0.171728 eval-error:0.016139 train-error:0.014433
[3] eval-rmse:0.269612 train-rmse:0.27111 eval-error:0.016139 train-error:0.014433
[4] eval-rmse:0.396903 train-rmse:0.398256 eval-error:0.016139 train-error:0.014433
对于boosting模型来说,最后会训练得到很多基学习器(在XGBoost中很多时候是很多棵树),我们可以一次完整训练,只用前n棵树的集成来完成预测。
#!/usr/bin/python import numpy as np import pandas as pd import pickle import xgboost as xgb from sklearn.model_selection import train_test_split # 基本例子,从csv文件中读取数据,做二分类 # 用pandas读入数据 data = pd.read_csv('./data/Pima-Indians-Diabetes.csv') # 做数据切分 train, test = train_test_split(data) # 转换成Dmatrix格式 feature_columns = ['Pregnancies', 'Glucose', 'BloodPressure', 'SkinThickness', 'Insulin', 'BMI', 'DiabetesPedigreeFunction', 'Age'] target_column = 'Outcome' xgtrain = xgb.DMatrix(train[feature_columns].values, train[target_column].values) xgtest = xgb.DMatrix(test[feature_columns].values, test[target_column].values) #参数设定 param = {'max_depth':5, 'eta':0.1, 'silent':1, 'subsample':0.7, 'colsample_bytree':0.7, 'objective':'binary:logistic' } # 设定watchlist用于查看模型状态 watchlist = [(xgtest,'eval'), (xgtrain,'train')] num_round = 10 bst = xgb.train(param, xgtrain, num_round, watchlist) # 只用第1颗树预测 ypred1 = bst.predict(xgtest, ntree_limit=1) # 用前9颗树预测 ypred2 = bst.predict(xgtest, ntree_limit=9) label = xgtest.get_label() print('用前1颗树预测的错误率为 %f' % (np.sum((ypred1>0.5)!=label) /float(len(label)))) print('用前9颗树预测的错误率为 %f' % (np.sum((ypred2>0.5)!=label) /float(len(label))))
输出:
[0] eval-error:0.255208 train-error:0.196181
[1] eval-error:0.234375 train-error:0.175347
[2] eval-error:0.25 train-error:0.163194
[3] eval-error:0.229167 train-error:0.149306
[4] eval-error:0.213542 train-error:0.154514
[5] eval-error:0.21875 train-error:0.152778
[6] eval-error:0.21875 train-error:0.154514
[7] eval-error:0.213542 train-error:0.138889
[8] eval-error:0.1875 train-error:0.147569
[9] eval-error:0.1875 train-error:0.144097
用前1颗树预测的错误率为 0.255208
用前9颗树预测的错误率为 0.187500
XGBoost有SKLearn预估器形态的接口,整体使用方法和SKLearn中其他预估器一致,如下是手动对数据做交叉验证,注意到这里直接使用XGBClassifier对Dataframe数据进行fit拟合和评估。
import pickle import xgboost as xgb import numpy as np from sklearn.model_selection import KFold, train_test_split, GridSearchCV from sklearn.metrics import confusion_matrix, mean_squared_error from sklearn.datasets import load_iris, load_digits, load_boston rng = np.random.RandomState(31337) # 二分类:混淆矩阵 print("数字0和1的二分类问题") digits = load_digits(2) y = digits['target'] X = digits['data'] # 数据切分对象 kf = KFold(n_splits=2, shuffle=True, random_state=rng) print("在2折数据上的交叉验证") # 2折交叉验证 for train_index, test_index in kf.split(X): xgb_model = xgb.XGBClassifier().fit(X[train_index],y[train_index]) predictions = xgb_model.predict(X[test_index]) actuals = y[test_index] print("混淆矩阵:") print(confusion_matrix(actuals, predictions)) #多分类:混淆矩阵 print("\nIris: 多分类") iris = load_iris() y = iris['target'] X = iris['data'] kf = KFold(n_splits=2, shuffle=True, random_state=rng) print("在2折数据上的交叉验证") for train_index, test_index in kf.split(X): xgb_model = xgb.XGBClassifier().fit(X[train_index],y[train_index]) predictions = xgb_model.predict(X[test_index]) actuals = y[test_index] print("混淆矩阵:") print(confusion_matrix(actuals, predictions)) #回归问题:MSE print("\n波士顿房价回归预测问题") boston = load_boston() y = boston['target'] X = boston['data'] kf = KFold(n_splits=2, shuffle=True, random_state=rng) print("在2折数据上的交叉验证") for train_index, test_index in kf.split(X): xgb_model = xgb.XGBRegressor().fit(X[train_index],y[train_index]) predictions = xgb_model.predict(X[test_index]) actuals = y[test_index] print("MSE:",mean_squared_error(actuals, predictions))
输出为:
数字0和1的二分类问题 在2折数据上的交叉验证 混淆矩阵: [[87 0] [ 1 92]] 混淆矩阵: [[91 0] [ 3 86]] Iris: 多分类 在2折数据上的交叉验证 混淆矩阵: [[19 0 0] [ 0 31 3] [ 0 1 21]] 混淆矩阵: [[31 0 0] [ 0 16 0] [ 0 3 25]] 波士顿房价回归预测问题 在2折数据上的交叉验证 MSE: 9.860776812557337 MSE: 15.942418468446029
上面提到XGBoost的预估器接口,整体使用方法和SKLearn中其他预估器一致,所以我们也可以使用SKLearn中的超参数调优方法来进行模型调优。
如下是一个典型的网格搜索交法调优超参数的代码示例,我们会给出候选参数列表字典,通过GridSearchCV进行交叉验证实验评估,选出XGBoost在候选参数中最优的超参数。
print(“参数最优化:”)
y = boston['target']
X = boston['data']
xgb_model = xgb.XGBRegressor()
clf = GridSearchCV(xgb_model,
{'max_depth': [2,4,6],
'n_estimators': [50,100,200]}, verbose=1)
clf.fit(X,y)
print(clf.best_score_)
print(clf.best_params_)
输出为:
参数最优化:
Fitting 3 folds for each of 9 candidates, totalling 27 fits
[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
0.6001029721598573
{'max_depth': 4, 'n_estimators': 100}
[Parallel(n_jobs=1)]: Done 27 out of 27 | elapsed: 1.3s finished
XGBoost模型有时候会因为不停叠加新的树(修正训练集上拟合尚不正确的一些样本),可能会因为对于训练集过度学习而导致模型过拟合。early stopping早停止是一个有效的策略,具体的做法是,在训练集不断追加树学习的过程中,对验证集上的表现进行监控,如果出现一定轮次评估准则都没有优化提升的情况,则回溯到历史上验证集最好的点,保存为最佳模型。
下面是对应的代码示例,其中参数early_stopping_rounds设定了验证集上能接受的效果不提升的最多轮次数,eval_set指定了验证数据集。
# 在训练集上学习模型,一颗一颗树添加,在验证集上看效果,当验证集效果不再提升,停止树的添加与生长
X = digits['data']
y = digits['target']
X_train, X_val, y_train, y_val = train_test_split(X, y, random_state=0)
clf = xgb.XGBClassifier()
clf.fit(X_train, y_train, early_stopping_rounds=10, eval_metric="auc",
eval_set=[(X_val, y_val)])
输出为:
[0] validation_0-auc:0.999497 Will train until validation_0-auc hasn't improved in 10 rounds. [1] validation_0-auc:0.999497 [2] validation_0-auc:0.999497 [3] validation_0-auc:0.999749 [4] validation_0-auc:0.999749 [5] validation_0-auc:0.999749 [6] validation_0-auc:0.999749 [7] validation_0-auc:0.999749 [8] validation_0-auc:0.999749 [9] validation_0-auc:0.999749 [10] validation_0-auc:1 [11] validation_0-auc:1 [12] validation_0-auc:1 [13] validation_0-auc:1 [14] validation_0-auc:1 [15] validation_0-auc:1 [16] validation_0-auc:1 [17] validation_0-auc:1 [18] validation_0-auc:1 [19] validation_0-auc:1 [20] validation_0-auc:1 Stopping. Best iteration: [10] validation_0-auc:1 XGBClassifier(base_score=0.5, booster='gbtree', colsample_bylevel=1, colsample_bytree=1, gamma=0, learning_rate=0.1, max_delta_step=0, max_depth=3, min_child_weight=1, missing=None, n_estimators=100, n_jobs=1, nthread=None, objective='binary:logistic', random_state=0, reg_alpha=0, reg_lambda=1, scale_pos_weight=1, seed=None, silent=True, subsample=1)
XGBoost建模过程中,还可以学习到对应的特征重要度信息,并保存在模型的feature_importances_属性中。如下为绘制特征重要度的可视化代码:
iris = load_iris() y = iris['target'] X = iris['data'] xgb_model = xgb.XGBClassifier().fit(X,y) print('特征排序:') feature_names=['sepal_length', 'sepal_width', 'petal_length', 'petal_width'] feature_importances = xgb_model.feature_importances_ indices = np.argsort(feature_importances)[::-1] for index in indices: print("特征 %s 重要度为 %f" %(feature_names[index], feature_importances[index])) %matplotlib inline import matplotlib.pyplot as plt plt.figure(figsize=(16,8)) plt.title("feature importances") plt.bar(range(len(feature_importances)), feature_importances[indices], color='b') plt.xticks(range(len(feature_importances)), np.array(feature_names)[indices], color='b')
输出为:
特征排序:
特征 petal_length 重要度为 0.415567
特征 petal_width 重要度为 0.291557
特征 sepal_length 重要度为 0.179420
特征 sepal_width 重要度为 0.113456
在多资源的情况下,XGBoost可以实现并行训练加速,示例代码如下:
import os if __name__ == "__main__": try: from multiprocessing import set_start_method except ImportError: raise ImportError("Unable to import multiprocessing.set_start_method." " This example only runs on Python 3.4") #set_start_method("forkserver") import numpy as np from sklearn.model_selection import GridSearchCV from sklearn.datasets import load_boston import xgboost as xgb rng = np.random.RandomState(31337) print("Parallel Parameter optimization") boston = load_boston() os.environ["OMP_NUM_THREADS"] = "2" # or to whatever you want y = boston['target'] X = boston['data'] xgb_model = xgb.XGBRegressor() clf = GridSearchCV(xgb_model, {'max_depth': [2, 4, 6], 'n_estimators': [50, 100, 200]}, verbose=1, n_jobs=2) clf.fit(X, y) print(clf.best_score_) print(clf.best_params_)
输出为:
Parallel Parameter optimization
Fitting 3 folds for each of 9 candidates, totalling 27 fits
[Parallel(n_jobs=2)]: Using backend LokyBackend with 2 concurrent workers.
[Parallel(n_jobs=2)]: Done 24 out of 27 | elapsed: 2.2s remaining: 0.3s
0.6001029721598573
{'max_depth': 4, 'n_estimators': 100}
[Parallel(n_jobs=2)]: Done 27 out of 27 | elapsed: 2.4s finished
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。