局部敏感哈希 | 青训营笔记

447 阅读3分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第5篇笔记。

传统哈希算法目的是减少冲突以加速增删改查的速度,而此处介绍的局部敏感哈希(Locality Sensitive Hash)旨在最大化哈希冲突,尽可能保证以更高概率将相似的输入项散列到相同的桶中。通过这么一种哈希算法,我们可以将高维的数据映射到一个低维的向量空间,同时也能保证在一定概率下,原有向量空间相似的输入项在映射后的向量空间中仍然相似。LSH算法可用于数据聚类和最近邻搜索,在实际场景中,LSH算法常用于信息检索、数据挖掘、推荐系统以及视觉相似性排名等应用。

定义

对于一个LSH的哈希算法族(原文为:LSH Family)F\mathcal{F},定义度量空间M=(M,d)\mathcal{M}=(M,d),阈值R>0R>0,近似因子c>1c>1,以及概率P1,P2P_1,P_2F\mathcal{F}是一个函数的集合,其中的函数h:MSh:M\rightarrow S将度量空间的元素映射到桶中sSs\in S。一个LSH算法族应满足如下条件,对于在度量空间MM的两个点p,qMp,q\in M,以及从F\mathcal{F}中随机选取的任意一个散列函数hh:

  1. 如果d(p,q)Rd(p,q)\le R,那么h(p)=h(q)h(p)=h(q)的概率至少P1P_1。(例如p,qp,q为同一个点)
  2. 如果d(p,q)Rd(p,q)\ge R,那么h(p)=h(q)h(p)=h(q)的概率至多P2P_2

P1>P2P_1\gt P_2时,这个LSH算法族是有意义的。这样一个LSH算法族F\mathcal{F}被称为是(R,cR,P1,P2)(R,cR,P_1,P_2)-敏感的。

方法

LSH算法有很多方法,包括汉明距离的位采样、MinHashNilsimsa Hash、TLSH以及SimHash等。其中较为经典的方法为SimHash,本文也主要介绍SimHash的思想。

SimHash是Google于2007年在Detecting near-duplicates for web crawling这篇论文中提出,目的是为了解决海量网页的去重任务。SimHash通常用于长文本,将长文本压缩成几个关键词来代表,再将这些关键词编码为定长的二进制字符串,通过这样的编码,我们如需要查询文章,仅需通过相同方法查询对应的编码即可。

SimHash的步骤

分词

分词部分可以调用各语言的库,如jieba(Python)、GoJieba(Golang)等,此处不做过多描述。

TF-IDF

TF-IDF(term frequency–inverse document frequency)是一种用于信息检索与数据挖掘的常用加权技术,可以统计一字词对于一个文件集或一个语料库中的其中一份文件的重要程度,TF-IDF算法在网上也可搜到相关信息。

Hash

得到的关键词以及其TF-IDF权重后,对第ii个关键词进行编码,对其进行Hash后得到一个N位的二进制串,定义一个N位的新二进制串sis_i,对每个Hash后的二进制串逐位进行处理,对应位为0的,将sis_i中对应位置置为该关键词权重的负数;对应位为1的,将sis_i中对应位置置为该关键词权重,最后将该文章中所有关键词的二进制串sis_i进行逐位的累加得到一个最终的二进制串ss,针对该二进制串,我们同样进行逐位的处理,如果第ii的值为正数,我们最终SimHash的值的第ii的值置为1;如果第ii的值为负数,我们最终SimHash的值的第ii的值置为0。如此一来,我们便得到了最终的SimHash值。

计算相似度

最终我们如果想计算两篇文章的相似度时,我们就可以计算两篇文章的SimHash值,将海量高维数据计算相似度的问题转换为计算低维数据相似度的问题。计算两个SimHash的相似度通常使用汉明距离,汉明距离即二进制位相同的位数,如果相同的位数高于一定阈值,我们便可认为两篇文章相似。