背景介绍
在一个大的文本语料库中,一些单词将出现很多次(例如 “the”, “a”, “is” 是英文),因此对文档的实际内容没有什么有意义的信息。 如果我们将直接计数数据直接提供给分类器,那么这些频繁词组会掩盖住那些我们关注但很少出现的词。
为了为了重新计算特征权重,并将其转化为适合分类器使用的浮点值,因此使用 tf-idf 变换是非常常见的。
Tf表示术语频率,而 tf-idf 表示术语频率乘以转制文档频率:
通俗的理解
字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降
公式解释:
在书本上面的通用的公式是:
其中
表示术语
在
中出现的次数,
表示所有的
中的单词个数之和
其中
是文档的总数,
是包含术语 t 的文档数,其中分母加1是为了防止除数为0
sklearn中tf-idf解释
在sklearn中的
中计算过程和上述的公式是有些区别的,在sklearn中,使用 TfidfTransformer
的默认设置TfidfTransformer(norm='l2', use_idf=True, smooth_idf=True, sublinear_tf=False)
术语频率,一个术语在给定文档中出现的次数乘以 idf
组件, 计算为
其中
表示术语
在
中出现的次数
其中
是文档的总数,
是包含术语 t 的文档数
但是当smooth_idf=False
然后,所得到的 tf-idf 向量通过欧几里得范数归一化:
现在我们实现如下代码:
from sklearn.feature_extraction.text import TfidfTransformer
transformer = TfidfTransformer(smooth_idf=False)
counts = [[3, 0, 1],
[2, 0, 0],
[3, 0, 0],
[4, 0, 0],
[3, 2, 0],
[3, 0, 2]]
tfidf = transformer.fit_transform(counts)
print(tfidf.toarray())
#output:
[[ 0.81940995, 0. , 0.57320793],
[ 1. , 0. , 0. ],
[ 1. , 0. , 0. ],
[ 1. , 0. , 0. ],
[ 0.47330339, 0.88089948, 0. ],
[ 0.58149261, 0. , 0.81355169]]
例如,我们可以计算计数
数组中第一个文档中第一个项的 tf-idf ,如下所示:
现在,如果我们对文档中剩下的2个术语重复这个计算,我们得到:
所以原始向量为:
然后,应用欧几里德(L2)规范,我们获得文档1的以下 tf-idfs:
此外,默认参数 smooth_idf=True
将 “1” 添加到分子和分母,就好像一个额外的文档被看做包含集合中的每个术语,这样可以避免零分割:
使用此修改,文档1中第三项的 tf-idf 更改为 1.8473:
而 L2 标准化的 tf-idf 变为:
通过以下代码可以验证:
transformer = TfidfTransformer()
transformer.fit_transform(counts).toarray()
array([[ 0.85151335, 0. , 0.52433293],
[ 1. , 0. , 0. ],
[ 1. , 0. , 0. ],
[ 1. , 0. , 0. ],
[ 0.55422893, 0.83236428, 0. ],
[ 0.63035731, 0. , 0.77630514]])
参考:
http://scikit-learn.org/stable/modules/feature_extraction.html#tfidf-term-weighting
https://zh.wikipedia.org/wiki/Tf-idf