机器学习常被视为高深的技术概念,其核心在于让系统自行学会从数据中提取规律并做出预测。通常,借助数据集和算法,模型便能挖掘数据模式。然而现实往往不尽如人意——许多模型的准确率偏低,预测结果也存在偏差。此时,一种相对简便的解决方案便是引入“集成学习”。

所谓集成学习,通俗来说就是“三个臭皮匠,顶个诸葛亮”。它将多个机器学习模型的预测结果进行组合,从而得到一个更优、更稳定的模型。这种方式的一大优势是能有效缓解过拟合——即模型在训练数据上表现良好,在测试数据上同样不逊色。具体而言,集成学习的优点包括:
- 提升模型整体性能
- 减少过拟合风险
- 降低方差
- 比单一模型拥有更高的预测精度
- 能同时处理线性和非线性数据
无论是回归问题还是分类问题,集成技术都能发挥重要作用。下面我们逐一介绍几种主流的集成学习方法。
Voting(投票集成)
Voting(投票集成)是最直观的方式:在完整数据集上训练多个基础模型,每个模型都给出自己的预测结果,然后将这些预测视为“投票”。得票最多的预测即为最终答案。

在汇总基础预测时,有硬投票和软投票两种方式。

硬投票直接统计哪个预测被投票最多;软投票则更为精细,它会汇总每个模型对各类别的概率,取概率最高的类作为最终预测。对于回归问题,则不存在“投票”概念——直接将所有模型的预测值取平均,即为最终结果。
使用Scikit-learn实现Voting分类器非常简单:
from sklearn.ensemble import VotingClassifier
## Base Models
from sklearn.tree import DecisionTreeClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import GaussianNB
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
ensemble_voting = VotingClassifier(
estimators = [('dtc',DecisionTreeClassifier(random_state=42)),
('lr', LogisticRegression()),
('gnb', GaussianNB()),
('knn',KNeighborsClassifier()),
('svc',SVC())],
voting='hard')
ensemble_voting.fit(X_train,y_train)
Bagging(自助聚合)
Bagging(自助聚合)同样是将多个弱模型的结果聚合起来,但其抽样方式很特别——基于bootstrap(有放回抽样)生成不同的子集,每个模型在不同子集上训练,最后再聚合。随机森林是Bagging最经典的例子:它由大量决策树组成,每棵树在随机数据样本和随机特征上训练,然后整体投票得出最终结果。

Bagging通常有两种形式:决策树集合(即随机森林),以及非决策树模型的集合。原理相同,只是基础模型不同。在sklearn中,BaggingClassifier类允许你使用非决策树模型进行Bagging:
## Bagging Ensemble of Same Classifiers (Decision Trees)
from sklearn.ensemble import RandomForestClassifier
classifier= RandomForestClassifier(n_estimators= 10, criterion="entropy")
classifier.fit(x_train, y_train)
## Bagging Ensemble of Different Classifiers
from sklearn.ensemble import BaggingClassifier
from sklearn.svm import SVC
clf = BaggingClassifier(base_estimator=SVC(),
n_estimators=10, random_state=0)
clf.fit(X_train,y_train)
Boosting(提升)
Boosting(提升)走的是一条“亡羊补牢”的路线。它将弱学习器转变为强学习器,通过顺序训练模型,每个新模型都重点关注前一个模型犯错的样本。简而言之,就是给之前分类错误的样本增加权重,让下一个模型更“重视”它们。

训练第n+1个模型时,每个数据点初始权重相等,但被前一个模型分错的样本会获得更高权重。误差就这样从n传递到n+1,逐步压缩。ADA Boost是最经典的代表,它创建的是“决策树桩”森林(每个树桩只有一个节点和两个叶子),不像随机森林那样使用完整树。它不断为错分样本加大权重,直到错误率降到可接受范围。
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import AdaBoostClassifier
dt = DecisionTreeClassifier(max_depth=2, random_state=0)
adc = AdaBoostClassifier(base_estimator=dt, n_estimators=7, learning_rate=0.1, random_state=0)
adc.fit(x_train, y_train)
Stacking(堆叠)
Stacking(堆叠)由David H. Wolpert于1992年提出,又称“叠加泛化”。其核心思想是:将多个不同泛化器(基础模型)的预测结果作为特征,输入给一个元模型(第二层模型),由元模型做出最终预测。

具体操作上,先将数据拆分为训练集和测试集。训练集再分成k折。基础模型在k-1折上训练,在第k折上预测,并反复迭代直到每一折都被预测过。之后,基础模型在整个训练集上拟合一次,计算性能。所有这些预测(来自训练集)构成了第二层模型的特征,该第二层模型最后在测试集上预测。
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import StackingClassifier
base_learners = [
('l1', KNeighborsClassifier()),
('l2', DecisionTreeClassifier()),
('l3',SVC(gamma=2, C=1)))
]
model = StackingClassifier(estimators=base_learners, final_estimator=LogisticRegression(),cv=5)
model.fit(X_train, y_train)
Blending(混合)
Blending(混合)可以看作是Stacking的简化版。唯一区别在于:它从训练集中单独留出一部分作为验证集,仅在这个验证集上获取基础模型的预测结果,然后用这些预测结果构建第二层模型。流程更简单直接,但与Stacking本质相同。

下面是Blending完整的Python示例,展示了其具体步骤:
import numpy as np
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
## Base Models
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
## Meta Learner
from sklearn.linear_model import LogisticRegression
## Creating Sample Data
X,y = make_classification(n_samples=10000, n_features=20, n_informative=15, n_redundant=5, random_state=42)
## Training a Individual Logistic Regression Model
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1)
logrec = LogisticRegression()
logrec.fit(X_train,y_train)
pred = logrec.predict(X_test)
score = accuracy_score(y_test, pred)
print('Base Model Accuracy: %.3f' % (score*100))
## Defining Base Models
def base_models():
models = list()
models.append(('knn', KNeighborsClassifier()))
models.append(('dt', DecisionTreeClassifier()))
models.append(('svm', SVC(probability=True)))
return models
## Fitting Ensemble Blending Model
## Step 1:Splitting Data Into Train, Holdout(Validation) and Test Sets
X_train_full, X_test, y_train_full, y_test = train_test_split(X, y, test_size=0.3, random_state=1)
X_train, X_val, y_train, y_val = train_test_split(X_train_full, y_train_full, test_size=0.33, random_state=1)
## Step 2: train base models on train set and make predictions on validation set
models = base_models()
meta_X = list()
for name, model in models:
# training base models on train set
model.fit(X_train, y_train)
# predict on hold out set
yhat = model.predict_proba(X_val)
# storing predictions
meta_X.append(yhat)
# horizontal stacking predictions
meta_X = np.hstack(meta_X)
## Step 3: Creating Blending Meta Learner
blender = LogisticRegression()
## training on base model predictions
blender.fit(meta_X, y_val)
## Step 4: Making predictions using blending meta learner
meta_X = list()
for name, model in models:
yhat = model.predict_proba(X_test)
meta_X.append(yhat)
meta_X = np.hstack(meta_X)
y_pred = blender.predict(meta_X)
# Evaluate predictions
score = accuracy_score(y_test, y_pred)
print('Blending Accuracy: %.3f' % (score*100))
---------------------------------
Base Model Accuracy: 82.367
Blending Accuracy: 96.733
从结果可以明显看出,Blending模型将准确率从82.367%提升到了96.733%——集成学习的威力由此可见一斑。
总结
读到这里,你可能会问:到底哪个集成方法最好?或者,我该从哪个开始用?
一个很务实的建议是:先从简单的单个模型开始尝试。如果单个模型表现尚可,就先用它,没必要一上来就搞集成。有些场景下,单个模型反而比集成模型跑得更好,甚至好很多。
要特别提醒的是:集成学习绝不应该是你的第一选择,而应该是最后一个选择。原因很简单——集成模型训练非常耗时,对算力的要求也高得多。所以别一上来就搞大动作。
回到实际问题:如果你的数据方差高,试试Bagging;如果基础模型偏差高(欠拟合严重),那就上Boosting;如果有好几个模型都表现不错,拿不准选哪个,那Stacking或Blending可以帮你“综合”一下。当然,具体哪种方法最适合,最终还是得看你的数据和特征分布——没有任何一招能通吃所有场景。
总的来说,集成学习是提升模型精度和稳定性的利器。尤其在竞赛中,它往往是拉开分数差距的关键。但记住:工具虽好,不能滥用,用在刀刃上才有价值。
