相似项

相似项

一个基本的数据挖掘问题是从数据中获得相似项

近邻搜索

先引入一个特定的相似度的概念,通过计算交集的相对大小来获得集合之间的相似度。这种相似度称为Jaccard相似度

集合的Jaccard相似度

集合S和T的相似度记为$|S\cap T|/|S\cup T|$ ,也就是集合S和T的交集和集合并集大小之间的比率。下面将S和T的Jaccard相似度记为SIM(S,T)

集合的相似度应用之一——文档的相似度

如果是在大语料库(例如Web或者新闻语料)中寻找文本内容的相似的文档,这种相似度侧重于字面上的相似,这个时候Jaccard相似度可以取得较好的效果。文本字面上的相似度同样有很重要的应用。其中很多应用都涉及检查两篇文档之间是否完全重复或近似重复。首先,检查两篇文档是否完全重复很容易,只要一个字符一个字符的比较,很多应用中两篇文档并不是完全重复,而是大部分重复。

例如:抄袭文档,他可能会进行改变语序或者改变个别词组、镜像页面,使得搜索引擎返回的结果避免在第一页包含几乎重复的两个网页、同源新闻稿:一个人将其的新闻稿同时投到多数报商中

集合相似度应用之一——协同过滤

另一个重要的集合相似度应用称为系统过滤collaborative filtering,在协同过滤中,系统会像用户推荐相似兴趣用户所喜欢的那些项

在线购物:购物网站中的销售库中记录了那些顾客购买了哪些商品,如果两个顾客购买的商品集合具有较高的Jaccard相似度,我们就说这两个顾客是相似的。类似的,若两件商品的购买客户集合之间具有较高的Jaccard相似度,那么就认为这两件商品是相似的。值得注意的是,对于镜像网站相似度我们期望是能超过90%,但是两个顾客之间的Jaccard相似度仅仅只要到达20%就足以判断两人的喜好相似。对于商品来说也是如此,只要俩个商品的相似度不用太高就已经值得注意了。

电影评级:Netflix不仅记录了每个用户租界电影的情况,还记录了顾客对这些电影的评价情况。如果电影被许多相同的用户租界或者评级打了很高的分数,那么就可以认为这些电影是相似的。如果用户租界很多相同的电影或者对他们的评价都很高,就可以认为这些用户兴趣相似,同购物网站一样,这里要求的相似度也不必太高

当数据中包含评级而不只是二值信息(已购买/未购买或者喜欢/讨厌)时,我们不能简单的将集合看成顾客或商品的表示加以以来。

以下是处理的三种方法1. 忽略低评用户/电影对,也就是说,如果每个用户对某个电影评分很低,则认为该用户没看过该电影2. 在进行用户比较时,假设梅毒电影可以有两类标签:喜欢或讨厌。如果用户对电影评分很高,那么将用户集合中对应该电影的元素设置为喜欢,同样的,如果用户对电影评分很低,那么就将相应位置上的元素设置为讨厌,于是可以在集合中找到高的Jaccard相似度3. 如果用户的评级范围为1~5星,则将评级为n的电影在集合中重复放置n次。这样就可以通过所谓的包bag之间的jaccard相似度来近似计算用户的相似度,即计算B,C交集时,某元素在B,C中的最小次数作为其在交集中的出现次数,计算B和C的并集时,某个元素在两个集合上的出现次数之和作为其在并集上的出现次数。

两个包{a,a,a,b}和{a,a,b,b,c}之间的相似度为1/3.其中两者的交集由2个a、1个b、组成,因此其大小为3.两个包的并集等于这两个包的大小之和,这里等于9.由于包的Jaccard相似度最好的情况才是1/2,所以1/3表明两个包非常相似,这一点通过他们的内容可以看出

未解决的问题:对于全集U含有n个元素,随机选择两个子集S和T,每个子集都有m个元素,请问S和T的期望的Jaccard相似度是多少?

文档的shingling

为了识别字面上相似性的文档,将文档表示为集合的最有效的方法是构建文档中的短字符串集合。如果文档采用这样的集合表示,那么有相同的句子甚至短语的文档之间将会拥有很多公共的集合元素,即使两片文档中的句序并不相同也是如此。

k-shingle

一篇文档就是一个字符串。文档的k-shingle定义为其中任意长度为k的子串。于是,每篇文档可以表示成文档中出现一次或者多次的k-shingle的集合。对于空白串(空格、tab及回车等)的处理可以有多种策略,将任意长度的空白串替换为单个空格或许很合理。采用这种做法,会覆盖2个或更多词的shingle和其他shingle区分开来

shingle大小的选择

理论上,我们可以选择任意的常数作为k,但是,如果选的k太小,那么可以推测大部分长度为k对额字符串会出现在大部分文档中。如果是这样,我们就会有很多jaccard相似度很高的文档,即使它们之间没有出现任何相同的句子或者短语。一个极端的例子就是k=1,大部分Web网页中都有很多常见字符,而其他字符相对来说就很少,因此几乎所有的网页都具有较高的jaccard相似度

到底要选择多大的k值依赖于文档的典型长度以及典型的字符表的大小。需要注意的是:

  • k应该选择的足够大,用以保证任意给定的shingle出现在任意文档中的概率较低。

因此,如果文档集由邮件组成,那么选择k=5应该比较合适。这是因为,假定邮件中只有字符和普通的空白字符(尽管实际上会出现其他字符),于是所有可能的5-shingle个数为$27^{5}=14348907$ 由于典型的邮件长度会远远低于1400万字符,所以我们希望k=5将会处理的很好。

然而,显然邮件中出现的字符不止27个,但是所有字符出现的概率却并不相同,常见的字符和空白字符出于支配地位,因此即使短邮件也会包含很多常见字符构成的5-shingle,因此彼此无关的邮件都包含这些shingle的几率会比上面计算所暗示的几率要高。一个很好的经验规则就是把邮件想象为只有20个不同的字符构成,其中k-shingle的数目大约为$20^{k}$.而对于研究论文一样的大文档来说,选择k=9则比较安全。

对shingle进行hash

可以不将不同的子字符串直接用成shingle,而是通过某个哈希函数将长度为k的字符串映射为桶编号,然后将得出的桶编号看成最终的shingle。于是,可以将文档表示成这些桶编号整数整数构成的集合,然后这些桶编号代表了一个或多个文档中出现的k-shingle。举例来说,对于文档可以构建9-shingle集合,然后将没9-shingle映射为0到$2^{32}-1$ 之间的一个桶编号。因此,每个shingle由4个字节而不是9个字节来表示,这样不仅数据上得了压缩,并且可以对哈希后得到的整数shingle进行单字机器运算。

我们注意到尽管使用9-shingle然后将他们映射成4字节整数来表示文档与与直接使用4-shingle来表示文档所使用的空间一样,但是前者却具有更强的文档区分能力。如果使用4-shingle,那么大部分4字节序列不太可能或根本不可能在典型文档中出现。因此,实际使用4-shingle,那么大部分4字节序列不太可能,或者根本不可能在典型文档中出现。因此,实际有效的不同shingle数目远小于$2^{32}-1$ ,正如之前所说,假定英文文本中仅有20个字符出现的比较频繁,那么可能出现的不同4-shingle数目仅为$20^{4}=16000$.但是如果使用9-shingle,那么出现不同的9-shingle数目就比$2^{32}$要多,当这些9-shingle映射成4个字节时,差不多任意组合的4字节序列都有可能出现。

基于词的shingle

shingle的另一种表现形式被证明在新闻报道近似重复检测中非常有用。该问题的一个可以利用的不同点在于网页中的新闻报道部分往往与其周边元素的写作风格差异很大,新闻报道以及大部分散文都包含大量的停用词,包括常见的and,you,to,在很多应用中,我们都想忽略这些停用词,因为他们对于文章(主题)都没有任何作用。然而对于新闻报道的近似重复检测来说,将shingle定义为一个停用词加上后续的两个词(不管是不是停用词)形成一个有用的shingle集。在进行Web网页表示时,这种做法的优势在于新闻本身比周边元素提供了更多的shingle集。上述做法在表示时更偏向新闻文本中的shingle集,于是,新闻内容相同但周边材料不同的网页的jaccard相似度高于周边材料相同但是新闻内容不同的网页的相似度。

保持相似度的集合摘要表示

shingle集合非常大,即使是将每个shingle都哈希为4个字节,一篇文档的shingle集合所需的空间仍然大概是该文档所需空间的4倍,如果有百万文档,很可能不能将这些文档的shingle集合都放入到内存中。

本书的目标是将上述大集合替换成规模小很多的签名signature表示,对于签名而言,我们所需要i的重要特性是能够仅仅通过比较两片文档的签名集合就可以估计实际shingle集合之间的jaccard相似度。当然,通过签名无法得到原始shingle集合之间jaccard相似度的精确值,但是估计结果与真实结果相差不大,并且签名集合越大,估计的精确度也就越高。例如,5000字节文档的shingle可能会映射为200 000字节的哈希结果,然后替换成1000字节大小的签名集合,基于最终的签名集合得到的原始文档jaccard相似度的估计值与真实值的差异也就在几个百分点之内。

集合的矩阵表示

在介绍如何构建大集合的小签名之前,将一系列集合表示成其特征矩阵characteristic matrix对于理解非常重要。矩阵的列对应集合,行对应全集(所有集合中可能的元素组成全集)中的元素。如果行r对应的元素属于列c对应的集合,那么矩阵第r行第c列的元素为1否则为0.注意一个需要密切关注的问题是,即使所有的集合都可以放入内存中,所需的对应的数目也可能会多到无法估计每对的相似度

需要记住的是,特征矩阵并非数据的真正储存方式,但是作为数据可视化的一种方式则是非常有用的。在实际当中,数据不会存储为矩阵的一个原因就是该矩阵往往非常稀疏(0的个数远多于1的个数)。只储存1的位置能够大大的节省存储的开销,同时又能够完整的表示整个矩阵。另一个原因是,数据往往基于其他目的的而存储为其他格式

举例来说,如果行代表商品,列代表顾客,则每个顾客可以表示成其所购买的商品集合,该数据可能真实 存在于销售记录库的数据表中。表中的元组也可能会包含商品、顾客及一些销售的细节信息,比如销售日期和所使用的信用卡信息。

最小哈希

我们想要构建的集合的签名由大量计算(比如数百次)的结果组成,而每次计算是特征矩阵的最小哈希minhashing过程

为了对特征矩阵每列所表示的集合进行最小哈希计算,首先选择行的一个排列转换,任意一列的最小哈希值是在排列转换后的行排列次序下第一个列值为1的行号

对于矩阵abcde排列方式,假定采用beadc的行序重新排列。该排列转换定义了一个最小哈希函数h,它将集合映射成一行。接下来我们基于函数h计算集合$S_{1}$ 的最小哈希值。按照becda的顺序来扫描集合$S_1$所对应的第一列,由于b行对应的值为0,所以需要往下继续扫描到行e,即排列转换次序,即排列转换次序中的第二行,其对应的$S_{1}$列值仍为0.于是再往下处理到行a,此时对应值为1,因此我们有$h(S_1)=a$

尽管物理上不可能对非常大的特征矩阵进行行排列转换,最小哈希函数h却隐式地将矩阵的行重新排列,使之变成新的矩阵,在新的矩阵中,h函数的值可以通过从上往下扫描直至遇到一为止。

最小哈希及jaccard相似度

在集合的jaccard的相似度及集合的最小哈希值之间存在着非同寻常的关联:

设函数\cal f: A \rightarrow A,A是一个集合,如果f是一一映射,就称f是A的一个排列转换,有时候也称为置换运算。即将行号重新排列。

  • 两个集合经随机排列转换之后得到的两个最小哈希值相等的概念等于这两个集合的jaccard相似度

理解这个结论的原因,必须要对两个集合同一列所对应的所有可能结果进行枚举。假设只考虑集合S_1和S_2所对应的列,那么他们所在的行可以按照所有可能的结果分成如下三类:

  • 1属于X类的行,两列的值均为1
    属于Y类的行,其中一列的值为0,另一列的值为1
    属于Z类的行,两列的值都没0

由于特征矩阵十分稀疏,因此大部分都属于Z类。但是X和Y行数目比例决定了SIM(S1,S2)以及概率h(S1)=h(S2)的大小。假定X类行的数目为x,Y类的行的数目为y,则$SIM(S_1,S_2)=x/(x+y)$,原因是$S_1 \cap S_2$的大小为x,$S_1 \cup S_2$ 的大小值为x+y

接下来我们考虑h(S_1)=h(S_2)的概率。设想所有行进行随机排列转换,然后我们从上到下进行扫描处理,在碰到Y类行之前碰到X类行的概率是X/(X+Y)。但是如果从上到下扫描到遇到除Z类行之外的第一行属于X类,那么坑定有h(S_1)=h(S_2),所以h(S_1)=h(S_2)的概率是x/(x+y)。这也正好是两个集合jaccard相似度的计算公式。

最小哈希签名

回到前面的一些列集合的特征矩阵表示M,为表示这些集合,我们随机选择n个排列转换用于矩阵M的行处理/其中n一般设置为一百或几百,对于集合S对应的列,分别调用这些排列转换所决定的嘴角哈希函数h_1,h_2,...h_n,则可以构建S的最小哈希签名minhash signature向量[h_1(S),h_2(S),...,h_n(S)],该向量通常写成列向量方式,因此基于矩阵M可以构建一个签名矩阵,其中M的每一列替换成该列所对应的最小哈希签名向量即可。

需要注意的是,签名矩阵与M的列数相同但行数只有n。即使不显示表示M中的全部元素而只适用与稀疏矩阵某种压缩形式(比如只储存一所在的位置)来表示,通常情况下签名矩阵所需要的空间仍比矩阵M本身的表示空间要小很多。

最小哈希签名的计算

对大规模特征矩阵进行显示排列转换是不可行的,即使对上百万甚至数十亿的行选择一个随机排列转换也极其耗时间,而对进行必要的排序则需要更多的时间。因此对上式给出的行排列转换后的矩阵在概念上听起来十分吸引人,但是却缺乏可操作性。

幸运的是,我们可以通过一个随机哈希函数来模拟随机排列转换的效果,该函数将行号映射到与行数目大致相等数量的桶中。通常而言,一个将整数0,1,2,...,k-1映射到桶号0,1,2,...k-1的哈希函数会将某些整数对映射到同一个桶中,而有些桶却没有被任何整数所映射到。然而只要k很大且哈希结果冲突不太频繁的话,差异就不是很重要了。于是我们继续假设哈希函数h将原来的r行放在排列转换后次序中的第h(r)个位置。

因此,我们就可以不对行选择n个随机排列转换,取而代之的是随机选择n个哈希函数h1,h2,...,hn作用于行。在上述处理基础上,就可以根据每行在哈希之后的位置构建签名矩阵。令SIG(i,c)为签名矩阵中第i个哈希函数在第c列上的元素。一开始,对于所有的i和c,将SIG(i,c)化为\infty然后对r行进行如下处理:

  • 计算h_1(r),h_2(r),...,h_n(r)\
  • 对每列c进行如下操作:
    • 如果c在第r行为0,则什么都不做
    • 否则,如果c在第r行为1,那么对于每个i=1,2,...,n将SIG(i,c)置为原来的SIG(i,c)和h_i(r) 中的较小值。

基于上述签名矩阵,我们可以估计原始集合之间的jaccard相似度。需要注意的是签名矩阵的一致程度只是真实jaccard相似度的一个估计值,因为本列规模太小,所以并不足以说明在大规模数据下估计值与真实值相近的规律。

文档的局部敏感哈希算法

即使可以使用最小哈希将大文档压缩成小的签名,并同时保持任意对文档之间的预期的相似度,但是高效寻找具有最大相似度的文档的。主要原因在于,即使文档本身数目并不是很大,但是需要比较的文档对的数目可能太大。

如果我们的目标是计算没对文档的相似度,那么即使采用并行机制来减少实耗时间,也没有办法来减少计算量。但是实际中往往需要得到那些最相似或者相似度超过某个下届的文档对。

如果是这样的话我们就只需要关注那些可能相似的文档对,而不需要研究所有的文档对。目前对这类问题的处理存在着一个称为局部敏感哈希locality-sensitive hashing 或近邻搜索的一般性理论。

面向最小哈希签名的LSH

LSH的一般性做法就是对目标项进行多次哈希处理,使得相似项会比不相似项更可能会哈希到同一桶中。然后至少有一次哈希到同一桶中的文档对看成候选对 candidate pair 我们只会检查这些候选对的相似度。我们希望大部分不想似的文档对永远不会哈希到相同的桶中,这样就永远不会检查它们之间的相似度。那些哈希到同一桶中的非相似对文档假阳性false positive 我们希望他们在所有对中的占比越低越好,同时我们希望大部分真正相似的文档对至少会被哈希函数映射到同一桶中,那些没有映射到相同桶中的真正相似文档称为假阴性false negative,我们希望他们所有真正相似的文档对中的比例也很小。

如果使用目标项的最小哈希签名矩阵,那么一个有效的哈希处理方式是将签名矩阵划分为b个行条,每个行条由r行组成。对每个行条,存在一个哈希函数能够将行条中的每r个整数组成的列向量(行条中的每一列)映射到某个大数目范围的桶中。可以对所有行条使用相同的哈希函数,但是对于每个行条我们都是用一个独立的桶数组,因此即使是不同的行条中的相同向量列,他们可能不会被哈希到同一桶中。

由于哈希桶的2数目也不少,偶然冲突的预期概率非常低,通常我们都假设当且仅当两个向量相等时,他们才会哈希到同一桶中。

我们观察到,如果签名矩阵的两列越相似,那么在多个行条中的向量相等的可能性也就越大。因此直观上看,行条化策略能够使得相似的列会比不相似的列更有可能成为候选对。

行条化策略的分析

假定使用b个行条,每个行条由r行组成,并且假定某对具体的文档之间的jaccard相似度为s。文档的最小哈希签名矩阵中的某个具体行中的两个签名相等的概率也为s,现计算这些文档或其签名作为候选对的概率,具体计算过程如下:

  • 在某个具体行条中所有行的两个签名相等的概率为s^r

  • 在某个具体行条中至少有一对签名不相等的概率是1-s^r

  • 在任何行条中的任意一行的签名对都不相等的概率为(1-sr)b

  • 签名至少在一个行条中全部相等的概率,也即是称为候选对的概率为1-(1-sr)b

虽然有可能并不明显,但是不论常数b和r的取值为何,上述图像的大致图像都是s-1曲线s-curve。曲线中候选概率1/2处对应的相似度就是所谓的阈值threshold,他是b和r的函数。阈值对应的大概是上升最陡峭的地方,对于较大恶的b和r,相似度在阈值之上的对很可能成为候选对,而在阈值之下的对则不太可能成为候选对,着正是我们想要的结果。阈值的一个近似估计是(1/b)^{1/r}

技术综述

给出一个完整的相似项的方法:首先找出可能的候选对相相似文档集合,然后基于该集合发现真正的相似文档。必须要强调的是,这种方法可能会产生两种反例,即某些相似文档对于由于没有进入候选对所以最终没有被识别出来。同样该方法也可能会产生假阳性,即在评估了某些后选对,发现其相似度不足。

  • 选择某个k,并对每篇文档建立其k-shingle集合。将这些k-shingle映射成更短的桶编号(后一步可以选)

  • 将文档的shingle按照shingle排序

  • 选择最小哈希签名的长度n,将第二步中的排好序的表传递给算法来计算所有文档的最小哈希签名

  • 选择阈值t来定义应该达到的相似程度使之被看作使预期的相似对。选择行条数b和每个行条中的行数r,使得br=n,而阈值t近似等于(1/b)^{1/r} .如果要避免假阴性的产生,应改选则合适的b和r以产生小于t的阈值。而如果速度相当重要并且希望限制假阳性的数目,那么选择数和的b和r来获得更高的阈值。

  • 用LSH技术构建候选对

  • 检查每个候选对的签名,确定他们的一致性的比例是否大于t

  • 这步可选可不选,如果签名足够相似,则直接检查文档本身看他们是否是真的相似,不相似的文档有时后会碰巧会具有相似的签名。

posted @ 2020-09-02 16:48  wshf  阅读(333)  评论(1编辑  收藏  举报