字面文本相似度算法——SimHash

什么是字面文本相似度?

在NLP领域如何判断两个文本的相似性是一个基础性的任务,而文本的相似性往往可以理解为两个方面:字面相似性和语义相似性。怎么理解这个内容呢?就比如说白龙马赤兔马,乍一看,”WC,这不就是马么有啥区别?一个是白的一个是红的,也没啥!“,但是究其本质白龙马是龙啊,赤兔马就是一匹普通的坐骑。

上面的例子可以认为是“形似韵不同”的诠释,还有些是“形不似,神似”,等等。而字面文本相似度就是解决无论语义怎样,只要两个文本长得差不多,那就相似。

什么是SimHash?

说SimHash不难会想到Hash。

Hash对于一个了解数据结构的人来说并不陌生,可以认为是数据的一个“唯一性”id,但是并不唯一,这与hash算法和hash函数的选取有关,有可能出现冲突等问题。扯远了~

一个文本采用Hash后的编码可以代表这个文本,但是将整个文本的内容进行hash后,很少有两个hash文本很类似,也就是说,文本间的hash码会有很大的差异。也就无法度量文本间的字面相似度。

SimHash是Google发表于2007的论文《Detecting Near-Duplicates for Web Crawling》。设计的初衷是用于搜索引擎的网页去重的工作。

其实还有一个作用,就是用于判断两篇文章是否有抄袭。如果最后的SimHash的值相差不多,很可能文章就有抄袭。

SimHash还有一种叫法,称为局部Hash。同时得到的SimHash值通过计算海明距离就可以得到文本间的距离差值。

SimHash计算流程

其中SimHash可以划分为5个步骤:

  1. 分词
  2. 对词做Hash
  3. 针对每个词做加权
  4. 以句子(文本)为单位进行合并
  5. 降维

下图可以很形象的描绘整个算法的计算流程:
在这里插入图片描述

step1:分词

分词不必多说,是将文本中的句子分为词的列表,当然也可以以字为单位进行。按照下面的句子作为示例进行介绍。

	今天天气很好 ==> 今天/天气/很好

step2:Hash

针对词表中的每个词汇做hash处理,生成一个32位(或者64位)长度的二进制数。Python中可以输出字符串所对应的二进制数来代替,不够的可以补0处理。下面以8位二进制数作为例子来介绍

	hash(今天)=01000101

step3:加权

每个词汇的重要程度不同,我们可以为每个词汇设置不同的权重,从而加以区分。加权的操作就是针对每个词汇的二进制码的每一位乘上对应的权值,原先为0的位置设置为负值。

	weight(今天) = 3
	weight_hash(今天) = [-3,3,-3,-3,-3 ,3,-3,3]

step4:合并

将文本中的每个词汇进行求和处理(对位求和),即可得到文本的hash表示。假设如下所示为句子的合并后的hash码

	merged_hash = [6,9,-1,0,7,-10,2,3]

step5:降维

其实这一步并不是降维的操作,而是将合并后的hash码进行归一化(规范化)的处理。即大于0的位置置为1,其它位置为0。

	sim_hash = [1, 1, 0, 0, 1, 0, 1, 1]

文本相似度计算

文本的相似度计算有多种方法,但是对于SimHash常用的方法为海明距离。因为SimHash码并不能反映一个文本的具体含义,它仅仅可以理解为一个文本的唯一性id,所以这就是为什么将SimHash又称为文本的指纹。

海明距离(Hamming distance)在信息编码中,两个合法代码对应位置上编码不同的位数称为码距,又称为海明距离。

比如:

vec1 = [1,0,1,1,0,0]
vec2 = [1,1,1,0,0,1]
hamming_distance(vec1, vec2) = 3

可以从上边的例子中了解到,第二位,第四位,第六位的编码不同,一共三个,所以码距为3

计算海明距离也有快速的方法,比如说利用向量的异或

hamming_vec = ve1 xor vec2 = [0, 1, 0, 1, 0, 1]

至此我们就可以对任意两个文本计算它的SimHash的距离了。当定义了最小的码距之后就可以确定哪些文本是相似的。

超大规模数据集计算

当文本的数量较少的时候轮训一遍数据集可以很快的找到想要的结果。但是如果语料中的文本规模有100亿个怎么办呢?加设备!好那要是有100万亿个文本怎么办呢?加设备是不够的的,需要利用鸽巢原理。对文本SimHash的向量维度进行切分,切分的个数为最小码距加1。并以这些切分后的结果进行建立倒排索引,加速计算。

猜你喜欢

转载自blog.csdn.net/qq_19672707/article/details/105640763