集成学习思路
- 多模型融合。
- 一个模型解决不了的问题,多个模型一起。
数据准备:make_moons
类似于月牙形状的数据集,通常用于机器学习中的分类问题。
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_moons
import matplotlib.pyplot as plt
# 随机选择500个数据点,为了演示模型效果,加入了较高的噪声数据noise
X, y = make_moons(n_samples=500, noise=0.3, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
plt.plot(X[:, 0][y == 0], X[:, 1][y == 0], 'ro', alpha=0.6)
plt.plot(X[:, 0][y == 1], X[:, 1][y == 1], 'bs', alpha=0.6)
plt.show()
1. 投票策略-Voting
- 硬投票:直接用类别值,少数服从多数。
- 软投票:各自分类器的概率值进行加权平均(要求每个分类器都能计算出概率值)。
1.1 硬投票
对于某个样本,三种模型的预测结果为“红红蓝”,红:蓝=2:1,则硬投票预测结果为“红”。
以下示例中,使用随机森林、逻辑回归和支持向量机分别进行预测,得到每个分类器的准确率。
代码示例:
from sklearn.ensemble import RandomForestClassifier, VotingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
log_clf = LogisticRegression()
rfc_clf = RandomForestClassifier()
svm_clf = SVC()
# 硬投票
voting_clf = VotingClassifier(estimators=[('lr', log_clf), ('rf', rfc_clf), ('svc', svm_clf)], voting='hard')
for clf in (log_clf, rfc_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.864
RandomForestClassifier 0.896
SVC 0.896
VotingClassifier 0.904
可以看出,硬投票的准确率0.904,高于其它单模型。
1.2 软投票
对于某个样本,计算三种模型的预测结果(概率),根据概率判断类别。
代码示例
from sklearn.ensemble import RandomForestClassifier, VotingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
log_clf = LogisticRegression()
rfc_clf = RandomForestClassifier()
# 支持向量机默认不计算概率值,需要显示传参probability=True
svm_clf = SVC(probability=True)
# 修改voting参数为soft
voting_clf = VotingClassifier(estimators=[('lr', log_clf), ('rf', rfc_clf), ('svc', svm_clf)], voting='soft')
# 计算每个分类其的概率值
for clf in (log_clf, rfc_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.864
RandomForestClassifier 0.88
SVC 0.896
VotingClassifier 0.92
软投票策略效果高于硬投票。
对于单个模型,可以通过其classes_属性和predict_proba()方法得到每个类别的概率。
2. Bagging策略
2.1 算法过程
- 首先对训练数据集进行多次采样(数据和特征),保证每次得到的采样数据都是不同的(增加多样性,同时降低过拟合风险)。
- 训练多个基础模型(并行计算,提升效率)。
- 训练的每个模型效果有好有坏,预测新样本时,先得到所有模型的预测结果,再进行集成,最终确定整体预测结果。
特点:
- 随机:数据采样随机,特征选择随机。
- 并行计算,分别同时独立训练多个模型,增加多样性。
- 预测时需得到所有基础模型结果再进行集成。
- 解决过拟合问题。
代码示例:
from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier
# 基础模型,模型个数,最大特征数
bag_clf = BaggingClassifier(estimator=DecisionTreeClassifier(), # 基础模型
n_estimators=500, # 模型个数
max_features=X.shape[1], # 最大特征数
bootstrap=True, # 是否随机采样
n_jobs=-1, # 是否多线程计算,-1表示使用所有CPU
random_state=42)
bag_clf.fit(X_train, y_train)
y_pred = bag_clf.predict(X_test)
accuracy_score(y_test, y_pred)
0.92
# 决策树示例
tree_clf = DecisionTreeClassifier(random_state=42)
tree_clf.fit(X_train, y_train)
y_pred_tree = tree_clf.predict(X_test)
accuracy_score(y_test, y_pred_tree)
0.856
在上述示例中,构建了Bagging分类器和决策树分类器,其运行结果为0.92和0.856,Bagging的效果高于决策树。
由于同时训练多个决策树,运行速度相较于决策树会变慢。
2.2 可视化决策边界
import numpy as np
from matplotlib.colors import ListedColormap
def plot_decision_boundary(clf, X, y, axes=[-2, 3, -2, 2], alpha=0.5, contour=True):
x1s = np.linspace(axes[0], axes[1], 100)
x2s = np.linspace(axes[2], axes[3], 100)
x1, x2 = np.meshgrid(x1s, x2s)
X_new = np.c_[x1.ravel(), x2.ravel()]
y_pred = clf.predict(X_new).reshape(x1.shape)
custom_cmap = ListedColormap(['#FFC0CB', '#F0FFFF', '#507d50'])
plt.contourf(x1, x2, y_pred, cmap=custom_cmap, alpha=0.5)
if contour:
custom_cmaps = ListedColormap(['#7d7d58', '#F0FFFF', '#507d50'])
plt.contour(x1, x2, y_pred, cmap=custom_cmaps, alpha=0.8)
plt.plot(X[:, 0][y == 0], X[:, 1][y == 0], 'ro', alpha=0.6)
plt.plot(X[:, 0][y == 0], X[:, 1][y == 1], 'bs', alpha=0.6)
plt.axis(axes)
plt.xlabel('x1')
plt.xlabel('x2')
plt.figure(figsize=(12, 5))
plt.subplot(121)
plot_decision_boundary(tree_clf, X, y)
plt.title('Decision Tree')
plt.subplot(122)
plot_decision_boundary(bag_clf, X, y)
plt.title('Decision Tree with Bagging')
plt.show()
总体上,Bagging效果高于单模型。
注意:在(1.5,0.25)位置上,有两个红色点,按照分布来看,这两个点更有可能是蓝色点。决策树对这两个点分类正确,而Bagging分类错误,模型泛化能力上,Bagging高于单模型的决策树。
2.3 OOB策略
- out of bag 解决验证问题
在Bagging方法中,模型通常是基于对训练集进行有放回抽样而构建的。由于有放回抽样的方式,大约有37%的训练样本不会被抽中,这些未被抽中的样本就被称为OOB样本。
oob_score参数是为了利用这些未被抽中的样本来评估模型的性能。在训练过程中,对每个基础模型,可以使用其对OOB样本的预测来计算一个袋外分数(OOB Score)。最终,这些袋外分数可以用来估计整体模型在未见过的数据上的性能。
在进行有放回的抽样时,对于一个包含N个样本的训练集,抽样时,某个样本被抽中的概率为 1 N \frac{1}{N} N1。因此,某个样本没有被选中的概率是 ( 1 − 1 N ) N {(1-\frac{1}{N})}^N (1−N1)N,在N很大时会趋近于 1 e \frac{1}{e} e1,约为0.37。
代码示例
# oob_score=True,使用OOB策略
bag_clf = BaggingClassifier(estimator=DecisionTreeClassifier(), # 基础模型
n_estimators=500, # 模型个数
max_features=X.shape[1], # 最大特征数
bootstrap=True, # 是否随机采样
n_jobs=-1, # 是否多线程计算,-1表示使用所有CPU
random_state=42,
oob_score=True
)
bag_clf.fit(X_train, y_train)
bag_clf.oob_score_ # 验证集的结果
0.896
2.4 随机森林
- Bagging的经典代表。
- 能够处理很高维度的数据,并且不用做特征选择。
- 在训练完后,能够给出哪些特征变量比较重要,解释性强。
- 可以并行计算,速度比较快。
代码示例
from sklearn.datasets import load_iris
iris = load_iris()
# 随机森林分类器
rf_clf = RandomForestClassifier(n_estimators=500, n_jobs=-1)
rf_clf.fit(iris['data'], iris['target'])
for name, score in zip(iris['feature_names'], rf_clf.feature_importances_):
print(name, score)
sepal length (cm) 0.10090833612940953
sepal width (cm) 0.022648813776966623
petal length (cm) 0.43745799107944655
petal width (cm) 0.4389848590141774
feature_importances_属性表示特征重要性。
2.5 特征重要性
数据准备:手写数字数据集,每一行表示28*28灰度图像像素值。
数据每一行是784列,mnist是一个类似字典的数据格式。
from sklearn.datasets import fetch_openml
mnist = fetch_openml('mnist_784', version=1, parser='auto')
rf_clf = RandomForestClassifier(n_estimators=500, n_jobs=-1)
rf_clf.fit(mnist['data'], mnist['target'])
可以通过可视化方法反转绘制原图,使用第一行的数据,转为28*28的二维数组。
表示真实数字5。
plt.imshow(mnist['data'].iloc[0, :].values.reshape((28, 28)), cmap='gray')
plt.show()
模型训练完成后,可以查看其特征重要性(每个像素点对于分类的重要性)。
import matplotlib.cm
def plot_digit(data):
image = data.reshape(28, 28)
plt.imshow(image, cmap=matplotlib.cm.hot)
plt.axis('off')
plt.colorbar(ticks=[rf_clf.feature_importances_.min(),
rf_clf.feature_importances_.max()])
plot_digit(rf_clf.feature_importances_)
在图片的四个角落位置,像素值基本为0(在处理图像时,习惯将数字放在中间),而中间位置通常是数字经过的地方,在中间位置,其特征重要性远高于角落位置。
3. Boosting-提升策略
3.1 AdaBoost
adaptive boosting,自适应提升。
3.1.1 AdaBoost原理
做题时,这次做错的题,加大对错题的研究时间,争取下次作对。
- 不断提升错误样本重要性。
以下示例使用SVM分类演示AdaBoost的流程。
from sklearn.svm import SVC
m = len(X_train)
plt.figure(figsize=(14, 5))
for subplot, learning_rate in ((121, 1), (122, 0.5)):
# 最初所有样本权重一致
sample_weights = np.ones(m)
plt.subplot(subplot)
for i in range(5):
svm_clf = SVC(kernel='rbf', C=0.05, random_state=42)
# 训练模型,设置样本权重sample_weight
svm_clf.fit(X_train, y_train, sample_weight=sample_weights)
y_pred = svm_clf.predict(X_train)
# 更新权重,learning_rate控制权重增大或减小的幅度
sample_weights[y_pred != y_train] *= (1+learning_rate)
# 决策边界
plot_decision_boundary(svm_clf, X, y, alpha=0.2)
plt.title('learning_rate = {}'.format(learning_rate))
if subplot == 121:
plt.text(-0.7, -0.65, '1', fontsize=25)
plt.text(-0.6, -0.10, '2', fontsize=25)
plt.text(-0.5, 0.15, '3', fontsize=25)
plt.text(-0.4, 0.55, '4', fontsize=25)
plt.text(-0.3, 0.90, '5', fontsize=25)
plt.show()
重点:
- 权重更新
- 调整学习率,过大的学习率可能导致模型变差,较小的学习率会增加迭代次数。
3.1.2 AdaBoost示例
from sklearn.ensemble import AdaBoostClassifier
# AdaBoost分类器
ada_clf = AdaBoostClassifier(
estimator=DecisionTreeClassifier(max_depth=1), # 基础模型
n_estimators=200,
learning_rate=0.5, # 学习率
random_state=42
)
ada_clf.fit(X_train, y_train)
plot_decision_boundary(ada_clf, X, y)
3.2 Gradient Boosting
梯度提升
3.2.1 Gradient Boosting原理
刚开始时,训练得到第一个基础模型,再次加入第二个训练好的基础模型,该模型有好有坏,坏的舍弃,最终得到一个越来越强的集成模型。每一次的计算是为了减少上一次的残差,GBDT在残差减少(负梯度)的方向上建立一个新的模型。
- 从弱学习器开始,通过加权来进行训练,不断减小误差。
- 将上一轮残差作为本轮输入,最小化本轮残差。
- 串行计算,模型只能一步一步提升,算法效率低。
- 解决欠拟合问题。
Gradient Boosting代表:梯度提升决策树(Gradient Boosting Decision Tree,GBDT)
GBDT结合了提升方法(Boosting)的思想与决策树模型,通过迭代地训练决策树来减少模型的偏差,从而提高模型的预测精度。
下面是GBDT的基本原理:
- 提升方法(Boosting)
提升方法是一种集成学习技术,其核心思想是将多个弱学习器组合成一个强学习器。在GBDT中,这些弱学习器通常是决策树,特别是回归树(用于回归任务)或分类树(用于分类任务)。每一轮的学习都是为了减少上一轮的残差(实际值与预测值之间的差异),通过这种方式,模型逐步增强其预测能力。 - 梯度提升-负梯度一阶展开
梯度提升是提升方法的一种,它利用梯度下降算法来最小化损失函数。在每一轮迭代中,GBDT都会构建一个新的决策树来预测前一轮所有树的残差。然后,它将这个新树的预测添加到之前的树的预测上,通过这种方式逐步减少总体的损失。 - 迭代过程
- 初始化:GBDT首先使用一个基础模型来进行初始化预测。
- 迭代构建:接着,算法进入迭代循环,每一次迭代包括以下步骤:
- 计算残差:计算当前模型的残差,即真实值与当前模型预测值之间的差。
- 构建决策树:使用残差作为目标值,构建一个新的决策树。
- 更新模型:将这棵新树的预测结果乘以一个学习率(也称为步长)后加到现有模型的预测上,以更新模型。
- 模型输出:迭代达到指定次数后,所有决策树的预测结果相加得到最终的模型预测。
- 学习率(Learning Rate)
学习率是一个重要的超参数,它控制着每棵树对最终模型的贡献度。较小的学习率意味着需要更多的树来训练模型,通常可以提高模型的性能,但同时也会增加计算成本。 - 正则化
为了避免过拟合,GBDT还可以通过各种方法进行正则化,如设置树的最大深度、最小叶子节点的样本数、树的最大叶子节点数等。
数据准备:随机生成一些样本点。
np.random.seed(42)
X = np.random.rand(100, 1)-0.5
y = 3*X[:, 0]**2 + 0.05*np.random.randn(100)
第一步,训练模型。
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_reg2.predict(X)
tree_reg3 = DecisionTreeRegressor(max_depth=2)
tree_reg3.fit(X, y3)
预测结果:0.75026781,其真实值为1.92,模型误差依然较大(只进行两轮误差学习,次数太少)。
X_new = np.array([[0.8]])
y_pred = sum(tree.predict(X_new) for tree in (tree_reg1, tree_reg2, tree_reg3))
y_pred
绘制每一轮的结果。
def plot_predictions(regressors, X, y, axes, label=None, style='r-', data_style='b.', data_label=None):
x1 = np.linspace(axes[0], axes[1], 500)
y_pred = sum(regressor.predict(x1.reshape(-1, 1)) for regressor in regressors)
plt.plot(X[:, 0], y, data_style, label=data_label)
plt.plot(x1, y_pred, style, linewidth=2, label=label)
if label or data_label:
plt.legend(loc='upper center', fontsize=16)
plt.axis(axes)
plt.figure(figsize=(11, 11))
plt.subplot(321)
plot_predictions([tree_reg1], X, y, axes=[-0.5, 0.5, -0.1, 0.8],
label='$h_1(x_1)$', style='g-', data_label='Train set')
plt.ylabel('$y$', fontsize=16, rotation=0)
plt.title('Residuals and tree predictions', fontsize=16)
plt.subplot(322)
plot_predictions([tree_reg1], X, y, axes=[-0.5, 0.5, -0.1, 0.8],
label='$h(x_1) = h_1(x_1)$', data_label='Train set')
plt.ylabel('$y$', fontsize=16, rotation=0)
plt.title('Ensemble predictions', fontsize=16)
plt.subplot(323)
plot_predictions([tree_reg2], X, y2, axes=[-0.5, 0.5, -0.5, 0.5],
label='$h_2(x_1)$', style='g-', data_style='k+', data_label='Residuals')
plt.ylabel('$y - h_1(x_1)$', fontsize=16)
plt.subplot(324)
plot_predictions([tree_reg1, tree_reg2], X, y, axes=[-0.5,
0.5, -0.1, 0.8], label='$h(x_1) = h_1(x_1) + h_2(x_1)$')
plt.ylabel('$y$', fontsize=16, rotation=0)
plt.subplot(325)
plot_predictions([tree_reg3], X, y3, axes=[-0.5, 0.5, -0.5, 0.5],
label='$h_3(x_1)$', style='g-', data_style='k+')
plt.ylabel('$y - h_1(x_1) - h_2(x_1)$', fontsize=16)
plt.xlabel('$x_1$', fontsize=16)
plt.subplot(326)
plot_predictions([tree_reg1, tree_reg2, tree_reg3], X, y, axes=[-0.5,
0.5, -0.1, 0.8], label='$h(x_1) = h_1(x_1) + h_2(x_1) + h_3(x_1)$')
plt.xlabel('$x_1$', fontsize=16)
plt.ylabel('$y$', fontsize=16, rotation=0)
plt.show()
3.2.2 Gradient Boosting示例
from sklearn.ensemble import GradientBoostingRegressor
gbdt = GradientBoostingRegressor(max_depth=2,
n_estimators=3,
learning_rate=1.0,
random_state=41)
gbdt.fit(X, y)
gbdt_slow_1 = GradientBoostingRegressor(max_depth=2,
n_estimators=3,
learning_rate=0.1,
random_state=41)
gbdt_slow_1.fit(X, y)
gbdt_slow_2 = GradientBoostingRegressor(max_depth=2,
n_estimators=200,
learning_rate=0.1,
random_state=41)
gbdt_slow_2.fit(X, y)
学习率小,森林规模应该足够大。
plt.figure(figsize=(11, 4))
plt.subplot(121)
plot_predictions([gbdt], X, y, axes=[-0.5, 0.5, -0.1, 0.8], label='Ensemble predictions')
plt.title('learning rate = {}, n_estimators = {}'.format(gbdt.learning_rate, gbdt.n_estimators))
plt.subplot(122)
plot_predictions([gbdt_slow_1], X, y, axes=[-0.5, 0.5, -0.1, 0.8], label='Ensemble predictions')
plt.title('learning rate = {}, n_estimators = {}'.format(gbdt_slow_1.learning_rate, gbdt_slow_1.n_estimators))
plt.show()
规模大容易过拟合。
plt.figure(figsize=(11, 4))
plt.subplot(121)
plot_predictions([gbdt_slow_2], X, y, axes=[-0.5, 0.5, -0.1, 0.8], label='Ensemble predictions')
plt.title('learning rate = {}, n_estimators = {}'.format(gbdt_slow_2.learning_rate, gbdt_slow_2.n_estimators))
plt.subplot(122)
plot_predictions([gbdt_slow_1], X, y, axes=[-0.5, 0.5, -0.1, 0.8], label='Ensemble predictions')
plt.title('learning rate = {}, n_estimators = {}'.format(gbdt_slow_1.learning_rate, gbdt_slow_1.n_estimators))
plt.show()
3.3 XGBoost
3.3.1 安装xgboost:下载xgboost库
然后
pip install 补全文件完整路径\xgboost-2.0.3-py3-none-win_amd64.whl
原理解释: https://blog.csdn.net/greatxiang888/article/details/99202764
XGBoost(eXtreme Gradient Boosting,极端梯度提升)是GBDT(Gradient Boosting Decision Tree)的一种高效且广泛使用的实现,旨在优化传统GBDT的速度和性能。
- XGBoost对传统的GBDT算法进行了优化,包括计算速度(二阶泰勒展开)和内存使用上的优化。它采用了一种称为“近似分裂点算法”的技术,能够在处理大规模数据时显著提高效率。
- 不同于传统的GBDT,XGBoost在损失函数中加入了正则化项(L1和L2正则化)。这有助于控制模型的复杂度,从而减少过拟合的风险,提高模型的泛化能力。
- 并行处理,虽然树的构建本身是顺序的,XGBoost能够在特征维度上进行并行处理,通过优化数据结构和算法来加速训练过程。
3.3.2 简单示例
import xgboost as xgb
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer
from sklearn.metrics import accuracy_score
# 加载数据集
data = load_breast_cancer()
X = data.data
y = data.target
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 转换为DMatrix数据格式,这是XGBoost的优化数据结构
dtrain = xgb.DMatrix(X_train, label=y_train)
dtest = xgb.DMatrix(X_test, label=y_test)
# 设置参数
# 这里是二分类问题,使用'binary:logistic'作为目标函数
param = {
'max_depth': 3, # 树的最大深度
'eta': 0.3, # 学习率
'objective': 'binary:logistic',
'eval_metric': 'logloss' # 评估指标
}
num_round = 100 # 训练轮数
# 训练模型
bst = xgb.train(param, dtrain, num_round)
# 使用训练好的模型进行预测
preds = bst.predict(dtest)
predictions = [round(value) for value in preds]
# 评估模型
accuracy = accuracy_score(y_test, predictions)
print("Accuracy: %.2f%%" % (accuracy * 100.0))
Accuracy: 95.61%
3.3.3 主要参数
binary:logistic 用于二分类,返回分类的概率
multi:softmax 多分类问题,返回类别
multi:softprob 多分类,返回样本属于每一类的概率
-
通用参数
booster: 选择每一次迭代的模型,常用的有gbtree(树模型)、gblinear(线性模型)。
nthread: 并行线程的数量。默认值为最大可能的线程数。在不同的系统中,这个参数可能被命名为n_jobs。 -
集成(Booster)参数
eta (也称为learning_rate): 每一步迭代的步长缩减,用来防止过拟合。通过减少每一步的权重,可以让模型更加稳健。范围是[0,1]。
min_child_weight: 决定最小叶子节点样本权重和。用来控制过拟合。较大的值会导致模型更加保守。
max_depth: 树的最大深度。用来控制过拟合,较大的值会让模型学习到更具体的样本特征。
gamma (也称为min_split_loss): 在节点分裂时只有在分裂所带来的损失函数的减少量大于此值时才会分裂,在回归任务中它就像是正则化参数一样。
subsample: 训练每棵树时用到的数据比率,防止过拟合。
colsample_bytree: 建立每棵树时列的采样比率。
lambda (L2 正则化项权重): 正则化项。增加此值会使模型更加保守。
alpha (L1 正则化项权重): 可以应用于非常高维的情况下,使得算法的运行速度更快。 -
任务参数
objective: 指定学习任务和相应的学习目标,例如binary:logistic用于二分类问题,reg:squarederror用于回归问题。
eval_metric: 评价指标,用于模型的评估。例如auc表示面积下曲线值,对于回归问题可以使用rmse(均方根误差)。
seed: 随机种子,用于产生可复现的结果。
3.4 提前停止策略
不断提升后,可能出现模型效果变差的情况,此时需要提前终止训练。
from sklearn.metrics import mean_absolute_error
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
gbdt = GradientBoostingRegressor(max_depth=2,
n_estimators=120,
learning_rate=1.0,
random_state=42)
gbdt.fit(X_train, y_train)
# staged_predict 每棵树依次加进来后的预测值
errors = [mean_absolute_error(y_pred, y_test) for y_pred in gbdt.staged_predict(X_test)]
误差最小的迭代次数
(28, 0.04242765129927983)
best_n_estimators = np.argmin(errors)
min_error = np.min(errors)
best_n_estimators, min_error
使用最小误差的迭代次数:
gbdt_best = GradientBoostingRegressor(max_depth=2,
n_estimators=best_n_estimators,
random_state=42)
gbdt_best.fit(X_train, y_train)
plt.figure(figsize=(11, 4))
plt.subplot(121)
plt.plot(range(1, 121), errors, 'b-')
plt.plot([best_n_estimators, best_n_estimators], [0, min_error], 'k--')
plt.plot([0, 120], [min_error, min_error], 'k--')
plt.title('test error')
plt.subplot(122)
plot_predictions([gbdt_best], X, y, axes=[-0.5, 0.5, -0.1, 0.8])
plt.title('Best Model(%d trees)' % best_n_estimators)
plt.show()
停止方案
gbdt = GradientBoostingRegressor(max_depth=2,
random_state=42,
warm_start=True)
# error连续增加的次数
error_going_up = 0
min_pre_error = float('inf')
for n_estimators in range(1, 120):
gbdt.n_estimators = n_estimators
gbdt.fit(X_train, y_train)
y_pred = gbdt.predict(X_test)
pre_error = mean_absolute_error(y_pred, y_test)
if pre_error < min_pre_error:
min_pre_error = pre_error
error_going_up = 0
else:
error_going_up += 1
if error_going_up == 5:
break
gbdt.n_estimators
# 连续5次error都没有下降,达到上限
72
4. Stacking-堆叠
- 将任务拆分,分阶段做。
- 每个阶段可以是分类或回归,可以是不同模型的组合。
示例:
手写数字数据集。
from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split
mnist = fetch_openml('mnist_784', version=1, parser='auto')
X_train, X_test, y_train, y_test = train_test_split(mnist.data, mnist.target, test_size=10000, random_state=42)
构建四个分类器,依次进行训练。
from sklearn.ensemble import RandomForestClassifier, ExtraTreesClassifier
from sklearn.svm import LinearSVC
from sklearn.neural_network import MLPClassifier
random_forest_clf = RandomForestClassifier(random_state=42)
extra_trees_clf = ExtraTreesClassifier(random_state=42)
svm_clf = LinearSVC(random_state=42)
mlp_clf = MLPClassifier(random_state=42)
estimators = [random_forest_clf, extra_trees_clf, svm_clf, mlp_clf]
for estimator in estimators:
estimator.fit(X_train, y_train)
依次计算每个分类器的预测结果,输出的每一行依次是四个分类器的结果。第一步完成。
import numpy as np
# 创建数组,用于保存每个模型的预测结果
X_test_pred = np.empty((len(X_test), len(estimators)), dtype=np.float32)
for index, estimator in enumerate(estimators):
X_test_pred[:, index] = estimator.predict(X_test)
X_test_pred
array([[8., 8., 8., 8.],
[4., 4., 4., 4.],
[8., 8., 8., 5.],
...,
[3., 3., 3., 3.],
[8., 8., 3., 8.],
[3., 3., 3., 3.]], dtype=float32)
可以先计算每个分类器的准确率。
for estimator in estimators:
accuracy = accuracy_score(estimator.predict(X_test), y_test)
print(estimator, accuracy)
RandomForestClassifier(random_state=42) 0.9674
ExtraTreesClassifier(random_state=42) 0.9682
LinearSVC(random_state=42) 0.8134
MLPClassifier(random_state=42) 0.9616
ExtraTreesClassifier链接:https://www.geeksforgeeks.org/ml-extra-tree-classifier-for-feature-selection/
第一步输出作为第二步的输入,构建随机森林分类器进行训练。
rf = RandomForestClassifier(n_estimators=200, oob_score=True, random_state=42)
rf.fit(X_test_pred, y_test)
rf.oob_score_
输出结果为:0.9692