【问题标题】:Python tf-idf: fast way to update the tf-idf matrixPython tf-idf:更新 tf-idf 矩阵的快速方法
【发布时间】:2017-07-01 22:22:45
【问题描述】:

我有一个几千行文本的数据集,我的目标是计算 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 矩阵,这样我就不必将新的文本文档附加到原始数据集并重新计算整个事情?

【问题讨论】:

    标签: python nlp tf-idf gensim cosine-similarity


    【解决方案1】:

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

    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 分数。所以我的解决方法是每周或每天重建模型,因为这样做很快。

    【讨论】:

    • 这真的有效吗?我会认为,由于 tfidf 的性质,基本上你不能增量更新模型(更新 tfidf 矩阵),因为每次有新文档进来时,你都必须更新包含在整个语料库中的新文档。此外,当文档出现新词时会发生什么 - 你不会有特征长度不匹配吗?请告诉我,因为我也在积极研究这个问题
    • 它正在工作,但我相信它所做的只是使用您现有的模型查询您的新文档。我将编辑我的答案以展示作品。
    • 哇!这真的很酷 - 非常感谢分享这个。所以如果我理解正确的话,当一个新的查询文档进来时,gensim 会根据预先计算的 tfidf 矩阵 新的查询文档来计算 tfidf 分数吗?还是仅从预先计算的 tfidf 矩阵中计算出来?如果不断有新的查询进来,定期更新模型更有意义,特别是如果更新模型的成本很高
    • 还没有查看源代码,但是由于实际查询只发生在tfidf[vec_bow]这行代码中,我认为它只查询预先计算的tfidf矩阵而不更新任何内容。所以是的,你是对的,定期更新可以弥补更新部分。
    • 我最近也有类似的问题。谢谢。我对如何增量更新矩阵感到很困惑。
    【解决方案2】:

    让我分享一下我的想法。

    一个是Corpus,另一个是Model,另一个是Query。我会说有时很容易将它们混合在一起。

    1) 语料库和模型

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

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

    我会说这是出色的 Gensim 的主要本质,成为一个 Corpus 转换器。目标是找到能够更好地代表您的应用程序文档之间相似性的语料库表示。

    几个重要的想法:

    • 首先,模型总是从词条Corpus构建,例如: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]。但这只是查询。模型未使用新的语料库/文档进行更新。也就是说,模型是使用原始语料库建模的,并且可以与新文档一起使用。

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

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

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

    在任何情况下,请考虑即使您可以更新模型,您也需要再次将其应用到您的条目语料库以获得输出语料库,并重建相似性。

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

    【讨论】:

    • 从概念上讲,IDF 部分可以在没有完整语料库的情况下进行更新,只要您知道文档总数即可。例如,如果一个词对 10 个文档的文档频率为 0.5(为简单起见,省略了对数缩放和逆向),添加一个没有该词的文档会将文档频率降低到 0.45(11 个文档中有 5 个),不需要自己有实际的文件。
    猜你喜欢
    • 2017-06-19
    • 1970-01-01
    • 2020-05-11
    • 2018-08-22
    • 2016-02-03
    • 2015-05-07
    • 2016-05-08
    • 2014-07-22
    • 1970-01-01
    相关资源
    最近更新 更多