CountVectorizer 令牌计数和 use_idf 设置为 False 的 TfidfTransformer 有什么区别?

数据挖掘 机器学习 nlp scikit-学习
2021-09-27 00:26:22

我们可以使用 CountVectorizer 来计算一个词在语料库中出现的次数:

# Tokenizing text
from sklearn.feature_extraction.text import CountVectorizer
count_vect = CountVectorizer()
X_train_counts = count_vect.fit_transform(twenty_train.data)

如果我们将其转换为数据框,我们可以看到标记的样子:

在此处输入图像描述

例如,第 3 个文档的第 35,780 个单词出现两次。

我们可以使用 TfidfTransformer 来计算一个词在语料库中出现的次数(只有词频而不是逆词),如下所示:

from sklearn.feature_extraction.text import TfidfTransformer
tf_transformer = TfidfTransformer(use_idf=False).fit(X_train_counts)
X_train_tf = tf_transformer.transform(X_train_counts)

将其转换为数据框,我们得到:

在此处输入图像描述

我们可以看到表示是不同的。TF 显示为 0.15523。为什么这与使用 CountVectorizer 的令牌计数不同?

3个回答

实际上,文档非常清楚。我会保留它,以防其他人在阅读之前搜索:

TfidfTransformer 计数矩阵转换为标准化的tf 或 tf-idf 表示。因此,尽管 theCountVectorizerTfidfTransformer(with use_idf=False) 都产生词频,但TfidfTransformer它正在对计数进行归一化。

仅就我自己而言,我发现通过使用我能找到的最简单的例子来解决这些事情要容易得多,而不是那些sklearn提供的大型怪物文本。怪物文本在以后很有用,但是当你试图从骨头中挑选出什么与什么相关时,弄清楚单词之间的区别CountVectorizerTfidfVectorizer绝对数量并不是很有帮助。

然后,考虑一个我们创建两个矢量化器的情况,以及两个非常简单的示例:

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer

cv = CountVectorizer(stop_words='english')
tv = TfidfVectorizer(stop_words='english')

a = "cat hat bat splat cat bat hat mat cat"
b = "cat mat cat sat"

使用我们的文档列表调用fit_transform()任一向量化[a,b]器,作为每种情况下的参数,返回相同类型的对象——一个 2x6 稀疏矩阵,其中包含 8 个压缩稀疏行格式的存储元素。唯一的区别是TfidfVectorizer()返回浮动,而CountVectorizer()返回整数。这是意料之中的——正如上面引用的文档中所解释的,在计数TfidfVectorizer()时分配分数。CountVectorizer()

cv_score = cv.fit_transform([a, b])
cv_score
>>> <2x6 sparse matrix of type '<class 'numpy.int64'>'
    with 8 stored elements in Compressed Sparse Row format>

tv_score = tv.fit_transform([a, b])
tv_score
>>> <2x6 sparse matrix of type '<class 'numpy.float64'>'
    with 8 stored elements in Compressed Sparse Row format>

如果我们对它们进行迭代,我们的评分矩阵之间的差异就更容易看出——因此为我们的示例选择了漂亮的短文本。首先,我们将编写一个函数来将我们的备用矩阵转换为好的旧列表。

def matrix_to_list(matrix):
    matrix = matrix.toarray()
    return matrix.tolist()

cv_score_list = matrix_to_list(cv_score)
cv_score_list
>>> [[2, 3, 2, 1, 0, 1], [0, 2, 0, 1, 1, 0]]

tv_score_list = matrix_to_list(tv_score)
tv_score_list
>>> [[0.5333344767907123,
  0.5692078092660131,
  0.5333344767907123,
  0.18973593642200434,
  0.0,
  0.26666723839535617],
 [0.0, 0.7572644142929534, 0.0, 0.3786322071464767, 0.5321543559503558, 0.0]]

每个列表包含两个列表作为元素—— 和 的得分,以及a单词计数我们将此与知识相结合,即如果我们调用任一矢量化器,单词的(字母)顺序与评分顺序相匹配。因此,我们可以很好地迭代我们的四个列表(2x2)和我们的单词列表来制作一个有用的表格:btv_score_listabcv_score_list.get_feature_names()

print("tfidf_a  tfidf_b  count_a count_b   word")
print("-"*41)
for i in range(6):
    print("  {:.3f}    {:.3f}        {:}       {:}   {:}".format(tv_score_list[0][i],
                                               tv_score_list[1][i],
                                               cv_score_list[0][i],
                                               cv_score_list[1][i],
                                               cv.get_feature_names()[i]))

tfidf_a  tfidf_b  count_a count_b   word
-----------------------------------------
  0.533    0.000        2       0   bat
  0.569    0.757        3       2   cat
  0.533    0.000        2       0   hat
  0.190    0.379        1       1   mat
  0.000    0.532        0       1   sat
  0.267    0.000        1       0   splat

查看表格可以让我们了解tfidf算法的工作原理。例如,splat在 中出现一次,在 中a根本不出现b,而在sat中出现一次,在 中b根本不出现a然而,splat得分为 0.267,而sat得分为 0.532。另请注意,虽然mat出现在两个列表中,但它的得分为 0.19a和 0.379 b这是算法在工作中词频和文档频率之间的区别。

谢谢你陪我。我希望这对某人有所帮助。

将计数矩阵转换为标准化的 tf 或 tf-idf 表示

Tf 表示词频,而 tf-idf 表示词频乘以逆文档频率。这是信息检索中常见的术语加权方案,在文档分类中也有很好的用途。