转自:http://www.07net01.com/2015/08/907327.html

在数据挖掘中,有一个比较基本的问题,就是比较两个集合的相似度。关于这个问题,最笨的方法就是用一个两重循环来遍历这两个集合中的所有元素,进而统计这两个集合中相同元素的个数。但是,当这两个集合里的元素数量非常庞大时,同时又有很多个集合需要判断两两之间的相似度时,这种方法就呵呵了,对内存和时间的消耗都非常大。因此,为了解决这个问题,数据挖掘中有另一个方法。

Jaccard相似度

在介绍具体算法之前,我们首先来了解一个概念:Jaccard相似度。

Jaccard相似度是用来描述两个集合间的相似度的,其计算方法如下(假设有两个集合A,B):,也就是A与B交集的元素个数除以A与B并集的元素个数;为了书写方便,下面的讨论中我们将集合A和B的Jaccard相似度记为SIM(A,B);

例如:上图中有两个集合A,B;A中有4个元素,B中有5个元素;A,B的交集元素个数为2,并集元素个数为7,所以SIM(A,B) = 2 / 7;

k-Shingle

假如我们把一整篇文章看成一个长的字符串,那么k-shingle就是这篇文档中长度为k的任意字符子串。所以,一篇文章就是很多个不同的k-shingle的集合。

例如:现在我们有一篇很短的文章,文章内容为abcdabd,令k=2,那么这篇文章中所有的2-shingle组成的集合为{ab,bc,cd,da,bd},需要注意的是,ab在文章中出现了两次,但是在集合中只出现一次,这是因为集合中不能有相同的元素。

尽管用k-shingle的方式来表示每篇文章,然后再通过判断每篇文章中shingle集合的相同元素的数量,就可以得出文章的相似度;但是,一篇文章得到的shingle集合的元素个数是很多的。假定k=4,那么每个shingle中就会有4个字符,存在内存中就至少需要4个字节;那么要以这种方式存下一篇文章的所有shingle,需要的内存空间大概是原文档大小的4倍(假设原文档大小为100K,那么存下这篇文档的所有shingle则需要400K),这是因为原文档中的每个字符串都会出现在4个shingle中(除了开头和结尾那几个字符)。因此,以shingle的方式来存文章会消耗大量的内存。

接下来,我们需要把上面的shingle集合替换成规模小很多的“签名”集合。这样,就可以通过比较两篇文章的签名集合的相似度,就能够估计shingle的相似度了。这样得到的相似度只是原来相似度的近似值。

在介绍签名集合之前,我们先来看下如何将集合表示成其特征矩阵。

特征矩阵

特征矩阵的一列就对应一个集合,所有的行加起来就是所有集合元素的全集,如果集合中有那个元素,则矩阵中的对应位置为1,否则为0(好吧,讲的不是很清楚,还是直接上例子吧):

假设现在有4个集合,分别为S1,S2,S3,S4;其中,S1={a,d}, S2={c}, S3={b,d,e}, S4={a,c,d},所以全集U={a,b,c,d,e}

那么这4个集合的特征矩阵为:

其中第一行和第一列不是特征矩阵的一部分,只是为了便于理解而写上的。

最小哈希

构建集合的特征矩阵是为了计算集合的最小哈希。

为了计算最小哈希,首先对特征矩阵的行进行打乱(也即随机调换行与行之间的位置),这个打乱是随机的。然后某一列的最小哈希值就等于打乱后的这一列第一个值为1的行所在的行号(不明白的直接看例子),行号从0开始。

例如,定义一个最小哈希函数h,然后对上面的特征矩阵进行行打乱,原来第一列的顺序为abcde,打乱后为beadc,则新的特征矩阵为:

对于列S1,从这一列的第一行往下走,直到遇到第一个1,所在的行号则为这一列的最小哈希值。所以这4列的最小哈希值依次为h(S1) = 2, h(S2) = 4, h(S3) = 0, h(S4) = 2.

最小哈希与Jaccard相似度

在经过行打乱后的两个集合计算得到的最小哈希值相等的概率等于这两个集合的Jaccard相似度。简单推导如下:

假设只考虑集合S1和S2,那么这两列所在的行有下面三种类型:

1.      这一行的S1和S2的值都为1(即两列值都为1),记为X类;

2.      这一行只有一个值为1,另一个值为0,记为Y类;

3.      这一行两列的值都为0,记为Z类。

假设属于X类的行有x个,属于Y类的行有y个,所以S1和S2交集的元素个数为x,并集的元素个数为x+y,所以SIM(S1,S2) = x / (x+y)。注:SIM(S1,S2)就是集合S1和S2的Jaccard相似度。

接下来计算最小哈希h(S1) = h(S2)的概率。经过行打乱之后,对特征矩阵从上往下扫描,在碰到Y类行之前碰到X类行的概率是x / (x+y);又因为X类行中h(S1)=h(S2),所以h(S1)=h(S2)的概率为x/(x+y),也就是这两个集合Jaccard相似度。

最小哈希签名

上面是用一个行打乱来处理特征矩阵,然后就可以得到每个集合最小哈希值,这样多个集合就会有多个最小哈希值,这些值就可以组成一列。当我们用多个随机行打乱(假设为n个,分别为h1,h2…hn)来处理特征矩阵时,然后分别计算打乱后的这n个矩阵的最小哈希值;这样,对于集合S,就会有n个最小哈希值,这n个哈希值就可以组成一个列向量,为[h1(S), h2(S)…hn(S)];因此对于一个集合,经过上面的处理后,就能得到一个列向量;如果有m个集合,就会有m个列向量,每个列向量中有n个元素。把这m个列向量组成一个矩阵,这个矩阵就是特征矩阵的签名矩阵;这个签名矩阵的列数与特征矩阵相同,但行数为n,也即哈希函数的个数。通常来说,n都会比特征矩阵的行数要小很多,所以签名矩阵就会比特征矩阵小很多。

最小签名的计算

其实得到上面的签名矩阵之后,我们就可以用签名矩阵中列与列之间的相似度来计算集合间的Jaccard相似度了;但是这样会带来一个问题,就是当一个特征矩阵很大时(假设有上亿行),那么对其进行行打乱是非常耗时,更要命的是还要进行多次行打乱。               为了解决这个问题,可以通过一些随机哈希函数来模拟行打乱的效果。具体做法如下:

假设我们要进行n次行打乱,则为了模拟这个效果,我们选用n个随机哈希函数h1,h2,h3…hn(注意,这里的h跟上面的h不是同一个哈希函数,只是为了方便,就不用其他字母了)。处理过程如下:

令SIG(i,c)表示签名矩阵中第i个哈希函数在第c列上的元素。开始时,将所有的SIG(i,c)初始化为Inf(无穷大),然后对第r行进行如下处理:

1.      计算h1(r), h2(r)…hn(r);

2.      对于每一列c:

a)        如果c所在的第r行为0,则什么都不做;

b)        如果c所在的第r行为1,则对于每个i=1,2…n,将SIG(i,c)置为原来的SIG(i,c)和hi(r)之间的最小值。

(看不懂的直接看例子吧,这里讲的比较晦涩)

例如,考虑上面的特征矩阵,将abcde换成对应的行号,在后面加上两个哈希函数,其中h1(x)=(x+1) mod 5,h2(x) = (3*x+1) mod 5,注意这里x指的是行号:

接下来计算签名矩阵。一开始时,全部初始化为Inf:

接着看特征矩阵中的第0行;这时S2和S3的值为0,所以无需改动;S1和S4的值为1,需改动。h1= 1,h2= 1。1比Inf小,所以需把S1和S4这两个位置对应的值替换掉,替换后效果如下:

接着看第1行;只有S3的值为1;此时h1= 2,h2= 4;对S3那一列进行替换,得到:

接着看第2行;S2和S4的值为1;h1=3,h2=2;因为签名矩阵S4那一列的两个值都为1,比3和2小,所以只需替换S2那一列:

接着看第3行;S1,S3和S4的值都为1,h1=4, h2= 0;替换后效果如下:

接着看第4行;S3值为1,h1=0, h2= 3,最终效果如下:

这样,所有的行都被遍历一次了,最终得到的签名矩阵如下:

基于这个签名矩阵,我们就可以估计原始集合之间的Jaccard相似度了。由于S2和S4对应的列向量完全一样,所以可以估计SIM(S1,S4)=1;同理可得SIM(S1,S3) = 0.5;

局部敏感哈希算法(LSH)

通过上面的方法处理过后,一篇文档可以用一个很小的签名矩阵来表示,节省下很多内存空间;但是,还有一个问题没有解决,那就是如果有很多篇文档,那么如果要找出相似度很高的文档,其中一种办法就是先计算出所有文档的签名矩阵,然后依次两两比较签名矩阵的两两;这样做的缺点是当文档数量很多时,要比较的次数会非常大。那么我们可不可以只比较那些相似度可能会很高的文档,而直接忽略过那些相似度很低的文档。接下来我们就讨论这个问题的解决方法。

首先,我们可以通过上面的方法得到一个签名矩阵,然后把这个矩阵划分成b个行条(band),每个行条由r行组成。对于每个行条,存在一个哈希函数能够将行条中的每r个整数组成的列向量(行条中的每一列)映射到某个桶中。可以对所有行条使用相同的哈希函数,但是对于每个行条我们都使用一个独立的桶数组,因此即便是不同行条中的相同列向量,也不会被哈希到同一个桶中。这样,只要两个集合在某个行条中有落在相同桶的两列,这两个集合就被认为可能相似度比较高,作为后续计算的候选对;下面直接看一个例子:

例如,现在有一个12行签名矩阵,把这个矩阵分为4个行条,每个行条有3行;为了方便,这里只写出行条1的内容。

可以看出,行条1中第2列和第4列的内容都为[0,2,1],所以这两列会落在行条1下的相同桶中,因此不过在剩下的3个行条中这两列是否有落在相同桶中,这两个集合都会成为候选对。在行条1中不相等的两列还有另外的3次机会成为候选对,因为他们只需在剩下的3个行条中有一次相等即可。

经过上面的处理后,我们就找出了相似度可能会很高的一些候选对,接下来我们只需对这些候选队进行比较就可以了,而直接忽略那些不是候选对的集合。

(转)最小Hash和局部敏感Hash的更多相关文章

  1. 在茫茫人海中发现相似的你——局部敏感哈希(LSH)

    一.引入 在做微博文本挖掘的时候,会发现很多微博是高度相似的,因为大量的微博都是转发其他人的微博,并且没有添加评论,导致很多数据是重复或者高度相似的.这给我们进行数据处理带来很大的困扰,我们得想办法把 ...

  2. 从NLP任务中文本向量的降维问题,引出LSH(Locality Sensitive Hash 局部敏感哈希)算法及其思想的讨论

    1. 引言 - 近似近邻搜索被提出所在的时代背景和挑战 0x1:从NN(Neighbor Search)说起 ANN的前身技术是NN(Neighbor Search),简单地说,最近邻检索就是根据数据 ...

  3. 海量数据挖掘MMDS week2: 局部敏感哈希Locality-Sensitive Hashing, LSH

    http://blog.csdn.net/pipisorry/article/details/48858661 海量数据挖掘Mining Massive Datasets(MMDs) -Jure Le ...

  4. [Algorithm] 局部敏感哈希算法(Locality Sensitive Hashing)

    局部敏感哈希(Locality Sensitive Hashing,LSH)算法是我在前一段时间找工作时接触到的一种衡量文本相似度的算法.局部敏感哈希是近似最近邻搜索算法中最流行的一种,它有坚实的理论 ...

  5. LSH︱python实现局部敏感随机投影森林——LSHForest/sklearn(一)

    关于局部敏感哈希算法.之前用R语言实现过,可是由于在R中效能太低.于是放弃用LSH来做类似性检索.学了python发现非常多模块都能实现,并且通过随机投影森林让查询数据更快.觉得能够试试大规模应用在数 ...

  6. 局部敏感哈希算法(Locality Sensitive Hashing)

    from:https://www.cnblogs.com/maybe2030/p/4953039.html 阅读目录 1. 基本思想 2. 局部敏感哈希LSH 3. 文档相似度计算 局部敏感哈希(Lo ...

  7. 基于局部敏感哈希的协同过滤推荐算法之E^2LSH

    需要代码联系作者,不做义务咨询. 一.算法实现 基于p-stable分布,并以‘哈希技术分类’中的分层法为使用方法,就产生了E2LSH算法. E2LSH中的哈希函数定义如下: 其中,v为d维原始数据, ...

  8. 基于局部敏感哈希的协同过滤算法之simHash算法

    搜集了快一个月的资料,虽然不完全懂,但还是先慢慢写着吧,说不定就有思路了呢. 开源的最大好处是会让作者对脏乱臭的代码有羞耻感. 当一个做推荐系统的部门开始重视[数据清理,数据标柱,效果评测,数据统计, ...

  9. 局部敏感哈希-Locality Sensitive Hashing

    局部敏感哈希 转载请注明http://blog.csdn.net/stdcoutzyx/article/details/44456679 在检索技术中,索引一直须要研究的核心技术.当下,索引技术主要分 ...

随机推荐

  1. itest(爱测试) 4.5.0 发布,开源BUG 跟踪管理 & 敏捷测试管理软件

    itest 简介 test 开源敏捷测试管理,testOps 践行者.可按测试包分配测试用例执行,也可建测试迭代(含任务,测试包,BUG)来组织测试工作,也有测试环境管理,还有很常用的测试度量:对于发 ...

  2. [MongoDB]MongoDB的ObjectId组成

    一.ObjectId的组成首先通过终端命令行,向mongodb的collection中插入一条不带“_id”的记录.然后,通过查询刚插入的数据,发现自动生成了一个objectId“5e4fa350b6 ...

  3. tomcat - 解决 org.bouncycastle.asn1.ASN1Boolean 非法循环依赖的错误

    背景 记录遇到一次奇怪的错误,在发布war包到Tomcat的时候,出现了org.bouncycastle.asn1.ASN1Boolean非法循环依赖的错误. INFO: Deploying web ...

  4. 20200228 尚硅谷-NIO

    尚硅谷-NIO Java NIO简介 Java NIO(New IO.Non Blocking IO)是从Java1.4版本开始引入的新的 IO API,可以替代标准的 Java IO API. NI ...

  5. .NET MVC强类型参数排除和包含

    MVC接收强类型对象时排除或只接收某几个属性使用Bind特性 只接收几个属性:Bind(Include="属性1,属性2,属性3,...") 排除某几个属性:Bind(Exclud ...

  6. 关于Git GUI克隆代码

    1.首先需要使用Git GUI生成一个SSH秘钥并将其拷贝到远程(码云或者GitHub)账号下的SSH公钥中(以码云为例) 将上一步生成的SSH密钥拷贝到下面的码云的公钥中 2.拷贝下码云上代码的SS ...

  7. HQL查询 HQL Named parameter [xxx] not set 的解决办法

    org.springframework.dao.InvalidDataAccessResourceUsageException: Named parameter [xxx] not set; nest ...

  8. Linux 命令之 linux 四剑客

    Linux命令-- 四剑客 一:Linux命令 之 AWK 符号:^ 开头 $ 结尾 awk 是一种处理文本的语言,一个强大的文本分析命令! 1:提取文件中的每行的第二个 提取前文本中内容为  命令: ...

  9. 获取http://XX.XX.XX.XX :XXXX/QuestionResult.aspx?method=接口返回值

    private string GetWeather(string strRegisterNo) { string getWeatherUrl = "http://XX.XX.XX.XX :X ...

  10. SVN提交更新文件,抛出"svn: No such revision 27106"异常问题处理

    SVN,不管是更新或者是提交原来存在的文件,都会抛出此异常"svn: No such revision 27106",注意,是原来存在的文件,要是新增的文件,不会出现此问题. 百度 ...