参考文献:Dataworkshop
XGBoost
全称
extreme gradient boost
regularized gradient boost
它用于监督学习问题,比如:分类、回归和排序。
XGBoost方法详解-知乎
在经典的决策树算法中,ID3的目标函数是基于“信息熵”,CART的目标函数是基于“GINI系数”,
XGBoost的目标函数引入了“偏差”这个变量。
GBDT与XGBoost之间的区别是:前者使用梯度下降法(所以只有一次导数)求参数,后者使用牛顿法(使用到了损失函数的二次导数);
如何高效地生成一棵决策树?
在XGBoost中,利用贪心算法生成一棵树,从而提高了效率。
贪心算法:每一步都选择当前最优,从而达到全局最优解。
在决策树生成的背景下,其表述为“保证每一次节点的分裂产生的新树,都是目标函数最小的”。
如何判断是否应该分裂一个节点?
分裂后的树的目标函数值小于分裂前的树的目标函数值。如果增益太小,那么做这次分裂,会带来更大的负面影响——增加模型复杂度,所以下面模型中会有个惩罚项,从而避免这种情况发生。
上面选择了最佳特特征进行划分,下面要考虑对于这个最佳特征,用于划分特征输入空间的最佳特征值是什么。
XGBoost采用加权分位法来做。
对选定最佳分裂特征的特征值进行“重要性”排序,根据排序的结果,选出值得尝试分裂的特征值。
特征值的重要性排名,
在我们得到了使用加权分位法的分裂点之后,在贪心算法的分裂过程中,我们就只需要对这几个分裂点进行尝试,而不需要与原先一样,对所有的特征值进行尝试。这大大减少了算法的开销。
基于加权分位法,我们有两种策略进行分裂点的计算:1、全局策略;2、局部策略
全局策略:生成树之前,就计算好了所有特征的分裂点,如此一来,开销比较低;缺点是如果分裂点比较少,准确率是不够的;
局部策略:因地制宜,在节点处,根据该节点所包含的样本计算所有特征的分裂点。每个节点所包含的样本不同,这些样本的特征值也是不同的。对每个结点重新计算分裂结点,以保证准确性。优点是,分裂点数目不用太多,也能达到一定的准确率;缺点是,开销比较大。
-
全局策略和局部策略的对比
分裂点数目相同时,局部策略在AUC指标上优于全局策略;
分裂点数目越多,两个策略的效果越好;
全局策略可以通过增加分裂点的数目,达到逼近局部策略的效果。 -
步骤
- 基于贪心算法进行划分,计算目标函数增益,选择该节点使用哪个特征
- 为了提高算法效率,使用“加权分位法”,计算分裂点,只考虑分裂点的目标函数值,而不是该特征的所有特征值。
- 可以选择“全局策略”或“局部策略”,计算分裂点。
XGBoost对缺失值的处理方法,
以对第k个特征为例,把第k个特征为缺失值的样本选出来;然后,对剩余样本进行划分;最后,看把缺失值全部放在“左节点”,放在“右节点”哪个增益大,就代表这个特征最好的划分。
如果训练集有缺失值,那么在训练过程中会指定这些缺失值去哪边(左边还是右边),在预测阶段测试集的缺失值也会去到那一边;
如果训练集没有缺失值,那么在预测阶段测试集中的缺失值会被默认分到左子树上(这是默认方向)。
XGBoost关于缺失值处理的小细节
XGBoost方法及其实战 - 知乎
XGBoost方法的参数调整及其含义
min_child_weight这个参数可以用来控制过拟合,当节点上的所有样本的权重和小于min_child_weight时,停止该节点的分裂,这个节点变成了叶节点。
收缩率,弱学习器的权重值,目的是防止过拟合。值越小,越减少过拟合。
超参数的训练,
XGBoost的缺点:
基于预排序方法的决策树算法
步骤:先对所有特征排序,找用于分裂的特征,再找一个特征上最好的分割点,然后将数据分裂成左右子节点。
优点是,能精确找到分割点;
缺点是,空间消耗很大(不仅保存数据的特征值,还保存特征排序的结果,以便于后续计算分割点);
LightGBM,
为了解决GBDT每次训练都需要所有训练数据而造成效率比较低的问题,LightGBM在传统GBDT算法上做了优化。
GBDT对同一层的叶子不加区分,带来了一些没必要的开销。实际上,很多叶子的分裂增益较低,没必要搜索和分裂。LightGBM使用了带深度限制的leaf-wise的叶子生长算法。
listGBM支持类别特征
详细代码,见jupyter文件xgboost_study2(已经附上了)
- 数据项描述
datetime - hourly date + timestamp
season - 1 = spring, 2 = summer, 3 = fall, 4 = winter
holiday - whether the day is considered a holiday
workingday - whether the day is neither a weekend nor holiday
weather -
1: Clear, Few clouds, Partly cloudy, Partly cloudy
2: Mist + Cloudy, Mist + Broken clouds, Mist + Few clouds, Mist
3: Light Snow, Light Rain + Thunderstorm + Scattered clouds, Light Rain + Scattered clouds
4: Heavy Rain + Ice Pallets + Thunderstorm + Mist, Snow + Fog
temp - temperature in Celsius
atemp - “feels like” temperature in Celsius
humidity - relative humidity
windspeed - wind speed
casual - number of non-registered user rentals initiated
registered - number of registered user rentals initiated
count - number of total rentals
下面简要记录文件的思路
内容:使用xgboost方法,根据特征数据预测count,registered,casual等响应变量,其中count=registed+casual
。
首先,从 datetime
数据中提取出day,hour,dayofweek,weekend
等信息,作为特征;
然后,
- 尝试了以下几种方法去预测
- 使用 原数据的特征 直接预测
count
; - 使用 原数据的特征 间接预测
count
:具体地,首先使用XGBoost预测registed
和casual
,然后,二者加和得到count
的预测值; - 使用 原数据的特征 间接预测
count
:具体地,首先使用XGBoost预测log(count)
,然后,取对数得到count
的预测值; - 使用 原数据的特征 间接预测
count
:具体地,首先使用XGBoost预测log(registed+1)
和log(casual+1)
(考虑到registered
,casual
可能取值为0),然后,二者取对数-1,再加和,得到count
的预测值; - 使用 原数据的特征的衍生特征(得到的数据集train_magic) 直接预测
count
;
比较上述所有方法的relative mean square log error.
-
与其他方法作对比
取“relative mean square log error”为性能指标(越小越好),比较XGBoost与随机森林、Adaboost,Bagging等其他机器学习集成方法的性能。 -
调参
除了网格搜索调参,这个项目还展示了贝叶斯优化方法搜索超参数的使用:具体地,调用python第三方库的使用hyperopt
。
remark:
小心过拟合
对比:
决策树虽然可解释性比较好,但是表现比较差;
集成学习方法:将弱分类器组成成强分类器,具体地,如随机森林、提升法.
日后再补……
数据分析的流程
详细代码见文件share_bicycle_demand(已经附上了)
数据还是上面的数据,学习的材料还是源自DataWorkShop这个github主。
下面简要罗列一下原作者的分析流程和一些细节。
数据预处理
首先,用.info检查数据的类型;
然后,使用.isnull().values.sum()
检查数据中有无缺失值;
数据可视化部分包括:
对比不同年份,各个小时租用量的趋势;
对比是否为工作日,各个小时租用量的趋势;
对比不同年,月租用量的趋势;(绘制了箱线图和柱形图)
对比不同年,各个小时租用量的趋势。(绘制了箱线图和柱形图)
特征工程
删除掉方差比较小的特征、使用SelectKBest
,chi2
,RFE
等方法选择比较重要的特征。具体地,对于不同的模型,重要特征也不同。所以,要为每个模型选择它专属的重要特征。
模型的选择
这里尝试了随机森林、adaboost,梯度提升等集成学习方法,为每一个模型方法选择他们的最优特征集合,然后训练模型,并预测count指标,打印出score。
比较这几种方法的score值,得出 梯度提升方法表现比较好。
进一步的特征工程
从时间项中分离出来”是否周末“、”对应季节的平均租用量“等信息加入到模型中
间接预测目标值
对预测值count,registered,casual等,先取对数,得到count_log,reg_log,casual_log。
然后,分别以count_log,reg_log,casual_log为训练目标值,以X_train为训练特征,训练模型,
接着,将测试集的特征信息X_test作为输入,带入到模型中,分别得到预测值
c
o
u
n
t
l
o
g
^
\hat{count_{log}}
countlog^,
r
e
g
l
o
g
^
\hat{reg_{log}}
reglog^,
c
a
s
u
a
l
l
o
g
^
\hat{casual_{log}}
casuallog^;
然后,对这三个预测值分别取指数,得到预测值
c
o
u
n
t
^
\hat{count}
count^,
r
e
g
^
\hat{reg}
reg^,
c
a
s
u
a
l
^
\hat{casual}
casual^。
线性组合三种集成模型得到最终结果
见’def modeling’函数
def modeling(models,data,n_folds=3): # linear combination of several ensumble models,like rondomForest,GradientBoost,XGBoost
scores=[]
kf=KFold(n_splits=n_folds)
for n_fold,(train_idx,test_idx) in enumerate(kf.split(data)):
print("n_fold: ",n_fold)
y_pred = np.array([0.]*len(test_idx))# !! you can't write it as [0]
for weight_for_model,feats,model in models:
X=data[feats].values
X_train,X_test = X[train_idx],X[test_idx]
y_reg_train = data['registered_log'][train_idx].astype('float')
y_cas_train = data['casual_log'][train_idx].astype('float')
y_test=data['count'][test_idx].astype('float')
model.fit(X_train,y_reg_train)
y_pred_reg_log = model.predict(X_test)
y_pred_reg=np.exp2(y_pred_reg_log)-1
model.fit(X_train,y_cas_train)
y_pred_cas_log = model.predict(X_test)
y_pred_cas=np.exp2(y_pred_cas_log)-1
y_pred+=weight_for_model*(y_pred_reg+y_pred_cas)
score=rmsle(y_test,y_pred)
scores.append(score)
print("score:{0}, std-score:{1}".format(round(np.mean(scores),5),round(np.std(scores),4)))
xgb_params={'n_estimators':150,'learning_rate':0.1,'max_depth':5,'subsample':0.6,'colsample_bytree':0.8}
xgb_model = xgb.XGBRegressor(**xgb_params)
gb_params={'n_estimators':150,'max_depth':5,'random_state':0,'min_samples_leaf':10,'learning_rate':0.1,'subsample':0.7,'loss':'squared_error'}
gb_model=GradientBoostingRegressor(**gb_params)
rf_params={'n_estimators':1000,'max_depth':15,'random_state':0,'random_state':0,'min_samples_split':5,'n_jobs':-1}
rf_model=RandomForestRegressor(**rf_params)
xgb_feats = ['weather', 'temp', 'atemp', 'humidity', 'windspeed', 'holiday', 'workingday', 'season','hour', 'dayofweek', 'year']
gb_feats = ['weather', 'temp', 'atemp', 'humidity', 'windspeed', 'holiday', 'workingday', 'season','hour', 'dayofweek', 'year']
rf_feats = ['weather', 'temp', 'atemp', 'windspeed','workingday', 'season', 'holiday', 'hour', 'dayofweek', 'rush_hour', 'peak']
models=[
(0.8*0.7,xgb_feats,xgb_model),
(0.8*0.3,gb_feats,gb_model),
(0.2,rf_feats,rf_model)
]
modeling(models,df_all[~df_all['is_test']])#trainData from df_all
代码二:贝叶斯优化调参
预测目标,选 “count”列
Final result: {
‘target’: -150.1472393766906,
‘params’: {‘colsample_bytree’: 0.876888634776859, ‘max_depth’: 7.698877185131134, ‘min_child_weight’: 21.89595721880947, ‘subsample’: 0.9967855924737787}}
D:\PyCharm2020\myven2v\Scripts\python.exe D:/PyCharm2020/myven2v/xgboost-lightgbm-hyperparameter-tuning-master/bayesHyper_Study4.py
Mem. usage decreases to 0.19Mb, (71.9% reduction)
| iter | target | colsam... | max_depth | min_ch... | subsample |
-------------------------------------------------------------------------
[0] train-rmse:261.13659 test-rmse:266.44075
[200] train-rmse:170.31282 test-rmse:176.45617
.....
[600] train-rmse:142.63274 test-rmse:144.69786
[800] train-rmse:140.60119 test-rmse:144.21686
[999] train-rmse:139.24480 test-rmse:144.12899
| 22 | -150.2 | 0.9441 | 8.174 | 25.37 | 0.793 |
=========================================================================
0.0 hours 4.0 minutes 12.809617000000003 seconds
Final result: {'target': -150.03965155427224, 'params': {'colsample_bytree': 0.9653678768627341, 'max_depth': 6.021691581706388, 'min_child_weight': 24.016201688956542, 'subsample': 0.7312737130360377}}
Process finished with exit code 0