矩阵A选取其中特征值较大的r个并排序,这样USVT就可以近似表示矩阵A。
对于矩阵U,每一列代表一个潜语义,这个潜语义的意义由m个单词按不同权重组合而成。因为U中每一列相互独立,所以r个潜语义构成了一个语义空间。
S中每一个奇异值指示了该潜语义的重要度。
VT中每一列仍然是一篇文档,但此时文档被映射了语义空间。其大小远小于A。
有了VT,我们就相当于有了矩阵A的另外一种表示,之后我们就可以使用VT代替A进行之后的工作。
(1)分析文档集合,建立词汇-文本矩阵A。
(2)对词汇-文本矩阵进行奇异值分解。
(3)对SVD分解后的矩阵进行降维
(4)使用降维后的矩阵构建潜在语义空间
1 获得用户输入的检索语句query 对应的列向量Xq,
其中该列代表文档集合的索引词,该列的值代表伪文本中该索引词出现的次数。
比如一个文档集合有索引词{T1,T2,T3},输入query为t1,t3,t2,t1,则Xq={2,1,1}。获得Xq后,通过公式
2 计算对应的query的表示
Dq = XqUT S-1计算文档坐标。
其中U和S分别代表奇异分解中得到的矩阵(X = USVT).
3 Dq计算出来后,就可以迭代比较Dq和文档集合中所有文档,计算两者个cosine夹角
可以将查询的关键词字符串看着一个document,后面称为查询文档,同样可以将其转换为了Term-Document矩阵,不过对此有两种方案可以选择。
方案一:根据邮件样本训练出的Term-Document矩阵,将查询文档映射成其中一列,然后利用奇异值分解的方程,计算得到其潜在因子的数值,再利用相似度算法,找出前十个最相似的邮件。
方案二:简单处理得到查询文档的Term-Document矩阵,然后根据查询文档中Term在u中找到对应的潜在因子,根据Term和Document的潜在因子的相似度进行加权,找到前十个最相似的邮件。
1)低维空间表示可以刻画同义词,同义词会对应着相同或相似的主题。
2)降维可去除部分噪声,是特征更鲁棒。
3)充分利用冗余数据。
4)无监督/完全自动化。
5)与语言无关。
1)LSA可以处理向量空间模型无法解决的一义多词(synonymy)问题,但不能解决一词多义(polysemy)问题。因为LSA将每一个词映射为潜在语义空间中的一个点,也就是说一个词的多个意思在空间中对于的是同一个点,并没有被区分。
2)SVD的优化目标基于L-2 norm 或者 Frobenius Norm 的,这相当于隐含了对数据的高斯分布假设。而 term 出现的次数是非负的,这明显不符合 Gaussian 假设,而更接近 Multi-nomial分布。(需要进一步研究为什么)
3)特征向量的方向没有对应的物理解释。
4)SVD的计算复杂度很高,而且当有新的文档来到时,若要更新模型需重新训练。
5)没有刻画term出现次数的概率模型。
6)对于count vectors 而言,欧式距离表达是不合适的(重建时会产生负数)。
7)维数的选择是ad-hoc(点对点)的。
8)LSA具有词袋模型的缺点,即在一篇文章,或者一个句子中忽略词语的先后顺序。
9)LSA的概率模型假设文档和词的分布是服从联合正态分布的,但从观测数据来看是服从泊松分布的。因此LSA算法的一个改进PLSA使用了多项分布,其效果要好于LSA。
>SVD分解
表示我们将文档映射到了一个3维语义空间中,其中第一维潜语义可以表示为
每一个红色的点,都表示一个词
每一个蓝色的点,都表示一个主题
这样我们可以对这些词和主题进行聚类,比如stock和market可以放在一类,这也符合他们经常出现在一起的直觉,real和estate可以放在一类,dads,guide这种词就看起来有点孤立了,我们就不对他们进行合并了。
对于title,T1和T3可以聚成一类,T2、T4、T5和T8可以聚成一类,所以T1和T3比较相似,T2、T4、T5和T8比较相似。
按这样聚类出现的效果,可以提取文档集合中的近义词,这样当用户检索文档的时候,是用语义级别(近义词集合)去检索了,而不是之前的词的级别。这样一减少我们的检索、存储量,因为这样压缩的文档集合和PCA是异曲同工的,二可以提高我们的用户体验,用户输入一个词,我们可以在这个词的近义词的集合中去找,这是传统的索引无法做到的。
gensim
class gensim.models.lsimodel.LsiModel(corpus=None, num_topics=200, id2word=None, chunksize=20000, decay=1.0, distributed=False, onepass=True, power_iters=2, extra_samples=100, dtype=
)
关键参数:
corpus:文本语料
num_topic:保留的语义维数
id2word:ID到单词映射
该对象包括如下方法:
LsiModel.projection.u,获得左奇异向量;
LsiModel.projection.s,获得奇异值;
add_documents(),用新的语料更新模型;
get_topics(),获取所有潜语义的向量表示;
save(),保存模型到本地;
load(),从本地加载模型;
print_topic(topicno, topn=10),以string的形式输出第topicno个潜在语义的前topn个单词表示;
print_topics(num_topics=20, num_words=10),以string形式输出前num_topics个潜在语义,每个语义用num_words个单词表示;
show_topic(topicno, topn=10),获取定义第topicno个潜在语义的单词及其贡献;
from gensim.test.utils import common_corpus,common_dictionary,get_tmpfile
from gensim.models import LsiModel
#构建模型
print(common_corpus)
'''
#[[(0, 1), (1, 1), (2, 1)], [(0, 1), (3, 1), (4, 1), (5, 1), (6, 1), (7, 1)], [(2, 1), (5, 1),......
输出的为bag-of-word后的元组,(id,count)
#语料为:common_texts = [
['human', 'interface', 'computer'],
['survey', 'user', 'computer', 'system', 'response', 'time'],
['eps', 'user', 'interface', 'system'],
['system', 'human', 'system', 'eps'],
['user', 'response', 'time'],
['trees'],
['graph', 'trees'],
['graph', 'minors', 'trees'],
['graph', 'minors', 'survey']
]
'''
model = LsiModel(common_corpus[:3],id2word=common_dictionary,num_topics=3)
#将文档映射到语义空间
vector = model[common_corpus[4]]
#更新模型
model.add_documents(common_corpus[4:])
tmp_fname = get_tmpfile("lsi.model")
model.save(tmp_fname) # save model
loaded_model = LsiModel.load(tmp_fname) # load model
umatri = loaded_model.projection.u
print(umatri)
print(umatri.shape)
ss = umatri = loaded_model.projection.s
print(ss)
allt = loaded_model.get_topics()
print(allt)
t1 = loaded_model.print_topic(1,topn=12)
print(t1)
s1 = loaded_model.show_topic(1,topn=12)
print(s1)
参考:
https://blog.csdn.net/pipisorry/article/details/42560331
https://blog.csdn.net/jiayalu/article/details/100533184