机器学习之集成学习和随机森林

1、集成学习

集成学习就是合并多个分类器的预测。通常会在一个项目快结束的时候使用集成算法,一旦创建了一些好的分类器,就可使用集成把它们合并成一个更好的分类器。
著名的集成方法:投票分类、bogging、pasting、boosting、stacking、和一些其它算法。node

1.1 投票分类(少数服从多数)

使人惊奇的是这种投票分类器得出的结果常常会比集成中最好的一个分类器结果更好。
事实上,即便每个分类器都是一个弱学习器(意味着它们也就比瞎猜好点),集成后仍然是一个强学习器(高准确率),只要有足够数量的弱学习者,他们就足够多样化。git

若是每个分类器都在同一个数据集上训练,会致使犯同一种类型的错误。相比较而言,每一个分类器在不一样的数据集上训练,集成后的结果会更好。
下面使用moons数据集,训练三个分类器,使用集成算法。github

from sklearn.datasets import make_moons from sklearn.model_selection import train_test_split moons = make_moons(noise=0.3, random_state=0) X, y = moons X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.4, random_state=42) # print(X_train[10], y_train[0])
[-0.65805008 -0.12944211] 0
from sklearn.ensemble import RandomForestClassifier from sklearn.ensemble import VotingClassifier #软投票/多数规则分类器
from sklearn.linear_model import LogisticRegression from sklearn.svm import SVC log_clf = LogisticRegression() rnd_clf = RandomForestClassifier() svm_clf = SVC() voting_clf = VotingClassifier(estimators=[("lr", log_clf), ("rf", rnd_clf), ("svc", svm_clf)], voting="hard") #voting:"soft"/"hard" #硬投票,默认"hrad"。"hard",使用预测的类标签进行多数规则投票。 #软投票,"soft",基于预测几率之和的argmax来预测类别标签,这推荐用于通过良好校准的分类器的集合。

# voting_clf.fit(X_train, y_train)

测一下准确率:算法

from sklearn.metrics import accuracy_score #分类准确度得分

for clf in (log_clf, rnd_clf, svm_clf, voting_clf): clf.fit(X_train, y_train) y_pred = clf.predict(X_test) print(clf.__class__.__name__, accuracy_score(y_test, y_pred))
LogisticRegression 0.875 RandomForestClassifier 0.925 SVC 0.95 VotingClassifier 0.95

1.2 Bagging和Pasting

对每个分类器都使用相同的训练算法,可是在不一样的训练集上去训练它们。有放回采样被称为装袋(Bagging,是 bootstrap aggregating 的缩写)。无放回采样称为粘贴(pasting)bootstrap

聚合函数一般对分类是统计模式(例如硬投票分类器),对回归是平均数组

API:对分类是BaggingClassifier
对于回归是`BaggingRegressordom

接下来的代码训练了一个 500 个决策树分类器的集成,每个都是在数据集上有放回采样 100 个训练实例下进行训练(这是 Bagging 的例子,若是你想尝试 Pasting,就设置bootstrap=False)函数

n_jobs参数告诉 sklearn 用于训练和预测所须要 CPU 核的数量。(-1 表明着 sklearn 会使用全部空闲核)学习

整体而言,Bagging 一般会致使更好的模型优化

from sklearn.ensemble import BaggingClassifier from sklearn.tree import DecisionTreeClassifier bag_clf = BaggingClassifier(DecisionTreeClassifier(), n_estimators=500, max_samples=50, oob_score=True, bootstrap=True, n_jobs=-1) bag_clf.fit(X_train, y_train)
BaggingClassifier(base_estimator=DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=None, max_features=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, min_samples_leaf=1, min_samples_split=2, min_weight_fraction_leaf=0.0, presort=False, random_state=None, splitter='best'), bootstrap=True, bootstrap_features=False, max_features=1.0, max_samples=50, n_estimators=500, n_jobs=-1, oob_score=True, random_state=None, verbose=0, warm_start=False)
  1. 在 sklearn 中,你能够在训练后须要建立一个BaggingClassifier来自动评估时设置oob_score=True来自动评估。而不须要使用交叉验证或者使用单独的验证集
bag_clf.oob_score_
0.8833333333333333
# 比较一下
y_pred = bag_clf.predict(X_test) accuracy_score(y_test, y_pred)

0.95

1.3 随机贴片和随机子空间

BaggingClassifier也支持采样特征。它被两个超参数max_features和bootstrap_features控制。他们的工做方式和max_samples和bootstrap同样,但这是对于特征采样而不是实例采样。所以,每个分类器都会被在随机的输入特征内进行训练。

当你在处理高维度输入下(例如图片)此方法尤为有效。对训练实例和特征的采样被叫作随机贴片。保留了全部的训练实例(例如bootstrap=False和max_samples=1.0),可是对特征采样(bootstrap_features=True而且/或者max_features小于 1.0)叫作随机子空间。

采样特征致使更多的预测多样性,用高误差换低方差。

1.4 boosting(提高)

提高(Boosting,最初称为假设加强)指的是能够将几个弱学习者组合成强学习者的集成方法。
对于大多数的提高方法的思想就是按顺序去训练分类器,每个都要尝试修正前面的分类。
现现在已经有不少的提高方法了,但最著名的就是 Adaboost(适应性提高,是 Adaptive Boosting 的简称) 和 Gradient Boosting(梯度提高)。让咱们先从 Adaboost 提及。

1.4.1 Adaboost

使一个新的分类器去修正以前分类结果的方法就是对以前分类结果不对的训练实例多加关注。这致使新的预测因子愈来愈多地聚焦于这种状况。这是 Adaboost 使用的技术。
举个例子,去构建一个 Adaboost 分类器,第一个基分类器(例如一个决策树)被训练而后在训练集上作预测,在误分类训练实例上的权重就增长了。第二个分类机使用更新过的权重而后再一次训练,权重更新,以此类推

sklearn 一般使用 Adaboost 的多分类版本 SAMME(这就表明了 分段加建模使用多类指数损失函数)。若是只有两类别,那么 SAMME 是与 Adaboost 相同的。若是分类器能够预测类别几率(例如若是它们有predict_proba()),若是 sklearn 可使用 SAMME 叫作SAMME.R的变量(R 表明“REAL”),这种依赖于类别几率的一般比依赖于分类器的更好。

from sklearn.ensemble import AdaBoostClassifier ada_clf = AdaBoostClassifier(DecisionTreeClassifier(max_depth=1), n_estimators=200,algorithm="SAMME.R", learning_rate=0.5) ada_clf.fit(X_train, y_train)
AdaBoostClassifier(algorithm='SAMME.R', base_estimator=DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=1, max_features=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, min_samples_leaf=1, min_samples_split=2, min_weight_fraction_leaf=0.0, presort=False, random_state=None, splitter='best'), learning_rate=0.5, n_estimators=200, random_state=None)

1.4.2 梯度提高(Gradient Boosting)
另外一个很是著名的提高算法是梯度提高。与 Adaboost 同样,梯度提高也是经过向集成中逐步增长分类器运行的,每个分类器都修正以前的分类结果。然而,它并不像 Adaboost 那样每一次迭代都更改实例的权重,这个方法是去使用新的分类器去拟合前面分类器预测的残差 。

(1)以决策树回归详解

from sklearn.tree import DecisionTreeRegressor # 第一个分类器
tree_reg1 = DecisionTreeRegressor(max_depth=2) tree_reg1.fit(X, y) # 在第一个分类器的残差上运行第二个分类器
y2 = y - tree_reg1.predict(X) tree_reg2 = DecisionTreeRegressor(max_depth=2) tree_reg2.fit(X, y2) # 在第二个分类器的残差上运行第三个分类器
y3 = y2 - tree_reg1.predict(X) tree_reg3 = DecisionTreeRegressor(max_depth=2) ree_reg3.fit(X, y3) # 它能够经过集成全部树的预测来在一个新的实例上进行预测。
y_pred = sum(tree.predict(X_new) for tree in (tree_reg1, tree_reg2, tree_reg3))

(2)使用sklearn自带分类器实现

    • 超参数learning_rate 确立了每一个树的贡献。若是你把它设置为一个很小的树,例
      如 0.1,在集成中就须要更多的树去拟合训练集,但预测一般会更好。这个正则化技术叫作 shrinkage
from sklearn.ensemble import GradientBoostingRegressor gbrt = GradientBoostingRegressor(max_depth=2, n_estimators=3, learning_rate=1.0) gbrt.fit(X, y)

(3)更好的梯度提高

为了找到树的最优数量,最简单使用这个技术的方法就是使用staged_predict():它在训练的每一个阶段(用一棵树,两棵树等)返回一个迭代器。接下来的代码用 120 个树训练了一个 GBRT 集成,而后在训练的每一个阶段验证错误以找到树的最佳数量,最后使用 GBRT 树的最优数量训练另外一个集成:

import numpy as np from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error from sklearn.ensemble import GradientBoostingRegressor X_train, X_val, y_train, y_val = train_test_split(X, y) gbrt = GradientBoostingRegressor(max_depth=2, n_estimators=120) gbrt.fit(X_train, y_train) errors = [mean_squared_error(y_val, y_pred) for y_pred in gbrt.staged_predict(X_val)] bst_n_estimators = np.argmin(errors) ## np.argmin表示最小值在数组中所在的位置
gbrt_best = GradientBoostingRegressor(max_depth=2,n_estimators=bst_n_estimators) gbrt_best.fit(X_train, y_train)
GradientBoostingRegressor(alpha=0.9, criterion='friedman_mse', init=None, learning_rate=0.1, loss='ls', max_depth=2, max_features=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, min_samples_leaf=1, min_samples_split=2, min_weight_fraction_leaf=0.0, n_estimators=119, n_iter_no_change=None, presort='auto', random_state=None, subsample=1.0, tol=0.0001, validation_fraction=0.1, verbose=0, warm_start=False)

(4)第二种更好的梯度提高
你也能够早早的中止训练来实现早停(与先在一大堆树中训练,而后再回头去找最优数目相反)。你能够经过设置warm_start=True来实现 ,这使得当fit()方法被调用时 sklearn 保留现有树,并容许增量训练。接下来的代码在当一行中的五次迭代验证错误没有改善时会中止训练:

gbrt = GradientBoostingRegressor(max_depth=2, warm_start=True) min_val_error = float("inf") error_going_up = 0 for n_estimators in range(1, 120): gbrt.n_estimators = n_estimators gbrt.fit(X_train, y_train) y_pred = gbrt.predict(X_val) val_error = mean_squared_error(y_val, y_pred) if val_error < min_val_error: min_val_error = val_error error_going_up = 0 else: error_going_up += 1
    if error_going_up == 5:

1.5 Stacking

另一个集成方法叫作 Stacking(stacked generalization 的缩写)。
这个算法基于一个简单的想法:不使用琐碎的函数(如硬投票)来聚合集合中全部分类器的预测,而是本身训练一个模型来执行这个聚合。

sklearn 并不直接支持 stacking ,可是你本身组建是很容易的(看接下来的练习)。或者你也可使用开源的项目例如 brew (网址为 <https: brew="" github.com="" viisar="">)</https:>

2、 随机森林

2.1 实现随机森林

随机森林是决策树的一种集成,**一般是经过 bagging 方法(有时是 pasting 方法)**进行训练,一般用max_samples设置为训练集的大小与创建一个BaggingClassifier而后把它放入 DecisionTreeClassifier 相反,你可使用更方便的也是对决策树优化够的RandomForestClassifier(对于回归是RandomForestRegressor)。接下来的代码训练了带有 50个树(每一个被限制为 16 叶子结点)的决策森林,使用全部空闲的 CPU 核:

from sklearn.ensemble import RandomForestClassifier rnd_clf = RandomForestClassifier(n_estimators=50, max_leaf_nodes=16, n_jobs=-1) rnd_clf.fit(X_train, y_train) y_pred_rf = rnd_clf.predict(X_test)

2.2 极端随机树

当你在随机森林上生长树时,在每一个结点分裂时只考虑随机特征集上的特征(正如以前讨论过的同样)。相比于找到更好的特征咱们能够经过使用对特征使用随机阈值使树更加随机(像规则决策树同样)。

这种极端随机的树被简称为 Extremely Randomized Trees(极端随机树),或者更简单的称为 Extra-Tree。再一次用高误差换低方差。它还使得 Extra-Tree 比规则的随机森林更快地训练,由于在每一个节点上找到每一个特征的最佳阈值是生长树最耗时的任务之一。

你可使用 sklearn 的ExtraTreesClassifier来建立一个 Extra-Tree 分类器。他的 API 跟RandomForestClassifier是相同的,类似的, ExtraTreesRegressor 跟RandomForestRegressor也是相同的 API。

咱们很难去分辨ExtraTreesClassifier和RandomForestClassifier到底哪一个更好。一般状况下是经过交叉验证来比较它们(使用网格搜索调整超参数)。

2.3 特征重要度

若是你观察一个单一决策树,重要的特征会出如今更靠近根部的位置,而不重要的特征会常常出如今靠近叶子的位置。所以咱们能够经过计算一个特征在森林的所有树中出现的平均深度来预测特征的重要性。sklearn 在训练后会自动计算每一个特征的重要度。你能够经过feature_importances_变量来查看结果。下面以鸢尾花数据为例,得出最重要的特征是花瓣长度(44%)和宽度(42%)。而萼片长度和宽度相对比较是不重要的(分别为 11% 和 2%)

from sklearn.datasets import load_iris iris = load_iris() rnd_clf = RandomForestClassifier(n_estimators=500, n_jobs=-1) rnd_clf.fit(iris["data"], iris["target"]) for name, score in zip(iris["feature_names"], rnd_clf.feature_importances_): print(name, score)
sepal length (cm) 0.10318363296580253 sepal width (cm) 0.024861953583854814 petal length (cm) 0.43069959942052854 petal width (cm) 0.4412548140298142
相关文章
相关标签/搜索