经常使用的集成学习方法

集成学习是构建一组基学习器,并将它们综合做为最终的模型,在不少集成学习模型中,对基学习器的要求很低,集成学习适用于机器学习的几乎全部的领域:
一、回归
二、分类
三、推荐
四、排序算法

集成学习有效的缘由
多样的基学习器能够在不一样的模型中取长补短
每一个基学习器都犯不一样的错误,综合起来犯错的可能性不大
可是想同的多个基学习器不会带来任何提高bootstrap

集成学习示例:
经常使用的集成学习方法
例如在上图中每一个线性模型都不能成功将该数据集分类
可是三个线性模型的简单综合便可将数据集成功分类,每一个模型犯不一样的错,可是在综合时可以取长补短,使得综合后的模型性能更好。网络

那么如何构建不一样的基学习器?如何将基学习器综合起来?数据结构

如何构建不一样的学习器
一、采用不一样的学习算法
二、采用相同的学习算法,可是使用不一样的参数
三、采用不一样的数据集,其中采用不一样的样本子集,在每一个数据集中使用不一样的特征框架

如何综合不一样的基学习器
一、投票法
每一个基学习器具备相同的权重
二、有权重的投票
可用不一样的方法来肯定权重
三、训练一个新模型来肯定如何综合
stacking
咱们通常偏好简单的模型(线性回归)dom

主要的集成学习模式有如下几种
一、bagging random forest(随机森林)
二、boosting
adaboost
GBDT
三、stacking机器学习

bagging
在集成算法中,bagging 方法会在原始训练集的随机子集上构建一类黑盒估计器的多个实例,而后把这些估计器的预测结果结合起来造成最终的预测结果。 该方法经过在构建模型的过程当中引入随机性,来减小基估计器的方差(例如,决策树)。 在多数状况下,bagging 方法提供了一种很是简单的方式来对单一模型进行改进,而无需修改背后的算法。 由于 bagging 方法能够减少过拟合,因此一般在强分类器和复杂模型上使用时表现的很好(例如,彻底决策树,fully developed decision trees),相比之下 boosting 方法则在弱模型上表现更好(例如,浅层决策树,shallow decision trees)。ide

bagging 方法有不少种,其主要区别在于随机抽取训练子集的方法不一样:函数

若是抽取的数据集的随机子集是样例的随机子集,咱们叫作 Pasting 。
若是样例抽取是有放回的,咱们称为 Bagging 。
若是抽取的数据集的随机子集是特征的随机子集,咱们叫作随机子空间 (Random Subspaces)。
最后,若是基估计器构建在对于样本和特征抽取的子集之上时,咱们叫作随机补丁 (Random Patches) 。
在 scikit-learn 中,bagging 方法使用统一的 BaggingClassifier 元估计器(或者 BaggingRegressor ),输入的参数和随机子集抽取策略由用户指定。max_samples 和 max_features 控制着子集的大小(对于样例和特征), bootstrap 和 bootstrap_features 控制着样例和特征的抽取是有放回仍是无放回的。 当使用样本子集时,经过设置 oob_score=True ,可使用袋外(out-of-bag)样原本评估泛化精度。性能

采样几率

在Bagging中,一个样本可能被屡次采样,也可能一直不被采样,假设一个样本一直不出如今采样集的几率为(1-1/N) ** N,那么对其求极限可知,原始样本数据集中约有63.2%的样本出如今了,Bagging使用的数据集中,同时在采样中,咱们还可使用袋外样本(out of Bagging)来对咱们模型的泛化精度进行评估.

最终的预测结果

对于分类任务使用简单投票法,即每一个分类器一票进行投票(也能够进行几率平均)
对于回归任务,则采用简单平均获取最终结果,即取全部分类器的平均值

基于KNN的Bagging算法

关于参数和方法要注意的是:

首先控制特征子采样与样本子采样是否采用,采用的话是否要注意控制比例(通常而言,不要采起较小的数值,过小的特征子采样和样本子采样都会形成子学习器的性能太差.通常而言特征选择越少,方差越大,这点能够与最后的实验方差误差分解对比分析).
其次控制Bagging中的随机数参数random_state固定,否则不一样实验的结果将不一致,同时要注意的不少时候random_state对于测试偏差的影响很大,所以加入你想要在某一个数据集上使用Bagging,那么建议多尝试几个不一样的Random_state
oob_score = True 对性能有必定的提高(使用袋外样本进行泛化能力的评估,可是不少时候效果并不明显,或者看不出什么效果)
其余参数通常默认便可

from sklearn.ensemble import BaggingClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score

# load data from sklearn import datasets,model_selection
def load_data():
    iris=datasets.load_iris() # scikit-learn 自带的 iris 数据集
    X_train=iris.data
    y_train=iris.target
    return model_selection.train_test_split(X_train, y_train,test_size=0.25,random_state=0,stratify=y_train)

bagging = BaggingClassifier(KNeighborsClassifier(),max_samples=0.1,max_features=0.5,random_state=1)

X_train,X_test,y_train,y_test=load_data()

bagging.fit(X_train,y_train)
y_pre = bagging.predict(X_test)
print(accuracy_score(y_test,y_pre))

boosting
Boosting主要是Adaboost(Adaptive Boosting),它与Bagging的不一样在于他将权重赋予每一个训练元组,生成基分类器的过程为迭代生成。每当训练生成一个分类器M(i)时要进行权重更新,使得M(i+1)更关注被M(i)分类错误的训练元组。最终提高总体集合的分类准确率,集成规则是加权投票,每一个分类器投票的权重是其准确率的函数。

继续详细介绍的话,假设数据集D,共有d类。(X1,Y1)…(Xd,Yd),Yi是Xi的类标号,假设须要生成k的分类器。其步骤为:

一、对每一个训练元组赋予相等的权重1/d。

二、for i=1:k

从D中进行有放回的抽样,组成大小为d的训练集Di,同一个元组能够被屡次选择,而每一个元组被选中的概率由权重决定。利用Di训练获得分类器Mi,而后使用Di做为测试集计算Mi的偏差。而后根据偏差调整权重。

当元组没有被正确分类时,则权重增长;反之权重减小。而后利用新的权重为下一轮训练分类器产生训练样本。使其更“关注”上一轮中错分的元组。

三、进行加权投票集成

Bagging与Boosting的差别

经过上述简单的介绍,能够看出这两种集成算法主要区别在于“加没加权”。Bagging的训练集是随机生成,分类器相互独立;而Boosting的分类器是迭代生成,更关注上一轮的错分元组。所以Bagging的各个预测函数能够并行生成;而Boosting只能顺序生成。所以对于像一些比较耗时的分类器训练算法(如神经网络等)若是使用Bagging能够极大地解约时间开销。

可是经过在大多数数据集的实验,Boosting的准确率多数会高于Bagging,可是也有极个别数据集使用Boosting反倒会退化。

stacking
stakcing经常在各大数据挖掘竞赛中被普遍使用,号称“大杀器”。是数据挖掘竞赛高端玩家必备技能,本篇文章就对stakcing的一些基本原理进行介绍。

首先,在我看来stacking 严格来讲不能称为一种算法,我理解的是一种很是精美而复杂的对模型的集成策略。你们都知道,在给定了数据集的状况下,数据内部的空间结构和数据之间的关系是很是复杂的。而不一样的模型,其实很重要的一点就是在不一样的角度去观测咱们的数据集。好比说,KNN 可能更加关注样本点之间的距离关系(包括欧几里得距离(Euclidean Distance)、明可夫斯基距离(Minkowski Distance 等等),当样本距离相对较近, KNN 就把他们分为一类;而决策树,可能更加关注分裂节点时候的不纯度变化,有点像咱们本身找的规则,在知足某个条件且知足某个条件的状况下,决策树把样本分为一类等等。也就是说,不一样的算法模型,实际上是在不一样的数据空间角度和数据结构角度来观测数据,而后再依据它本身的观测,结合本身的算法原理,来创建一个模型,在新的数据集上再进行预测。这样你们就会有个疑问了,俗话说:三人行必有我师。既然是不一样的算法对数据有不一样的观测,那么咱们能不能相互取长补短,我看看你的观测角度,你看看个人观测角度,咱俩结合一下,是否是能够获得一个更加全面更加优秀的结果呢?答案是确定的。在我当初学基础算法的时候就有这么一个疑问,可是不知道怎么结合,直到有一天看到了 stacking的框架,瞬间感受找到了一片新天地~~~~下面我从如下几个方面介绍 stacking。

1、stacking 的框架结构与运行过程:

刚开始看 stacking 好像是交叉检验的既视感,其实并非这样。假设是五折的stacking,咱们有一个train 数据集和一个test 数据集,那么一个基本的stacking 框架会进行以下几个操做:

一、选择基模型。咱们能够有 xgboost,lightGMB,RandomForest,SVM,ANN,KNN, LR 等等你能想到的各类基本算法模型。

二、把训练集分为不交叉的五份。咱们标记为 train1 到 train5。

三、从 train1 开始做为预测集,使用 train2 到 train5 建模,而后预测 train1,并保留结果;而后,以 train2 做为预测集,使用 train1,train3 到 train5 建模,预测 train2,并保留结果;如此进行下去,直到把 train1 到 train5 各预测一遍;

四、在上述创建的五个模型过程当中,每一个模型分别对 test 数据集进行预测,并最终保留这五列结果,而后对这五列取平均,做为第一个基模型对 test 数据的一个 stacking 转换。

五、把预测的结果按照 train1 到 trian5 的位置对应填补上,获得对 train 整个数据集在第一个基模型的一个 stacking 转换。

六、选择第二个基模型,重复以上 2-5 操做,再次获得 train 整个数据集在第二个基模型的一个 stacking 转换。

七、以此类推。有几个基模型,就会对整个train 数据集生成几列新的特征表达。一样,也会对test 有几列新的特征表达。

八、通常使用LR 做为第二层的模型进行建模预测。

bagging的优势:
易于并行计算
可使用不在训练集中的样原本估计基学习器的性能
boosting的优势:
学习速度快可以有效利用弱学习器构建强大的学习器
boosting缺点与bagging相比更激进,更容易受噪声影响过拟合,不易并行
stacking多用于最终综合多个性能较好的模型,最易于过拟合

如何避免过拟合:
一、引入随机性
是机器学习中一个广为使用的避免过拟合的方法

stacking示例代码

from sklearn import datasets  

iris = datasets.load_iris()  
X, y = iris.data[:, 1:3], iris.target  

from sklearn import model_selection  
from sklearn.linear_model import LogisticRegression  
from sklearn.neighbors import KNeighborsClassifier  
from sklearn.naive_bayes import GaussianNB   
from sklearn.ensemble import RandomForestClassifier  
from mlxtend.classifier import StackingClassifier  
import numpy as np  

clf1 = KNeighborsClassifier(n_neighbors=1)  
clf2 = RandomForestClassifier(random_state=1)  
clf3 = GaussianNB()  
lr = LogisticRegression()  
sclf = StackingClassifier(classifiers=[clf1, clf2, clf3],   
                          meta_classifier=lr)  

print('3-fold cross validation:\n')  

for clf, label in zip([clf1, clf2, clf3, sclf],   
                      ['KNN',   
                       'Random Forest',   
                       'Naive Bayes',  
                       'StackingClassifier']):  

    scores = model_selection.cross_val_score(clf, X, y,   
                                              cv=3, scoring='accuracy')  
    print("Accuracy: %0.2f (+/- %0.2f) [%s]"   
          % (scores.mean(), scores.std(), label))