一、平行集成 Parallel ensemble learning
Bagging : bootstrap aggregating 的缩写 (有放回采样)在从样本中抽样给classifier 或者predictor来训练集成模型里面的单个模型的时候,这里的采样方式是有放回的。如下图中,假设总样本为9个不同颜色的球,其中红色4个,绿色3个,蓝色两个。现在要从这个样本中抽取两个子集(subset),分别命名为bag1和bag2,在一中抽取的为4个红球,两个蓝球,此时如果不将球放回的话,那么bag2中只能从剩下的三个绿色的球中抽取,bagging是有放回的采样,所以这里相当于还是从原来的总样本中抽取一些球来作为bag2的子集,下图中抽取的是两个蓝球和两个绿球来作为bag2的样本集。
这里一个iteration,就是一个predictor, T个iteration最后结果的平均值。每个predictor里面F%个抽出来训练,剩下的用来test。
Pasting: (无放回采样)
同样的在选取子样本时,和bagging不一样的是,当bag1已经选取好之后,bag2只能从bag1中选取剩下的里面做出选择,因为bag1中采样之后,并没有放回,所以bag2所采样的总体样本中就不存在bag1中已有的样本,bag2只能从剩下的三个绿球中选择。
其中每一个bag的样本会传到一个predictor里面,让predictor计算得出一个结果。如下图所示。
一旦所有的predictor被训练完成,这个集成算法就可以对新的样本进行预测,其预测的结果可以通过简单地汇总所有的预测变量来得到。分类中的典型统计模式通常是使用聚合函数(aggregating function), 回归中通常是使用平均值。
In database management, aggregate function or aggregation function is a function where the values of multiple rows are grouped together to form a single summary value. --wiki
下图也是以bagging的方式采样到predictors的过程。
我们可以通过不同的CPU核甚至不同的服务器平行训练Bagging中的predictors。类似的,也可以平行地做出预测。Scikit-Learn 同时为bagging和pasting提供了简单的API,BaggingClassifier 用来分类,BaggingRegressor用来做回归。
下面我们看一下如何用Scikit Learn实现bagging和pasting。
我们使用的是sklearn.datasets中的make_moons来产生两个交织半圈的数据集(一共有500个samples),如下图所示。
from sklearn.datasets import make_moons
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
X,y=make_moons(n_samples=500,noise=0.3,random_state=42)
X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=42)
plt.scatter(X[:,0],X[:,1],c=y)
现在分别使用DecisionTreeClassifier和BaggingClassifier为它们分类,其中BaggingClassifier中里面的basic classifier 为DecisionTreeClassifier。
from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier
import numpy as np
def visualize_classifier(model, X, y, ax=None, cmap='rainbow'):ax = ax or plt.gca()# Plot the training pointsax.scatter(X[:, 0], X[:, 1], c=y, s=30, cmap=cmap,clim=(y.min(), y.max()), zorder=3)ax.axis('tight')ax.axis('off')xlim = ax.get_xlim()ylim = ax.get_ylim()# fit the estimatormodel.fit(X, y)xx, yy = np.meshgrid(np.linspace(*xlim, num=200),np.linspace(*ylim, num=200))Z = model.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)# Create a color plot with the resultsn_classes = len(np.unique(y))contours = ax.contourf(xx, yy, Z, alpha=0.3,levels=np.arange(n_classes + 1) - 0.5,cmap=cmap, clim=(y.min(), y.max()),zorder=1)ax.set(xlim=xlim, ylim=ylim)
单一的DecisionTreeClassifier
visualize_classifier(DecisionTreeClassifier(), X, y)
使用bagging集成后的决策树
bag_clf=BaggingClassifier(DecisionTreeClassifier(),n_estimators=500,max_samples=100,bootstrap=True, n_jobs=-1)
bag_clf.fit(X_train,y_train)
y_pred=bag_clf.predict(X_test)
visualize_classifier(bag_clf, X, y)
使用pasting集成后的决策树:
bag_clf=BaggingClassifier(DecisionTreeClassifier(),n_estimators=500,max_samples=100,bootstrap=False, n_jobs=-1) #设置为False好快呀
bag_clf.fit(X_train,y_train)
y_pred=bag_clf.predict(X_test)
由上面一些列图片可以看到,BaggingClassifier系列的集成算法做出来的结果其边界要比单棵决策树做出来的边界更为平缓。BaggingClassifier中,改变一些参数,如bootstrap,当bootstrap为True时,使用的是bagging的采样方式,为False时,使用的是pasting的采样方式(无放回)。
下面看看BaggingClassifier的使用方法:
BaggingClassifier (base_estimators = None, n_estimators=10, *, max_samples = 1.0, max_features=1.0, bootstrap=True, bootstrap_feature = False, oob_score=False, warm_start = False, n_jobs = None, random_state = None, verbose = 0)
解释一下相关参数:
Base_estimators: the base estimator to fit on random subsets of the dataset. If None, then the base estimator is a decision tree.
集成算法中的基础算法,这里用的是决策树分类,所以我们的第一个参数是DecisionTreeClassifier。n_estimator: int, default=10; the number of base estimators in the ensemble.在集成中使用道的基本的算法的个数。
对于上面的那500个散点,我们的bagging classifier中使用了500个estimators。
Max_samples: int or float, default=1.0;The number of samples to draw from X to train each base estimator(with replacement by default, see bootstrap for more detail)。从X中获得用来为每一个base estimator 的样本的个数,bootstrap为True时,X中的样本可以替代,也就是一个样本可以重复出现在多个estimator中,如果为False,那就是pasting的采样方法,这些样本不会重复出现不同的estimator中。这个参数如果设置为整数,那么就是从X中抓取出来的样本个数。如果这个参数设置为float,也就是一个比例那么就抓取max_sampleX.shape[0] 个样本(X.shape[0]得到的就是样本的个数(长度)啦)。在代码中所举的例子中,Max_samples我们取的是100。
Max_features: int or float, default=1.0The number of features to draw from X to train each base estimator(without replacement by default, see bootstrap_features for more detail).上文提到过,我们在训练每一个classifier的时候,有时候也并不会选取所有的特征,而是让每一个predictor 在features(特征)的subset上面训练的,但是如果不设置这个参数的话,就是默认使用所有的特征,在特征特别多的时候(高维度输入时)还是可以设置一下,特别是在图像识别的时候。这个参数如果设置为整数,那么就是每一个estimator(classifier)使用的特征的个数。如果这个参数设置为float格式,那它就是一个比例,那么用来训练的特征的个数为max_featuresX.shape[1](X.shape[1]得到的就是数据集中特征的个数)。
Bootstrap:bool, default=True;采样是否需要替代,默认为True,设置为False的时候,为不替代。
Bootstrap_features: bool, default=False。类似于bootstrap的功能,只是这里是针对于features,默认为False。
Warm_start:bool, default=False;When set to True, reuse the solution of the previous call to fit and add more estimators to the ensemble, otherwise, just fit a whole new ensemble.当参数设置为True的时候,重复使用之前call的结果用来fit,并且增加更多estimators到ensemble中,设置为False的话,那就当作一个新的来fit,而不会考虑到上一次trained的那些estimators.Warm_start参数在模型训练过程中起作用,当warm_start=True时,模型训练可以在前一阶段训练结果上进行,而不是从头开始重新训练,可以提升模型的训练速度。比如我们上面设置的n_estimators=500,如果再加上一些estimators,那么在下一次训练的时候n_estimators=510,在warm_start=True的情况下,n_estimators就再多加个十棵树,而不会从0棵决策树开始计算。当使用一个estimator在同样的数据集上面拟合,但是对于大部分参数值(比如用grid search找到使模型最优的值),它有可能从先前的参数值中学到模型的各方面信息,从而节省时间。当warm_start为true时,现存的拟合好的模型参数用于随后的需要拟合的模型的初始化值。注意到,这里只适用于一些模型和一些参数,甚至是一些参数值的顺序。例如,warm_start用于建立随机森林模型中添加决策树到森林中(通过增加n_estimators),但是不能用来减少这个数量。
N_jobs:int, default=NoneThe number of jobs to run in parallel for both fit and predict.None means 1 unless in a joblib.parallel_backend context. -1 means using all processors.The n_jobs parameter tells Scikit-Learn the number of CPU cores to use for training and predictions.N_jobs设置参数告诉scikit-learn要使用多少个CPU核来用作训练,至少为1个,当设置为-1时,即使用所有的CPU核来进行训练核和预测。代码里面是n_jobs=-1,然后我发现我跑起来的时候我的CPU是100%的,em…
Random_state: int or randomstate, default=NoneControls the random resampling of the original dataset (sample wise and feature wise). If the base estimator accepts a random_state attribute, a different seed is generated for each instance in the ensemble. Pass an int for reproducible output across multiple function calls. See Glossary.控制原始数据集的随机重采样,具体可以参考“一维卷积神经网络应用于电信号分类 Ⅰ”的random_state。
Oob_score:bool,default=Falseoob_score = accuracy_score(y, np.argmax(predictions, axis=1))是否使用out-of-bag样本来评估泛化性能错误。这里介绍一下out-of-bag。在使用bagging的采样方式时(bootstrap=True),有放回抽样,对于任何给定的predictor,一些样本可以被多次采样,而有些可能完全没有被采样到。假设在一次有放回的采样中,一个baggingclassifier中有m个样本(samples),那么每个样本抽到的概率为1/m,没有被抽到的概率为(1-1/m),那么被抽取了m次仍然没有被抽到的概率为(1-1/m)^m。如果样本足够大,抽取的次数足够多,那么也就是m趋于无穷,下面我们来求解一下m趋于无穷时等于多少:
当m趋于无穷时
关于
及t满足:
在0的某去心领域内两者都可导,且
不等于零,所以这里可以使用洛必达法则:
所以对于求得的极限为-1。
因此,当样本充足,且取了很多次,那么没有被取到的样本数大概有36.79%个,也就是说被取到用来训练的样本占比63.21%。没有被取到bag中的那些样本我们把它们叫做out-of-bag (OOB)样本。
因此,一个predictor在训练时从来没有碰到过OOB样本,所以可以用这些样本来对训练的模型进行评估,而不需要从中分离一个验证集(validation data set)出来,或者说使用交叉验证(cross-validation)。
使用oob样本评估训练的集成模型。实际的和预测的差值,预测的是用OOB的来作为预测,所以整个集成模型的误差为OOB数据集的误差。
要使用OOB作为测试数据集的话,需要设置参数(parameter)oob_score=True。设置了oob_score=True时,才会有oob_score_和oob_decision_function_这两个属性。下面简单说说这两个参数:
Bag.clf.oob_score_
Oob_score_: Score of the training dataset obtained using an out-of-bag estimate. This attribute exists only when oob_score is True.这里会对所有参加train的sample进行一个二分类,结果为概率大的那一方,这个oob_score_会把所有的大的那个结果加起来求平均值。
Oob_decision_function_: ndarray of shape(n_samples, n_classes)Decision function computed with out-of-bag estimate on the training set. If n_estimators is small it might be possible that a data point was never left out during the bootstrap.计算用来train的sample分类为每个类别的概率。如下图,比如第一行,分类为第一类和第二类的概率分别为0和1,第二行,为第二个用来训练的sample,分为两类的概率分别为0.34和0.66,以此类推。
bag_clf=BaggingClassifier(DecisionTreeClassifier(),n_estimators=500,oob_score=True,max_samples=100,bootstrap=True, n_jobs=-1) #设置为False好快呀
bag_clf.fit(X_train,y_train)
y_pred=bag_clf.predict(X_test)
bag_clf.oob_score_
bag_clf.oob_decision_function_
在计算oob_score_之前,我们先要来了解一下voting的两种:硬投票(hard voting)和软投票(soft voting):
l 硬投票适用于预测类别标签的模型。
l 软投票适用于预测类别成员可能性的模型。
这里面用来做分类,使用的是hard voting。
from sklearn.metrics import accuracy_score
oob_score = accuracy_score(y_train, np.argmax(bag_clf.oob_decision_function_, axis=1))
oob_score
Out-of-bag(OOB)error, also called out-of-bag estimate, is a method of measuring the prediction error of random forests, boosted decision trees, and other machine learning models utilizing bootstrap aggregating(bagging) to sub-sample data samples used for training. OOB is the mean prediction error on each training sample xi using only the trees that did not have xi in their bootstrap sample. --wiki
OOB 是平均预测误差,是由哪些计算得到平均的呢,里面的每一个用来求解这个平均值的元素都是不含有这个训练样本的树Decision Tree 对这个样本进行预测。
大概就是下面这样计算的,用来训练的由375个,然后通过bag_clf.oob_decision_function_可以看到每一个sample分类两类的概率分别为多少。
y_train.shape
Numpy.argmax(a,axis=None,out=None)Returns the indices of the maximum values along an axis.
返回沿轴方向的最大值的指标。这里面我们用的axis=1,横向的,在每一行中,第二列大的,那么返回的值为1,第一列大的话,返回的值是0,然后我们得到一系列的0和1,再与原来的标签比较,从而可以计算得到accuracy score。
然后使用accuracy_score来计算总体的得分。或者我们自己写代码,对分类正确的进行统计,然后再除以总我们用来分类的样本个数,这里是375,也就是hard voting的方法,相除,得到的分数为0.91和之前直接用模型的attributes中的oob_score_得到的值是一样的。
i=0
for item1,item2 in zip(np.argmax(bag_clf.oob_decision_function_, axis=1),y_train):if item1==item2:i+=1
i/375
np.argmax(bag_clf.oob_decision_function_, axis=1)
最后再补充一下:
Random Patches(随机补丁) and Random Subspace(随机子空间)
同时对训练样本和训练特征的采样叫做random patches 方法(随机补丁法), 保留所有的训练样本(bootstrap=False and max_samples=1.0)而不是样本特征(bootstrap_features=True),被叫做Random Subspace 方法, 随机子空间法。
总结在下表:
注意上面的oob_score_和整个模型的score是不一样的,我们刚刚用X_train,y_train计算的oob_score_和直接用bag_clf
这个model计算得到的score是不一样的。这个score表示的是对X_test进行predict得到预测的y再与y_test,计算它们的accuracy得到的结果,也可以使用accuracy_score(y_test,y_pred),计算预测和用来测试的y_test之间的accuracy。
bag_clf.score(X_tain,y_train)
bag_clf.score(X_test,y_test)
二、bagging 中的random forests.
A Random Forest is an ensemble of Decision Trees, generally trained via the bagging method, typically with max_samples set to the size of the training set.
随机森林是一个决策树的集合,通常使用bagging的方法来训练,并且将max_samples设置为训练集的大小。
除了建立BaggingClassifier 并且传递它一个决策树,你还可以使用RanddomForestClassifer, 你可以使用RandomForestClassifier类,该类对于决策树更方便且经过优化。
同样的,对于回归问题,可以使用RandomForestRegressor 类。
让我们用500棵树来训练一个Random Forest 分类,每个限制在最大16个结点,使用所有可以使用的CPU核。
from sklearn.ensemble import ExtraTreesClassifier
extra_tree_clf=ExtraTreesClassifier(n_estimators=500,max_leaf_nodes=16,n_jobs=-1,random_state=42)
extra_tree_clf.fit(X_train,y_train)
y_pred_extra_trees=extra_tree_clf.predict(X_test)
Sklearn.ensemble.randomForestClassifier(n_estimator=100,*,criterion=’gini’, max_depth=None,…)
A random forest is a meta estimator that fits a number of decision tree classifier on various sub-samples of the dataset and uses averaging to improve the predictive accuracy an control over-fitting. The sub-sample size is controlled with the max_samples parameter if bootstrap=True(default), otherwise the whole dataset is used to build each tree.
n_estimators: predictor 的数量,在Random Forests里面这个predictor 是Decision Tree,所以这里指的是这片Random Forests 里面的决策树的数量。
Criterion:”gini”,或”entropy”, default=”gini” 用来评判结点分裂的质量,在决策树分类中有讲过,自定义选择的是gini指数,也就是说这里面自定义选择的单棵决策树是CART决策树。
Max_depth: 树的最大深度,如果这个参数设置为None,节点就会一直分裂下去,直到所有的叶节点包含少于min_samples_split所设置的样本数量。
Min_samples_split:分裂到最少的样本数量,default值为2,如果为整数,min_samples_split代表的是最少数量,如果为float 浮点型,也就是说是一个比例,那么这个样本分裂到最小的数为min_samples_split*n_samples。
Max_leaf_nodes: 最大叶节点数量,如果为None,那么就不会对叶节点的数量进行限制。N_jobs: 并行运行的数量,用于指定与joblib并行化的例程应使用多少个并发进程或线程。-1表示使用所有的进程。