Johnson-Lindenstrauss 引理及其在数据降维中的应用
在处理高维数据时,维度灾难是一个常见挑战。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 引理在实际数据降维中的有效性。