前言: 网上有很多对simHash的算法的讲解,但是大多数的通病是要么讲的太冗余,比如分词讲太多,代码写太多,要么关键点没有讲到,例如针对海量数据,如何利用simHash算法。网上都知道使用抽屉原理,但是要知道这个抽屉原理充分条件而非必要条件。本文主要简单明了讲解一下原理
问题的起源:
设计比较两篇文章相似度的算法。
其实比较两篇文章相似度的算法有很多,为什么使用这个,网上也一大堆就不多说了。
simHash算法分为5个步骤:
分词:就是分词,但是要对词语加上权重,如给定一段语句:“CSDN博客结构之法算法之道的作者July”,分词后为:“CSDN 博客 结构 之 法 算法 之 道 的 作者 July”,然后为每个特征向量赋予权值:CSDN(4)博客(5)结构(3)之(1)法(2)算法(3)之(1)道(2)的(1)作者(5)July(5),权重代表了
这个特征在整条语句中的重要程度。hash: 通过hash函数计算各个特征的hash值,hash值为二进制数组成的n位签名。
Hash(CSDN)=100101,Hash(博客)=101011。加权: W = Hash * weight。W(CSDN)=100101 * 4=4-4-44-44,W(博客)=101011*5=5-55-555。(注意我们把0看成-1)
合并: 将上述各个特征的加权结果累加,变成一个序列串。如:“4+5,-4+-5,-4+5,4+-5,-4+5,4+5”,得到“9,-9,1,-1,1”。
降维 对于n位签名的累加结果,如果大于0则置1,否则置0,从而得到该语句的simhash值,最后我们便可以根据不同语句simhash的海明距离来判断它们的相似度。例如
把上面计算出来的“9,-9,1,-1,1,9”降维,得到 “101011”,从而形成它们的simhash签
名。
如何判断相似度
每篇文档得到simHash签名值后,接着计算两个签名的海明距离即可。根据经验值,对
64位的SimHash值,海明距离在3以内的可认为相似度比较高
海明距离算法:
两个二进制数异或值中1的个数
海量数据如何处理呢
如何将数据扩展到海量数据呢,譬如如何在海量的样本库中查询与其海明距离在3以内的记录呢?
方案一: 第一种是方案是查找待查询文本的64位simhash code的所有3位以内变化的组合,需要去某个数据仓库查询43690次(假如数据参考存有)
方案二: 小学奥数来了,抽屉原理!!
具体什么是抽屉原理就不说了,下面这句话应该很好理解:
把64位的二进制simHash签名均分成4块,每块16位。根据抽屉原理,如果两个签名的海明距离在3以内,它们必有一块完全相同。
然后把分成的4块中的每一个块分别作为前16位来进行查找,建立倒排索引
之前看到这个很疑惑,感觉这是一个充分条件啊,分成4份,如果海明距离在3以内,他们肯定是有一块完全相同没错。 但是有一块完全相同,也不能证明海明距离是3以内呀, 后来仔细想了一想, 其实是这样的:
先分成4分,对每一份都去查是否有完全相同的,看看有没有相同的,如果有相同的,再把这两篇文章的simHash码进行一次异或,看看这个的海明距离是否在3以内.
这样好处如下:
- 可以建立倒排索引,或者类似于key-value的库,每一篇文章只需要存4组key-value即可了
- 精确的匹配某个二进制,即使是海量数据,精确匹配一般也是是比较快的,大大的减少了查询的时间,之前的4万多次,现在只需要查一次, 然后再将查出来的两两对比一下即可。
补充
分词的权值计算
- TF-IDF(term frequency–inverse document frequency)是一种用于资讯检索与资讯探勘的常用加权技术。TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。
- 字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频成反比下降:Weight =
TF*IDF 。 - 如果某个分词在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,
适合用来分类 - 事实上,该技术在自然语言处理用途广泛,可以配合其它方法一起使用,如余弦距离(反比于相似度)、LDA主题模型等,用于聚类、标签传递算法等后续分析中。
参考: http://grunt1223.iteye.com/blog/964564
参考: http://grunt1223.iteye.com/blog/964564