Mining Massive Data: Minhash & Locality Sensitive Hash

来源:互联网 发布:软件测试总结 编辑:程序博客网 时间:2024/05/27 20:13

Mining Massive Data学习笔记

——————minhash & LSH


在互联网上有很多相似的文章,如果我们想要在互联网上找到相似的文章,那么我们就需要minhash和LSH。算法的主要思想是先用minhash把大量的数据降维,然后有LSH找到我们关心的相似的集合。

1. Shingles

首先我们需要把互联网上的数据转换为我们的数据集合,我们一般使用k-shingle来表示数据。k-shingle就是连续的k个字符,我们从网页的第一个字符开始,依次取连续的k个字符放到我们的数据集中,就组成了shingle的集合。如对abcab,k=2,那么我们得到的集合就是{ab,bc,ca},用这样一个集合我们就能够表示一个网页。通常对于不同的数据我们用不同的k,对email来说k=5就足够了,对网页的话k可以取10。因为若是k过小,比如k=1,那么我们得到的集合的相似度就会非常高,不利于我们后面的比较。

在k=10的情况下,如果我们还想继续缩小数据量,可以用一个hash函数把得到的由长度为10的元素组成的集合映射成长度较短(如4)的元素组成的集合

2. Jaccard Similarity

Jaccard相似度是衡量两个集合是否相似的一个量。对于两个集合,他们的交集中n个元素,并集中m个元素,那么Jaccard Similarity就是n/m

我们可以通过比较两个网页的Jaccard相似度来判断他们是否相似。但是由于网上的网页太多,而且每个网页得到的数据集合也非常多,直接比较显然不现实,所以我们需要对数据进行压缩降维。

首先我们把数据集用布尔矩阵表示出来

矩阵的行是所有得到的集合中可能出现的元素,列就表示各个集合。若某个元素在一个集合中,那么这个元素的相对应的行和这个集合相对应的列的位置的值就是1,否则为0。这个矩阵显然是个稀疏矩阵。

只考虑两列,也就是两个集合的对比。我们可以得到4种行

a

11

b

10

c

01

d

00

行a就是两个集合中都由某个元素,d是两个集合都没某个元素,依此类推。
这样的话两个集合的Jaccard相似度就是a/(a+b+c),也就是矩阵的列的相似度

3. minhash

我们把数据用上面的矩阵表示出来之后发现对于大量的数据来说,矩阵可以变得非常大,显然我们仍然无法比较相似度。因此我们引入了minhash对这个矩阵进行降维。

minhashing function: h(C) =打乱后的C列中,第一次遇到1的次数,就是说我们首先把矩阵的行随机打乱,然后对于某个集合(也就是矩阵的一列),minhash的值就是在打乱后的矩阵中扫描行,查找第一次出现1的行。

然后我们就得到了一个奇妙的结论:对于两列C1和C2,h(C1)=h(C2)的概率和就等于Jaccard相似度!(具体证明看video),那么我们只需要进行m次minhash,算出来hi(C1)=hi(C2)的次数是n,那么Jaccard就可以用minhash的结果来表示成n/m了。若是把每次minhash的结果放到一行中,那么当m远小于所有元素的个数x时,就达到了降维的目的,但是同时我们仍然可以从m维的矩阵中得到Jaccard相似度。

想法很好,但是由于元素很多,我们想要对上面的矩阵进行随机排序仍然是不可能的,所以我们使用下面的方法来近似得到一个随机的排序:选择若干个hash函数hi,对每个hi(r)和列c,选择一个槽函数M(i,c)。扫描行r,当r行c列的值为1时,M(i,c)取最小的hi(r)的值。这样的话的得到的每一行M(i,c)就可以去近似某个排序的h(c)

大致的意思就是找一个hash函数hi,把行号映射成一个数hi(r),对于所有的行r,我们取最小的hi(r)作为minhash的结果,因为对于不同的hash函数使hi(r)取最小的行号r不同,所以我们就用这个hi(r)来近似minhash的结果。那这个结果为什么又能代替minhash的结果表示Jaccard相似度呢?假设两个集合相似度为s,他们在某一行的值都是1的概率也是s,若都是1,那么hi(r)就同时把他们映射成同一个结果。最终我们得到的是一个m行c列的矩阵,m行是hash函数hi的个数,c列是集合(也就是不同网页)的个数,我们成功地把原来行数非常多的矩阵压缩成了一个m行的矩阵,这个矩阵我们称之为特征矩阵(Signature Matrix)。特征矩阵中某一行的两列相等的概率就是这两列的Jaccard相似度,也就是相应集合(网页)的相似度。

4. Locality Sensitive Hash

我们想要从特征矩阵中找到相似的列,但是由于列很多,虽然降过维了两两比较仍然是不现实的。这个时候我们就需要LSH方法

我们把得到的特征矩阵沿行分成b段,每段r行,那么上面得到的特征矩阵共有b*r行。
每个段都有一个hash函数,把段中一列的r个元素组成的向量hash到某个桶中,需要注意不同的段中的向量不会hash到一个桶中。
对于两列,假设他们的Jaccard相似度是s,那么对于我们的矩阵的某一行,两个值相等的概率就是s。那么对于某一段(r行),这两列映射到同一个桶中(两列完全相等)的概率就是s^r,那么所有的段中这两列都不相等的概率就是(1-s^r)^b,那么b段中至少有一段这两列完全相等的概率就是1-(1-s^r)^b
对于我们来说,这两列的b段中只要有一段相等(这也就意味着至少有r个signature是相等的),我们就可以判断这两列是相似的

所以我们并不需要两两比较,我们只需要在这些桶中寻找,只要hash函数把某两列的某一段映射到同一个桶中,那这两列就有很大的可能性相似。

在实际应用中,我们希望有一个阈值t,当s>t时,就判断二者相似,否则不相似
在我们的算法里面,这个t大约等于(1/b)^(1/r),也就是说我们可以通过选择b和r来确定这个阈值,当实际集合的相似度大于这个阈值的时候,我们的算法就有很大的可能性判断二者相似,而事实情况也是这样:
当s=0.8时,1-(1-s^r)^b=0.9996,意思就是说当两个集合的实际相似度为0.8时,在我们选择的b和r下,
至少有一段映射到同一个桶的概率是0.9996,那么我们能够判断出二者相似的概率就是0.9996。当然我们还有0.0004的概率错误地判断二者不相似,但是一般来说可以忽略不计。


0 0
原创粉丝点击