机器学习

【机器学习实战】 集成学习和随机森林

本文主要是介绍【机器学习实战】 集成学习和随机森林,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

投票分类器

假设已经训练好了一些分类器, 每个分类器准确率约为80%。 这时, 要创建一个更好的分类器, 最简单的办法是聚合每个分类器的预测, 然后将得票数最多的结果作为预测类别。 这种大多数投票分类器被称为硬投票分类器。

如下用Scikit-Learn创建并训练一个投票分类器, 由三种不同的分类器组成:

# satellite datasets
from sklearn.datasets import make_moons

X, y = make_moons(n_samples=100, noise=0.15)
X_train, X_test, y_train, y_test = X[:90], X[90:], y[:90], y[90:]
# voting classifier
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_clf.fit(X_train, y_train)
# classification precision
from sklearn.metrics import accuracy_score

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

如果所有分类器都能算出类别概率(即具有predict_proba()方法), 那么你可以将概率在所有单个分类器上平均, 然后让Scikit-Learn给出平均概率最高的类别做出预测, 这被称为软投票法。
通常, 它比硬投票法表现更优, 因为它给予那些高度自信的投票更高的权重。
只需要用 voting="soft"代替voting=“hard”, 并确保所有分类器可以估算概率。

 

bagging 和 pasting

每个预测器使用的算法相同, 但是在不同训练集的随机子集上进行训练。采样时如果将样本放回, 这种方法叫bagging(bootstrap aggregating,自举汇聚法);采样时样本不放回, 叫pasting。bagging模型一般更好, 偏差略高, 预测器间关联更低, 集成方差更低。

# 训练一个包含500个决策树分类器的集成
# 每次从训练集随机采样50个训练实例进行训练
# 这是bagging的示例, 如果使用pasting,需设置bootstrap=False
# n_jobs指示Scikit-Learn使用多少CPU内核进行训练和预测, -1表示让使用所有可用内核

from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier

bag_clf = BaggingClassifier(
    DecisionTreeClassifier(), n_estimators=500,
    max_samples=50, bootstrap=True, n_jobs=-1)
bag_clf.fit(X_train, y_train)
y_pred = bag_clf.predict(X_test)

如果基本分类器可以估计类别概率, 则BaggingClassifier自动进行软投票。

 

包外评估
未被采样的训练实例称为包外(oob)实例
在Scikit-Learn中, 创建BaggingClassifier时, 设置oob_score=True就可以在训练结束后自动进行包外评估

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_
# 0.9222222222222223

训练实例的包外决策函数可以通过变量oob_decision_function_获得

bag_clf.oob_decision_function_
'''
array([[0.        , 1.        ],
       [1.        , 0.        ],
       [0.01030928, 0.98969072],
       [0.        , 1.        ],
       ...
       [0.97282609, 0.02717391],
       [0.        , 1.        ],
       [0.99415205, 0.00584795],
       [0.        , 1.        ]])
'''

 

随机补丁和随机子空间

BaggingClassifier类可以支持对特征进行采样, 由超参数max_features和bootstrap_features控制。
对训练实例和特征都进行采样,叫随机补丁法。
而保留所有训练实例(bootstrap=False且max_samples=1.0)但对特征进行采样(bootstrap_features=True且/或max_features<1.0)称为随机子空间法

 

随机森林

随机森林是决策树的集成,通常用bagging(有时也用pasting)方法训练,训练集大小通过max_samples设置。

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)

除少数例外, RandomForestClassifier具有DecisionTreeClassifier的所有超参数(以控制树的生长方式),以及BaggingClassifier的所有超参数来控制集成本身。

随机森林在树的生长上引入了更多的随机性:分裂节点是在一个随机生成的特征子集里搜索最好的特征, 使决策树有更大的多样性。

下面的BaggingClassifier与上述的RandomForestClassifier大致相同:

bag_clf = BaggingClassifier(
    DecisionTreeClassifier(splitter="random", max_leaf_nodes=16),
    n_estimators=500, max_samples=1.0, bootstrap=True, n_jobs=-1)

 

极端随机树
随机森林里单棵树生长过程中, 每个节点在分裂时仅考虑到一个随机子集所包含的特征。如果对每个特征使用随机阈值, 而不是搜索得出的最佳阈值(如常规决策树), 则可能让决策树生长得更随机。

极端随机的决策树组成的森林称为极端随机树集成(Extra-Tree), 以更高的偏差换取更低的偏差,且训练速度比常规随机森林快很多。

使用Scikit-Learn的ExtraTreesClassifier类可以创建一个极端随机数森林, 它的API与 RandomForestClassifier类相同。 同理, ExtraTreeRegressor类与RandomForestRegressor类的API也相同。

一般用交叉验证比较ExtraTreesClassifier类和RandomForestClassifier类的好坏。

 

特征重要性
Scikit-Learn通过查看使用该特征的树节点平均减少不纯度的程度衡量该特征的重要性。

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.09045003660617805
sepal width (cm) 0.023146425767105787
petal length (cm) 0.44988069044206885
petal width (cm) 0.4365228471846474
'''

 

提升法

提升法(boosting)将几个弱学习器结合成一个强学习器
大多数提升法总体思路是循环训练预测器, 每一次都对前序做出一些改正。

adaboost
新预测器通过更多地关注前序欠拟合的训练实例, 使新预测器不断地越来越关注难缠的问题, 从而对前序进行纠正。

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)

如果过拟合, 可以试试减少估算器数量, 或提高基础估算器正则化程度。

 

梯度提升
让新的预测器针对前一个预测器的残差进行拟合

# 决策树作为基础预测器 ———— 梯度树提升或梯度提升回归树(GBRT)
# 首先, 在训练集上拟合一个DecisionTreeRegressor
tree_reg1 = DecisionTreeRegressor(max_depth=2)
tree_reg1.fit(X, y)

# 针对第一个预测器的残差,训练第二个DecisionTreeRegressor
y2 = y - tree_reg1.predict(X)
tree_reg2 = DecisionTreeRegressor(max_depth=2)
tree_reg2.fit(X, y2)

# 针对第二个预测器的残差,训练第三个DecisionTreeRegressor
y3 = y2 - tree_reg1.predict(X)
tree_reg2 = DecisionTreeRegressor(max_depth=2)
tree_reg2.fit(X, y3)

# 将所有的树的预测相加, 从而对新实例进行预测
y_pred = sum(tree.predict(X_new) for tree in (tree_reg1, tree_reg2, tree_reg3))

 

训练GBRT, Scikit-Learn的GradientBoostRegressor类, 具有控制决策树生长和集成训练的超参数。

from sklearn.ensemble import GradientBoostRegressor

gbrt = GradientBoostingRegressor(max_depth=2, n_estimators=3, learning_rate=1.0)
gbrt.fit(X, y)

 

超参数learning_rate对每棵树的贡献进行缩放。如果设为低值, 如0.1, 则需要更多树来拟合训练, 泛化误差也更小。

找到树的最佳数量, 可以使用提前停止法。

# 训练一个拥有120棵树的集成, 每个阶段都对集成的预测返回一个迭代器(一棵树, 两棵树...)
# 测量每个阶段的验证误差, 从而找到最优数量
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error

X_train, X_test, y_train, y_test = 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) + 1

gbrt_best = GradientBoostingRegressor(max_depth=2, n_estimators=bst_n_estimators)
gbrt_best.fit(X, y)
# 提前停止法
# 验证误差连续五次迭代未改善时, 停止训练
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
            break

 

库XGBoost(Extreme Gradient Boost)提供了梯度提升的优化实现

import xgboost

xgb_reg = xgboost.XGBoostRegressor()
xgb_reg.fit(X_train, y_train)
y_pred = xgb_reg.predict(X_val)

# 自动处理提前停止
xgb_reg.fit(X_train, y_train,
            eval_set[(X_val, y_val)], early_stopping_rounds=2)
y_pred = xgb_reg.predict(X_val)

 

 

 

 

 

 

 

这篇关于【机器学习实战】 集成学习和随机森林的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!