文章目录
一、如何计算海明距离
from simhash import Simhash
print Simhash('aa').distance(Simhash('bb'))
print Simhash('aa').distance(Simhash('aa'))
二、如何计算simhash相似度
from simhash import Simhash
def simhash_similarity(text_a, text_b):
"""
计算两个文本的simhash相似度
"""
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
三、在实际项目中,如何使用simhash来去重
3.1. 如何对原有集合构建simhash倒排索引
def build_simhash_dict(hash_list):
"""
基于simhash构建倒排索引,将hash_list中的每个元素放入这个倒排索引中
"""
#hash_list = list(df['simhash'])
hash_dict = {}
SPLITS_NUM = 8
for i,h in enumerate(hash_list):
#将哈希数值转化成01序列,并填充到64维
hash_string = str(bin(h.value).replace('0b', '')).zfill(64)
# 将64维的simhash值分成8份意味着,
# 如果在查重时,没有召回结果,说明海明距离肯定>=8。
# 如果有召回结果,不一定说明海明距离<8,具体海明距离是多少,还需要根据召回结果计算;
#
# 同理,如果分成4份,这意味着在查重时,如果没有召回结果,说明海明距离肯定>=4。
# 如果有召回结果,不一定说明海明距离<4,具体海明距离是多少,还需要根据召回结果计算。
for j in range(0, SPLITS_NUM):
#将64维的数据分成8份,作为hash_dict的键
key = hash_string[j*SPLITS_NUM : (j+1)*SPLITS_NUM]
#查找Key是否在字典中,如果不在,则把key添加到hash_dict中,然后把hash_list中的元素添加进去。
if key not in hash_dict.keys():
hash_dict[key] = []
hash_dict[key].append(hash_list[i])
#查找Key是否在字典中,如果在,直接把hash_list中的元素添加进去。
else:
hash_dict[key].append(hash_list[i])
return hash_dict
3.2 当新的item来临,如何判断它在原有集合中是否有重复
def compute_shortest_distance(h, hash_dict):
"""
如果hash_dict存在distance < 8,则从中找出举例海明距离最短的值distance,并返回该值;
否则,返回默认最小值
"""
hash_string = str(bin(h.value).replace('0b', '')).zfill(64)
reverse_list = []
for j in range(0, SPLITS_NUM):
key = hash_string[j*SPLITS_NUM : (j+1)*SPLITS_NUM]
if key in hash_dict:
reverse_list.extend(hash_dict[key])
min_value = 1000
for i in reverse_list:
distance = h.distance(i)
if distance < min_value:
min_value = distance
return min_value
四、simhash的局限性是什么?
在处理小于500字的短文本时,simhash的表现并不是很好
五、参考文献
- 使用SimHash进行海量文本去重流程¶
- simhash文本去重流程
- 面试|海量文本去重~simhash
(这篇文章讲得比较好,在实际落地时怎么操作比较清楚) - Simhash算法+倒排索引搜索
(源代码不错) - simhash算法