sklearn的TfidfVectorizer生成的TF-IDF是否存在计算错误?
代码示例
from sklearn.feature_extraction.text import TfidfVectorizer import pandas as pd textRaw = [ "good boy girl", "good good good", "good boy", "good girl", "good bad girl", ] vectorizer = TfidfVectorizer() X = vectorizer.fit_transform(textRaw) allWords = vectorizer.get_feature_names_out() dense = X.todense() XList = dense.tolist() df = pd.DataFrame(XList, columns=allWords) dictionary = df.T.sum(axis=1) print(dictionary)
输出结果
bad 0.772536
boy 1.561542
girl 1.913661
good 2.870128
问题
我原本以为,"good"出现在所有文档中,其IDF值应该为0,对应的TF-IDF值也应该是0,但为什么用TfidfVectorizer计算后,"good"的TF-IDF总和反而最高?
解答
这是因为TfidfVectorizer默认采用了平滑处理的IDF计算公式,和你理解的基础IDF逻辑不同。
基础IDF公式是 log(N / df),其中N是总文档数,df是包含目标词的文档数。如果某个词出现在所有文档里,df=N,代入后IDF为log(1)=0,TF-IDF自然为0。但sklearn的默认实现为了避免出现IDF为0的情况(防止某些词被完全忽略),使用了平滑公式:log((1 + N) / (1 + df)) + 1
代入你的例子:总文档数N=5,"good"的df=5,计算得log((1+5)/(1+5)) +1 = 0 +1 =1,所以"good"的IDF值是1,而非0。
另外,"good"在多个文档中的词频很高(比如第二个文档重复了3次),再加上TF部分默认做了L2归一化,每个文档里"good"的TF-IDF值都有一定权重,累加后总和自然成为最高。
如果想要使用基础的IDF公式,初始化TfidfVectorizer时设置smooth_idf=False即可:
vectorizer = TfidfVectorizer(smooth_idf=False)
此时"good"的IDF为log(5/5)=0,所有文档中它的TF-IDF值都会是0,总和也会变为0。
内容的提问来源于stack exchange,提问作者small tomato

