joey 周琦
本文首先介绍了局部敏感哈希的概念与用处,然后介绍了常见的快速计算相似度、寻找近邻的方法minHash, simHash
局部敏感哈希Locality-sensitive hashing (LSH)
定义
首先我们看看wiki上比较准确的英文描述[1]。
An LSH family
- if d(p,q)
≤ R, then h(p)=h(q) (i.e.,p and q collide) with probability at leastP1 ,- if d(p,q)
≥ cR, then h(p)=h(q) with probability at mostP2 .
A family is interesting whenP1>P2 . Such a familyF is called(R,cR,P1,P2) -sensitive.
wiki关于metric space给出的定义
In mathematics, a metric space is a set for which distances between all members of the set are defined. Those distances, taken together, are called a metric on the set.
根据上述信息,我中文理解下。 局部敏感哈希(Locality-sensitive hashing)是为了度量空间
- if d(p,q)
≤ R, then h(p)=h(q) (i.e.,p and q collide) with probability at leastP1 ,- if d(p,q)
≥ cR, then h(p)=h(q) with probability at mostP2 .
A family is interesting whenP1>P2 . Such a familyF is called(R,cR,P1,P2) -sensitive.
其中
横坐标表示距离,纵坐标可以理解两个点(下面用“点”来统一代替文档,item,或物品等名称,在应用都可以视为一种东西)被放入一个桶(即认为二者较为相似)的概率。可以看出LSH可以将距离较近的点以至少概率
意义Motivation
一个算法或概念的意义是很重要的。我们学习这个概念算法到底可以解决什么问题?适用于哪些场景?
刚才看了LSH的定义,那么这个东西有啥用,哪些场景可以用呢?如何在海量数据中找到一个高维度点相似的点集合?(搜索中找出最相关的query, 视频业务中找到最接近重复的视频,等等)最简单的方法是计算每个点与该点的距离,然后排序。然后如果面对海量数据,这种暴力计算的方法是不可取的。如果我们可以找到一类函数LSH,高效率的将任意两个点是否很接近找出来,就可以解决上述问题。常见的LSH方案有minHash,simHash. 下面分别简单介绍下
minHash
相关概念
- Jaccard similarity coefficient (Jaccard系数) 是常见的衡量两个集合相似度的度量:
J(A,B)=|A∩B||A∪B| - 利用矩阵代表集合,例:有四个集合
S1={a,d} ,S2={c} ,S3={b,d,e} ,S4={a,c,d} ,可用下图的矩阵表示[参考2]
minHashing
minHash ( min-wise independent permutation LSH scheme) 可以快速估计两个集合的相似度。为了minHash一个集合,首先将该集合用矩阵表示,然后随机选取行索引的一个排列(permutation), 该集合的minHash的值是按照这个排列遇见的第一个为1的行的索引。
下面看例子,将上述矩阵的行按照一个随机的排列如下,那么minHash(
性质
对于一个随机的排列,两个集合的minHash相等的概率等于两个集合的Jaccard相似度
即
证明参考[2]第三章,例子也来自于此书。
假设
在现实中排列一个很大的行索引也是很慢的,所以一般用随机的哈希函数来替代排列.
还是依据上面的矩阵表示,我们这里用两个哈希函数(x+1 mod 5 和3x+1 mod 5)代表两个排列.
对于第一个排列(x+1 mod 5)的含义,新第0行对应的第4行,新的第一行为原来的第0行,所以第一个排列的顺序为[4 0 1 2 3 4], 第二个排列为[3 0 2 4 1]. 那么根据minHash的定义,我们可以得到
当然这是我们根据肉眼看的,那么如何通过一个算法得到呢?
若S 表示集合的矩阵表示。初始化新的minHash矩阵K, 每列代表一个集合,每行代表一个排列,矩阵每个元素初始化为
1 根据哈希算出每行的
h1(i),...,hn(i).(i=1...N)
2 For i = 1:N
For c = 1:M
如果S[i,c]为0;跳过
否则;对于每个排列r=1…n, K(r,c) = min ( K(r,c), h_r(i) )
上述例子的更新过程如下面几幅图
通过上面的过程,每个集合就可以用一个
书[2]中描述了一种桶方式,可以高效率的找出相似的pair对。上面得到向量可以分为
- 两个点在一个段中,完全一样的概率为
sr - 两个点在一个段中,不完全一样的概率为
1−sr - 两个点在所有段中,不完全一样的概率为
(1−sr)b - 两个点至少有一个段相同的概率为,
1−(1−sr)b
最后一行的这个函数可以画成一个S曲线,横轴为Jaccard相似度,纵轴为被选择为相似对的概率
根据上述技术(Banding Technique), 就可以高效率的找出任意点的相似点有哪些。
上面我们看到了如何利用minHash和banding technique来对一个集合表示进行降维和快速找出近邻。
simHash
从上面可以minHash方法比较适合集合表示或者说(0,1)数据类型的降维与近邻查找。若某个点(如最开始说的,可以为item,object,物品,文档等等)在每个特征上面有相应的权重,如果想要利用上权重的信息那么minHash的方法就不适用了。可以使用simHash。
论文[4]提出simHash,论文[5]将simHash运用到了网页的去重应用中,并且给出了快速查找近邻的方法。下面我只简单介绍下simHash的实习方法,原理部分自己也没太搞懂。
输入:有很多点(doc or item or..),每个点可以用一串(feature,weight)((特征,权重))表示。
输出: 每个点用一个固定长度f的(如64)的二进制数表示
求解过程:
- 对于每个点p将其每个feature通过一个哈希函数(如MD5)哈希为二进制长度为f的值。如
[(hash[feature1],weight1),...,(hash[featureN],weightN)] ,每个点的特征数目可以不同。 - 若用浮点数组p_float(64位)来代表点p,具体方式如下, 对于每一位
i=1...64
-
v_float[i]=∑j=1N indicator(hash[featurej][i])⋅weightj - 其中
hash[featurej][i] 代表第j个特征的第i个bit位 - indicator是一个指示函数,indicator(f) = 1 if f>0 else -1
-
- 得到了浮点数组p_float, 那么数组的每一位若为正则点p的二进制表示的那位上为1,否则为0.
- 通过上述方式我们就讲任意点映射(压缩)到了一个固定长度的二进制数上了。利用这个结果可以进行快速查重,找近邻,聚类等功能
结论
一般情况若每个feature无权重,则minHash效果优于simHash[3], 有权重时simHash合适(因为minHash没办法用)
参考文献
- https://en.wikipedia.org/wiki/Locality-sensitive_hashing
- Mining of Massive Datasets
- In Defense of MinHash Over SimHash
- Similarity Estimation Techniques from Rounding Algorithms
- Detecting Near-Duplicates for Web Crawling: similiarty research