minHash最小哈希

LSH算法简介

在介绍min-hash算法之前,我们必须先简单介绍一下LSH(局部敏感哈希 Locality Sensitive Hashing)的概念。

LSH(局部敏感哈希 Locality Sensitive Hashing)算法是近似最近邻搜索算法中最流行的一种,而近似最近邻搜索最通俗的解释就是寻找与指定对象相似的目标对象。其主要应用于从海量的数据中挖掘出相似的数据,可以具体应用到文本相似度检测、网页搜索等领域。

LSH算法大致分为三个步骤:

  1. Shingling:将文本文档转换为集合表示 (通常是转换为布尔型向量)
  2. Min-Hashing: 将高维度的向量转换为低维的哈希签名,此时再计算哈希签名的相似性
  3. Locality-Sensitive Hashing: 重点关注来自相似文档的一对候选哈希签名

(上述的三个步骤中,第一步Shingling属于文本的向量化,这是一个非常大的方面,之后会单独开系列讲解。)

现在我们可以知道,min-hash 算法是LSH算法中的一个步骤,其主要工作是对输入的高维向量(可能是几百万维甚至更高)转换为低维的向量(降维后的向量被称作数字签名),然后再对低维向量计算其相似,以达到降低计算成本,提高运行效率的目的。

知道了min-hash的目的,我们接下来需要关注的就是min-hash是如何实现上述需求的了。


作者:在这里唱歌不一定都是神经病
链接:https://juejin.cn/post/7025522652898918414
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Jaccard相似度

       在本例中,我们仅探讨集合的相似度,先来看Jaccard相似度。假设有两个集合A,B,则

       Jaccard(A, B)= |A ∩ B| / |A ∪ B|,我们举一个例子:

       在上述例子中,sim(A,B)=2/7。

minHash最小哈希

在做文本去重任务时其实有很多中方法可供选择,譬如,对文章分词,两两对比词集合的jaccard系数,但是当遇到大规模文本去重时,这种方法的效率就太低了,接下来介绍一种大规模文本去重算法minhash

什么是minhash?

什么是minhash呢,他跟传统的hash算法有什么区别呢,要理解这个问题,我们就要是知道hash是什么,简单理解hash就是将不同长度规则的文本转化成相同长度的字符串,用这些相同长度的字符串来表示原文本。但是传统hash存在一个问题是,相同内容的文本会生成相同的hash,但是相似的文本(可能就是一个字的差别)生成的hash会有很大的不同。但是我们在做文本相似度时,希望对相似的文本生成相似的hash,这样我们只需要计算一个个特定长度的hash值之间相似度,就可以近似得到原文本之间的相似度了,显然传统的hash算法是做不到这一点的。

怎么生成hash?

针对这个问题我们就要设计一种hash算法,让相似的文本生成相似的hash值。那在minhash算法中是怎么生成hash的呢?

假设我们这里有三个文本(假设a、b、c、d是四个不同的词):

S1 = abcd

S2 = bcd

S3 = ad

我们用一个特征矩阵来表示比较直观一点:

可以用如下3步来简单理解如何生成hash:

1)将行随机打乱。

2)行打乱后,针对每个S1、S2、S3看第一个1所在的行号,这个行号就是这个集合的最小哈希值。

3)设定hash的大小,如果是N,则重复上述步骤,随机进行N次行打乱,得到N个最小哈希值,那么这N个最小哈希值组成的集合就是S1、S2、S3对应的哈希签名。

为什么要进行行变换使用第一个1所在的行号作为最小哈希值呢,这样生成的哈希有什么意义呢?

我的理解是,这近似于一种抽样方法,用少数的哈希值来代替原本稀疏的特征矩阵,至于用第一个1所在的行号作为最小哈希的原因在于行号一样的集合原本的特征值都是1,这样得到哈希值也是一样,那么两个相似的文本得到的哈希在很大程度上就具有相似性,即解决了传统的hash算法存在的相似文本得到差别很大的哈希的问题。

我们直接看例子:

基于上述的矩阵,我们进行第一次行变换得到如下新矩阵(行号从0开始算):

那么对于S1来说,顺着行号往下走,发现第一个1所在的行号是0,那么h(S1) = 0,依次类推,h(S2) = 0, h(S3) = 2。

第二次行变换:

h(S1) = 0,h(S2) = 1,h(S3) = 0

第三次行变换:

h(S1) = 0,h(S2) = 0,h(S3) = 1

假设我们就进行三次行变换及N为3(N通常要远远小于特征矩阵的行数),我们就得到了3个最小哈希值,每个集合对应的哈希值可以表示如下(h里边的1,2,3分别代表对应的第几次行变换):

怎么计算相似度?

从表中可以看出来,我们将原本的S1=abcd 转化成了[0,0,0],S2=bcd转化成了[0,1,0],S2=ad转化成了{2,0,1}。

我们现在已经将文本进行了hash编码,那么我们接下来就要计算哈希签名的相似度了,相似度的计算方法是对应位置相同的元素个数比上哈希签名长度。则:

Sim(S1,S2) = 2/3

Sim(S1,S3) = 1/3

Sim(S2,S3) = 0

以上就是minhash的计算过程,可能你要问了,一般情况下,特征矩阵有很多行,对特征矩阵进行打乱很耗时,特别是还要进行多次打乱,怎么办呢?

所以一般在工程中会定义一些函数,用这些函数算出来的值来作为最小哈希签名,在这里就不做过多介绍了,大家有时间也可以看看minhash的实现源码,加深理解minhash算法。

那么可能有要问了,使用minhash也只不过是把长文本用较短的hash编码来表示,不还是需要两两进行相似度计算嘛,别急,后边会写关于局部敏感哈希算法(LSH)来解决这个问题,更快速的进行文本去重。

       在经过随机行打乱后,两个集合的最小哈希值相等的概率等于这两个集合的Jaccard相似度,证明如下:

       现仅考虑集合S1和S2,那么这两列所在的行有下面3种类型:
       1、S1和S2的值都为1,记为X
       2、只有一个值为1,另一个值为0,记为Y
       3、S1和S2的值都为0,记为Z

       S1和S2交集的元素个数为x,并集的元素个数为x+y,所以sim(S1,S2) = Jaccard(S1,S2) = x/(x+y)。接下来计算h(S1)=h(S2)的概率,经过随机行打乱后,从上往下扫描,在碰到Y行之前碰到X行的概率为x/(x+y),即h(S1)=h(S2)的概率为x/(x+y)

集合的Jaccard系数与min-hash系数只能说比较接近,但不能说完全一致。这是由于本例中的三个原始集合维度本身也不高,仅有5维,在实际的应用中,我们所面对的集合通常是成百万上千万维的,在宏观的角度下,或者说从统计上来讲,min-hash系数是等于Jaccard系数的。这就引出了上一节留下的问题:凭什么认为完成了最小哈希操作后的集合之间的Jaccard距离与原始集合之间的Jaccard距离还是相等的呢? 对于该疑问,我们证明如下:

将矩阵按行打乱排序是一个计算复杂度相当高的操作。因此,我们要将min-hash算法投入实际应用,就必须要找出另一种哈希函数来替代打乱排序的操作,作为新的最小哈希操作来得到哈希签名。那么,实际应用中采取的都是什么方法呢?

如何去选取这样的一组哈希函数。

事实上,基于经验,我们通常使用以下公式,通过直接改变系数,来得到需要数量的哈希函数:

实际应用中,我们可以通过调整两个coe系数,以及mod,共计三个参数的大小,来得到无限多的哈希函数。

  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值