目录

  • Lasso线性回归学习笔记(公式与代码实现)
  • 1 为什么要在线性回归中引入正则化项(简介)
  • 2 常见正则化项
  • 3 损失函数图像与正则化之后的图像
  • 3.1损失函数图像
  • 3.2 加了 L~1~ 正则项之后的损失函数图像
  • 4 L~1~ 范数正则化的解中有更多零的原因
  • 5 Lasso 线性回归
  • 6 Lasso线性回归的优化算法(求最优解)
  • 6.1 梯度下降(Gradient Descent)
  • - 为什么梯度方向是函数上升最快方向?
  • - 向量的方向角和方向余弦
  • - 方向导数
  • -方向导数与梯度的关系
  • 6.2 近端梯度下降(Proximal Gradient Descent)
  • - 大致思想
  • - 推导过程
  • 7 代码实现


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

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

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

首先,多元线性回归的基本形式为lasso回归缺失值 lasso回归公式_正则表达式,为便于讨论,把 lasso回归缺失值 lasso回归公式_线性回归_02lasso回归缺失值 lasso回归公式_算法_03 吸收入向量形式 lasso回归缺失值 lasso回归公式_算法_04,相应的,把数据集 lasso回归缺失值 lasso回归公式_正则化_05 表示为一个 lasso回归缺失值 lasso回归公式_算法_06 大小的矩阵 lasso回归缺失值 lasso回归公式_正则化_07 (其中lasso回归缺失值 lasso回归公式_lasso回归缺失值_08为样本条数,lasso回归缺失值 lasso回归公式_正则化_09为特征数),即
lasso回归缺失值 lasso回归公式_lasso回归缺失值_10
再把标记也写成向量形式 lasso回归缺失值 lasso回归公式_正则表达式_11
则根据最小二乘法,参数估计值lasso回归缺失值 lasso回归公式_线性回归_12应该满足
lasso回归缺失值 lasso回归公式_正则表达式_13
lasso回归缺失值 lasso回归公式_线性回归_14,对lasso回归缺失值 lasso回归公式_算法_15求导得到(相关矩阵求导知识链接

lasso回归缺失值 lasso回归公式_线性回归_16

令上式得零则可得到 lasso回归缺失值 lasso回归公式_算法_15

  • 情况一:当 lasso回归缺失值 lasso回归公式_线性回归_18 为满秩矩阵时,即可逆,令上式得零,可直接通过移项求的
    lasso回归缺失值 lasso回归公式_线性回归_19
  • 情况二:然而现实任务中 lasso回归缺失值 lasso回归公式_线性回归_18 往往不是满秩矩阵,例如在高维数据中,变量的数目会超过样例数目,导致 lasso回归缺失值 lasso回归公式_正则表达式_21 的列数多于行数,而 lasso回归缺失值 lasso回归公式_线性回归_18 秩等于 lasso回归缺失值 lasso回归公式_正则表达式_21 的秩,显然lasso回归缺失值 lasso回归公式_线性回归_18 不满秩,此时可解出多个 lasso回归缺失值 lasso回归公式_lasso回归缺失值_25 (个人参考了《2022张宇线代9讲》P29 矩阵方程),它们都能使均方误差最小化,选择哪一个作为输出,常见的做法是引入正则化(regularization)项。

2 常见正则化项

首先介绍常见范数——P-范数 (范数详见百度百科),即
lasso回归缺失值 lasso回归公式_正则表达式_26
L1范数正则化项,即令 lasso回归缺失值 lasso回归公式_lasso回归缺失值_27 = 1,并针对参数向量,即为 lasso回归缺失值 lasso回归公式_lasso回归缺失值_28 ,其中 lasso回归缺失值 lasso回归公式_lasso回归缺失值_29 为正则化参数。对于 L1 正则化, lasso回归缺失值 lasso回归公式_lasso回归缺失值_29

类似地,L2范数正则化项为 lasso回归缺失值 lasso回归公式_正则化_31

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

3.1损失函数图像

为了可视化,假设一个回归函数及相应的损失函数如下:
回归函数:lasso回归缺失值 lasso回归公式_算法_32
损失函数(均方差):lasso回归缺失值 lasso回归公式_线性回归_33其中m表示样本量,

为了保持简单,只取一个样本点(1,1)代入上面的代价函数方程中,即 lasso回归缺失值 lasso回归公式_线性回归_34
以下则是上式的图像

lasso回归缺失值 lasso回归公式_lasso回归缺失值_35


可以看出,有无穷多个解可以使损失函数达到最小值。根据前面的论证,在只有一个样本点情况下,外加上最后一列是 1,得到的反应数据集 lasso回归缺失值 lasso回归公式_正则化_05 的矩阵 lasso回归缺失值 lasso回归公式_正则化_07是一行两列,lasso回归缺失值 lasso回归公式_线性回归_38

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

加了 L1 正则项之后的损失函数: lasso回归缺失值 lasso回归公式_线性回归_39 (令lasso回归缺失值 lasso回归公式_线性回归_40

上式图像为

lasso回归缺失值 lasso回归公式_正则表达式_41


可以看出,有唯一最优解了

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

lasso回归缺失值 lasso回归公式_正则表达式_42


(《机器学习》周志华 p253)

经典图片了,不多说了。

5 Lasso 线性回归

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

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

6.1 梯度下降(Gradient Descent)

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


首先介绍经典的梯度下降算法。
可能都知道,梯度下降算法的迭代公式是
lasso回归缺失值 lasso回归公式_正则表达式_43
其中 lasso回归缺失值 lasso回归公式_算法_04,而
lasso回归缺失值 lasso回归公式_正则化_45
便是优化目标中的损失函数 lasso回归缺失值 lasso回归公式_算法_46

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

(1)非零向量 lasso回归缺失值 lasso回归公式_线性回归_47lasso回归缺失值 lasso回归公式_算法_48 轴、lasso回归缺失值 lasso回归公式_算法_49 轴、lasso回归缺失值 lasso回归公式_线性回归_50 轴正向的夹角 lasso回归缺失值 lasso回归公式_线性回归_51lasso回归缺失值 lasso回归公式_正则表达式_52lasso回归缺失值 lasso回归公式_正则表达式_53 称为 lasso回归缺失值 lasso回归公式_线性回归_47 的方向角。
(2) lasso回归缺失值 lasso回归公式_正则表达式_55lasso回归缺失值 lasso回归公式_lasso回归缺失值_56lasso回归缺失值 lasso回归公式_正则表达式_57 称为 lasso回归缺失值 lasso回归公式_线性回归_47 的方向余弦,且lasso回归缺失值 lasso回归公式_lasso回归缺失值_59lasso回归缺失值 lasso回归公式_正则化_60lasso回归缺失值 lasso回归公式_算法_61
(3)由(2)可知lasso回归缺失值 lasso回归公式_正则化_62 称为向量 lasso回归缺失值 lasso回归公式_线性回归_47 的单位向量
以上基础知识有利于从二元直接向更多元推广。

- 方向导数

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

  • 首先给出明确定义:(此部分我感觉参考文章写的更好理解,以下定义更精确、好推广)
    设二元函数 lasso回归缺失值 lasso回归公式_算法_64在点 lasso回归缺失值 lasso回归公式_lasso回归缺失值_65 有定义,lasso回归缺失值 lasso回归公式_正则表达式_66 为从 lasso回归缺失值 lasso回归公式_算法_67 出发的射线,lasso回归缺失值 lasso回归公式_线性回归_68 为在 lasso回归缺失值 lasso回归公式_正则表达式_66 上的任一点,则
    lasso回归缺失值 lasso回归公式_线性回归_70
    其中 lasso回归缺失值 lasso回归公式_线性回归_71 表示 lasso回归缺失值 lasso回归公式_线性回归_72lasso回归缺失值 lasso回归公式_算法_67 之间的距离。
    则极限
    lasso回归缺失值 lasso回归公式_lasso回归缺失值_74
    此极限便是函数 lasso回归缺失值 lasso回归公式_lasso回归缺失值_75 在点 lasso回归缺失值 lasso回归公式_算法_67 沿方向 lasso回归缺失值 lasso回归公式_正则化_77 的方向导数,记作
    lasso回归缺失值 lasso回归公式_算法_78
  • 方向导数计算公式:设函数 lasso回归缺失值 lasso回归公式_算法_64 在点 lasso回归缺失值 lasso回归公式_算法_67 点出可微分,则 lasso回归缺失值 lasso回归公式_lasso回归缺失值_75 在点 lasso回归缺失值 lasso回归公式_算法_67 处沿任意方向 lasso回归缺失值 lasso回归公式_正则化_77 的方向导数都存在,且
    lasso回归缺失值 lasso回归公式_算法_84
    其中 lasso回归缺失值 lasso回归公式_lasso回归缺失值_85lasso回归缺失值 lasso回归公式_lasso回归缺失值_86 为方向 lasso回归缺失值 lasso回归公式_正则化_77 的方向余弦,lasso回归缺失值 lasso回归公式_lasso回归缺失值_88 部分利用的多元函数的泰勒展开式
-方向导数与梯度的关系

从上式可以看出,方向导数其实就是 梯度 lasso回归缺失值 lasso回归公式_线性回归_89 与 方向余弦组成的单位向量 lasso回归缺失值 lasso回归公式_正则化_90 的内积,即
lasso回归缺失值 lasso回归公式_线性回归_91
其中 lasso回归缺失值 lasso回归公式_线性回归_92

那么如果此时想让 lasso回归缺失值 lasso回归公式_lasso回归缺失值_93 最大,自然是 lasso回归缺失值 lasso回归公式_线性回归_92lasso回归缺失值 lasso回归公式_算法_95 的时候,也就是方向与梯度一致的时候的方向导数最大,即变化率最大且是正的,那么如果沿着该方向前进,可以上升(增加)的最快;同理,如果lasso回归缺失值 lasso回归公式_线性回归_92lasso回归缺失值 lasso回归公式_正则表达式_97

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

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


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

具体来说,设优化目标
lasso回归缺失值 lasso回归公式_lasso回归缺失值_98
lasso回归缺失值 lasso回归公式_正则化_99 表示微分算子,lasso回归缺失值 lasso回归公式_正则化_100 即为 lasso回归缺失值 lasso回归公式_正则表达式_101lasso回归缺失值 lasso回归公式_算法_48

- 大致思想

(1)在一定条件下,通过泰勒展开式将目标函数可微的部分化简
(2)以分段函数的形式,对 lasso回归缺失值 lasso回归公式_正则化_103

- 推导过程


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

lasso回归缺失值 lasso回归公式_线性回归_105 可导,且 lasso回归缺失值 lasso回归公式_正则化_100满足 L-Lipschitz 条件,即存在常数 lasso回归缺失值 lasso回归公式_lasso回归缺失值_107 使得
lasso回归缺失值 lasso回归公式_正则表达式_108
(上式可看成是 lasso回归缺失值 lasso回归公式_线性回归_105 的二阶导数恒不大于 lasso回归缺失值 lasso回归公式_线性回归_110 ,即 lasso回归缺失值 lasso回归公式_算法_111 )
则在 lasso回归缺失值 lasso回归公式_算法_112 附近可将 lasso回归缺失值 lasso回归公式_正则表达式_113 通过二阶泰勒展开式近似为
lasso回归缺失值 lasso回归公式_lasso回归缺失值_114
其中 lasso回归缺失值 lasso回归公式_正则表达式_115 是与 lasso回归缺失值 lasso回归公式_算法_116 无关的常数(后续的求解过程也是求导,就直接忽略了,上述具体推导过程参见《机器学习公式详解》(俗称南瓜书)第11章)
也就是说在 lasso回归缺失值 lasso回归公式_正则表达式_117 附近可将目标函数进行简化,那么问题可转化为在这个小范围内寻找可使目标函数最小的 lasso回归缺失值 lasso回归公式_线性回归_118,然后再进行迭代(对于经典梯度下降算法来说,其实也是这么个思想),即
lasso回归缺失值 lasso回归公式_正则表达式_119
lasso回归缺失值 lasso回归公式_正则化_120 表示 lasso回归缺失值 lasso回归公式_算法_116 的第 lasso回归缺失值 lasso回归公式_正则化_122 个分量,将上式按分量展开可看出,其中不存在 lasso回归缺失值 lasso回归公式_线性回归_123 这样的项,也就是说各分量直间互不影响,假设只有一个分量 lasso回归缺失值 lasso回归公式_正则表达式_124 带入展开,求导,令导得零,便可以求得这个小范围内的最小值点,推广可得上式解为:
可先计算 lasso回归缺失值 lasso回归公式_线性回归_125
lasso回归缺失值 lasso回归公式_lasso回归缺失值_126
(如果不考虑 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)