文本相似度计算——Simhash算法(python实现)

互联网网页存在着大量重复内容,必须有一套高效的去重算法,否则爬虫将做非常多的无用功,工作时效性无法得到保证,更重要的是用户体验也不好。业界关于文本指纹去重的算法众多,如 k-shingle 算法、google 提出的simhash 算法、Minhash 算法、百度top k 最长句子签名算法等等,本文主要介绍simhash算法以及python应用.

simhash 与传统hash 的区别

传统的Hash算法只负责将原始内容尽量均匀随机地映射为一个签名值,原理上仅相当于伪随机数产生算法。传统的hash算法产生的两个签名,如果原始内容在一定概率下是相等的;如果不相等,除了说明原始内容不相等外,不提供任何信息,因为即使原始内容只相差一个字节,所产生的签名也很可能差别很大。所以传统的Hash是无法在签名的维度上来衡量原内容的相似度,而SimHash本身属于一种局部敏感哈希算法,它产生的hash签名在一定程度上可以表征原内容的相似度。

我们主要解决的是文本相似度计算,我们降维生成hash签名也是用于这个目的。看到这里估计大家就明白了,我们使用的simhash就算把文章中的字符串变成 01 串也还是可以用于计算相似度的,而传统的hash却不行。我们可以来做个测试,两个相差只有两个字符的文本串,“你妈妈喊你回家吃饭哦” 和 “你妈妈叫你回家吃饭啦”。

通过simhash计算结果为:

1000010010101101111111100000101011010001001111100001001011001011

1000010010101101011111100000101011010001001111100001101010001011

通过传统hash计算为:

0001000001100110100111011011110

1010010001111111110010110011101

大家可以看得出来,相似的文本simhash只有部分 01 串变化了,而普通的hash却不能做到,这个就是局部敏感哈希的魅力。

simhash简介

simhash 是 google 用来处理海量文本去重的算法。 simhash 可以将一个文档转换成一个 64 位的字节,暂且称之为特征字。判断文档是否重复,只需要判断文档特征字之间的汉明距离。根据经验,一般当两个文档特征字之间的汉明距离小于 3, 就可以判定两个文档相似。

主要步骤:在新拿到文本之后需要先进行分词,这是因为需要挑出TopN个词来表征这篇文本,并且分词的权重不一样,可以使用相应数据集的tf-idf值作为分词的权重,这样就分成了带权重的分词结果。

之后对所有分词进行哈希运算获取二值化的hash结果,再将权重与哈希值相乘,获得带权重的哈希值,最后进行累加以及二值化处理.

  • 分词

使用分词手段将文本分割成关键词的特征向量,分词方法有很多一般都是实词,也就是把停用词等都去掉之后的部分,使用者可以根据自己的需求选择.最后形成去掉噪音词的单词序列并为每个词加上权重. 例如:

傲游AI 专注 于 游戏 领域 多年 AI技术 积淀 一站式 提供 文本 图片 音视频 内容 审核 游戏AI 以及 数据 平台 服务

目前的词只是进行了分割,但是词与词含有的信息量是不一样的,比如傲游AI 游戏 审核 这三个词就比 专注 服务 以及更能表达文本的主旨含义,这也就是所谓信息熵的概念。

为此我们还需要设定特征词的权重,简单一点的可以使用绝对词频来表示,也就是某个关键词出现的次数,但是事实上出现次数少的所含有的信息量可能更多.总之需要选择一种加权方法,否则效果会打折扣。

  • 哈希和权重化

前面我们使用分词方法和权重分配将文本就分割成若干个带权重的实词,比如权重使用1-5的数字表示,1最低5最高

傲游AI(5) 专注(2) 于(1) 游戏(3) 领域(1) ......

对各个特征词进行二值化哈希值计算, 再将所有的哈希值累加,最后将累加结果二值化.

  • 汉明距离

在信息论中,两个等长字符串之间的汉明距离(英语:Hamming distance)是两个字符串对应位置的不同字符的个数。换句话说,它就是将一个字符串变换成另外一个字符串所需要替换的字符个数。 汉明重量是字符串相对于同样长度的零字符串的汉明距离,也就是说,它是字符串中非零的元素个数:对于二进制字符串来说,就是1的个数,所以11101的汉明重量是4。 对于二进制字符串a与b来说,它等于a 异或b后所得二进制字符串中“1”的个数。 汉明距离是以理查德·卫斯里·汉明的名字命名的,汉明在误差检测与校正码的基础性论文中首次引入这个概念。 在通信中累计定长二进制字中发生翻转的错误数据位,所以它也被称为信号距离。汉明重量分析在包括信息论、编码理论、密码学等领域都有应用。但是,如果要比较两个不同长度的字符串,不仅要进行替换,而且要进行插入与删除的运算,在这种场合下,通常使用更加复杂的编辑距离等算法。

谷歌经过工程验证认为当两个64bit的二值化simhash值的汉明距离超过3则认为不相似,所以判重问题就转换为求两个哈希值的汉明距离问题。

Simhash局限

simhash也有其局限性:

  1. SimHash处理短文本内容准确率往往不能得到保证。由于simhash是局部敏感的hash,其可能不适合做这种短标题的重复度判断,会存在一定的误差,当文本内容较长时,使用SimHash准确率很高(即文本越长判断的准确率越高)。在处理小于500字的短文本时,simhash的表现并不是很好,所以在使用simhash前一定要注意这个细节。

2. 文本内容中每个term对应的权重如何确定要根据实际的项目需求,一般是可以使用IDF权重来进行计算

Python实现

1. 调包实现

from simhash import Simhash


def simhash_demo(text_a, text_b):
   
"""
   
求两文本的相似度
   
:param text_a:
    :param text_b:
    :return:
    """
   
a_simhash = Simhash(text_a)
    b_simhash = Simhash(text_b)
    max_hashbit =
max(len(bin(a_simhash.value)), len(bin(b_simhash.value)))
   
# 汉明距离
   
distince = a_simhash.distance(b_simhash)
   
print(distince)
    similar =
1 - distince / max_hashbit
   
return similar


if __name__ == '__main__':
    text1 =
"傲游AI专注于游戏领域,多年的AI技术积淀,一站式提供文本、图片、音/视频内容审核,游戏AI以及数据平台服务"
    
text2 = "傲游AI专注于游戏领域,多年的AI技术积淀,二站式提供文本、图片、音 视频内容审核,游戏AI以及数据平台服务"
    
text3 = '"傲游AI专注于游戏领域,多年的AI技术积淀,三站式提供文本、图片、音视频内容审核,游戏AI以及数据平台服务"'
   
similar = simhash_demo(text1, text2)
    similar2 = simhash_demo(text1
, text3)
    similar3 = simhash_demo(text2
, text3)
   
print(similar)
   
print(similar2)
   
print(similar3)

2. 自主实现

#!/usr/bin/python
# coding=utf-8
class simhash:
    # 构造函数
    def __init__(self, tokens='', hashbits=128):                      
        self.hashbits = hashbits
        self.hash = self.simhash(tokens)

    # toString函数
    def __str__(self):
        return str(self.hash)

    # 生成simhash值
    def simhash(self, tokens):
        v = [0] * self.hashbits
        for t in [self._string_hash(x) for x in tokens]:  # t为token的普通hash值
            for i in range(self.hashbits):
                bitmask = 1 << i
                if t & bitmask:
                    v[i] += 1  # 查看当前bit位是否为1,是的话将该位+1
                else:
                    v[i] -= 1  # 否则的话,该位-1
        fingerprint = 0
        for i in range(self.hashbits):
            if v[i] >= 0:
                fingerprint += 1 << i
        return fingerprint  # 整个文档的fingerprint为最终各个位>=0的和

    # 求海明距离
    def hamming_distance(self, other):
        x = (self.hash ^ other.hash) & ((1 << self.hashbits) - 1)
        tot = 0
        while x :
            tot += 1
            x &= x - 1
        return tot

    # 求相似度
    def similarity (self, other):
        a = float(self.hash)
        b = float(other.hash)
        if a > b:
            return b / a
        else:
            return a / b

    # 针对source生成hash值               (一个可变长度版本的Python的内置散列)
    def _string_hash(self, source):
        if source == "":
            return 0
        else:
            x = ord(source[0]) << 7
            m = 1000003
            mask = 2 ** self.hashbits - 1
            for c in source:
                x = ((x * m) ^ ord(c)) & mask
                x ^= len(source)
                if x == -1:
                    x = -2
                return x


if __name__ == '__main__':
        s1 = "傲游AI专注于游戏领域,多年的AI技术积淀,一站式提供文本、图片、音/视频内容审核,游戏AI以及数据平台服务"
        hash1 = simhash(s1.split())
        s2 = "傲游AI专注于游戏领域,多年的AI技术积淀,二站式提供文本、图片、音 视频内容审核,游戏AI以及数据平台服务"
        hash2 = simhash(s2.split())
        s3 = '"傲游AI专注于游戏领域,多年的AI技术积淀,三站式提供文本、图片、音视频内容审核,游戏AI以及数据平台服务"'
        hash3 = simhash(s3.split())
        print(hash1.hamming_distance(hash2) , "               " , hash1.similarity(hash2))
        print(hash1.hamming_distance(hash3) , "               " , hash1.similarity(hash3))
        print(hash2.hamming_distance(hash3) , "               " , hash2.similarity(hash3))
  • 5
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
### 回答1: 对于微博文本相似度计算simhash算法可能更适合。 余弦相似度算法是一种常见的文本相似度计算方法,它可以计算两个文本向量之间的夹角余弦值,用于衡量它们的相似度。但是,当面对大量文本时,计算文本向量的时间复杂度很高,这可能会影响性能。 相比之下,simhash算法可以快速计算文本的哈希值,而且能够在哈希值之间计算汉明距离,从而衡量文本相似度simhash算法的优点是它能够快速处理大量文本,并且可以识别并过滤掉文本中的噪声和重复内容,因此可能更适合微博文本相似度计算。 ### 回答2: 对于微博文本相似度计算simhash算法更适合。 首先,simhash算法是一种局部敏感哈希算法,可以快速计算文本之间的相似度。它通过将文本表示为一条固定长度的哈希值,在计算相似度时可以直接比较哈希值的相似程度,而不需要对文本进行逐字逐句的比较。这样可以大大提高计算效率,尤其对于微博这样大量文本的场景,计算速度是一个重要考量因素。 其次,微博文本往往短小,包含的信息量有限,使用余弦相似度算法可能不够准确。余弦相似度算法是基于向量的相似性度量,将文本表示为向量后,通过计算向量之间的夹角余弦值来得到相似度。然而,微博文本的长度较短,往往无法包含足够多的特征信息,导致向量表示不准确,从而影响相似度计算的准确性。 最后,simhash算法在处理文本复制粘贴、文本重复等问题时有较好的效果。微博上经常出现转发、评论等类似内容的现象,使用simhash算法可以有效地区分出相似但不完全一致的文本。这使得simhash算法更适合微博文本相似度计算。 综上所述,simhash算法相较于余弦相似度算法更适合微博文本相似度计算,因为它具有更高的计算效率和更好的应对微博文本特点的能力。 ### 回答3: 对于微博文本相似度计算simhash算法更适合。 首先,simhash算法是一种利用哈希函数计算文本指纹的方法。在计算微博文本相似度时,可以将微博文本经过处理得到对应的simhash值,并比较两个simhash值的汉明距离,汉明距离越小表示两个文本相似度越高。相比之下,余弦相似度算法需要对文本进行向量化表示,计算文本向量之间的余弦相似度simhash算法相对于余弦相似度算法来说,计算速度更快,计算文本指纹的过程比较简单,而且对文本的维度和长度不敏感,适用于处理大规模的文本数据。 其次,微博文本的特点是短文本,通常只有很少的几十个字。对于短文本相似度计算simhash算法更适合。因为余弦相似度算法更适合长文本相似度计算,对于短文本来说,由于文本长度较短,导致文本中的关键词权重较小,很容易受到噪音的干扰。而simhash算法不会受到文本长度的限制,可以更好地处理短文本相似度计算。 综上所述,simhash算法更适合微博文本相似度计算。它具有计算速度快、对文本长度不敏感以及适用于处理大规模文本数据的优势,更适合用于短文本的高效相似度计算
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Trisyp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值