LSA(LSI)算法简介
前言
在信息检索领域常用的检索和索引算法有空间向量模型和隐语义模型。
传统向量空间模型
向量空间模型是信息检索领域最常用的检索方法,其检索过程是,将文档集D中的所有文档和查询都表示成以单词为特征的向量,特征值为每个单词的TF-IDF值,然后使用向量空间模型(即计算查询Q的向量和每个文档的之间的相似度)来衡量文档和查询之间的相似度,从而得到和给定查询最相关的文档。
缺点
向量空间模型简单的基于单词的出现与否以及TF-IDF等信息来检索,但是说了和写了哪些单词和真正要表达的意思之间有很大的区别,其中两个最主要的阻碍是单词的多义性(polysems)和同义性(synonymys)。多义性指的是一个单词可能有多个意思,比如苹果,既可以指的是水果苹果,也可以指的是苹果公司;而同义性指的是多个不同的词可能表示同样的意思,比如search和look up。同义词和多义词的存在使得单纯基于单词的检索方法(比如空间向量模型等)的检索准确度收到很大影响。
隐语义模型(latent semantic analysis-latent semantic indexing)
LSA潜在语义分析的目的,就是要找出在文档和查询中的真正含义,也就是潜在语义。我们希望找到一个模型,能够获取单词之间的相似性。如果两个单词之间有很强的相关性,那么当一个单词出现时,往往意味着另一个单词也应该出现(同义词);反之,如果查询语句或者文档中的某个单词和其他单词的相关性都不大,那么这个单词可能表达的就是另外一个意思(比如在讨论互联网的文章中,apple更可能指的是apple公司,而不是水果)。
LSA(LSI)使用SVD(奇异值分解)对单词文档矩阵进行分解。SVD可以看作是从单词-文档矩阵中发现部相关的索引变量(因子),将原来的数据映射到语义空间内。在单词-文档矩阵中不相似的两个文档,,可能在语义空间内比较相似。
SVD,是对矩阵进行分解的一种方法,假设是一个t*d维的矩阵(单词-文档矩阵)X,可以将其分解成T*S*DT ,其中T为t*n维矩阵,S为n*n维对角矩阵,每个值为奇异值,D为d*n维矩阵。在对单词文档矩阵做SVD分解之后,我们只保存s中最大的K个奇异值,以及T和D中对应的k个奇异向量,k个奇异值构成新的对角矩阵S',则
X'=T'*S'*D'T形成了一个新的t*d矩阵。
假设索引文档的集合如下:
A[ 1. 0. 0. 1. 1.]
[ 1. 0. 1. 0. 1.]
[ 0. 1. 0. 0. 0.]
对其进行分解后得到X=T*S*DT。其中T为:
[-0.71 -0.71 0. ]
[-0.71 0.71 0. ]
[ 0. 0. 1.]
S为:
[ 2.24 0. 0]
[0. 1. 0.]
[0. 0. 1.]
D为:
[-0.63 0. -0.32 -0.32 -0.63]
[ 0. 0. 0.71 -0.71 0. ]
[-0. 1. 0. 0. -0.]
[ 0.76 -0. -0.16 -0.16 -0.6 ]
[-0.12 0. 0.61 0.61 -0.49]
保留值最大的2个奇异值和其对应的奇异向量,得到的T’为
[-0.71 -0.71]
[-0.71 0.71]
[ 0. 0.]
S'为
[ 2.24 0. ]
[ 0. 1. ]
D’为:
[-0.63 0. -0.32 -0.32 -0.63]
[ 0. 0. 0.71 -0.71 0. ]
得到的新矩阵X'为:
[ 1. 0. -0. 1. 1.]
[ 1. 0. 1. 0. 1.]
[ 0. 0. 0. 0. 0.]
还原后的X’和X差别很大,这是因为我们认为之前X存在很大的噪音,X'是处理过同义词和多义词的结果。
在查询时,对于给定的一个查询,我们根据这个查询中包含的单词构造一个伪文档,然后该伪文档和D’中的每一行计算相似度(余弦相似度)来给定与查询最相似的文档。
详细python代码如下:
1 import string 2 import types 3 from numpy import * 4 from numpy.linalg import svd 5 def main(): 6 A=array([ 7 [1.,0.,0.,1.,1.], 8 [1.,0.,1.,0.,1.], 9 [0.,1.,0.,0.,0.] 10 ]) 11 print 'A',A 12 T,S,D=svd(A) 13 print 'T',T 14 print 'S',S 15 print 'D',D 16 print 'T' 17 for x in T: 18 print around(x,decimals=2) 19 print 'S' 20 for x in S: 21 print around(x,decimals=2) 22 print 'D' 23 for x in D: 24 print around(x,decimals=2) 25 print '*'*100 26 k=2 27 S1=zeros(shape=(k,k)) 28 S1[:k,:k]=diag(S[:k]) 29 T=delete(T,s_[k:],axis=1) 30 D=delete(D,s_[k:],axis=0) 31 print 'T' 32 for x in T: 33 print around(x,decimals=2) 34 print 'S1',S1 35 print 'D' 36 for x in D: 37 print around(x,decimals=2) 38 B=dot(T,dot(S1,D)) 39 print 'B',B 40 for x in B: 41 print around(x,decimals=2) 42 if __name__=='__main__': 43 43 main()
参考文献:
[1] Indexing by Latent Semantic Analysis.Scott Deerwester, Susan T. Dumais, George W.Furnas, Thomas K.Landauer, Richard Harshman.
[2] Latent Semantic Analysis Note.Zhou Li
[3] 推荐系统实践.项亮
友情参考:http://www.cnblogs.com/kemaswill/archive/2013/04/17/3022100.html