局部敏感哈希(Locality-Sensitive Hashing, LSH)

用于高维数据近似最近邻搜索(Approximate Nearest Neighbor, ANN)的高效算法。

其核心思想是通过哈希函数相似的数据点高概率映射到同一个“桶”中,从而在查询时仅需比较同一桶内的数据,大幅降低计算复杂度。


LSH 的核心原理

  1. 局部敏感性
    哈希函数族 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)是数据点之间的距离度量(如欧氏距离、余弦相似度等)。

  2. 哈希函数设计
    LSH 的哈希函数针对不同距离度量有不同的实现方式:

    • 欧氏距离:随机投影(Random Projection)或稳定分布(如 p-stable LSH)。

    • 余弦相似度:符号随机投影(Sign Random Projection)。

    • Jaccard 相似度:MinHash(用于集合相似度)。


常见 LSH 方法

1. 随机投影(Random Projection)
  • 适用场景:欧氏距离或余弦相似度。

  • 实现

    1. 随机生成超平面(法向量),将数据点投影到超平面的法向量方向

    2. 根据投影值的符号(正/负)生成哈希值
      例如:h(x)=sign(w⋅x+b),其中 w 是随机向量,b 是随机偏移。

2. MinHash
  • 适用场景:集合的 Jaccard 相似度(如文档相似性、推荐系统)。

  • 实现

    1. 对集合元素进行随机排列(或通过哈希模拟排列)。

    2. 记录每个集合在排列后第一个出现的元素作为哈希值。
      Jaccard 相似度越高,MinHash 值相同的概率越大。

3. SimHash
  • 适用场景:文本相似性(如网页去重)。

  • 实现

    1. 将文本表示为高维向量(如词频或 TF-IDF)。

    2. 通过随机投影将向量映射到低维二进制哈希码
      相似文本的 SimHash 码汉明距离较小。


LSH 的典型应用

  1. 推荐系统:快速找到相似用户或物品。

  2. 图像/视频检索:基于特征向量的近似搜索。

  3. 文本去重:检测相似文档或网页。

  4. 生物信息学:基因序列比对。


实现步骤

  1. 选择哈希函数族根据距离度量选择合适的 LSH 方法(如 MinHash 或随机投影)。

  2. 构建哈希表:

    • 使用多个哈希函数(或哈希表)提高召回率。

    • 每个哈希函数生成一个哈希值,组合多个哈希值为键(如 g(x) =[h1(x),h2(x),...,hk(x)])。

  3. 查询处理

    • 计算查询点的哈希值,检索对应桶中的所有候选点。

    • 对候选点进行精确距离计算,返回最近邻。


优缺点

优点
  • 高效:时间复杂度从 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))