原载:http://cool.sinaapp.com
作者:junGle
原文网址:http://1.cool.sinaapp.com/?p=911
前文所说的minhash,比较的是jaccard相似度,基于两两来比较的话,如果文档数很大,比如:100w文档,根据排列组合公式可知,需要对比5000亿次。如果两篇文档签名相似度比较需要花费1微秒,那需要花费6天时间。
有啥办法能快速进行比较呢?有的,局部敏感哈希(locality-sensitive hashing, LSH)。
目标:减少对比次数
方法:通过多次哈希处理,让相似项尽可能落到同一桶中(确实相似的称为候选对,非相似的称为伪正例). 不相似的文档最好永远都不会哈希到相同的桶中。
————————————————————————————
一、MinHash的局部敏感哈希
以MinHash及其签名矩阵为例。
一个有效的哈希处理方法:将签名矩阵划分成多个band(行条, 行带),每个band由r行组成。对每个band,存在一个哈希函数能够将band中的每r个整数组成的列向量映射到某个大数目范围的哈希桶。对所有band使用相同的哈希函数,但是每个band都落在一个独立的桶数组中,因而保证了不同band间即使有列向量相同,也不会落到同一个桶中。
以12行的签名矩阵为例(每个band由3行组成):
假设:当且仅当两个向量相等时,才哈希到同一桶中
对于band1中, [0,2,1],有两列相同,因而落在相同桶中。[1,3,0]和[0,2,1]落在不同桶中。
整体上看,如果签名矩阵中的两列越相似,多个band中的向量相等的可能性也越大。
二、分析
假设:有b个行条(band),每个band都由r行组成,并假定对具体文档间的jaccard相似度为s。那么,文档的最小哈希签名矩阵中,某个具体行中的两个签名相等的概率等于s.
- 1.在某个band中,所有行的两两签名相等的概率为 :s^r; (幂运算)
- 2.在某个band中,至少有一对签名不相等的概率为:1-s^r;
- 3.在任何band中,任意一行的签名对都不相等的概率为:(1-s^r)^b;
- 4.签名至少在一个band中全部相等的概率(成为候选对的概率):1-(1-s^r)^b;
成为候选对的概率:1-(1-s^r)^b。这个概率函数曲线(S曲线:S-curve)如下所示。上升最陡的地方对应的相似度就是阀值(它是b和r的函数,阀值的一个近似估计是:(1/b)^(1/r))。
当b=20, r=5时,成为候选对的概率为:1-(1-s^5)^20, s的取值(相似程度)决定了候选对“抱团”的质量。
可以看到,当s=0.8时,1-(0.8)^5为0.328,其概率可以达到0.9996,也就是说,如果认为两篇文档的相似度达80%时,如果有3000个对,大致只有1个对相似度为80%的对不会成为候选对(3000*(1-0.9996)=1.2左右)。
【简单介绍下Jaccard距离】
d(x,y)=1-SIM(x,y)
三、局部敏感函数
3.1 (d1, d2, p1, p2)-sensitive
我们需要一个判定函数,函数f判定f(x,y)的两个输入项是否为候选对。
- x和y是一个候选对,用f(x)=f(y)表示
- x和y不是候选对,用f(x)≠f(y)表示
多个这种形式的函数集合构成一个“函数族”F。函数族F中的每个函数f,都基于特征矩阵的一个可能行排列转换而成。
令d1<d2是定义在某个距离测度d下的两个距离值。如果一个函数族F中的每一个函数f都满足下列条件:
(1)如果d(x,y)≤d1, 那么f(x)=f(y)的概率至少为p1;
(2)如果d(x,y)≥d2,那么f(x)=f(y)的概率最大是p2.
则称F为(d1,d2,p1,p2)-敏感的函数族;
有点“马太效应” 的味道在里头。
对于MinHash来说,换一个方法解释最小哈希函数h:当且仅当h(x)=h(y)时,x和y是一个候选对。(很容易理解)
于是有结论:
对于任意d1,d2,0≤d1<d2≤1,最小哈希函数族是 (d1, d2, 1-d1, 1-d2)-敏感 的。
推导:如果x,y的jaccard距离d(x,y)≤d1, 那么SIM(x,y)=1-d(x,y)≥1-d1。由x,y的jaccard相似度等于h(x)=h(y)的概率可知,上述p1≥SIM(x,y)≥1-d1。 对d2的推导类似。
设d1=0.3, d2=0.6,可以断言最小哈希函数族是 (0.3, 0.6, 0.7, 0.4)-sensitive 的。
也就是说,
如果x和y的jaccard距离不大于0.3, 那么x,y哈希到相同值的概率至少为0.7.
如果x和y之间的jaccard距离不小于0.6,那么最小哈希函数将x和y哈希到相同值的概率至多为0.4.
3.2 与构造:(d1, d2, p1^r, p2^r)-sensitive
F ‘ 的成员函数由r个F成员函数组成。=> 降低所有概率
3.3 或构造:(d1, d2, 1-(1-p1)^b, 1-(1-p2)^b)-sensitive
F ‘ 的成员函数f由b个F中的成员函数{f1, f2, f3, … , fb}组成。=> 提升所有概率
simhash的汉明距离
4. 利用 Simhash 查找相似文档
已知两篇文档 Simhash 值之间的海明距离越小,Jaccard 相似度越高,假设我们能够接受的最大海明距离为K,根据上面对 LSH 的描述,我们可以实现一种快速查找相似文档的方法:
- 对文档集中的每一篇文档:
- 计算一个 N 位的 Simhash 值,
- 对值按位做 T 次随机排列,得到 T 个 N 位的值,
- 对每个值取前 P 位生成 Key 存入词典,Value 为原 Simhash 值;
- 查找时:
- 对查找文档生成一个 N 位的 Simhash 值,
- 对值按位做 T 次随机排列,得到 T 个 N 位的值,
- 对每个值取前 P 位生成 Key 查找词典,计算原 Simhash 值和 Value 间的海明距离,
- 如果小于 K,则加入到结果中。
假设文档集中有一篇文档和查找文档的 Simhash 值间海明距离为 K,则上述查找过程能够找到这个文档(即Key 命中)的概率:
- 对某个排列,前 K 位相同的概率为:
(1-K/N)**P
- 对某个排列,前 K 位不相同的概率为:
1 - (1-K/N)**P
- 对 T 次排列,前 K 位都不相同的概率为:
(1 - (1-K/N)**P)**T
- 对 T 次排列,前 K 位至少有一次相同的概率为:
1 - (1 - (1-K/N)**P)**T
因此, Key 命中的概率为1 - (1 - (1-K/N)**P)**T
。
例如当 N=64,P=16,K=6,T=8
时,P = 0.791520
。
对于haming距离
假设两条相似消息的simhash每一位相同的概率为p
从64位里随机选取a位
这a位数相同的概率是p^a,不同的概率就是1-p^a
进行b次选取,每次取的a位数都不相同的概率就是(1-p^a)^b
这b次选取中有1次或以上a位数相同的概率是y=1-(1-p^a)^b
若汉明距离阀值定为8(<8即相似),那么对于两条相似的消息,p=(64-8)/64=0.875
然后,我们可以定义b个不同的0-64的排列,每个排列选前a个数,表示“随机选取a位,组成一个a位数”。
对每条消息,都计算b次这样的a位数,作为b个索引。
假设a=16,b=10,若一条消息是命中相似的,则有y=1-(1-0.875^16)^10 = 0.715=71%的概率可以通过以上方法建立的索引找到与其相似的消息
假设有100w消息,大约每条消息只要经过100w/(2^16)*10=152次汉明距离计算就有一定概率找到确实与其相似的消息,计算量降低了不少.