Bagging元估计器

BaggingBootstrap Aggregating的简称,意思就是再取样(Bootstrap)然后在每个样本上训练出来的模型进行集成.

通常如果目标是分类,则集成的方式是投票;如果目标是回归,则集成方式是取平均.

在集成算法中,bagging方法会在原始训练集的随机子集上构建一类黑盒估计器的多个实例,然后把这些估计器的预测结果结合起来形成最终的预测结果.

该方法通过在训练模型的过程中引入随机性,来减少基估计器的方差(例如,决策树).在多数情况下,bagging方法提供了一种非常简单的方式来对单一模型进行改进,而无需修改背后的算法.因为bagging方法可以减小过拟合(variance),所以通常在强分类器和复杂模型上使用时表现的很好.

bagging方法有很多种,其主要区别在于随机抽取训练子集的方法不同:

  • 如果抽取的数据集的随机子集是样例的随机子集,我们叫做粘贴(Pasting).
  • 如果样例抽取是有放回的,我们称为Bagging.
  • 如果抽取的数据集的随机子集是特征的随机子集,我们叫做随机子空间(Random Subspaces)
  • 如果基估计器构建在对于样本和特征抽取的子集之上时,我们叫做随机补丁(Random Patches)

bagging的另一个好处是天生的易于并行.完全可以多个机器同时训练,之后再集成起来,这样可以大大提高效率.

使用sklearn做bagging集成

sklearn提供了两个接口来做bagging:

  • sklearn.ensemble.BaggingClassifier 用于集成分类器
  • sklearn.ensemble.BaggingRegressor 用于集成回归器

他们的用法类似,下面的例子简单介绍用法,使用的数据集为iris


In [1]:
import requests
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder,StandardScaler
from sklearn.neural_network import MLPClassifier
from sklearn.metrics import classification_report
from sklearn.ensemble import BaggingClassifier

数据预处理


In [2]:
csv_content = requests.get("http://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data").text
row_name = ['sepal_length','sepal_width','petal_length','petal_width','label']
csv_list = csv_content.strip().split("\n")
row_matrix = [line.strip().split(",") for line in csv_list]
dataset = pd.DataFrame(row_matrix,columns=row_name)

encs = {}
encs["feature"] = StandardScaler()
encs["feature"].fit(dataset[row_name[:-1]])
table = pd.DataFrame(encs["feature"].transform(dataset[row_name[:-1]]),columns=row_name[:-1])

encs["label"]=LabelEncoder()
encs["label"].fit(dataset["label"])
table["label"] = encs["label"].transform(dataset["label"])

In [3]:
table[:10]


Out[3]:
sepal_length sepal_width petal_length petal_width label
0 -0.900681 1.032057 -1.341272 -1.312977 0
1 -1.143017 -0.124958 -1.341272 -1.312977 0
2 -1.385353 0.337848 -1.398138 -1.312977 0
3 -1.506521 0.106445 -1.284407 -1.312977 0
4 -1.021849 1.263460 -1.341272 -1.312977 0
5 -0.537178 1.957669 -1.170675 -1.050031 0
6 -1.506521 0.800654 -1.341272 -1.181504 0
7 -1.021849 0.800654 -1.284407 -1.312977 0
8 -1.748856 -0.356361 -1.341272 -1.312977 0
9 -1.143017 0.106445 -1.284407 -1.444450 0

数据集拆分


In [4]:
train_set,validation_set = train_test_split(table)

训练模型


In [5]:
bagging = BaggingClassifier(MLPClassifier(),n_estimators=15,max_samples=0.5, max_features=0.5,n_jobs=4)

In [6]:
bagging.fit(train_set[row_name[:-1]], train_set["label"])


Out[6]:
BaggingClassifier(base_estimator=MLPClassifier(activation='relu', alpha=0.0001, batch_size='auto', beta_1=0.9,
       beta_2=0.999, early_stopping=False, epsilon=1e-08,
       hidden_layer_sizes=(100,), learning_rate='constant',
       learning_rate_init=0.001, max_iter=200, momentum=0.9,
       nesterovs_momentum=True, power_t=0.5, random_state=None,
       shuffle=True, solver='adam', tol=0.0001, validation_fraction=0.1,
       verbose=False, warm_start=False),
         bootstrap=True, bootstrap_features=False, max_features=0.5,
         max_samples=0.5, n_estimators=15, n_jobs=4, oob_score=False,
         random_state=None, verbose=0, warm_start=False)

In [7]:
pre = bagging.predict(validation_set[row_name[:-1]])

In [8]:
print(classification_report(validation_set["label"],pre))


             precision    recall  f1-score   support

          0       1.00      1.00      1.00        12
          1       0.62      0.91      0.74        11
          2       0.90      0.60      0.72        15

avg / total       0.85      0.82      0.81        38

随机森林和sklearn中的接口

随机森林是最知名的bagging应用,利用多个随机树实例投票进行预测分类或者求平均做回归预测(cart tree使用基尼系数而非信息熵,因此可以处理连续数据).

sklearn中提供了4个随机森林接口:

接口 说明
ensemble.RandomForestClassifier([…]) 随机森林分类器
ensemble.RandomForestRegressor([…]) 随机森林回归器
ensemble.ExtraTreesClassifier([…]) 极限随机树分类器
ensemble.ExtraTreesRegressor([n_estimators, …]) 极限随机树回归器

在计算分割点方法中的随机性进一步增强.

其中极限随机树是RF的一个变种,原理几乎和RF一模一样,仅有区别有:

  1. 在决策树节点的划分决策的时候,RF采用的是随机选择一部分特征来选择划分特征,而extra trees还是比较符合bagging的传统,基于所有的特征来选择划分特征.

  2. 在选定了划分特征后,RF的决策树会基于信息增益,基尼系数,均方差之类的原则,选择一个最优的特征值划分点,这和传统的决策树相同.但是extra trees比较的激进,他会随机的选择一个特征值来划分决策树.

随机森林的原理不多复述,这里主要给出利用sklearn中接口的例子:


In [9]:
from sklearn.ensemble import RandomForestClassifier

In [10]:
rfc = RandomForestClassifier(n_estimators=1000,n_jobs=4)

In [11]:
rfc.fit(train_set[row_name[:-1]], train_set["label"])


Out[11]:
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=None, max_features='auto', max_leaf_nodes=None,
            min_impurity_split=1e-07, min_samples_leaf=1,
            min_samples_split=2, min_weight_fraction_leaf=0.0,
            n_estimators=1000, n_jobs=4, oob_score=False,
            random_state=None, verbose=0, warm_start=False)

In [12]:
pre = rfc.predict(validation_set[row_name[:-1]])

In [13]:
print(classification_report(validation_set["label"],pre))


             precision    recall  f1-score   support

          0       1.00      1.00      1.00        12
          1       0.85      1.00      0.92        11
          2       1.00      0.87      0.93        15

avg / total       0.96      0.95      0.95        38

使用上述这些方法时要调整的参数主要是

  • n_estimators 是森林里树的数量.

    通常数量越大,效果越好,但是计算时间也会随之增加.此外要注意,当树的数量超过一个临界值之后,算法的效果并不会很显著地变好.

  • max_features是分割节点时考虑的特征的随机子集的大小.

    这个值越低,方差减小得越多(泛化能力变强).但是偏差的增大也越多(准确率变差).根据经验,回归问题中使max_features = n_features,分类问题使 max_features = sqrt(n_features)(其中n_features是特征的个数)是比较好的默认值.

  • max_depth = None和min_samples_split=2 结合通常会有不错的效果(即生成完全的树).

通常默认的参数通常不是最佳的,同时还可能消耗大量的内存,最佳参数值应由交叉验证获得.

另外要请注意:

  • 在随机森林中,默认使用自助采样法(bootstrap = True)
  • 极限随机树中,默认策略是使用整个数据集(bootstrap = False)

当使用自助采样法方法抽样时,泛化精度是可以通过剩余的或者袋外的样本来估算的.设置oob_score = True即可实现.