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并在原基础上进行了说明和改善。