在天然語言處理——詞袋模型與向量化中咱們講到在文本挖掘的預處理中,向量化以後通常都伴隨着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與標準化。