查看全课大纲(第 40 / 82 节)
- 1.函数与数据泛化
- 2.向量:从几何直觉到高维空间
- 3.矩阵与张量
- 4.特征值与特征向量:矩阵变换的不动方向
- 5.凸函数:从向量求导的矩阵记号到好优化的函数形状
- 6.概率与统计:机器学习的数学基础
- 7.独立性与随机变量:贝叶斯公式与二项分布
- 8.期望、方差与协方差:随机变量的数字画像
- 9.联合概率:当一条轴不够用的时候
- 10.概率分布(一):从伯努利到伽马函数
- 11.概率分布(二):贝塔、泊松、正态与两个贝叶斯故事
- 12.机器学习的模型:找输入与输出的关系
- 13.机器学习的应用
- 14.过拟合
- 15.机器学习的分类
- 16.有监督学习:从房价预测说起
- 17.损失函数
- 18.梯度下降(上):更新规则与学习速率
- 19.梯度下降(2)
- 20.牛顿方法
- 21.KNN简介
- 22.距离测算
- 23.朴素贝叶斯
- 24.朴素贝叶斯的实际应用
- 25.信息熵:决策树构建的度量基础
- 26.信息增益与决策树的构建
- 27.ID3算法
- 28.决策树节点的划分
- 29.CART树
- 30.Bagging
- 31.Boosting:自适应提升算法
- 32.Gradient Boosting
- 33.线性模型:回归与分类的同一副骨架
- 34.最小二乘:把最优参数直接解出来
- 35.最小二乘法的几何与概率视角
- 36.极大似然:给最小二乘一个概率出身
- 37.逻辑回归(1):把线性模型接到分类上
- 38.逻辑回归(2):损失函数与多分类
- 39.---- 手造数据: 5 个样本, 2 个特征; x2 几乎 = 2*x1 (偏差手工指定, 无随机) ----
- 40.讲师例: 向量 "23014" -- 三把范数尺子量同一个向量
- 41.优化方法(1):坐标下降与前向选择
- 42.优化方法(2):前向策略与最小角回归
- 43.拉格朗日乘子法(1):从无约束到等式约束
- 44.拉格朗日乘子法(2):等式约束下的平行条件与拉格朗日函数
- 45.拉格朗日乘子法(3):不等式约束与 KKT 条件
- 46.最大间隔:把分类问题变成优化问题
- 47.拉格朗日对偶问题:把 w 和 b 全部换成 α
- 48.支持向量:边界上的少数派
- 49.SVM 计算过程:一笔到底算完,再走进核方法
- 50.贝叶斯公式:概率即信念
- 51.隐含变量和概率模型:给看不见的原因建模
- 52.EM 算法:期望与最大化的迭代
- 53.琴生不等式:EM 的数学钥匙
- 54.三个硬币问题:EM 的复盘与衔接
- 55.高斯混合模型:用隐变量解释双峰数据
- 56.隐马尔可夫模型
- 57.隐马尔可夫模型(2):前向算法与动态混合模型
- 58.隐马尔可夫模型在 NLP 中的运用
- 59.EM 算法:把「为什么收敛」推到底
- 60.HMM 在 NLP 中的运用:从分词到机器翻译
- 61.HMM 参数估计:Baum-Welch 的三块拉格朗日
- 62.高维下的高斯模型
- 63.主题模型:从词袋到隐含主题
- 64.Dirichlet 分布(1)
- 65.Dirichlet 分布(2)
- 66.统计学习内容回顾
- 67.K-means 算法
- 68.PCA 降维
- 69.SVD 降维
- 70.从聚类到流形
- 71.局部线性嵌入
- 72.随机邻域嵌入:SNE 与 t-SNE
- 73.无参模型:让数据自己说话
- 74.高斯过程:函数空间里的正态分布
- 75.高斯过程(2):噪声、正则化与核的线性组合
- 76.神经网络简介:从感知器到自编码器
- 77.反向传播:把误差一层层传回去
- 78.卷积神经网络(CNN):让特征自己学出来
- 79.循环神经网络(RNN):给网络装上记忆
- 80.深度学习回顾:静态一类,动态一类
- 81.增强学习(1):蒙特卡洛、树搜索与 Q-learning
- 82.强化学习(2):从乌鸦吃核桃到井字棋的 value 回传
讲师例: 向量 "23014" -- 三把范数尺子量同一个向量
约 19 分钟
LASSO:把不重要的系数压成零
小象实战讲义 · 机器学习算法精讲
上一节的 Ridge 把系数统统”缩水”——但缩完之后,每个系数都还活着,只是变小了。也有同学提到了复杂度的问题——这确实是一件重要的事。本节我们走得更极端一点:希望有些系数就是 0 就好了——只留下最重要的那几个特征。登场的方法叫 LASSO,全名特别长:Least Absolute Shrinkage and Selection Operator——所以简写为 LASSO。拆开读:shrinkage 是缩水(Ridge 干的也是这个);absolute 是对绝对值缩水;selection 是它还能选择特征——这两者加在一起,构成了新的约束项。
💡 核心导读
- 动机:特征选择是机器学习里特别难的事—— 里每个系数就是一个特征的权重,把 设成 0 等于自动扔掉这个特征。
- L0 的理想与现实:最想要的是 L0 范数(非零个数)最少,但它不凸、不连续,没法优化。
- L1 登场:换成 L1 范数 ——连续、可优化,且能达到逼近 L0 的效果(稀疏解)。
- 几何直觉:L2 的约束区域是圆(无角),L1 是菱形(有顶点)——等高线撞上菱形时,大概率撞在顶点上,而顶点上总有一个维度是 0。
- 代价:L1 在零点不可导,梯度下降失灵,得用其他方法求。
从”缩水”到”归零”:特征选择
我们想求的函数 是线性函数:。每一个 ,代表的正是对应特征的权重。上一节的约束能把过大的值变小;再走极端一点——如果某个特征根本不重要,把它的权重设成 0,这个特征在预测里就不再产生任何影响,相当于被自动剔除了。
为什么想要这个?因为在整个机器学习里特别难的一件事,就是特征选择。给定一个问题时,很多特征真的是冗余的、没必要的,或者跟其他特征线性相关。讲师的例子:想知道一个房屋的价值,把”平方尺”和”平方米”都放上去了——100 平方尺换算过来就是约 30 平方米,同一个信息放了两遍,用一个就足够。这种完全冗余的特征,把某个 设为 0 就自动去除了。
所以线性模型 的形式本身就代表着每个特征的权重;而选特征的过程,就是把 设成非 0 和 0 的过程。
L0 范数:理想很美,没法优化
顺着这个想法,我们希望特征里尽量多的都是 0、只有少数非零——少数特征的组合就能解决问题。这件事有个名字:优化 的 L0 范数。L0 范数数的是向量里非零元素的个数,说白了就是查数:比如向量 ,L0 范数等于 4——四个非零、一个零。
理想的优化问题写出来是:在满足 (把给定的数据拟合住)的前提下,让 最小。先跑个代码,把”查数”这件事和它的麻烦一起看清楚:
# 讲师例: 向量 "23014" -- 三把范数尺子量同一个向量
def L0(v):
return sum(1 for x in v if x != 0.0) # 数非零个数 ("查数")
def L1(v):
return sum(abs(x) for x in v)
def L2(v):
return sum(x * x for x in v) ** 0.5
v = [2.0, 3.0, 0.0, 1.0, 4.0]
print(f"v = {v}")
print(f"L0(v) = {L0(v)} L1(v) = {L1(v):.4f} L2(v) = {L2(v):.6f}")
# 把那个 0 抬高一根头发丝, 向量几乎没动
v2 = [2.0, 3.0, 0.0001, 1.0, 4.0]
print(f"v' = {v2} (只把 0.0 改成 0.0001)")
print(f"L0(v') = {L0(v2)} L1(v') = {L1(v2):.4f} L2(v') = {L2(v2):.6f}")
print("=> L0 从 4 跳到 5: 查数是不连续的, 中间没有 3.5、3.76, 没法求导优化")
print(" L1 只涨 0.0001、L2 几乎不动: 它们连续, 才能进损失函数")v = [2.0, 3.0, 0.0, 1.0, 4.0]
L0(v) = 4 L1(v) = 10.0000 L2(v) = 5.477226
v' = [2.0, 3.0, 0.0001, 1.0, 4.0] (只把 0.0 改成 0.0001)
L0(v') = 5 L1(v') = 10.0001 L2(v') = 5.477226
=> L0 从 4 跳到 5: 查数是不连续的, 中间没有 3.5、3.76, 没法求导优化
L1 只涨 0.0001、L2 几乎不动: 它们连续, 才能进损失函数问题就在这里:把一个 0 改成 0.0001,向量几乎没动,L0 却从 4 一下跳到 5——中间没有 3.5、3.76 这种过渡。它不凸、甚至不连续,我们没办法把它构造进一个能优化的 cost function:比如给原先的损失 加一项 乘 L0 范数——这个新的目标函数是无法优化的。理想虽美,此路不通。
换 L1:可优化的逼近
那怎么办?不 optimizing 它的 0 范数,改求它的 1 范数。1 范数是可以求的,而且比较接近、能逼近 0 范数的表达。这种拟合形式就叫 LASSO(拉索)。
到这里把三兄弟摆在一起,结构非常清楚——最开始的最小二乘法,不加任何约束,就是普通最小二乘;加平方方向的约束(L2 范数),就是 Ridge Regression;加 L1 范数的正则化,就是 Lasso。沿用上一节的口径,损失函数写成:
(同样不含偏置 ; 的权衡跟上一节是同一条 U 形曲线: 退回普通最小二乘, 把系数全推向 0。)它也有带约束的写法——,满足 ——构造拉格朗日乘子后就是上面的形式,与上一节同款操作。
LASSO 优化的最好值,会使 变得非常稀疏:向量里很多都是 0,只有少数非零。于是这个约束项自动带上了特征选择的功能—— 的特征不重要,忽略不计,相当于把非零的那些特征选择出来了。
还有一笔账:线性函数的核心就是 ,循环的次数与 的维度 直接相关—— 的计算复杂度。把非零系数的个数压小, 实际上就减小了,模型的复杂度直接降下来。所以也会说,这种约束使模型不要过度复杂。
更大的图景:损失函数是一门手艺
往后再退一步看。以上说的还只是线性模型里”约束函数取值”的正则化;还有一些类似的构造,限制的是整个模型的复杂度,函数形式各不相同。所以关键是:在不同的问题里构造不同的损失函数,才会得到不同的效果。 到今天尤其深度学习的情况下,很多工作都是在找特别合适的 loss function——怎么构造一个特别合适的、能满足你的问题的损失函数——这本身成为特别重要的一个研究点。
几何直观:圆没有角,菱形有
为什么 1 范数的优化能逼近 0 范数、产生稀疏解?经典的图给出直观。两个参数 、:
- L2 范数相同的点构成一个圆: 常数;
- L1 范数相同的点构成一个正方形(菱形): 常数——每条边上任取一点,绝对值相加都是同一个数。
(这两把尺子在第 5 章《距离测算》里见过:L2 是欧氏、L1 是曼哈顿——今天它们被用来量参数。)图上彩色的圈是 cost function 的等高线:同一条线上 值相同,一圈圈往外,值越来越大;黑色圆圈/方框是约束。要做的事是:在约束边界上的所有点里,找到 最小的那一个——几何上就是等高线往外扩,第一次碰到约束边界的位置。Ridge 的情形,等高线与圆相切在一段光滑的弧上(讲师在图上把等高线标成 0、0.5、1.0、3.0、5.0、8.0……相切的切点落在 8.0 那条上,圆上其余点都在 8.0 与 9.0 之间或超过 9.0)。
L1 的情形不同:菱形有四个顶点,而且都在坐标轴上。等高线往外扩、第一次撞上菱形时,有更大的概率撞在顶点上——讲师特意强调用词:是”更大的概率”,不是一定会,这个是没有 guarantee 的;如果损失函数的形状特殊,也可能撞在边上,只是概率相对小。而一旦撞在顶点上,总有一个维度是 0(左边两个顶点 ,上下两个顶点 )——稀疏就这么发生了。做的是 1 范数的优化,达到的效果是逼近 0 范数:非零的系数比较少,尽量都是 0。
把这张图变成可以跑的:4 个样本、2 个特征, 与 严格正交,数据由 精确生成(无噪声,OLS 解恰好是 )。在平面上铺一张 0.005 步长的网格逐点找最小——等高线往外扩的数值版:
# ---- 4 个样本, 2 个特征; x1 与 x2 严格正交 (内积 = 0), 数据由 y = 0.9*x1 + 0.3*x2 精确生成 ----
X = [
[1.0, 1.0],
[2.0, -1.0],
[3.0, -1.0],
[4.0, 1.0],
]
y = [1.2, 1.5, 2.4, 3.9]
def loss(t1, t2, lam, kind):
s = 0.0
for row, yi in zip(X, y):
s += (row[0] * t1 + row[1] * t2 - yi) ** 2
s *= 0.5
if kind == "L2": # Ridge: 惩罚平方和
s += lam * (t1 * t1 + t2 * t2)
else: # Lasso: 惩罚绝对值和
s += lam * (abs(t1) + abs(t2))
return s
def grid_min(lam, kind):
# 在 [0,1] x [-0.1,0.4] 平面上铺 0.005 步长的网格, 逐点找最小 (等高线往外扩的数值版)
best, bt = None, None
for i in range(0, 201):
t1 = i / 200
for j in range(-20, 81):
t2 = j / 200
v = loss(t1, t2, lam, kind)
if best is None or v < best:
best, bt = v, (t1, t2)
return bt
def L0_of(t):
return sum(1 for x in t if abs(x) > 1e-12)
print("数据 (x1, x2 -> y), x1 与 x2 内积 = 0 (严格正交):")
for row, yi in zip(X, y):
print(f" ({row[0]:.0f}, {row[1]:.0f}) -> {yi}")
print("\n网格搜索 (步长 0.005) 的最优 theta:")
t = grid_min(0.0, "L1")
print(f" lambda = 0.0 OLS: ({t[0]:.3f}, {t[1]:.3f}) L0 = {L0_of(t)}")
for lam in [0.5, 1.5, 10.0]:
tr = grid_min(lam, "L2")
tl = grid_min(lam, "L1")
print(f" lambda = {lam:4.1f} Ridge: ({tr[0]:.3f}, {tr[1]:.3f}) L0 = {L0_of(tr)}")
tail = " <- 切在顶点上: theta2 恰好为零" if abs(tl[1]) < 1e-12 else ""
print(f" lambda = {lam:4.1f} Lasso: ({tl[0]:.3f}, {tl[1]:.3f}) L0 = {L0_of(tl)}{tail}")数据 (x1, x2 -> y), x1 与 x2 内积 = 0 (严格正交):
(1, 1) -> 1.2
(2, -1) -> 1.5
(3, -1) -> 2.4
(4, 1) -> 3.9
网格搜索 (步长 0.005) 的最优 theta:
lambda = 0.0 OLS: (0.900, 0.300) L0 = 2
lambda = 0.5 Ridge: (0.870, 0.240) L0 = 2
lambda = 0.5 Lasso: (0.885, 0.175) L0 = 2
lambda = 1.5 Ridge: (0.820, 0.170) L0 = 2
lambda = 1.5 Lasso: (0.850, 0.000) L0 = 1 <- 切在顶点上: theta2 恰好为零
lambda = 10.0 Ridge: (0.540, 0.050) L0 = 2
lambda = 10.0 Lasso: (0.565, 0.000) L0 = 1 <- 切在顶点上: theta2 恰好为零读这张表。Ridge 永远压不死: 从 0.300 缩到 0.240、0.170、0.050,一路变小但始终大于 0——圆没有角,等高线永远切在弧上(对这份正交数据,,任何有限的 都除不到 0)。Lasso 对弱者下死手、对强者手下留情: 的”信号强度”是 , 只有 1.2—— 一过 1.2, 恰好死在坐标轴上(0.000), 却还稳稳站着(0.850、0.565,比同 的 Ridge 还大一点:Lasso 把死掉那个的份额省下来,留给了活着的)。看 L0 那一列:Lasso 的解从 2 个非零变成 1 个——1 范数的优化,实际达到了逼近 0 范数的效果,这就是特征选择在数字上的样子。
代价:零点不可导
为什么用 1 范数?因为它首先还是连续的,而且是一个凸函数——这两条让它能优化。但有一个问题:在某些点上——就是某维为 0 的那些点上——它不可导。走到那里,梯度做不出来,梯度下降就用不了了。
对比收束一下:Ridge(L2)处处平滑可导,所以上一节直接用梯度下降更新,没有任何障碍;Lasso(L1)的损失函数照样能构造出来——这没问题——但求解不能再用以前那种梯度下降了,会用其他的方法来求 LASSO 的优化。这就是两种正则化在求解上的分水岭。
📝 动手练一练
- 特征选择选谁:你有一个包含 100 个特征的数据集,但怀疑其中只有 10 个左右真正重要。想构建线性模型并让它自动识别出这 10 个关键特征——普通最小二乘、岭回归、LASSO,选哪个?为什么?
👉 点击查看参考答案
选 LASSO。
- LASSO 的 L1 正则会把不重要特征的权重恰好压成 0—— 的特征自动出局,最终模型只保留少数非零特征,正好匹配”只有 10 个左右重要特征”的设想(本节数值演示里 在 过 1.2 后精确死在 0 上)。
- 普通最小二乘给所有特征都分配权重,100 个特征一个不少,特征多时还不稳定。
- 岭回归把所有权重一起缩小,但圆没有角—— 很少能恰好等于 0,100 个特征全都留在模型里,只是贡献变小,不具备特征选择功能。
- 单参数手算:单个样本 ,LASSO 损失 。取 ,手算 三处的损失,指出最优点在哪;再取 同样算这三个点,观察 的归宿。两问合起来说明 L1 对参数做了什么?
👉 点击查看参考答案
:;;。最小在 ——比无正则的最优 被拉向 0。
:;;。最小在 ——恰好压死。单样本下信号强度是 , 一过 1, 就从”缩水”变成”归零”,之后一直躺在 0 上。
结论:L1 正则化对参数做的是绝对值的缩水,且对信号弱的参数能缩到精确的 0——这正是块二里 遭遇的单参数版。
本章小结
- 动机:特征选择是机器学习特别难的事; 是特征的权重,设为 0 即自动剔除(房屋的平方尺/平方米冗余例)。
- L0 不可行:L0 范数=数非零个数(查数),不凸、不连续(4 直接跳 5,没有中间值),构造不进可优化的损失函数。
- L1 逼近 L0: 连续且凸,可优化;, 照旧不惩罚。
- 三兄弟:不加约束=普通最小二乘;加 L2 平方约束=Ridge;加 L1=Lasso。
- 稀疏与特征选择:最优解很多分量为 0(数值演示:正交数据下 过 1.2, 精确归零、 存活);非零个数少=复杂度 直接受益。
- 几何:L2 等值线是圆(切点落在光滑弧上),L1 是菱形(四顶点在轴上,等高线大概率撞顶点——不保证);撞上顶点就有维度为 0。
- 求解分水岭:L1 在零点不可导——梯度下降失灵,用其他方法求。
- 更大图景:不同问题构造不同损失函数才有不同效果——找合适的 loss function 是重要研究点。
📋 行动清单
- 口头复述 LASSO 全称,逐词说出 absolute 与 selection 各自对应什么性质
- 解释 L0 为什么不可优化(不凸、不连续),L1 凭什么能逼近它
- 在纸上画出二维的圆(L2 约束)与菱形(L1 约束),说明等高线为什么大概率撞在菱形顶点上,以及为什么”不保证”
- 跑代码二:把 lambda 扫描加密(如 1.0、1.1、1.2、1.3),找出 恰好死掉的那个 ,对照”信号强度” ——死期由信号强度决定,不由系数大小决定
- 对比记忆:Ridge 求解用梯度下降(处处可导),Lasso 要用其他方法(零点不可导)
—— 小象教研组
配套资料 · 直接下载
课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。