从项目入手机器学习(八)—— 模型集成

这篇文章主要讲一些模型集成的原理,实际上我做完集成后中kaggle上的分数反而不如单一模型的表现(目前我最好的成绩已经到了Top3%,大家可以期待一下后续的文章)

模型集成是机器学习里 "花小钱办大事" 的核心技巧 ------ 哪怕单个模型效果平平,选对方法把它们组合起来,就能显著提升预测准确率和稳定性。

集成的核心逻辑就一句话:让不同模型 "错得不一样",互相弥补错误。比如预测学生成绩:

  • 模型 A:容易低估 "学习时长短但效率高" 的学生;
  • 模型 B:容易高估 "学习时长久但注意力不集中" 的学生;把两个模型的预测结果平均,A 和 B 的错误会相互抵消,最终结果更接近真实值。

关键前提:参与集成的模型要 "有差异"(比如类型不同、参数不同),如果所有模型都犯一样的错,集成只会放大错误,反而更差。

1、Voting

核心思路

像 "投票选答案":分类任务用 "少数服从多数"(投票),回归任务用 "取平均值",是最易上手的集成方式。

  • 硬投票:每个模型预测 "类别",最终选得票最多的类别(比如 5 个模型里 3 个预测 "存活",结果就是 "存活",但是硬投票有一个问题,就是会把好模型与坏模型的效果模糊化:比如一个优秀的模型预测"存活",两个效果一般的模型预测"死亡",由于硬投票设置了相同的权重,最终会预测:死亡,等于降低了好模型的效果);
  • 软投票:每个模型输出 "类别概率",最终选概率总和最高的类别(更精准,优先用);
  • 平均集成:回归任务专用,把所有模型的预测值取平均(也可按模型好坏加权)。

代码实现

python 复制代码
# 第一步:准备数据(泰坦尼克数据集,简化版)
import pandas as pd
from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder

# 加载数据并预处理
titanic = fetch_openml('titanic', version=1, as_frame=True)
df = titanic.frame
# 简单预处理:填充缺失值、编码类别特征
df['Age'].fillna(df['Age'].median(), inplace=True)
df['Embarked'].fillna(df['Embarked'].mode()[0], inplace=True)
df['Sex'] = LabelEncoder().fit_transform(df['Sex'])
df = pd.get_dummies(df, columns=['Embarked'], drop_first=True)
# 选择特征和标签
X = df[['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked_Q', 'Embarked_S']]
y = df['survived'].map({'0':0, '1':1})
# 划分训练集/测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 第二步:定义基础模型
from sklearn.ensemble import VotingClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.tree import DecisionTreeClassifier
from sklearn.linear_model import LogisticRegression

# 准备多个不同类型的基础模型
models = [
    ('knn', KNeighborsClassifier(n_neighbors=5)),
    ('nb', GaussianNB()),
    ('dt', DecisionTreeClassifier(random_state=42)),
    ('lr', LogisticRegression(random_state=42))
]

# 第三步:构建投票集成模型
# 软投票(推荐):voting='soft',利用概率提升效果
voting_clf = VotingClassifier(
    estimators=models,
    voting='soft',  # 硬投票用voting='hard'
    weights=[1, 1, 1, 2]  # 给效果更好的逻辑回归更高权重
)

# 第四步:训练并评估
voting_clf.fit(X_train, y_train)
print(f"投票集成模型准确率:{voting_clf.score(X_test, y_test):.4f}")

# 对比单个模型效果(看集成的提升)
for name, model in models:
    model.fit(X_train, y_train)
    print(f"{name} 准确率:{model.score(X_test, y_test):.4f}")
  • weights参数:给不同模型分配权重(比如逻辑回归效果好,权重设为 2),避免 "差模型拖垮好模型";
  • 适用场景:快速出效果,适合新手或小数据集(如泰坦尼克、鸢尾花分类);
  • 避坑点:不要用多个 "高度相似" 的模型(比如 2 个参数几乎一样的决策树),投票会冗余。

2、Bagging(并行集成)

"多采样、多模型、求平均":从训练集中随机抽样(有放回)生成多个子数据集,每个子数据集训练一个相同类型的模型,最终集成所有模型的结果。最经典的 Bagging 代表是随机森林(RandomForest)------ 本质是 "多棵决策树的 Bagging 集成"。

代码实现

python 复制代码
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

# 构建随机森林(Bagging的典型应用)
rf_clf = RandomForestClassifier(
    n_estimators=100,  # 集成100棵决策树
    max_depth=5,       # 限制树深度,避免过拟合
    random_state=42,
    n_jobs=-1          # 并行训练,提升速度
)

# 训练并评估
rf_clf.fit(X_train, y_train)
y_pred = rf_clf.predict(X_test)
print(f"随机森林准确率:{accuracy_score(y_test, y_pred):.4f}")

# 对比单棵决策树
dt_clf = DecisionTreeClassifier(max_depth=5, random_state=42)
dt_clf.fit(X_train, y_train)
print(f"单棵决策树准确率:{dt_clf.score(X_test, y_test):.4f}")
  • n_estimators:集成的模型数量(树的数量),越多效果越稳(但不是越多越好,100~200 足够);
  • 核心优势:降低单模型的过拟合风险(比如单棵决策树容易过拟合,100 棵树平均后更稳定);
  • 适用场景:树模型、易过拟合的模型(比如决策树、KNN)。

目前我跑出来的最好结果是用RF完成的。

3、Stacking

本质是分层建模:把多个模型的预测结果当 "新特征",训练一个 "二级模型" 来做最终预测,相当于 "让模型给模型打分",是竞赛中冲高分的核心方法。比如:先用 KNN、决策树、随机森林做第一轮预测,再用逻辑回归把这 3 个预测结果整合,输出最终答案。

代码实现

python 复制代码
from sklearn.ensemble import StackingClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC

# 第一步:定义一级模型(基础模型)
base_models = [
    ('knn', KNeighborsClassifier(n_neighbors=5)),
    ('rf', RandomForestClassifier(n_estimators=100, random_state=42)),
    ('svm', SVC(probability=True, random_state=42))  # 软投票需要概率,probability=True
]

# 第二步:定义二级模型(融合模型)
final_estimator = LogisticRegression(random_state=42)

# 第三步:构建Stacking模型
stacking_clf = StackingClassifier(
    estimators=base_models,
    final_estimator=final_estimator,
    cv=5  # 5折交叉验证,确保一级模型的预测结果无过拟合
)

# 第四步:训练并评估
stacking_clf.fit(X_train, y_train)
print(f"Stacking集成模型准确率:{stacking_clf.score(X_test, y_test):.4f}")
  • cv参数:用交叉验证生成一级模型的 "无偏预测",避免二级模型过拟合;
  • 一级模型:尽量选不同类型的模型(比如 KNN + 树模型 + SVM),提升多样性;
  • 二级模型:简单模型即可(比如逻辑回归、线性回归),复杂模型容易过拟合;
  • 适用场景:追求极致准确率(如 Kaggle 竞赛),小数据集慎用(易过拟合)。

核心技巧

  • 模型要 "多样":优先选不同类型的模型(树模型 + 线性模型 + 贝叶斯),或同一模型不同参数(比如随机森林调不同 max_depth),避免 "全是一样的模型";
  • 只集成 "优质模型":先筛选验证集分数前 80% 的模型,差模型直接剔除,避免拖后腿;
  • 计算模型相关性:用皮尔逊相关系数看模型预测结果的相似度,相关性 > 0.9 的模型只留一个;
  • 从简单到复杂:先试投票 / 平均,效果不够再试 Stacking,不要上来就用复杂方法;
  • 加权比等权好:回归任务用 "模型分数加权平均",分类任务用软投票,比简单平均更精准。

当然,还有一些更复杂的集成方法,后续用到了会再提出。kaggle竞赛中,高分的题解几乎都需要集成大量的模型(50~200个),如何获得大量优秀模型也是一个问题,在后续的文章中也会继续进行讨论。

相关推荐
九.九10 小时前
ops-transformer:AI 处理器上的高性能 Transformer 算子库
人工智能·深度学习·transformer
春日见10 小时前
拉取与合并:如何让个人分支既包含你昨天的修改,也包含 develop 最新更新
大数据·人工智能·深度学习·elasticsearch·搜索引擎
恋猫de小郭10 小时前
AI 在提高你工作效率的同时,也一直在增加你的疲惫和焦虑
前端·人工智能·ai编程
deephub11 小时前
Agent Lightning:微软开源的框架无关 Agent 训练方案,LangChain/AutoGen 都能用
人工智能·microsoft·langchain·大语言模型·agent·强化学习
大模型RAG和Agent技术实践11 小时前
从零构建本地AI合同审查系统:架构设计与流式交互实战(完整源代码)
人工智能·交互·智能合同审核
老邋遢11 小时前
第三章-AI知识扫盲看这一篇就够了
人工智能
互联网江湖11 小时前
Seedance2.0炸场:长短视频们“修坝”十年,不如AI放水一天?
人工智能
PythonPioneer11 小时前
在AI技术迅猛发展的今天,传统职业该如何“踏浪前行”?
人工智能
冬奇Lab12 小时前
一天一个开源项目(第20篇):NanoBot - 轻量级AI Agent框架,极简高效的智能体构建工具
人工智能·开源·agent
阿里巴巴淘系技术团队官网博客12 小时前
设计模式Trustworthy Generation:提升RAG信赖度
人工智能·设计模式