用于高维数据近似最近邻搜索(Approximate Nearest Neighbor, ANN)的高效算法。
其核心思想是通过哈希函数将相似的数据点以高概率映射到同一个“桶”中,从而在查询时仅需比较同一桶内的数据,大幅降低计算复杂度。
LSH 的核心原理
-
局部敏感性
哈希函数族 HH 需要满足:-
相似数据的碰撞概率高:若 d(x,y)≤R,则 P[h(x)=h(y)]≥p1;
-
不相似数据的碰撞概率低:若 d(x,y)≥cR(c>1),则 P[h(x)=h(y)]≤p2(p1≫p2)。
注:d(x,y)是数据点之间的距离度量(如欧氏距离、余弦相似度等)。
-
-
哈希函数设计
LSH 的哈希函数针对不同距离度量有不同的实现方式:-
欧氏距离:随机投影(Random Projection)或稳定分布(如 p-stable LSH)。
-
余弦相似度:符号随机投影(Sign Random Projection)。
-
Jaccard 相似度:MinHash(用于集合相似度)。
-
常见 LSH 方法
1. 随机投影(Random Projection)
-
适用场景:欧氏距离或余弦相似度。
-
实现:
-
随机生成超平面(法向量),将数据点投影到超平面的法向量方向。
-
根据投影值的符号(正/负)生成哈希值。
例如:h(x)=sign(w⋅x+b),其中 w 是随机向量,b 是随机偏移。
-
2. MinHash
-
适用场景:集合的 Jaccard 相似度(如文档相似性、推荐系统)。
-
实现:
-
对集合元素进行随机排列(或通过哈希模拟排列)。
-
记录每个集合在排列后第一个出现的元素作为哈希值。
Jaccard 相似度越高,MinHash 值相同的概率越大。
-
3. SimHash
-
适用场景:文本相似性(如网页去重)。
-
实现:
-
将文本表示为高维向量(如词频或 TF-IDF)。
-
通过随机投影将向量映射到低维二进制哈希码。
相似文本的 SimHash 码汉明距离较小。
-
LSH 的典型应用
-
推荐系统:快速找到相似用户或物品。
-
图像/视频检索:基于特征向量的近似搜索。
-
文本去重:检测相似文档或网页。
-
生物信息学:基因序列比对。
实现步骤
-
选择哈希函数族:根据距离度量选择合适的 LSH 方法(如 MinHash 或随机投影)。
-
构建哈希表:
-
使用多个哈希函数(或哈希表)提高召回率。
-
每个哈希函数生成一个哈希值,组合多个哈希值为键(如 g(x) =[h1(x),h2(x),...,hk(x)])。
-
-
查询处理:
-
计算查询点的哈希值,检索对应桶中的所有候选点。
-
对候选点进行精确距离计算,返回最近邻。
-
优缺点
优点:
-
高效:时间复杂度从 O(N) 降至接近 O(1)。
-
可扩展:适用于海量高维数据(如千万级图像检索)。
-
节省存储:哈希表结构比原始数据更紧凑。
缺点:
-
近似结果:无法保证找到精确最近邻。
-
参数敏感:需平衡哈希函数数量、桶大小等参数,以权衡召回率与计算成本。
-
维度影响:部分方法在高维空间中效果下降(维度灾难)。
示例代码(MinHash 实现)
import numpy as np
from datasketch import MinHash
# 创建两个集合
set1 = set(["apple", "banana", "cherry"])
set2 = set(["apple", "banana", "durian"])
# 初始化 MinHash
m1 = MinHash(num_perm=128)
m2 = MinHash(num_perm=128)
# 添加元素到 MinHash
for d in set1:
m1.update(d.encode('utf8'))
for d in set2:
m2.update(d.encode('utf8'))
# 计算 Jaccard 相似度估计值
print("Estimated Jaccard:", m1.jaccard(m2))