模型调优
XGBoost有一些参数可以显著影响模型的准确性和训练速度。 应该了解的第一个参数是:n_estimators and early_stopping_roundsn_estimators 指定训练循环次数。
early_stopping_rounds 提供了一种自动查找理想值的方法。 early_stopping_rounds会导致模型在validation score停止改善时停止迭代,即使迭代次数还没有到n_estimators。为n_estimators设置一个高值然后使用early_stopping_rounds来找到停止迭代的最佳时间是明智的。
存在随机的情况有时会导致validation score无法改善,因此需要指定一个数字,以确定在停止前允许多少轮退化。early_stopping_rounds = 5是一个合理的值。 因此,在五轮validation score无法改善之后训练将停止。 以下是early_stopping的代码:
my_model = XGBRegressor(n_estimators=1000) my_model.fit(train_X, train_y, early_stopping_rounds=5, eval_set=[(test_X, test_y)], verbose=False) predictions = my_model.predict(test_X) from sklearn.metrics import mean_absolute_error print("Mean Absolute Error : " + str(mean_absolute_error(predictions, test_y)))
当使用early_stopping_rounds时,需要留出一些数据来检查要使用的轮数。 如果以后想要使所有数据拟合模型,请将n_estimators设置为在早期停止运行时发现的最佳值。
learning_rate
对于更好的XGBoost模型,这是一个微妙但重要的技巧:
XGBoost模型不是通过简单地将每个组件模型中的预测相加来获得预测,而是在将它们添加之前将每个模型的预测乘以一个小数字。这意味着我们添加到集合中的每个树都不会对最后结果有决定性的影响。在实践中,这降低了模型过度拟合的倾向。
因此,使用一个较大的n_estimators值并不会造成过拟合。如果使用early_stopping_rounds,树的数量会被设置成一个合适的值。
通常,较小的learning rate(以及大量的estimators)将产生更准确的XGBoost模型,但是由于它在整个循环中进行更多迭代,因此也将使模型更长时间进行训练。 包含学习率的代码如下:
my_model = XGBRegressor(n_estimators=1000, learning_rate=0.05) my_model.fit(train_X, train_y, early_stopping_rounds=5, eval_set=[(test_X, test_y)], verbose=False) predictions = my_model.predict(test_X) from sklearn.metrics import mean_absolute_error print("Mean Absolute Error : " + str(mean_absolute_error(predictions, test_y)))
实战
实战基于数据集 AllstateClaimsSeverity (Kaggle2016竞赛) :
官网:https://www.kaggle.com/c/allstate-claims-severity/overview
基于给出的数据预测保险赔偿。给出的训练数据是116列(cat1-cat116)的离散数据和14列(con1-con14)的连续数据。
import pandas as pd import numpy as np import matplotlib.pyplot as plt from sklearn.linear_model import LogisticRegression from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import roc_auc_score as AUC from sklearn.metrics import mean_absolute_error from sklearn.decomposition import PCA from sklearn.preprocessing import LabelEncoder,LabelBinarizer from sklearn.model_selection import cross_val_score from scipy import stats import seaborn as sns from copy import deepcopy %matplotlib inline %config InlineBackend.figure_format = 'retina'
加载数据
train = pd.read_csv('allstate-claims-severity/train.csv') test = pd.read_csv('allstate-claims-severity/test.csv')
观察数据,看看数据是啥样的
train.shape # (188318, 132)
输出训练数据,查看数据内容
train
print('First 20 columns:',list(train.columns[:20])) print('Last 20 columns:',list(train.columns[-20:])) First 20 columns: ['id', 'cat1', 'cat2', 'cat3', 'cat4', 'cat5', 'cat6', 'cat7', 'cat8', 'cat9', 'cat10', 'cat11', 'cat12', 'cat13', 'cat14', 'cat15', 'cat16', 'cat17', 'cat18', 'cat19'] Last 20 columns: ['cat112', 'cat113', 'cat114', 'cat115', 'cat116', 'cont1', 'cont2', 'cont3', 'cont4', 'cont5', 'cont6', 'cont7', 'cont8', 'cont9', 'cont10', 'cont11', 'cont12', 'cont13', 'cont14', 'loss']
观察得到:一共有 object 类型属性 116 个,float64 属性15个,int64 属性 1 个,其中 id 是int64,loss 赔偿是 float64.
train.describe()
查看缺失值
大多情况,我们都需要对数据进行缺失值处理。
pd.isnull(train).values.any()# False 表示没有缺失值 连续值与离散值 train.info() #类型以及数量:float64(15), int64(1), object(116) <class 'pandas.core.frame.DataFrame'> RangeIndex: 188318 entries, 0 to 188317 Columns: 132 entries, id to loss dtypes: float64(15), int64(1), object(116) memory usage: 189.7+ MB
查看离散特征和连续特征个数
cat_features = list(train.select_dtypes(include=['object'])) print('离散特征Categorical: {} features'.format(len(cat_features))) 离散特征Categorical: 116 features cont_features = [cont for cont in list(train.select_dtypes(include=['float64','int64'])) if cont not in ['loss','id']] print('连续特征Continuous: {} features'.format(len(cont_features)))
连续特征Continuous: 14 features
id_col = list(train.select_dtypes(include=['int64'])) print('A column of int64:{}'.format(id_col))
类别值中属性的个数
#统计类别属性中不同类别的个数
cat_uniques=[]
for cat in cat_features:
cat_uniques.append(len(train[cat].unique()))
uniq_values_in_categories = pd.DataFrame.from_dict([('cat_name',cat_features),('unique_values',cat_uniques)])
uniq_values_in_categories.head()
赔偿值
plt.figure(figsize=(16,8)) plt.plot(train['id'],train['loss']) print('train[\'id\']个数:',len(train['id'])) plt.title('Loss values per id') plt.xlabel('id') plt.ylabel('loss') plt.legend() plt.show()
如上图所示,损失值有几个显著的峰值,表示严重事故。这样的数据分布,使得这个功能非常扭曲导致回归表现不佳。
基本上,偏度 度量了实值随机变量的均值分布的不对称性,下面让我们来计算一下loss的偏度:
#scipy.stats 统计指标。 stats.mstats.skew(train['loss']).data #输出:array(3.79492815) 偏度值比1大,说明数据是倾斜的。不利于数据建模。我们利用对数变换np.log,使倾斜降低。 stats.mstats.skew(np.log(train['loss'])).data #输出:array(0.0929738)
两种 loss 分布对比:
fig, (ax1, ax2) = plt.subplots(1,2) fig.set_size_inches(16,5) ax1.hist(train['loss'], bins=50) ax1.set_title('Train Loss target histogram') ax1.grid(True) ax2.hist(np.log(train['loss']), bins=50, color='g') ax2.set_title("Train Log Loss target histogram") ax2.grid(True) plt.show()
特征之间的相关性
plt.subplots(figsize=(16,9)) correlation_mat = train[cont_features].corr() sns.heatmap(correlation_mat,annot=True)
XGBoost 调参策略
导入依赖
import pandas as pd import numpy as np import xgboost as xgb import pickle import sys import matplotlib.pyplot as plt from sklearn.metrics import make_scorer from sklearn.metrics import mean_absolute_error from sklearn.preprocessing import LabelEncoder,LabelBinarizer from sklearn.model_selection import cross_val_score from sklearn.model_selection import KFold,train_test_split from xgboost import XGBRegressor import warnings warnings.filterwarnings('ignore') %matplotlib inline %config InlineBackend.figure_format = 'retina'
数据预处理
train = pd.read_csv('allstate-claims-severity/train.csv') train['log_loss']=np.log(train['loss']) features = [x for x in train.columns if x not in ['id','loss','log_loss']] cat_features =[x for x in train.select_dtypes(include = ['object']) if x not in ['id','loss','log_loss']] num_features =[x for x in train.select_dtypes(exclude = ['object']) if x not in ['id','loss','log_loss']] print('离散特征Categorical: {} features'.format(len(cat_features))) print('Numerical:{} features'.format(len(num_features))) features 离散特征 Categorical: 116 features Numerical:14 features ['cat1', 'cat2', 'cat3', 'cat4', 'cat5', 'cat6', 'cat7', 'cat8', 'cat9', 'cat10', 'cat11', 'cat12', 'cat13', 'cat14', 'cat15', 'cat16', 'cat17', 'cat18', 'cat19', 'cat20', 'cat21', 'cat22', 'cat23', 'cat24', 'cat25', 'cat26', 'cat27', 'cat28', 'cat29', 'cat30', 'cat31', 'cat32', 'cat33', 'cat34', 'cat35', 'cat36', 'cat37', 'cat38', 'cat39', 'cat40', 'cat41', 'cat42', 'cat43', 'cat44', 'cat45', 'cat46', 'cat47', 'cat48', 'cat49', 'cat50', 'cat51', 'cat52', 'cat53', 'cat54', 'cat55', 'cat56', 'cat57', 'cat58', 'cat59', 'cat60', 'cat61', 'cat62', 'cat63', 'cat64', 'cat65', 'cat66', 'cat67', 'cat68', 'cat69', 'cat70', 'cat71', 'cat72', 'cat73', 'cat74', 'cat75', 'cat76', 'cat77', 'cat78', 'cat79', 'cat80', 'cat81', 'cat82', 'cat83', 'cat84', 'cat85', 'cat86', 'cat87', 'cat88', 'cat89', 'cat90', 'cat91', 'cat92', 'cat93', 'cat94', 'cat95', 'cat96', 'cat97', 'cat98', 'cat99', 'cat100', 'cat101', 'cat102', 'cat103', 'cat104', 'cat105', 'cat106', 'cat107', 'cat108', 'cat109', 'cat110', 'cat111', 'cat112', 'cat113', 'cat114', 'cat115', 'cat116', 'cont1', 'cont2', 'cont3', 'cont4', 'cont5', 'cont6', 'cont7', 'cont8', 'cont9', 'cont10', 'cont11', 'cont12', 'cont13', 'cont14'] ntrain = train.shape[0] #ntrain = 188318 train_x = train[features] train_y = train['log_loss'] for c in range(len(cat_features)): train_x[cat_features[c]] = train_x[cat_features[c]].astype('category').cat.codes print('Xtrain:',train_x.shape) # Xtrain: (188318, 130) print('ytrain:',train_y.shape) # ytrain: (188318,) train_x
注:.cat.codes
我有一个名为language的数据框 lang level 0 english intermediate 1 spanish intermediate 2 spanish basic 3 english basic 4 english advanced 5 spanish intermediate 6 spanish basic 7 spanish advanced 我使用 language.lang.astype('category').cat.codes 以及 language.level.astype('category').cat.codes 分别是。获取以下数据帧: lang level 0 0 1 1 1 1 2 1 0 3 0 0 4 0 2 5 1 1 6 1 0 7 1 2
Simple XGBoost Model
首先,我们训练一个基本的xgboost模型,然后进行参数调节通过交叉验证来观察结果的变换,使用平均绝对误差衡量 mean_absolute_error(np.exp(y),np.exp(yhat))。
xgboost 自定义一个数据矩阵类 DMatrix,会在训练开始时,进行一边预处理,从而提高之后每次迭代的效率。
结果衡量方法
#评估策略,e的次幂,用来评估。 #结果衡量方法:使用平均绝对误差来衡量 #mean_absolute_error(np.exp(y), np.exp(yhat))。 #定义计算损失值的函数 def xg_eval_mae(yhat,dtrain): y = dtrain.get_label() return 'mae',mean_absolute_error(np.exp(y),np.exp(yhat))
XGBoost 参数调节
Step 1: 选择一组初始参数 Step 2: 改变 max_depth 和 min_child_weight. Step 3: 调节 gamma 降低模型过拟合风险. Step 4: 调节 subsample 和 colsample_bytree 改变数据采样策略. Step 5: 调节学习率 eta.
class XGBoostRegressor(object): def __init__(self, **kwargs): self.params = kwargs if 'num_boost_round' in self.params: self.num_boost_round = self.params['num_boost_round'] self.params.update({'silent': 1, 'objective': 'reg:linear', 'seed': 0})#默认参数 def fit(self, x_train, y_train): ''' #数据类型转换,#用参数去训练xgboost模型 ''' dtrain = xgb.DMatrix(x_train, y_train) self.bst = xgb.train(params=self.params, dtrain=dtrain, num_boost_round=self.num_boost_round, feval=xg_eval_mae, maximize=False) def predict(self, x_pred): dpred = xgb.DMatrix(x_pred) self.bst = xgb.train(params=self.params, dtrain=dtrain, num_boost_round=self.num_boost_round, feval=xg_eval_mae, maximize=False) return self.bst.predict(dpred) def kfold(self, x_train, y_train, nfold=5): dtrain = xgb.DMatrix(x_train, y_train) cv_rounds = xgb.cv(params=self.params, dtrain=dtrain, num_boost_round=self.num_boost_round, nfold=nfold, feval=xg_eval_mae, maximize=False, early_stopping_rounds=10) return cv_rounds.iloc[-1,:] def plot_feature_importances(self): feat_imp = pd.Series(self.bst.get_fscore()).sort_values(ascending=False) feat_imp.plot(title='Feature Importances') plt.ylabel('Feature Importance Score') def get_params(self, deep=True): return self.params def set_params(self, **params): self.params.update(params) return self #衡量标准 def mae_score(y_true, y_pred): return mean_absolute_error(np.exp(y_true), np.exp(y_pred)) mae_scorer = make_scorer(mae_score, greater_is_better=False) bst = XGBoostRegressor(eta=0.1, colsample_bytree=0.5, subsample=0.5, max_depth=5, min_child_weight=3, num_boost_round=50) bst.kfold(train_x, train_y, nfold=5) train-rmse-mean 0.558938 train-rmse-std 0.001005 test-rmse-mean 0.562665 test-rmse-std 0.002445 train-mae-mean 1209.707324 train-mae-std 3.004207 test-mae-mean 1218.884204 test-mae-std 8.982969 Name: 49, dtype: float64