在sklearn TfidfVectorizer中使用SnowballStemmer后词权重异常的修复
问题原因及修复方案
你遇到的问题核心在于sklearn的TfidfVectorizer默认启用了IDF平滑(smooth_idf=True),这会导致即使某个词在所有文档中都出现(df = n,df是文档频率,n是总文档数),它的IDF值也不会变成0。
为什么当前disk的TF-IDF不为0?
默认的平滑IDF计算公式是:
idf = log((1 + n) / (1 + df)) + 1
你的例子里,总文档数n=3,disk的df=3,代入后:
idf = log((1+3)/(1+3)) +1 = log(1)+1 = 0+1=1
再结合TF值(每个文档中disk的词频/该文档总词数)和L2归一化(默认norm='l2'),最终得到的TF-IDF值就不会是0了——比如第一个文档中,disk和format的TF都是1/2,乘以IDF=1后是0.5,经过L2归一化(除以sqrt(0.5²+0.5²)=√0.5≈0.707),就得到了你看到的0.707。
修复代码的步骤
要让所有文档都出现的词IDF为0,只需要在初始化StemmedTfidfVectorizer时,设置smooth_idf=False即可。同时注意你代码里的一处笔误:fit_transform的参数应该是posts而不是posts_root(你注释掉的行里写错了)。
修改后的完整代码:
from sklearn.feature_extraction.text import TfidfVectorizer import nltk.stem english_stemmer = nltk.stem.SnowballStemmer('english') class StemmedTfidfVectorizer(TfidfVectorizer): def build_analyzer(self): analyzer = super(StemmedTfidfVectorizer, self).build_analyzer() return lambda doc: (english_stemmer.stem(word) for word in analyzer(doc)) # 所有句子 posts = ["How to format my disks", "hard disk formating at", "How to formated my disks"] # 初始化时添加smooth_idf=False vectorizer_tfidf = StemmedTfidfVectorizer(min_df=1, stop_words="english", smooth_idf=False) x_tfidf = vectorizer_tfidf.fit_transform(posts) print("feature_name:%s" % vectorizer_tfidf.get_feature_names()) num_samples, num_features = x_tfidf.shape print("samples_noroot: %d ,#features_noroot: %d" % (num_samples, num_features)) print(x_tfidf.toarray())
修改后的输出效果
运行后,disk的IDF值会是log(n/df)=log(3/3)=0,所以它的TF-IDF值会变成0,输出结果会是:
feature_name:['disk', 'format', 'hard'] samples_noroot: 3 ,#features_noroot: 3 [[0. 1. 0. ] [0. 0.5547002 0.83205029] [0. 1. 0. ]]
这样就符合你预期的“所有文档都出现的词TF-IDF权重为0”的结果了。
内容的提问来源于stack exchange,提问作者thirsd
相关产品推荐
相关产品推荐

