当前位置:   article > 正文

Lasso线性回归学习笔记(公式与代码实现)_推导lasso回归模型的梯度、梯度向量

推导lasso回归模型的梯度、梯度向量

Lasso线性回归学习笔记(公式与代码实现)

1 为什么要在线性回归中引入正则化项(简介)

 (主要参考《机器学习》周志华 第三章)

首先,多元线性回归的基本形式为 f ( x ) = w T x + b f(\pmb{x})=\pmb{w}^T\pmb{x}+b f(xxx)=wwwTxxx+b,为便于讨论,把 w \pmb{w} www b b b 吸收入向量形式 w ^ = ( w ; b ) \hat{\pmb{w}}=(\pmb{w};b) www^=(www;b),相应的,把数据集 D D D 表示为一个 m × ( d + 1 ) m\times(d+1) m×(d+1) 大小的矩阵 X \pmb{X} XXX (其中 m m m为样本条数, d d d为特征数),即
X = ( x 11 x 12 ⋯ x 1 d 1 x 21 x 22 ⋯ x 2 d 1 ⋮ ⋮ ⋱ ⋮ ⋮ x m 1 x m 2 ⋯ x m d 1 ) \pmb{X}=\left(

x11x12x1d1x21x22x2d1xm1xm2xmd1
\right) XXX=x11x21xm1x12x22xm2x1dx2dxmd111
再把标记也写成向量形式 y = ( y 1 ; y 2 ; ⋯   ; y m ) y=(y_1;y_2;\cdots;y_m) y=(y1;y2;;ym)
则根据最小二乘法,参数估计值 w ^ ∗ \hat{\pmb{w}}^* www^应该满足
w ^ ∗ = arg min ⁡ w ^ ( y − X w ^ ) T ( y − X w ^ ) \hat{\pmb{w}}^*= {\underset {\hat{w}}{\operatorname {arg\,min} }}(\pmb{y}-\pmb{X}\hat{\pmb{w}})^T(\pmb{y}-\pmb{X}\hat{\pmb{w}}) www^=w^argmin(yyyXXXwww^)T(yyyXXXwww^)
E w ^ = ( y − X w ^ ) T ( y − X w ^ ) E_{\hat{w}}=(\pmb{y}-\pmb{X}\hat{\pmb{w}})^T(\pmb{y}-\pmb{X}\hat{\pmb{w}}) Ew^=(yyyXXXwww^)T(yyyXXXwww^),对 w ^ \hat{\pmb{w}} www^求导得到(相关矩阵求导知识链接

∂ E w ^ ∂ w ^ = 2 X T ( X w ^ − y ) \frac{\partial E_{\hat{w}}}{\partial \hat w}=2\pmb X^T(\pmb X \hat{\pmb{w}}-\pmb y) w^Ew^=2XXXT(XXXwww^yyy)

令上式得零则可得到 w ^ \hat{\pmb{w}} www^ 的最优解,有两种情况:

  • 情况一:当 X T X \pmb X^T \pmb X XXXTXXX 为满秩矩阵时,即可逆,令上式得零,可直接通过移项求的
    w ^ ∗ = ( X T X ) − 1 X T y \hat{\pmb{w}}^*=(\pmb X^T \pmb X)^{-1} \pmb X^T \pmb y www^=(XXXTXXX)1XXXTyyy
  • 情况二:然而现实任务中 X T X \pmb X^T \pmb X XXXTXXX 往往不是满秩矩阵,例如在高维数据中,变量的数目会超过样例数目,导致 X \pmb X XXX 的列数多于行数,而 X T X \pmb X^T \pmb X XXXTXXX 秩等于 X \pmb X XXX 的秩,显然 X T X \pmb X^T \pmb X XXXTXXX 不满秩,此时可解出多个 w ^ \hat{\pmb{w}} www^ (个人参考了《2022张宇线代9讲》P29 矩阵方程),它们都能使均方误差最小化,选择哪一个作为输出,常见的做法是引入正则化(regularization)项。

2 常见正则化

首先介绍常见范数——P-范数 (范数详见百度百科),即
∣ ∣ x ∣ ∣ p = ( ∣ x 1 ∣ p + ∣ x 2 ∣ p + ⋯ + ∣ x n ∣ p ) 1 p ||\pmb x||_p=(|x_1|^p+|x_2|^p+\cdots+|x_n|^p)^{\frac{1}{p}} xxxp=(x1p+x2p++xnp)p1
L1范数正则化项,即令 p p p = 1,并针对参数向量,即为 λ ∣ ∣ w ∣ ∣ 1 \lambda ||\pmb w||_1 λwww1 ,其中 λ \lambda λ 为正则化参数。对于 L1 正则化, λ \lambda λ 越大可以使越多的参数为零或接近零。

类似地,L2范数正则化项为 λ ∣ ∣ w ∣ ∣ 2 2 \lambda ||\pmb w||_2^2 λwww22

3 损失函数图像与正则化之后的图像

(参考文章链接,下面是利用网站GeoGebra画出的函数图像)

3.1损失函数图像

为了可视化,假设一个回归函数及相应的损失函数如下:
回归函数: f ( x i ) = w 1 x i + b f(x_i)=w_1x_i+b f(xi)=w1xi+b
损失函数(均方差): L = 1 m ∑ i = 1 m ( f ( x i ) − y i ) 2 L=\frac{1}{m}\sum\limits_{i=1}^m(f(x_i)-y_i)^2 L=m1i=1m(f(xi)yi)2其中m表示样本量,

为了保持简单,只取一个样本点(1,1)代入上面的代价函数方程中,即 L = ( w 1 + b − 1 ) 2 L=(w_1+b-1)^2 L=(w1+b1)2
以下则是上式的图像

在这里插入图片描述
可以看出,有无穷多个解可以使损失函数达到最小值。根据前面的论证,在只有一个样本点情况下,外加上最后一列是 1,得到的反应数据集 D D D 的矩阵 X \pmb{X} XXX是一行两列, X T X \pmb X^T \pmb X XXXTXXX 不是满秩矩阵,解不唯一,没毛病。

3.2 加了 L1 正则项之后的损失函数图像

加了 L1 正则项之后的损失函数: L = w 1 + b − 1 + ∣ w 1 ∣ L=w_1+b-1+|w_1| L=w1+b1+w1 (令 λ = 1 \lambda=1 λ=1
上式图像为
在这里插入图片描述
可以看出,有唯一最优解了

4 L1 范数正则化的解中有更多零的原因

在这里插入图片描述
(《机器学习》周志华 p253)

经典图片了,不多说了。

5 Lasso 线性回归

就是在损失函数中加入 L1正则化项的线性回归,值得注意的是在测试集中验证预测效果的时候的损失函数是不带正则化项的。

6 Lasso线性回归的优化算法(求最优解)

6.1 梯度下降(Gradient Descent)

- 为什么梯度方向是函数上升最快方向?

(参考:为什么梯度反方向是函数下降最快的方向?、《2022张宇高数18讲(第17讲)》)

首先介绍经典的梯度下降算法。
可能都知道,梯度下降算法的迭代公式是
w ^ k + 1 = w ^ k − η ∂ L ( w ^ k ) ∂ w ^ \hat{\pmb w}^{k+1}=\hat{\pmb w}^k- \eta \frac{\partial L(\hat{\pmb w}^k) } {\partial\hat{ \pmb w}} www^k+1=www^kηwww^L(www^k)
其中 w ^ = ( w ; b ) \hat{\pmb{w}}=(\pmb{w};b) www^=(www;b),而
∂ L ( w ^ k ) ∂ w ^ \frac{\partial L(\hat{\pmb w}^k) }{\partial\hat{ \pmb w}} www^L(www^k)
便是优化目标中的损失函数 L ( w ^ ) L(\hat{\pmb{w}}) L(www^) 的梯度,接下来只要弄清为什么梯度方向是函数上升最快的方向,便就清楚这个式子了。

- 向量的方向角和方向余弦

(1)非零向量 a \pmb a aaa x x x 轴、 y y y 轴、 z z z 轴正向的夹角 α \alpha α β \beta β γ \gamma γ 称为 a \pmb a aaa 的方向角。
(2) c o s α cos\alpha cosα c o s β cos\beta cosβ c o s γ cos\gamma cosγ 称为 a \pmb a aaa 的方向余弦,且 c o s α = a x ∣ a ∣ cos\alpha=\frac{a_x}{|a|} cosα=aax c o s β = a y ∣ a ∣ cos\beta=\frac{a_y}{|a|} cosβ=aay c o s γ = a z ∣ a ∣ cos\gamma=\frac{a_z}{|a|} cosγ=aaz
(3)由(2)可知 a ∣ a ∣ = ( c o s α , c o s β , c o s γ ) \frac{a}{|a|}=(cos\alpha,cos\beta,cos\gamma) aa=(cosαcosβcosγ) 称为向量 a \pmb a aaa 的单位向量
以上基础知识有利于从二元直接向更多元推广。

- 方向导数

要想解决以上疑问,首先要知道方向导数。在许多问题中,不仅要知道函数在坐标轴方向上的变化率(即偏导数),而且还要设法求得函数在某点沿着其他特定方向上的变化率。这就是方向倒数。

  • 首先给出明确定义:(此部分我感觉参考文章写的更好理解,以下定义更精确、好推广)
    设二元函数 u = u ( x , y ) u=u(x,y) u=u(x,y)在点 P 0 ( x 0 , y 0 ) P_0(x_0,y_0) P0(x0,y0) 有定义, l l l 为从 P 0 P_0 P0 出发的射线, P ( x , y ) P(x,y) P(x,y) 为在 l l l 上的任一点,则
    { x − x 0 = Δ x = t c o s α y − y 0 = Δ y = t c o s β \left\{

    xx0=Δx=tcosαyy0=Δy=tcosβ
    \right. {xx0=Δx=tcosαyy0=Δy=tcosβ
    其中 t = ( Δ x ) 2 + ( Δ y ) 2 t=\sqrt{(\Delta x)^2+(\Delta y)^2} t=(Δx)2+(Δy)2 表示 P P P P 0 P_0 P0 之间的距离。
    则极限
    l i m t → 0 + u ( P ) − u ( P 0 ) t = l i m t → 0 + u ( x 0 + t c o s α , y 0 + t c o s β ) − u ( x 0 , y 0 ) t \underset{t\rightarrow 0^+}{lim}\frac{u(P)-u(P_0)}{t} \\ =\underset{t\rightarrow 0^+}{lim}\frac{u(x_0+ t cos\alpha,y_0+ t cos\beta)-u(x_0,y_0)}{t} t0+limtu(P)u(P0)=t0+limtu(x0+tcosα,y0+tcosβ)u(x0,y0)
    此极限便是函数 u u u 在点 P 0 P_0 P0 沿方向 l \pmb l lll 的方向导数,记作
    ∂ u ∂ l ∣ P 0 \frac{\partial u}{\partial \pmb l}|_{P_0} llluP0

  • 方向导数计算公式:设函数 u = u ( x , y ) u=u(x,y) u=u(x,y) 在点 P 0 P_0 P0 点出可微分,则 u u u 在点 P 0 P_0 P0 处沿任意方向 l \pmb l lll 的方向导数都存在,且
    ∂ u ∂ l ∣ P 0 = l i m t → 0 + u ( P ) − u ( P 0 ) t = l i m t → 0 + u ( x 0 + Δ x , y 0 + Δ y ) − u ( x 0 , y 0 ) ( Δ x ) 2 + ( Δ y ) 2 = ∗ l i m t → 0 + u x ′ ( P 0 ) Δ x + u y ′ ( P 0 ) Δ y + o ( t ) ( Δ x ) 2 + ( Δ y ) 2 = u x ′ ( P 0 ) c o s α + u y ′ ( P 0 ) c o s β

    ull|P0=limt0+u(P)u(P0)t=limt0+u(x0+Δx,y0+Δy)u(x0,y0)(Δx)2+(Δy)2=limt0+ux(P0)Δx+uy(P0)Δy+o(t)(Δx)2+(Δy)2=ux(P0)cosα+uy(P0)cosβ
    llluP0====t0+limtu(P)u(P0)t0+lim(Δx)2+(Δy)2 u(x0+Δx,y0+Δy)u(x0,y0)t0+lim(Δx)2+(Δy)2 ux(P0)Δx+uy(P0)Δy+o(t)ux(P0)cosα+uy(P0)cosβ
    其中 c o s α cos\alpha cosα c o s β cos\beta cosβ 为方向 l \pmb l lll 的方向余弦, = ∗ \overset{*}{=} = 部分利用的多元函数的泰勒展开式

-方向导数与梯度的关系

从上式可以看出,方向导数其实就是 梯度 g r a d   u = ( u x ′ , u y ′ ) \pmb{grad} \, u = (u_x^\prime,u_y^\prime) gradgradgradu=(ux,uy) 与 方向余弦组成的单位向量 I = ( c o s α , c o s β ) I=(cos\alpha,cos\beta) I=(cosα,cosβ) 的内积,即
∂ u ∂ l = g r a d   u ⋅ I = ∣ g r a d   u ∣   ∣ I ∣   c o s θ = ∣ g r a d   u ∣   c o s θ \frac{\partial u}{\partial \pmb l}=\pmb{grad} \, u \cdot I=|\pmb{grad} \, u| \, |I| \, cos\theta =|\pmb{grad} \, u| \, cos\theta lllu=gradgradgraduI=gradgradgraduIcosθ=gradgradgraducosθ
其中 θ \theta θ 为两向量之间的夹角。

那么如果此时想让 ∂ u ∂ l \frac{\partial u}{\partial \pmb l} lllu 最大,自然是 θ \theta θ 0 o 0^o 0o 的时候,也就是方向与梯度一致的时候的方向导数最大,即变化率最大且是正的,那么如果沿着该方向前进,可以上升(增加)的最快;同理,如果 θ \theta θ 18 0 o 180^o 180o 的时候,也就是方向与梯度相反的时候的方向导数最小且为负(两者的绝对值相同),那么沿着该方向前进就可以下降(减小)的最快。

【注】以上证明角度最直观好想,对于梯度下降算法的证明还有其他角度,例如在一定条件下直接利用泰勒展开近似目标函数,然后直接求解,得到的就是梯度下降迭代式,在下文中的近端梯度下降其实就利用到了这个思想。

6.2 近端梯度下降(Proximal Gradient Descent)

参考文章(
近端梯度下降法
《机器学习》(周志华)P253,
《机器学习公式详解》(俗称南瓜书)P122(pdf页数),
矩阵微分与向量函数泰勒展开

近端梯度下降法是众多梯度下降 (gradient descent) 方法中的一种,将proximal翻译成“近端”可能是想表达 “接近,近似” 的意思,但在这点上,经典梯度算法其实也是近似的。与经典的梯度下降法相比,近端梯度下降法 主要是想解决目标函数中存在不可微或不方便微分的部分。如对于凸优化问题,当其目标函数存在 L1正则化项,近端梯度下降法就会派上用场。
(个人理解:其实就是在经典梯度下降的基础上,最后用分段函数的方法对L1正则化项求导)

具体来说,设优化目标
m i n   f ( x ) + λ ∣ ∣ x ∣ ∣ 1 min \, f(\pmb x)+\lambda ||\pmb x||_1 minf(xxx)+λxxx1
∇ \nabla 表示微分算子, ∇ f ( x ) \nabla f(\pmb x) f(xxx) 即为 ∂ f ( x ) ∂ x \frac{\partial f(x)}{\partial x} xf(x) x x x 为向量,粗的打不出来了)

- 大致思想

(1)在一定条件下,通过泰勒展开式将目标函数可微的部分化简
(2)以分段函数的形式,对 ∣ ∣ x ∣ ∣ 1 ||\pmb x||_1 xxx1 求导,令导数得零,最后自然得到了分段函数形式的迭代公式 (加粗的是向量)。

- 推导过程


L-Lipschitz 条件简介:它是一个比“连续”更强的光滑性条件.直觉上,利普希茨连续函数限制了函数改变的速度,符合利普希茨条件的函数的斜率,必小于一个称为利普希茨常数的实数 L(该常数依函数而定,在梯度下降中,可以将此参数理解为学习率 η \eta η 的倒数,在训练中应该自己给出)(以上仅为个人理解,详见百度百科

f ( x ) f(\pmb x) f(xxx) 可导,且 ∇ f ( x ) \nabla f(\pmb x) f(xxx)满足 L-Lipschitz 条件,即存在常数 L > 0 L>0 L>0 使得
∣ ∇ f ( x ′ ) − ∇ f ( x ) ∣ ∣ x ′ − x ∣ ≤ L \frac{|\nabla f(\pmb x^\prime)-\nabla f(\pmb x)|}{|\pmb x^\prime-\pmb x|} \leq L xxxxxxf(xxx)f(xxx)L
(上式可看成是 f ( x ) f(\pmb x) f(xxx) 的二阶导数恒不大于 L L L ,即 ∇ 2 f ( x ) ≤ L \nabla^2 f(\pmb x) \leq L 2f(xxx)L )
则在 x k x_k xk 附近可将 f ( x ) f(x) f(x) 通过二阶泰勒展开式近似为
f ( x ) ^ ≈ f ( x k ) + ( ∇ f ( x k ) , ( x − x k ) ) + ∇ 2 f ( x k ) 2 ∣ ∣ x − x k ∣ ∣ 2 2 ≤ f ( x k ) + ( ∇ f ( x k ) , ( x − x k ) ) + L 2 ∣ ∣ x − x k ∣ ∣ 2 2 = L 2 ∣ ∣ x − ( x k − 1 L ∇ f ( x k ) ) ∣ ∣ 2 2 + c o n s t

f(xx)^f(xxk)+(f(xxk),(xxxxk))+2f(xk)2||xxxxk||22f(xxk)+(f(xxk),(xxxxk))+L2||xxxxk||22=L2||xx(xxk1Lf(xxk))||22+const
f(xxx)^=f(xxxk)+(f(xxxk),(xxxxxxk))+22f(xk)xxxxxxk22f(xxxk)+(f(xxxk),(xxxxxxk))+2Lxxxxxxk222Lxxx(xxxkL1f(xxxk))22+const
其中 c o n s t const const 是与 x \pmb x xxx 无关的常数(后续的求解过程也是求导,就直接忽略了,上述具体推导过程参见《机器学习公式详解》(俗称南瓜书)第11章)
也就是说在 x k \pmb x_k xxxk 附近可将目标函数进行简化,那么问题可转化为在这个小范围内寻找可使目标函数最小的 x k + 1 \pmb x_{k+1} xxxk+1,然后再进行迭代(对于经典梯度下降算法来说,其实也是这么个思想),即
x k + 1 = a r g   m i n x L 2 ∣ ∣ x − ( x k − 1 L ∇ f ( x k ) ) ∣ ∣ 2 2 + λ ∣ ∣ x ∣ ∣ 1 \pmb x_{k+1}=\underset{x}{arg\,min}\frac{L}{2}||\pmb x- (\pmb x_k-\frac{1}{L} \nabla f(\pmb x_k))||_2^2 + \lambda||\pmb x||_1 xxxk+1=xargmin2Lxxx(xxxkL1f(xxxk))22+λxxx1
x i x^i xi 表示 x \pmb x xxx 的第 i i i 个分量,将上式按分量展开可看出,其中不存在 x i x j ( i ≠ j ) x^ix^j(i \neq j) xixj(i=j) 这样的项,也就是说各分量直间互不影响,假设只有一个分量 x 1 x^1 x1 带入展开,求导,令导得零,便可以求得这个小范围内的最小值点,推广可得上式解为:
可先计算 z = x k − 1 L ∇ f ( x k ) \pmb z=\pmb x_k-\frac{1}{L} \nabla f(\pmb x_k) zzz=xxxkL1f(xxxk)
x k + 1 i = { z i − λ / L , λ / L < z i 0 , ∣ z i ∣ ≤ λ / L z i + λ / L , z i < − λ / L x_{k+1}^i= \left\{
ziλ/L,λ/L<zi0,|zi|λ/Lzi+λ/L,zi<λ/L
\right.
xk+1i=zi0ziλ/L,,+λ/L,λ/Lzizi<ziλ/L<λ/L

(如果不考虑 L1 正则化项,该步骤得解就是 经典梯度下降 的迭代公式)

7 代码实现

import numpy as np

# 导入数据
filepath = "D:\\机器学习\\housing.csv"
data = np.loadtxt(filepath, delimiter=',', skiprows=1, encoding='utf-8')
# 选择特征与标签
x = data[0:20, 1:]
y = data[0:20, 0]
# 加一列
X = np.column_stack((x, np.ones((x.shape[0], 1))))
# 划分训练集与测试集
X_train, y_train = x[:10], y[:10]
X_test, y_test = x[10:], y[10:]

print(X_train.shape, y_train.shape, X_test.shape, y_test.shape)


# 定义初始化参数
def initialize(dims):
    w = np.zeros((dims))
    return w


# 在 MSE 基础上定义 Lasso 损失函数值

def l1_loss(X, y, w, lambda_):
    num_train = X.shape[0]
    y_hat = np.dot(X, w)
    loss = np.sum((y_hat - y) ** 2) / num_train + np.sum(lambda_ * abs(w))

    return y_hat, loss, num_train


# 定义训练过程

def lasso_train(X, y, learn_rate=50, lambda_=50, epochs=300):
    loss_list = []
    w = initialize(X.shape[1])
    temporary_para = lambda_ * learn_rate

    for i in range(epochs):
        y_hat, loss, num_train = l1_loss(X, y, w, lambda_)
        z = w - learn_rate * (np.dot(X.T, (y_hat - y)) * 2 / num_train)
        a = np.dot(X.T, (y_hat - y))
        b = X.T
        c = (y_hat - y)
        y_hat[0]

        w_list = []
        for z_i in z:
            if z_i > temporary_para:
                w_i = z_i - temporary_para

            elif z_i < temporary_para:
                w_i = z_i + temporary_para

            else:
                w_i = 0

            w_list.append(w_i)

        w = np.array(w_list)
        loss_list.append(loss)

        if i % 50 == 0:
            print('epoch %d loss %f' % (i, loss))
        params = w

    return loss, loss_list, params


loss, loss_list, params = lasso_train(X,
                                      y,
                                      learn_rate=50,
                                      lambda_=50,
                                      epochs=300)


  • 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
本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/598938
推荐阅读
  

闽ICP备14008679号