LSH 哈希函数设计与选择:MinHash、SimHash 及其他
想必你已经对局部敏感哈希(Locality Sensitive Hashing,LSH)有了相当的了解,LSH 的核心思想在于利用哈希函数将高维数据映射到低维空间,同时保持相似的数据点在哈希后仍然有较高的概率被映射到同一个桶中。那么,如何设计和选择合适的哈希函数,就成了 LSH 算法性能的关键。今天,咱们就来深入聊聊 LSH 哈希函数的设计与选择,包括常见的哈希函数类型(如 MinHash、SimHash 等),以及如何根据不同的数据类型和应用场景选择合适的哈希函数。
啥是 LSH 哈希函数?
在深入探讨之前,咱先明确一下,LSH 哈希函数跟平时说的哈希函数(比如 MD5、SHA-256)可不太一样。普通的哈希函数追求的是“雪崩效应”,也就是输入数据的微小变化会导致哈希值的巨大变化。而 LSH 哈希函数则相反,它希望相似的数据点经过哈希后,仍然有很大概率得到相同的哈希值,或者说“碰撞”到一起。
更正式地说,LSH 哈希函数族 H 满足以下性质:
如果 d(x, y) ≤ r1,则 P(h(x) = h(y)) ≥ p1;
如果 d(x, y) ≥ r2,则 P(h(x) = h(y)) ≤ p2。
其中:
- d(x, y) 表示数据点 x 和 y 之间的距离(或相似度);
- r1 和 r2 是距离阈值,r1 < r2;
- p1 和 p2 是概率阈值,p1 > p2;
- h(x) 和 h(y) 分别表示 x 和 y 经过哈希函数 h 后的哈希值。
也就是说,如果两个数据点很近(距离小于 r1),那么它们哈希值相同的概率至少是 p1;如果两个数据点很远(距离大于 r2),那么它们哈希值相同的概率至多是 p2。这样的哈希函数族被称为 (r1, r2, p1, p2)-sensitive。
常见的 LSH 哈希函数类型
根据不同的距离度量和数据类型,LSH 哈希函数有很多种。下面介绍几种常见的:
1. MinHash(最小哈希)
MinHash 主要用于处理集合数据,比如文档、用户购买记录等。它基于 Jaccard 相似度来衡量集合之间的相似性。Jaccard 相似度的计算公式是:
J(A, B) = |A ∩ B| / |A ∪ B|
其中,A 和 B 是两个集合,|A ∩ B| 表示 A 和 B 的交集大小,|A ∪ B| 表示 A 和 B 的并集大小。Jaccard 相似度的值域是 [0, 1],值越大表示两个集合越相似。
MinHash 的基本思想是:对集合中的元素进行多次随机排列,每次取排列后的第一个元素作为哈希值。这样,两个集合的 MinHash 值相等的概率就等于它们的 Jaccard 相似度。
具体步骤:
- 将集合中的所有元素(比如文档中的所有词)映射成一个整数集合。
- 选择 k 个独立的随机排列(或者说哈希函数)。
- 对于每个集合,计算 k 个 MinHash 值:对于每个随机排列,取排列后第一个出现的元素作为哈希值。
- 将 k 个 MinHash 值组合起来,形成一个签名向量。
举个栗子:
假设有两个集合:
A = {a, b, c, d}
B = {b, c, e, f}
假设我们选择两个随机排列:
排列 1:c, a, b, d, e, f
排列 2:b, f, a, c, d, e
那么:
- A 的 MinHash 值为 (c, b)
- B 的 MinHash 值为 (c, b)
这两个集合的 MinHash 值完全相同,因为它们的 Jaccard 相似度较高(2/6)。
2. SimHash(相似哈希)
SimHash 主要用于处理文本数据,比如网页、文档等。它基于余弦相似度来衡量文本之间的相似性。余弦相似度的计算公式是:
cos(θ) = (A · B) / (||A|| * ||B||)
其中,A 和 B 是两个文本的向量表示(比如 TF-IDF 向量),A · B 表示向量的点积,||A|| 和 ||B|| 分别表示向量的模长。余弦相似度的值域是 [-1, 1],值越大表示两个文本越相似。
SimHash 的基本思想是:将文本的向量表示降维成一个 f 位的二进制指纹(fingerprint)。对于每一位,如果该位对应的向量分量为正,则加 1,否则减 1。最后,将每一位的值根据阈值(通常是 0)转换为 0 或 1,得到最终的指纹。
具体步骤:
- 将文本分词,并计算每个词的权重(比如 TF-IDF 值)。
- 初始化一个 f 位的零向量 v。
- 对于每个词,计算一个 f 位的哈希值(比如使用 MD5 或 SHA-256)。
- 根据哈希值的每一位,更新向量 v:如果该位为 1,则 v 的对应分量加上该词的权重;如果该位为 0,则 v 的对应分量减去该词的权重。
- 将向量 v 的每个分量根据阈值(通常是 0)转换为 0 或 1,得到最终的 f 位指纹。
举个栗子:
假设有一段文本:“今天天气真好,适合出去玩。”
假设分词和权重计算结果如下:
- 今天:0.2
- 天气:0.3
- 真好:0.4
- 适合:0.1
- 出去玩:0.2
假设我们使用一个 8 位的哈希函数,并假设每个词的哈希值如下:
- 今天:10101100
- 天气:01100110
- 真好:11011011
- 适合:00110010
- 出去玩:10010101
那么,我们可以按照上述步骤计算出 SimHash 指纹。最后可能得到一个类似于 10110010 的指纹。
3. 基于随机投影的 LSH
对于欧氏空间中的数据,可以使用基于随机投影的 LSH 方法。这种方法的基本思想是:将数据点投影到一条随机直线上,然后根据投影点的位置进行哈希。
具体步骤:
- 生成一个随机向量 r,其每个分量都服从标准正态分布。
- 选择一个常数 b。
- 对于每个数据点 x,计算哈希值:h(x) = floor((r · x + b) / w),其中 w 是一个常数,floor() 表示向下取整。
可以证明,这种哈希函数族是 (r1, r2, p1, p2)-sensitive 的,其中 p1 和 p2 的值取决于 w 和距离度量。
4. 其他 LSH 哈希函数
除了上述几种常见的 LSH 哈希函数外,还有很多其他的 LSH 哈希函数,比如:
- p-stable LSH:适用于 p-范数距离(比如曼哈顿距离、欧氏距离)。
- 球面 LSH:适用于球面距离。
- 汉明距离 LSH:适用于二进制数据。
- 等等...
如何选择合适的 LSH 哈希函数?
选择 LSH 哈希函数时,主要考虑以下几个因素:
- 数据类型:不同的数据类型需要使用不同的哈希函数。比如,集合数据适合使用 MinHash,文本数据适合使用 SimHash,欧氏空间中的数据适合使用基于随机投影的 LSH。
- 距离度量:LSH 哈希函数需要与距离度量相匹配。比如,MinHash 适用于 Jaccard 相似度,SimHash 适用于余弦相似度,基于随机投影的 LSH 适用于欧氏距离。
- 查询效率:不同的哈希函数有不同的查询效率。一般来说,哈希函数的计算复杂度越低,查询效率越高。但是,过于简单的哈希函数可能会导致精度下降。
- 内存占用:不同的哈希函数有不同的内存占用。一般来说,哈希函数的位数越多,内存占用越大。但是,位数太少可能会导致精度下降。
- 应用场景:不同的应用场景对 LSH 的要求不同。比如,对于大规模数据去重,需要选择计算效率高、内存占用低的哈希函数;对于相似性搜索,需要选择精度高的哈希函数。
总的来说,选择 LSH 哈希函数是一个权衡的过程,需要根据具体情况进行综合考虑。没有一种哈希函数是万能的,只有最适合的。
总结
LSH 哈希函数的设计与选择是 LSH 算法的关键。不同的数据类型、距离度量和应用场景需要选择不同的哈希函数。常见的 LSH 哈希函数包括 MinHash、SimHash、基于随机投影的 LSH 等。选择合适的 LSH 哈希函数需要综合考虑查询效率、内存占用、精度等因素。希望今天的分享能让你对 LSH 哈希函数有更深入的了解,并在实际应用中做出更明智的选择。如果你还有其他问题,欢迎随时提问!