【问题标题】:How is the TFIDFVectorizer in scikit-learn supposed to work?scikit-learn 中的 TFIDFVectorizer 应该如何工作?
【发布时间】:2016-08-16 11:42:23
【问题描述】:

我正在尝试使用 scikit-learn 中的 TfIDFVectorizer 类来获取与某些文档不同的单词。它创建了一个 tfidf 矩阵,其中包含所有文档中的所有单词及其分数,但它似乎也计算了常见单词。这是我正在运行的一些代码:

vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform(contents)
feature_names = vectorizer.get_feature_names()
dense = tfidf_matrix.todense()
denselist = dense.tolist()
df = pd.DataFrame(denselist, columns=feature_names, index=characters)
s = pd.Series(df.loc['Adam'])
s[s > 0].sort_values(ascending=False)[:10]

我希望这会返回文档“Adam”的独特单词列表,但它的作用是返回常用单词列表:

and     0.497077
to      0.387147
the     0.316648
of      0.298724
in      0.186404
with    0.144583
his     0.140998

我可能不完全理解它,但据我了解,tf-idf 应该在语料库中查找与一个文档不同的单词,查找在一个文档中频繁出现但在其他文档中不出现的单词。这里,and 经常出现在其他文档中,所以我不知道为什么它在这里返回了很高的值。

我用来生成它的完整代码是in this Jupyter notebook

当我半手动计算 tf/idfs 时,使用 NLTK 并计算每个单词的分数,我得到了适当的结果。对于“亚当”文档:

fresh        0.000813
prime        0.000813
bone         0.000677
relate       0.000677
blame        0.000677
enough       0.000677

这看起来是对的,因为这些词出现在“亚当”文档中,但在语料库的其他文档中没有那么多。用于生成它的完整代码在this Jupyter notebook 中。

我的 scikit 代码有问题吗?有没有另一种方法来初始化这个类,它返回正确的结果?当然,我可以通过stop_words = 'english' 忽略停用词,但这并不能真正解决问题,因为任何类型的常用词在这里都不应该有高分。

【问题讨论】:

    标签: python nlp scikit-learn


    【解决方案1】:

    来自 scikit-learn 文档:

    由于 tf–idf 经常用于文本特征,还有另一个名为 TfidfVectorizer 的类将 CountVectorizer 和 TfidfTransformer 的所有选项组合在一个模型中。

    如您所见,TfidfVectorizerCountVectorizer 后跟 TfidfTransformer

    您可能正在寻找的是TfidfTransformer 而不是TfidfVectorizer

    【讨论】:

    • TfidfTransformer 会转换 CountVectorizer 的输出,所以我可以先运行 CountVectorizer,然后再运行 TfidfTransformer,但这和运行 TfidfVectorizer 是一样的。所以我不相信我需要 TfidfTransformer,如果我必须首先运行 CountVectorizer。它不会返回相同的结果吗?
    【解决方案2】:

    我相信您的问题在于使用不同的停用词列表。 Scikit-learn 和 NLTK 默认使用不同的停用词列表。对于 scikit-learn,将自定义 stop_words 列表传递给 TfidfVectorizer 通常是个好主意,例如:

    my_stopword_list = ['and','to','the','of']
    my_vectorizer = TfidfVectorizer(stop_words=my_stopword_list)
    

    TfidfVectorizer 类的文档页面:[http://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html][1]

    【讨论】:

    • 很高兴知道这一点,但我想我对为什么需要删除停用词一开始感到困惑。如果'and'或'the'在所有文档中频繁出现,比方说,那为什么它会有很高的tf-idf值呢?在我看来,tf-idf 的目的是针对所有文档中的术语频率进行调整,以便在整个语料库中频繁出现的术语不会出现在列表的顶部。
    • @Jono,我猜你的直觉是 TFIDF 应该有利于稀有术语。这是对的一半。 TFIDF 主要考虑两个方面:TF 是文档中的词频,IDF 是整个文档集的逆词频。 TF 有利于高频词,而 IDF 有利于罕见词。这两个几乎是相反的度量,这使得 TFIDF 成为一个平衡的指标。
    • 此外,在使用向量空间表示时,去除停用词是一种非常常见的做法。我们可以这样推断:对于大多数应用程序,您希望有一个指标对于重要的术语来说是高的,而对于不重要的术语来说是低/零的。如果您的表示(在这种情况下为 TFIDF)未能做到这一点,您可以通过删除一个没有帮助并且可能会损害您的模型的术语来解决这个问题。
    【解决方案3】:

    我不确定为什么它不是默认值,但您可能希望在 TfidfVectorizer 的初始化中使用 sublinear_tf=True。我分叉了你的 repo 并向你发送了一个 PR,其中包含一个可能看起来更像你想要的示例。

    【讨论】:

    • 太棒了。这是一个很大的进步。但是,如果您使用较小的字符集而不是所有字符运行它,您会再次获得常用词列表:github.com/JonathanReeve/milton-analysis/blob/v0.2/…“And”、“to”、“the”和“of”是词Adam 和 Eve 的 tf-idf 最高,但这些词在语料库中经常出现,所以我不知道他们为什么在这里获得高 tf-idf 分数。
    • 因为您现在使用的文档要少得多。因此,随着术语在文档中出现次数的增加(即,每个文档计数),IDF 不会变得非常大,只有四个文档(
    • @Jono,我怎么会通过运行相同的代码得到不同的结果。唯一的代码区别是“vectorizer = TfidfVectorizer(sublinear_tf=True, stop_words='english')”,然后我似乎得到了很多合理的亚当输出:维持 0.045090 骨骼 0.045090 0.044417 0.043673 及时 0.043269 0.042731 素数 0.041628 缺席 0.0 0.041234 感觉 0.040259
    【解决方案4】:

    使用下面的代码我得到了更好的结果

    vectorizer = TfidfVectorizer(sublinear_tf=True, stop_words='english')
    

    输出

    sustain    0.045090
    bone       0.045090
    thou       0.044417
    thee       0.043673
    timely     0.043269
    thy        0.042731
    prime      0.041628
    absence    0.041234
    rib        0.041234
    feel       0.040259
    Name: Adam, dtype: float64
    

    thee          0.071188
    thy           0.070549
    forbids       0.069358
    thou          0.068068
    early         0.064642
    earliest      0.062229
    dreamed       0.062229
    firmness      0.062229
    glistering    0.062229
    sweet         0.060770
    Name: Eve, dtype: float64
    

    【讨论】:

      【解决方案5】:

      您的问题的答案可能在于您的语料库的大小和不同实现的源代码。我没有详细研究过 nltk 代码,但是 3-8 个文档(在 scikit 代码中)可能不足以构建一个语料库。构建语料库时;使用具有数十万篇文章或数千本书的新闻档案。也许在 8 个文档中像“the”这样的词出现的频率总体上并不大,无法解释这些词在这些文档中的共性。

      如果您查看源代码,您可能会发现实现的差异,无论它们遵循不同的归一化步骤还是频率分布(https://nlp.stanford.edu/IR-book/html/htmledition/document-and-query-weighting-schemes-1.html 有常见的 tfidf 变体)

      另一件可能有帮助的事情是查看词频(scikit 中的 CountVectorizer),并确保像“the”这样的词在所有文档中都出现过度。

      【讨论】:

        猜你喜欢
        • 2018-01-23
        • 2014-08-22
        • 2014-11-12
        • 2018-06-03
        • 2015-08-30
        • 2019-04-03
        • 1970-01-01
        • 2017-05-26
        相关资源
        最近更新 更多