集成学习 是一种机器学习范式,它创建一组模型,并将它们的预测结果结合起来,以期望最终模型能够优于单个模型。集成学习的关键在于如何有效地结合不同的模型。
集成学习算法分为:Bagging,Boosting和Stacking等类型。
- Bagging(自举汇聚):通过自助采样从原始训练数据集中创建多个数据集,然后在每个数据集上训练相同的模型,最后将结果结合起来。
- Boosting(提升):按顺序训练模型,每个新模型都在前一个模型的误差上进行改进。
- Stacking(堆叠):训练多个不同的模型,然后将它们的预测作为新的特征输入到一个或多个最终模型中。
Bagging:并行的弱学习器
Bagging,即Bootstrap Aggregating,是一种简单而有效的集成技术。它通过并行训练多个弱学习器来实现:
- 原理:Bagging通过对原始数据集进行多次重采样(有放回抽样)来创建不同的训练子集,然后在每个子集上训练一个弱学习器。
- 分类问题:在分类问题中,Bagging通过投票机制来决定最终的预测类别,即得票最多的类别获胜。
- 回归问题:在回归问题中,Bagging简单地计算所有弱学习器预测值的平均值作为最终预测。
典例:随机森林是一种典型的Bagging集成方法,它使用多个决策树作为弱学习器,并通过并行训练和投票/平均机制来提高预测的准确性和鲁棒性。
Bagging随机森林
RF 默认采用 CART 作为基学习器,而且它在 Bagging 模型的基础上再进一步,每次训练基学习器时,除对样本随机采样外,对样本的特征也进行随机采样。
由于采用的是 CART ,所以 RF 既可以用来分类,又可以用来回归 RF 用来分类时使用 CART 分类树作为基学习器,最后的投票结果是取票数最多的类别作为最终的预测结果;RF 用来回归时使用 CART 回归树作为基学习器,最后的预测结果是采用所有 CART 回归树的预测值的均值。
怎样获得不同的弱分类器?
-
使用不同的训练集:随机森林通过从原始训练集中进行有放回抽样来为每棵决策树创建不同的训练集。这种重采样过程增加了模型的多样性,因为每棵树都是在略微不同的数据集上训练的。
-
决策树桩:随机森林中的弱分类器通常是决策树桩(decision stumps),即深度为1的决策树。这些树桩虽然简单,但足以捕捉数据中的局部特征。
-
参数多样性:即使使用相同的学习算法,不同的参数设置也能产生不同的模型。随机森林通过调整决策树的参数(如树的最大深度、分裂所需的最小样本数等)来增加模型的多样性。
-
特征随机性:在随机森林中,每棵树在分裂节点时不是考虑所有特征,而是随机选择一部分特征。这种方法进一步增加了每棵树的独立性。
-
不同表示法:通过使用不同的特征子集或变换,相同的输入对象可以有不同的表示,从而凸显数据的不同特征
随机森林的流程
-
初始化:设置森林中树的数量和其他相关参数。
-
重采样:对于每棵树,从原始训练集中进行有放回抽样,创建不同的训练数据集。
-
训练:在每个训练集上训练一棵决策树,通常每棵树都是一个简单的决策树桩。
-
特征选择:在每个决策树的节点分裂过程中,随机选择一部分特征,选择最佳分裂点。
-
弱分类器集合:重复步骤2-4,直到获得足够数量的树。
-
聚合结果:对于分类问题,通过多数投票的方式决定最终的预测类别;对于回归问题,计算所有树预测结果的平均值。
Code
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# 创建一个二分类数据集
X, y = make_classification(n_samples=1000, n_features=20,
n_informative=2, n_redundant=10,
random_state=42)
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 初始化随机森林分类器
# 参数解释:
# n_estimators: 森林中树的数量
# max_depth: 树的最大深度
# min_samples_split: 分割内部节点所需的最小样本数
# min_samples_leaf: 叶节点所需的最小样本数
# random_state: 控制随机性的种子
rf_classifier = RandomForestClassifier(n_estimators=100, max_depth=10,
min_samples_split=2, min_samples_leaf=1,
random_state=42)
# 训练模型
rf_classifier.fit(X_train, y_train)
# 预测测试集
y_pred = rf_classifier.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.2f}")
# 特征重要性
feature_importances = rf_classifier.feature_importances_
print("Feature importances:", feature_importances)
优点
-
高准确性:由于随机森林结合了多个决策树的预测,它通常能够提供比单个决策树更高的准确性。
-
防止过拟合:随机森林通过训练多个树并进行投票或平均,减少了模型对训练数据的过度拟合。
-
特征重要性评估:随机森林能够评估各个特征对预测结果的重要性,这有助于特征选择和数据理解。
-
并行处理:随机森林中的每棵树是独立构建的,可以并行训练,这使得它在处理大规模数据集时非常高效。
Boosting:迭代的弱学习器
Boosting是一种迭代的集成技术,它逐步构建弱学习器,每个学习器都在前一个的基础上进行改进:
- 原理:Boosting通过调整数据的权重来关注前一轮分类错误的样本,从而使得后续的弱学习器能够专注于难以分类的数据点。
- 加权机制:在加入新的弱学习器时,通常会根据它们的分类准确率给予不同的权重,以确保模型的性能不断提升。
- 数据重新加权:每次迭代后,数据会被重新加权,以强化对错误分类数据点的关注。
典例:AdaBoost(Adaptive Boosting)算法是一种流行的Boosting方法,它通过迭代地调整数据权重和弱学习器的权重,有效地提高了分类的准确性。
AdaBoost的运行过程
AdaBoost算法的核心在于其迭代过程,主要涉及以下几个问题:
-
如何计算每一次训练集样本的权重?AdaBoost 轮都会使用全部的训练集样本,但每一轮都会改变样本的权重分布,其方法是用本轮得到的基学习器对所有训练样本进行 次预测,得到一个预测误差率 ;下一轮训练中各个训练样本的情况由该训练样本自身、本轮基学习器对该样本的预测值、本轮基学习器对训练样本的整体预测误差率三者共同决定。
-
如何训练基模型?实际上, AdaBoost与RF一样,既可以用于分类问题,又可以用于回归问题, 因为它们默认使用的基学习器都是 CART 决策树。所以,只要每一轮将原始样本按新的权重系数重新计算出来后,基学习器的训练与普通的单模型训练过程是完全一致的。
-
如何计算基模型的预测误差率?对于分类问题,计算模型的预测误差率可以直接使用 0-1损失函数:对于回归问题,计算基模型的预测误差率可以使用平方损失函数或指数损失函数。
-
如何计算各个基学习器的投票权重?各个基学习器的投票权重问是根据每一轮的预测误差率计算得到的,假设通过 轮迭代,我们得到了各个基学习器的投票权重, k = 1,2, ... , K,那么对于结果为 {-1,1}的二分类,最后的投票公式就是:
其中是第k个基学习器的预测结果值。
流程图如下:
流程
-
初始化样本权重:为训练集中的每个样本分配相同的权重。
-
训练基模型:在当前加权的训练集上训练一个弱学习器。
-
计算预测误差率:评估基模型在加权训练集上的表现,计算误差率。
-
计算基学习器权重:根据基模型的误差率计算其权重,误差率越低,权重越大。
-
更新样本权重:根据基模型的表现更新样本权重,错误分类的样本将获得更高的权重。
-
迭代训练:重复步骤2-5,直到满足迭代次数或模型性能不再提升。
-
组合基模型:将所有基模型按照其权重进行投票或加权平均,得到最终的强分类器。
Code
使用Python和scikit-learn
库实现AdaBoost算法的一个简单例子如下:
from sklearn.ensemble import AdaBoostClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# 创建一个二分类数据集
X, y = make_classification(n_samples=1000, n_features=20,
n_informative=2, n_redundant=10,
random_state=42)
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 初始化AdaBoost分类器
ada_boost = AdaBoostClassifier(n_estimators=50, random_state=42)
# 训练模型
ada_boost.fit(X_train, y_train)
# 预测测试集
y_pred = ada_boost.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.2f}")
优点
- 提高准确性:AdaBoost通过逐步关注难以分类的样本,提高了模型的整体准确性。
- 防止过拟合:通过结合多个弱学习器,AdaBoost减少了过拟合的风险。
- 易于实现:AdaBoost算法简单,易于实现,并且可以使用不同的弱学习器。
- 自适应性:AdaBoost能够适应数据的变化,自动调整基学习器的权重。
- 鲁棒性:AdaBoost对噪声和异常值具有较好的鲁棒性。
Stacking:堆叠的模型
Stacking是一种将多个模型的预测结果作为新特征输入到一个或多个最终模型中的集成技术:
- 原理:Stacking首先训练多个不同的基模型,然后将它们的预测结果作为新的特征,用于训练一个或多个元模型(meta-model)。
- 多模型融合:这种方法可以结合不同模型的优势,通过元模型的非线性能力来提高整体的预测性能。
Stacking算法流程
Stacking是一种层次化的集成方法,它通常分为两个层次:
-
基础层(Level 0):在基础层,训练多个不同的模型,这些模型可以是决策树、支持向量机、神经网络等。
-
元层(Level 1):元层是一个或多个模型,它们使用基础层模型的预测作为输入来做出最终预测。
流程
-
步骤 1:将训练数据集分割为多个子集。
-
步骤 2:在每个子集上训练基础层模型。
-
步骤 3:使用基础层模型对验证集进行预测。
-
步骤 4:将这些预测作为特征,训练元层模型。
-
步骤 5:在测试集上重复步骤3和4,得到最终预测。
Code
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
# 加载数据集
X, y = load_iris(return_X_y=True)
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 基础层模型
level_0_models = [
RandomForestClassifier(n_estimators=50),
SVC(probability=True),
GradientBoostingClassifier(n_estimators=50)
]
# 元层模型
meta_model = LogisticRegression()
# Stacking预测
stacked_predictions = np.zeros((X_train.shape[0], len(level_0_models)))
for i, model in enumerate(level_0_models):
model.fit(X_train, y_train)
stacked_predictions[:, i] = model.predict_proba(X_train)[:, 1]
# 元层模型训练
meta_model.fit(stacked_predictions, y_train)
# 预测测试集
test_predictions = np.zeros((X_test.shape[0], len(level_0_models)))
for i, model in enumerate(level_0_models):
test_predictions[:, i] = model.predict_proba(X_test)[:, 1]
# 元层模型预测
final_predictions = meta_model.predict(test_predictions)
# 输出结果
print("Final predictions:", final_predictions)
优点
-
提高准确性:通过结合多个模型的预测,Stacking通常能够提高模型的准确性。
-
减少过拟合:Stacking通过引入元层模型,有助于减少过拟合的风险。
-
灵活性:Stacking允许使用不同类型的基础层和元层模型,提供了高度的灵活性。
-
特征学习:元层模型可以从基础层模型的预测中学习更复杂的特征。
-
鲁棒性:Stacking通过集成多个模型,提高了对异常值和噪声的鲁棒性。
总结
集成算法的优势
- 提高准确性:集成算法通过结合多个模型的预测,通常能够提供比单个模型更高的准确性。
- 增强鲁棒性:集成算法减少了模型对异常值和噪声的敏感性,提高了模型的泛化能力。
- 减少过拟合:通过多样化的模型组合,集成算法降低了过拟合的风险。