在天然语言处理——词袋模型与向量化中咱们讲到在文本挖掘的预处理中,向量化以后通常都伴随着TF-IDF的处理,那么什么是TF-IDF,为何通常咱们要加这一步预处理呢?这里就对TF-IDF的原理作一个总结。python
在将文本分词并向量化后,咱们能够获得词汇表中每一个词在各个文本中造成的词向量,好比在天然语言处理——词袋模型与向量化这篇文章中,咱们将下面4个短文本作了词频统计:segmentfault
corpus=["I come to China to travel", "This is a car polupar in China", "I love tea and Apple ", "The work is to write some papers in science"]
不考虑停用词,处理后获得的词向量以下:code
[[0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 2 1 0 0] [0 0 1 1 0 1 1 0 0 1 0 0 0 0 1 0 0 0 0] [1 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0] [0 0 0 0 0 1 1 0 1 0 1 1 0 1 0 1 0 1 1]]
若是咱们直接将统计词频后的19维特征作为文本分类的输入,会发现有一些问题。好比第一个文本,咱们发现"come","China"和“Travel”各出现1次,而“to“出现了两次。彷佛看起来这个文本与”to“这个特征更关系紧密。可是实际上”to“是一个很是广泛的词,几乎全部的文本都会用到,所以虽然它的词频为2,可是重要性却比词频为1的"China"和“Travel”要低的多。若是咱们的向量化特征仅仅用词频表示就没法反应这一点。所以咱们须要进一步的预处理来反应文本的这个特征,而这个预处理就是TF-IDF。orm
TF-IDF是Term Frequency - Inverse Document Frequency的缩写,即“词频-逆文本频率”。它由两部分组成,TF和IDF。ci
前面的TF也就是咱们前面说到的词频,咱们以前作的向量化也就是作了文本中各个词的出现频率统计,并做为文本特征,这个很好理解。关键是后面的这个IDF,即“逆文本频率”如何理解。在上一节中,咱们讲到几乎全部文本都会出现的"to"其词频虽然高,可是重要性却应该比词频低的"China"和“Travel”要低。咱们的IDF就是来帮助咱们来反应这个词的重要性的,进而修正仅仅用词频表示的词特征值。get
归纳来说,IDF反应了一个词在全部文本中出现的频率,若是一个词在不少的文本中出现,那么它的IDF值应该低,好比上文中的“to”。而反过来若是一个词在比较少的文本中出现,那么它的IDF值应该高。好比一些专业的名词如“Machine Learning”。这样的词IDF值应该高。一个极端的状况,若是一个词在全部的文本中都出现,那么它的IDF值应该为0。数学
上面是从定性上说明的IDF的做用,那么如何对一个词的IDF进行定量分析呢?这里直接给出一个词xx的IDF的基本公式以下:it
$$ IDF(x) = log\frac{N}{N(x)} $$io
其中,$N$表明语料库中文本的总数,而$N(x)$表明语料库中包含词xx的文本总数。为何IDF的基本公式应该是是上面这样的而不是像$N/N(x)$这样的形式呢?这就涉及到信息论相关的一些知识了。感兴趣的朋友建议阅读吴军博士的《数学之美》第11章。form
上面的IDF公式已经可使用了,可是在一些特殊的状况会有一些小问题,好比某一个生僻词在语料库中没有,这样咱们的分母为0, IDF没有意义了。因此经常使用的IDF咱们须要作一些平滑,使语料库中没有出现的词也能够获得一个合适的IDF值。平滑的方法有不少种,最多见的IDF平滑后的公式之一为:
$$ IDF(x) = log\frac{N+1}{N(x)+1} + 1 $$
有了IDF的定义,咱们就能够计算某一个词的TF-IDF值了:
$$ TF-IDF(x) = TF(x) * IDF(x) $$
其中$TF(x)$指词xx在当前文本中的词频。
在scikit-learn中,有两种方法进行TF-IDF的预处理。
第一种方法是在用CountVectorizer类向量化以后再调用TfidfTransformer类进行预处理。第二种方法是直接用TfidfVectorizer完成向量化与TF-IDF预处理。
首先咱们来看第一种方法,CountVectorizer+TfidfTransformer的组合,代码以下:
from sklearn.feature_extraction.text import TfidfTransformer from sklearn.feature_extraction.text import CountVectorizer corpus=["I come to China to travel", "This is a car polupar in China", "I love tea and Apple ", "The work is to write some papers in science"] vectorizer=CountVectorizer() transformer = TfidfTransformer() tfidf = transformer.fit_transform(vectorizer.fit_transform(corpus)) print tfidf
输出的各个文本各个词的TF-IDF值以下:
(0, 4) 0.442462137895 (0, 15) 0.697684463384 (0, 3) 0.348842231692 (0, 16) 0.442462137895 (1, 3) 0.357455043342 (1, 14) 0.453386397373 (1, 6) 0.357455043342 (1, 2) 0.453386397373 (1, 9) 0.453386397373 (1, 5) 0.357455043342 (2, 7) 0.5 (2, 12) 0.5 (2, 0) 0.5 (2, 1) 0.5 (3, 15) 0.281131628441 (3, 6) 0.281131628441 (3, 5) 0.281131628441 (3, 13) 0.356579823338 (3, 17) 0.356579823338 (3, 18) 0.356579823338 (3, 11) 0.356579823338 (3, 8) 0.356579823338 (3, 10) 0.356579823338
如今咱们用TfidfVectorizer一步到位,代码以下:
from sklearn.feature_extraction.text import TfidfVectorizer tfidf2 = TfidfVectorizer() re = tfidf2.fit_transform(corpus) print re
输出的各个文本各个词的TF-IDF值和第一种的输出彻底相同。你们能够本身去验证一下。
因为第二种方法比较的简洁,所以在实际应用中推荐使用,一步到位完成向量化,TF-IDF与标准化。