LSI计算文档相似度的过程以及gensim源码走读

2016年11月11日 19168点热度 2人点赞 1条评论
0. TL;DR

本文前半段主要参考:http://www.ce.yildiz.edu.tr/personal/banud/file/1201/latent-semantic-indexing-fast-track-tutorial.pdf

这里只介绍过程,不介绍原理,只做简单分析。

后半段将过一下gensim的simserver是如何调用LSI找到相似文档的。

本文为原创,转载需要注明出处:
http://www.flyml.net/2016/11/11/lsi-doc-sim-gensim-source-code-go-throught/

 

1.一个简单的语料库

Q: gold silver truck

d1: Shipment of gold damaged in a fire.

d2: Delivery of silver arrived in a silver truck.

d3: Shipment of gold arrived in a truck.

需要解决的问题:Q与哪个文档最接近?

补充说明:

可以使用TFIDF、字符编辑距离等计算文档相似性。具体方法可以参考:

http://chato.cl/2015/data_analysis/01_vector-space-model/vector-space-model.pdf

原文链接:http://www.flyml.net/2016/11/11/lsi-doc-sim-gensim-source-code-go-throught/

2.Term Count Model 矩阵

这种模型比较简单,从TFIDF的角度来说,就是TF了。常见的就是下面这种形式:
word_i 为行,d_j 为一列

 

3.使用SVD进行矩阵分解

公式:

计算结果:

注意:矩阵S是一个对角矩阵,并且是按照大小进行了排序

各个矩阵的大小是有讲究的:(下面的仅供参考)

4.开始降维(可选)

如果我们的机器能扛得住原始维度,就不需要下降了。 降维的作用是在精度损失可接受的程度下去掉相对无关的词(并且这些词可能很多很多),从而达到降低资源开销。

假设将维度从3降到2:

计算过程:对于U:取前2列,S:前2x2,V:前2列, VT:前2行

下面的图显示了矩阵是如何被剪裁下来的:

 

From:https://blog-potatolife.rhcloud.com/?p=132

 

补充说明:SVD的几何/物理意义?

https://www.zhihu.com/question/22237507
http://blog.sciencenet.cn/blog-696950-699432.html

5. 在(降维的)矩阵之中计算查询语句矩阵(q)

公式:

实现:

注意:

  • S-1 为S的逆矩阵
  • 这一步的q与第一步的q矩阵已经不一样了(不太理解为什么用相同的变量名)
6. 使用余弦相似度计算文档相关性

经过前面的铺垫,终于到我们的目的地了:计算文档相似度

 

以sim(q,d1)为例,-0.4945与0.6492来自VTk第一列.

在图上画出各个向量,直观比较:

注意: 余弦向量是只看夹角不看长度

原文链接:http://www.flyml.net/2016/11/11/lsi-doc-sim-gensim-source-code-go-throught/

 

7. 可以进行的一些优化工作:
  • 可以尝试将停用词去掉之后再重复进行计算
  • 去停用词 + 使用TF-IDF 作为矩阵A的值

 

8. Gensimsimserver 是如何实现LSI的?

官网地址:http://radimrehurek.com/gensim/simserver.html

  1. 安装
    pip install simserver
  2. 使用
  3. 实现细节:

    可以看到,gensim之中矩阵A已经是TFIDF值了
    LSI_TOPICS 已经被hardcode成400了
  4. LsiModel的参数

    上面是LsiModel的构造函数解释一下几个参数的意义:

    • chunksize: 每次训练多少文档。如果内存不足,可以将chunksize减少,但是消耗的时间更多。
    • decay: 如果我们需要忘记老的数据,decay < 1.0
    • distributed: 大概是分布式计算。如果启用了,会通过Pyro4进行远程调用~
    • onepass: 目前只能是True,False还没有实现,会直接抛出异常
    • power_iters: 计算次数。可能进行矩阵分解(SVD),是一个逐步接近的过程,而不是一步到位。计算次数越多,分解出来的矩阵与原始矩阵越接近。
    • extra_samples: 目的与power_iters相同(从gensim的解释),原理未知
    • 他们的mathutils是基于scipy,自己封装了操作。 具体不表~
    • 比较有意思的是:k+30,后面的注释是说:这个函数经常会出bug,本来应该返回x列,但是最后会少返回几列~ 于是统统+30,简单粗暴的workaround
    • 重要:可以看到k经过了clip_spectrum()之后,数值发生了变化。这个函数主要是看矩阵s然后丢弃掉1%的数据(spectrum, 范围、光谱)
      最后两行就是做了降维操作。看看gensim是如何SVD的
      我们从304行的Projection进去看看
      核心步骤:

     

本文为原创文章,转载请注明出处
原文链接:http://www.flyml.net/2016/11/11/lsi-doc-sim-gensim-source-code-go-throught/

 

RangerWolf

保持饥渴的专注,追求最佳的品质

文章评论