我的编程空间,编程开发者的网络收藏夹
学习永远不晚

浅谈simhash及其python实现

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

浅谈simhash及其python实现

作者原创,转载请注明出处。

一直想写个总结来回顾simhash,一直没抽出时间,现在还是好好写写总结一下。作者随笔,废话有点多,不喜勿喷,欢迎指教。

谷歌每天从网上抓取海量的信息,怎么样区分重复的呢,据说就采用了simhash算法,当然肯定也不仅仅就只采用它,不过至少可以说明其性能。

预备知识:

我们知道,在文本去重的时候,有很多方式,在文本与文本之间对比,如果是整篇对比,费时费力,有人就想到用什么东西代表每篇文章,如摘要,当然,对计算机来说,摘要和整篇的区别只是缩小了篇幅,所以又有人想到了采用关键字来对比。这样确实可以大大缩减我们对比的复杂性。那我们怎么得到一篇文章的关键字呢?一般采用词频(TF),但是只用词频,如中文出现类似“的”、“我们”之类的词语很多,应该怎么去掉这些词语呢,手动去掉实在是麻烦,于是可以结合逆向词频(IDF),这就是著名的TD-IDF,一种提取一个文章的关键词的算法。词频我们很好理解,一个词语在整篇文章中出现的次数与词语总个数之比。IDF又怎么算呢,假如一个词语,在我们所有文章中出现的频率都非常高(例如“的”在我们多个文本中出现的次数很多),我们就认为,这个词语不具有代表性,就可以降低其作用,也就是赋予其较小的权值。

那这个权重,我们怎么计算呢,(这里敲公式比较麻烦,直接找来图片),如下图,分子代表文章总数,分母表示该词语在这些文章(|D|)出现的篇数。一般我们还会采取分母加一的方法,防止分母为0的情况出现,在这个比值之后取对数,就是IDF了。

好了,在得到idf之后,最终用tf*idf得到一个词语的权重。这里我知道了TD-IDF可以计算一篇文章的关键词。在我们取得一篇的文章的关键词,之后,我们可以采取每篇文章对比其关键词的方法来去重。

这里又有一个权衡,假如我们取的关键词过少,就不能很好代表一篇文章,假如我们取很多,又会降低效率。有没有一种方法,既可以很少的对比,又能有好的代表性呢。答案肯定是有的,于是simhash产生了。

(汗,终于讲到正题来了)

原理:

simhash是一种局部敏感hash。我们都知道什么是hash。那什么叫局部敏感呢,假定A、B具有一定的相似性,在hash之后,仍然能保持这种相似性,就称之为局部敏感hash。

在上文中,我们得到一个文档的关键词,取得一篇文章关键词集合,又会降低对比效率,我们可以通过hash的方法,把上述得到的关键词集合hash成一串二进制,这样我们直接对比二进制数,看其相似性就可以得到两篇文档的相似性,在查看相似性的时候我们采用海明距离,即在对比二进制的时候,我们看其有多少位不同,就称海明距离为多少。在这里,我是将文章simhash得到一串64位的二进制,一般取海明距离为3作为阈值,即在64位二进制中,只有三位不同,我们就认为两个文档是相似的。当然了,这里可以根据自己的需求来设置阈值。

就这样,我们把一篇文档用一个二进制代表了,也就是把一个文档hash之后得到一串二进制数的算法,称这个hash为simhash。

具体simhash步骤如下:

(1)将文档分词,取一个文章的TF-IDF权重最高的前20个词(feature)和权重(weight)。即一篇文档得到一个长度为20的(feature:weight)的集合。

(2)对其中的词(feature),进行普通的哈希之后得到一个64为的二进制,得到长度为20的(hash : weight)的集合。

(3)根据(2)中得到一串二进制数(hash)中相应位置是1是0,对相应位置取正值weight和负值weight。例如一个词进过(2)得到(010111:5)进过步骤(3)之后可以得到列表[-5,5,-5,5,5,5],即对一个文档,我们可以得到20个长度为64的列表[weight,-weight...weight]。

(4)对(3)中20个列表进行列向累加得到一个列表。如[-5,5,-5,5,5,5]、[-3,-3,-3,3,-3,3]、[1,-1,-1,1,1,1]进行列向累加得到[-7,1,-9,9,3,9],这样,我们对一个文档得到,一个长度为64的列表。

(5)对(4)中得到的列表中每个值进行判断,当为负值的时候去0,正值取1。例如,[-7,1,-9,9,3,9]得到010111,这样,我们就得到一个文档的simhash值了。

(6)计算相似性。连个simhash取异或,看其中1的个数是否超过3。超过3则判定为不相似,小于等于3则判定为相似。

呼呼呼,终于写完大致的步骤,可参考下图理解步骤。

python实现:

在下面python实现中,用的结巴分词,得到tf-idf的权值。

# -*- coding: utf-8 -*-
import jieba
import jieba.analyse
import numpy as np
import json

class simhash:
    def __init__(self,content):
        self.simhash=self.simhash(content)

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

    def simhash(self,content):
        seg = jieba.cut(content)
        jieba.analyse.set_stop_words('stopword.txt')
        keyWord = jieba.analyse.extract_tags(
            '|'.join(seg), topK=20, withWeight=True, allowPOS=())#在这里对jieba的tfidf.py进行了修改
        #将tags = sorted(freq.items(), key=itemgetter(1), reverse=True)修改成tags = sorted(freq.items(), key=itemgetter(1,0), reverse=True)
        #即先按照权重排序,再按照词排序
        keyList = []
        # print(keyWord)
        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)
            # print(temp)
            keyList.append(temp)
        list1 = np.sum(np.array(keyList), axis=0)
        print(list1)
        if(keyList==[]): #编码读不出来
            return '00'   
        simhash = ''
        for i in list1:
            if(i > 0):
                simhash = simhash + '1'
            else:
                simhash = simhash + '0'
        return simhash


    def string_hash(self,source):
        if source == "":
            return 0
        else:
            x = ord(source[0]) << 7
            m = 1000003
            mask = 2 ** 128 - 1
            for c in source:
                x = ((x * m) ^ ord(c)) & mask
            x ^= len(source)
            if x == -1:
                x = -2
            x = bin(x).replace('0b', '').zfill(64)[-64:]
            print(source,x)

            return str(x)

        '''
        以下是使用系统自带hash生成,虽然每次相同的会生成的一样,
        不过,对于不同的汉子产生的二进制,在计算海明码的距离会不一样,
        即每次产生的海明距离不一致
        所以不建议使用。
        '''
        # x=str(bin(hash(source)).replace('0b','').replace('-','').zfill(64)[-64:])
        # print(source,x,len(x))
        # return x


    def hammingDis(self,com):
        t1 = '0b' + self.simhash
        t2 = '0b' + com.simhash
        n=int(t1, 2) ^ int(t2, 2)
        i=0
        while n:
            n &= (n-1)
            i+=1
        return i




免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

浅谈simhash及其python实现

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

浅谈simhash及其python实现

作者原创,转载请注明出处。一直想写个总结来回顾simhash,一直没抽出时间,现在还是好好写写总结一下。作者随笔,废话有点多,不喜勿喷,欢迎指教。谷歌每天从网上抓取海量的信息,怎么样区分重复的呢,据说就采用了simhash算法,当然肯定也不
2023-01-31

浅谈Node模块系统及其模式

模块是构建应用程序的基础,也使得函数和变量私有化,不直接对外暴露出来,接下来我们就要介绍Node的模块化系统和它最常用的模式 为了让Node.js的文件可以相互调用,Node.js提供了一个简单的模块系统。模块是Node.js 应用程序的基
2022-06-04

python如何实现Simhash算法

这篇文章主要介绍python如何实现Simhash算法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!1、simhash步骤simhash包含分词、hash、加权、合并、降维五大步骤simhash代码如下:import
2023-06-29

浅谈Python单向链表的实现

链表由一系列不必在内存中相连的结构构成,这些对象按线性顺序排序。每个结构含有表元素和指向后继元素的指针。最后一个单元的指针指向NULL。为了方便链表的删除与插入操作,可以为链表添加一个表头。删除操作可以通过修改一个指针来实现。插入操作需要执
2022-06-04

浅谈python 线程池threadpool之实现

首先介绍一下自己使用到的名词: 工作线程(worker):创建线程池时,按照指定的线程数量,创建工作线程,等待从任务队列中get任务; 任务(requests):即工作线程处理的任务,任务可能成千上万个,但是工作线程只有少数。任务通过
2022-06-04

浅谈express 中间件机制及实现原理

简介中间件机制可以让我们在一个给定的流程中添加一个处理步骤,从而对这个流程的输入或者输出产生影响,或者产生一些中作用、状态,或者拦截这个流程。中间件机制和tomcat的过滤器类似,这两者都属于责任链模式的具体实现。 express 中间件使
2022-06-04

怎么利用python实现Simhash算法

本文小编为大家详细介绍“怎么利用python实现Simhash算法”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么利用python实现Simhash算法”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。1. 为什
2023-07-02

浅谈Java继承中的转型及其内存分配

看书的时候被一段代码能凌乱啦,代码是这样的:package 继承;abstract class People { public String tag = "疯狂Java讲义"; //① public String na
2023-05-30

浅谈Python浅拷贝、深拷贝及引用机制

这礼拜碰到一些问题,然后意识到基础知识一段时间没巩固的话,还是有遗忘的部分,还是需要温习,这里做份笔记,记录一下 前续先简单描述下碰到的题目,要求是写出2个print的结果可以看到,a指向了一个列表list对象,在Python中,这样的赋值
2022-06-04

浅谈Node Inspector 代理实现

背景 平时做 node 开发的时候,通过 node inspector 来进行断点调试是一个很常用的 debug 方式。但是有几个问题会导致我们的调试效率降低。 问题一:当使用 vscode 进行断点调试时,如果应用是通过 cluster
2022-06-04

浅谈Java中的atomic包实现原理及应用

1.同步问题的提出假设我们使用一个双核处理器执行A和B两个线程,核1执行A线程,而核2执行B线程,这两个线程现在都要对名为obj的对象的成员变量i进行加1操作,假设i的初始值为0,理论上两个线程运行后i的值应该变成2,但实际上很有可能结果为
2023-05-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录