Skip to content

提升机器学习模型性能

使用集成方法提升机器学习模型性能

Section titled “使用集成方法提升机器学习模型性能”

集成方法是强大的技术,它结合多个独立机器学习模型(称为基学习器或评估器)的预测,产生最终预测。其核心思想是,通过结合多样化的模型,集成模型的预测通常比任何单个基学习器更准确、更鲁棒、更稳定。

可以将其想象成向多个专家寻求建议,而不仅仅是一个。每个专家可能有稍微不同的知识或偏见,但结合他们的意见通常会带来更好的整体决策。当基学习器是多样化的,即它们犯不同类型的错误时,集成方法效果最好。

集成方法大致可根据基学习器的构建方式分类:

序列集成方法 (Sequential Ensemble Methods, Boosting)

Section titled “序列集成方法 (Sequential Ensemble Methods, Boosting)”

基学习器按顺序生成。每个新的学习器都专注于纠正之前学习器犯的错误。这通常会降低偏差并构建强大的预测模型。示例包括 AdaBoost 和 Gradient Boosting。

并行集成方法 (Parallel Ensemble Methods, Bagging)

Section titled “并行集成方法 (Parallel Ensemble Methods, Bagging)”

基学习器独立并行生成。每个学习器都在训练数据的不同随机子集上训练。这主要降低方差并提高稳定性。示例包括 Bagged Decision Trees 和 Random Forests。

以下是组合基学习器预测的最流行方法:

Bagging 涉及在训练数据的不同随机子集上训练同一基学习器的多个实例,通常采用有放回抽样(bootstrap sampling)。最终预测通过对所有基学习器的预测进行平均(用于回归)或多数投票(用于分类)获得。Bagging 对像决策树这样的高方差模型特别有效,有助于减少过拟合。

Boosting 按顺序构建集成模型。每个新模型都尝试纠正之前集成模型犯的错误。被早期模型错误分类的样本在后续模型的训练中会被赋予更高的权重。这使得学习过程更关注“困难”的样本。AdaBoost 和梯度提升机(GBM)是经典示例。

Voting 结合了多个不同类型模型(例如,逻辑回归、SVM、决策树)的预测。在硬投票法 (hard voting) 中,最终预测是多数模型预测的类别标签。在软投票法 (soft voting) 中,它平均每个模型预测的概率,并选择平均概率最高的类别(如果分类器可以输出概率,通常效果更好)。

另一种相关技术是 Stacking,其中多个基学习器的预测被用作最终“元学习器”(meta-learner)的输入特征,由元学习器做出最终预测。

让我们使用 Pima Indians 糖尿病数据集实现一些常见的 Bagging 算法。我们将使用交叉验证来获得更可靠的性能估计。

# Common imports for Bagging examples
import pandas as pd
from sklearn.model_selection import KFold, cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
# --- Load Data (Example using URL) ---
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv'
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
dataframe = pd.read_csv(url, names=names)
X = dataframe[names[:-1]]
y = dataframe[names[-1]]
# --- Setup Cross-Validation ---
# Use KFold for cross-validation. shuffle=True is recommended.
kfold = KFold(n_splits=10, shuffle=True, random_state=42)

Bagging 通常应用于决策树,因为它们通常具有高方差。我们使用 BaggingClassifier 并将 DecisionTreeClassifier 作为基评估器。

from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier
# --- Define Base Estimator and Ensemble ---
base_estimator = DecisionTreeClassifier(random_state=42)
num_trees = 100 # Number of trees in the ensemble
# Create a pipeline to scale data then apply bagging
# Scaling is less critical for trees but good practice if comparing with other models
pipeline = Pipeline([
('scaler', StandardScaler()),
('bagging', BaggingClassifier(estimator=base_estimator,
n_estimators=num_trees,
random_state=42))
])
# --- Evaluate Model ---
results = cross_val_score(pipeline, X, y, cv=kfold, scoring='accuracy')
print(f"Bagged Decision Trees Accuracy: {results.mean():.4f} (Std: {results.std():.4f})")

输出解释:此代码训练 100 个决策树,每个树都在(缩放后的)数据的不同 bootstrap 样本上训练。最终准确率是 10 个交叉验证折叠上平均的准确率。标准差给出了得分变异性的大致概念。

Random Forest 是对基本 bagged 树的增强。除了采样数据点(bagging)外,它在构建树时,在每个分裂点还会采样特征的随机子集。这进一步增加了树之间的多样性,并且通常带来更好的性能。

from sklearn.ensemble import RandomForestClassifier
# --- Define and Evaluate Model ---
num_trees = 100
max_features = 'sqrt' # Common choice: sqrt(n_features)
pipeline = Pipeline([
('scaler', StandardScaler()), # Still included for consistency, though less vital for RF
('rf', RandomForestClassifier(n_estimators=num_trees,
max_features=max_features,
random_state=42))
])
results = cross_val_score(pipeline, X, y, cv=kfold, scoring='accuracy')
print(f"Random Forest Accuracy: {results.mean():.4f} (Std: {results.std():.4f})")

输出解释:与 bagged 树类似,但 RandomForestClassifier 本身包含数据和特征采样。max_features='sqrt' 告诉它在寻找每个节点最佳分裂点时,只考虑一个随机子集(特征总数的平方根)。

Extra Trees (Extremely Randomized Trees / 极限随机树)

Section titled “Extra Trees (Extremely Randomized Trees / 极限随机树)”

Extra Trees 引入了更多的随机性。它使用整个原始样本构建树(没有 bootstrap),但在每个节点,它考虑一个随机特征子集(像 Random Forest),并在其中随机选择分裂点,而不是寻找最优分裂点。这有时可以进一步降低方差并加快训练速度。

from sklearn.ensemble import ExtraTreesClassifier
# --- Define and Evaluate Model ---
num_trees = 100
max_features = 'sqrt'
pipeline = Pipeline([
('scaler', StandardScaler()),
('et', ExtraTreesClassifier(n_estimators=num_trees,
max_features=max_features,
random_state=42))
])
results = cross_val_score(pipeline, X, y, cv=kfold, scoring='accuracy')
print(f"Extra Trees Accuracy: {results.mean():.4f} (Std: {results.std():.4f})")

输出解释:使用 Extra Trees 算法训练一个集成模型,该算法以其在特征选择和分裂点确定中的高度随机性而闻名。

Boosting 算法按顺序构建模型,每个新模型都专注于纠正前一个模型犯的错误。通常建议对 Boosting 算法进行数据缩放。

AdaBoost 通过为训练样本分配权重来工作。最初,所有样本具有相同的权重。在每个基学习器(通常是称为 ‘stump’ 的浅层决策树)训练完成后,错误分类样本的权重会增加。随后的学习器因此会更关注这些更难分类的样本。

from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier # Often used as base estimator
# --- Define and Evaluate Model ---
# AdaBoost often uses shallow trees
base_estimator = DecisionTreeClassifier(max_depth=1, random_state=42)
num_estimators = 50
pipeline = Pipeline([
('scaler', StandardScaler()),
('adaboost', AdaBoostClassifier(estimator=base_estimator, # Use 'estimator' instead of 'base_estimator' in newer versions
n_estimators=num_estimators,
random_state=42))
])
results = cross_val_score(pipeline, X, y, cv=kfold, scoring='accuracy')
print(f"AdaBoost Accuracy: {results.mean():.4f} (Std: {results.std():.4f})")

输出解释:实现 AdaBoost,通常使用弱学习器(决策树桩)。它按顺序训练评估器,根据错误分类调整权重。

Gradient Boosting Machine (GBM / 梯度提升机)

Section titled “Gradient Boosting Machine (GBM / 梯度提升机)”

GBM 像 AdaBoost 一样按顺序构建模型,但它不是调整样本权重,而是让每个新模型拟合先前集成模型的残差(预测值与实际值之间的差)。它使用梯度下降来最小化损失函数。

from sklearn.ensemble import GradientBoostingClassifier
# --- Define and Evaluate Model ---
num_estimators = 100
pipeline = Pipeline([
('scaler', StandardScaler()),
('gbm', GradientBoostingClassifier(n_estimators=num_estimators,
random_state=42))
])
results = cross_val_score(pipeline, X, y, cv=kfold, scoring='accuracy')
print(f"Gradient Boosting Accuracy: {results.mean():.4f} (Std: {results.std():.4f})")

输出解释:实现标准的梯度提升算法。每棵树都试图纠正前面一系列树所犯的错误。

高级 Boosting 注释: 虽然 Scikit-learn 提供了 GradientBoostingClassifier,但像 XGBoost、LightGBM 和 CatBoost 这样的库提供了高度优化且通常更优越的梯度提升实现,并具有正则化和处理分类数据等附加功能。它们值得探索以获得具有竞争力的性能:

Voting 分类器结合了多个不同机器学习模型的预测。当你有几个表现良好但多样化的模型时,它很有用。

示例:组合逻辑回归、决策树和 SVM。

from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.ensemble import VotingClassifier
# --- Define Base Models ---
# Create pipelines for each model to include scaling
log_reg = Pipeline([('scaler', StandardScaler()),
('lr', LogisticRegression(solver='liblinear', random_state=42))])
dtree = Pipeline([('scaler', StandardScaler()), # Scaling might not affect tree much, but keeps setup consistent
('dt', DecisionTreeClassifier(random_state=42))])
svm_clf = Pipeline([('scaler', StandardScaler()),
# Enable probability estimates for soft voting
('svc', SVC(probability=True, random_state=42))])
# --- Create Voting Ensemble ---
# List of (name, model) tuples
estimators = [
('lr', log_reg),
('dt', dtree),
('svc', svm_clf)
]
# Use soft voting (averages probabilities) - often better
ensemble = VotingClassifier(estimators=estimators, voting='soft')
# --- Evaluate Model ---
results = cross_val_score(ensemble, X, y, cv=kfold, scoring='accuracy')
print(f"Voting Classifier (Soft) Accuracy: {results.mean():.4f} (Std: {results.std():.4f})")
# --- Example for Hard Voting ---
ensemble_hard = VotingClassifier(estimators=estimators, voting='hard')
results_hard = cross_val_score(ensemble_hard, X, y, cv=kfold, scoring='accuracy')
print(f"Voting Classifier (Hard) Accuracy: {results_hard.mean():.4f} (Std: {results_hard.std():.4f})")

输出解释:此代码在包含缩放的 Pipeline 中训练三个不同的模型(逻辑回归、决策树、SVM)。然后使用 VotingClassifier 组合它们的预测。展示了软投票(平均概率)和硬投票(多数投票)。请注意,SVC 需要 probability=True 才能参与软投票。

集成方法是现代机器学习的基石,通常能显著提升性能。实验不同的基学习器和集成策略是为给定问题找到最佳解决方案的关键。请记住,对基学习器和集成方法本身进行超参数调优对于获得最优结果也至关重要。