<jupyter_start><jupyter_text>集成学习和随机森林假设你去随机问很多人一个很复杂的问题，然后把它们的答案合并起来。通常情况下你会发现这个合并的答案比一个专家的答案要好。这就叫做 群体智慧 。同样的，如果你合并了一组分类器的预测（像分类或者回归），你也会得到一个比单一分类器更好的预测结果。这一组分类器就叫做集成；__因此，这个技术就叫做集成学习，一个集成学习算法就叫做集成方法。__集成方法：* bagging* boosting* stacking  投票分类假设你已经训练了一些分类器，每一个都有 80% 的准确率。一个非常简单去创建一个更好的分类器的方法就是去整合每一个分类器的预测然后经过投票去预测分类。这种分类器就叫做硬投票分类器。> 令人惊奇的是这种投票分类器得出的结果经常会比集成中最好的一个分类器结果更好。事实上，即使每一个分类器都是一个弱学习器（意味着它们也就比瞎猜好点），集成后仍然是一个强学习器（高准确率），只要有足够数量的弱学习者，他们就足够多样化。 实例使用 sklearn 训练一个投票分类器：<jupyter_code>from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier 
from sklearn.ensemble import VotingClassifier 
from sklearn.linear_model import LogisticRegression 
from sklearn.svm import SVC


X, y = load_digits(n_class=10, return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y)


log_clf = LogisticRegression() 
rnd_clf = RandomForestClassifier() 
svm_clf = SVC(C=1, degree=2, kernel='poly')

voting_clf = VotingClassifier(estimators=[('lr', log_clf), ('rf', rnd_clf), ('svc', svm_clf)], voting='hard') 
voting_clf.fit(X_train, y_train)<jupyter_output>/usr/local/lib/python3.6/dist-packages/sklearn/linear_model/logistic.py:432: FutureWarning: Default solver will be changed to 'lbfgs' in 0.22. Specify a solver to silence this warning.
  FutureWarning)
/usr/local/lib/python3.6/dist-packages/sklearn/linear_model/logistic.py:469: FutureWarning: Default multi_class will be changed to 'auto' in 0.22. Specify the multi_class option to silence this warning.
  "this warning.", FutureWarning)
/usr/local/lib/python3.6/dist-packages/sklearn/ensemble/forest.py:245: FutureWarning: The default value of n_estimators will change from 10 in version 0.20 to 100 in 0.22.
  "10 in version 0.20 to 100 in 0.22.", FutureWarning)
/usr/local/lib/python3.6/dist-packages/sklearn/svm/base.py:193: FutureWarning: The default value of gamma will change from 'auto' to 'scale' in version 0.22 to account better for unscaled features. Set gamma explicitly to 'auto' or 'scale' to avoid this warning.
  "avoid this warning.", FutureWarning)<jupyter_text>在测试集上的准确率：<jupyter_code>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)) 
from sklearn.model_selection import GridSearchCV

param_grid = [
    {'kernel': ['rbf'], 'C': [1, 5, 10], 'gamma': [0.1, 2, 10]},
    {'kernel': ['poly'], 'C': [1, 5, 10], 'degree': [2, 3]},
]

svm_clf = SVC()
grid_search = GridSearchCV(svm_clf, param_grid, cv=5, scoring='neg_mean_squared_error', n_jobs=-1)
grid_search.fit(X_train, y_train)
grid_search.best_params_
grid_search.best_estimator_
svm_clf = grid_search.best_estimator_
y_pred = svm_clf.predict(X_test)
accuracy_score(y_test, y_pred)
from sklearn.metrics import f1_score, recall_score

f1_score(y_test, y_pred, average='macro')
recall_score(y_test, y_pred, average='macro')<jupyter_output><empty_output><jupyter_text>> 这三个单独的模型效果都太好了，所以无法反应投票分类的优势，实际上，投票分类的准确率应该会更高些。如果所有的分类器都能够预测类别的概率（例如他们有一个 `predict_proba()` 方法），那么你就可以让 sklearn 以最高的类概率来预测这个类，平均在所有的分类器上。这种方式叫做 __软投票__。他经常比硬投票表现的更好，因为它给予高自信的投票更大的权重。可以通过把 `voting="hard"` 设置为 `voting="soft"` 来保证分类器可以预测类别概率。然而这不是 SVC 类的分类器默认的选项，所以你需要把它的 `probability hyperparameter` 设置为 `True`（这会使 SVC 使用交叉验证去预测类别概率，其降低了训练速度，但会添加 `predict_proba()` 方法）。  Bagging 和 PastingBagging 和 Pasting 都允许在多个分类器间对训练集进行多次采样，但只有 Bagging，可以通过使用不同的训练算法去得到一些不同的分类器。另一种方法就是对每一个分类器都使用相同的训练算法，但是在不同的训练集上去训练它们。__有放回采样被称为装袋（Bagging，是 bootstrap aggregating 的缩写）。无放回采样称为粘贴（pasting）。__> Bagging 和 Pasting 都允许在多个分类器上对训练集进行多次采样，但只有 Bagging 允许对同一种分类器上对训练集进行进行多次采样。![image](./images/Image00625.jpg)当所有的分类器被训练后，集成可以通过对所有分类器结果的简单聚合来对新的实例进行预测。聚合函数通常对分类是 _统计模式_ （例如硬投票分类器）或者对回归是平均。 sklearn 中的 Bagging 和 Pastingsklearn 为 Bagging 和 Pasting 提供了一个简单的API：`BaggingClassifier` 类（或者对于回归可以是 `BaggingRegressor`。接下来的代码训练了一个 500 个决策树分类器的集成，每一个都是在数据集上有放回采样 100 个训练实例下进行训练（这是 Bagging 的例子，如果你想尝试 Pasting，就设置 `bootstrap=False`）。> 如果基分类器可以预测类别概率（例如它拥有 `predict_proba()` 方法），那么 `BaggingClassifier` 会自动的运行软投票，这是决策树分类器的情况。<jupyter_code>from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier

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)
y_pred<jupyter_output><empty_output><jupyter_text>Out-of-Bag 评估对于 Bagging 来说，一些实例可能被一些分类器重复采样，但其他的有可能不会被采样。`BaggingClassifier` 默认采样。`BaggingClassifier` 默认是有放回的采样 m 个实例（`bootstrap=True`），其中 m 是训练集的大小，这意味着平均下来只有63%的训练实例被每个分类器采样，剩下的37%个没有被采样的训练实例就叫做 Out-of-Bag 实例。注意对于每一个的分类器它们的 37% 不是相同的。__因为在训练中分类器从来没有看到过 oob 实例，所以它可以在这些实例上进行评估，而不需要单独的验证集或交叉验证__。可以拿出每一个分类器的 oob 来评估集成本身。在 sklearn 中，可以在训练后需要创建一个 `BaggingClassifier` 来自动评估时设置 `oob_score=True` 来自动评估。> 评估结果通过变量 `oob_score_` 来显示。<jupyter_code>bag_clf = BaggingClassifier(DecisionTreeClassifier(), n_estimators=500, bootstrap=True, n_jobs=-1, oob_score=True)

bag_clf.fit(X_train, y_train) 
bag_clf.oob_score_ 
# accuracy_score
y_pred = bag_clf.predict(X_test) 
accuracy_score(y_test, y_pred)<jupyter_output><empty_output><jupyter_text>测试集上准确率和交叉验证差不多，可以说，模型拟合的很好。> 对于每个训练实例 oob 决策函数也可通过 `oob_decision_function_` 变量来展示。<jupyter_code>bag_clf.oob_decision_function_<jupyter_output><empty_output><jupyter_text>随机贴片与随机子空间__`BaggingClassifier` 也支持采样特征__。它被两个超参数 `max_features` 和 `bootstrap_features` 控制。他们的工作方式和 `max_samples` 和 `bootstrap` 一样，但这是对于特征采样而不是实例采样。因此，每一个分类器都会被在随机的输入特征内进行训练。当在处理高维度输入下（例如图片）此方法尤其有效。__对训练实例和特征的采样被叫做随机贴片__。保留了所有的训练实例（例如 `bootstrap=False` 和 `max_samples=1.0`），但是对特征采样（`bootstrap_features=True` 并且/或者 `max_features` 小于 1.0）叫做随机子空间。  随机森林随机森林是决策树的一种集成，通常是通过 bagging 方法（有时是 pasting 方法）进行训练，通常用 `max_samples` 设置为训练集的大小。与建立一个 `BaggingClassifier` 然后把它放入 `DecisionTreeClassifier` 相反，可以使用更方便的也是对决策树优化够的 `RandomForestClassifier`（对于回归是 `RandomForestRegressor`）。> 除了一些例外，`RandomForestClassifier` 使用 `DecisionTreeClassifier` 的所有超参数（决定数怎么生长），把 `BaggingClassifier` 的超参数加起来来控制集成本身。<jupyter_code>from sklearn.ensemble import RandomForestClassifier

rnd_clf = RandomForestClassifier(n_estimators=500, max_leaf_nodes=16, n_jobs=-1) 
rnd_clf.fit(X_train, y_train)
y_pred_rf = rnd_clf.predict(X_test)
y_pred_rf<jupyter_output><empty_output><jupyter_text>极端随机树当在随机森林上生长树时，在每个结点分裂时只考虑随机特征集上的特征。相比于找到更好的特征我们可以通过使用对特征使用随机阈值使树更加随机（像规则决策树一样）。这种极端随机的树被简称为 Extremely Randomized Trees（极端随机树），或者更简单的称为 Extra-Tree。可以使用 sklearn 的 `ExtraTreesClassifier` 来创建一个 Extra-Tree 分类器。> 很难去分辨 `ExtraTreesClassifier` 和 `RandomForestClassifier` 到底哪个更好。通常情况下是通过交叉验证来比较它们（使用网格搜索调整超参数）。 特征重要度如果你观察一个单一决策树，重要的特征会出现在更靠近根部的位置，而不重要的特征会经常出现在靠近叶子的位置。__因此可以通过计算一个特征在森林的全部树中出现的平均深度来预测特征的重要性。__sklearn 在训练后会自动计算每个特征的重要度。可以通过 `feature_importances_` 变量来查看结果。  提升提升（Boosting，最初称为 假设增强 ）__指的是可以将几个弱学习者组合成强学习者的集成方法__。对于大多数的提升方法的思想就是按顺序去训练分类器，每一个都要尝试修正前面的分类。现如今已经有很多的提升方法了，但最著名的就是 Adaboost（适应性提升，是 Adaptive Boosting 的简称） 和 Gradient Boosting（梯度提升）。 Adaboost使一个新的分类器去修正之前分类结果的方法就是对之前分类结果不对的训练实例多加关注。这导致新的预测因子越来越多地聚焦于这种情况。这是 Adaboost 使用的技术。举个例子，去构建一个 Adaboost 分类器，第一个基分类器（例如一个决策树）被训练然后在训练集上做预测，在误分类训练实例上的权重就增加了。第二个分类机使用更新过的权重然后再一次训练，权重更新，以此类推（详见图 7-7）![images](./images/Image00633.jpg)sklearn 实例<jupyter_code>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)<jupyter_output><empty_output><jupyter_text>梯度提升另一个非常著名的提升算法是梯度提升。与 Adaboost 一样，梯度提升也是通过向集成中逐步增加分类器运行的，每一个分类器都修正之前的分类结果。然而，它并不像 Adaboost 那样每一次迭代都更改实例的权重，这个方法是去使用新的分类器去拟合前面分类器预测的 _残差_。> 这被叫做梯度提升回归树（GBRT，Gradient Tree Boosting 或者 Gradient Boosted Regression Trees）。可以使用 sklean 中的 `GradientBoostingRegressor` 来训练 GBRT 集成。<jupyter_code>from sklearn.ensemble import GradientBoostingRegressor

gbrt = GradientBoostingRegressor(max_depth=2, n_estimators=3, learning_rate=1.0) 
gbrt.fit(X, y)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09976127654227918, 'fraction_numerical': 0.016459354190224904, 'mean_word_length': 10.586608442503639, 'pattern_counts': {'":': 0, '<': 32, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '316857', 'license': 'MIT', 'n_tokens_mistral': 4618, 'n_tokens_neox': 4971, 'n_words': 484, 'path': 'sklearn-guide/ensemble.ipynb', 'repo_name': 'a630140621/machine-learning-course', 'size': '7959'}