文本數據預處理的第一步通常是進行分詞,分詞后會進行向量化的操作。在介紹向量化之前,我們先來了解下詞袋模型。
1.詞袋模型(Bag of words,簡稱 BoW )
詞袋模型假設我們不考慮文本中詞與詞之間的上下文關系,僅僅只考慮所有詞的權重。而權重與詞在文本中出現的頻率有關。
詞袋模型首先會進行分詞,在分詞之后,通過統計每個詞在文本中出現的次數,我們就可以得到該文本基於詞的特征,如果將各個文本樣本的這些詞與對應的詞頻放在一起,就是我們常說的向量化。向量化完畢后一般也會使用 TF-IDF 進行特征的權重修正,再將特征進行標准化。 再進行一些其他的特征工程后,就可以將數據帶入機器學習模型中計算。
詞袋模型的三部曲:分詞(tokenizing),統計修訂詞特征值(counting)與標准化(normalizing)。
詞袋模型有很大的局限性,因為它僅僅考慮了詞頻,沒有考慮上下文的關系,因此會丟失一部分文本的語義。
在詞袋模型統計詞頻的時候,可以使用 sklearn 中的 CountVectorizer 來完成。下面具體說明。
2.詞頻向量化
CountVectorizer 類會將文本中的詞語轉換為詞頻矩陣,例如矩陣中包含一個元素a[i][j],它表示j詞在i類文本下的詞頻。它通過 fit_transform 函數計算各個詞語出現的次數,通過get_feature_names()可獲取詞袋中所有文本的關鍵字,通過 toarray()可看到詞頻矩陣的結果。
官方文件中提到其參數很多默認值就很好,無需再改動,詳細參數設置參見:點擊打開鏈接。例子如下:
from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer(min_df=1)
corpus = [ 'This is the first document.',
'This is the second second document.',
'And the third one.',
'Is this the first document?',
]
X = vectorizer.fit_transform(corpus)
feature_name = vectorizer.get_feature_names()
print (X)
print (feature_name)
print (X.toarray())
輸出:
(0, 1) 1
(0, 2) 1
(0, 6) 1
(0, 3) 1
(0, 8) 1
(1, 5) 2
(1, 1) 1
(1, 6) 1
(1, 3) 1
(1, 8) 1
(2, 4) 1
(2, 7) 1
(2, 0) 1
(2, 6) 1
(3, 1) 1
(3, 2) 1
(3, 6) 1
(3, 3) 1
(3, 8) 1
['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this']
[[0 1 1 ..., 1 0 1]
[0 1 0 ..., 1 0 1]
[1 0 0 ..., 1 1 0]
[0 1 1 ..., 1 0 1]]
在輸出中,左邊的括號中的第一個數字是文本的序號i,第2個數字是詞的序號j,注意詞的序號是基於所有的文檔的。第三個數字就是我們的詞頻。
可以看到一共有9個詞,所以4個文本對應的都是9維的特征向量。
由於大部分文本都只會用詞匯表中很少一部分的詞,因此詞向量中有大量的0,也就是說詞向量是稀疏的。因此在實際應用中一般使用稀疏矩陣來存儲。
3.TF-IDF處理
TF-IDF(Term Frequency–Inverse Document Frequency)是一種用於資訊檢索與文本挖掘的常用加權技術。TF-IDF是一種統計方法,用以評估一個字詞對於一個文件集或一個語料庫中的其中一份文件的重要程度。字詞的重要性隨着它在文件中出現的次數成正比增加,但同時會隨着它在語料庫中出現的頻率成反比下降。TF-IDF加權的各種形式常被搜索引擎應用,作為文件與用戶查詢之間相關程度的度量或評級。
TF-IDF的主要思想是:如果某個詞或短語在一篇文章中出現的頻率TF高,並且在其他文章中很少出現,則認為此詞或者短語具有很好的類別區分能力,適合用來分類。TF-IDF實際上是:TF * IDF。
(1)詞頻(Term Frequency,TF)指的是某一個給定的詞語在該文件中出現的頻率。即詞w在文檔d中出現的次數count(w, d)和文檔d中總詞數size(d)的比值。
tf(w,d) = count(w, d) / size(d)
這個數字是對詞數 (term count) 的歸一化,以防止它偏向長的文件。(同一個詞語在長文件里可能會比短文件有更高的詞數,而不管該詞語重要與否。)
(2)逆向文件頻率(Inverse Document Frequency,IDF)是一個詞語普遍重要性的度量。某一特定詞語的IDF,可以由總文件數目除以包含該詞語之文件的數目,再將得到的商取對數得到。即文檔總數n與詞w所出現文件數docs(w, D)比值的對數。
idf = log(n / docs(w, D))
TF-IDF根據 tf 和 idf 為每一個文檔d和由關鍵詞w[1]…w[k]組成的查詢串q計算一個權值,用於表示查詢串q與文檔d的匹配度:
tf-idf(q, d) = sum { i = 1..k | tf-idf(w[i], d) } = sum { i = 1..k | tf(w[i], d) * idf(w[i]) }
某一特定文件內的高詞語頻率,以及該詞語在整個文件集合中的低文件頻率,可以產生出高權重的TF-IDF。因此,TF-IDF傾向於過濾掉常見的詞語,保留重要的詞語。
4.用sklearn進行TF-IDF預處理
第一種方法是在用 CountVectorizer 類向量化之后再調用 TfidfTransformer 類進行預處理。第二種方法是直接用 TfidfVectorizer 完成向量化與 TF-IDF 預處理。
4.1 CountVectorizer 結合 TfidfTransformer
依舊用上面的文本,實現如下:
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer
corpus = [ 'This is the first document.',
'This is the second second document.',
'And the third one.',
'Is this the first document?',
]
vectorizer=CountVectorizer()
transformer = TfidfTransformer()
tfidf = transformer.fit_transform(vectorizer.fit_transform(corpus))
print (tfidf)
輸出的各個文本各個詞的 TF-IDF 值如下:
(0, 8) 0.438776742859 (0, 3) 0.438776742859 (0, 6) 0.358728738248 (0, 2) 0.541976569726 (0, 1) 0.438776742859 (1, 8) 0.272301467523 (1, 3) 0.272301467523 (1, 6) 0.222624292325 (1, 1) 0.272301467523 (1, 5) 0.853225736145 (2, 6) 0.28847674875 (2, 0) 0.552805319991 (2, 7) 0.552805319991 (2, 4) 0.552805319991 (3, 8) 0.438776742859 (3, 3) 0.438776742859 (3, 6) 0.358728738248 (3, 2) 0.541976569726 (3, 1) 0.438776742859
4.2 用 TfidfVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer tfidf2 = TfidfVectorizer() re = tfidf2.fit_transform(corpus) print (re)
輸出:
(0, 8) 0.438776742859 (0, 3) 0.438776742859 (0, 6) 0.358728738248 (0, 2) 0.541976569726 (0, 1) 0.438776742859 (1, 8) 0.272301467523 (1, 3) 0.272301467523 (1, 6) 0.222624292325 (1, 1) 0.272301467523 (1, 5) 0.853225736145 (2, 6) 0.28847674875 (2, 0) 0.552805319991 (2, 7) 0.552805319991 (2, 4) 0.552805319991 (3, 8) 0.438776742859 (3, 3) 0.438776742859 (3, 6) 0.358728738248 (3, 2) 0.541976569726 (3, 1) 0.438776742859
統計個數和計算頻率兩種方法雖然非常實用,但是也由其局限性導致詞匯量可能變得非常大。詞匯量過大又將導致需要非常大的矢量來編碼文檔,從而對內存產生很大的要求,同時拖慢算法的速度。鹵煮會在后續的博客中介紹優化方法。
參考資料:
http://scikit-learn.org/stable/modules/feature_extraction.html#common-vectorizer-usage
http://www.cnblogs.com/weidagang2046/archive/2012/10/22/tf-idf-from-probabilistic-view.html#top
https://zhangzirui.github.io/posts/Document-14%20(sklearn-feature).md