当前位置:首页 > 技术 > 正文内容

Johnson-Lindenstrauss 引理及其在数据降维中的应用

访客 技术 2026年9月13日 28

在处理高维数据时,维度灾难是一个常见挑战。Johnson-Lindenstrauss (JL) 引理提供了一种强大的数学工具,证明可以通过随机投影将高维向量集映射到低维空间,同时近似保留原始向量之间的距离。本文将深入探讨 JL 引理的理论基础及其在实际应用中的考量。

马尔可夫不等式的一个推广形式

在证明 JL 引理之前,我们首先需要引入马尔可夫不等式的一个变种,它特别适用于处理指数形式的概率边界。对于任意非负随机变量 \(X\) 和正数 \(a\),以及任意正数 \(\lambda\),有:

\[ P(X \ge a) = P(e^{\lambda X} \ge e^{\lambda a}) \le \min_{\lambda > 0} e^{-\lambda a} \mathbb{E}[e^{\lambda X}] \]

这个形式的强大之处在于,它将原始的概率问题转化为求随机变量指数的期望值(即矩生成函数 MGF)。特别是对于正态分布,其 MGF 有简洁的表达式,使得此不等式能够推导出更紧的边界。

单位向量模长集中引理

该引理描述了随机单位向量的模长平方如何集中在1附近。设 \(u \in \mathbb{R}^n\) 是一个随机向量,其每个分量 \(u_i\) 都独立地从均值为0、方差为 \(1/n\) 的正态分布 \(N(0, 1/n)\) 中采样。那么对于任意 \(\epsilon \in (0, 1)\),有:

\[ P\left(\left| \Vert u \Vert^2 - 1 \right| \ge \epsilon\right) \le 2\exp(-\epsilon^2n/8) \]

这个引理表明,当维度 \(n\) 足够大时,向量模长平方 \(\Vert u \Vert^2\) 会以极高的概率落在 \([1-\epsilon, 1+\epsilon]\) 区间内。下面我们来证明这个结论。

证明思路

我们首先考虑上尾概率 \(P(\Vert u \Vert^2 - 1 > \epsilon)\)。根据前面提到的马尔可夫不等式推广形式,我们可以得到:

\[ P(\Vert u \Vert^2 - 1 > \epsilon) \le \min_{\lambda > 0} e^{-\lambda (\epsilon+1)} \mathbb{E}[e^{\lambda \Vert u \Vert^2}] \]

接下来计算期望 \(\mathbb{E}[e^{\lambda \Vert u \Vert^2}]\)。由于 \(u\) 的各分量独立同分布,且 \(\Vert u \Vert^2 = \sum_{i=1}^n u_i^2\),所以:

\[ \mathbb{E}[e^{\lambda \Vert u \Vert^2}] = \mathbb{E}\left[e^{\lambda \sum_{i=1}^n u_i^2}\right] = \prod_{i=1}^n \mathbb{E}[e^{\lambda u_i^2}] = \left(\mathbb{E}[e^{\lambda u_1^2}]\right)^n \]

对于单个分量 \(u_1 \sim N(0, 1/n)\),其概率密度函数为 \(f(t) = \frac{1}{\sqrt{2\pi(1/n)}} e^{-t^2 / (2(1/n))} = \frac{\sqrt{n}}{\sqrt{2\pi}} e^{-nt^2/2}\)。因此,我们可以计算 \(\mathbb{E}[e^{\lambda u_1^2}]\):

\[ \mathbb{E}[e^{\lambda u_1^2}] = \int_{-\infty}^{\infty} \frac{\sqrt{n}}{\sqrt{2\pi}} e^{-nt^2/2} e^{\lambda t^2} dt = \int_{-\infty}^{\infty} \frac{\sqrt{n}}{\sqrt{2\pi}} e^{-(n/2 - \lambda)t^2} dt \]

为了使积分收敛,我们需要 \(n/2 - \lambda > 0\),即 \(\lambda < n/2\)。我们将被积函数调整为标准正态分布的形式。回想一下,对于 \(X \sim N(0, \sigma^2)\),其概率密度函数为 \(\frac{1}{\sqrt{2\pi\sigma^2}} e^{-x^2/(2\sigma^2)}\),且 \(\int_{-\infty}^{\infty} \frac{1}{\sqrt{2\pi\sigma^2}} e^{-x^2/(2\sigma^2)} dx = 1\)。 比较可知,我们有 \(2(n/2 - \lambda) = 1/\sigma^2\),即 \(\sigma^2 = \frac{1}{n-2\lambda}\)。 因此,我们可以在积分中乘以和除以 \(\frac{1}{\sqrt{2\pi \sigma^2}}\),得到:

\[ \mathbb{E}[e^{\lambda u_1^2}] = \frac{\sqrt{n}}{\sqrt{2\pi}} \frac{\sqrt{2\pi}}{\sqrt{n-2\lambda}} \int_{-\infty}^{\infty} \frac{\sqrt{n-2\lambda}}{\sqrt{2\pi}} e^{-(n/2 - \lambda)t^2} dt = \frac{\sqrt{n}}{\sqrt{n-2\lambda}} \] 所以,有: \[ P(\Vert u \Vert^2 - 1 > \epsilon) \le \min_{\lambda \in (0, n/2)} e^{-\lambda (\epsilon+1)} \left(\frac{n}{n-2\lambda}\right)^{n/2} \]

为了找到使上界最小的 \(\lambda\),我们对函数 \(f(\lambda) = -\lambda(\epsilon+1) + \frac{n}{2}\ln\left(\frac{n}{n-2\lambda}\right)\) 求导并令其为零(这是取对数后的形式):

\[ \frac{d}{d\lambda} \left(-\lambda(\epsilon+1) + \frac{n}{2}(\ln n - \ln(n-2\lambda))\right) = -(\epsilon+1) + \frac{n}{2}\left(-\frac{1}{n-2\lambda}(-2)\right) = -(\epsilon+1) + \frac{n}{n-2\lambda} \] 令导数为0,解得 \(\lambda = \frac{n\epsilon}{2(\epsilon+1)}\)。 将此 \(\lambda\) 值代回不等式中:

\[ P(\Vert u \Vert^2 - 1 > \epsilon) \le e^{-\frac{n\epsilon}{2(\epsilon+1)}(\epsilon+1)} \left(\frac{n}{n-2\frac{n\epsilon}{2(\epsilon+1)}}\right)^{n/2} \] \[ = e^{-n\epsilon/2} \left(\frac{n}{n - n\epsilon/(\epsilon+1)}\right)^{n/2} = e^{-n\epsilon/2} \left(\frac{n}{\frac{n(\epsilon+1)-n\epsilon}{\epsilon+1}}\right)^{n/2} \] \[ = e^{-n\epsilon/2} \left(\frac{n}{n/(\epsilon+1)}\right)^{n/2} = e^{-n\epsilon/2} (\epsilon+1)^{n/2} = \exp\left(\frac{n}{2}(\ln(1+\epsilon) - \epsilon)\right) \]

接下来,利用不等式 \(\ln(1+x) - x \le -x^2/4\) 对于 \(x \in (0,1)\) 成立(可以通过考察函数 \(g(x)=\ln(1+x)-x+x^2/4\) 的导数 \(g'(x)=\frac{1}{1+x}-1+\frac{x}{2} = \frac{-x+x(1+x)/2}{1+x} = \frac{-x+x/2+x^2/2}{1+x} = \frac{-x/2+x^2/2}{1+x} = \frac{x(x-1)/2}{1+x} \le 0\) 来证明,所以 \(g(x) \le g(0) = 0\))。 因此,我们得到:

\[ P(\Vert u \Vert^2 - 1 > \epsilon) \le \exp\left(\frac{n}{2}(-\epsilon^2/4)\right) = \exp(-n\epsilon^2/8) \]

对于下尾概率 \(P(\Vert u \Vert^2 - 1 < -\epsilon)\),即 \(P(1 - \Vert u \Vert^2 > \epsilon)\),我们可以类似地使用马尔可夫不等式,或者利用对称性得到相同的上界。将这两个上界相加,即可得到单位向量模长集中引理的最终形式:

\[ P\left(\left| \Vert u \Vert^2 - 1 \right| \ge \epsilon\right) \le 2\exp(-n\epsilon^2/8) \]

Johnson-Lindenstrauss (JL) 引理

JL 引理是高维数据降维的核心理论之一。它指出,对于任意一组在 \(m\) 维欧氏空间中的 \(N\) 个向量 \(v_1, \ldots, v_N \in \mathbb{R}^m\),如果目标维度 \(d\) 满足 \(d > \frac{24 \ln N}{\epsilon^2}\) (其中 \(\epsilon \in (0,1)\) 是一个误差参数),那么存在一个随机线性映射 \(f: \mathbb{R}^m \to \mathbb{R}^d\)(通常通过随机矩阵实现),使得以至少 \(\frac{N-1}{N}\) 的概率,所有向量对之间的欧氏距离近似保持不变:

\[ \forall i \neq j, \quad (1-\epsilon)\Vert v_i - v_j \Vert^2 \le \Vert f(v_i) - f(v_j) \Vert^2 \le (1+\epsilon)\Vert v_i - v_j \Vert^2 \]

该引理的关键在于,所需的低维空间维度 \(d\) 只依赖于数据点的数量 \(N\) 和允许的误差 \(\epsilon\),而与原始维度 \(m\) 无关。这使得在处理大规模高维数据集时,JL 引理成为降维的有力工具。

证明概述

构造随机矩阵 \(A \in \mathbb{R}^{d \times m}\),其每个元素 \(A_{ij}\) 独立地从 \(N(0, 1/d)\) 分布中采样。对于任意向量 \(x \in \mathbb{R}^m\),映射后的向量为 \(Ax\)。 考虑任意一个非零向量 \(u = v_i - v_j\)。我们希望证明 \(\Vert Au \Vert^2\) 约等于 \(\Vert u \Vert^2\)。 令 \(u' = u / \Vert u \Vert\) 是单位向量。那么 \(\Vert Au \Vert^2 = \Vert u \Vert^2 \Vert Au' \Vert^2\)。 我们关注 \(P\left(\left| \Vert Au' \Vert^2 - 1 \right| \ge \epsilon\right)\)。 根据前面的单位向量模长集中引理,如果 \(A\) 的每一行都是从 \(N(0, 1/d)\) 中采样的,那么 \(Au'\) 的每个分量也将是 \(N(0, 1/d)\) 分布的。因此,我们可以直接应用该引理,将 \(n\) 替换为 \(d\),得到:

\[ P\left(\left| \Vert Au' \Vert^2 - 1 \right| \ge \epsilon\right) \le 2\exp(-\epsilon^2 d/8) \]

这个概率是针对一对特定的向量 \(v_i, v_j\) 而言的。由于有 \(\binom{N}{2}\) 对不同的向量,我们需要使用联合界 (Union Bound) 来保证所有距离同时满足条件。因此,至少存在一对向量距离被破坏的概率为:

\[ P\left(\exists i \neq j, \left| \frac{\Vert A(v_i - v_j) \Vert^2}{\Vert v_i - v_j \Vert^2} - 1 \right| \ge \epsilon\right) \le \binom{N}{2} \cdot 2\exp(-\epsilon^2 d/8) \] \[ \le N^2 \cdot \exp(-\epsilon^2 d/8) \] 我们希望这个概率非常小,例如小于 \(1/N\)。 如果 \(d > \frac{24 \ln N}{\epsilon^2}\),那么 \(\epsilon^2 d/8 > 3 \ln N\)。 因此 \(\exp(-\epsilon^2 d/8) < \exp(-3 \ln N) = N^{-3}\)。 所以, \[ N^2 \cdot \exp(-\epsilon^2 d/8) < N^2 \cdot N^{-3} = 1/N \] 所以,所有距离都保持在 \(1 \pm \epsilon\) 范围内的概率至少为 \(1 - 1/N = \frac{N-1}{N}\)。证毕。

尽管理论上 \(d\) 只需要 \(O(\log N)\) 维度,但在实际应用中,常数因子 \(24/\epsilon^2\) 使得对于较小的 \(\epsilon\) 值,所需的维度 \(d\) 仍然可能相对较大。因此,选择合适的 \(\epsilon\) 对于实际降维效果至关重要。

Box-Muller 变换:快速生成正态分布随机数

在模拟随机投影或任何需要正态分布随机数的场景中,Box-Muller 变换是一个常用的高效方法。它能够将两个独立的、服从 \((0,1)\) 均匀分布的随机数转换为两个独立的、服从标准正态分布 \(N(0,1)\) 的随机数。

设 \(U_1, U_2\) 是两个独立的 \((0,1)\) 均匀分布随机数,则通过以下公式可以得到两个独立的标准正态分布随机数 \(Z_0, Z_1\):

\[ Z_0 = \sqrt{-2\ln U_1}\cos(2\pi U_2) \] \[ Z_1 = \sqrt{-2\ln U_1}\sin(2\pi U_2) \]

如果需要均值为 \(\mu\)、标准差为 \(\sigma\) 的正态分布随机数,只需进行线性变换:\(X = \sigma Z_0 + \mu\) 和 \(Y = \sigma Z_1 + \mu\)。

C++ 实现示例

下面通过 C++ 代码演示如何使用 Box-Muller 变换生成正态分布随机数,并应用 JL 引理进行降维,最后验证降维前后向量距离的近似保持特性。

#include <iostream>
#include <vector>
#include <cmath>
#include <random>
#include <numeric> // for std::accumulate

// 使用 Box-Muller 变换生成一个标准正态分布 N(0,1) 随机数
// 为了效率,可以一次生成两个并缓存一个,此处简化为每次生成一个
double generateStandardNormal() {
    static std::random_device rd;
    static std::mt19937 generator(rd());
    static std::uniform_real_distribution<> uniform_dist(0.0, 1.0);
    
    // 生成两个均匀分布随机数
    double u1 = uniform_dist(generator);
    double u2 = uniform_dist(generator);
    
    // 应用 Box-Muller 变换
    return std::sqrt(-2.0 * std::log(u1)) * std::cos(2.0 * M_PI * u2);
}

// 计算两个向量的欧氏距离的平方
double calculateSquaredEuclideanDistance(const std::vector<double>& vec_a, const std::vector<double>& vec_b) {
    double sum_sq_diff = 0.0;
    for (size_t i = 0; i < vec_a.size(); ++i) {
        double diff = vec_a[i] - vec_b[i];
        sum_sq_diff += diff * diff;
    }
    return sum_sq_diff;
}

// 随机生成 N 个 K 维的向量,每个分量服从 N(0,1)
std::vector<std::vector<double>> createRandomHighDimVectors(int num_vectors, int high_dim) {
    std::vector<std::vector<double>> data_vectors(num_vectors, std::vector<double>(high_dim));
    for (int i = 0; i < num_vectors; ++i) {
        for (int j = 0; j < high_dim; ++j) {
            data_vectors[i][j] = generateStandardNormal();
        }
    }
    return data_vectors;
}

// 应用 Johnson-Lindenstrauss 随机投影降维
// 这里的随机矩阵A的元素是 N(0, 1/sqrt(target_dim)),或者 N(0,1) 然后投影结果乘以 1/sqrt(target_dim)
// 本实现采用后者,即随机矩阵A的元素直接通过 generateStandardNormal() 得到 N(0,1)
// 然后投影结果除以 sqrt(target_dim) 进行缩放,这在数学上是等价的
std::vector<std::vector<double>> applyJLProjection(
    const std::vector<std::vector<double>>& original_vectors, 
    int target_dim) {
    
    int num_vectors = original_vectors.size();
    int high_dim = original_vectors[0].size();
    
    std::vector<std::vector<double>> projected_vectors(num_vectors, std::vector<double>(target_dim));
    
    // 构建一个临时的随机投影矩阵(元素为N(0,1))
    // 实际操作中,为了避免内存开销,可以每次需要时生成,但这里为清晰性模拟矩阵生成
    // 或者如原代码所示,每次乘法时生成随机数
    // 我们按照原代码的逻辑:每次计算投影分量时,独立生成矩阵元素
    
    for (int i = 0; i < num_vectors; ++i) { // 遍历每个原始向量
        for (int j = 0; j < target_dim; ++j) { // 遍历投影后向量的每个分量
            double sum_product = 0.0;
            for (int k = 0; k < high_dim; ++k) { // 向量与随机矩阵一行相乘
                // 这里的 generateStandardNormal() 相当于 A_jk 矩阵的元素
                sum_product += original_vectors[i][k] * generateStandardNormal();
            }
            // 按照 JL 引理的常见实现,投影结果需要乘以 1/sqrt(target_dim)
            projected_vectors[i][j] = sum_product / std::sqrt(static_cast<double>(target_dim));
        }
    }
    
    return projected_vectors;
}

// 计算所有向量对之间欧氏距离平方的和
double sumAllPairwiseSquaredDistances(const std::vector<std::vector<double>>& vectors) {
    double total_squared_distance = 0.0;
    int num_vectors = vectors.size();
    
    for (int i = 0; i < num_vectors; ++i) {
        for (int j = i + 1; j < num_vectors; ++j) {
            total_squared_distance += calculateSquaredEuclideanDistance(vectors[i], vectors[j]);
        }
    }
    
    return total_squared_distance;
}

int main() {
    std::cout << "请输入向量数量 N 和原始维度 K: ";
    int N, K;
    std::cin >> N >> K;

    double epsilon = 0.5; // 允许的距离误差
    // 根据 JL 引理计算目标维度 D
    int D = static_cast<int>(std::ceil(24.0 * std::log(static_cast<double>(N)) / (epsilon * epsilon)));
    
    std::cerr << "根据 JL 引理,目标维度 D = " << D << std::endl;
    if (D > K) {
        std::cerr << "警告: 目标维度 D (" << D << ") 大于原始维度 K (" << K << ")。降维效果可能不明显或无降维。" << std::endl;
        D = K; // 在这种情况下,我们选择不进行实际降维
    }
	
    auto high_dim_vectors = createRandomHighDimVectors(N, K);
    auto low_dim_vectors = applyJLProjection(high_dim_vectors, D);

    // 计算原始空间中所有向量对的欧氏距离平方和
    double original_sum_sq_dist = sumAllPairwiseSquaredDistances(high_dim_vectors);
    // 计算投影后空间中所有向量对的欧氏距离平方和
    double projected_sum_sq_dist = sumAllPairwiseSquaredDistances(low_dim_vectors);

    std::cout << "原始空间中所有向量对的欧氏距离平方和: " << original_sum_sq_dist << std::endl;
    std::cout << "投影空间中所有向量对的欧氏距离平方和: " << projected_sum_sq_dist << std::endl;

    double ratio = projected_sum_sq_dist / original_sum_sq_dist;
    std::cout << "投影距离平方和与原始距离平方和的比值 (应在 " 
              << 1.0 - epsilon << " 到 " << 1.0 + epsilon << " 之间): " << ratio << std::endl;
    
    return 0;
}

当输入向量数量 \(N=100\),原始维度 \(K=2000\),允许误差 \(\epsilon=0.5\) 时,根据 JL 引理,计算出的目标维度 \(D \approx \lceil 24 \ln(100) / 0.5^2 \rceil = \lceil 24 \times 4.605 / 0.25 \rceil = \lceil 442.08 \rceil = 443\)。

运行示例代码,可能得到如下结果:

请输入向量数量 N 和原始维度 K: 100 2000
根据 JL 引理,目标维度 D = 443
原始空间中所有向量对的欧氏距离平方和: 4976860.54
投影空间中所有向量对的欧氏距离平方和: 4981123.71
投影距离平方和与原始距离平方和的比值 (应在 0.5 到 1.5 之间): 1.000856

从结果可以看出,投影后的距离平方和与原始距离平方和非常接近,比值 \(1.000856\) 确实落在 \([1-\epsilon, 1+\epsilon] = [0.5, 1.5]\) 的区间内。这验证了 Johnson-Lindenstrauss 引理在实际数据降维中的有效性。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

linux screen 用法详情 (nohup 的替代方案)

一、screen 是什么?能干嘛?screen 是一个终端复用器,可以:在一个 SSH 会话中开多个“虚拟终端”SSH 断线后,程序仍然在后台运行随时重新连接到原来的会话特别适合:nohup 的替代方案跑脚本 / 爬虫 / 训练模型运维、远程开发二、安装 screen# CentOS / Rocky / Almayum install -y screen# Debian / Ubuntuapt i...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。