@chanvee
2015-05-18T19:25:12.000000Z
字数 6565
阅读 4856
数据挖掘
Python
集成方法的目的是通过合并基于多种学习算法构成的预测器(estimators),从而实现比单个预测器具有更高的普适性(generalizability)和鲁棒性(robustness)。
常见的集成方法通常区分为如下两类:
- 对于averaging methods,其驱动的原则是通过独立的建立几种预测器进行预测,然后平均这些预测器的预测结果。在平均意义下,合并后的预测器因为减小了方差,因此其通常优于单个的预测器。
Examples: Bagging methods, Forests of randomized trees, ...
- 相反的,对于boosting methods,基本的预测器被以此建立,并且每一个预测器都尽量去减小合并后的预测器某一项的偏差。其动机是通过合并几个弱模型从而形成一个强有力的集成。
Examples: AdaBoost, Gradient Tree Boosting, ...
在集成算法(ensemble algorithms)中,bagging methods建立了一类通过在原始训练集上随机采样的子集建立几个黑盒(black-box)预测器然后这些单独的预测器作为最终的预测。这些方法常常被用来作为一种减小基本预测器的方差的方式(e.g., 决策树),通过引入随机到模型的构建过程然后将结果集成。在很多情况下,bagging methods是一个非常简单的可以提高相对的单个模型而且不需要适应底层算法的的方式。此外由于它也提供了一种减小过拟合的方式,其在复杂的模型(e.g.,fully developed decision trees)中工作的很好,相反的 boosting methods通常在若模型中表现更好 (e.g.,shallow decision trees)。
Bagging methods 可以有多种方式,但是彼此之间最大的不同是对训练集随机划分为子集的方式的区别:
- 当随机子集是对训练集中的例子(samples)进行随机划分形成的随机子集时,这种算法称为 Pasting
- 当是对例子进行替换时,这种算法称为 Bagging
- 当随机子集是对特征进行随机划分形成的随机子集,这种算法称为 Random Subspaces
- 最后,当基本的预测器是通过子集的例子和特征基础上建立的,那么这种算法称为 Random Patches
在 scikit-learn 中, bagging methods 统一定义为 BaggingClassifier 元预测器(meta-estimator) (相应的. BaggingRegressor), 通过用户指定的已经通过参数确定了以何种策略来划分子集的预测器作为输入。特别的, max_samples
和 max_features
控制随机子集的大小(对应例子数和特征数)), bootstrap
和 bootstrap_features
控制例子和特征是/否被替换。一个例子, 下面的代码说明了怎么实例化一个KNeighborsClassifier 的bagging ensemble 预测器, 每一个单独的分类器都建立在随机选取50%例子和50%特征的随机子集上。
%doctest_mode #removing >>> manually
>>> from sklearn.ensemble import BaggingClassifier
>>> from sklearn.neighbors import KNeighborsClassifier
>>> bagging = BaggingClassifier(KNeighborsClassifier(),
... max_samples=0.5, max_features=0.5)
Exception reporting mode: Plain
Doctest mode is: ON
Examples:
- Single estimator versus bagging: bias-variance decomposition
sklearn.ensemble模块包含了两种基于随机决策树的 averaging 算法: 随机森林算法(RandomForest algorithm) 和 (Extra-Trees method).。这两种算法都是利用扰动-合并(perturb-and-combine)技术特别是针对树 。这意味着不同的分类器是通过在分类器的构建过程中引入随机而生成的。然后将不同的单个分类器的预测结果取平均作为集成的预测结果。
与其他的分类器一样,随机森林分类器需要适应两个数组:一个大小为[n_samples, n_features]
来控制训练集稀疏或稠密的矩阵X, 以及一个大小为[n_samples]
表示目标值(分类标签)的数组Y:
%doctest_mode #removing >>> manually
>>> from sklearn.ensemble import RandomForestClassifier
>>> X = [[0, 0], [1, 1]]
>>> Y = [0, 1]
>>> clf = RandomForestClassifier(n_estimators=10)
>>> clf = clf.fit(X, Y)
Exception reporting mode: Context
Doctest mode is: OFF
与决策树一样,随机森林也可以用于解决多输出问题 (multi-output problems)。
在随机森林中,集成的每一棵树都是建立在可更换的训练集上。此外,当在建树划分节点时不再是从所有的特征中选择最好的划分,而是从随机选取的特征子集进行最好的划分。由于随机性,随机森林的通常会略微的增加(相对于单个的非随机的树),但是由于平均的缘故,它的 variance会减小最为bias增加的补偿,因此其是一个整体上更好的模型。
与原始文献不同的是,scikit-learn 在合并分类器时是通过平均预测的概率,而不是简单的每一个分类器对单独的类别进行投票。
在极度随机化的树中,随机化跟进一步。对于随机森林,通常利用一个备选的随机特征子集,而不是去寻找最优的判别阈值,对于每一个备选的特征阈值都是随机选取的,最好的随机生成阈值是通过划分规则进行选取的。这样通常会较多的降低模型的variance:
%doctest_mode #removing >>> manually
>>> from sklearn.cross_validation import cross_val_score
>>> from sklearn.datasets import make_blobs
>>> from sklearn.ensemble import RandomForestClassifier
>>> from sklearn.ensemble import ExtraTreesClassifier
>>> from sklearn.tree import DecisionTreeClassifier
>>> X, y = make_blobs(n_samples=10000, n_features=10, centers=100,
... random_state=0)
>>> clf = DecisionTreeClassifier(max_depth=None, min_samples_split=1,
... random_state=0)
>>> scores = cross_val_score(clf, X, y)
>>> print(scores.mean())
>>> clf = RandomForestClassifier(n_estimators=10, max_depth=None,
... min_samples_split=1, random_state=0)
>>> scores = cross_val_score(clf, X, y)
>>> print(scores.mean() )
>>> clf = ExtraTreesClassifier(n_estimators=10, max_depth=None,
... min_samples_split=1, random_state=0)
>>> scores = cross_val_score(clf, X, y)
>>> print(scores.mean() > 0.999)
Exception reporting mode: Context
Doctest mode is: OFF
0.979408793821
0.999607843137
True
利用随机森林最主要的两个参数可就是 n_estimators
和 max_features
。 前者指定的树的个数。一般来说越大越好,但是也会更花时间。此外值得注意的是当结果已经明显较好并超过了某个判别的值那么其会自动停止。后者是当划分节点时随机子集的大小。越小则variance减小的更多,但是bias也会增加的更多。经验上一个好的默认的选择是对于回归问题max_features=n_features
,对于分类问题max_features=sqrt(n_features)
。通常设置 max_depth=None
同时min_samples_split=1
(i.e., 完全开发的树)可以得到一个好结果。需要记住的是这些值通常不是最优的, 可能导致模型消耗大量的运存。最好的参数通常需要交叉验证。此外,在随机森林中, bootstrap samples 默认情况下是使用的(bootstrap=True) ,但是对于extra-trees需要利用全部数据 (bootstrap=False)。
一个特征在决策一个节点时在树中的相对位置可以当做是这个特征预测目标变量相对的重要性。在树的顶部的特征能够将更多的输入例子进行划分因此其贡献越大。因此一个特征预估的能够划分输入项里的比例通常被用来评估其相对的重要性 。
在实际应用中,特征的重要性存储在学习好的模型中一个叫做 feature_importances_
的属性中。这是一个大小为特征数的数组,里面的值都为正并且和为1。值越大代表在构建模型是特征越重要。
AdaBoost的核心原则是重复在更新的数据上学习一系列的若分类器 (i.e., 模型纸币随机猜测好一点,比如小的决策树 ) 。然后把这些结果按着一定的权重合并作为最终的结果。对每一个训练例子结果的更新就是所谓的boosting迭代有一系列的权重
下面的例子展示了怎么利用100个弱分类器来构建 AdaBoost 分类器
>>> from sklearn.cross_validation import cross_val_score
>>> from sklearn.datasets import load_iris
>>> from sklearn.ensemble import AdaBoostClassifier
>>> iris = load_iris()
>>> clf = AdaBoostClassifier(n_estimators=100)
>>> scores = cross_val_score(clf, iris.data, iris.target)
>>> print(scores.mean() )
0.959967320261
弱分类其的数目由n_estimators
控制。参数 learning_rate
控制弱分类器在控制最后的合并。默认情况下,弱分类器都是decision stumps。不同的弱分类器可以通过参数base_estimator
指定。为了得到好结果可调的参数是n_estimators
,以及基本分类器的复杂度 (e.g., 比如在决策树max_depth
或者 最小的需要的样例min_samples_leaf
)。
Gradient Tree Boosting or Gradient Boosted Regression Trees (GBRT) 是一种普适化的对不同任意的损失函数的boosting。GBRT是一种准确的和有效的现成的(off-the-shelf) 可以同时用于回归和分类问题。 Gradient Tree Boosting 模型被应用于很多诸如包括网页搜索和经济领域。
GBRT的优势是:
- 处理混合的类型 (= 异质特征heterogeneous features)
- 预测能力
- 对异常值鲁棒
GBRT的缺点是:
- 可扩展性,由于其连续性boosting很难并行化。
模块sklearn.ensemble提供了利用GBRT解决分类和回归问题。
GradientBoostingClassifier支持二元和多元分类。下面的例子展示怎么用100个弱分类器训练一个gradient boosting分类器:
>>> from sklearn.datasets import make_hastie_10_2
>>> from sklearn.ensemble import GradientBoostingClassifier
>>> X, y = make_hastie_10_2(random_state=0)
>>> X_train, X_test = X[:2000], X[2000:]
>>> y_train, y_test = y[:2000], y[2000:]
>>> clf = GradientBoostingClassifier(n_estimators=100, learning_rate=1.0,
... max_depth=1, random_state=0).fit(X_train, y_train)
>>> clf.score(X_test, y_test)
0.91300000000000003
弱分类器的数量由参数n_estimators
分类;每棵树的大小要么由 max_depth
设定,要么由max_leaf_nodes
设定。learning_rate
是一个取值范围为(0.0, 1.0]通过shrinkage控制过拟合。
GradientBoostingRegressor假设指定许多不同的损失函数; 回归问题默认的损失函数是最小二乘least squares ('ls')。
>>> import numpy as np
>>> from sklearn.metrics import mean_squared_error
>>> from sklearn.datasets import make_friedman1
>>> from sklearn.ensemble import GradientBoostingRegressor
>>> X, y = make_friedman1(n_samples=1200, random_state=0, noise=1.0)
>>> X_train, X_test = X[:200], X[200:]
>>> y_train, y_test = y[:200], y[200:]
>>> est = GradientBoostingRegressor(n_estimators=100, learning_rate=0.1,
... max_depth=1, random_state=0, loss='ls').fit(X_train, y_train)
>>> mean_squared_error(y_test, est.predict(X_test))
5.0091548599603213
scikit-learn原文见http://scikit-learn.org/stable/modules/ensemble.html#ensemble-methods