最小哈希签名(minhashing signature)解决的问题是,如何用一个哈希方法来对一个集合(集合大小为n)中的子集进行保留相似度的映射(使他在内存中占用的字节数尽可能的少)。
其实哈希本身并不算难,难的是怎么保留两个子集的相似度的信息。所谓保留相似度,就是说我们能十分直观的从两个子集的哈希结果中看出他们的相似度。当然,朴素的办法就用是一个长度为n的二进制数的每个位来分别对应集合中的每个元素。不过当n比较大而待hash的集合的数目比较小的时候,这种方法的效率就太低了。这时候最常用的方法就是对集合进行最小哈希。
什么叫最小哈希,我的理解是,一个很大的集合进行哈希处理的过程其实是由很多小的哈希过程组成。而这些最小的哈希过程就被称为是最小哈希。最小哈希的具体内容就是把一个集合映射到一个编号上。具体的过程也很简单了。
比如对于集合U=\{a,b,c,d,e\},S_1:\{a,d\},S_2:\{c\},S_3:\{b,d,e\},S_4:\{a,c,d\},我们用一个矩阵形式来表示他们:
那么,对他进行一次最小哈希就是在经过随机的行排列之后,对于每个集合,从上到下取第一个数值为1的那一行的行号。
比如对上面的矩阵进行随机行排列后变成:
那么每个集合的minhash结果就应该是h(S_1)=0,h(S_2)=2,h(S_3)=1,h(S_4)=0。
这就是minhash的基本方法。
在最小哈希的基础上,最小哈希签名也就很简单了。在最小哈希中,需要对每行进行随机行排列,如果是真随机排列的话显然计算消耗会特别大。因此实际上我们采用了一个替代方法,就是再用一个哈希函数,将行号进行哈希变换。比如当n=5时,对0,1,2,3,4这5个数,可以用h(x)=(3x+1)%5的方法进行映射,得到1,4,2,0,3。当然,随便找的h(x)=ax+b这种哈希函数显然可能会冲突,不过只要n和a互素,那么生成的一定是一个排列,这一点用同余类的知识很好证明。
不过显然,一次最小哈希的结果不能全面的表现出集合的特征。因此最小哈希签名采用了k个不同的哈希函数h_1,h_2,h_3,...,h_k,对于集合S,分别调用这些函数作为最小哈希的排列函数,构建出集合S的最小哈希签名[h_1(S),h_2(S),h_3(S),...,h_k(S)]。显然,这个签名所占的空间要远远小于用朴素的方法保存集合所需的空间。
为什么说这个最小哈希签名是一种保留相似度的哈希呢?其实也很好理解。
事实上,对于两个集合S_1,S_2来说,我们知道在前面的矩阵的所有行中,他们的值同时为1的行有|S_1\cap S_2|个;一个是1一个是0的行有|S_1\cup S_2|-|S_1 \cap S_2|个。那么在对行进行随机排列之后,从上往下数同时为1的行比一个为1一个为0的行先出现的概率就是\frac{|S_1\cap S_2|}{|S_1\cup S_2|}。而这恰巧就是两个集合的Jaccard相似度。也就是说在每一次最小哈希的过程中,两个集合的哈希值相等的概率就是两个集合的Jaccard相似度。这个性质就非常棒了,他保证了如果把最小哈希签名生成的向量当成集合,那么对两个集合进行最小哈希签名之后生成的集合之间的Jaccrad相似度的期望值与原集合的Jaccard相似度相等。
这就是所谓的保留相似度的哈希。