【机器学习】机器学习中的常用范数详解

机器学习中的常用范数详解

文章目录

  • 机器学习中的常用范数详解
    • [1 什么是范数?](#1 什么是范数?)
    • [2 常用的向量范数](#2 常用的向量范数)
      • [2.1 L0范数](#2.1 L0范数)
      • [2.2 L1范数(曼哈顿范数)](#2.2 L1范数(曼哈顿范数))
      • [2.3 L2范数(欧几里得范数)](#2.3 L2范数(欧几里得范数))
      • [2.4 Lp范数](#2.4 Lp范数)
      • [2.5 L∞范数(最大范数)](#2.5 L∞范数(最大范数))
    • [3 常用的矩阵范数](#3 常用的矩阵范数)
      • [3.1 弗罗贝尼乌斯范数(Frobenius Norm)](#3.1 弗罗贝尼乌斯范数(Frobenius Norm))
      • [3.2 核范数(Nuclear Norm)](#3.2 核范数(Nuclear Norm))
      • [3.3 算子范数(Operator Norm)](#3.3 算子范数(Operator Norm))
    • [4 范数在机器学习中的应用](#4 范数在机器学习中的应用)
    • [5 可视化范数比较](#5 可视化范数比较)
      • [5.1 单位圆比较示例](#5.1 单位圆比较示例)
      • [5.2 等高线比较示例](#5.2 等高线比较示例)
    • [6 总结](#6 总结)

1 什么是范数?

在数学中,范数(Norm)是对向量或矩阵"长度"或"大小"的一种度量。范数将向量或矩阵映射到一个非负实数,满足以下性质:

  1. 非负性:对于所有向量x,‖x‖ ≥ 0,且‖x‖ = 0当且仅当x=0
  2. 齐次性:对于所有标量α和向量x,‖αx‖ = |α|·‖x‖
  3. 三角不等式:对于所有向量x和y,‖x + y‖ ≤ ‖x‖ + ‖y‖

范数在机器学习、优化问题、信号处理等领域有广泛应用。

2 常用的向量范数

2.1 L0范数

L0范数表示向量中非零元素的个数

∥ x ∥ 0 = # { i ∣ x i ≠ 0 } \|x\|_0 = \#\{i | x_i \neq 0\} ∥x∥0=#{i∣xi=0}

虽然称为"范数",但严格来说L0并不满足范数的所有性质(特别是齐次性)。它在稀疏表示、压缩感知等领域有重要应用。

python 复制代码
import numpy as np

def l0_norm(x):
    return np.count_nonzero(x)

x = np.array([1, 0, 3, 0, 5])
print(l0_norm(x))  # 输出:3

2.2 L1范数(曼哈顿范数)

L1范数是向量中各元素绝对值之和

∥ x ∥ 1 = ∑ i = 1 n ∣ x i ∣ \|x\|1 = \sum{i=1}^n |x_i| ∥x∥1=i=1∑n∣xi∣

L1范数能促进稀疏性,常用于特征选择(Lasso回归)和稀疏编码。

python 复制代码
def l1_norm(x):
    return np.sum(np.abs(x))

x = np.array([1, -2, 3])
print(l1_norm(x))  # 输出:6

2.3 L2范数(欧几里得范数)

L2范数是向量各元素平方和的平方根:

∥ x ∥ 2 = ∑ i = 1 n x i 2 \|x\|2 = \sqrt{\sum{i=1}^n x_i^2} ∥x∥2=i=1∑nxi2

这是最常用的范数,表示向量的几何长度。在机器学习中,L2正则化可以防止过拟合。

python 复制代码
def l2_norm(x):
    return np.sqrt(np.sum(x**2))

x = np.array([3, 4])
print(l2_norm(x))  # 输出:5.0

2.4 Lp范数

Lp范数是更一般的范数形式:

∥ x ∥ p = ( ∑ i = 1 n ∣ x i ∣ p ) 1 / p \|x\|p = \left( \sum{i=1}^n |x_i|^p \right)^{1/p} ∥x∥p=(i=1∑n∣xi∣p)1/p

当p=1时为L1范数,p=2时为L2范数。

2.5 L∞范数(最大范数)

L∞范数是向量中绝对值最大的元素

∥ x ∥ ∞ = max ⁡ i ∣ x i ∣ \|x\|_\infty = \max_i |x_i| ∥x∥∞=imax∣xi∣

python 复制代码
def linf_norm(x):
    return np.max(np.abs(x))

x = np.array([1, -5, 3, 2])
print(linf_norm(x))  # 输出:5

3 常用的矩阵范数

3.1 弗罗贝尼乌斯范数(Frobenius Norm)

类似于向量的L2范数,是矩阵元素平方和的平方根:

∥ A ∥ F = ∑ i = 1 m ∑ j = 1 n ∣ a i j ∣ 2 \|A\|F = \sqrt{\sum{i=1}^m \sum_{j=1}^n |a_{ij}|^2} ∥A∥F=i=1∑mj=1∑n∣aij∣2

python 复制代码
def frobenius_norm(A):
    return np.sqrt(np.sum(A**2))

A = np.array([[1, 2], [3, 4]])
print(frobenius_norm(A))  # 输出:5.477...

3.2 核范数(Nuclear Norm)

矩阵的核范数是其奇异值之和,常用于矩阵补全和低秩矩阵恢复:

∥ A ∥ ∗ = ∑ i = 1 r σ i \|A\|* = \sum{i=1}^r \sigma_i ∥A∥∗=i=1∑rσi

其中r是矩阵A的秩,σ_i是奇异值。

python 复制代码
def nuclear_norm(A):
    return np.sum(np.linalg.svd(A)[1])

A = np.array([[1, 0, 0], [0, 2, 0], [0, 0, 3]])
print(nuclear_norm(A))  # 输出:6.0

3.3 算子范数(Operator Norm)

根据不同的向量范数,可以定义不同的矩阵算子范数。例如:

  • p=1时: ∥ A ∥ 1 = max ⁡ j ∑ i = 1 m ∣ a i j ∣ \|A\|1 = \max_j \sum{i=1}^m |a_{ij}| ∥A∥1=maxj∑i=1m∣aij∣ (列和最大值)
  • p=∞时: ∥ A ∥ ∞ = max ⁡ i ∑ j = 1 n ∣ a i j ∣ \|A\|\infty = \max_i \sum{j=1}^n |a_{ij}| ∥A∥∞=maxi∑j=1n∣aij∣ (行和最大值)
  • p=2时: ∥ A ∥ 2 = σ max ⁡ \|A\|2 = \sigma{\max} ∥A∥2=σmax (最大奇异值)

4 范数在机器学习中的应用

  1. 正则化

    • L1正则化产生稀疏解,用于特征选择
    • L2正则化防止过拟合,使解更平滑
  2. 距离度量

    • 在KNN、K-means等算法中,常用L2范数作为距离度量
    • 在异常检测中,有时使用L1范数
  3. 优化约束

    • 在支持向量机中,使用L2范数定义间隔
    • 在矩阵分解中,使用核范数约束低秩性
  4. 损失函数

    • 回归问题中常用L2范数作为损失(MSE)
    • 鲁棒回归中可能使用L1范数作为损失(MAE)

5 可视化范数比较

5.1 单位圆比较示例

下面是一个Python代码,使用matplotlib绘制不同范数(L0.5, L1, L2, L3, L∞)的单位圆:

python 复制代码
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rcParams

# 设置中文显示和字体
rcParams['font.sans-serif'] = ['SimHei']
rcParams['axes.unicode_minus'] = False

def plot_unit_balls():
    # 创建极坐标角度数组
    theta = np.linspace(0, 2*np.pi, 1000)
    
    # 创建图形
    plt.figure(figsize=(10, 8))
    plt.title('Comparison of unit circles with different norms', fontsize=16)
    plt.axhline(0, color='gray', linewidth=0.5)
    plt.axvline(0, color='gray', linewidth=0.5)
    plt.grid(True, linestyle='--', alpha=0.7)
    plt.axis('equal')
    
    # 定义不同p值的范数
    p_values = [0.5, 1, 2, 3, np.inf]
    colors = ['red', 'blue', 'green', 'purple', 'orange']
    labels = ['L0.5 Norm', 'L1 Norm', 'L2 Norm', 'L3 Norm', 'L∞ Norm']
    
    # 计算并绘制每个范数的单位圆
    for p, color, label in zip(p_values, colors, labels):
        if p == np.inf:
            # L∞范数是正方形
            x = np.array([-1, 1, 1, -1, -1])
            y = np.array([-1, -1, 1, 1, -1])
        else:
            # 对于其他p值,计算极坐标下的r(θ)
            cos_theta = np.cos(theta)
            sin_theta = np.sin(theta)
            r = 1 / (np.abs(cos_theta)**p + np.abs(sin_theta)**p)**(1/p)
            x = r * np.cos(theta)
            y = r * np.sin(theta)
        
        plt.plot(x, y, color=color, linewidth=2, label=label)
    
    # 添加图例和标签
    plt.legend(fontsize=12)
    plt.xlabel('x', fontsize=12)
    plt.ylabel('y', fontsize=12)
    plt.xlim(-1.5, 1.5)
    plt.ylim(-1.5, 1.5)
    
    # 显示图形
    plt.tight_layout()
    plt.show()

# 注意:L0范数实际上不是一个真正的范数,且其单位"圆"在二维空间中是四个离散的点
# 所以这里没有包含L0范数,因为它不形成连续的形状

plot_unit_balls()

这段代码绘制了L0.5、L1、L2、L3和L∞范数的单位圆,每个范数的单位圆用不同颜色表示,并添加了图例说明,图形设置为等比例,以便正确比较不同范数的形状。

注:关于L0范数的说明:严格来说,L0范数(计算非零元素的数量)不是一个真正的范数,它的单位"圆"在二维空间中实际上是四个离散的点:(1,0), (-1,0), (0,1), (0,-1)。因此在上面的连续曲线图中没有包含它。如果需要显示L0范数,可以单独添加这四个点。

可视化效果如下图所示:

其中:

  • L0.5范数:星形(向内凹陷)
  • L1范数:菱形(曼哈顿距离)
  • L2范数:标准的圆形(欧几里得距离)
  • L3范数:介于圆形和方形之间
  • L∞范数:正方形(切比雪夫距离)

5.2 等高线比较示例

python 复制代码
import numpy as np
import matplotlib.pyplot as plt

# 创建一个二维向量空间
x = np.linspace(-1, 1, 100)
y = np.linspace(-1, 1, 100)
X, Y = np.meshgrid(x, y)
Z = np.stack([X, Y], axis=-1)

# 计算不同范数
l0 = np.apply_along_axis(lambda v: np.count_nonzero(v), -1, Z)
l1 = np.apply_along_axis(lambda v: np.sum(np.abs(v)), -1, Z)
l2 = np.apply_along_axis(lambda v: np.sqrt(np.sum(v**2)), -1, Z)
linf = np.apply_along_axis(lambda v: np.max(np.abs(v)), -1, Z)

# 绘制范数等高线
plt.figure(figsize=(12, 10))

plt.subplot(2, 2, 1)
plt.contour(X, Y, l0, levels=[0.5, 1.5, 2.5])
plt.title("L0 Norm")

plt.subplot(2, 2, 2)
plt.contour(X, Y, l1, levels=[0.5, 1, 1.5])
plt.title("L1 Norm")

plt.subplot(2, 2, 3)
plt.contour(X, Y, l2, levels=[0.5, 1, 1.5])
plt.title("L2 Norm")

plt.subplot(2, 2, 4)
plt.contour(X, Y, linf, levels=[0.5, 1, 1.5])
plt.title("L∞ Norm")

plt.tight_layout()
plt.show()

这段代码会绘制不同范数在二维空间中的等高线图,直观展示各种范数的几何形状差异。

结果如下所示:

6 总结

不同范数有不同的性质和应用场景:

  • L0范数:用于稀疏计数,但优化困难
  • L1范数:促进稀疏性,可用于特征选择
  • L2范数:最常用,具有良好的几何性质
  • L∞范数:关注最大偏差
  • 核范数:用于低秩矩阵恢复

在实际应用中,需要根据具体问题选择合适的范数形式。理解这些范数的性质和差异,对于设计和理解机器学习算法至关重要。