Python tf-idf:更新 tf-idf 矩阵的快速方法

Python tf-idf: fast way to update the tf-idf matrix

我有一个包含几千行文本的数据集,我的目标是计算 tfidf 分数,然后计算文档之间的余弦相似度,这是我在 Python 中使用 gensim 所做的,遵循教程:

dictionary = corpora.Dictionary(dat)
corpus = [dictionary.doc2bow(text) for text in dat]

tfidf = models.TfidfModel(corpus)
corpus_tfidf = tfidf[corpus]
index = similarities.MatrixSimilarity(corpus_tfidf)

假设我们已经建立了 tfidf 矩阵和相似度,当我们有一个新文档进来时,我想在我们现有的数据集中查询它最相似的文档。

问题:有没有什么方法可以更新 tf-idf 矩阵,这样我就不必将新的文本文档附加到原始数据集并再次重新计算整个过程?

我将 post 我的解决方案,因为没有其他答案。假设我们处于以下场景:

import gensim
from gensim import models
from gensim import corpora
from gensim import similarities
from nltk.tokenize import word_tokenize
import pandas as pd

# routines:
text = "I work on natural language processing and I want to figure out how does gensim work"
text2 = "I love computer science and I code in Python"
dat = pd.Series([text,text2])
dat = dat.apply(lambda x: str(x).lower()) 
dat = dat.apply(lambda x: word_tokenize(x))


dictionary = corpora.Dictionary(dat)
corpus = [dictionary.doc2bow(doc) for doc in dat]
tfidf = models.TfidfModel(corpus)
corpus_tfidf = tfidf[corpus]


#Query:
query_text = "I love icecream and gensim"
query_text = query_text.lower()
query_text = word_tokenize(query_text)
vec_bow = dictionary.doc2bow(query_text)
vec_tfidf = tfidf[vec_bow]

如果我们看:

print(vec_bow)
[(0, 1), (7, 1), (12, 1), (15, 1)]

和:

print(tfidf[vec_bow])
[(12, 0.7071067811865475), (15, 0.7071067811865475)]

仅供参考 ID 和文档:

print(dictionary.items())

[(0, u'and'),
 (1, u'on'),
 (8, u'processing'),
 (3, u'natural'),
 (4, u'figure'),
 (5, u'language'),
 (9, u'how'),
 (7, u'i'),
 (14, u'code'),
 (19, u'in'),
 (2, u'work'),
 (16, u'python'),
 (6, u'to'),
 (10, u'does'),
 (11, u'want'),
 (17, u'science'),
 (15, u'love'),
 (18, u'computer'),
 (12, u'gensim'),
 (13, u'out')]

看起来查询只选择了现有的术语并使用预先计算的权重来为您提供 tfidf 分数。所以我的解决方法是每周或每天重建模型,因为这样做很快。

让我分享我的想法。

一个是语料库,另一个是模型,另一个是查询。我会说有时很容易混合它们。

1) 语料库和模型

语料库是一组文档,您的图书馆,其中每个文档都以特定格式表示。例如,Corpus_BOW 将您的文档表示为词袋。 Corpus_TFIDF 用 TFIDF 表示您的文档。

模型是将语料库表示转换为另一个的东西。比如Model_TFIDF变换Corpus_BOW --> Corpus_TFIDF。您可以有其他模型,例如 Corpus_TFIDF --> Corpus_LSI 或 Corpus_BOW --> Corpus_LSI.

的模型

我想说这是出色的 Gensim 的主要性质,成为 Corpus transformator。 objective 是为您的应用程序找到能更好地表示文档之间相似性的语料库表示。

几个重要的想法:

  • 首先,模型总是从条目语料库构建,例如:Model_TFIDF = models.TfidfModel(Corpus_BOW, id2word = yourDictionary)
  • 其次,如果您希望语料库采用 (Corpus_TFIDF) 格式,您 需要先构建模型 (Model_TFIDF) 然后转换你的入口语料库: Corpus_TFIDF = Model_TFIDF[Corpus_BOW].

所以,我们先用词条语料建立模型,然后把模型应用到同一个词条语料上,得到输出语料。也许可以加入一些步骤,但这些是概念性步骤。

2) 查询和更新

可以将给定的模型应用于新文档,得到新文档的TFIDF。例如,New_Corpus_TFIDF = Model_TFIDF[New_Corpus_BOW].但这只是查询。模型未使用新 corpus/documents 更新。也就是说,该模型是用原始语料库建模的,并按原样与新文档一起使用。

当新文档只是一个简短的用户查询并且我们想在我们的原始语料库中找到最相似的文档时,这很有用。或者当我们只有一个新文档并且我们想在我们的语料库中找到最相似的文档时。在这些情况下,如果您的语料库足够大,则不需要更新模型。

但是假设你的图书馆,你的语料库是有生命的。你想用新文档更新你的模型,就好像它们从一开始就是这样。只需提供新文档即可更新某些模型。例如 models.LsiModel 有“add_documents” 方法在你的 LSI 模型中包含新的语料库(所以如果你用 Corpus_BOW 构建它,你可以只更新给出 New_Corpus_BOW).

但是TFIDF模型没有这个“add_documents”方法。我不知道是否有复杂而聪明的数学方法来克服这个问题,但问题是 TFIDF 的“IDF”部分依赖于完整的语料库(以前的和新的)。因此,如果您添加一个新文档,那么之前每个文档的 IDF 都会发生变化。更新 TFIDF 模型的唯一方法是重新计算它。

无论如何,请考虑即使你可以更新一个模型,然后你需要再次将它应用到你的入口语料库以获得输出语料库,并重建相似性。

正如之前有人所说,如果您的库足够大,您可以使用原始 TFIDF 模型并按原样应用于新文档,而无需更新模型。可能结果已经足够好了。然后,有时,当新文档的数量很大时,您再次 re-build TFIDF 模型。