集成学习
概述
集成学习是一种机器学习方法,旨在通过结合多个基本模型(称为基学习器)的预测来提高整体性能。它通过将不同的学习算法组合在一起,以解决单个模型可能无法很好解决的问题。集成学习的核心思想是多个弱模型的组合能够形成一个强大的集成模型,从而提高预测的准确性和鲁棒性。
个体学习器
- 基学习器(base learner)如果所有的个体学习器都是同质的,或者说都是同一个种类的,那么称这种个体学习器为基学习器
- 组件学习器(component learner)如果所有的个体学习器都是异质的,或者说是不同种类的,那么称这种个体学习器为组件学习器
- 弱学习器(weak learner)指泛化性能略优于随机猜测的学习器
- 强学习器指泛化性能显著优于随机猜测的学习器
集成方法
- 自助法(Bagging)
- 增强法(Boosting)
- 堆叠法(Stacking)
组合方法
-
平均法平均法主要用于数值型输出,分为简单平均法和加权平均法
- 简单平均法:取基学习器输出的平均数作为最终的输出
$$ H(x)=\frac{1}{M}\sum_i^Mh_i(x) $$
- 加权平均法:对每个基学习器的输出附以权重后相加 $$ H(X)=\frac{1}{M}\sum_i^Mw_ih_i(x) $$ $w_i$为每一个基学习器的权重,$w_i>0$且$\sum_i^Mw_i=1$
-
投票法投票法主要用于分类型输出,分为绝对多数投票法、相对多数投票法和加权投票法
-
绝对多数投票法:要求一个类别标记只有得票超过半数才被判断为该类别,否则拒绝预测 $$ H(x)=\begin{cases}c_j\quad\quad\sum_{i=1}^Mh_i^j(x)>0.5\sum_{k=1}^N\sum_{i=1}^Mh_i^k(x)\refuse\end{cases} $$
-
相对多数投票法:只要一个类别的预测输出最多则预测为该类别,不会拒绝预测
$$ H(x)=c_{argmax_j\sum_{i=1}^Mh_i^j(x)} $$
-
加权投票法:在相对多数投票法的基础上为基学习器对每个类别的预测输出添加了权重 $$ H(x)=c_{argmax_j\sum_{i=1}^Mw_ih_i^j(x)} $$
-
硬投票(Hard Voting):$h_i^j(x)$的取值只能为0和1
-
软投票(Soft Voting):$h_i^j(x)$的取值为0到1的任意值
-
自助法 Bagging
自助法(Bootstrap Aggregating) 的基本思想是通过从原始数据集中进行有放回抽样(bootstrap),创建多个子数据集,然后训练基学习器,最终进行预测。
- 对于给定的包含 m 个样本的数据集 D ,有放回的随机采样 m 次,就得到一个同样包含 m 个样本的数据集$\hat{D}$
- 初始数据集 D 中约有 36.8% 的样本未出现在采样数据集$\hat{D}$中,可以被用来作为测试集,测试得到的结果被称为包外估计
$$ \lim_{m\rightarrow\infty}(1-\frac{1}{m})^m=\frac{1}{e}\approx0.368 $$
- 组合方法
- 分类任务则采用投票法,得票最多的分类类别为最终的类别
- 回归任务则采用平均法,对所有基学习器的预测结果取平均得到最终的预测值
随机森林
随机森林(Random Forest)是一种利用决策树作为基学习器的Bagging集成学习算法,除此之外,随机森林还在决策树的训练过程中引入了随机属性选择。
- 构建过程
- 随机采样
- 采用自助采样法,对于给定的包含 m 个样本的数据集 D ,有放回的随机采样 m 次
- 随机属性
- 训练集的特征个数为 d ,每次仅选择 k(k<d) 个属性构建决策树
- 一般推荐$k=\log_2d$
- 树的构建
- 根据随机采样以及随机属性构建决策树,不进行剪枝,构建的若干棵决策树组成随机森林
- 随机采样
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
# 加载数据集
iris = load_iris()
X = iris.data
y = iris.target
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建随机森林模型
random_forest = RandomForestClassifier(n_estimators=100, random_state=42)
# 在训练集上训练模型
random_forest.fit(X_train, y_train)
# 在测试集上进行预测
y_pred = random_forest.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.2f}")
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error
# 加载数据集
boston = load_boston()
X = boston.data
y = boston.target
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建随机森林回归模型
random_forest = RandomForestRegressor(n_estimators=100, random_state=42)
# 在训练集上训练模型
random_forest.fit(X_train, y_train)
# 在测试集上进行预测
y_pred = random_forest.predict(X_test)
# 计算均方误差
mse = mean_squared_error(y_test, y_pred)
print(f"Mean Squared Error: {mse:.2f}")
增强法 Boosting
增强法 Boosting 是一种集成学习方法,它通过迭代地训练一系列弱学习器,并将它们组合成一个强大的集成模型。Boosting 方法通过关注先前迭代中被错误分类的样本,逐步提高这些样本的权重,从而让后续的弱学习器更专注于这些难以分类的样本。这有助于最终提高整体模型的性能。
构建过程
- 利用初始训练样本集训练得到一个基学习器
- 提高被基学习器误分的样本的权重,使得误分类样本在下一轮训练中得到更大的关注,利用调整后的样本训练得到下一个基学习器
- 重复上述步骤,直至得到M个学习器
- 将以上M个学习器加权结合
- 对于分类问题,采用有权重的投票方式
- 对于回归问题,采用加权平均得到预测值
常见方法
- AdaBoost (Adaptive Boosting): AdaBoost 是最早引入的 Boosting 方法之一。它在每个迭代中调整样本的权重,使先前被错误分类的样本获得更高的权重,从而让后续的模型更专注于这些样本。AdaBoost 使用加权多数投票的方式整合各个弱学习器的预测结果。
- Gradient Boosting: Gradient Boosting 是另一种常见的 Boosting 方法,通过逐步拟合残差来构建模型。每个新的弱学习器试图纠正之前模型的错误,使得整体模型逐步改进。XGBoost 和 LightGBM 是基于 Gradient Boosting 的优化算法,它们在大规模数据集上表现出色。
- XGBoost (Extreme Gradient Boosting): 一种高度优化的 Gradient Boosting 方法,通过改进了的正则化技术、并行处理和缺失值处理来提高性能。它在梯度提升的基础上引入了正则化项和一阶和二阶梯度信息,从而在训练过程中能够更好地控制模型的复杂度。XGBoost 在处理大规模数据集和高维数据时表现优异。
- LightGBM (Light Gradient Boosting Machine): 另一种基于 Gradient Boosting 的优化算法,它在处理大规模数据集时具有很高的效率。LightGBM 通过基于直方图的技术来处理特征分箱(binning),并采用了 Leaf-wise 生长策略,这使得它能够更快地建立决策树。此外,LightGBM 还支持类别特征的自动编码,从而减少了特征工程的工作量。
Bagging、Boosting二者之间的区别
-
抽样方法:
- Bagging(Bootstrap Aggregating):Bagging 使用有放回抽样(bootstrap)来创建多个子数据集,每个子数据集用于训练不同的基学习器。
- Boosting:Boosting 也使用抽样,但样本的权重会根据先前迭代中的表现进行调整,使错误分类的样本获得更高的权重。
-
弱学习器的训练方式:
-
Bagging:Bagging 使用并行方式训练每个基学习器,各个基学习器之间是独立的。
-
Boosting:Boosting 是串行训练的,每个基学习器会根据先前学习器的表现进行调整,专注于难以分类的样本。
-
-
重点关注样本:
-
Bagging:Bagging 平等对待所有样本,不特别关注错误分类的样本。
-
Boosting:Boosting 重点关注先前迭代中错误分类的样本,通过逐步提高这些样本的权重来进行学习。
-
-
预测结果整合:
-
Bagging:Bagging 方法通常通过投票或平均的方式整合各个基学习器的预测结果。
-
Boosting:Boosting 方法通常通过加权和的方式整合各个基学习器的预测结果。
-
-
集成模型性能:
-
Bagging:Bagging 方法通常能够减少模型的方差,从而提高泛化性能。
-
Boosting:Boosting 方法倾向于减少模型的偏差,从而提高整体性能。
-
自适应增强 Adaboost 算法
Adaboost (Adaptive Boosting) 是 Boosting 算法中最有代表性的一个。原始的 Adaboost 算法用于解决二分类问题。
构建过程
对于一个训练集 $$ T={(x_1,y_1),(x_2,y_2),\cdots,(x_n,y_n)} $$ 初始化样例权重为 $$ D_1=(w_{11},w_{12},\cdots,w_{1n})\ w_{1i}=\frac{1}{n} $$ 即初始化时每个样例的权重相等
对于每一轮训练,采用不放回抽样的方法,训练基学习器,基学习器的误差为$e_m$,根据误差确定该基学习器的权重系数$\alpha_m$ $$ \alpha_m=\frac{1}{2}\ln\frac{1-e_m}{e_m} $$ 随后更新样例权重 $$ D_{m+1}=(w_{m+1,1},w_{m+1,2},\cdots,w_{m+1,n})\ w_{m+1,i}=\frac{w_{m,i}}{Z_m}e^{-\alpha_my_ih_m(x_i)} $$ 其中$Z_m$为规范化因子 $$ Z_m=\sum_{i=1}^n w_{m,i}e^{-\alpha_my_ih_m(x_i)} $$
根据构建的M个基学习器得到最终的学习器 $$ h_{f(x)}=sign(\sum_{m=1}^M\alpha_mh_m(x)) $$
如何理解Adaboost 算法
- 分类器越准确,权重系数越大
$$ e_m=P(h_m(x_i)\not=y_i)\in(0,1) $$
显然,$e_m$越接近0,$\alpha_m$越大;$e_m$越接近1,$\alpha_m$越小;$e_m<0.5$时,表明基分类器不如随机猜测,此时$\alpha_m$为负。
- 增加分类错误样本的权重,减少分类正确样本的权重
$h_m(x_i)$为样本的预测类别,$y_i$为样本的真实类别,取值范围均为-1和1
讨论$\alpha_m>0$的情形
当$y_ih_m(x_i)$为$1$时,表示样本分类正确,系数$e^{-\alpha_my_ih_m(x_i)}<1$,$w_{m+1,i}$增大
为$-1$时表示样本分类错误,系数$e^{-\alpha_my_ih_m(x_i)}>1$,$w_{m+1,i}$减小
- 规范化因子$Z_m$保证$D_{m+1}$为一个概率分布
显然有: $$ \sum_{i=1}^Nw_{m+1,i}=1 $$
- 最终的学习器通过加权和符号函数生成了输出取值范围为-1和1的强分类器
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.ensemble import AdaBoostClassifier
from sklearn.metrics import accuracy_score
# 加载数据集
iris = load_iris()
X = iris.data
y = iris.target
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建 AdaBoost 分类器
adaboost = AdaBoostClassifier(n_estimators=50, random_state=42)
# 在训练集上训练模型
adaboost.fit(X_train, y_train)
# 在测试集上进行预测
y_pred = adaboost.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.2f}")
梯度提升树 GBDT
**梯度提升树(Gradient Boosting Decision Tree,GBDT)**是一种基于决策树的集成学习方法,属于 Boosting 算法的一种。它通过迭代地构建多个决策树,并通过梯度下降来逐步减小残差(预测误差),从而提高整体模型的性能。
构建过程
- 先建立一棵树,然后逐渐迭代,每次迭代过程中都增加一棵树,逐渐形成众多树模型集成的强评估器。
- 其核心在于每棵树学的是之前所有树结论和的残差,这里的残差是指真实值与已有预测值的差值。
- 对于 GBDT 而言,每个样本的预测结果都是上一个样本预测结果的加权求和。
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import accuracy_score
# 加载数据集
iris = load_iris()
X = iris.data
y = iris.target
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建 GBDT 分类器
gbdt = GradientBoostingClassifier(n_estimators=100, random_state=42)
# 在训练集上训练模型
gbdt.fit(X_train, y_train)
# 在测试集上进行预测
y_pred = gbdt.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.2f}")
XGBoost
**XGBoost(eXtreme Gradient Boosting)**是一种基于梯度提升树的机器学习算法,专门设计用于处理结构化数据和回归/分类问题。XGBoost 在梯度提升树的基础上引入了许多创新,以提高模型性能和训练速度。
关键特点
- 正则化项添加了正则化项(L1 和 L2 正则化)来控制模型的复杂度,避免过拟合。
- 二阶导数信息利用二阶导数信息来更精确地拟合残差,提高预测的准确性。
- 直方图近似使用直方图方法对特征分箱(binning),从而减少了计算和内存开销。
- 缺失值处理可以自动处理缺失值,不需要额外的预处理步骤。
- 分布式计算支持分布式计算,可以在多个核心上并行训练模型,提高训练速度。
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
import xgboost as xgb
from sklearn.metrics import accuracy_score
# 加载数据集
iris = load_iris()
X = iris.data
y = iris.target
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 将数据转换为 XGBoost 的 DMatrix 格式
dtrain = xgb.DMatrix(X_train, label=y_train)
dtest = xgb.DMatrix(X_test, label=y_test)
# 定义参数
params = {
"objective": "multi:softmax", # 多分类问题
"num_class": 3, # 类别数
"max_depth": 3, # 树的深度
"eta": 0.1, # 学习率
"seed": 42 # 随机种子
}
# 训练模型
num_round = 100 # 迭代次数
xgb_model = xgb.train(params, dtrain, num_round)
# 在测试集上进行预测
y_pred = xgb_model.predict(dtest)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.2f}")
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from xgboost import XGBClassifier
from sklearn.metrics import accuracy_score
# 加载数据集
iris = load_iris()
X = iris.data
y = iris.target
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建 XGBClassifier 模型
xgb_classifier = XGBClassifier(objective="multi:softmax", num_class=3, max_depth=3, learning_rate=0.1, random_state=42)
# 在训练集上训练模型
xgb_classifier.fit(X_train, y_train)
# 在测试集上进行预测
y_pred = xgb_classifier.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.2f}")
LightGBM
**LightGBM(Light Gradient Boosting Machine)**是一种高效的梯度提升树算法,专门设计用于处理大规模数据集和高维数据。它在性能和效率方面进行了优化,通过一些创新性的技术,能够在短时间内构建强大的预测模型。
关键特点
- 基于直方图的特征分箱:使用直方图的方法来对特征进行分箱,减少了特征工程的负担,同时提高了计算效率。
- Leaf-wise 生长策略:与传统的层次生长不同,LightGBM 采用了 Leaf-wise 策略,从树的叶节点开始进行生长,可以更快地构建深度树。
- GOSS(Gradient-based One-Side Sampling):GOSS 是一种样本采样策略,它只选择梯度大的样本来进行训练,从而提高了训练速度。
- EFB(Exclusive Feature Bundling):EFB 是一种特征选择技术,通过将相关性高的特征捆绑在一起,减少了冗余特征,提高了模型效率。
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
import lightgbm as lgb
from sklearn.metrics import accuracy_score
# 加载数据集
iris = load_iris()
X = iris.data
y = iris.target
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建 LightGBM 分类器模型
lgb_classifier = lgb.LGBMClassifier(objective="multiclass", num_class=3, max_depth=3, learning_rate=0.1, random_state=42)
# 在训练集上训练模型
lgb_classifier.fit(X_train, y_train)
# 在测试集上进行预测
y_pred = lgb_classifier.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.2f}")
堆叠法 Stacking算法
Stacking方法又称为 Stacked Generalization,是一种基于分层模型组合的集成算法。
基本思想
- 利用初级学习算法对原始数据集进行学习,同时生成一个新的数据集。
- 根据从初级学习算法生成的新数据集,利用次级学习算法学习并得到最终的输出。
对于初级学习器,可以是相同类型也可以是不同类型的。在新的数据集中,初级学习器的输出被用作次级学习器的输入特征,初始样本的标记仍被用作次级学习器学习样本的标记。
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.ensemble import StackingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
# 加载数据集
iris = load_iris()
X = iris.data
y = iris.target
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 定义基学习器
base_learners = [
("rf", RandomForestClassifier(n_estimators=100, random_state=42)),
("svm", SVC(kernel="linear", probability=True, random_state=42))
]
# 定义元学习器
meta_learner = LogisticRegression()
# 创建 Stacking 分类器模型
stacking_classifier = StackingClassifier(estimators=base_learners, final_estimator=meta_learner)
# 在训练集上训练模型
stacking_classifier.fit(X_train, y_train)
# 在测试集上进行预测
y_pred = stacking_classifier.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.2f}")
组件学习器
.如果所有的个体学习器都是异质的,或者说是不同种类的,那么称这种个体学习器为组件学习器
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
from sklearn.naive_bayes import GaussianNB
from sklearn.neural_network import MLPClassifier
from sklearn.ensemble import RandomForestClassifier
# 组件学习器、堆叠法分类器
from mlxtend.classifier import EnsembleVoteClassifier, StackingClassifier
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
# 绘制决策边界
from mlxtend.plotting import plot_decision_regions
iris = datasets.load_iris()
X, y = iris.data[:, [0, 2]], iris.target
# 逻辑回归
lr = LogisticRegression(solver='lbfgs', multi_class='multinomial', random_state=1)
# 堆叠法的初级评估器
meta = LogisticRegression(solver='lbfgs', multi_class='multinomial', random_state=1)
# 决策树
dtc = DecisionTreeClassifier(max_depth=4, random_state=1)
# K近邻
knn = KNeighborsClassifier(n_neighbors=4)
# 支持向量机
svc = SVC(gamma='scale', kernel='rbf', probability=True, random_state=1)
# 朴素贝叶斯
gnb = GaussianNB()
# 多层感知器
mlp = MLPClassifier(hidden_layer_sizes=(4, 4), activation='logistic', solver='lbfgs', random_state=1)
# 随机森林
rfc = RandomForestClassifier(n_estimators=4, max_depth=4, random_state=1)
# 投票法
evc = EnsembleVoteClassifier(
clfs=[lr, dtc, knn, svc, gnb, mlp, rfc],
voting='soft'
)
# 堆叠法
sc = StackingClassifier(
classifiers=[lr dtc, knn, svc, gnb, mlp, rfc],
meta_classifier=meta
)
clf_names = [
'Logistic Regression', 'Decision Tree', 'KNN','SVC', 'Naive Bayes', 'MLP','Random Forest', 'Voting', 'Stacking']
clfs = [lr, dtc, knn, svc, gnb, mlp, rfc, evc, sc]
fig = plt.figure(figsize=(8, 9))
gs = gridspec.GridSpec(3, 3)
for clf, name, grid in zip(clfs, clf_names, range(len(clfs))):
clf.fit(X, y)
# 定义绘制空间
ax = plt.subplot(gs[int(grid / 3), grid % 3])
# 绘制决策边界
plot_decision_regions(X=X, y=y, clf=clf, legend=2)
# 无坐标轴
plt.axis('off')
# 紧密布局
plt.tight_layout()
# 绘制标题
plt.title(name)