python实现Simhash处理大规模文本相似度

Simhash简介:

Simhash–顾名思义,通过hash值比较相似度,通过两个字符串得出来的hash值,进行异或操作,然后得到相差的个数,数字越大则差异越大。

Simhash流程:

计算文本hash值的步骤:

1、用分词工具(jieba、NLPIR、哈工大分词器等)对字符串进行分词、去除停用词,英文除外;

seg = jieba.cut(str)

2、分词后筛选关键词,计算关键词的权重;

keyword = jieba.analyse.extract_tags('|'.join(seg), topK=20, withWeight=True, allowPOS=())

3、把关键词的特征提取出来;

for i in feature:
    if i == '1':
        temp.append(weight)
    else:
        temp.append(-weight)

4、将该文本的整体关键词特征进行融合,归一化;

list1 = np.sum(np.array(keyList), axis=0)

计算sim值:

1、用hash得出来的hash值两两进行比较;

t1 = '0b' + self.sim1
t2 = '0b' + self.sim2
n = int(t1, 2) ^ int(t2, 2)

2、通过异或比较,得处simhash值。

i = 0
while n:
    n &= (n - 1)
    i += 1
return i

处理大规模文本

如何使用simhash处理大规模文本数据,原理很简单,以上步骤我们可以计算两个字符串之间的相似度,引申这种思想,对文本中的数据进行处理。
其中使用到了排序的思路,我们对文本中的数据进行两两比较,那么本身不用比,本身和后面字符串比较过的也不必比较,那就是一个对角矩阵,即i与i+1个元素对比。

for i in range(len(list)-1):
	for y in range(i+1,len(list))

以上为在处理大规模文本相似度时所用到的simhash思想。

# -*- coding: utf-8 -*-
# !/usr/bin/env python

'''
function:python实现大规模simhash对比
time:2020-06-19 14:32:10
author:为援不可图
'''
import jieba
import jieba.analyse
import numpy as np


# 获取字符串对应的hash值
class SimhashStr():
    def __init__(self, str):
        self.str = str

    # 得到输入字符串的hash值
    def get_hash(self):
        # 结巴分词
        seg = jieba.cut(self.str)
        # 取前20个关键词
        keyword = jieba.analyse.extract_tags('|'.join(seg), topK=20, withWeight=True, allowPOS=())
        keyList = []
        # 获取每个词的权重
        for feature, weight in keyword:
            # 每个关键词的权重*总单词数
            weight = int(weight * 20)
            # 获取每个关键词的特征
            feature = self.string_hash(feature)
            temp = []
            # 获取每个关键词的权重
            for i in feature:
                if i == '1':
                    temp.append(weight)
                else:
                    temp.append(-weight)
                keyList.append(temp)
        # 将每个关键词的权重变成一维矩阵
        list1 = np.sum(np.array(keyList), axis=0)
        # 获取simhash值
        simhash = ''
        for i in list1:
            # 对特征标准化表示
            if i > 0:
                simhash = simhash + '1'
            else:
                simhash = simhash + '0'
        return simhash

    def string_hash(self, feature):
        if feature == "":
            return 0
        else:
            # 将字符转为二进制,并向左移动7位
            x = ord(feature[0]) << 7
            m = 1000003
            mask = 2 ** 128 - 1
            # 拼接每个关键词中字符的特征
            for c in feature:
                x = ((x * m) ^ ord(c)) & mask
            x ^= len(feature)
            if x == -1:
                x = -2
            # 获取关键词的64位表示
            x = bin(x).replace('0b', '').zfill(64)[-64:]
            return str(x)


# 比较两个字符串的相似度
class simliary():
    def __init__(self, sim1, sim2):
        self.sim1 = sim1
        self.sim2 = sim2

    # 比较两个simhash值的相似度
    def com_sim(self):
        # 转为二进制结构
        t1 = '0b' + self.sim1
        t2 = '0b' + self.sim2
        n = int(t1, 2) ^ int(t2, 2)
        # 相当于对每一位进行异或操作
        i = 0
        while n:
            n &= (n - 1)
            i += 1
        return i

#比较大量文本中数据之间的相似度
class com_file_data_sim():
    def __init__(self, path):
        self.path = path

    # 获取文件中的数据列表
    def get_file_data(self):
        content_txt = []
        with open(self.path, 'r', encoding='utf-8') as f:
            lines = f.readlines()
            for line in lines:
                content = line.strip()
                content_txt.append(content)
        return content_txt

    # 对列表中的数据进行hash值比对
    def com_data_sim(self):
        content_data = self.get_file_data()
        for i in range(len(content_data) - 1):
            for y in range(i + 1, len(content_data)):
                str1 = content_data[i]
                str2 = content_data[y]
                sim1 = SimhashStr(str1).get_hash()
                sim2 = SimhashStr(str2).get_hash()
                sim = simliary(sim1, sim2).com_sim()
                print(str1 + ' ' + str2 + ' ' + '\n'+'simhash值为:'+str(sim))


if __name__ == '__main__':
    com_file_data_sim('com.txt').com_data_sim()

本程序参考自https://blog.csdn.net/madujin/article/details/53152619并在原基础上进行了说明和改善。

猜你喜欢

转载自blog.csdn.net/qq_32113189/article/details/106856527