一个基本的数据挖掘问题是从数据中获得“相似项”。应用在检测抄袭网页,抄袭文档(也可以通过关联分析算法来检测),检查是否是镜像网页。
首先,需要将相似度问题表述为寻找具有相对较大交集的集合问题(Jaccard)。扩展可以需要采用其他的距离测度:来具体定量相似项的相似度。包括欧式距离、Jaccard距离、余弦距离、编辑距离、海明距离。
如果是文本的相似问题,我们转换为集合问题并且通过著名的“shinging”技术来解决。然后通过最小哈希(minhashing)来对大集合进行压缩,然后基于压缩后的结果推导原始集合相似度。当相似度要求很高时,可以使用面向高相似度的方法:
基于长度的过滤
前缀索引
使用位置和长度信息的索引
通过局部敏感哈希(Locality Sensitive Hashing LSH)技术来把搜索范围集中在那些可能的相似项对上面。因为即使每项之间的相似度计算非常简单,但是由于项对数目过多,无法对所有的项对检测相似度。
衡量文本相似度的几种手段:
(1)最长公共子串(基于词条空间)
(2)最长公共子序列(基于权值空间、词条空间)
(3)最少编辑距离法(基于词条空间)
(4)汉明距离(基于权值空间)
(5)余弦值(基于权值空间)
集合S和T的相似度 SIM(S,T) = |S∩T|/|S∪T/,这是字面上的相似,意义相似度计算也是个非常有趣的问题,但是需要通过其他技术来解决。
应用:计算文档相似度,包括抄袭文档、镜像页面、同源新闻稿。
另一个非常重要的应用是协同过滤(collaborative filtering),在协同过滤系统中,系统会向用户推荐相似兴趣用户所喜欢的项,应用在推荐系统中。但是协同过滤除了相似顾客或商品的发现之外,还需要一些其他的工具。例如,两个喜欢科幻小说的Amazon顾客可能各自从网站购买了很多的科幻小说,但是他们之间的交集很小。然而,通过将相似度发现和聚类技术融合,就可以发现科幻小说之间相互类似而将他们归为一类。这样,通过询问他们是否在多个相同类下购买了商品,我们就能得到一个更强的顾客相似度概念。
一篇文档为一个字符串,k-shining定义为其中任意长度为k的字串。
例如文档D为abcdabd,当k=2,所有的2-shining组成的集合为{ab,bc,cd,da,ab,bd}, 设字符为n, 则集合最多有n+1-k个。由于重复的字串在集合中只算1次。扩展包括基于包的表示,对空白串的处理。
k的选择依赖于文档的典型长度以及典型的字符表大小。k应该选择的足够大,以保证任意给定的shining出现在任意文档中的概率较低。
邮件的的k=5.因为所有的5-shining个数为27^5= 14348907。而典型的邮件长度会远远低于1400万字。由于在邮件中有的字符船舷的概率明显会比其他的高。所以把邮件想象为只由20个不同的字符构成。
对于研究论文的大文档来说,选择k=9则比较安全。
将每个k-shining通过某个哈希函数映射为桶编号。如9-shining映射为0-2^32-1之间的桶编号。将数据从9字节压缩到4个字节。使用的空间与4-shining一样,但是却具有更高的数据区分能力。但是20^9次方比2^32大很多。
对于新闻内容及散文包含大量的停用词,平时我们很可能会忽略这些词,因为他们没有任何作用。如"and","to","you"等。但是对于新闻报道的近似重复检测,我们将shining定义为一个停用词加上后续的两个词(不再对词进行区分)。这样如过两个包含新闻的网页,如果得到高jaccard相似度,那么可以推断他们的新闻内容相同即使他的周边材料会不同。
即使采用哈希表示,每9个字节的k-shinging数目在一篇有n字符的文档中会有m = n+1-9 ≈ n个k-shining字符串,如果采用哈希函数,仍然需要大概4*n的空间,是该文档所需空间的4倍。这一节的目标是对集合进行压缩,将上述的大集合替换成规模小很多的“签名”(signature)表示。尽管通过签名无法得到原始shining集合之间的Jaccard相似度的精确值,但是估计结果与真实结果相差不大。签名集合越大,估计的精度也越高。
矩阵的列对应集合,行对应于全集。如果行r对应的元素属于列C对应的集合,那么矩阵的第r行第c列的元素为1,否则为0。
例如全集{a,b,c,d,e}中元素组成的几个S1={a,d},S2={c},S3={b,d,e},S4={a,c,d}
元素 |
S1 |
S2 |
S3 |
S4 |
a |
1 |
0 |
0 |
1 |
b |
0 |
0 |
1 |
0 |
c |
0 |
1 |
0 |
1 |
d |
1 |
0 |
1 |
1 |
e |
0 |
0 |
1 |
0 |
特征矩阵并不是数据真正的存储方式,只是作为一种数据可视化的方式。因为对于稀疏矩阵0远远多于1的个数,所以把数据转换为元组的方式只存储1的位置可以大大的节省存储的开销。
实际中,行可以是商品,列可以是顾客,那么每个顾客表示成其购买的商品的集合,这样可以发现不同顾客购买的商品的相似性。
集合的签名是由大量的计算结果构成,每次计算是特征矩阵的最小哈希过程。
集合(特征矩阵)的最小哈希计算过程为:首先选择行的一个排列转换,任意一列的最小哈希值是在转换后的行排列次序下第一个列值为1的行的行号。
例如上面特征举证的最小哈希为:
将abcde排列转换为beadc, 这个排列转换定义了一个最小哈希函数h,他将某个集合映射成一行。接下来基于函数h即排列转换来计算列元素集合S的最小哈希值。
元素 |
S1 |
S2 |
S3 |
S4 |
b |
0 |
0 |
1 |
0 |
e |
0 |
0 |
1 |
0 |
a |
1 |
0 |
0 |
1 |
d |
1 |
0 |
1 |
1 |
c |
0 |
1 |
0 |
1 |
我们有h(S1)=a,h(S2)=c,h(S3)=b,h(S4)=a。
实际中我们并不需要对一个很大的矩阵去进行重排。最小哈希函数可以隐式的表示为一个集合全集元素的随机排列rand(abced),然后按照随机排列的顺序依次扫描S对应的元素是否为1.
SIG a c, b, a
具体代码操作为:
for r=1:R (matrix总共有RXM行,SIG=1XM,从1到R行依次扫描,如果某列m的值为1,那么前面矩阵该列的值换成h(r), 如扫描第一行,S3列为1,前面的值为b,然后检测 。第 二 行,S3列的值为1,但是e却大于b,不改变)
for m=1:M
{
if(matrix(r,m) ==1)
new SIG(m)=h(r)
if(new Sig(m)< old Sig(m))
SIG(m)= new Sig(m)
}
即:两个集合经随机转换之后得到的两个最小哈希值相等的概率等于这两个集合的Jaccard相似度。
(1)X类的行,两列的值都为1
(2)Y类的行,其中一个为1一个为0
(3)Z类的行,两列都为0.
所以SIM(S1,S2) = S1∩S2/S1∪S2。=x/x+y。
现在考虑h(S1)=h(S2)的概率。经过排列转换,将第一行的值固定h(S1)下来,如果要相等的概率是在第二列首先碰到的是X类的概率为X/X+Y。
那么P(h(S1)=h(S2))=x/x+y.
最后由向量[h1(S),h2(S),...,hn(S)],通常该向量写成列向量的形式,由于S是一个具有列的行向量,所以是NXM的矩阵。
由于所需的行数是n,n通常在一百或者几百,比k-shining的可能组合少很多,所以能够极大的压缩特征矩阵。
具体的计算如下:
通过一个随机哈希函数来模拟随机排列转换的效果,该函数将行号映射为与行数目大致相等数量的桶中。尽管哈希冲突可能会不可避免的存在,但是只要0,1,2,...,k-1中k很大且哈希冲突不太频繁的话,差异就不是很重要。所以r经过排列转换放在第hj(r)行。即以前的r索引变成现在的h(r)索引。
所以SIG(i,c)开始都初始化为无穷
for r=1:R(matrix = RXM, h=1XN,SIG=NXM)
for m=1:M
{
//新增
for n=1:N
if(matrix(r,m) ==1)
new SIG(n,m)=hn(r)
if(new Sig(m)< old Sig(n,m))
SIG(n,m)= new Sig(n,m)
}