利用simhash来进行文本去重复

原文http://d3s.mff.cuni.cz/~holub/sw/shash/#a1

传统的hash函数能够将一样的文本生成一样的hash函数,但是,通过simhash方法,能够差不多相同的文档得到的hash函数也比较相近。

Charikar's hash

通过Charikar‘s hash,能够将比较相似度的文档得到比较相近的fingerprint。

该算法的流程如下:

    *  Document is split into tokens (words for example) 
or super-tokens (word tuples)
    * Each token is represented by its hash value; a traditional 
hash function is used
    * Weights are associated with tokens
    * A vector V of integers is initialized to 0, length of the vector 
corresponds to the desired hash size in bits
    * In a cycle for all token's hash values (h), vector V is updated:
          o ith element is decreased by token's weight if the ith bit of 
the hash h is 0, otherwise
          o ith element is increased by token's weight if the ith bit of 
the hash h is 1
    * Finally, signs of elements of V corresponds to the bits of the
 final fingerprint

    该hash不是将文档总体计算hash值,而是将文档中的每个token计算哈希值,对文档中每个token的hash值,按照 对hash值进行求和,如果当前token的hash值在该位上是0,则减去1,如果在该位上是1,则加上1.将所有的token按照这种方式累加,求的最终的值作为fingerprint。

python对应的代码如下:

#!/usr/bin/python

# Implementation of Charikar simhashes in Python
# See: http://dsrg.mff.cuni.cz/~holub/sw/shash/#a1

class simhash():
    def __init__(self, tokens='', hashbits=128):
        self.hashbits = hashbits
        self.hash = self.simhash(tokens)

    def __str__(self):
        return str(self.hash)

    def __long__(self):
        return long(self.hash)

    def __float__(self):
        return float(self.hash)

    def simhash(self, tokens):
        # Returns a Charikar simhash with appropriate bitlength
        v = [0]*self.hashbits

        for t in [self._string_hash(x) for x in tokens]:
            bitmask = 0
            print (t)
            for i in range(self.hashbits):
                bitmask = 1 << i
                print(t,bitmask, t & bitmask)
                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 
#整个文档的fingerprint为最终各个位大于等于0的位的和
        return fingerprint

    def _string_hash(self, v):
        # A variable-length version of Python's builtin hash
        if v == "":
            return 0
        else:
            x = ord(v[0])<<7
            m = 1000003
            mask = 2**self.hashbits-1
            for c in v:
                x = ((x*m)^ord(c)) & mask
            x ^= len(v)
            if x == -1: 
                x = -2
            return x

    def hamming_distance(self, other_hash):
        x = (self.hash ^ other_hash.hash) & ((1 << self.hashbits) - 1)
        tot = 0
        while x:
            tot += 1
            x &= x-1
        return tot

    def similarity(self, other_hash):
        a = float(self.hash)
        b = float(other_hash)
        if a>b: return b/a
        return a/b

if __name__ == '__main__':
    s = 'This is a test string for testing'
    hash1 =simhash(s.split())
    #print("0x%x" % hash1)
    #print ("%s/t0x%x" % (s, hash1))

    s = 'This is a test string for testing also!'
    hash2 = simhash(s.split())
    #print ("%s/t[simhash = 0x%x]" % (s, hash2))

    print (hash1.similarity(hash2), "percent similar")
    print (hash1.hamming_distance(hash2), "bits differ out of", hash1.hashbits)

上述代码运行的结果如下:

0.97584098811 percent similar
14 bits differ out of 128

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 以下是用Python实现基于simhash算法计算多行文本相似度,去除相似度高于0.8的文本的代码: ```python import simhash # 定义相似度阈值 threshold = 0.8 # 定义simhash函数 def get_simhash(text): return simhash.Simhash(text).value # 读取文本内容,每行文本存储在一个列表中 with open('text.txt', 'r', encoding='utf-8') as f: text_list = f.readlines() # 生成simhash值列表 simhash_list = [get_simhash(text) for text in text_list] # 计算相似度矩阵 similarities = [] for i in range(len(text_list)): row = [] for j in range(len(text_list)): # 计算simhash值的汉明距离 distance = simhash.hamming_distance(simhash_list[i], simhash_list[j]) # 计算相似度 similarity = 1 - distance / 64 row.append(similarity) similarities.append(row) # 输出相似度高于阈值的文本行 for i in range(len(text_list)): if max(similarities[i]) > threshold: continue print(text_list[i].strip()) ``` 以上代码会首先从文件`text.txt`中读取文本内容,然后将每行文本存储在一个列表中。接着,生成每行文本simhash值,并计算相似度矩阵。最后,输出相似度低于阈值的文本行。 这段代码使用了simhash算法来计算文本相似度,simhash算法可以将文本转换为一个固定长度的二进制数,同时保证相似的文本得到的二进制数相似度较高。通过计算二进制数之间的汉明距离,可以得到文本之间的相似度。 ### 回答2: 以下是使用Python编写的simhash算法代码,用于计算多行文本的相似度并去除相似度高于0.8的文本。 ```python import hashlib def simhash(text): # 分词处理,并去除停用词等 words = text.split() words = [word.strip() for word in words if len(word.strip()) > 0] # 创建一个64位的hash列表并初始化为0 hash_list = [0] * 64 for word in words: # 获取词语的hash值 hash_value = int(hashlib.md5(word.encode('utf-8')).hexdigest(), 16) # 遍历hash值的每一位 for i in range(64): bit_mask = 1 << i if hash_value & bit_mask: hash_list[i] += 1 else: hash_list[i] -= 1 simhash_value = 0 for i in range(64): if hash_list[i] > 0: simhash_value |= 1 << i return simhash_value def similarity(text1, text2): simhash1 = simhash(text1) simhash2 = simhash(text2) # 计算Hamming距离 hamming_distance = bin(simhash1 ^ simhash2).count('1') similarity = 1 - hamming_distance / 64 return similarity def filter_similar_texts(texts): filtered_texts = [] for i in range(len(texts)): for j in range(i+1, len(texts)): similarity_score = similarity(texts[i], texts[j]) if similarity_score <= 0.8: filtered_texts.append(texts[i]) filtered_texts.append(texts[j]) return list(set(filtered_texts)) texts = [ "这是一段文本", "这是另一段文本", "这是相似文本", "这是不相似文本", "这是重复文本", "这是重复文本" ] filtered_texts = filter_similar_texts(texts) print(filtered_texts) ``` 上述代码中,simhash函数用于计算输入文本simhash值,similarity函数用于计算两段文本之间的相似度(使用Hamming距离计算),filter_similar_texts函数用于过滤相似度大于0.8的文本。最后,我们将一个文本列表传递给filter_similar_texts函数,并输出过滤后的结果。 ### 回答3: 使用Python编写一段利用simhash算法计算多行文本相似度,并去除相似度高于0.8的文本的代码可以如下: 首先,需要安装Simhash库,可以使用 pip install simhash 进行安装。然后,导入所需的库和模块: ```python from simhash import Simhash, SimhashIndex import re ``` 定义一个函数,用于计算两个文本的相似度: ```python def cal_similarity(text1, text2): # 去除文本中的特殊字符和空格 text1 = re.sub(r"[^\w\s]", "", text1) text2 = re.sub(r"[^\w\s]", "", text2) text1 = re.sub(r"\s+", " ", text1) text2 = re.sub(r"\s+", " ", text2) # 创建Simhash对象 simhash1 = Simhash(text1) simhash2 = Simhash(text2) # 计算两个文本的汉明距离(相似度) distance = simhash1.distance(simhash2) similarity = 1 - distance / 128 return similarity ``` 接下来,读取多行文本,并计算相似度: ```python # 读取文本文件 with open("text_file.txt", "r") as file: texts = file.readlines() # 构建Simhash索引 simhash_index = SimhashIndex([], k=3) # 用于存储相似度低于0.8的文本 filtered_texts = [] for text in texts: # 去除换行符 text = text.strip() # 判断是否存在相似度大于0.8的文本 if any(cal_similarity(text, existing_text) >= 0.8 for existing_text in filtered_texts): continue # 添加文本到索引 simhash_index.add(text, Simhash(text)) filtered_texts.append(text) ``` 最后,得到相似度低于0.8的文本集合: ```python # 获取相似度低于0.8的文本 filtered_texts = set(filtered_texts) # 输出结果 print(filtered_texts) ``` 以上代码通过Simhash算法计算多行文本的相似度,并去除相似度高于0.8的文本,最后输出相似度低于0.8的文本集合。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值