系列目录:
————————————————————————————
本文主要介绍如何从一个语料库中,查询一个指定文本的相似文本。
1、创建语料
创建语料和之前的三节相似,代码如下:
from collections import defaultdict
from gensim import corpora
documents = [
"Human machine interface for lab abc computer applications",
"A survey of user opinion of computer system response time",
"The EPS user interface management system",
"System and human system engineering testing of EPS",
"Relation of user perceived response time to error measurement",
"The generation of random binary unordered trees",
"The intersection graph of paths in trees",
"Graph minors IV Widths of trees and well quasi ordering",
"Graph minors A survey",
]
# remove common words and tokenize
stoplist = set('for a of the and to in'.split())
texts = [
[word for word in document.lower().split() if word not in stoplist]
for document in documents
]
# remove words that appear only once
frequency = defaultdict(int)
for text in texts:
for token in text:
frequency[token] += 1
texts = [
[token for token in text if frequency[token] > 1]
for text in texts
]
dictionary = corpora.Dictionary(texts)
corpus = [dictionary.doc2bow(text) for text in texts]
2、相似度接口
在02-Gensim系列之二:语料和向量空间和03-Gensim系列之三:主题和变换 中,介绍如何创建向量空间的语料,以及如何在不同的向量空间的转换。这是查询文档之间相似性的基础。
接下来通过上述的语料来说明如何实现相似度查询,以LSI模型为例:
from gensim import models
lsi = models.LsiModel(corpus, id2word=dictionary, num_topics=2)
在本示例中,不对LSI模型作详细解释,只对两点加以说明:(1)LSI为一个向量变换模型,它将文本从一个向量空间转换到另外一个向量空间。(2)LSI可以识别文本的模式和文本中单词之间的关系和主题。下面的LSI是一个2维向量空间,即包含2个主题,但是主题的数量是可以任意设置的。更多关于LSI模型的介绍可以参考:Latent Semantic Indexing:
现在,假设有一个用户输入一个查询 "Human computer interaction",则根据和查询的相似度,对原始语料中的9个文本进行排序。不像现在的搜索引擎,这里的相似度搜索仅仅为文本在概率上的相似性——没有语义上的、没有超链接等。
doc = "Human computer interaction"
vec_bow = dictionary.doc2bow(doc.lower().split())
vec_lsi = lsi[vec_bow] # 将查询文本转换到LSI模型的向量空间
print(vec_lsi)
# 输出
"""
[(0, 0.4618210045327158), (1, 0.07002766527900064)]
"""
另外,我们将考虑使用余弦距离来计算两个向量之间的相似度。余弦相似度是计算向量举例的一种常用方法,但是在向量表示概率分布的时候,使用 different similarity measures可能是更好的选择。
3、初始化查询结构
为了准备后续的查询,我们需要对用于查询的语料进行处理。在本样例中,9个文本均用于LSI模型的训练,此处将它们都转换到2-D的LSA向量空间。当然我们也可以用训练好的模型,将非训练集的样本进行转换。
from gensim import similarities
index = similarities.MatrixSimilarity(lsi[corpus]) # 将语料转换到LSI空间并建立索引
值得注意的是,similarities.MatrixSimilarity 类将把所有的向量导入内存,举例来说,一个100万规模的语料如果转换为256维的向量可能需要2GB的内存。如果不想消耗这么大的内存,可以使用 similarities.Similarity 类,这种方法只占用固定的内存(较小的内存),通过将语料文件切分成多个部分。这个类的内部使用 similarities.MatrixSimilarity
和 similarities.SparseMatrixSimilarity,所以这个方法仍然很快,但是稍微复杂一点。
建立的索引可以通过 save() 和 load() 两个方法进行保存和加载。
index.save("lsi_index.index")
index=similarities.MatrixSimilarity。load("lsi_index.index")
上述的保存和加载方法对所有的索引类都有效(包括similarities.Similarity,
similarities.MatrixSimilarity
和 similarities.SparseMatrixSimilarity
)。如果出现异常,可以尝试使用 similarities.Similarity,它的兼容性最好,且支持增量索引。
4、进行查询
在将查询转换到LSI空间,且将原始语料转换到LSI空间并建立索引之后,就可以获取查询文本和语料中文本的相似度了,代码如下:
sims = index[vec_lsi] # 获取查询文本和语料中文本的相似度
print(list(enumerate(sims))) # 打印 (文本序号, 文本相似度) 2元元组
#输出
"""
[(0, 0.998093), (1, 0.93748635), (2, 0.9984453), (3, 0.9865886), (4, 0.90755945), (5, -0.12416792), (6, -0.10639259), (7, -0.09879464), (8, 0.050041765)]
"""
由于余弦举例在(-1,1)之间,因此查询文本和语料中的第一个文本的相似度得分为 0.99809301,对语料中的文本根据相似度进行排序:
sims = sorted(enumerate(sims), key=lambda item: -item[1])
for i, s in enumerate(sims):
print(s, documents[i])
# 输出
"""
(2, 0.9984453) Human machine interface for lab abc computer applications
(0, 0.998093) A survey of user opinion of computer system response time
(3, 0.9865886) The EPS user interface management system
(1, 0.93748635) System and human system engineering testing of EPS
(4, 0.90755945) Relation of user perceived response time to error measurement
(8, 0.050041765) The generation of random binary unordered trees
(7, -0.09879464) The intersection graph of paths in trees
(6, -0.10639259) Graph minors IV Widths of trees and well quasi ordering
(5, -0.12416792) Graph minors A survey
"""
值得注意的是,假如采用标准的全文搜索的话,第3个文档 "The EPS user interface management system" 和第4个文档”Relation of user perceived response time to error measurement“ 将不会返回,因为他们和查询文本"Human computer interaction"没有 任何相同的关键词,但是在使用了LSI之后,这两个文本和查询文本的相似度都非常高,这也比较符合我们的直觉。事实上,这也是我们为什么要采用主题模型并进行变换的原因。
翻译和编辑自:Similarity Queries