美文网首页
集成学习之xgboost、lightGBM、CatBoost、N

集成学习之xgboost、lightGBM、CatBoost、N

作者: Andy9918 | 来源:发表于2021-04-10 23:46 被阅读0次

集成学习

Boosting,与Bagging一样,使用的相同的弱学习器,不过是以自适应的方法顺序地学习这些弱学习器,即每个新学习器都依赖于前面的模型,并按照某种确定性的策略将它们组合起来
两个重要的 Boosting 算法:AdaBoost(自适应提升)和Gradient Boosting(梯度提升)
AdaBoost,使用前面的学习器用简单的模型去适配数据,然后分析错误。然后会给予错误预测的数据更高权重,然后用后面的学习器去修复
Boosting通过把一些列的弱学习器串起来,组成一个强学习器

Boosting与Bagging:

结构上,Bagging是基分类器并行处理,而Boosting是串行处理
训练集,Bagging的基分类器训练是独立的,而Boosting的训练集是依赖于之前的模型
作用,Bagging的作用是减少variance,而Boosting在于减少bias
对于Bagging,对样本进行重采样,通过重采样得到的子样本集训练模型,最后取平均。因为子样本集的相似性,而且使用相同的弱学习器,因此每个学习器有近似相等的bias和variance,因为每个学习器相互独立,所以可以显著降低variance,但是无法降低bias
对于Boosting,采用顺序的方式最小化损失函数,所以bias自然是逐步下降,子模型之和不能显著降低variance

Gradient Boosting集成学习神器:

XGBoost, LightGBM, CatBoost, NGBoost实际上是对GBDT方法的不同实现,针对同一目标、做了不同的优化处理

XGBoost

论文:
https://arxiv.org/abs/1603.02754

XGBoost基学习器:CART回归树

目标函数

目标函数=损失函数 + 正则化项
Obj(Θ)=L(Θ) + Ω(Θ)
L(Θ)为损失函数
Ω(Θ)为正则化项,用于惩罚复杂模型

Ω(f_t)误差函数尽量拟合训练数据,正则化项鼓励简单的模型
用于控制树的复杂度,防止过拟合,使得模型更简化,也使得最终的模型的预测结果更稳定
Ω(f_t)=γT + \frac{1}{2}λ\sum_{j=1}^Tw_j^2
T:叶子数量
w_j:叶子分数的L2正则项
γ:加入新叶子节点引入的复杂度代价

Tree Ensemble 集成学习 :
单个CART回归树过于简单,可以通过多个CART回归树组成一个强学习器
预测函数,样本的预测结果=每棵树预测分数之和
\hat y_i=\sum_{k=1}^Kf_k(x_i)

目标函数:
Obj(\Theta)=\sum_{i}l(y_i,\hat y_i)+\sum\Omega(f_k)
\Omega (f)=γT+\frac{1}{2}λ||w||^2
正则项是由叶子结点的数量和叶子结点权重的平方和决定。

XGBoost目标函数:
Obj(Θ)=L(l(y_i,\hat y_i^{(t-1)}+f_t(x_i)) + Ω(f_t)+constant

Obj 目标函数也称为结构分数(打分函数),代表当指定一个树的结构的时候,我们在目标上最多可以减少多少

XGBoost的分裂节点算法:
贪心方法,获取最优分割节点(split point)


将所有样本按照gi从小到大排序,通过遍历,查看每个节点是否需要分割
对于特征值的个数为n时,总共有n−1种划分
Step1,对样本扫描一遍,得出GL,GR
Step2,根据Gain的分数进行分割
通过贪心法,计算效率得到大幅提升,XGBoost重新定义划分属性,即Gain,而Gain的计算是由目标损失函数obj决定的

对于连续型特征值,样本数量非常大,该特征取值过多时,遍历所有取值会花费很多时间,且容易过拟合
方法,在寻找split节点的时候,不会枚举所有的特征值,而会对特征值进行聚合统计,然后形成若干个bucket(桶),只将bucket边界上的特征值作为split节点的候选,从而获得性能提升
从算法伪代码中该流程还可以分为两种,全局的近似是在新生成一棵树之前就对各个特征计算分位点并划分样本,之后在每次分裂过程中都采用近似划分,而局部近似就是在具体的某一次分裂节点的过程中采用近似算法

XGBoost算法特点:

XGBoost将树模型的复杂度加入到正则项中,从而避免过拟合,泛化性能好
损失函数是用泰勒展开式展开的,用到了一阶导和二阶导,可以加快优化速度
在寻找最佳分割点时,采用近似贪心算法,用来加速计算
不仅支持CART作为基分类器,还支持线性分类器,在使用线性分类器的时候可以使用L1,L2正则化
支持并行计算,XGBoost的并行是基于特征计算的并行,将特征列排序后以block的形式存储在内存中,在后面的迭代中重复使用这个结构。在进行节点分裂时,计算每个特征的增益,选择增益最大的特征作为分割节点,各个特征的增益计算可以使用多线程并行
优点:速度快、效果好、能处理大规模数据、支持自定义损失函数等
缺点:算法参数过多,调参复杂,不适合处理超高维特征数据

XGBoost工具:

https://github.com/dmlc/xgboost
参数分为:
通用参数:对系统进行控制
Booster参数:控制每一步的booster(tree/regression)
学习目标参数:控制训练目标的表现
通用参数:
booster,模型选择,gbtree或者gblinear。gbtree使用基于树的模型进行提升计算,gblinear使用线性模型进行提升计算。[default=gbtree]
silent,缄默方式,0表示打印运行时,1表示以缄默方式运行,不打印运行时信息。[default=0]
nthread,XGBoost运行时的线程数,[default=缺省值是当前系统可以获得的最大线程数]
num_feature,boosting过程中用到的特征个数,XGBoost会自动设置
Booster参数:
eta [default=0.3],为了防止过拟合,更新过程中用到的收缩步长。在每次提升计算之后,算法会直接获得新特征的权重。 eta通过缩减特征的权重使提升计算过程更加保守,取值范围为[0,1]
gamma [default=0],分裂节点时,损失函数减小值只有大于等于gamma节点才分裂,gamma值越大,算法越保守,越不容易过拟合,但性能就不一定能保证,需要trade off,取值范围 [0,∞]
max_depth [default=6] ,树的最大深度,取值范围为[1,∞],典型值为3-10
min_child_weight [default=1],一个子集的所有观察值的最小权重和。如果新分裂的节点的样本权重和小于min_child_weight则停止分裂 。这个可以用来减少过拟合,但是也不能太高,会导致欠拟合,取值范围为[0,∞]
subsample [default=1],构建每棵树对样本的采样率,如果设置成0.5,XGBoost会随机选择50%的样本作为训练集
colsample_bytree [default=1],列采样率,也就是特征采样率
lambda [default=1, alias: reg_lambda],L2正则化,用来控制XGBoost的正则化部分
alpha [default=0, alias: reg_alpha],L1正则化,增加该值会让模型更加收敛
scale_pos_weight [default=1],在类别高度不平衡的情况下,将参数设置大于0,可以加快收敛

学习目标参数:
objective [ default=reg:linear ],定义学习目标,reg:linear,reg:logistic,binary:logistic,binary:logitraw,count:poisson,multi:softmax,multi:softprob,rank:pairwise
eval_metric,评价指标,包括rmse,logloss,error,merror,mlogloss,auc,ndcg,map等
seed[ default=0 ],随机数的种子
dtrain,训练的数据
num_boost_round,提升迭代的次数,也就是生成多少基模型
early_stopping_rounds,早停法迭代次数
evals:这是一个列表,用于对训练过程中进行评估列表中的元素。形式是evals = [(dtrain,'train'),(dval,'val')]或者是evals = [(dtrain,'train')],对于第一种情况,它使得我们可以在训练过程中观察验证集的效果
verbose_eval ,如果为True,则对evals中元素的评估输出在结果中;如果输入数字,比如5,则每隔5个迭代输出一次
learning_rates:每一次提升的学习率的列表

天猫用户复购预测(XGBoost使用示意)

X_train, X_valid, y_train, y_valid = train_test_split(train_X, train_y, test_size=.2)
# 使用XGBoost
model = xgb.XGBClassifier(
    max_depth=8, #树的最大深度
    n_estimators=1000, #提升迭代的次数,也就是生成多少基模型
    min_child_weight=300, #一个子集的所有观察值的最小权重和
    colsample_bytree=0.8, #列采样率,也就是特征采样率
    subsample=0.8, #构建每棵树对样本的采样率
    eta=0.3,    # eta通过缩减特征的权重使提升计算过程更加保守,防止过拟合
    seed=42    #随机数种子
)
model.fit(
    X_train, y_train,
    eval_metric='auc', eval_set=[(X_train, y_train), (X_valid, y_valid)],
    verbose=True,
    #早停法,如果auc在10epoch没有进步就stop
    early_stopping_rounds=10 
)
model.fit(X_train, y_train)
prob = model.predict_proba(test_data)

模型参数配置:

param = {'boosting_type':'gbdt',
                         'objective' : 'binary:logistic', #任务目标
                         'eval_metric' : 'auc', #评估指标
                         'eta' : 0.01, #学习率
                         'max_depth' : 15, #树最大深度
                         'colsample_bytree':0.8, #设置在每次迭代中使用特征的比例
                         'subsample': 0.9, #样本采样比例
                         'subsample_freq': 8, #bagging的次数
                         'alpha': 0.6, #L1正则
                         'lambda': 0, #L2正则
        }

模型训练,得出预测结果:

X_train, X_valid, y_train, y_valid = train_test_split(train.drop('Attrition',axis=1), train['Attrition'], test_size=0.2, random_state=42)
train_data = xgb.DMatrix(X_train, label=y_train)
valid_data = xgb.DMatrix(X_valid, label=y_valid)
test_data = xgb.DMatrix(test)
model = xgb.train(param, train_data, evals=[(train_data, 'train'), (valid_data, 'valid')], num_boost_round = 10000, early_stopping_rounds=200, verbose_eval=25)
predict = model.predict(test_data)
test['Attrition']=predict
# 转化为二分类输出
test['Attrition']=test['Attrition'].map(lambda x:1 if x>=0.5 else 0)
test[['Attrition']].to_csv('submit_lgb.csv')

LightGBM:

2017年经微软推出,XGBoost的升级版
Kaggle竞赛使用最多的模型之一,必备机器学习神器
Light => 在大规模数据集上运行效率更高
GBM => Gradient Boosting Machine
Motivation:
常用的机器学习算法,例如神经网络等算法,都可以以mini-batch的方式训练,训练数据的大小不会受到内存限制
GBDT在每一次迭代的时候,都需要遍历整个训练数据多次。如果把整个训练数据装进内存则会限制训练数据的大小;如果不装进内存,反复地读写训练数据又会消耗非常大的时间。对于工业级海量的数据,普通的GBDT算法是不能满足其需求的
LightGBM的提出是为了解决GBDT在海量数据遇到的问题,让GBDT可以更好更快地用于工业场景

LightGBM与XGBoost:
模型精度:两个模型相当
训练速度:LightGBM训练速度更快 => 1/10
内存消耗:LightGBM占用内存更小 => 1/6
特征缺失值:两个模型都可以自动处理特征缺失值
分类特征:XGBoost不支持类别特征,需要对其进行OneHot编码,而LightGBM支持分类特征

XGBoost模型的复杂度:
模型复杂度 = 树的棵数 X 每棵树的叶子数量 X 每片叶子生成复杂度
每片叶子生成复杂度 = 特征数量 X 候选分裂点数量 X 样本的数量
针对XGBoost的优化:
Histogram算法,直方图算法 => 减少候选分裂点数量
GOSS算法,基于梯度的单边采样算法 => 减少样本的数量
EFB算法,互斥特征捆绑算法 => 减少特征的数量
LightGBM = XGBoost + Histogram + GOSS + EFB

XGBoost的预排序(pre-sorted)算法:
将样本按照特征取值排序,然后从全部特征取值中找到最优的分裂点位
预排序算法的候选分裂点数量=样本特征不同取值个数减1

LightGBM的Histogram算法:
替代XGBoost的预排序算法
思想是先连续的浮点特征值离散化成k个整数,同时构造一个宽度为k的直方图,即将连续特征值离散化到k个bins上(比如k=255)
当遍历一次数据后,直方图累积了需要的统计量,然后根据直方图的离散值,遍历寻找最优的分割点
XGBoost需要遍历所有离散化的值,LightGBM只要遍历k个直方图的值
候选分裂点数量 = k-1

GOSS算法:
Gradient-based One-Side Sampling,基于梯度的单边采样算法
思想是通过样本采样,减少目标函数增益Gain的计算复杂度
单边采样,只对梯度绝对值较小的样本按照一定比例进行采样,而保留了梯度绝对值较大的样本
因为目标函数增益主要来自于梯度绝对值较大的样本 => GOSS算法在性能和精度之间进行了很好的trade off

EFB算法:
Exclusive Feature Bundling,互斥特征绑定算法
思想是特征中包含大量稀疏特征的时候,减少构建直方图的特征数量,从而降低计算复杂度
数据集中通常会有大量的稀疏特征(大部分为0,少量为非0)我们认为这些稀疏特征是互斥的,即不会同时取非零值
EFB算法可以通过对某些特征的取值重新编码,将多个这样互斥的特征绑定为一个新的特征
类别特征可以转换成onehot编码,这些多个特征的onehot编码是互斥的,可以使用EFB将他们绑定为一个特征
在LightGBM中,可以直接将每个类别取值和一个bin关联,从而自动地处理它们,也就无需预处理成onehot编码

LightGBM工具:

import lightgbm as lgb
官方文档:http://lightgbm.readthedocs.io/en/latest/Python-Intro.html
参数:

boosting_type,训练方式,gbdt
objective,目标函数,可以是binary,regression
metric,评估指标,可以选择auc, mae,mse,binary_logloss,multi_logloss
max_depth,树的最大深度,当模型过拟合时,可以降低 max_depth
min_data_in_leaf,叶子节点最小记录数,默认20

Bagging参数:bagging_fraction+bagging_freq(需要同时设置)
bagging_fraction,每次迭代时用的数据比例,用于加快训练速度和减小过拟合
bagging_freq:bagging的次数。默认为0,表示禁用bagging,非零值表示执行k次bagging,可以设置为3-5
feature_fraction,设置在每次迭代中使用特征的比例,例如为0.8时,意味着在每次迭代中随机选择80%的参数来建树
early_stopping_round,如果一次验证数据的一个度量在最近的round中没有提高,模型将停止训练
lambda,正则化项,范围为0~1
min_gain_to_split,描述分裂的最小 gain,控制树的有用的分裂
max_cat_group,在 group 边界上找到分割点,当类别数量很多时,找分割点很容易过拟合时
num_boost_round,迭代次数,通常 100+
num_leaves,默认 31
device,指定cpu 或者 gpu
max_bin,表示 feature 将存入的 bin 的最大数量
categorical_feature,如果 categorical_features = 0,1,2, 则列 0,1,2是 categorical 变量
ignore_column,与 categorical_features 类似,只不过不是将特定的列视为categorical,而是完全忽略
param = {'boosting_type':'gbdt',
                         'objective' : 'binary', #任务类型
                         'metric' : 'auc', #评估指标
                         'learning_rate' : 0.01, #学习率
                         'max_depth' : 15, #树的最大深度
                         'feature_fraction':0.8, #设置在每次迭代中使用特征的比例
                         'bagging_fraction': 0.9, #样本采样比例
                         'bagging_freq': 8, #bagging的次数
                         'lambda_l1': 0.6, #L1正则
                         'lambda_l2': 0, #L2正则
        }
X_train, X_valid, y_train, y_valid = train_test_split(train.drop('Attrition',axis=1), train['Attrition'], test_size=0.2, random_state=42)
trn_data = lgb.Dataset(X_train, label=y_train)
val_data = lgb.Dataset(X_valid, label=y_valid)
model = lgb.train(param,train_data,valid_sets=[train_data,valid_data],num_boost_round = 10000 ,early_stopping_rounds=200,verbose_eval=25, categorical_feature=attr)
predict=model.predict(test)
test['Attrition']=predict
# 转化为二分类输出
test['Attrition']=test['Attrition'].map(lambda x:1 if x>=0.5 else 0)
test[['Attrition']].to_csv('submit_lgb.csv')

LGBMClassifier经验参数

clf = lgb.LGBMClassifier(
            num_leaves=2**5-1, reg_alpha=0.25, reg_lambda=0.25, objective='binary',
            max_depth=-1, learning_rate=0.005, min_child_samples=3, random_state=2021,
            n_estimators=2000, subsample=1, colsample_bytree=1,
        )

num_leavel=2**5-1 #树的最大叶子数,对比XGBoost一般为2^(max_depth)
reg_alpha,L1正则化系数
reg_lambda,L2正则化系数
max_depth,最大树的深度

n_estimators,树的个数,相当于训练的轮数
subsample,训练样本采样率(行采样)
colsample_bytree,训练特征采样率(列采样)

XGBoost VS LightGBM

XGBoost效果相对LightGBM可能会好一些

xgb = xgb.XGBClassifier(
            max_depth=6, learning_rate=0.05, n_estimators=2000, 
            objective='binary:logistic', tree_method='gpu_hist', 
            subsample=0.8, colsample_bytree=0.8, 
            min_child_samples=3, eval_metric='auc', reg_lambda=0.5
        )


max_depth ,树的最大深度
learning_rate, 学习率
reg_lambda,L2正则化系数
n_estimators,树的个数,相当于训练的轮数
objective,目标函数, binary:logistic 用于二分类任务
tree_method, 使用功能的树的构建方法,hist代表使用直方图优化的近似贪婪算法
subsample,训练样本采样率(行采样)
colsample_bytree,训练特征采样率(列采样)

** subsample, colsample_bytree是个值得调参的参数**
典型的取值为0.5-0.9(取0.7效果可能更好)

CatBoost算法:

俄罗斯科技公司Yandex开源的机器学习库(2017年)
https://arxiv.org/pdf/1706.09516.pdf
CatBoost = Catgorical + Boost
高效的处理分类特征(categorical features),首先对分类特征做统计,计算某个分类特征(category)出现的频率,然后加上超参数,生成新的数值型特征(numerical features)
同时使用组合类别特征,丰富了特征维度
采用的基模型是对称决策树,算法的参数少、支持分类变量,通过可以防止过拟合

CatBoost,LightGBM,XGBoost对比:

2015 年航班延误数据,包含分类和数值变量
https://www.kaggle.com/usdot/flight-delays/data
一共有约 500 万条记录,使用10%的数据,即50条记录
CatBoost 过拟合程度最小,在测试集上准确度最高0.816,同时预测用时最短,但这个表现仅仅在有分类特征,而且调节了one-hot最大量时才会出现
如果不利用 CatBoost 算法在这些特征上的优势,表现效果就会变成最差,AUC 0.752
使用CatBoost需要数据中包含分类变量,同时适当地调节这些变量时, 才会表现不错
处理特征为分类的神器
支持即用的分类特征,因此我们不需要对分类特征进行预处理(比如使用LabelEncoding 或 OneHotEncoding)
CatBoost 设计了一种算法验证改进,避免了过拟合。因此处理分类数据比LightGBM 和XGBoost 强
准确性比 XGBoost 更高,同时训练时间更短
支持 GPU 训练
可以处理缺失的值

CatBoost工具:

https://github.com/dmlc/xgboost
https://catboost.ai/docs/concepts/python-reference_catboostclassifier.html

构造参数:

learning_rate,学习率
depth, 树的深度
l2_leaf_reg,L2正则化系数
n_estimators,树的最大数量,即迭代次数
one_hot_max_size,one-hot编码最大规模,默认值根据数据和训练环境的不同而不同
loss_function ,损失函数,包括Logloss,RMSE,MAE,CrossEntropy,回归任务默认RMSE,分类任务默认Logloss
eval_metric,优化目标,包括RMSE,Logloss,MAE,CrossEntropy,Recall,Precision,F1,Accuracy,AUC,R2

fit函数参数:

X,输入数据数据类型可以是:list; pandas.DataFrame; pandas.Series
y=None
cat_features=None,用于处理分类特征
sample_weight=None,输入数据的样本权重
logging_level=None,控制是否输出日志信息,或者其他信息
plot=False,训练过程中,绘制,度量值,所用时间等
eval_set=None,验证集合,数据类型list(X, y)tuples
baseline=None
use_best_model=None
verbose=None

model = CatBoostClassifier(iterations=1000, #最大树数,即迭代次数
                              depth = 6, #树的深度
                               learning_rate = 0.03, #学习率
                               custom_loss='AUC', #训练过程中,用户自定义的损失函数
                               eval_metric='AUC', #过拟合检验(设置True)的评估指标,用于优化
                               bagging_temperature=0.83, #贝叶斯bootstrap强度设置
                               rsm = 0.78, #随机子空间
                               od_type='Iter', #过拟合检查类型
                               od_wait=150, #使用Iter时,表示达到指定次数后,停止训练
                               metric_period = 400, #计算优化评估值的频率
                               l2_leaf_reg = 5, #l2正则参数
                               thread_count = 20, #并行线程数量
                               random_seed = 967 #随机数种子
                              )
model = cb.CatBoostClassifier(iterations=1000, 
                              depth=7, 
                              learning_rate=0.01, 
                              loss_function='Logloss', 
                              eval_metric='AUC',
                              logging_level='Verbose', 
                              metric_period=50)
# 得到分类特征的列号
categorical_features_indices = []
for i in range(len(X_train.columns)):
    if X_train.columns.values[i] in attr:
        categorical_features_indices.append(i)
print(categorical_features_indices)

model.fit(X_train, y_train, eval_set=(X_valid, y_valid), cat_features=categorical_features_indices)
predict = model.predict(test)
test['Attrition']=predict
test[['Attrition']].to_csv('submit_cb.csv')

LighGBM效率高,在Kaggle比赛中应用多
CatBoost对于分类特征多的数据,可以高效的处理,过拟合程度小,效果好
XGBoost, LightGBM, CatBoost参数较多,调参需要花大量时间
Boosting集成学习包括AdaBoosting和Gradient Boosting
Boosting只是集成学习中的一种(Bagging, Stacking)


参数对比

image.png image.png image.png image.png image.png image.png

相关文章

网友评论

      本文标题:集成学习之xgboost、lightGBM、CatBoost、N

      本文链接:https://www.haomeiwen.com/subject/lpcokltx.html