SimHash

算法原理
 前面我们讲到,一段文字所包含的信息,就是它的信息熵。如果对这段信息进行无损压缩编码,理论上编码后的最短长度就是它的信息熵大小。如果仅仅是用来做区分,则远不需要那么长的编码,任何一段信息(文字、语音、视频、图片等),都可以被映射(Hash编码)为一个不太长的随机数,作为区别这段信息和其他信息的指纹,只要Hash算法设计得好,任何两段信息的指纹都很难重复。
SimHash是一种用来做文本查重的常用方法,是Google在2002年发明的一项技术,其特点是,如果两个文本的SimHash值差别越小,这两个网页的相似性就越高。下面我们来看一下它是怎么做到的?



1.  将一个f维的向量V初始化为0,f位的二进制数S也初始化为0;

2.  对每一个特征(分词),用传统的hash算法对该特征产生一个f位的二进制签名b;

3.  对i=1到f,如果b的第i位为1,则该位的值即为该特征的权重值(TF-IDF),如果为0,则为负的权重值;

4.  将所有特征的权重向量按位相加赋值给V;

5.  如果V的第i个元素值大于0,则S的第i位为1,否则为0;

6. 输出S作为最终签名,即SimHash值。

对两篇文档的SimHash值,计算它们的海明距离(Simhash值之间不同位的个数)。可以有如下高效的实现:



int hamdistance(uint64_t sim1, uint64_t sim2){
   uint64_t
xor_val = sim1 ^ sim2;

   int distance =
0;
   while(xor_val
> 0){
       xor_val =
xor_val & (xor_val - 1);
       distance++;
   }
   return
distance;
}

int main(int argc, char *argv[]){
   uint64_t sim1 =
851459198;
   uint64_t sim2 =
847263864;
   int dis =
hamdistance(sim1, sim2);
  
printf("hamdistance of %lu and %lu is %d", sim1, sim2, dis);
}


加密算法(MD5、SHA-1等)也是将不定长的信息变成定长的128位或160位二进制随机数,但是加密算法的一个明显特征是,两段信息哪怕只有微小的不同,最终结果也会截然不同。 SimHash的最大特点就是它的局部敏感性。
1.  
因为SimHash算法最终是将权重值相加,而加法满足交换律,所以对词的顺序不敏感;
2.  
如果两篇文章只有少数权重小的词不相同,几乎可以肯定它的SimHash值也会相同。 SimHash去重非常高效:一是指纹的计算可以离线进行,而是海明距离的计算也非常高效(直接异或,还可以使用Hash分桶原理,假如我们认为海明距离在3以内的具有很高的相似性,我们可以将simhash值分成4段,那么至少有一段完全相等的情况下才能满足海明距离在3以内)。
通过大量测试,simhash用于比较大文本,比如500字以上效果都还蛮好,距离小于3的基本都是相似,误判率也比较低。但是如果我们处理的是微博信息,最多也就140个字,使用simhash的效果并不那么理想,我们测试短文本很多看起来相似的距离确实为10,如果使用距离为3,短文本大量重复信息不会被过滤,如果使用距离为10,长文本的错误率也非常高。


社群

QQ交流群



微信交流群




微信公众号







了解更富哦干货文章,可以关注小程序八斗问答




 

### SimHash算法原理 SimHash是一种基于局部敏感哈希(Locality-Sensitive Hashing, LSH)技术的近似相似度计算方法,主要用于规模数据集中的文本去重和相似性检测。其核心思想是将任意长度的文档映射到固定长度的指纹(通常是64位二进制数),并通过比较这些指纹之间的汉明距离来衡量原始文档的相似程度[^1]。 #### 文档向量化 为了生成SimHash值,首先需要将输入文档表示为一组加权特征向量。具体过程如下: 1. **分词**:将文档分割成单独的词语或短语。 2. **权重分配**:根据每个词的重要性为其赋予权重,通常可以使用TF-IDF或其他统计指标。 3. **特征提取**:对于每一个单词,将其通过某种散列函数转化为一个高维稀疏向量(例如128维)。这个向量的方向由该词决定,而小则取决于它的权重。 #### 计算SimHash值 有了上述准备之后,就可以按照下面的方式得到最终的SimHash签名: - 对于每一维度i (0 ≤ i < n),累加所有词对应的第i个位置上的数值乘以其各自的权重; - 如果总和于零,则令结果向量在此处取1;否则设为0。 这样就得到了整个文档的一个紧凑表达形式——即所谓的“特征字”。两个不同文件如果非常接近的话,在理想情况下它们应该具有相同的或者几乎一致的SimHash码[^1]。 ### Python实现示例 以下是利用Python语言简单模拟了一个版本的SimHash创建流程以及如何评估两份资料间的差异程度的例子[^2]: ```python import math from collections import defaultdict class Simhash(object): def __init__(self, tokens='', hashbits=64): self.hashbits = hashbits v = [0]*self.hashbits for t in [self._string_hash(x) for x in tokens]: for i in range(self.hashbits): bitmask = 1 << i if t & bitmask : v[i] +=1 else: v[i] -=1 fingerprint = 0 for i in range(self.hashbits): if v[i] >=0: fingerprint |= (1<<i) self.value = fingerprint @staticmethod def _string_hash(token): """ A basic hashing function """ hval = int(math.fmod(abs(hash(token)), pow(2,32))) return hval def hamming_distance(self, other): x = (self.value ^ other.value) & ((1 << self.hashbits)-1) tot = 0; while(x): tot+=1 x &= x -1 return tot def similarity(self,other): a = float(self.value) b = float(other.value) if(a>b):return(b/a) return(a/b) if __name__ == '__main__': s = 'This is a test string for testing' hash1 = Simhash(s.split()) s = 'This is a string testing 11' hash2 = Simhash(s.split()) print(f"{hash1.hamming_distance(hash2)} {hash1.similarity(hash2)}") ``` 此脚本定义了一个名为`Simhash`类的对象结构体,它接受字符串列表作为参数并返回相应的simhash值。此外还提供了两种测量手段用于判定两者之间关系紧密与否的方法分别是hamming distance 和 similarity ratio.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值