LASSO回归

阅读本文需要的背景知识点:线性回归算法、一丢丢编程知识

一、引言

  上一节我们学习了解决多重共线性的一种方法是对代价函数正则化,其中一种正则化的算法叫岭回归算法(Ridge Regression Algorithm)。下面我们来学习另一种正则化的算法 - Lasso回归算法1(Lasso Regression Algorithm),LASSO的完整名称叫最小绝对值收敛和选择算子算法(least absolute shrinkage and selection operator)。

二、模型介绍

  先来回顾一下岭回归的代价函数,在原来标准线性回归代价函数上加上了一个带惩罚系数 λ 的 w 向量的 L2-范数的平方:

Cost ⁡ ( w ) = ∑ i = 1 N ( y i − w T x i ) 2 + λ ∥ w ∥ 2 2 \operatorname{Cost}(w) = \sum_{i = 1}^N \left( y_i - w^Tx_i \right)^2 + \lambda\|w\|_{2}^{2}

Cost(w)=

i=1

N

(y

i

−w

T

x

i

)

2

+λ∥w∥

2

2

  Lasso回归算法也同岭回归一样加上了正则项,只是改成加上了一个带惩罚系数 λ 的 w 向量的 L1-范数作为惩罚项(L1-范数的含义为向量 w 每个元素绝对值的和),所以这种正则化方式也被称为L1正则化。

Cost ⁡ ( w ) = ∑ i = 1 N ( y i − w T x i ) 2 + λ ∥ w ∥ 1 \operatorname{Cost}(w) = \sum_{i = 1}^N \left( y_i - w^Tx_i \right)^2 + \lambda\|w\|_1

Cost(w)=

i=1

N

(y

i

−w

T

x

i

)

2

+λ∥w∥

1

  同样是求使得代价函数最小时 w 的大小:

w = argmin ⁡ w ( ∑ i = 1 N ( y i − w T x i ) 2 + λ ∥ w ∥ 1 ) w = \underset{w}{\operatorname{argmin}}\left(\sum_{i = 1}^N \left( y_i - w^Tx_i \right)^2 + \lambda\|w\|_1\right)

w=

w

argmin

(

i=1

N

(y

i

−w

T

x

i

)

2

+λ∥w∥

1

)

  由于加入的是向量的 L1-范数,其中存在绝对值,导致其代价函数不是处处可导的,所以就没办法通过直接求导的方式来直接得到 w 的解析解。下面介绍两种求解权重系数 w 的方法:坐标下降法2(coordinate descent)、最小角回归法3(Least Angle Regression,LARS)

三、算法步骤

坐标下降法:

  坐标下降法的核心与它的名称一样,就是沿着某一个坐标轴方向,通过一次一次的迭代更新权重系数的值,来渐渐逼近最优解。

  具体步骤:

(1)初始化权重系数 w,例如初始化为零向量。

(2)遍历所有权重系数,依次将其中一个权重系数当作变量,其他权重系数固定为上一次计算的结果当作常量,求出当前条件下只有一个权重系数变量的情况下的最优解。

  在第 k 次迭代时,更新权重系数的方法如下:

w m k 表 示 第 k 次 迭 代 , 第 m 个 权 重 系 数 w 1 k = argmin ⁡ w 1 ( Cost ⁡ ( w 1 , w 2 k − 1 , … , w m − 1 k − 1 , w m k − 1 ) ) w 2 k = argmin ⁡ w 2 ( Cost ⁡ ( w 1 k , w 2 , … , w m − 1 k − 1 , w m k − 1 ) ) ⋮ w m k = argmin ⁡ w m ( Cost ⁡ ( w 1 k , w 2 k , … , w m − 1 k , w m ) )

wkm表示第k次迭代,第m个权重系数wk1=argminw1(Cost(w1,wk−12,…,wk−1m−1,wk−1m))wk2=argminw2(Cost(wk1,w2,…,wk−1m−1,wk−1m))⋮wkm=argminwm(Cost(wk1,wk2,…,wkm−1,wm))

wmk表示第k次迭代,第m个权重系数w1k=argminw1(Cost⁡(w1,w2k−1,…,wm−1k−1,wmk−1))w2k=argminw2(Cost⁡(w1k,w2,…,wm−1k−1,wmk−1))⋮wmk=argminwm(Cost⁡(w1k,w2k,…,wm−1k,wm))

w

m

k

表示第k次迭代,第m个权重系数

w

1

k

=

w

1

argmin

(Cost(w

1

,w

2

k−1

,…,w

m−1

k−1

,w

m

k−1

))

w

2

k

=

w

2

argmin

(Cost(w

1

k

,w

2

,…,w

m−1

k−1

,w

m

k−1

))

w

m

k

=

w

m

argmin

(Cost(w

1

k

,w

2

k

,…,w

m−1

k

,w

m

))

(3)步骤(2)为一次完整迭代,当所有权重系数的变化不大或者到达最大迭代次数时,结束迭代。

By Nicoguaro - Own work

  如上图所示,每次迭代固定其他的权重系数,只朝着其中一个坐标轴的方向更新,最后到达最优解。

最小角回归法:

  最小角回归法是一种特征选择的方法,计算出每个特征的相关性,通过数学公式逐渐计算出最优解。

  具体步骤:

(1)初始化权重系数 w,例如初始化为零向量。

(2)初始化残差向量 residual 为目标标签向量 y − X w y - Xwy−Xw,由于此时 w 为零向量,所以残差向量等于目标标签向量 y

(3)选择一个与残差向量相关性最大的特征向量 x i x_ix

i

,沿着特征向量 x i x_ix

i

  的方向找到一组权重系数 w,出现另一个与残差向量相关性最大的特征向量 x j x_jx

j

  使得新的残差向量 residual 与这两个特征向量的相关性相等(即残差向量等于这两个特征向量的角平分向量上),重新计算残差向量。

(4)重复步骤(3),继续找到一组权重系数 w,使得第三个与残差向量相关性最大的特征向量 x k x_kx

k

  使得新的残差向量 residual 与这三个特征向量的相关性相等(即残差向量等于这三个特征向量的等角向量上),以此类推。

(5)当残差向量 residual 足够小或者所有特征向量都已被选择,结束迭代。

Least Angle Regression - Figure 2

  上图演示了只有两个特征向量时的情况,初始残差向量为 y 2 y_2y

2

,其中 x 1 x_1x

1

  向量与残差向量的相关性最大(向量夹角最小),找到一个 θ 11 θ_{11}θ

11

  使得新的残差向量 y 2 − x 1 ∗ θ 11 y_2 - x_1 * θ_{11}y

2

−x

1

∗θ

11

  是 x 1 x_1x

1

  和 x 2 x_2x

2

  的角平分线(图中为 u 2 u_2u

2

),此时 w 1 = θ 11 w_1 = θ_{11}w

1

11

, w 2 = 0 w_2 = 0w

2

=0。最后找到一组 θ 21 θ_{21}θ

21

,θ 22 θ_{22}θ

22

  使得新的残差向量 y 2 − x 1 ∗ θ 11 − ( x 1 ∗ θ 21 + x 2 ∗ θ 22 ) y_2 - x_1 * θ_{11} - (x_1 * θ_{21} + x_2 * θ_{22})y

2

−x

1

∗θ

11

−(x

1

∗θ

21

+x

2

∗θ

22

) 尽可能小, 此时 w 1 = θ 11 + θ 21 w_1 = θ_{11} + θ_{21}w

1

11

21

,w 2 = θ 22 w_2 = θ_{22}w

2

22

。所有特征向量都已被选择,所以结束迭代。

  坐标下降法相对最小角回归法相对好理解一些,每次只需要关心一个权重系数即可。最小角回归法则是通过一些巧妙的数学公式减少了迭代次数,使其的最坏计算复杂度和最小二乘法类似。

四、原理证明

Lasso回归代价函数为凸函数

  同样需要证明:

f ( x 1 + x 2 2 ) ≤ f ( x 1 ) + f ( x 2 ) 2 f\left(\frac{x_{1}+x_{2}}{2}\right) \leq \frac{f\left(x_{1}\right)+f\left(x_{2}\right)}{2}

f(

2

x

1

+x

2

)≤

2

f(x

1

)+f(x

2

)

  不等式左边:

Cost ⁡ ( w 1 + w 2 2 ) = ∑ i = 1 N [ ( w 1 + w 2 2 ) T x i − y i ] 2 + λ ∥ w 1 + w 2 2 ∥ 1 \operatorname{Cost}\left(\frac{w_{1}+w_{2}}{2}\right)=\sum_{i=1}^{N}\left[\left(\frac{w_{1}+w_{2}}{2}\right)^{T} x_{i}-y_{i}\right]^{2}+\lambda\left\|\frac{w_{1}+w_{2}}{2}\right\|_{1}

Cost(

2

w

1

+w

2

)=

i=1

N

[(

2

w

1

+w

2

)

T

x

i

−y

i

]

2


2

w

1

+w

2



1

  不等式右边:

Cost ⁡ ( w 1 ) + Cost ⁡ ( w 2 ) 2 = ∑ i = 1 N ( w 1 T x i − y i ) 2 + ∑ i = 1 N ( w 2 T x i − y i ) 2 + λ ∥ w 1 ∥ 1 + λ ∥ w 2 ∥ 1 2 \frac{\operatorname{Cost}\left(w_{1}\right)+\operatorname{Cost}\left(w_{2}\right)}{2}=\frac{\sum_{i=1}^{N}\left(w_{1}^{T} x_{i}-y_{i}\right)^{2}+\sum_{i=1}^{N}\left(w_{2}^{T} x_{i}-y_{i}\right)^{2}+\lambda\left\|w_{1}\right\|_{1}+\lambda\left\|w_{2}\right\|_{1}}{2}

2

Cost(w

1

)+Cost(w

2

)

=

2

i=1

N

(w

1

T

x

i

−y

i

)

2

+∑

i=1

N

(w

2

T

x

i

−y

i

)

2

+λ∥w

1

1

+λ∥w

2

1

(1)不等式两边的前半部分与标准线性回归一致,只需要证明剩下的差值大于等于零即可

(2)根据向量范数的正齐次性,常数项系数可以乘进去

(3)将 λ 提到括号外

(4)根据向量范数的定义,满足三角不等式,必然是大于等于零

Δ = λ ∥ w 1 ∥ 1 + λ ∥ w 2 ∥ 1 − 2 λ ∥ w 1 + w 2 2 ∥ 1 ( 1 ) = λ ∥ w 1 ∥ 1 + λ ∥ w 2 ∥ 1 − λ ∥ w 1 + w 2 ∥ 1 ( 2 ) = λ ( ∥ w 1 ∥ 1 + ∥ w 2 ∥ 1 − ∥ w 1 + w 2 ∥ 1 ) ( 3 ) ≥ 0 ( 4 )

Δ=λ∥w1∥1+λ∥w2∥1−2λ∥∥∥w1+w22∥∥∥1=λ∥w1∥1+λ∥w2∥1−λ∥w1+w2∥1=λ(∥w1∥1+∥w2∥1−∥w1+w2∥1)≥0(1)(2)(3)(4)

Δ=λ‖w1‖1+λ‖w2‖1−2λ‖w1+w22‖1(1)=λ‖w1‖1+λ‖w2‖1−λ‖w1+w2‖1(2)=λ(‖w1‖1+‖w2‖1−‖w1+w2‖1)(3)≥0(4)

Δ


=λ∥w

1

1

+λ∥w

2

1

−2λ


2

w

1

+w

2



1

=λ∥w

1

1

+λ∥w

2

1

−λ∥w

1

+w

2

1

=λ(∥w

1

1

+∥w

2

1

−∥w

1

+w

2

1

)

≥0


(1)

(2)

(3)

(4)

人为的控制 λ 的大小,最后的结果在实数范围内必然大于等于零,证毕。

最小回归法数学公式

  求单位角平分向量:

(1)设单位角平分向量为 u A u_Au

A

,可以将其看成选中的特征向量的线性组合,下标 A 表示选中的特征的序号集合

(2)由于每个选中的特征向量与角平分向量的夹角都相同,所以特征向量与角平分向量的点积后的向量每一个元素必然相同,1 A 1_A1

A

  为元素都为 1 的向量,z 为常数

(3)根据(2)式可以表示出线性组合的系数向量 ω A ω_Aω

A

u A = X A ω A ( 1 ) X A T u A = X A T X A ω A = z 1 A ( 2 ) ω A = z ( X A T X A ) − 1 1 A ( 3 )

uA=XAωAXTAuA=XTAXAωA=z1AωA=z(XTAXA)−11A(1)(2)(3)

uA=XAωA(1)XATuA=XATXAωA=z1A(2)ωA=z(XATXA)−11A(3)


u

A

=X

A

ω

A

X

A

T

u

A

=X

A

T

X

A

ω

A

=z1

A

ω

A

=z(X

A

T

X

A

)

−1

1

A


(1)

(2)

(3)

(1)角平分向量 u A u_Au

A

  为单位向量,所以长度为 1

(2)改写成向量的形式

(3)带入上一步的线性组合的系数向量 ω A ω_Aω

A

(4)根据转置的性质第一项的括号可以化简,提出常数 z

(5)矩阵乘以其逆矩阵为单位矩阵,所以可以化简

(6)最后解得常数 z 的表达式

∥ u A ∥ 2 = 1 ( 1 ) ω A T X A T X A ω A = 1 ( 2 ) ( z ( X A T X A ) − 1 1 A ) T X A T X A z ( X A T X A ) − 1 1 A = 1 ( 3 ) z 2 1 A T ( X A T X A ) − 1 ( X A T X A ) ( X A T X A ) − 1 1 A = 1 ( 4 ) z 2 1 A T ( X A T X A ) − 1 1 A = 1 ( 5 ) z = 1 1 A T ( X A T X A ) − 1 1 A = ( 1 A T ( X A T X A ) − 1 1 A ) − 1 2 ( 6 )

∥uA∥2=1ωTAXTAXAωA=1(z(XTAXA)−11A)TXTAXAz(XTAXA)−11A=1z21TA(XTAXA)−1(XTAXA)(XTAXA)−11A=1z21TA(XTAXA)−11A=1z=11TA(XTAXA)−11A−−−−−−−−−−−−−√=(1TA(XTAXA)−11A)−12(1)(2)(3)(4)(5)(6)

‖uA‖2=1(1)ωATXATXAωA=1(2)(z(XATXA)−11A)TXATXAz(XATXA)−11A=1(3)z21AT(XATXA)−1(XATXA)(XATXA)−11A=1(4)z21AT(XATXA)−11A=1(5)z=11AT(XATXA)−11A=(1AT(XATXA)−11A)−12(6)


∥u

A

2

=1

ω

A

T

X

A

T

X

A

ω

A

=1

(z(X

A

T

X

A

)

−1

1

A

)

T

X

A

T

X

A

z(X

A

T

X

A

)

−1

1

A

=1

z

2

1

A

T

(X

A

T

X

A

)

−1

(X

A

T

X

A

)(X

A

T

X

A

)

−1

1

A

=1

z

2

1

A

T

(X

A

T

X

A

)

−1

1

A

=1

z=


1

A

T

(X

A

T

X

A

)

−1

1

A

1

=(1

A

T

(X

A

T

X

A

)

−1

1

A

)

2

1


(1)

(2)

(3)

(4)

(5)

(6)

(1)将特征向量的转置乘以特征向量用 G A G_AG

A

  表示

(2)带入 G A G_AG

A

,得到 z 的表达式

(3)带入 G A G_AG

A

  ,得到 ω A ω_Aω

A

  的表达式

G A = X A T X A ( 1 ) z = ( 1 A T ( G A ) − 1 1 A ) − 1 2 ( 2 ) ω A = z ( G A ) − 1 1 A ( 3 )

GA=XTAXAz=(1TA(GA)−11A)−12ωA=z(GA)−11A(1)(2)(3)

GA=XATXA(1)z=(1AT(GA)−11A)−12(2)ωA=z(GA)−11A(3)


G

A

=X

A

T

X

A

z=(1

A

T

(G

A

)

−1

1

A

)

2

1

ω

A

=z(G

A

)

−1

1

A


(1)

(2)

(3)

  将 X A X_AX

A

  乘以 ω A ω_Aω

A

  ,就得到了角平分向量 u A u_Au

A

  的表达式,这样就可以求出单位角平分向量。更加详细的证明请参考 Bradley Efron 的论文4。

  求角平分向量的长度:

(1)μ A μ_Aμ

A

  表示当前预测值,沿着角平分向量的方向更新一个 γ 长度

(2)C 表示特征向量与残差向量的相关性,为两个向量的点积,带入(1)式,得到相关性的更新表达式

(3)当特征向量为被选中的特征向量时,由于每个特征向量与角平分向量的乘积都相同,都等于 z

(4)计算每个特征向量与角平分向量的乘积

(5)当特征向量不是被选中的特征向量时,使用 a 来带入(2)式

(6)要想加入下一个特征向量,则(3)式与(5)式的绝对值必然相等,才能保证下一次更新后的相关性也是相同的

(7)解得 γ 的表达式

μ A + = μ A + γ u A ( 1 ) C + = X T ( y − μ A + ) = X T ( y − μ A − γ u A ) = C − γ X T u A ( 2 ) C + = C − γ z ( j ∈ A ) ( 3 ) a = X T u A ( 4 ) C + = C j − γ a j ( j ∉ A ) ( 5 ) ∣ C − γ z ∣ = ∣ C − γ a j ∣ ( 6 ) γ = min ⁡ j ∉ A + { C − C j z − a j , C + C j z + a j } ( 7 )

μA+=μA+γuAC+=XT(y−μA+)=XT(y−μA−γuA)=C−γXTuAC+=C−γz(j∈A)a=XTuAC+=Cj−γaj(j∉A)|C−γz|=|C−γaj|γ=minj∉A+{C−Cjz−aj,C+Cjz+aj}(1)(2)(3)(4)(5)(6)(7)

μA+=μA+γuA(1)C+=XT(y−μA+)=XT(y−μA−γuA)=C−γXTuA(2)C+=C−γz(j∈A)(3)a=XTuA(4)C+=Cj−γaj(j∉A)(5)|C−γz|=|C−γaj|(6)γ=minj∉A+{C−Cjz−aj,C+Cjz+aj}(7)


μ

A

+

A

+γu

A

C

+

=X

T

(y−μ

A

+

)=X

T

(y−μ

A

−γu

A

)=C−γX

T

u

A

C

+

=C−γz(j∈A)

a=X

T

u

A

C

+

=C

j

−γa

j

(j∈

/

A)

∣C−γz∣=∣C−γa

j

γ=

j∈

/

A

min

+

{

z−a

j

C−C

j

,

z+a

j

C+C

j

}


(1)

(2)

(3)

(4)

(5)

(6)

(7)

  这样就求出了 γ 的表达式,也就是角平分向量的长度。更加详细的证明请参考 Bradley Efron 的论文4。

五、代码实现

使用 Python 实现Lasso回归算法(坐标下降法):

def lassoUseCd(X, y, lambdas=0.1, max_iter=1000, tol=1e-4):

    """

    Lasso回归,使用坐标下降法(coordinate descent)

    args:

        X - 训练数据集

        y - 目标标签值

        lambdas - 惩罚项系数

        max_iter - 最大迭代次数

        tol - 变化量容忍值

    return:

        w - 权重系数

    """

    # 初始化 w 为零向量

    w = np.zeros(X.shape[1])

    for it in range(max_iter):

        done = True

        # 遍历所有自变量

        for i in range(0, len(w)):

            # 记录上一轮系数

            weight = w[i]

            # 求出当前条件下的最佳系数

            w[i] = down(X, y, w, i, lambdas)

            # 当其中一个系数变化量未到达其容忍值,继续循环

            if (np.abs(weight - w[i]) > tol):

                done = False

        # 所有系数都变化不大时,结束循环

        if (done):

            break

    return w

def down(X, y, w, index, lambdas=0.1):

    """

    cost(w) = (x1 * w1 + x2 * w2 + ... - y)^2 + ... + λ(|w1| + |w2| + ...)

    假设 w1 是变量,这时其他的值均为常数,带入上式后,其代价函数是关于 w1 的一元二次函数,可以写成下式:

    cost(w1) = (a * w1 + b)^2 + ... + λ|w1| + c (a,b,c,λ 均为常数)

    => 展开后

    cost(w1) = aa * w1^2 + 2ab * w1 + λ|w1| + c (aa,ab,c,λ 均为常数)

    """

    # 展开后的二次项的系数之和

    aa = 0

    # 展开后的一次项的系数之和

    ab = 0

    for i in range(X.shape[0]):

        # 括号内一次项的系数

        a = X[i][index]

        # 括号内常数项的系数

        b = X[i][:].dot(w) - a * w[index] - y[i]

        # 可以很容易的得到展开后的二次项的系数为括号内一次项的系数平方的和

        aa = aa + a * a

        # 可以很容易的得到展开后的一次项的系数为括号内一次项的系数乘以括号内常数项的和

        ab = ab + a * b

    # 由于是一元二次函数,当导数为零时,函数值最小值,只需要关注二次项系数、一次项系数和 λ

    return det(aa, ab, lambdas)

def det(aa, ab, lambdas=0.1):

    """

    通过代价函数的导数求 w,当 w = 0 时,不可导

    det(w) = 2aa * w + 2ab + λ = 0 (w > 0)

    => w = - (2 * ab + λ) / (2 * aa)

    det(w) = 2aa * w + 2ab - λ = 0 (w < 0)

    => w = - (2 * ab - λ) / (2 * aa)

    det(w) = NaN (w = 0)

    => w = 0

    """

    w = - (2 * ab + lambdas) / (2 * aa)

    if w < 0:

        w = - (2 * ab - lambdas) / (2 * aa)

        if w > 0:

            w = 0

    return w

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

使用 Python 实现Lasso回归算法(最小角回归法):

def lassoUseLars(X, y, lambdas=0.1, max_iter=1000):

    """

    Lasso回归,使用最小角回归法(Least Angle Regression)

    论文:https://web.stanford.edu/~hastie/Papers/LARS/LeastAngle_2002.pdf

    args:

        X - 训练数据集

        y - 目标标签值

        lambdas - 惩罚项系数

        max_iter - 最大迭代次数

    return:

        w - 权重系数

    """

    n, m = X.shape

    # 已被选择的特征下标

    active_set = set()

    # 当前预测向量

    cur_pred = np.zeros((n,), dtype=np.float32)

    # 残差向量

    residual = y - cur_pred

    # 特征向量与残差向量的点积,即相关性

    cur_corr = X.T.dot(residual)

    # 选取相关性最大的下标

    j = np.argmax(np.abs(cur_corr), 0)

    # 将下标添加至已被选择的特征下标集合

    active_set.add(j)

    # 初始化权重系数

    w = np.zeros((m,), dtype=np.float32)

    # 记录上一次的权重系数

    prev_w = np.zeros((m,), dtype=np.float32)

    # 记录特征更新方向

    sign = np.zeros((m,), dtype=np.int32)

    sign[j] = 1

    # 平均相关性

    lambda_hat = None

    # 记录上一次平均相关性

    prev_lambda_hat = None

    for it in range(max_iter):

        # 计算残差向量

        residual = y - cur_pred

        # 特征向量与残差向量的点积

        cur_corr = X.T.dot(residual)

        # 当前相关性最大值

        largest_abs_correlation = np.abs(cur_corr).max()

        # 计算当前平均相关性

        lambda_hat = largest_abs_correlation / n

        # 当平均相关性小于λ时,提前结束迭代

        # https://github.com/scikit-learn/scikit-learn/blob/2beed55847ee70d363bdbfe14ee4401438fba057/sklearn/linear_model/_least_angle.py#L542

        if lambda_hat <= lambdas:

            if (it > 0 and lambda_hat != lambdas):

                ss = ((prev_lambda_hat - lambdas) / (prev_lambda_hat - lambda_hat))

                # 重新计算权重系数

                w[:] = prev_w + ss * (w - prev_w)

            break

        # 更新上一次平均相关性

        prev_lambda_hat = lambda_hat

        # 当全部特征都被选择,结束迭代

        if len(active_set) > m:

            break

        # 选中的特征向量

        X_a = X[:, list(active_set)]

        # 论文中 X_a 的计算公式 - (2.4)

        X_a *= sign[list(active_set)]

        # 论文中 G_a 的计算公式 - (2.5)

        G_a = X_a.T.dot(X_a)

        G_a_inv = np.linalg.inv(G_a)

        G_a_inv_red_cols = np.sum(G_a_inv, 1)   

        # 论文中 A_a 的计算公式 - (2.5)

        A_a = 1 / np.sqrt(np.sum(G_a_inv_red_cols))

        # 论文中 ω 的计算公式 - (2.6)

        omega = A_a * G_a_inv_red_cols

        # 论文中角平分向量的计算公式 - (2.6)

        equiangular = X_a.dot(omega)

        # 论文中 a 的计算公式 - (2.11)

        cos_angle = X.T.dot(equiangular)

        # 论文中的 γ

        gamma = None

        # 下一个选择的特征下标

        next_j = None

        # 下一个特征的方向

        next_sign = 0

        for j in range(m):

            if j in active_set:

                continue

            # 论文中 γ 的计算方法 - (2.13)

            v0 = (largest_abs_correlation - cur_corr[j]) / (A_a - cos_angle[j]).item()

            v1 = (largest_abs_correlation + cur_corr[j]) / (A_a + cos_angle[j]).item()

            if v0 > 0 and (gamma is None or v0 < gamma):

                gamma = v0

                next_j = j

                next_sign = 1

            if v1 > 0 and (gamma is None or v1 < gamma):

                gamma = v1

                next_j = j

                next_sign = -1

        if gamma is None:

            # 论文中 γ 的计算方法 - (2.21)

            gamma = largest_abs_correlation / A_a

        # 选中的特征向量

        sa = X_a

        # 角平分向量

        sb = equiangular * gamma

        # 解线性方程(sa * sx = sb)

        sx = np.linalg.lstsq(sa, sb)

        # 记录上一次的权重系数

        prev_w = w.copy()

        d_hat = np.zeros((m,), dtype=np.int32)

        for i, j in enumerate(active_set):

            # 更新当前的权重系数

            w[j] += sx[0][i] * sign[j]

            # 论文中 d_hat 的计算方法 - (3.3)

            d_hat[j] = omega[i] * sign[j]

        # 论文中 γ_j 的计算方法 - (3.4)

        gamma_hat = -w / d_hat

        # 论文中 γ_hat 的计算方法 - (3.5)

        gamma_hat_min = float("+inf")

        # 论文中 γ_hat 的下标

        gamma_hat_min_idx = None

        for i, j in enumerate(gamma_hat):

            if j <= 0:

                continue

            if gamma_hat_min > j:

                gamma_hat_min = j

                gamma_hat_min_idx = i

        if gamma_hat_min < gamma:

            # 更新当前预测向量 - (3.6)

            cur_pred = cur_pred + gamma_hat_min * equiangular

            # 将下标移除至已被选择的特征下标集合

            active_set.remove(gamma_hat_min_idx)

            # 更新特征更新方向集合

            sign[gamma_hat_min_idx] = 0

        else:

            # 更新当前预测向量

            cur_pred = X.dot(w)

            # 将下标添加至已被选择的特征下标集合

            active_set.add(next_j)

            # 更新特征更新方向集合

            sign[next_j] = next_sign

    return w

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

六、第三方库实现

scikit-learn6 实现(坐标下降法):

from sklearn.linear_model import Lasso

# 初始化Lasso回归器,默认使用坐标下降法

reg = Lasso(alpha=0.1, fit_intercept=False)

# 拟合线性模型

reg.fit(X, y)

# 权重系数

w = reg.coef_

1

2

3

4

5

6

7

8

scikit-learn7 实现(最小角回归法):

from sklearn.linear_model import LassoLars

# 初始化Lasso回归器,使用最小角回归法

reg = LassoLars(alpha=0.1, fit_intercept=False)

# 拟合线性模型

reg.fit(X, y)

# 权重系数

w = reg.coef_

1

2

3

4

5

6

7

8

七、示例演示

  下面动图展示了前面一节的工作年限与平均月工资的例子,每次只朝这坐标轴的一个方向改变权重系数,逐渐逼近最优解的过程。

坐标下降法

  下面动图展示了 λ 对各个自变量权重系数的影响,横轴为惩罚系数 λ ,纵轴为权重系数,每一个颜色表示一个自变量的权重系数(训练数据来源于sklearn diabetes datasets):

λ 对权重系数的影响

  可以看到当 λ 逐渐增大时( λ 向左移动),某些特征的权重系数会快速变成零,通过这个性质说明Lasso 回归可以用来做特征选择,控制 λ 的大小来选择出关键特征。

————————————————

版权声明:本文为CSDN博主「Saisimonzs」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/sai_simon/article/details/122359015

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容