【机器学习】案例2.2——集成学习(Ensemble Learning)进行鸢尾花分类
·
1. 项目背景及解决问题的方案
1.1 项目背景
机器学习中,单一分类模型(如逻辑回归、决策树、SVM等)往往存在泛化能力不足、对数据分布敏感或易过拟合/欠拟合的问题。集成学习(Ensemble Learning) 作为提升模型性能的核心方法,通过组合多个弱学习器(基模型)的预测结果,能有效降低单一模型的偏差和方差,显著提升分类任务的准确率与稳定性。
本项目以经典的鸢尾花(Iris)分类任务为载体,验证两种核心集成学习策略的效果:
- 投票法(Voting):组合不同类型基分类器,通过多数投票生成最终预测;
- 装袋法(Bagging):基于同类型基分类器,通过有放回抽样生成多份训练子集,训练多模型后聚合结果,同时利用袋外数据(OOB)实现无额外验证集的模型评估。
鸢尾花数据集包含3类鸢尾花(Setosa、Versicolor、Virginica)共150条样本,每条样本含4个特征(花萼长度/宽度、花瓣长度/宽度)。本项目简化为仅用花萼长度和宽度两个特征,聚焦验证集成学习的核心效果。
1.2 解决问题的方案
本项目通过“单模型对比 + 集成模型验证”验证集成学习的性能提升,具体方案:
(1)数据预处理
- 加载鸢尾花数据集,提取花萼长度/宽度为特征X,品种标签为目标y;
- 按2:1划分训练集/测试集(test_size=0.33),固定随机种子(random_state=42)保证实验可复现。
(2)硬投票(Hard Voting)集成
- 选择3类异构基分类器:逻辑回归(线性分类)、随机森林(树集成)、SVM(核方法);
- 构建VotingClassifier,采用“硬投票”(多数投票)规则生成最终预测;
- 训练单模型和投票模型,对比测试集准确率。
(3)Bagging集成
- 以决策树为基分类器,构建两类Bagging模型:
- 普通Bagging:10棵决策树,全量抽样,输出预测结果、类别概率及准确率;
- 带OOB评估的Bagging:500棵决策树,启用OOB评分,利用未抽样的袋外数据评估模型,验证OOB评分的有效性。
(4)结果分析
对比单模型、投票模型、Bagging模型的准确率,验证集成学习的性能优势;验证OOB评分可作为无额外验证集时的性能参考。
2. 带详细注释的完整代码(含中文说明)
# 导入集成学习相关库:随机森林、投票分类器、装袋分类器
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import VotingClassifier
from sklearn.ensemble import BaggingClassifier
# 导入基础分类器:逻辑回归、支持向量机、决策树
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier
# 导入数据集:加载鸢尾花经典分类数据集
from sklearn.datasets import load_iris
# 导入数据划分工具:拆分训练集/测试集
from sklearn.model_selection import train_test_split
# 导入评估指标:计算分类准确率
from sklearn.metrics import accuracy_score
# 导入可视化库:绘制准确率对比图
import matplotlib.pyplot as plt
# 设置matplotlib支持中文显示(适配Windows系统,其他系统可替换为对应中文字体)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 黑体
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示异常
# ---------------------- 步骤1:初始化异构基分类器 ----------------------
# 逻辑回归:适用于线性可分的多分类任务,计算效率高
log_clf = LogisticRegression()
# 随机森林:多棵决策树的集成,抗过拟合能力强,无需复杂特征工程
rnd_clf = RandomForestClassifier()
# 支持向量机:基于核函数映射,适用于低维特征的非线性分类
svm_clf = SVC()
# ---------------------- 步骤2:构建硬投票集成分类器 ----------------------
# VotingClassifier参数说明:
# - estimators:列表,元素为(模型别名, 模型实例),指定参与投票的基模型
# - voting:'hard'=硬投票(多数投票),'soft'=软投票(概率加权)
voting_clf = VotingClassifier(
estimators=[('lr', log_clf), ('rf', rnd_clf), ('svc', svm_clf)],
voting='hard' # 硬投票规则:最终预测为得票最多的类别
)
# ---------------------- 步骤3:加载并预处理鸢尾花数据集 ----------------------
# 加载鸢尾花数据集(内置数据集,包含data/feature_names/target/target_names等属性)
iris = load_iris()
# 提取特征:仅取前2列(花萼长度、花萼宽度),简化特征维度以聚焦集成学习效果
X = iris.data[:, :2]
# 提取目标变量:3类鸢尾花的标签(0=Setosa,1=Versicolor,2=Virginica)
y = iris.target
# 划分训练集和测试集:测试集占33%,random_state固定随机种子保证实验可复现
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.33, random_state=42
)
# ---------------------- 步骤4:训练并评估单模型与投票集成模型 ----------------------
# 初始化列表:存储模型名称和对应准确率,用于后续可视化
model_names = []
accuracy_scores = []
# 打印分隔符和标题,提升输出可读性
print("="*50)
print("单模型与硬投票集成模型的测试集准确率:")
print("="*50)
# 遍历所有模型(3个单模型 + 1个投票集成模型)
for clf in (log_clf, rnd_clf, svm_clf, voting_clf):
# 模型训练:用训练集数据拟合模型
clf.fit(X_train, y_train)
# 测试集预测:生成模型对测试集的预测标签
y_pred = clf.predict(X_test)
# 计算准确率:预测标签与真实标签的匹配比例
acc = accuracy_score(y_test, y_pred)
# 存储模型名称和准确率
model_names.append(clf.__class__.__name__)
accuracy_scores.append(acc)
# 打印结果:中文标注模型名称和准确率(保留4位小数)
print(f"模型名称:{clf.__class__.__name__},测试集准确率:{acc:.4f}")
# ---------------------- 步骤5:构建普通Bagging集成分类器 ----------------------
# BaggingClassifier参数说明:
# - base_estimator:基分类器(此处为决策树)
# - n_estimators:基模型数量(10棵决策树)
# - max_samples:每个基模型抽样的样本比例(1.0=全量样本)
# - bootstrap:是否有放回抽样(True=有放回)
# - n_jobs:并行训练进程数(1=单进程,避免多进程冲突)
bag_clf = BaggingClassifier(
DecisionTreeClassifier(), n_estimators=10,
max_samples=1.0, bootstrap=True, n_jobs=1
)
# 训练Bagging模型
bag_clf.fit(X_train, y_train)
# 测试集预测标签
y_pred_bag = bag_clf.predict(X_test)
# 测试集类别概率:每个样本对应3个类别的预测概率
y_pred_proba_bag = bag_clf.predict_proba(X_test)
# 打印Bagging模型结果
print("\n" + "="*50)
print("普通Bagging集成模型(10棵决策树)结果:")
print("="*50)
print(f"测试集预测标签:{y_pred_bag}")
print(f"测试集类别概率:\n{y_pred_proba_bag}")
# 计算Bagging模型准确率
acc_bag = accuracy_score(y_test, y_pred_bag)
print(f"Bagging模型测试集准确率:{acc_bag:.4f}")
# 存储Bagging模型信息用于可视化
model_names.append("BaggingClassifier(10)")
accuracy_scores.append(acc_bag)
# ---------------------- 步骤6:构建带OOB评估的Bagging集成模型 ----------------------
# oob_score=True:启用袋外数据评分,利用未被抽样的样本评估模型(无需额外验证集)
bag_clf_oob = BaggingClassifier(
DecisionTreeClassifier(), n_estimators=500, # 增加基模型数量至500,提升稳定性
bootstrap=True, n_jobs=1, oob_score=True
)
# 训练带OOB的Bagging模型
bag_clf_oob.fit(X_train, y_train)
# 打印带OOB的Bagging模型结果
print("\n" + "="*50)
print("带OOB评估的Bagging集成模型(500棵决策树)结果:")
print("="*50)
# 打印OOB评分:袋外数据的准确率(未被抽样到的样本的预测准确率)
print(f"OOB评分(袋外数据准确率):{bag_clf_oob.oob_score_:.4f}")
# 测试集预测
y_pred_oob = bag_clf_oob.predict(X_test)
# 计算测试集准确率
acc_oob = accuracy_score(y_test, y_pred_oob)
print(f"测试集准确率:{acc_oob:.4f}")
# 打印OOB决策函数(前5个样本):每个样本对应3个类别的OOB预测概率
print(f"OOB决策函数(类别概率):\n{bag_clf_oob.oob_decision_function_[:5]}")
# 存储带OOB的Bagging模型信息用于可视化
model_names.append("BaggingClassifier(OOB)")
accuracy_scores.append(acc_oob)
# ---------------------- 步骤7:可视化各模型准确率对比 ----------------------
# 创建画布,设置尺寸
plt.figure(figsize=(10, 6))
# 绘制柱状图:不同颜色区分不同模型
bars = plt.bar(model_names, accuracy_scores, color=['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b'])
# 为每个柱子添加数值标签(准确率)
for bar in bars:
height = bar.get_height()
plt.text(bar.get_x() + bar.get_width()/2., height + 0.01,
f'{height:.4f}', ha='center', va='bottom', fontsize=10)
# 设置图表标题和坐标轴标签
plt.title('各分类模型测试集准确率对比', fontsize=14)
plt.xlabel('模型名称', fontsize=12)
plt.ylabel('准确率', fontsize=12)
# 旋转x轴标签,避免重叠
plt.xticks(rotation=15)
# 设置y轴范围,突出准确率差异
plt.ylim(0.7, 1.0)
# 添加y轴网格线,提升可读性
plt.grid(axis='y', linestyle='--', alpha=0.7)
# 显示图表
plt.show()
3. 仅保留代码的简洁版
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import VotingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
log_clf = LogisticRegression()
rnd_clf = RandomForestClassifier()
svm_clf = SVC()
voting_clf = VotingClassifier(
estimators=[('lr', log_clf), ('rf', rnd_clf), ('svc', svm_clf)],
voting='hard'
)
iris = load_iris()
X = iris.data[:, :2]
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)
model_names = []
accuracy_scores = []
print("="*50)
print("单模型与硬投票集成模型的测试集准确率:")
print("="*50)
for clf in (log_clf, rnd_clf, svm_clf, voting_clf):
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
acc = accuracy_score(y_test, y_pred)
model_names.append(clf.__class__.__name__)
accuracy_scores.append(acc)
print(f"模型名称:{clf.__class__.__name__},测试集准确率:{acc:.4f}")
bag_clf = BaggingClassifier(
DecisionTreeClassifier(), n_estimators=10,
max_samples=1.0, bootstrap=True, n_jobs=1
)
bag_clf.fit(X_train, y_train)
y_pred_bag = bag_clf.predict(X_test)
y_pred_proba_bag = bag_clf.predict_proba(X_test)
print("\n" + "="*50)
print("普通Bagging集成模型(10棵决策树)结果:")
print("="*50)
print(f"测试集预测标签:{y_pred_bag}")
print(f"测试集类别概率:\n{y_pred_proba_bag}")
acc_bag = accuracy_score(y_test, y_pred_bag)
print(f"Bagging模型测试集准确率:{acc_bag:.4f}")
model_names.append("BaggingClassifier(10)")
accuracy_scores.append(acc_bag)
bag_clf_oob = BaggingClassifier(
DecisionTreeClassifier(), n_estimators=500,
bootstrap=True, n_jobs=1, oob_score=True
)
bag_clf_oob.fit(X_train, y_train)
print("\n" + "="*50)
print("带OOB评估的Bagging集成模型(500棵决策树)结果:")
print("="*50)
print(f"OOB评分(袋外数据准确率):{bag_clf_oob.oob_score_:.4f}")
y_pred_oob = bag_clf_oob.predict(X_test)
acc_oob = accuracy_score(y_test, y_pred_oob)
print(f"测试集准确率:{acc_oob:.4f}")
print(f"OOB决策函数(类别概率):\n{bag_clf_oob.oob_decision_function_[:5]}")
model_names.append("BaggingClassifier(OOB)")
accuracy_scores.append(acc_oob)
plt.figure(figsize=(10, 6))
bars = plt.bar(model_names, accuracy_scores, color=['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b'])
for bar in bars:
height = bar.get_height()
plt.text(bar.get_x() + bar.get_width()/2., height + 0.01,
f'{height:.4f}', ha='center', va='bottom', fontsize=10)
plt.title('各分类模型测试集准确率对比', fontsize=14)
plt.xlabel('模型名称', fontsize=12)
plt.ylabel('准确率', fontsize=12)
plt.xticks(rotation=15)
plt.ylim(0.7, 1.0)
plt.grid(axis='y', linestyle='--', alpha=0.7)
plt.show()
运行结果

'''
==================================================
单模型与硬投票集成模型的测试集准确率:
==================================================
模型名称:LogisticRegression,测试集准确率:0.8200
模型名称:RandomForestClassifier,测试集准确率:0.7400
模型名称:SVC,测试集准确率:0.7800
模型名称:VotingClassifier,测试集准确率:0.8000
==================================================
普通Bagging集成模型(10棵决策树)结果:
==================================================
测试集预测标签:[1 0 2 1 1 0 1 2 1 2 2 0 0 0 0 2 2 1 1 1 0 1 0 1 2 1 1 2 0 0 0 0 2 0 0 1 2
0 0 0 2 2 2 0 0 1 2 2 2 2]
测试集类别概率:
[[0. 1. 0. ]
[0.8 0.15 0.05 ]
[0. 0.2 0.8 ]
[0. 0.56666667 0.43333333]
[0. 0.6 0.4 ]
[0.7 0.1 0.2 ]
[0. 1. 0. ]
[0. 0.30833333 0.69166667]
[0. 0.675 0.325 ]
[0. 0.46833333 0.53166667]
[0. 0. 1. ]
[1. 0. 0. ]
[0.4 0.4 0.2 ]
[1. 0. 0. ]
[1. 0. 0. ]
[0. 0. 1. ]
[0. 0.1 0.9 ]
[0. 0.8 0.2 ]
[0. 0.75 0.25 ]
[0. 0.5 0.5 ]
[1. 0. 0. ]
[0. 0.7 0.3 ]
[1. 0. 0. ]
[0. 0.5 0.5 ]
[0.1 0. 0.9 ]
[0. 0.7 0.3 ]
[0. 0.7 0.3 ]
[0. 0. 1. ]
[1. 0. 0. ]
[1. 0. 0. ]
[1. 0. 0. ]
[0.8 0.15 0.05 ]
[0. 0.1 0.9 ]
[1. 0. 0. ]
[1. 0. 0. ]
[0. 0.8 0.2 ]
[0. 0. 1. ]
[0.9 0. 0.1 ]
[1. 0. 0. ]
[1. 0. 0. ]
[0. 0.46833333 0.53166667]
[0. 0.2 0.8 ]
[0. 0.1 0.9 ]
[1. 0. 0. ]
[0.8 0.1 0.1 ]
[0. 0.9 0.1 ]
[0. 0.4 0.6 ]
[0. 0. 1. ]
[0. 0.2 0.8 ]
[0. 0. 1. ]]
Bagging模型测试集准确率:0.7400
==================================================
带OOB评估的Bagging集成模型(500棵决策树)结果:
==================================================
OOB评分(袋外数据准确率):0.6300
测试集准确率:0.7600
OOB决策函数(类别概率):
[[0. 0.95111732 0.04888268]
[0. 0. 1. ]
[0.01604278 0.84313725 0.14081996]
[1. 0. 0. ]
[0. 0.04575163 0.95424837]]
进程已结束,退出代码为 0
'''
更多推荐
所有评论(0)