集成学习
1. 个体与集成
集成学习 (ensemble learning) 通过构建并结合多个学习器来完成学习任务,有时也被称为多分类器系统 (multi-classifier system)、基于委员会的学习 (committee-based learning) 等。
注:ensemble 读音似 "昂桑宝" 而非 "因桑宝"。
集成学习的一般结构是:先产生一组 "个体学习器" (individual learner),再用某种策略将它们结合起来。个体学习器通常由一个现有的学习算法从训练数据产生,例如 C4.5 决策树算法、BP 神经网络算法等,此时集成中只包含同种类型的个体学习器,例如 "决策树集成" 中全是决策树,"神经网络集成" 中全是神经网络,这样的集成是 "同质" 的 (homogeneous)。同质集成中的个体学习器亦称 "基学习器" (base learner),相应的学习算法称为 "基学习算法" (base learning algorithm)。集成也可包含不同类型的个体学习器,例如同时包含决策树和神经网络,这样的集成是 "异质" 的 (heterogenous)。异质集成中的个体学习器由不同的学习算法生成,这时就不再有基学习算法;相应的,个体学习器一般不称为基学习器,常称为 "组件学习器" (component learner) 或直接称为个体学习器。
集成学习通过将多个学习器进行结合,常可获得比单一学习器显著优越的泛化性能。这对 "弱学习器" (weak learner) 尤为明显,因此集成学习的很多理论研究都是针对弱学习器进行的,而基学习器有时也被直接称为弱学习器。但需注意的是,虽然从理论上来说使用弱学习器集成足以获得好的性能,但在实践中出于种种考虑,例如希望使用较少的个体学习器,或是重用关于常见学习器的一些经验等,人们往往会使用比较强的学习器。
注:弱学习器常指泛化性能略优于随机猜测的学习器;例如在二分类问题上精度略高于 50% 的分类器。
在一般经验中,如果把好坏不等的东西掺到一起,那么通常结果会是比最坏的要好一些,比最好的要坏一些。集成学习把多个学习器结合起来,如何能获得比最好的单一学习器更好的性能呢?
考虑一个简单的例子:在二分类任务中,假定三个分类器在三个测试样本上的表现,其中 \sqrt{} 表示分类正确,×\times× 表示分类错误,集成学习的结果通过投票法 (voting) 产生,即 "少数服从多数"。如果每个分类器都只有 66.6% 的精度,但集成学习却达到了 100%;如果三个分类器没有差别,集成之后性能没有提高;如果每个分类器的精度都只有 33.3%,集成学习的结果变得更糟。这个简单的例子显示出:要获得好的集成,个体学习器应 "好而不同",即个体学习器要有一定的 "准确性",即学习器不能太坏,并且要有 "多样性" (diversity),即学习器间具有差异。
我们来做个简单的分析。考虑二分类问题 y∈{−1,+1}y \in \{-1, +1\}y∈{−1,+1} 和真实函数 fff,假定基分类器的错误率为 ϵ\epsilonϵ,即对每个基分类器 hih_ihi 有
P(hi(x)≠f(x))=ϵ(1) P(h_i(\boldsymbol{x}) \neq f(\boldsymbol{x})) = \epsilon \quad \quad (1) P(hi(x)=f(x))=ϵ(1)
假设集成通过简单投票法结合 TTT 个基分类器,若有超过半数的基分类器正确,则集成分类就正确:
H(x)=sign(∑i=1Thi(x))(2) H(\boldsymbol{x}) = \text{sign} \left( \sum_{i=1}^{T} h_i(\boldsymbol{x}) \right) \quad \quad (2) H(x)=sign(i=1∑Thi(x))(2)
注:为简化讨论,假设 TTT 为奇数。
假设基分类器的错误率相互独立,则由 Hoeffding 不等式可知,集成的错误率为
P(H(x)≠f(x))=∑k=0⌊T/2⌋(Tk)(1−ϵ)kϵT−k≤exp(−12T(1−2ϵ)2)(3) \begin{aligned} P(H(\boldsymbol{x}) \neq f(\boldsymbol{x})) &= \sum_{k=0}^{\lfloor T/2 \rfloor} \binom{T}{k} (1-\epsilon)^k \epsilon^{T-k} \\ &\le \exp \left( -\frac{1}{2} T (1-2\epsilon)^2 \right) \quad \quad (3) \end{aligned} P(H(x)=f(x))=k=0∑⌊T/2⌋(kT)(1−ϵ)kϵT−k≤exp(−21T(1−2ϵ)2)(3)
上式显示出,随着集成中个体分类器数目 TTT 的增大,集成的错误率将指数级下降,最终趋向于零。
然而我们必须注意到,上面的分析有一个关键假设:基学习器的误差相互独立。在现实任务中,个体学习器是为解决同一个问题训练出来的,它们显然不可能相互独立!事实上,个体学习器的 "准确性" 和 "多样性" 本身就存在冲突。一般的,准确性很高之后,要增加多样性就需牺牲准确性。事实上,如何产生并结合 "好而不同" 的个体学习器,恰是集成学习研究的核心。
根据个体学习器的生成方式,目前的集成学习方法大致可分为两大类,即个体学习器间存在强依赖关系、必须串行生成的序列化方法,以及个体学习器间不存在强依赖关系、可同时生成的并行化方法;前者的代表是 Boosting,后者的代表是 Bagging 和 "随机森林" (Random Forest)。
python
> **【代码实践 1】 简单的投票集成示例**
>
> 下面代码模拟了三个准确率略高于随机猜测的分类器,通过投票机制提升整体性能的过程:
>
> ```python
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import RandomForestClassifier, VotingClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# 1. 生成样本数据
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 2. 定义三个差异较大的基学习器
clf1 = LogisticRegression(random_state=1)
clf2 = RandomForestClassifier(n_estimators=50, random_state=1)
clf3 = GaussianNB()
# 3. 定义投票集成学习器 (硬投票)
eclf = VotingClassifier(estimators=[('lr', clf1), ('rf', clf2), ('gnb', clf3)], voting='hard')
# 4. 输出各模型性能
for clf, label in zip([clf1, clf2, clf3, eclf], ['Logistic Regression', 'Random Forest', 'naive Bayes', 'Ensemble']):
clf.fit(X_train, y_train)
pred = clf.predict(X_test)
print(f"Accuracy: {accuracy_score(y_test, pred):.2f} [{label}]")
2. Boosting
Boosting 是一族可将弱学习器提升为强学习器的算法。这族算法的工作机制类似:先从初始训练集训练出一个基学习器,再根据基学习器的表现对训练样本分布进行调整,使得先前基学习器做错的训练样本在后续受到更多关注,然后基于调整后的样本分布来训练下一个基学习器;如此重复进行,直至基学习器数目达到事先指定的值 TTT,最终将这 TTT 个基学习器进行加权结合。
Boosting 族算法最著名的代表是 AdaBoost [Freund and Schapire, 1997],其描述如下:
输入: 训练集 D={(x1,y1),(x2,y2),...,(xm,ym)}D = \{(\boldsymbol{x}_1, y_1), (\boldsymbol{x}_2, y_2), \dots, (\boldsymbol{x}_m, y_m)\}D={(x1,y1),(x2,y2),...,(xm,ym)};
基学习算法 L\mathfrak{L}L;
训练轮数 TTT.
过程:
1: D1(x)=1/mD_1(\boldsymbol{x}) = 1/mD1(x)=1/m.
2: for t=1,2,...,Tt = 1, 2, \dots, Tt=1,2,...,T do
3: ht=L(D,Dt)h_t = \mathfrak{L}(D, D_t)ht=L(D,Dt); % 基于分布 DtD_tDt 从数据集 DDD 中训练出分类器 hth_tht
4: ϵt=Px∼Dt(ht(x)≠f(x))\epsilon_t = P_{\boldsymbol{x} \sim D_t}(h_t(\boldsymbol{x}) \neq f(\boldsymbol{x}))ϵt=Px∼Dt(ht(x)=f(x)); % 估计 hth_tht 的误差
5: if ϵt>0.5\epsilon_t > 0.5ϵt>0.5 then break
6: αt=12ln(1−ϵtϵt)\alpha_t = \frac{1}{2} \ln \left( \frac{1-\epsilon_t}{\epsilon_t} \right)αt=21ln(ϵt1−ϵt); % 确定分类器 hth_tht 的权重
7: Dt+1(x)=Dt(x)exp(−αtf(x)ht(x))ZtD_{t+1}(\boldsymbol{x}) = \frac{D_t(\boldsymbol{x}) \exp(-\alpha_t f(\boldsymbol{x}) h_t(\boldsymbol{x}))}{Z_t}Dt+1(x)=ZtDt(x)exp(−αtf(x)ht(x)) % 更新样本分布,其中 ZtZ_tZt 是规范化因子,以确保 Dt+1D_{t+1}Dt+1 是一个分布
8: end for
输出: H(x)=sign(∑t=1Tαtht(x))H(\boldsymbol{x}) = \text{sign} \left( \sum_{t=1}^{T} \alpha_t h_t(\boldsymbol{x}) \right)H(x)=sign(∑t=1Tαtht(x))
AdaBoost 算法有多种推导方式,比较容易理解的是基于 "加性模型" (additive model),即基学习器的线性组合
H(x)=∑t=1Tαtht(x)(4) H(\boldsymbol{x}) = \sum_{t=1}^{T} \alpha_t h_t(\boldsymbol{x}) \quad \quad (4) H(x)=t=1∑Tαtht(x)(4)
来最小化指数损失函数 (exponential loss function) [Friedman et al., 2000]
ℓexp(H∣D)=Ex∼D[e−f(x)H(x)](5) \ell_{\exp}(H | \mathcal{D}) = \mathbb{E}_{\boldsymbol{x} \sim \mathcal{D}} [e^{-f(\boldsymbol{x})H(\boldsymbol{x})}] \quad \quad (5) ℓexp(H∣D)=Ex∼D[e−f(x)H(x)](5)
若 H(x)H(\boldsymbol{x})H(x) 能令指数损失函数最小化,则考虑式(5)对 H(x)H(\boldsymbol{x})H(x) 的偏导
∂ℓexp(H∣D)∂H(x)=−e−H(x)P(f(x)=1∣x)+eH(x)P(f(x)=−1∣x)(6) \frac{\partial \ell_{\exp}(H | \mathcal{D})}{\partial H(\boldsymbol{x})} = -e^{-H(\boldsymbol{x})} P(f(\boldsymbol{x}) = 1 | \boldsymbol{x}) + e^{H(\boldsymbol{x})} P(f(\boldsymbol{x}) = -1 | \boldsymbol{x}) \quad \quad (6) ∂H(x)∂ℓexp(H∣D)=−e−H(x)P(f(x)=1∣x)+eH(x)P(f(x)=−1∣x)(6)
令式(6)为零可解得
H(x)=12lnP(f(x)=1∣x)P(f(x)=−1∣x)(7) H(\boldsymbol{x}) = \frac{1}{2} \ln \frac{P(f(\boldsymbol{x}) = 1 | \boldsymbol{x})}{P(f(\boldsymbol{x}) = -1 | \boldsymbol{x})} \quad \quad (7) H(x)=21lnP(f(x)=−1∣x)P(f(x)=1∣x)(7)
因此,有
sign(H(x))=sign(12lnP(f(x)=1∣x)P(f(x)=−1∣x))={1,P(f(x)=1∣x)>P(f(x)=−1∣x)−1,P(f(x)=1∣x)<P(f(x)=−1∣x)=argmaxy∈{−1,1}P(f(x)=y∣x)(8) \begin{aligned} \text{sign}(H(\boldsymbol{x})) &= \text{sign} \left( \frac{1}{2} \ln \frac{P(f(\boldsymbol{x}) = 1 | \boldsymbol{x})}{P(f(\boldsymbol{x}) = -1 | \boldsymbol{x})} \right) \\ &= \begin{cases} 1, & P(f(\boldsymbol{x}) = 1 | \boldsymbol{x}) > P(f(\boldsymbol{x}) = -1 | \boldsymbol{x}) \\ -1, & P(f(\boldsymbol{x}) = 1 | \boldsymbol{x}) < P(f(\boldsymbol{x}) = -1 | \boldsymbol{x}) \end{cases} \\ &= \underset{y \in \{-1, 1\}}{\arg\max} P(f(\boldsymbol{x}) = y | \boldsymbol{x}) \quad \quad (8) \end{aligned} sign(H(x))=sign(21lnP(f(x)=−1∣x)P(f(x)=1∣x))={1,−1,P(f(x)=1∣x)>P(f(x)=−1∣x)P(f(x)=1∣x)<P(f(x)=−1∣x)=y∈{−1,1}argmaxP(f(x)=y∣x)(8)
注:这里忽略了 P(f(x)=1∣x)=P(f(x)=−1∣x)P(f(\boldsymbol{x}) = 1 | \boldsymbol{x}) = P(f(\boldsymbol{x}) = -1 | \boldsymbol{x})P(f(x)=1∣x)=P(f(x)=−1∣x) 的情形。
这意味着 sign(H(x))\text{sign}(H(\boldsymbol{x}))sign(H(x)) 达到了贝叶斯最优错误率。换言之,若指数损失函数最小化,则分类错误率也将最小化;这说明指数损失函数是分类任务原本 0/1 损失函数的一致的 (consistent) 替代损失函数。由于这个替代函数有更好的数学性质,例如它是连续可微函数,因此我们用它替代 0/1 损失函数作为优化目标。
在 AdaBoost 算法中,第一个基分类器 h1h_1h1 是通过直接将基学习算法用于初始数据分布而得;此后迭代地生成 hth_tht 和 αt\alpha_tαt,当基分类器 hth_tht 基于分布 Dt\mathcal{D}tDt 产生后,该基分类器的权重 αt\alpha_tαt 应使得 αtht\alpha_t h_tαtht 最小化指数损失函数
ℓexp(αtht∣Dt)=Ex∼Dt[e−f(x)αtht(x)]=Ex∼Dt[e−αtI(f(x)=ht(x))+eαtI(f(x)≠ht(x))]=e−αtPx∼Dt(f(x)=ht(x))+eαtPx∼Dt(f(x)≠ht(x))=e−αt(1−ϵt)+eαtϵt(9) \begin{aligned} \ell{\exp}(\alpha_t h_t | \mathcal{D}t) &= \mathbb{E}{\boldsymbol{x} \sim \mathcal{D}t} [e^{-f(\boldsymbol{x}) \alpha_t h_t(\boldsymbol{x})}] \\ &= \mathbb{E}{\boldsymbol{x} \sim \mathcal{D}t} [e^{-\alpha_t} \mathbb{I}(f(\boldsymbol{x}) = h_t(\boldsymbol{x})) + e^{\alpha_t} \mathbb{I}(f(\boldsymbol{x}) \neq h_t(\boldsymbol{x}))] \\ &= e^{-\alpha_t} P{\boldsymbol{x} \sim \mathcal{D}t}(f(\boldsymbol{x}) = h_t(\boldsymbol{x})) + e^{\alpha_t} P{\boldsymbol{x} \sim \mathcal{D}_t}(f(\boldsymbol{x}) \neq h_t(\boldsymbol{x})) \\ &= e^{-\alpha_t} (1 - \epsilon_t) + e^{\alpha_t} \epsilon_t \quad \quad (9) \end{aligned} ℓexp(αtht∣Dt)=Ex∼Dt[e−f(x)αtht(x)]=Ex∼Dt[e−αtI(f(x)=ht(x))+eαtI(f(x)=ht(x))]=e−αtPx∼Dt(f(x)=ht(x))+eαtPx∼Dt(f(x)=ht(x))=e−αt(1−ϵt)+eαtϵt(9)
其中 ϵt=Px∼Dt(ht(x)≠f(x))\epsilon_t = P_{\boldsymbol{x} \sim \mathcal{D}t}(h_t(\boldsymbol{x}) \neq f(\boldsymbol{x}))ϵt=Px∼Dt(ht(x)=f(x))。考虑指数损失函数的导数
∂ℓexp(αtht∣Dt)∂αt=−e−αt(1−ϵt)+eαtϵt(10) \frac{\partial \ell{\exp}(\alpha_t h_t | \mathcal{D}_t)}{\partial \alpha_t} = -e^{-\alpha_t}(1 - \epsilon_t) + e^{\alpha_t} \epsilon_t \quad \quad (10) ∂αt∂ℓexp(αtht∣Dt)=−e−αt(1−ϵt)+eαtϵt(10)
令式(10)为零可解得
αt=12ln(1−ϵtϵt)(11) \alpha_t = \frac{1}{2} \ln \left( \frac{1 - \epsilon_t}{\epsilon_t} \right) \quad \quad (11) αt=21ln(ϵt1−ϵt)(11)
这恰是 AdaBoost 算法中分类器权重更新公式。
AdaBoost 算法在获得 Ht−1H_{t-1}Ht−1 之后样本分布将进行调整,使下一轮的基学习器 hth_tht 能纠正 Ht−1H_{t-1}Ht−1 的一些错误。理想的 hth_tht 能纠正 Ht−1H_{t-1}Ht−1 的全部错误,即最小化
ℓexp(Ht−1+ht∣D)=Ex∼D[e−f(x)(Ht−1(x)+ht(x))]=Ex∼D[e−f(x)Ht−1(x)e−f(x)ht(x)](12) \begin{aligned} \ell_{\exp}(H_{t-1} + h_t | \mathcal{D}) &= \mathbb{E}{\boldsymbol{x} \sim \mathcal{D}} [e^{-f(\boldsymbol{x})(H{t-1}(\boldsymbol{x}) + h_t(\boldsymbol{x}))}] \\ &= \mathbb{E}{\boldsymbol{x} \sim \mathcal{D}} [e^{-f(\boldsymbol{x})H{t-1}(\boldsymbol{x})} e^{-f(\boldsymbol{x})h_t(\boldsymbol{x})}] \quad \quad (12) \end{aligned} ℓexp(Ht−1+ht∣D)=Ex∼D[e−f(x)(Ht−1(x)+ht(x))]=Ex∼D[e−f(x)Ht−1(x)e−f(x)ht(x)](12)
注意到 f2(x)=ht2(x)=1f^2(\boldsymbol{x}) = h_t^2(\boldsymbol{x}) = 1f2(x)=ht2(x)=1,式(12)可使用 e−f(x)ht(x)e^{-f(\boldsymbol{x})h_t(\boldsymbol{x})}e−f(x)ht(x) 的泰勒展式近似为
ℓexp(Ht−1+ht∣D)≃Ex∼D[e−f(x)Ht−1(x)(1−f(x)ht(x)+f2(x)ht2(x)2)]=Ex∼D[e−f(x)Ht−1(x)(1−f(x)ht(x)+12)](13) \begin{aligned} \ell_{\exp}(H_{t-1} + h_t | \mathcal{D}) &\simeq \mathbb{E}{\boldsymbol{x} \sim \mathcal{D}} \left[ e^{-f(\boldsymbol{x})H{t-1}(\boldsymbol{x})} \left( 1 - f(\boldsymbol{x})h_t(\boldsymbol{x}) + \frac{f^2(\boldsymbol{x})h_t^2(\boldsymbol{x})}{2} \right) \right] \\ &= \mathbb{E}{\boldsymbol{x} \sim \mathcal{D}} \left[ e^{-f(\boldsymbol{x})H{t-1}(\boldsymbol{x})} \left( 1 - f(\boldsymbol{x})h_t(\boldsymbol{x}) + \frac{1}{2} \right) \right] \quad \quad (13) \end{aligned} ℓexp(Ht−1+ht∣D)≃Ex∼D[e−f(x)Ht−1(x)(1−f(x)ht(x)+2f2(x)ht2(x))]=Ex∼D[e−f(x)Ht−1(x)(1−f(x)ht(x)+21)](13)
于是,理想的基学习器
ht(x)=argminh Ex∼D[e−f(x)Ht−1(x)(1−f(x)h(x)+12)]=argmaxh Ex∼D[e−f(x)Ht−1(x)f(x)h(x)]=argmaxh Ex∼D[e−f(x)Ht−1(x)Ex∼D[e−f(x)Ht−1(x)]f(x)h(x)](14) \begin{aligned} h_t(\boldsymbol{x}) &= \underset{h}{\arg\min} \, \mathbb{E}{\boldsymbol{x} \sim \mathcal{D}} \left[ e^{-f(\boldsymbol{x})H{t-1}(\boldsymbol{x})} \left( 1 - f(\boldsymbol{x})h(\boldsymbol{x}) + \frac{1}{2} \right) \right] \\ &= \underset{h}{\arg\max} \, \mathbb{E}{\boldsymbol{x} \sim \mathcal{D}} \left[ e^{-f(\boldsymbol{x})H{t-1}(\boldsymbol{x})} f(\boldsymbol{x})h(\boldsymbol{x}) \right] \\ &= \underset{h}{\arg\max} \, \mathbb{E}{\boldsymbol{x} \sim \mathcal{D}} \left[ \frac{e^{-f(\boldsymbol{x})H{t-1}(\boldsymbol{x})}}{\mathbb{E}{\boldsymbol{x} \sim \mathcal{D}}[e^{-f(\boldsymbol{x})H{t-1}(\boldsymbol{x})}]} f(\boldsymbol{x})h(\boldsymbol{x}) \right] \quad \quad (14) \end{aligned} ht(x)=hargminEx∼D[e−f(x)Ht−1(x)(1−f(x)h(x)+21)]=hargmaxEx∼D[e−f(x)Ht−1(x)f(x)h(x)]=hargmaxEx∼D[Ex∼D[e−f(x)Ht−1(x)]e−f(x)Ht−1(x)f(x)h(x)](14)
注意到 Ex∼D[e−f(x)Ht−1(x)]\mathbb{E}{\boldsymbol{x} \sim \mathcal{D}}[e^{-f(\boldsymbol{x})H{t-1}(\boldsymbol{x})}]Ex∼D[e−f(x)Ht−1(x)] 是一个常数。令 Dt\mathcal{D}tDt 表示一个分布
Dt(x)=D(x)e−f(x)Ht−1(x)Ex∼D[e−f(x)Ht−1(x)](15) \mathcal{D}t(\boldsymbol{x}) = \frac{\mathcal{D}(\boldsymbol{x}) e^{-f(\boldsymbol{x})H{t-1}(\boldsymbol{x})}}{\mathbb{E}{\boldsymbol{x} \sim \mathcal{D}}[e^{-f(\boldsymbol{x})H_{t-1}(\boldsymbol{x})}]} \quad \quad (15) Dt(x)=Ex∼D[e−f(x)Ht−1(x)]D(x)e−f(x)Ht−1(x)(15)
则根据数学期望的定义,这等价于令
ht(x)=argmaxh Ex∼D[e−f(x)Ht−1(x)Ex∼D[e−f(x)Ht−1(x)]f(x)h(x)]=argmaxh Ex∼Dt[f(x)h(x)](16) \begin{aligned} h_t(\boldsymbol{x}) &= \underset{h}{\arg\max} \, \mathbb{E}{\boldsymbol{x} \sim \mathcal{D}} \left[ \frac{e^{-f(\boldsymbol{x})H{t-1}(\boldsymbol{x})}}{\mathbb{E}{\boldsymbol{x} \sim \mathcal{D}}[e^{-f(\boldsymbol{x})H{t-1}(\boldsymbol{x})}]} f(\boldsymbol{x})h(\boldsymbol{x}) \right] \\ &= \underset{h}{\arg\max} \, \mathbb{E}_{\boldsymbol{x} \sim \mathcal{D}_t} [f(\boldsymbol{x})h(\boldsymbol{x})] \quad \quad (16) \end{aligned} ht(x)=hargmaxEx∼D[Ex∼D[e−f(x)Ht−1(x)]e−f(x)Ht−1(x)f(x)h(x)]=hargmaxEx∼Dt[f(x)h(x)](16)
由 f(x),h(x)∈{−1,+1}f(\boldsymbol{x}), h(\boldsymbol{x}) \in \{-1, +1\}f(x),h(x)∈{−1,+1},有
f(x)h(x)=1−2I(f(x)≠h(x))(17) f(\boldsymbol{x})h(\boldsymbol{x}) = 1 - 2\mathbb{I}(f(\boldsymbol{x}) \neq h(\boldsymbol{x})) \quad \quad (17) f(x)h(x)=1−2I(f(x)=h(x))(17)
则理想的基学习器
ht(x)=argminh Ex∼Dt[I(f(x)≠h(x))](18) h_t(\boldsymbol{x}) = \underset{h}{\arg\min} \, \mathbb{E}_{\boldsymbol{x} \sim \mathcal{D}_t} [\mathbb{I}(f(\boldsymbol{x}) \neq h(\boldsymbol{x}))] \quad \quad (18) ht(x)=hargminEx∼Dt[I(f(x)=h(x))](18)
由此可见,理想的 hth_tht 将在分布 Dt\mathcal{D}tDt 下最小化分类误差。因此,弱分类器将基于分布 Dt\mathcal{D}tDt 来训练,且针对 Dt\mathcal{D}tDt 的分类误差应小于 0.5。这在一定程度上类似 "残差逼近" 的思想。考虑到 Dt\mathcal{D}tDt 和 Dt+1\mathcal{D}{t+1}Dt+1 的关系,有
Dt+1(x)=D(x)e−f(x)Ht(x)Ex∼D[e−f(x)Ht(x)]=D(x)e−f(x)Ht−1(x)e−f(x)αtht(x)Ex∼D[e−f(x)Ht(x)]=Dt(x)⋅e−f(x)αtht(x)Ex∼D[e−f(x)Ht−1(x)]Ex∼D[e−f(x)Ht(x)](19) \begin{aligned} \mathcal{D}{t+1}(\boldsymbol{x}) &= \frac{\mathcal{D}(\boldsymbol{x}) e^{-f(\boldsymbol{x})H_t(\boldsymbol{x})}}{\mathbb{E}{\boldsymbol{x} \sim \mathcal{D}}[e^{-f(\boldsymbol{x})H_t(\boldsymbol{x})}]} \\ &= \frac{\mathcal{D}(\boldsymbol{x}) e^{-f(\boldsymbol{x})H{t-1}(\boldsymbol{x})} e^{-f(\boldsymbol{x})\alpha_t h_t(\boldsymbol{x})}}{\mathbb{E}{\boldsymbol{x} \sim \mathcal{D}}[e^{-f(\boldsymbol{x})H_t(\boldsymbol{x})}]} \\ &= \mathcal{D}t(\boldsymbol{x}) \cdot e^{-f(\boldsymbol{x})\alpha_t h_t(\boldsymbol{x})} \frac{\mathbb{E}{\boldsymbol{x} \sim \mathcal{D}}[e^{-f(\boldsymbol{x})H{t-1}(\boldsymbol{x})}]}{\mathbb{E}_{\boldsymbol{x} \sim \mathcal{D}}[e^{-f(\boldsymbol{x})H_t(\boldsymbol{x})}]} \quad \quad (19) \end{aligned} Dt+1(x)=Ex∼D[e−f(x)Ht(x)]D(x)e−f(x)Ht(x)=Ex∼D[e−f(x)Ht(x)]D(x)e−f(x)Ht−1(x)e−f(x)αtht(x)=Dt(x)⋅e−f(x)αtht(x)Ex∼D[e−f(x)Ht(x)]Ex∼D[e−f(x)Ht−1(x)](19)
这恰是算法中的样本分布更新公式。
于是,由式(11)和(19)可见,我们从基于加性模型迭代式优化指数损失函数的角度推导出了 AdaBoost 算法。
Boosting 算法要求基学习器能对特定的数据分布进行学习,这可通过 "重赋权法" (re-weighting)实施,即在训练过程的每一轮中,根据样本分布为每个训练样本重新赋予一个权重。对无法接受带权样本的基学习算法,则可通过 "重采样法" (re-sampling)来处理,即在每一轮学习中,根据样本分布对训练集重新进行采样,再用重采样而得的样本集对基学习器进行训练。一般而言,这两做法没有显著的优劣差别。需注意的是,Boosting 算法在训练的每一轮都要检查当前生成的基学习器是否满足基本条件(例如算法中检查当前基分类器误差是否大于 0.5,或比随机猜测好),一旦条件不满足,则当前基学习器即被抛弃,且学习过程停止。在此种情形下,初始设置的学习轮数 TTT 也许还远未达到,可能导致最终集成中只包含很少的基学习器而性能不佳。若采用 "重采样法",则可获得 "重启动" 机会以避免训练过程过早停止 [Kohavi and Wolpert, 1996],即在抛弃不满足条件的当前基学习器之后,可根据当前分布重新对训练样本进行采样,再基于新的采样结果重新训练出基学习器,从而使得学习过程可以持续到预设的 TTT 轮完成。
从偏差-方差分解的角度看,Boosting 主要关注降低偏差,因此 Boosting 能基于泛化性能相当弱的学习器构建出很强的集成。
python
> **【代码实践 2】 AdaBoost 分类与决策边界**
>
> 我们使用 sklearn 的 `AdaBoostClassifier` 来演示如何通过增加弱学习器数量来提升模型表现:
>
> ```python
import matplotlib.pyplot as plt
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import make_gaussian_quantiles
# 1. 生成非线性可分数据
X, y = make_gaussian_quantiles(n_samples=1000, n_features=2, n_classes=2, random_state=1)
# 2. 训练 AdaBoost 模型 (基学习器为深度为1的决策树桩)
bdt = AdaBoostClassifier(
DecisionTreeClassifier(max_depth=1),
algorithm="SAMME",
n_estimators=200
)
bdt.fit(X, y)
# 3. 绘制决策边界 (简化版可视化逻辑)
print(f"训练集准确率: {bdt.score(X, y):.4f}")
print(f"基学习器权重前5个: {bdt.estimator_weights_[:5]}")
print(f"基学习器误差前5个: {bdt.estimator_errors_[:5]}")
3. Bagging与随机森林
欲得到泛化性能强的集成,集成中的个体学习器应尽可能相互独立;虽然 "独立" 在现实任务中无法做到,但可以设法使基学习器尽可能具有较大的差异。给定一个训练数据集,一种可能的做法是对训练样本进行采样,产生出若干个不同的子集,再从每个数据子集中训练出一个基学习器。这样,由于训练数据不同,我们获得的基学习器可望具有比较大的差异。然而,为获得好的集成,我们同时还希望个体学习器不能太差。如果采样出的每个子集都完全不同,则每个基学习器只用到了一小部分训练数据,甚至不足以进行有效学习,这显然无法确保产生出比较好的基学习器。为解决这个问题,我们可考虑使用相互有交叠的采样子集。
3.1 Bagging
Bagging [Breiman, 1996a] 是并行式集成学习方法最著名的代表。从名字即可看出,它直接基于我们介绍过的自助采样法 (bootstrap sampling)。给定包含 mmm 个样本的数据集,我们先随机取出一个样本放入采样集中,再把该样本放回初始数据集,使得下次采样时该样本仍有可能被选中,这样,经过 mmm 次随机采样操作,我们得到含 mmm 个样本的采样集,初始训练集中有的样本在采样集里多次出现,有的则从未出现。由式(2.1)可知,初始训练集中约有 63.2% 的样本出现在采样集中。
照这样,我们可采样出 TTT 个含 mmm 个训练样本的采样集,然后基于每个采样集训练出一个基学习器,再将这些基学习器进行结合。这就是 Bagging 的基本流程。在对预测输出进行结合时,Bagging 通常对分类任务使用简单投票法,对回归任务使用简单平均法。若分类预测时出现两个类收到同样票数的情形,则最简单的做法是随机选择一个,也可进一步考察学习器投票的置信度来确定最终胜者。Bagging 的算法描述如下:
输入: 训练集 D={(x1,y1),(x2,y2),...,(xm,ym)}D = \{(\boldsymbol{x}_1, y_1), (\boldsymbol{x}_2, y_2), \dots, (\boldsymbol{x}_m, y_m)\}D={(x1,y1),(x2,y2),...,(xm,ym)};
基学习算法 L\mathfrak{L}L;
训练轮数 TTT.
过程:
1: for t=1,2,...,Tt = 1, 2, \dots, Tt=1,2,...,T do
2: ht=L(D,Dbs)h_t = \mathfrak{L}(D, D_{bs})ht=L(D,Dbs); % DbsD_{bs}Dbs 是自助采样产生的样本分布
3: end for
输出: H(x)=argmaxy∈Y∑t=1TI(ht(x)=y)H(\boldsymbol{x}) = \underset{y \in \mathcal{Y}}{\arg\max} \sum_{t=1}^{T} \mathbb{I}(h_t(\boldsymbol{x}) = y)H(x)=y∈Yargmax∑t=1TI(ht(x)=y)
假定基学习器的计算复杂度为 O(m)O(m)O(m),则 Bagging 的复杂度大致为 T(O(m)+O(s))T(O(m) + O(s))T(O(m)+O(s)),考虑到采样与投票/平均过程的复杂度 O(s)O(s)O(s) 很小,而 TTT 通常是一个不太大的常数,因此,训练一个 Bagging 集成与直接使用基学习算法训练一个学习器的复杂度同阶,这说明 Bagging 是一个很高效的集成学习算法。另外,与标准 AdaBoost 只适用于二分类任务不同,Bagging 能不经修改地用于多分类、回归等任务。
注:为处理多分类或回归任务,AdaBoost 需进行修改;目前已有适用的变体算法 [Zhou, 2012]。
值得一提的是,自助采样过程还给 Bagging 带来了另一个优点:由于每个基学习器只使用了初始训练集中约 63.2% 的样本,剩下约 36.8% 的样本可用作验证集来对泛化性能进行 "包外估计" (out-of-bag estimate) [Breiman, 1996a; Wolpert and Macready, 1999]。为此需记录每个基学习器所使用的训练样本。不妨令 DtD_tDt 表示 hth_tht 实际使用的训练样本集,令 Hoob(x)H^{oob}(\boldsymbol{x})Hoob(x) 表示对样本 x\boldsymbol{x}x 的包外预测,即仅考虑那些未使用 x\boldsymbol{x}x 训练的基学习器在 x\boldsymbol{x}x 上的预测,有
Hoob(x)=argmaxy∈Y∑t=1TI(ht(x)=y)⋅I(x∉Dt)(20) H^{oob}(\boldsymbol{x}) = \underset{y \in \mathcal{Y}}{\arg\max} \sum_{t=1}^{T} \mathbb{I}(h_t(\boldsymbol{x}) = y) \cdot \mathbb{I}(\boldsymbol{x} \notin D_t) \quad \quad (20) Hoob(x)=y∈Yargmaxt=1∑TI(ht(x)=y)⋅I(x∈/Dt)(20)
则 Bagging 泛化误差的包外估计为
ϵoob=1∣D∣∑(x,y)∈DI(Hoob(x)≠y)(21) \epsilon^{oob} = \frac{1}{|D|} \sum_{(\boldsymbol{x}, y) \in D} \mathbb{I}(H^{oob}(\boldsymbol{x}) \neq y) \quad \quad (21) ϵoob=∣D∣1(x,y)∈D∑I(Hoob(x)=y)(21)
事实上,包外样本还有许多其他用途。例如当基学习器是决策树时,可使用包外样本来辅助剪枝,或用于估计决策树中各结点的后验概率以辅助对零训练样本结点的处理;当基学习器是神经网络时,可使用包外样本来辅助早期停止以减小过拟合风险。
从偏差-方差分解的角度看,Bagging 主要关注降低方差,因此它在不剪枝决策树、神经网络等易受样本扰动的学习器上效用更为明显。
3.2 随机森林
随机森林 (Random Forest, 简称 RF) [Breiman, 2001a] 是 Bagging 的一个扩展变体。RF 在以决策树为基学习器构建 Bagging 集成的基础上,进一步在决策树的训练过程中引入了随机属性选择。具体来说,传统决策树在选择划分属性时是在当前结点的属性集合 (假定有 ddd 个属性) 中选择一个最优属性;而在 RF 中,对基决策树的每个结点,先从该结点的属性集合中随机选择一个包含 kkk 个属性的子集,然后再从这个子集中选择一个最优属性用于划分。这里的参数 kkk 控制了随机性的引入程度:若令 k=dk=dk=d,则基决策树的构建与传统决策树相同;若令 k=1k=1k=1,则是随机选择一个属性用于划分;一般情况下,推荐值 k=log2dk = \log_2 dk=log2d [Breiman, 2001a]。
随机森林简单、容易实现、计算开销小,令人惊奇的是,它在很多现实任务中展现出强大的性能,被誉为 "代表集成学习技术水平的方法"。可以看出,随机森林对 Bagging 只做了小改动,但是与 Bagging 中基学习器的 "多样性" 仅通过样本扰动 (通过对初始训练集采样) 而来不同,随机森林中基学习器的多样性不仅来自样本扰动,还来自属性扰动,这就使得最终集成的泛化性能可通过个体学习器之间差异度的增加而进一步提升。
随机森林的收敛性与 Bagging 相似。随机森林的起始性能往往相对较差,特别是在集成中只包含一个基学习器时。这很容易理解,因为通过引入属性扰动,随机森林中个体学习器的性能往往有所降低。然而,随着个体学习器数目的增加,随机森林通常会收敛到更低的泛化误差。值得一提的是,随机森林的训练效率常优于 Bagging,因为在个体决策树的构建过程中,Bagging 使用的是 "确定型" 决策树,在选择划分属性时要对结点的所有属性进行考察,而随机森林使用的 "随机型" 决策树则只需考察一个属性子集。
python
> **【代码实践 3】 决策树 vs Bagging vs 随机森林**
>
> 下面代码展示了随机森林如何通过引入样本扰动和属性扰动来获得比单一决策树更稳健的结果:
>
> ```python
from sklearn.ensemble import BaggingClassifier, RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_wine
# 1. 加载葡萄酒数据集
data = load_wine()
X, y = data.data, data.target
# 2. 定义模型
clf_dt = DecisionTreeClassifier(random_state=42)
clf_bag = BaggingClassifier(estimator=DecisionTreeClassifier(), n_estimators=50, random_state=42)
clf_rf = RandomForestClassifier(n_estimators=50, random_state=42)
# 3. 使用交叉验证评估性能
score_dt = cross_val_score(clf_dt, X, y, cv=5).mean()
score_bag = cross_val_score(clf_bag, X, y, cv=5).mean()
score_rf = cross_val_score(clf_rf, X, y, cv=5).mean()
print(f"单一决策树准确率: {score_dt:.4f}")
print(f"Bagging 准确率: {score_bag:.4f}")
print(f"随机森林准确率: {score_rf:.4f}")
4. 结合策略
学习器结合可能会从三个方面带来好处 [Dietterich, 2000]:首先,从统计的方面来看,由于学习任务的假设空间往往很大,可能有多个假设在训练集上达到同等性能,此时若使用单学习器可能因误选而导致泛化性能不佳,结合多个学习器则会减小这一风险;第二,从计算的方面来看,学习算法往往会陷入局部极小,有的局部极小点所对应的泛化性能可能很糟糕,而通过多次运行之后进行结合,可降低陷入糟糕局部极小点的风险;第三,从表示的方面来看,某些学习任务的真实假设可能不在当前学习算法所考虑的假设空间中,此时若使用单学习器则肯定无效,而通过结合多个学习器,由于相应的假设空间有所扩大,有可能学得更好的近似。
假定集成包含 TTT 个基学习器 {h1,h2,...,hT}\{h_1, h_2, \dots, h_T\}{h1,h2,...,hT},其中 hih_ihi 在示例 x\boldsymbol{x}x 上的输出为 hi(x)h_i(\boldsymbol{x})hi(x)。本节介绍几种对 hih_ihi 进行结合的常见策略。
4.1 平均法
对数值型输出 hi(x)∈Rh_i(\boldsymbol{x}) \in \mathbb{R}hi(x)∈R,最常见的结合策略是使用平均法 (averaging)。
-
简单平均法 (simple averaging)
H(x)=1T∑i=1Thi(x)(22) H(\boldsymbol{x}) = \frac{1}{T} \sum_{i=1}^{T} h_i(\boldsymbol{x}) \quad \quad (22) H(x)=T1i=1∑Thi(x)(22) -
加权平均法 (weighted averaging)
H(x)=∑i=1Twihi(x)(23) H(\boldsymbol{x}) = \sum_{i=1}^{T} w_i h_i(\boldsymbol{x}) \quad \quad (23) H(x)=i=1∑Twihi(x)(23)其中 wiw_iwi 是个体学习器 hih_ihi 的权重,通常要求 wi≥0,∑i=1Twi=1w_i \ge 0, \sum_{i=1}^{T} w_i = 1wi≥0,∑i=1Twi=1。
显然,简单平均法是加权平均法令 wi=1/Tw_i = 1/Twi=1/T 的特例。加权平均法在二十世纪五十年代已被广泛使用 [Markowitz, 1952],[Perrone and Cooper, 1993] 正式将其用于集成学习。它在集成学习中具有特别的意义,集成学习中的各种结合方法都可视为其特例或变体。事实上,加权平均法可认为是集成学习研究的基本出发点,对给定的基学习器,不同的集成学习方法可视为通过不同方式来确定加权平均法中的基学习器权重。
加权平均法的权重一般是从训练数据中学习而得,现实任务中的训练样本通常不充分或存在噪声,这将使得学出的权重不完全可靠。尤其是对规模比较大的集成来说,要学习的权重比较多,较容易导致过拟合。因此,实验和应用均显示出,加权平均法未必一定优于简单平均法 [Xu et al., 1992; Ho et al., 1994; Kittler et al., 1998]。一般而言,在个体学习器性能相差较大时宜使用加权平均法,而在个体学习器性能相近时宜使用简单平均法。
注:Breiman [1996b] 在研究 Stacking 回归时发现,必须使用非负权重才能确保集成性能优于最佳个体学习器,因此在集成学习中一般对学习器的权重施以非负约束。
注:例如估计出个体学习器的误差,然后令权重大小与误差大小成反比。
4.2 投票法
对分类任务来说,学习器 hih_ihi 将从类别标记集合 {c1,c2,...,cN}\{c_1, c_2, \dots, c_N\}{c1,c2,...,cN} 中预测出一个标记,最常见的结合策略是使用投票法 (voting)。为便于讨论,我们将 hih_ihi 在样本 x\boldsymbol{x}x 上的预测输出表示为一个 NNN 维向量 (hi1(x);hi2(x);... ;hiN(x))(h_i^1(\boldsymbol{x}); h_i^2(\boldsymbol{x}); \dots; h_i^N(\boldsymbol{x}))(hi1(x);hi2(x);...;hiN(x)),其中 hij(x)h_i^j(\boldsymbol{x})hij(x) 是 hih_ihi 在类别标记 cjc_jcj 上的输出。
-
绝对多数投票法 (majority voting)
H(x)={cj,if ∑i=1Thij(x)>0.5∑k=1N∑i=1Thik(x);reject,otherwise.(24) H(\boldsymbol{x}) = \begin{cases} c_j, & \text{if } \sum_{i=1}^{T} h_i^j(\boldsymbol{x}) > 0.5 \sum_{k=1}^{N} \sum_{i=1}^{T} h_i^k(\boldsymbol{x}); \\ \text{reject}, & \text{otherwise}. \end{cases} \quad \quad (24) H(x)={cj,reject,if ∑i=1Thij(x)>0.5∑k=1N∑i=1Thik(x);otherwise.(24)即若某标记得票过半数,则预测为该标记;否则拒绝预测。
-
相对多数投票法 (plurality voting)
H(x)=cargmaxj∑i=1Thij(x)(25) H(\boldsymbol{x}) = c_{\underset{j}{\arg\max} \sum_{i=1}^{T} h_i^j(\boldsymbol{x}) } \quad \quad (25) H(x)=cjargmax∑i=1Thij(x)(25)即预测为得票最多的标记,若同时有多个标记获最高票,则从中随机选取一个。
-
加权投票法 (weighted voting)
H(x)=cargmaxj∑i=1Twihij(x)(26) H(\boldsymbol{x}) = c_{\underset{j}{\arg\max} \sum_{i=1}^{T} w_i h_i^j(\boldsymbol{x}) } \quad \quad (26) H(x)=cjargmax∑i=1Twihij(x)(26)与加权平均法类似,wiw_iwi 是 hih_ihi 的权重,通常 wi≥0,∑i=1Twi=1w_i \ge 0, \sum_{i=1}^{T} w_i = 1wi≥0,∑i=1Twi=1。
标准的绝对多数投票法提供了 "拒绝预测" 选项,这在可靠性要求较高的学习任务中是一个很好的机制。若学习任务要求必须提供预测结果,则绝对多数投票法将退化为相对多数投票法。因此,在不允许拒绝预测的任务中,绝对多数、相对多数投票法统称为 "多数投票法"。
注:"多数投票法" 的英文术语使用不太一致:有文献称为 majority voting,也有直接称为 voting。
式(24)~(26)没有限制个体学习器输出值的类型。在现实任务中,不同类型个体学习器可能产生不同类型的 hij(x)h_i^j(\boldsymbol{x})hij(x) 值,常见的有:
- 类标记:hij(x)∈{0,1}h_i^j(\boldsymbol{x}) \in \{0, 1\}hij(x)∈{0,1},若 hih_ihi 将样本 x\boldsymbol{x}x 预测为类别 cjc_jcj 则取值为 1,否则为 0。使用类标记的投票亦称 "硬投票" (hard voting)。
- 类概率:hij(x)∈[0,1]h_i^j(\boldsymbol{x}) \in [0, 1]hij(x)∈[0,1],相当于对后验概率 P(cj∣x)P(c_j | \boldsymbol{x})P(cj∣x) 的一个估计。使用类概率的投票亦称 "软投票" (soft voting)。
不同类型的 hij(x)h_i^j(\boldsymbol{x})hij(x) 值不能混用。对一些能在预测出类别标记的同时产生分类置信度的学习器,其分类置信度可转化为类概率使用。若此类值未进行规范化,例如支持向量机的分类间隔值,则必须使用一些技术如 Platt 缩放 (Platt scaling) [Platt, 2000]、等分回归 (isotonic regression) [Zadrozny and Elkan, 2001] 等进行 "校准" (calibration) 后才能作为类概率使用。有趣的是,虽然分类器估计出的类概率值一般都不太准确,但基于类概率进行结合却往往比直接基于类标记进行结合性能更好。需注意的是,若基学习器的类型不同,则其类概率值不能直接进行比较;在此种情形下,通常可将类概率输出转化为类标记输出 (例如将类概率输出最大的 hij(x)h_i^j(\boldsymbol{x})hij(x) 设为 1,其他设为 0) 然后再投票。
注:例如异质集成中不同类型的个体学习器。
4.3 学习法
当训练数据很多时,一种更为强大的结合策略是使用 "学习法",即通过另一个学习器来进行结合。Stacking [Wolpert, 1992; Breiman, 1996b] 是学习法的典型代表。这里我们把个体学习器称为初级学习器,用于结合的学习器称为次级学习器或元学习器 (meta-learner)。
注:Stacking 本身是一种著名的集成学习方法,且有不少集成学习算法可视为其变体或特例。它也可看作一种特殊的集成策略,因此本书在此介绍。
注:初级学习器也可就是同质的。
Stacking 先从初始数据集训练出初级学习器,然后 "生成" 一个新数据集用于训练次级学习器。在这个新数据集中,初级学习器的输出被当作样例输入特征,而初始样本的标记仍被当作样例标记。Stacking 的算法描述如下:
输入: 训练集 D={(x1,y1),(x2,y2),...,(xm,ym)}D = \{(\boldsymbol{x}_1, y_1), (\boldsymbol{x}_2, y_2), \dots, (\boldsymbol{x}_m, y_m)\}D={(x1,y1),(x2,y2),...,(xm,ym)};
初级学习算法 L1,L2,...,LT\mathfrak{L}_1, \mathfrak{L}_2, \dots, \mathfrak{L}_TL1,L2,...,LT;
次级学习算法 L\mathfrak{L}L.
过程:
1: for t=1,2,...,Tt = 1, 2, \dots, Tt=1,2,...,T do
2: ht=Lt(D)h_t = \mathfrak{L}_t(D)ht=Lt(D);
3: end for
4: D′=∅D' = \emptysetD′=∅;
5: for i=1,2,...,mi = 1, 2, \dots, mi=1,2,...,m do
6: for t=1,2,...,Tt = 1, 2, \dots, Tt=1,2,...,T do
7: zit=ht(xi)z_{it} = h_t(\boldsymbol{x}_i)zit=ht(xi);
8: end for
9: D′=D′∪{((zi1,zi2,...,ziT),yi)}D' = D' \cup \{((z_{i1}, z_{i2}, \dots, z_{iT}), y_i)\}D′=D′∪{((zi1,zi2,...,ziT),yi)};
10: end for
11: h′=L(D′)h' = \mathfrak{L}(D')h′=L(D′);
输出: H(x)=h′(h1(x),h2(x),...,hT(x))H(\boldsymbol{x}) = h'(h_1(\boldsymbol{x}), h_2(\boldsymbol{x}), \dots, h_T(\boldsymbol{x}))H(x)=h′(h1(x),h2(x),...,hT(x))
在训练阶段,次级训练集是利用初级学习器产生的,若直接用初级学习器的训练集来产生次级训练集,则过拟合风险会比较大;因此,一般是通过使用交叉验证或留一法这样的方式,用训练初级学习器未使用的样本来产生次级学习器的训练样本。以 kkk 折交叉验证为例,初始训练集 DDD 被随机划分为 kkk 个大小相似的集合 D1,D2,...,DkD_1, D_2, \dots, D_kD1,D2,...,Dk。令 DjD_jDj 和 Dˉj=D∖Dj\bar{D}_j = D \setminus D_jDˉj=D∖Dj 分别表示第 jjj 折的测试集和训练集。给定 TTT 个初级学习算法,初级学习器 ht(j)h_t^{(j)}ht(j) 通过在 Dˉj\bar{D}_jDˉj 上使用第 ttt 个学习算法而得。对 DjD_jDj 中每个样本 xi\boldsymbol{x}ixi,令 zit=ht(j)(xi)z{it} = h_t^{(j)}(\boldsymbol{x}i)zit=ht(j)(xi),则由 xi\boldsymbol{x}ixi 所产生的次级训练样例的示例部分为 zi=(zi1;zi2;... ;ziT)\boldsymbol{z}i = (z{i1}; z{i2}; \dots; z{iT})zi=(zi1;zi2;...;ziT),标记部分为 yiy_iyi。于是,在整个交叉验证过程结束后,从这 TTT 个初级学习器产生的次级训练集是 D′={(zi,yi)}i=1mD' = \{(\boldsymbol{z}i, y_i)\}{i=1}^{m}D′={(zi,yi)}i=1m,然后 D′D'D′ 将用于训练次级学习器。
次级学习器的输入属性表示和次级学习算法对 Stacking 集成的泛化性能有很大影响。有研究表明,将初级学习器的输出类概率作为次级学习器的输入属性,用多响应线性回归 (Multi-response Linear Regression, 简称 MLR) 作为次级学习算法效果较好 [Ting and Witten, 1999],在 MLR 中使用不同的属性集更佳 [Seewald, 2002]。
注:MLR 是基于线性回归的分类器,它对每个类分别进行线性回归,属于该类的训练样本所对应的输出被置为 1,其他类置为 0;测试示例将被分给输出值最大的类。
注:WEKA 中的 StackingC 算法就是这样实现的。
贝叶斯模型平均 (Bayes Model Averaging, 简称 BMA) 基于后验概率来为不同模型赋予权重,可视为加权平均法的一种特殊实现 [Clarke, 2003]。对 Stacking 和 BMA 进行了比较。理论上来说,若数据生成模型恰在当前考虑的模型中,且数据噪声很少,则 BMA 不差于 Stacking;然而,在现实应用中无法确保数据生成模型一定在当前考虑的模型中,甚至可能难以用当前考虑的模型来进行近似,因此,Stacking 通常优于 BMA,因为其鲁棒性比 BMA 更好,而且 BMA 对模型近似误差非常敏感。
python
> **【代码实践 4】 Stacking 集成实现**
>
> 使用 sklearn 的 `StackingClassifier` 构建一个两层集成模型。第一层包含KNN、随机森林和SVM,第二层(元学习器)使用逻辑回归:
>
> ```python
from sklearn.ensemble import StackingClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression
# 1. 定义基学习器列表
estimators = [
('rf', RandomForestClassifier(n_estimators=10, random_state=42)),
('svr', SVC(random_state=42)),
('knn', KNeighborsClassifier(n_neighbors=5))
]
# 2. 构建 Stacking 分类器
# final_estimator 是次级学习器,默认使用 LogisticRegression
clf_stack = StackingClassifier(estimators=estimators, final_estimator=LogisticRegression())
# 3. 训练与评估
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) # 使用上一节的数据
clf_stack.fit(X_train, y_train)
print(f"Stacking 集成准确率: {clf_stack.score(X_test, y_test):.4f}")
5. 多样性
5.1 误差-分歧分解
8.1 节提到,欲构建泛化能力强的集成,个体学习器应 "好而不同"。现在我们来做一个简单的理论分析。
假定我们用个体学习器 h1,h2,...,hTh_1, h_2, \dots, h_Th1,h2,...,hT 通过加权平均法(23)结合产生的集成来完成回归学习任务 f:Rd↦Rf: \mathbb{R}^d \mapsto \mathbb{R}f:Rd↦R。对示例 x\boldsymbol{x}x,定义学习器 hih_ihi 的 "分歧" (ambiguity) 为
A(hi∣x)=(hi(x)−H(x))2(27) A(h_i | \boldsymbol{x}) = (h_i(\boldsymbol{x}) - H(\boldsymbol{x}))^2 \quad \quad (27) A(hi∣x)=(hi(x)−H(x))2(27)
则集成的 "分歧" 是
A‾(h∣x)=∑i=1TwiA(hi∣x)=∑i=1Twi(hi(x)−H(x))2(28) \begin{aligned} \overline{A}(h | \boldsymbol{x}) &= \sum_{i=1}^{T} w_i A(h_i | \boldsymbol{x}) \\ &= \sum_{i=1}^{T} w_i (h_i(\boldsymbol{x}) - H(\boldsymbol{x}))^2 \quad \quad (28) \end{aligned} A(h∣x)=i=1∑TwiA(hi∣x)=i=1∑Twi(hi(x)−H(x))2(28)
显然,这里的 "分歧" 项表征了个体学习器在样本 x\boldsymbol{x}x 上的不一致性,即在一定程度上反映了个体学习器的多样性。个体学习器 hih_ihi 和集成 HHH 的平方误差分别为
E(hi∣x)=(f(x)−hi(x))2(29) E(h_i | \boldsymbol{x}) = (f(\boldsymbol{x}) - h_i(\boldsymbol{x}))^2 \quad \quad (29) E(hi∣x)=(f(x)−hi(x))2(29)
E(H∣x)=(f(x)−H(x))2(30) E(H | \boldsymbol{x}) = (f(\boldsymbol{x}) - H(\boldsymbol{x}))^2 \quad \quad (30) E(H∣x)=(f(x)−H(x))2(30)
令 E‾(h∣x)=∑i=1Twi⋅E(hi∣x)\overline{E}(h | \boldsymbol{x}) = \sum_{i=1}^{T} w_i \cdot E(h_i | \boldsymbol{x})E(h∣x)=∑i=1Twi⋅E(hi∣x) 表示个体学习器误差的加权均值,有
A‾(h∣x)=∑i=1TwiE(hi∣x)−E(H∣x)=E‾(h∣x)−E(H∣x)(31) \begin{aligned} \overline{A}(h | \boldsymbol{x}) &= \sum_{i=1}^{T} w_i E(h_i | \boldsymbol{x}) - E(H | \boldsymbol{x}) \\ &= \overline{E}(h | \boldsymbol{x}) - E(H | \boldsymbol{x}) \quad \quad (31) \end{aligned} A(h∣x)=i=1∑TwiE(hi∣x)−E(H∣x)=E(h∣x)−E(H∣x)(31)
式(31)对所有样本 x\boldsymbol{x}x 均成立,令 p(x)p(\boldsymbol{x})p(x) 表示样本的概率密度,则在全样本上有
∑i=1Twi∫A(hi∣x)p(x)dx=∑i=1Twi∫E(hi∣x)p(x)dx−∫E(H∣x)p(x)dx(32) \sum_{i=1}^{T} w_i \int A(h_i | \boldsymbol{x})p(\boldsymbol{x}) d\boldsymbol{x} = \sum_{i=1}^{T} w_i \int E(h_i | \boldsymbol{x})p(\boldsymbol{x}) d\boldsymbol{x} - \int E(H | \boldsymbol{x})p(\boldsymbol{x}) d\boldsymbol{x} \quad \quad (32) i=1∑Twi∫A(hi∣x)p(x)dx=i=1∑Twi∫E(hi∣x)p(x)dx−∫E(H∣x)p(x)dx(32)
类似的,个体学习器 hih_ihi 在全样本上的泛化误差和分歧项分别为
Ei=∫E(hi∣x)p(x)dx(33) E_i = \int E(h_i | \boldsymbol{x})p(\boldsymbol{x}) d\boldsymbol{x} \quad \quad (33) Ei=∫E(hi∣x)p(x)dx(33)
Ai=∫A(hi∣x)p(x)dx(34) A_i = \int A(h_i | \boldsymbol{x})p(\boldsymbol{x}) d\boldsymbol{x} \quad \quad (34) Ai=∫A(hi∣x)p(x)dx(34)
集成的泛化误差为
E=∫E(H∣x)p(x)dx(35) E = \int E(H | \boldsymbol{x})p(\boldsymbol{x}) d\boldsymbol{x} \quad \quad (35) E=∫E(H∣x)p(x)dx(35)
将式(33)~(35)代入式(32),再令 E‾=∑i=1TwiEi\overline{E} = \sum_{i=1}^{T} w_i E_iE=∑i=1TwiEi 表示个体学习器泛化误差的加权均值,A‾=∑i=1TwiAi\overline{A} = \sum_{i=1}^{T} w_i A_iA=∑i=1TwiAi 表示个体学习器的加权分歧值,有
E=E‾−A‾(36) E = \overline{E} - \overline{A} \quad \quad (36) E=E−A(36)
注:这里我们用 EiE_iEi 和 AiA_iAi 简表示 E(hi)E(h_i)E(hi) 和 A(hi)A(h_i)A(hi)。
注:这里我们用 EEE 简化表示 E(H)E(H)E(H)。
式(36)这个漂亮的式子明确提示出:个体学习器准确性越高、多样性越大,则集成越好。上面这个分析首先由 [Krogh and Vedelsby, 1995] 给出,称为 "误差-分歧分解" (error-ambiguity decomposition)。
至此,读者可能很高兴:我们直接把 E‾−A‾\overline{E} - \overline{A}E−A 作为优化目标来求解,不就能得到最优的集成了?遗憾的是,在现实任务中很难直接对 E‾−A‾\overline{E} - \overline{A}E−A 进行优化,不仅由于它们是定义在整个样本空间上,还由于 A‾\overline{A}A 不是一个可直接操作的多样性度量,它仅在集成构造好之后才能进行估计。此外需注意的是,上面的推导只适用于回归学习,难以直接推广到分类学习任务上去。
5.2 多样性度量
顾名思义,多样性度量 (diversity measure) 是用于度量集成中个体分类器的多样性,即估算个体学习器的多样化程度。典型做法是考虑个体分类器的两两相似/不相似性。
注:亦称 "差异性度量"。
给定数据集 D={(x1,y1),(x2,y2),...,(xm,ym)}D = \{(\boldsymbol{x}_1, y_1), (\boldsymbol{x}_2, y_2), \dots, (\boldsymbol{x}_m, y_m)\}D={(x1,y1),(x2,y2),...,(xm,ym)},对二分类任务, yi∈{−1,+1}y_i \in \{-1, +1\}yi∈{−1,+1},分类器 hih_ihi 与 hjh_jhj 的预测结果列联表 (contingency table) 为
| hi=+1h_i = +1hi=+1 | hi=−1h_i = -1hi=−1 | |
|---|---|---|
| hj=+1h_j = +1hj=+1 | aaa | ccc |
| hj=−1h_j = -1hj=−1 | bbb | ddd |
其中,aaa 表示 hih_ihi 与 hjh_jhj 均预测为正类的样本数目;b,c,db, c, db,c,d 含义由此类推;a+b+c+d=ma+b+c+d=ma+b+c+d=m。基于这个列联表,下面给出一些常见的多样性度量。
-
不合度量 (disagreement measure)
disij=b+cm(37) dis_{ij} = \frac{b+c}{m} \quad \quad (37) disij=mb+c(37)
disijdis_{ij}disij 的值域为 [0,1][0, 1][0,1]。值越大则多样性越大。 -
相关系数 (correlation coefficient)
ρij=ad−bc(a+b)(a+c)(c+d)(b+d)(38) \rho_{ij} = \frac{ad-bc}{\sqrt{(a+b)(a+c)(c+d)(b+d)}} \quad \quad (38) ρij=(a+b)(a+c)(c+d)(b+d) ad−bc(38)
ρij\rho_{ij}ρij 的值域为 [−1,1][-1, 1][−1,1]。若 hih_ihi 与 hjh_jhj 无关,则值为 0;若 hih_ihi 与 hjh_jhj 正相关则值为正,否则为负。 -
QQQ-统计量 (QQQ-statistic)
Qij=ad−bcad+bc(39) Q_{ij} = \frac{ad-bc}{ad+bc} \quad \quad (39) Qij=ad+bcad−bc(39)
QijQ_{ij}Qij 与相关系数 ρij\rho_{ij}ρij 的符号相同,且 ∣Qij∣≤∣ρij∣|Q_{ij}| \le |\rho_{ij}|∣Qij∣≤∣ρij∣。 -
κ\kappaκ-统计量 (κ\kappaκ-statistic)
κ=p1−p21−p2(40) \kappa = \frac{p_1 - p_2}{1 - p_2} \quad \quad (40) κ=1−p2p1−p2(40)其中,p1p_1p1 是两个分类器取得一致的概率;p2p_2p2 是两个分类器偶然达成一致的概率,它们可由数据集 DDD 估算:
p1=a+dm(41) p_1 = \frac{a+d}{m} \quad \quad (41) p1=ma+d(41)
p2=(a+b)(a+c)+(c+d)(b+d)m2(42) p_2 = \frac{(a+b)(a+c) + (c+d)(b+d)}{m^2} \quad \quad (42) p2=m2(a+b)(a+c)+(c+d)(b+d)(42)若分类器 hih_ihi 与 hjh_jhj 在 DDD 上完全一致,则 κ=1\kappa = 1κ=1;若它们仅是偶然达成一致,则 κ=0\kappa = 0κ=0。 κ\kappaκ 通常为非负值,仅在 hih_ihi 与 hjh_jhj 达成一致的概率低于偶然性的情况下取负值。 κ\kappaκ-统计量常用于评估分类器的一致性 (agreement) 或可靠性,其值越大,多样性越小。
python
> **【代码实践 5】 计算基学习器的相关性 (多样性度量)**
>
> 我们利用相关系数(式 8.38)来观察随机森林中个体决策树之间的差异性。相关系数越低,多样性越大。
>
> ```python
import pandas as pd
import seaborn as sns
# 1. 训练一个包含10棵树的随机森林
rf = RandomForestClassifier(n_estimators=10, random_state=42)
rf.fit(X_train, y_train)
# 2. 获取每棵树对测试集的预测结果
# 结果形状: (样本数, 树的数量)
predictions = np.array([tree.predict(X_test) for tree in rf.estimators_]).T
# 3. 将预测结果转换为 DataFrame
df_preds = pd.DataFrame(predictions, columns=[f"Tree_{i}" for i in range(10)])
# 4. 计算相关系数矩阵 (Pearson Correlation)
corr_matrix = df_preds.corr()
print("基学习器预测结果的相关系数矩阵前3行3列:")
print(corr_matrix.iloc[:3, :3])
# (可选) 如果在 Jupyter Notebook 中,可以使用 sns.heatmap(corr_matrix) 可视化热力图