在文本挖掘預處理之向量化與Hash Trick中我們講到在文本挖掘的預處理中,向量化之后一般都伴隨着TF-IDF的處理,那么什么是TF-IDF,為什么一般我們要加這一步預處理呢?這里就對TF-IDF的原理做一個總結。
1. 文本向量化特征的不足
在將文本分詞並向量化后,我們可以得到詞匯表中每個詞在各個文本中形成的詞向量,比如在文本挖掘預處理之向量化與Hash Trick這篇文章中,我們將下面4個短文本做了詞頻統計:
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"]
不考慮停用詞,處理后得到的詞向量如下:
[[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。
2. TF-IDF概述
TF-IDF是Term Frequency - Inverse Document Frequency的縮寫,即“詞頻-逆文本頻率”。它由兩部分組成,TF和IDF。
前面的TF也就是我們前面說到的詞頻,我們之前做的向量化也就是做了文本中各個詞的出現頻率統計,並作為文本特征,這個很好理解。關鍵是后面的這個IDF,即“逆文本頻率”如何理解。在上一節中,我們講到幾乎所有文本都會出現的"to"其詞頻雖然高,但是重要性卻應該比詞頻低的"China"和“Travel”要低。我們的IDF就是來幫助我們來反應這個詞的重要性的,進而修正僅僅用詞頻表示的詞特征值。
概括來講, IDF反應了一個詞在所有文本中出現的頻率,如果一個詞在很多的文本中出現,那么它的IDF值應該低,比如上文中的“to”。而反過來如果一個詞在比較少的文本中出現,那么它的IDF值應該高。比如一些專業的名詞如“Machine Learning”。這樣的詞IDF值應該高。一個極端的情況,如果一個詞在所有的文本中都出現,那么它的IDF值應該為0。
上面是從定性上說明的IDF的作用,那么如何對一個詞的IDF進行定量分析呢?這里直接給出一個詞x
的IDF的基本公式如下:
其中,N
代表語料庫中文本的總數,而N代表語料庫中包含詞x的文本總數。為什么IDF的基本公式應該是是上面這樣的而不是像N
這樣的形式呢?這就涉及到信息論相關的一些知識了。感興趣的朋友建議閱讀吳軍博士的《數學之美》第11章。
上面的IDF公式已經可以使用了,但是在一些特殊的情況會有一些小問題,比如某一個生僻詞在語料庫中沒有,這樣我們的分母為0, IDF沒有意義了。所以常用的IDF我們需要做一些平滑,使語料庫中沒有出現的詞也可以得到一個合適的IDF值。平滑的方法有很多種,最常見的IDF平滑后的公式之一為:
有了IDF的定義,我們就可以計算某一個詞的TF-IDF值了:
其中T
指詞x
在當前文本中的詞頻。
3. 用scikit-learn進行TF-IDF預處理
在scikit-learn中,有兩種方法進行TF-IDF的預處理。
完整代碼參見我的github:https://github.com/ljpzzz/machinelearning/blob/master/natural-language-processing/tf-idf.ipynb
第一種方法是在用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與標准化。
4. TF-IDF小結
TF-IDF是非常常用的文本挖掘預處理基本步驟,但是如果預處理中使用了Hash Trick,則一般就無法使用TF-IDF了,因為Hash Trick后我們已經無法得到哈希后的各特征的IDF的值。使用了IF-IDF並標准化以后,我們就可以使用各個文本的詞特征向量作為文本的特征,進行分類或者聚類分析。
當然TF-IDF不光可以用於文本挖掘,在信息檢索等很多領域都有使用。因此值得好好的理解這個方法的思想。