simhash的py实现

流过昼夜 提交于 2019-11-26 05:26:51

前言:
这篇博客主要从python(3)代码的角度来讲本人是如何实现simhash的,不足之处还望大家不吝赐教。simhash的算法原理大家可以参考简单易懂讲解simhash算法。值得一提的是文中提到simhash对长文本更加有效,个人从算法原理角度思考过后感觉也是如此。

初始化

首先我们要明确我们需要的是什么,给定了一个大语料,我们希望得到的是每个词的编码以及对应的权重,那么我们可以将目标拆分为以下几个:
1.对文本进行分词,并根据需要进行停词处理。
2.对每个词进行hash编码(一般用32位的就够了)。
3.对每个词赋予权重,这里正好就能用idf的值作为其权重值,idf具体介绍可见tf-idf进行关键词提取
说了这么多,还是用代码来看看具体是怎么做到的吧~

分词
一上来就是最让人头疼的问题,如何进行分词,分词的相关理论也是种类繁多,能够成一个专题,这里大家有兴趣的可以自行去查阅相关资料,我在这里使用的是jieba分词,jieba是一个功能强大的分词工具,大家可以参考博客好玩的分词–jieba模块的的基本用法,分词完毕后我将其保存为新的txt(test_ws.txt),之后我们载入的文本文件便是分词过后的文件了。

hash编码和idf值计算

# -*- coding:utf-8 -*-
import numpy as np
import codecs
import math

BITS = 31
path = './data/FAQ_toB_par'


class simHash(object):
# 初始化,遍历文档(已分词),得到词汇表,并进行32位(能表示2^32种情况,完全足够)\
#hash编码和对应的idf值,将idf值作为其权重进行运算,分别存入两个字典(dict)
    def __init__(self, path):
        f = codecs.open(path, 'r', encoding='utf-8')
        dictHash = dict()
        dictWeight = dict()
        i = 0#hash编码
        lines = 0#记录文本数量,以计算idf值
        #遍历文本,进行hash编码和统计df词频(在多少篇文章出现过,而不是总词频,\
        #比如某个词在一个文本中出现三次也只算一次)
        for line in f:
            lines += 1
            temp = set(str(line).strip().split())#避免重复统计词频
            for item in temp:
                if item not in dictWeight:
                    dictWeight[item] = 1
                    dictHash[item] = i
                    i += 1
                else:
                    dictWeight[item] += 1
        f.close()
        del i
        #hash编码转为array形式的二进制,方便计算
        for item in dictHash:
            L = list(bin(dictHash[item]))[2:]
            intL = [int(x) for x in L]
            for i in range(len(intL)):
                if intL[i] == 0:
                    intL[i] = -1
            intL = (BITS - len(intL))*[-1]+intL
            dictHash[item] = np.array(intL)
        #根据词频计算idf值
        for item in dictWeight:
            dictWeight[item] = math.log(lines/dictWeight[item])

        self.dictHash = dictHash
        self.dictWeight = dictWeight

至此便完成了由大语料得到词语的hash编码和idf值,我们通过词典可以查看某个词:

print(self.dictHash['什么'])
print(self.dictWeight['什么'])

然后我们还需要根据两个词典对句子进行hash编码(注意输入的句子是分词过后的),
同时还定义了一个计算两个句子Hamming距离的函数,(Hamming距离越小说明句子相似度越高)。

    #根据词的hash对句子进行hash编码
    def senHash(self, sen):
        senHashCode = np.zeros(BITS)
        temp = sen.strip().split()
        for item in temp:
            senHashCode += self.dictHash[item]*self.dictWeight[item]
        for i in range(BITS):
            if senHashCode[i] > 0:
                senHashCode[i] = 1
            else:
                senHashCode[i] = 0
        return senHashCode

    #获取两个句子的Hamming distance,dis越小说明相似度越高
    def sen2senDis(self, sen1, sen2):
        temp1 = self.senHash(sen1)
        temp2 = self.senHash(sen2)
        Hamming = 0
        for i in range(BITS):
            if temp1[i] != temp2[i]:
                Hamming += 1
        return Hamming

到这里基本上就结束了,这里我是定义的一个类,大家可以用这个类来进行相似文本去重等操作。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!