集成学习是一种通过组合多个弱学习器(如决策树、线性模型等),从而减少单一模型的偏差和方差,进而提高模型的泛化能力和整体模型性能的机器学习方法。
在集成学习中,弱学习器可以采用不同类型的模型,比如将支持向量机、神经网络和决策树整合在一起,构建一个更强的集成模型。也可以采用相同类型的学习器,例如多个弱学习器都使用决策树。通常情况下,集成学习更倾向于使用相同的学习模型。
常见的集成学习算法包括 Bagging(如随机森林)、Boosting(如 AdaBoost、XGBoost)和 Stacking。
1. Bagging
Bagging 在原始数据集中,通过有放回采样产生训练子集来训练多个基础分类器,然后将这些分类器的预测结果通过多数投票或简单平均的方法组合起来,生成最终的预测结果。
有放回采样(With Replacement Sampling)是指在抽样过程中,每次从样本集中选取一个样本后,将该样本放回原始样本集中,这意味着这个样本在后续的抽取过程中仍然有可能再次被选中。
假设我们有一个包含 5 个元素的原始数据集:[A, B, C, D, E]
。
现在我们想从这个数据集中抽取 3 个样本,看看在有放回采样的情况下可能会出现什么结果:
- 第一次抽样:我们随机抽取到样本
B
,因为是有放回抽样,所以B
会被放回到数据集中。- 抽取结果:
B
- 数据集:
[A, B, C, D, E]
(保持不变)
- 抽取结果:
- 第二次抽样:我们又随机抽取到样本
B
,因为是有放回的,所以B
再次被放回数据集中。- 抽取结果:
B, B
- 数据集:
[A, B, C, D, E]
(保持不变)
- 抽取结果:
- 第三次抽样:我们随机抽取到样本
E
。- 抽取结果:
B, B, E
- 数据集:
[A, B, C, D, E]
(保持不变)
- 抽取结果:
最终,通过有放回采样,我们得到了一个子集 B, B, E
,其中 B
被重复抽取了两次。这就是有放回采样的特点:每次抽取的样本有可能再次被选中,从而导致重复的样本。
from sklearn.ensemble import BaggingClassifier from sklearn.datasets import load_iris from sklearn.svm import SVC from sklearn.tree import DecisionTreeClassifier from sklearn.ensemble import RandomForestClassifier from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler def test(): data = load_iris() X_train, X_test, y_train, y_test = train_test_split(data.data, data.target, test_size=0.2, random_state=42) estimators = [DecisionTreeClassifier(), SVC(), RandomForestClassifier()] for base_estimator in estimators: estimator = BaggingClassifier(estimator=base_estimator, n_estimators=3) estimator.fit(X_train, y_train) print(estimator.estimators_) score = estimator.score(X_test, y_test) print(score) if __name__ == '__main__': test()
2. Boosting
Boosting 是基于提升思想整合多个弱学习器的集成方法。每个学习器的训练都是基于前一个学习器的结果,从而在逐轮迭代中减少误差。这种 “循序渐进” 的训练方式确保了模型在训练过程中稳步提升其预测能力。这段话的重点:
简言之,Boosting 的核心思想是线性训练,每个学习器针对前面学习器的不足进行提升,提升的方式通常通过两种主要机制:
- 通过样本权重:
- 这种方式在 AdaBoost 中尤为明显。AdaBoost 通过逐轮调整样本的权重,重点关注那些前一轮分类错误的样本。模型会对那些难以分类的样本赋予更高的权重,使得后续的学习器在训练时更加重视这些难分类的样本。这种逐轮调整样本权重的机制可以理解为模型在针对难点进行提升。
- 通过拟合残差:
- 这种方式在 梯度提升(Gradient Boosting) 中被广泛使用。在每一轮中,模型通过拟合前一轮学习器的残差(即真实值与预测值的差异),来提升整体性能。残差拟合的过程可以看作是模型逐步纠正前一轮的错误,并通过残差缩小误差,逐渐逼近真实值。这种方式提升了模型的拟合能力。
from sklearn.ensemble import AdaBoostClassifier from sklearn.ensemble import GradientBoostingClassifier from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.tree import DecisionTreeClassifier def test(): data = load_iris() X_train, X_test, y_train, y_test = train_test_split(data.data, data.target, test_size=0.2, random_state=42) # 根据样本权重 estimator = AdaBoostClassifier(estimator=DecisionTreeClassifier(), n_estimators=10, learning_rate=1.0, algorithm="SAMME.R", random_state=42) estimator.fit(X_train, y_train) print(estimator.score(X_test, y_test)) # 根据拟合残差 estimator = GradientBoostingClassifier() estimator.fit(X_train, y_train) print(estimator.score(X_test, y_test)) if __name__ == '__main__': test()
3. Stacking
在不同的训练子集上并行训练多个弱学习器,然后用这多个弱学习器的输出结果训练最终的学习器。
from sklearn.ensemble import StackingClassifier from sklearn.datasets import load_iris from sklearn.svm import SVC from sklearn.tree import DecisionTreeClassifier from sklearn.ensemble import RandomForestClassifier from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler def test(): data = load_iris() X_train, X_test, y_train, y_test = train_test_split(data.data, data.target, test_size=0.2, random_state=42) estimators = [('dt', DecisionTreeClassifier()), ('svc', SVC()), ('rf', RandomForestClassifier())] estimator = StackingClassifier(estimators=estimators, final_estimator=LogisticRegression()) estimator.fit(X_train, y_train) score = estimator.score(X_test, y_test) print(score) if __name__ == '__main__': test()