前向选择法和前向梯度法
由于前向选择法和前向梯度法的实现原理涉及过多的矩阵运算,本文只给出两种算法的思路。两者实现都是把矩阵中的向量运算具体化成平面几何中的向量运算。
前向选择法
前向选择法是一种典型的贪心算法。
通常用前向选择法解决线性模型的回归系数。对于一个有 m m m个样本,每个样本有 n n n个特征的训练集而言,假设可以拟合一个线性模型 Y = ω T X Y=\omega^TX Y=ωTX,其中 Y Y Y是 m ∗ 1 m*1 m∗1的向量, X X X是 m ∗ n m*n m∗n的矩阵, ω \omega ω是 n ∗ 1 n*1 n∗1的向量。即可通过前向选择法求得最小化该模型的参数 ω \omega ω。
余弦相似度求投影
首先把矩阵
X
X
X看成
n
n
n个
m
∗
1
m*1
m∗1的向量
X
i
(
i
=
1
,
2
,
⋯
,
n
)
X_i \quad(i=1,2,\cdots,n)
Xi(i=1,2,⋯,n),之后选择与向量
Y
Y
Y余弦相似度最大,即与
Y
Y
Y最为接近的一个变量
X
i
X_i
Xi,然后用
X
i
X_i
Xi逼近
Y
Y
Y,即可得到
Y
^
=
X
i
ω
i
\hat{Y}=X_i\omega_i
Y^=Xiωi
其中
ω
i
=
<
X
i
,
Y
>
∣
∣
X
i
∣
∣
2
余弦相似度
\omega_i={\frac{<X_i,Y>}{{||X_i||}^2}}\quad\text{余弦相似度}
ωi=∣∣Xi∣∣2<Xi,Y>余弦相似度,其中
<
X
i
,
Y
>
=
∣
Y
∣
∗
cos
α
<X_i,Y>=|Y|*\cos\alpha
<Xi,Y>=∣Y∣∗cosα,
α
\alpha
α是
X
i
X_i
Xi和
Y
Y
Y的夹角。
上述公式因此可以认为 Y ^ \hat{Y} Y^是 Y Y Y在 X i X_i Xi上的投影。
得到 Y Y Y的接近值 Y ^ \hat{Y} Y^后既可以得到残差值为 Y e r r = Y − Y ^ Y_{err}=Y-\hat{Y} Yerr=Y−Y^,由于 Y ^ \hat{Y} Y^是投影,则 Y ^ \hat{Y} Y^和 X i X_i Xi是正交的,因此可以以 Y e r r Y_{err} Yerr为新的变量,从剩下的 X i ( i = 1 , 2 , i − 1 , i + 2 , ⋯ , n ) X_i\quad(i=1,2,i-1,i+2,\cdots,n) Xi(i=1,2,i−1,i+2,⋯,n)中,选择一个新的最接近残差 Y e r r Y_{err} Yerr的 X i X_i Xi重复上述投影和计算残差的流程,直至残差为0,停止算法。即可得到 ω \omega ω。
举例
# 举例图例
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
%matplotlib inline
font = FontProperties(fname='/Library/Fonts/Heiti.ttc')
# X1*w1
plt.annotate(xytext=(2, 5), xy=(8, 5), s='', color='r',
arrowprops=dict(arrowstyle="->", color='r'))
plt.text(6, 4.5, s='$X_1*\omega_1$', color='g')
# X2*w2
plt.annotate(xytext=(8, 5), xy=(9.3, 7.5), s='', color='r',
arrowprops=dict(arrowstyle="->", color='r'))
plt.text(9.3, 7, s='$X_2*\omega_2$', color='g')
# X1
plt.annotate(xytext=(2, 5), xy=(4, 5), s='', color='r',
arrowprops=dict(arrowstyle="->", color='k'))
plt.text(2.5, 4.5, s='$X_1$', color='g')
# X2
plt.annotate(xytext=(2, 5), xy=(3, 7), s='', color='r',
arrowprops=dict(arrowstyle="->", color='k'))
plt.text(2, 6, s='$X_2$', color='g')
# X2
plt.annotate(xytext=(8, 5), xy=(9, 7), s='', color='r',
arrowprops=dict(arrowstyle="->", color='k'))
plt.text(8.2, 6.5, s='$X_2$', color='g')
# Y
plt.annotate(xytext=(2, 5), xy=(8, 8), s='', color='r',
arrowprops=dict(arrowstyle="->", color='k'))
plt.text(5, 7.5, s='$Y$', color='g')
#
plt.annotate(xytext=(8, 5), xy=(8, 8), s='', color='r',
arrowprops=dict(arrowstyle="-", color='gray'))
plt.text(7.5, 6.5, s='$Y_1$', color='g')
#
plt.annotate(xytext=(8, 8), xy=(9.3, 7.5), s='',
arrowprops=dict(arrowstyle="-", color='gray'))
plt.text(8.5, 8, s='$Y_2$', color='g')
plt.xlim(0, 11)
plt.ylim(2, 10)
plt.title('前向选择法举例', fontproperties=font, fontsize=20)
plt.show()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vqUs6bVT-1583411304391)(A-05%20%E5%89%8D%E5%90%91%E9%80%89%E6%8B%A9%E6%B3%95%E5%92%8C%E5%89%8D%E5%90%91%E6%A2%AF%E5%BA%A6%E6%B3%95_files/A-05%20%E5%89%8D%E5%90%91%E9%80%89%E6%8B%A9%E6%B3%95%E5%92%8C%E5%89%8D%E5%90%91%E6%A2%AF%E5%BA%A6%E6%B3%95_7_0.png)]
上图假设 X X X为 2 2 2维,首先可以看出,离 Y Y Y最接近的是 X 1 X_1 X1,因此画出 Y Y Y在 X 1 X_1 X1上的投影红线 X 1 ∗ ω 1 X_1*\omega_1 X1∗ω1,此时残差为灰线 Y 1 Y_1 Y1。由于目前只剩下 X 2 X_2 X2,所以接着用残差 Y 1 Y_1 Y1在 X 2 X_2 X2上投影得到红线 X 2 ∗ ω 2 X_2*\omega_2 X2∗ω2,如果不只是 X 2 X_2 X2,则选择最接近 Y 1 Y_1 Y1的 X i X_i Xi。此时的 X 1 ω 1 + X 2 ω 2 X_1\omega_1+X_2\omega_2 X1ω1+X2ω2则模拟了 Y Y Y,即 ω = [ ω 1 , ω 2 ] \omega=[\omega_1,\omega_2] ω=[ω1,ω2]。
前向选择法优缺点
优点
- 算法对每个 X i X_i Xi只做一次操作,速度快。
缺点
- 由于变量 X i X_i Xi之间不是正交的,所以每次都必须做投影缩小残差,所以前向选择法最后只能给出一个局部近似解。(可以考虑下面的前向梯度法)
前向梯度法
前向梯度法类似于前向选择法,不同之处在于前向梯度法废除了前向选择法的投影逼近
Y
Y
Y,取而代之的是在每次最接近
Y
Y
Y的向量
X
i
X_i
Xi的方向上移动一小步,并且向量
X
i
X_i
Xi移动会不会被剔除,而是继续从
X
i
(
i
=
1
,
2
,
i
−
1
,
i
,
i
+
1
,
⋯
,
n
)
X_i \quad(i=1,2,i-1,i,i+1,\cdots,n)
Xi(i=1,2,i−1,i,i+1,⋯,n)中选择一个最接近残差
Y
e
r
r
Y_{err}
Yerr(注:残差计算方式类似于前向选择法)的向量
X
i
X_i
Xi,然后再走一小步,直至残差为0,停止算法,即可得到
ω
\omega
ω。
举例
# 举例图例
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
%matplotlib inline
font = FontProperties(fname='/Library/Fonts/Heiti.ttc')
# X1
plt.annotate(xytext=(2, 5), xy=(3, 5), s='', color='r',
arrowprops=dict(arrowstyle="->", color='r'))
plt.text(2.4, 4.8, s='$\epsilon{X_1}$', color='g')
# eX1
plt.annotate(xytext=(2, 5), xy=(4, 5), s='', color='r',
arrowprops=dict(arrowstyle="->", color='r'))
plt.text(3.2, 4.8, s='$\epsilon{X_1}$', color='g')
# eX1
plt.annotate(xytext=(2, 5), xy=(5, 5), s='', color='r',
arrowprops=dict(arrowstyle="->", color='r'))
plt.text(4.2, 4.8, s='$\epsilon{X_1}$', color='g')
# eX1
plt.annotate(xytext=(2, 5), xy=(2.8, 5), s='', color='r',
arrowprops=dict(arrowstyle="->", color='k'))
plt.text(1.9, 4.8, s='$X_1$', color='g')
# eX1
plt.annotate(xytext=(6.1, 6.2), xy=(7, 6.2), s='', color='r',
arrowprops=dict(arrowstyle="->", color='r'))
plt.text(6.2, 6, s='$\epsilon{X_1}$', color='g')
# ex2
plt.annotate(xytext=(5, 5), xy=(6.2, 6.2), s='', color='r',
arrowprops=dict(arrowstyle="->", color='r'))
plt.text(5.2, 5.8, s='$\epsilon{X_2}$', color='g')
# X2
plt.annotate(xytext=(2, 5), xy=(3, 6), s='', color='r',
arrowprops=dict(arrowstyle="->", color='k'))
plt.text(2, 5.5, s='$X_2$', color='g')
# X2
plt.annotate(xytext=(5, 5), xy=(6, 6), s='', color='r',
arrowprops=dict(arrowstyle="->", color='k'))
plt.text(5.6, 5.5, s='$X_2$', color='g')
# Y
plt.annotate(xytext=(2, 5), xy=(8, 7), s='', color='r',
arrowprops=dict(arrowstyle="->", color='k'))
plt.text(5, 6.2, s='$Y$', color='g')
plt.annotate(xytext=(5, 5), xy=(8, 7), s='', color='r',
arrowprops=dict(arrowstyle="-", color='gray'))
plt.xlim(1, 9)
plt.ylim(4, 8)
plt.title('前向梯度法举例', fontproperties=font, fontsize=20)
plt.show()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oaHPtYkp-1583411304392)(A-05%20%E5%89%8D%E5%90%91%E9%80%89%E6%8B%A9%E6%B3%95%E5%92%8C%E5%89%8D%E5%90%91%E6%A2%AF%E5%BA%A6%E6%B3%95_files/A-05%20%E5%89%8D%E5%90%91%E9%80%89%E6%8B%A9%E6%B3%95%E5%92%8C%E5%89%8D%E5%90%91%E6%A2%AF%E5%BA%A6%E6%B3%95_17_0.png)]
上图假设 X X X为 2 2 2维,首先可以看出,离 Y Y Y最接近的是 X 1 X_1 X1,因此沿着向量 X i X_i Xi的方向走上一段距离,此处的 ϵ \epsilon ϵ是一个手动调整的超参数,走了一段距离后发现,离残差 Y e r r Y_{err} Yerr最近接的还是 X 1 X_1 X1,因此继续接着走一段距离,直到走到离残差 Y e r r Y_{err} Yerr最近的为 X 2 X_2 X2的时候,沿着向量 X 2 X_2 X2的方向走上一段距离,发现此时残差 Y e r r Y_{err} Yerr离 X 1 X_1 X1更近,则沿着 X 1 X_1 X1走一段距离,直到走到最后残差为0,停止算法,即可得到 ω \omega ω。
前向梯度法优缺点
优点
- 可以手动控制 ϵ \epsilon ϵ的大小,即可以控制算法的精准度,如果 ϵ \epsilon ϵ较小的时候算法精准度很高
缺点
- ϵ \epsilon ϵ小,算法精准度高,同时算法迭代次数增加; ϵ \epsilon ϵ大,算法精准度降低。类似于梯度下降,这是前向梯度法较大的一个问题。(参考最小角回归法)