集成学习(ensemblelearning),它本身不是一个单独的机器学习算法,而是通过构建并结合多个机器学习器来完成学习任务。
如何产生并结合“好而不同”的个体学习器,是集成学习研究的核心。
也就是说,集成学习有两个主要的问题需要解决,
下面,我们从两个部分来理解集成学习:个体学习器的生成、学习器结合策略。
首先,生成的基学习器要满足两个条件:
在集成学习中,根据个体学习器的生成方式不同,可以分为Bagging算法和Boosting算法。
Boosting算法通过顺序地给训练集中的数据重新加权创造不同的基础学习器。
其核心思想是,
具体来说,
Boosting算法的最终模型是一系列基础学习器的线性组合,并且系数依赖于各个基础学习器的表现。
Boosting算法有很多版本,目前使用最广泛的是AdaBoost算法(AdaptiveBoosting自适应性提升法)和GBDT算法(梯度提升决策树GradientBoostingDecisionTree)。
#AdaBoostingfromsklearn.ensembleimportAdaBoostClassifierclf=AdaBoostClassifier(n_estimators=100)scores=cross_val_score(clf,iris.data,iris.target,cv=5)scores.mean()Bagging算法Bagging算法原理如下图,
#使用baggingfromsklearn.ensembleimportBaggingClassifier#回归用BaggingRegressorfromsklearn.treeimportDecisionTreeClassifierbagging_clf=BaggingClassifier(DecisionTreeClassifier(),n_estimators=500#基评估器数量,max_samples=100#每个子模型使用的样本数,bootstrap=True#放回取样#,oob_score=True#使用袋外数据做测试集,调用bagging_clf.oob_score_得到分数,n_jobs=-1#使用所有核进行训练,max_features=2#针对特征随机采样,bootstrap_features=True#特征放回取样)bagging_clf.fit(X_train,y_train)bagging_clf.score(X_test,y_test)随机森林是bagging的一个特化进阶版,
其基本思想没有脱离bagging的范畴。
Bagging法和Boosting法最显著的不同的是
将不同的分类算法套入此算法框架中在一定程度上可以提高原单一分类器的分类效果,但是也增大了计算量。
将决策树与这些算法框架进行结合得到新的算法如下:
在一般经验中,如果把好坏不等的东西掺到一起,那么通常结果会是比最坏的要好一些,比最好的要坏一些。集成学习如何把多个学习器结合起来,获得比单一学习器更好的性能呢?这就是所谓的“结合策略”
将个体学习器结合在一起的时候使用的方法叫做结合策略。常用的结合策略有平均法、投票法、学习法。
对于数值类的回归预测问题,通常使用的结合策略是平均法,也就是说将每个基学习器的结果进行简单平均或者加权平均。
加权平均的权重一般是从训练数据中学习得到,现实任务中的训练样本通常不充分或存在噪声,这将使得学出的权重不完全可靠。尤其是对规模比较大的集成来说,要学习的权重比较多,较容易导致过拟合。因此,实验和应用均显示出,加权平均法未必一定优于简单平均法。
一般而言,在个体学习器性能相差较大时宜使用加权平均法,而在个体学习器性能相近时宜使用简单平均法。
对于分类问题的预测,我们通常使用的是投票法,基学习器分类结果的多数作为最终结果。
下面代码将三种算法组成的集成算法和算法本身进行比较:
在训练阶段,次级训练集是利用初级学习器产生的,若直接用初级学习器的训练集来产生次级训练集,则过拟合的风险会比较大;我们一般有两种方法来处理这个问题:
由于stacking中的每个基模型都需要对数据集进行划分后进行交叉训练,如果为每个模型都写这部分的代码会显得非常冗余,因此这里提供一种简便实现stacking的思路。
下面以两个基模型为例进行stacking,分别是xgboost和lightgbm,这两个模型都只需要实现BasicModel中的train和predict方法.
第一个基模型xgboost:
importxgboostasxgbclassXGBClassifier(BasicModel):def__init__(self):"""setparameters"""self.num_rounds=1000self.early_stopping_rounds=15self.params={'objective':'binary:logistic','eta':0.1,'max_depth':8,'eval_metric':'auc','seed':0,'silent':0}deftrain(self,x_train,y_train,x_val,y_val):print('trainwithxgbmodel')xgbtrain=xgb.DMatrix(x_train,y_train)xgbval=xgb.DMatrix(x_val,y_val)watchlist=[(xgbtrain,'train'),(xgbval,'val')]model=xgb.train(self.params,xgbtrain,self.num_rounds)watchlist,early_stopping_rounds=self.early_stopping_rounds)returnmodel,float(model.eval(xgbval).split()[1].split(':')[1])defpredict(self,model,x_test):print('testwithxgbmodel')xgbtest=xgb.DMatrix(x_test)returnmodel.predict(xgbtest)第二个基模型lightgbm:
importlightgbmaslgbclassLGBClassifier(BasicModel):def__init__(self):self.num_boost_round=2000self.early_stopping_rounds=15self.params={'task':'train','boosting_type':'dart','objective':'binary','metric':{'auc','binary_logloss'},'num_leaves':80,'learning_rate':0.05,#'scale_pos_weight':1.5,'feature_fraction':0.5,'bagging_fraction':1,'bagging_freq':5,'max_bin':300,'is_unbalance':True,'lambda_l2':5.0,'verbose':-1}deftrain(self,x_train,y_train,x_val,y_val):print('trainwithlgbmodel')lgbtrain=lgb.Dataset(x_train,y_train)lgbval=lgb.Dataset(x_val,y_val)model=lgb.train(self.params,lgbtrain,valid_sets=lgbval,verbose_eval=self.num_boost_round,num_boost_round=self.num_boost_round)early_stopping_rounds=self.early_stopping_rounds)returnmodel,model.best_score['valid_0']['auc']defpredict(self,model,x_test):print('testwithlgbmodel')returnmodel.predict(x_test,num_iteration=model.best_iteration)下一个步骤就是将这两个基模型的输出作为第二层模型的输入,这里选用的第二层模型是LogisticsRegression.
首先需要将各个基模型的输出reshape和concatenate成合适的大小:
lgb_classifier=LGBClassifier()lgb_oof_train,lgb_oof_test=lgb_classifier.get_oof(x_train,y_train,x_test)xgb_classifier=XGBClassifier()xgb_oof_train,xgb_oof_test=xgb_classifier.get_oof(x_train,y_train,x_test)input_train=[xgb_oof_train,lgb_oof_train]input_test=[xgb_oof_test,lgb_oof_test]stacked_train=np.concatenate([f.reshape(-1,1)forfininput_train],axis=1)stacked_test=np.concatenate([f.reshape(-1,1)forfininput_test],axis=1)