加法模型,就是经过训练集不断的获得不一样的分类器(回归),而后将这些分类器组合成一个新的分类器的过程。算法
假设有\(N\)个样本,且咱们的加法模型以下:
\[f(x)=\sum_{m=1}^M\beta_mb(x;\cal Y_m)\]
其中\(x\)为自变量,即样本;\(\cal Y_m\)为第\(m\)个分类器的参数;\(b(x;\cal Y_m)\)为分类器,也就是基函数;\(\beta_m\)为该分类器的系数。app
能够看出,在给定这样一个加法模型的思路以及固定的训练集后,咱们要作的就是最小化该模型的损失,即:
\[\min_{\beta_m,\cal Y_m}\sum_{i=1}^N\left(y_i,\sum_{m=1}^M\beta_mb(x_i;\cal Y_m)\right)\]
对于这样一个模型,训练的思路是:由于是个加法模型,因此能够从前向后,每一步只学习一个分类器(即基函数)和系数,让它逐步的逼近目标函数,直到达到咱们可以接受的偏差为止。该方法也叫作前向分步算法。函数
前向分布算法过程以下:
假设目前训练集\(T={(x_1,y_1),(x_2,y_2),...(x_N,y_N)}\);损失函数\(L(y,f(x))\);分类器\({b(x;\cal Y)}\)。目标是获得最后的加法模型\(f(x)\)。性能
1)获得第一个分类器\(f_0(x)=0\)
2)对于\(m=1,2,...M\)学习
i)如数学概括法同样,假设目前已经获得了前\(m-1\)个分类器:
\[f(x)=f_{m-1}(x)=\sum_i^{m-1}\beta_ib(x;\cal Y_i)\]
那么,对于第\(m\)个分类器的参数及系数求法:
\[(\beta_m,\cal Y_m)=arg\min_{\beta,\cal Y}\sum_{i=1}^NL\left(y_i,f_{m-1}(x_i)+\beta b(x_i;\cal Y)\right)\]
这样就获得了第\(m\)个分类器的参数和系数;
ii)而后更新旧加法模型,获得新的加法模型:
\[f(x)=f_M(x)=\sum_{m=1}^M\beta_mb(x;\cal Y_m)\]
这样,就是将整个模型转换成了一步求得一个模型的参数和系数的优化问题上。优化
adaboost是加法模型的一个特例。假设目前有训练集\(T=\{(x_1,y_1),(x_2,y_2),...,(x_N,y_N)\}\), 其中样本都为\(n\)维向量\(x_i\in\bf R^n\), 标签\(y_i\in\{-1,+1\}\)spa
1)先设定初始时的训练样本的权值:
\[D_1 = (w_{11},...,w_{1i},...,w_{1N}),w_{1i}=\frac{1}{N},i=1,2,...N\]code
2)对\(m=1,2,...,M\),即有\(M\)个分类器,则:blog
i)使用具备权值分布\(D_m\)的训练集学习,获得第\(m\)个基本分类器:
\[G_m(x):\rightarrow\{-1,+1\}\]ip
ii)而后计算基于当前分类器\(G_m(x)\)在训练集上的分类偏差率:
\[e_m= P(G_m(x_i)\neq y_i)=\sum_{i=1}^Nw_{mi}I(G_m(x_i)\neq y_i)\]
ps:固然是选择当前权值基础上分类偏差率最低的那个分类器做为当前分类器。因此实际上是经过ii)来肯定i)的分类器
iii)计算该分类器\(G_m(x)\)的系数:
\[\alpha_m=\frac{1}{2}log\frac{1-e_m}{e_m}\]
这里对数是天然对数。
ps:能够发现,当\(e_m\leq\frac{1}{2}\)时,\(\alpha_m\geq0\),而且\(\alpha_m\)随着\(e_m\)的减少而增大,也就是分类偏差率越小的基本分类器在最终分类器中做用越大。
iv)更新训练集的权值为下一个分类器作准备:
ps:权值更新的式子能够写成以下形式:
\[w_{m+1,i}= \begin{cases} \frac{w_{mi}}{Z_m}e^{-\alpha_m},& G_m(x_i)=y_i\\ \frac{w_{mi}}{Z_m}e^{\alpha_m},& G_m(x_i)\neq y_i \end{cases}\]
能够看出,当样本分类正确时,其权值在变小,而当样本分类错误时,其权值被放大,由此,误分类样本在下一轮学习中会起更大做用,也就是下一个分类器会更关注那些误分类的样本。
3)构建基本分类器的线性组合:
\[f(x)=\sum_{m=1}^M\alpha_mG_m(x)\]
获得最终分类器:
\[G(x)=sign(f(x))=sign\left(\sum_{m=1}^M\alpha_mG_m(x)\right)\]
假设分类器是一个阈值分类器,即\(x>v,y=1\)和\(x<v,y=-1\),训练集为简单的一维数据:
d1 = [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1] x = [0,1,2,3,4,5,6,7,8,9] y = [1,1,1,-1,-1,-1,1,1,1,-1] '''g1分类器,这里是划分点为2.5''' def g1(x): return 1 if x < 2.5 else -1 y_prd = [g1(i) for i in x] # [1, 1, 1, -1, -1, -1, -1, -1, -1, -1] e = sum([d1i*(0 if y1 == y2 else 1) for y1,y2,d1i in zip(y,y_prd,d1)] ) # 0.3
i)由于当2.5时,错误率最低,则第一个分类器:
\[G_1(x)=\begin{cases} \quad1,&x<2.5\\ -1,&x>2.5 \end{cases}\]
ii)当前偏差率为0.3
iii)计算第一个分类器系数:
\[\alpha_1=\frac{1}{2}log\frac{1-e_1}{e_1}=0.4236\]
iv)更新训练集的权值分布:
\(D_2=(w_{21},...,w_{2i},...w_{210})\)
\(w_{2i}=\frac{w_{1i}}{Z_1}exp(-\alpha_iy_iG_1(x_i)),i=1,2,...10\)
\(D_2=(0.0715,0.0715,0.0715,0.0715,0.0715,0.0715,0.1666,0.1666,0.1666,0.0715)\)
d1 = [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1] y = [1,1,1,-1,-1,-1,1,1,1,-1] z = [] '''g1分类器,这里是划分点为2.5''' def g1(x): return 1 if x < 2.5 else -1 for ind,(d1Item,yItem) in enumerate(zip(d1,y)): w = d1Item*np.exp(-0.4236*yItem*g1(ind)) z.append(w) d2 = [ zItem/sum(z) for zItem in z ]
\(f_1(x)=0.4236G_1(x)\)
此时分类器\(sign[f_1(x)]\)当前误分类3个\(\{7,8,9\}\);
d1 = [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1] x = [0,1,2,3,4,5,6,7,8,9] y = [1,1,1,-1,-1,-1,1,1,1,-1] '''g1分类器,这里是划分点为2.5''' def g1(x): return 1 if x < 2.5 else -1 def f1(x): return 1 if 0.4236*g1(x) >0 else -1 y_prd = [ f1(i) for i in x] # [1, 1, 1, -1, -1, -1, -1, -1, -1, -1]
3)接着处理\(m=2\)时。
同上述方法计算每一个阈值\(v=\{1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5\}\)下分类偏差率
\(e_{0.5}=0.6428,错分类样本\{2,3,7,8,9\}\)
\(e_{1.5}=0.5713,错分类样本\{3,7,8,9\}\)
\(e_{2.5}=0.4998,错分类样本\{7,8,9\}\)
\(e_{3.5}=0.5713,错分类样本\{4,7,8,9\}\)
\(e_{4.5}=0.6428,错分类样本\{4,5,7,8,9\}\)
\(e_{5.5}=0.7143,错分类样本\{4,5,6,7,8,9\}\)
\(e_{6.5}=0.5477,错分类样本\{4,5,6,8,9\}\)
\(e_{7.5}=0.3811,错分类样本\{4,5,6,9\}\)
\(e_{8.5}=0.2145,错分类样本\{4,5,6\}\)
最低的分类器:
\[G_2(x)=\begin{cases} \quad1,&x<8.5\\ -1,&x>8.5 \end{cases}\]
i)此时偏差率为0.2145
# 能够看出当前样本的权重值,其中通过第一次分类以后错误分类的权重变大 d2 = [0.0715,0.0715,0.0715,0.0715,0.0715,0.0715,0.1666,0.1666,0.1666,0.0715] x = [0,1,2,3,4,5,6,7,8,9] y = [1,1,1,-1,-1,-1,1,1,1,-1] '''g2分类器,这里是划分点为8.5''' def g2(x): return 1 if x < 8.5 else -1 y_prd = [ g2(i) for i in x] # [1, 1, 1, -1, -1, -1, -1, -1, -1, -1] # 计算预测值与实际值不相等的,即为误分类,将其乘以样本权重,获得偏差率 e = sum([d1i*(0 if y1 == y2 else 1) for y1,y2,d1i in zip(y,y_prd,d2)] ) # 0.2145
ii)系数为0.6496
iii)训练集权值分布:
\(D_3=\{0.0455,0.0455,0.0455,0.1667,0.1667,0.1667,0.1060,0.1060,0.1060,0.0455\}\)
\(f_2(x)=0.4236G_1(x)+0.6496G_2(x)\)
iv)此时分类器\(sign[f_2(x)]\)训练集上错分类样本仍是3个\(\{4,5,6\}\)
x = [0,1,2,3,4,5,6,7,8,9] y = [1,1,1,-1,-1,-1,1,1,1,-1] d3 = [0.0455,0.0455,0.0455,0.1667,0.1667,0.1667,0.1060,0.1060,0.1060,0.0455] def g1(x): return 1 if x<2.5 else -1 def g2(x): return 1 if x<8.5 else -1 def f2(x): return 1 if (0.4236*g1(x) + 0.6496*g2(x)) > 0 else -1 y_prd = [ f2(i) for i in x] # [1, 1, 1, 1, 1, 1, 1, 1, 1, -1] isEqual = [1 if ypred == ygt else 0 for ypred,ygt in zip(y_prd, y)] # [1, 1, 1, 0, 0, 0, 1, 1, 1, 1]
4)如上述计算过程,第三轮获得的分类器:
\[G_3(x)=\begin{cases} \quad -1,&x<5.5\\ 1,&x>5.5 \end{cases}\]
i)此时偏差率为0.1820
d3 = [0.0455,0.0455,0.0455,0.1667,0.1667,0.1667,0.1060,0.1060,0.1060,0.0455] x = [0,1,2,3,4,5,6,7,8,9] y = [1,1,1,-1,-1,-1,1,1,1,-1] '''g3分类器,这里是划分点为5.5''' def g3(x): return -1 if x < 5.5 else 1 y_prd = [ g3(i) for i in x] # [-1, -1, -1, -1, -1, -1, 1, 1, 1, 1] # 计算预测值与实际值不相等的,即为误分类,将其乘以样本权重,获得偏差率 e = sum([d1i*(0 if y1 == y2 else 1) for y1,y2,d1i in zip(y,y_prd,d3)] ) # 0.182
ii)系数为0.6496
iii)训练集权值分布:
\(D_4=\{0.125,0.125,0.125,0.102,0.102,0.102,0.065,0.065,0.065,0.125\}\)
\[f_3(x)=0.4236G_1(x)+0.6496G_2(x)+0.7514G_3(x)\]
x = [0,1,2,3,4,5,6,7,8,9] y = [1,1,1,-1,-1,-1,1,1,1,-1] def g1(x): return 1 if x<2.5 else -1 def g2(x): return 1 if x<8.5 else -1 def g3(x): return -1 if x<5.5 else 1 def f3(x): return 1 if (0.4236*g1(x) + 0.6496*g2(x) + 0.7514*g3(x)) > 0 else -1 y_prd = [ f3(i) for i in x] # [1, 1, 1, -1, -1, -1, 1, 1, 1, -1] isEqual = [1 if ypred == ygt else 0 for ypred,ygt in zip(y_prd, y)] # [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
4)如上述计算过程,第三轮获得的分类器:
此时误分类样本为0个,因此无需训练所谓第四个基分类器。
最终分类器为:
\[G(x)=sign[f_3(x)]=sign[0.4236G_1(x)+0.6496G_2(x)+0.7514G_3(x)]\]
提高树是以回归树或者分类树做为基本分类器的模型,被认为统计学习中性能最好的方法之一(固然还有svm了)。
该类方法是采用了加法模型(基函数的线性组合)和前向分布算法,用决策树为基函数的提高方法叫提高树,分类问题 时,可采用二叉分类树,回归问题时,可采用二叉回归树。提高树模型能够表示为决策树的加法模型:
\[f_M(x)=\sum_{m=1}^MT(x;\Theta_m)\]
其中,\(T(x;\Theta_m)\)表示一棵决策树;\(\Theta_m\)表示第\(m\)棵决策树的参数;\(M\)为树的个数。
对于整个过程,如上面的加法模型同样,先肯定初始提高树\(f_0(x)=0\),而后第\(m\)轮以后,整个的模型:
\[f_m(x)=f_{m-1}(x)+T(x;\Theta_m)\]
其中\(f_{m-1}(x)\)是当前求得的模型,而后经过经验风险最小化肯定下一棵决策树的参数\(\Theta_m\):
\[\hat \Theta_m=arg\min_{\Theta_m}\sum_{i=1}^NL(y_i,f_{m-1}(x_I)+T(x_i;\theta_m))\]
ps:由于树的线性组合能够很好的拟合训练数据,即便数据中的输入与输出的关系很复杂也如此。因此提高树是一个高功能的学习算法
一般来讲,不一样的提高树学习算法,主要区别在于使用的损失函数:1)平方偏差损失函数的回归问题;2)指数损失函数的分类问题;3)通常损失函数的通常决策问题。
对于二类分类问题,即将adaboost中的基本分类器限制为二类分类树(即树桩:一个根节点,两个叶子节点)。这里主要介绍回归问题的提高树。
假设训练集\(T=\{(x_1,y_1),(x_2,y_2),...,(x_N,y_N)\}\),且\(x_i\in \cal X \subseteq \bf R^n\),\(y_i\in \cal Y \subseteq \bf R\).对于一棵回归树,若是将输入空间划分红\(J\)个互不相交的区域\(R_1,R_2,...R_J\)而且在每一个区域上肯定输出常量\(c_j\),那么树可表示为:
\[T(x:\Theta)=\sum_{j=1}^Jc_jI(x\in R_j)\]
其中参数\(\Theta=\{(R_1,c_1),(R_2,c_2),...,(R_J,c_J)\}\)表示树的区域划分和各个区域上的常量输出\(J\)表示回归树的复杂度,即最终叶节点个数。
前向分步步骤:
假设训练集\(T=\{(x_1,y_1),(x_2,y_2),...,(x_N,y_N)\}\),且\(x_i\in \cal X \subseteq \bf R^n\),\(y_i\in \cal Y \subseteq \bf R\)
1)初始化\(f_0(x)=0\)
2)对于轮数\(m=1,2,...,M\)
i)当第\(m\)步时,已知前\(m-1\)轮结果,须要求解:
\[\hat\Theta_m=arg\min_{\Theta_m}\sum_{i=1}^NL(y_i,f_{m-1}(x_i)+T(x_i;\Theta_m))\]
获得的\(\hat\Theta_m\)即为第\(m\)棵树的参数。当采用平方偏差损失函数时,:
\[L(y,f(x))=(y-f(x))^2\]
代入得:
\[\begin{eqnarray} L(y,f_{m-1}(x)+T(x:\Theta_m)) &=&[y-f_{m-1}(x)-T(x;\Theta_m)]^2\\ &=&[r-T(x;\Theta_m)]^2 \end{eqnarray}\]
其中\(r=y-f_{m-1}(x)\)是前\(m-1\)轮后获得的模型拟合数据的残差,因此对于回归问题的提高树来讲,就是拟合当前模型的残差。
ii)对于每一个样本\(i=1,...N\)
求得他们的残差:
\[r_{mi}=y_i-f{m-1}(x_i),i=1,2,...N\]
iii)拟合这轮获得的残差\(r_{mi}\),基于整个训练集学习一棵新的回归树,获得\(T(x;\Theta_m)\)
iv)更新\(f_m(x)=f_{m-1}(x)+T(x; \Theta_m)\)
3)获得最后结果模型:
\[f_M(x)=\sum_{m=1}^MT(x;\Theta_m)\]
以下表数据:
X = [1,2,3,4,5,6,7,8,9,10] Y0 = [5.56, 5.70, 5.91, 6.40, 6.80, 7.05, 8.90, 8.70, 9.00, 9.05] X_splits = [1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5] def cost_split_point(ind,xs,YT): R1 = YT[:ind+1] R2 = YT[ind+1:] c1 = round(mean(R1),3) c2 = round(mean(R2),3) ans0 = [(x-c1)*(x-c1) for x in R1] ans1 = [(x-c2)*(x-c2) for x in R2] return [sum(ans0+ans1), c1, c2] cost = [[xs]+cost_split_point(ind,xs,Y0) for ind,xs in enumerate(X_splits)] #[[1.5, 15.723, 5.559, 7.501], # [2.5, 12.083, 5.629, 7.726], # [3.5, 8.365, 5.723, 7.985], # [4.5, 5.775, 5.892, 8.25], # [5.5, 3.911, 6.073, 8.540], # [6.5, 1.930, 6.236, 8.912], # [7.5, 8.009, 6.617, 8.916], # [8.5, 11.735, 6.877, 9.025], # [9.5, 15.738, 7.113, 9.050]]
2)计算\(f_1(x)\)拟合训练集的残差计算公式\(r_{2i}=y_i-f_1(x_i),i=1,2,...,10\)
r_2i = [-0.68, -0.54, -0.33, -0.16, 0.56, 0.81, -0.01, -0.21, 0.09, 0.14] r_2i = np.array(r_2i) loss = (r_2i*r_2i).sum()#1.9301
3)在计算新的回归树时,选择的训练集是图3.1.3 而不是原来的3.1.1,便是基于上一轮模型结果以后的残差。从而获得这一轮的回归树:
\[T_2(x)=\begin{cases} -0.52,& x<3.5\\ 0.22,&x\geq3.5 \end{cases}\]
Y1 = [-0.68, -0.54, -0.33, 0.16, 0.56, 0.81, -0.01, -0.21, 0.09, 0.14] cost = [[xs]+cost_split_point(ind,xs,Y1) for ind,xs in enumerate(X_splits)] #[[1.5, 1.417, -0.680, 0.073], # [2.5, 1.002, -0.609, 0.151], # [3.5, 0.790, -0.517, 0.22], # [4.5, 1.129, -0.347, 0.230], # [5.5, 1.657, -0.166, 0.164], # [6.5, 1.930, -0.003, 0.003], # [7.5, 1.929, -0.004, 0.007], # [8.5, 1.896, -0.029, 0.115], # [9.5, 1.908, -0.017, 0.140]]
在获得这一轮的回归树以后,将前面获得的模型与当前模型相加,且重合区域须要注意相加减,如当\(x<3.5\)时,\(f_2(x)=-0.52+6.24=5.72\):
\[f_2(x)=f_1(x)+T_2(x)=\begin{cases} 5.72,& x<3.5\\ 6.46,& 3.5\leq x<6.5\\ 9.13,& x\geq 6.5 \end{cases}\]
用\(f_2(x)\)拟合训练集损失为\(L(y,f_2(x))=\sum_{i=1}^{10}(y_i-f_2(x_i))^2=0.79\)
如此获得最后结果:
\[f_6(x)=f_5(x)+T_6(x)=\begin{cases} 5.63,& x<2.5\\ 5.82,& 2.5\leq x<3.5\\ 6.56,& 3.5\leq x<4.5\\ 6.83,& 4.5\leq x <6.5\\ 8.95,&x \geq6.5 \end{cases}\]
当前模型拟合训练集平方损失为0.17.假设此时偏差已经知足要求,那么就能够将\(f_6(x)\)做为整个训练集的提高树
当提高树中选取的损失函数是平方损失和指数损失函数时,训练过程如上述所属,但是当通常损失函数而言,优化相对就较为麻烦了,这时候能够用freidma提出的gradient boosting算法,这是与最速降低法类似的方法,使用了损失函数的负梯度:
\[r_{mi}=-\left[\frac{\rm dL(y,f(x_i))}{\rm df(x_i)}\right]_{f(x)=f_{m-1}(x)}\]
将其做为3.1中每一轮计算的平方损失残差值,即这一轮所谓的"训练集"
其余部分的计算不变。
参考资料:
[] 李航,统计学习方法
2017/04/07 第一次修改!