前情回顾
结论速递
本次学习了解了AdaBoost的常见方法:用于分类的SAMME和用于回归的Adaboost.R2,学习内容比较硬核,根据李航《统计学习方法》进行了一定的重新整理。
目录
1 AdaBoost
1.1 概述
对提升方法来说,有两个问题需要回答:一是在每一轮如何改变训练数据的权值或概率分布;二是如何将弱分类器组合成一个强分类器。
关于第一个问题,AdaBoost的做法是,提高那些被前一轮弱分类器错误分类样本的全职,而降低那些被正确分类样本的权值;
对于第二个问题,采取加权多数表决的方法,具体地,加大分类误差率小的弱分类器的权值,使其在表决中起较大的作用,减小分类误差率大的弱分类器的权值,使其在表决中其较小的作用。
1.2 分类损失
AdaBoost所用的分类损失函数如下
对于 K K K分类问题而言,当样本标签 y = [ y 1 , . . . , y K ] T \mathbf{y}=[y_1,...,y_K]^T y=[y1,...,yK]T的类别 S ( y ) S(\mathbf{y}) S(y)为第 k k k类( k = 1 , . . . , K k=1,...,K k=1,...,K)时,标签 y \mathbf{y} y的第 i i i个( i = 1 , . . . , K i=1,...,K i=1,...,K)元素 y i y_i yi满足
y i = { 1 , i f i = k − 1 K − 1 , i f i ≠ k y_i=\left\{ \begin{aligned} &1,\quad &{\rm if}\ i=k\\ &-\frac{1}{K-1},\quad &{\rm if}\ i\neq k \end{aligned} \right. yi=⎩⎨⎧1,−K−11,if i=kif i=k
设模型的输出结果为 f = [ f 1 , . . . , f K ] T \mathbf{f}=[f_1,...,f_K]^T f=[f1,...,fK]T,则记损失函数为
L ( y , f ) = exp ( − y T f K ) L(\mathbf{y},\mathbf{f})=\exp(-\frac{\mathbf{y}^T\mathbf{f}}{K}) L(y,f)=exp(−KyTf)
【思考题】假设有一个3分类问题,标签类别为第2类,模型输出的类别标签为[-0.1,-0.3,0.4],请计算对应的指数损失。
首先可以写出标签
y
=
[
−
1
2
,
1
,
−
1
2
]
\mathbf{y}=[-\dfrac{1}{2},1,-\dfrac{1}{2}]
y=[−21,1,−21],则损失函数为
L
(
y
,
f
)
=
exp
(
−
y
T
f
K
)
=
exp
(
−
[
−
1
2
,
1
,
−
1
2
]
T
×
[
−
0.1
,
−
0.3
,
0.4
]
3
)
=
1.162
\begin{aligned} L(\mathbf{y},\mathbf{f})&=\exp(-\frac{\mathbf{y}^T\mathbf{f}}{K})\\ &=\exp(-\dfrac{[-\dfrac{1}{2},1,-\dfrac{1}{2}]^T×[-0.1,-0.3,0.4]}{3})\\ &=1.162 \end{aligned}
L(y,f)=exp(−KyTf)=exp(−3[−21,1,−21]T×[−0.1,−0.3,0.4])=1.162
2 SAMME
2.1 二分类AdaBoost
假定一个二分类的训练数据集
T
=
{
(
x
1
,
y
1
)
,
(
x
2
,
y
2
)
,
.
.
.
,
(
x
N
,
y
N
)
}
T = \{ (x_1,y_1), (x_2,y_2), ... ,(x_N,y_N)\}
T={(x1,y1),(x2,y2),...,(xN,yN)}
其中
y
i
∈
{
−
1
,
+
1
}
y_i \in \{ -1,+1\}
yi∈{−1,+1}
则流程如下
- 初始化训练数据的权值分布
D 1 = ( w 11 , . . . , w 1 i , . . . , w 1 N ) , w 1 i = 1 N , i = 1 , 2 , . . . , N D_1 = (w_{11},...,w_{1i},...,w_{1N}), w_{1i} = \dfrac{1}{N}, i=1,2,...,N D1=(w11,...,w1i,...,w1N),w1i=N1,i=1,2,...,N - 对
m
=
1
,
2
,
.
.
.
,
M
m=1,2,...,M
m=1,2,...,M
- 使用具有权值分布
D
m
D_m
Dm的训练数据集学习,得到基本分类器
G m ( x ) : → { − 1 , + 1 } G_m(x): \rightarrow \{ -1,+1\} Gm(x):→{−1,+1} - 计算
G
m
(
x
)
G_m(x)
Gm(x)在训练数据集上的分类误差率
e m = P ( G m ( x i ) ≠ y i ) = ∑ i = 1 N w m i I ( G m ( x i ) ≠ y i ) e_m = P(G_m(x_i) \neq y_i)=\sum_{i=1}^{N}w_{mi}I(G_m(x_i)\neq y_i) em=P(Gm(xi)=yi)=i=1∑NwmiI(Gm(xi)=yi) - 计算
G
m
(
x
)
G_m(x)
Gm(x)的系数
α m = 1 2 log 1 − e m e m \alpha_m = \dfrac{1}{2} \log{\dfrac{1-e_m}{e_m}} αm=21logem1−em
这里的对数是自然对数 - 更新训练数据集的权值分布
D m + 1 = ( w m + 1 , 1 , . . . , w m + 1 , i , . . . , w m + 1 , N ) D_{m+1}=(w_{m+1,1},...,w_{m+1,i},...,w_{m+1,N}) Dm+1=(wm+1,1,...,wm+1,i,...,wm+1,N)
w m + 1 , i = w m i Z m exp ( − α m y i G m ( x i ) ) , i = 1 , 2 , . . . , N w_{m+1,i}=\dfrac{w_{mi}}{Z_m}\exp{(-\alpha_m y_i G_m(x_i))},i=1,2,...,N wm+1,i=Zmwmiexp(−αmyiGm(xi)),i=1,2,...,N
这里, Z m Z_m Zm是规范化因子
Z m = ∑ i = 1 N w m i exp ( − α m y i G m ( x i ) ) Z_m=\sum_{i=1}^{N}w_{mi}\exp{(-\alpha_m y_i G_m(x_i))} Zm=i=1∑Nwmiexp(−αmyiGm(xi))
它使 D m + 1 D_{m+1} Dm+1成为一个 概率分布
- 使用具有权值分布
D
m
D_m
Dm的训练数据集学习,得到基本分类器
- 构建基本分类器的线性组合
f ( x ) = ∑ m = 1 M α m G m ( x ) f(x)=\sum_{m=1}^{M}\alpha_mG_m(x) f(x)=m=1∑MαmGm(x)
得到最终分类器
G ( x ) = s i g n ( f ( x ) ) = s i g n ( ∑ m = 1 M α m G m ( x ) ) G(x)=sign (f(x))=sign (\sum_{m=1}^{M}\alpha_mG_m(x)) G(x)=sign(f(x))=sign(m=1∑MαmGm(x))
2.2 SAMME
SAMME算法的全称是 S t a g e w i s e A d d i t i v e M o d e l i n g u s i n g a M u l t i c l a s s E x p o n e n t i a l l o s s f u n c t i o n \rm{\textbf{S}tagewise\,\textbf{A}dditive\,\textbf{M}odeling\, using\, a\,\textbf{M}ulticlass\,\textbf{E}xponential\, loss\, function} StagewiseAdditiveModelingusingaMulticlassExponentiallossfunction,它假定模型的总输出 f \mathbf{f} f具有 f ( M ) ( x ) = ∑ m = 1 M β ( m ) b ( m ) ( x ) \mathbf{f}^{(M)}(\mathbf{x})=\sum_{m=1}^M \beta^{(m)} \mathbf{b}^{(m)}(\mathbf{x}) f(M)(x)=∑m=1Mβ(m)b(m)(x)的形式。其中, M M M是模型的总迭代轮数, β ( m ) ∈ R + \beta^{(m)}\in \mathbb{R^+} β(m)∈R+是每轮模型的加权系数, b ( m ) ( x ) ∈ R K \mathbf{b}^{(m)}(\mathbf{x}) \in\mathbb{R}^K b(m)(x)∈RK是基模型 G G G输出类别的标签向量。
算法流程如下图
【思考题】对公式进行化简,写出
K
=
2
K=2
K=2时的SAMME算法流程,并与李航《统计学习方法》一书中所述的Adaboost二分类算法对比是否一致。
就是将含K的项可以去掉,因为 ( K − 1 ) 2 K \dfrac{(K-1)^2}{K} K(K−1)2在 K = 2 K=2 K=2时为1,而 log ( K − 1 ) \log{(K-1)} log(K−1)在 K = 2 K=2 K=2时为0。化简结果和二分类一致,具体见2.1。
2.3 SAMME的代码实现
导入基础库
import numpy as np
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_classification
定义类
class AdaBoost:
def __init__(self, n_estimators=100):
self.clf_num = n_estimators
self.classes = None
def init_args(self, X, y):
#初始化参数
self.X = X
self.y = y
M, _ = X.shape
self.models = []
self.alphas = []
self.weights = np.repeat(1/X.shape[0],X.shape[0])
self.classes = np.unique(y.reshape(-1)).shape[0]
def fit(self, X, y):
self.init_args(X, y)
output = 0
for n in range(self.clf_num):
#基础分类器
clf = DecisionTreeClassifier(max_depth=1)
clf.fit(X, y, sample_weight=self.weights)
P = clf.predict(X)
#误差计算
err = (self.weights*(P!=y)).sum()
#误差权重计算
alpha = np.log((1-err)/err)+np.log(self.classes-1)
#生成输出结果,对应于argmax形式
temp_output = np.full((X.shape[0],self.classes),
-1/(self.classes-1))
temp_output[np.arange(X.shape[0]),P] = 1
self.models.append(clf)
self.alphas.append(alpha)
#更新权重
self.weights *= np.exp(alpha * (y != P))
self.weights /= self.weights.sum()
#更新输出
output += temp_output * alpha
#acc = accuracy_score(y,np.argmax(output, axis = 1))
#print(acc)
def predict(self,X):
#预测过程不需要计算误差,只需要不断更新输出即可
result = 0
for n in range(self.clf_num):
cur_pred = self.models[n].predict(X)
temp_output = np.full((X.shape[0],self.classes),
-1/(self.classes-1))
temp_output[np.arange(X.shape[0]),cur_pred] = 1
result += self.alphas[n] * temp_output
return np.argmax(result,axis=1)
随后进行测试,与sklearn自带的进行对比。
X, y = make_classification(
n_samples=10000, n_features=10,
n_informative=5, random_state=0, n_classes=2
)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=0
)
from sklearn.ensemble import AdaBoostClassifier as ABC
clf = ABC(
DecisionTreeClassifier(max_depth=1),
n_estimators=20, algorithm="SAMME"
)
clf.fit(X_train, y_train)
result = clf.predict(X_test)
print("sklearn中SAMME的验证集得分为: ", accuracy_score(y_test, result))
clf = AdaBoost(20)
clf.fit(X_train, y_train)
result = clf.predict(X_test)
print("SAMME的验证集得分为: ", accuracy_score(y_test, result))
预测结果
3 Adaboost.R2
这是用于处理回归问题的最常使用的AdaBoost方法。
需要重新定义误差的表达形式
设训练集特征和目标分别为 X = ( x 1 , . . . , x n ) \mathbf{X}=(\mathbf{x}_1, ..., \mathbf{x}_n) X=(x1,...,xn)和 y = ( y 1 , . . . , y n ) \mathbf{y}=(y_1,...,y_n) y=(y1,...,yn),权重 w \mathbf{w} w初始化为 ( w 1 , . . . , w n ) (w_1,...,w_n) (w1,...,wn)。在第 m m m轮时,根据权重训练基预测器得到 G ∗ G^* G∗,计算每个样本的相对误差
e i = ∣ y i − G ∗ ( x i ) ∣ max i ∣ y i − G ∗ ( x i ) ∣ e_{i}=\frac{\vert y_i-G^*(\mathbf{x}_i)\vert}{\max_i \vert y_i-G^*(\mathbf{x}_i)\vert} ei=maxi∣yi−G∗(xi)∣∣yi−G∗(xi)∣
设样本的加权相对误差率为 E ( m ) = ∑ i = 1 n w i e i E^{(m)}=\sum_{i=1}^n w_ie_i E(m)=∑i=1nwiei,则相对误差率与正确率的比值为 β ( m ) = E ( m ) 1 − E ( m ) \beta^{(m)}=\frac{E^{(m)}}{1-E^{(m)}} β(m)=1−E(m)E(m),即预测器权重 α ( m ) = log 1 β ( m ) \alpha^{(m)}=\log \frac{1}{\beta^{(m)}} α(m)=logβ(m)1。
训练算法如下
4 知识回顾
- 二分类问题下,AdaBoost算法如何调节样本权重?
根据分类误差,每一轮训练都放大错误预测样本的权重。 - 样本A在当轮分类错误,且样本B在当轮分类正确,请问在权重调整后,样本A的权重一定大于样本B吗?
不是,因为样本权重是一个累积值,在整个boosting的过程中不断累积,由于未知样本A和样本B在本轮开始前的权重情况,因此不能知道该轮分类正确与否对样本权重的影响。 - 在处理分类问题时,Adaboost的损失函数是什么?请叙述其设计的合理性。
AdaBoost选用的损失函数是 L ( y , f ) = exp ( − y T f K ) L(\mathbf{y},\mathbf{f})=\exp(-\frac{\mathbf{y}^T\mathbf{f}}{K}) L(y,f)=exp(−KyTf)