利用Minhash和LSH寻找类似的集合

from: https://www.cnblogs.com/bourneli/archive/2013/04/04/2999767.htmlhtml

问题背景算法

给出N个集合,找到类似的集合对,如何实现呢?直观的方法是比较任意两个集合。那么能够十分精确的找到每一对类似的集合,可是时间复杂度是O(n2)。当N比较小时,好比K级,此算法能够在接受的时间范围内完成,可是若是N变大时,比B级,甚至P级,那么须要的时间是不可以被接受的。好比N= 1B = 1,000,000,000。一台计算机每秒能够比较1,000,000,000对集合是否相等。那么大概须要15的时间才能找到全部类似的集合!框架

 

上面的算法虽然效率很低,可是结果会很精确,由于检查了每一对集合。假如,N个集合中只有少数几对集合类似,绝大多数集合都不等呢?那么根据上述算法,绝大多数检测的结果是两个结合不类似,能够说这些检测“浪费了计算时间”。因此,若是能找到一种算法,将大致上类似的集合聚到一块儿,缩小比对的范围,这样只用检测较少的集合对,就能够找到绝大多数类似的集合对,大幅度减小时间开销。虽然牺牲了一部分精度,可是若是可以将时间大幅度减小,这种算法仍是能够接受的。接下来的内容讲解如何使用Minhash和LSH(Locality-sensitive Hashing)来实现上述目的,在类似的集合较少的状况下,能够在O(n)时间找到大部分类似的集合对。函数

 

 

Jaccard类似度学习

判断两个集合是否相等,通常使用称之为Jaccard类似度的算法(后面用Jac(S1,S2)来表示集合S1和S2的Jaccard类似度)。举个列子,集合X = {a,b,c},Y = {b,c,d}。那么Jac(X,Y) = 2 / 3 = 0.67。也就是说,结合X和Y有67%的元素相同。下面是形式的表述Jaccard类似度公式:spa

Jac(X,Y) = |X∩Y| / |X∪Y|.net

也就是两个结合交集的个数比上两个集合并集的个数。范围在[0,1]之间。htm

 

 

降维技术Minhash对象

原始问题的关键在于计算时间太长。因此,若是可以找到一种很好的方法将原始集合压缩成更小的集合,并且又不失去类似性,那么能够缩短计算时间。Minhash能够帮助咱们解决这个问题。举个例子,S1 = {a,d,e},S2 = {c, e},设全集U = {a,b,c,d,e}。集合能够以下表示:blog

行号

元素

S1

S2

类别

1

a

1

0

Y

2

b

0

0

Z

3

c

0

1

Y

4

d

1

0

Y

5

e

1

1

X

表1

表1中,列表示集合,行表示元素,值1表示某个集合具备某个值,0则相反(X,Y,Z的意义后面讨论)。Minhash算法大致思路是:采用一种hash函数,将元素的位置均匀打乱,而后将新顺序下每一个集合第一个元素做为该集合的特征值。好比哈希函数h1(i) = (i + 1) % 5,其中i为行号。做用于集合S1和S2,获得以下结果:

行号

元素

S1

S2

类别

1

e

1

1

X

2

a

1

0

Y

3

b

0

0

Z

4

c

0

1

Y

5

d

1

0

Y

Minhash

e

e

 

 

 

表2

这时,Minhash(S1) = e,Minhash(S2) = e。也就是说用元素e表示S1,用元素e表示集合S2。那么这样作是否科学呢?进一步,若是Minhash(S1) 等于Minhash(S2),那么S1是否和S2相似呢?

 

一个神奇的结论

P(Minhash(S­1) = Minhash(S2)) = Jac(S1,S2)

在哈希函数h1均匀分布的状况下,集合S1的Minhash值和集合S2的Minhash值相等的几率等于集合S1与集合S2的Jaccard类似度,下面简单分析一下这个结论。

S1和S2的每一行元素能够分为三类:

l  X类 均为1。好比表2中的第1行,两个集合都有元素e。

l  Y类 一个为1,另外一个为0。好比表2中的第2行,代表S1有元素a,而S2没有。

l  Z类 均为0。好比表2中的第3行,两个集合都没有元素b。

这里忽略全部Z类的行,由于此类行对两个集合是否类似没有任何贡献。因为哈希函数将原始行号均匀分布到新的行号,这样能够认为在新的行号排列下,任意一行出现X类的状况的几率为|X|/(|X|+|Y|)。这里为了方便,将任意位置设为第一个出现X类行的行号。因此P(第一个出现X类) = |X|/(|X|+|Y|) = Jac(S1,S2)。这里很重要的一点就是要保证哈希函数能够将数值均匀分布,尽可能减小冲撞。

 

通常而言,会找出一系列的哈希函数,好比h个(h << |U|),为每个集合计算h次Minhash值,而后用h个Minhash值组成一个摘要来表示当前集合(注意Minhash的值的位置须要保持一致)。举个列子,仍是基于上面的例子,如今又有一个哈希函数h2(i) = (i -1)% 5。那么获得以下集合:

行号

元素

S1

S2

类别

1

b

0

0

Z

2

c

0

1

Y

3

d

1

0

Y

4

e

1

1

X

5

a

1

0

Y

Minhash

d

c

 

 

 

表3

 

因此,如今用摘要表示的原始集合以下:

哈希函数

S1

S2

h1(i) = (i + 1) % 5

e

e

h2(i) = (i - 1) % 5

d

c

表4

从表四还能够获得一个结论,令X表示Minhash摘要后的集合对应行相等的次数(好比表4,X=1,由于哈希函数h1状况下,两个集合的minhash相等,h2不等):

X ~ B(h,Jac(S1,S2))

X符合次数为h,几率为Jac(S1,S2)的二项分布。那么指望E(X) = h * Jac(S1,S2) = 2 * 2 / 3 = 1.33。也就是每2个hash计算Minhash摘要,能够指望有1.33元素对应相等。

因此,Minhash在压缩原始集合的状况下,保证了集合的类似度没有被破坏。

 

 

LSH – 局部敏感哈希

如今有了原始集合的摘要,可是仍是没有解决最初的问题,仍然须要遍历全部的集合对,,才能全部类似的集合对,复杂度仍然是O(n2)。因此,接下来描述解决这个问题的核心思想LSH。其基本思路是将类似的集合汇集到一块儿,减少查找范围,避免比较不类似的集合。仍然是从例子开始,如今有5个集合,计算出对应的Minhash摘要,以下:

 

 

 

S1

S2

S3

S4

S5

区间1

b

b

a

b

a

c

c

a

c

b

d

b

a

d

c

区间2

a

e

b

e

d

b

d

c

f

e

e

a

d

g

a

区间3

d

c

a

h

b

a

a

b

b

a

d

e

a

b

e

区间4

d

a

a

c

b

b

a

c

b

a

d

e

a

b

e

表5

上面的集合摘要采用了12个不一样的hash函数计算出来,而后分红了B = 4个区间。前面已经分析过,任意两个集合(S1,S2)对应的Minhash值相等的几率r = Jac(S1,S2)。先分析区间1,在这个区间内,P(集合S1等于集合S2) = r3。因此只要S­1和S2的Jaccard类似度越高,在区间1内越有可能完成全一致,反过来也同样。那么P(集合S1不等于集合S2) = 1 - r3。如今有4个区间,其余区间与第一个相同,因此P(4个区间上,集合S1都不等于集合S2) = (1 – r3)4。P(4个区间上,至少有一个区间,集合S1等于集合S2) = 1 - (1 – r3)4。这里的几率是一个r的函数,形状犹如一个S型,以下:

 

 

图1

若是令区间个数为B,每一个区间内的行数为C,那么上面的公式能够形式的表示为:

P(B个区间中至少有一个区间中两个结合相等) = 1 - (1 – rC)B

领r = 0.4,C=3,B = 100。上述公式计算的几率为0.9986585。这代表两个Jaccard类似度为0.4的集合在至少一个区间内冲撞的几率达到了99.9%。根据这一事实,咱们只须要选取合适的B和C,和一个冲撞率很低的hash函数,就能够将类似的集合至少在一个区间内冲撞,这样也就达成了本节最开始的目的:将类似的集合放到一块儿。具体的方法是为B个区间,准备B个hash表,和区间编号一一对应,而后用hash函数将每一个区间的部分集合映射到对应hash表里。最后遍历全部的hash表,将冲撞的集合做为候选对象进行比较,找出相识的集合对。整个过程是采用O(n)的时间复杂度,由于B和C均是常量。因为聚到一块儿的集合相比于总体比较少,因此在这小范围内互相比较的时间开销也能够计算为常量,那么整体的计算时间也是O(n)。

 

总结

以上只是描述了Minhash和LSH寻找类似集合的算法框架,做为学习笔记和备忘录。还有一些算法细节没有讨论。但愿后面有机会,能够在海量数据的状况下使用这个算法。

 

 

参考资料

[1]       书籍《Mining of Massive Datasets》的第三章Find Similar Item,由Anand Rajaraman,Jure Leskovec和Jeffrey David Ullman

[2]       Jaccard类似度、minHash、Locality-Sensitive Hashing(LSH)

[3]       Wiki上的Jaccard距离

[4]       Wiki上的Minhash

[5]       Wiki上的LSH

相关文章
相关标签/搜索