機器學習中,使用Scikit-Learn簡單處理文本數據
更多深度文章,請關注雲計算頻道:https://yq.aliyun.com/cloud
機器學習中,我們總是要先將源數據處理成符合模型算法輸入的形式,比如將文字、聲音、圖像轉化成矩陣。對於文本數據首先要進行分詞(tokenization),移除停止詞(stop words),然後將詞語轉化成矩陣形式,然後再輸入機器學習模型中,這個過程稱為特征提取(feature extraction)或者向量化(vectorization)。本文會教你使用Scikit-Learn機器學習庫中的三種模型來實現這一轉化過程,包括CountVectorizer, TfidfVectorizer, HashingVectorizer。
在將文本數據進行分詞操作以後,有兩種處理方法,一種是做句法分析,另一種是對這些詞從統計學上進行分析,即詞袋模型(Bag-of-Words Model, BoW)。詞袋模型將文檔看成一個袋子,裏麵裝著文檔中的詞匯表。詞袋模型剔除了一些對於統計模型沒有意義的詞,即停止詞,比如那些出現頻率高的連詞,介詞。這些停止詞在自然語言中起到很重要的連接作用,和詞序一起構成了合乎文法的語言結構,對於理解自然語言相當重要。但詞袋模型並沒有利用這些信息,而且還具有幹擾作用,因此在詞袋模型中隻能放棄這些停止詞,不過還是可以使用N元文法(N-Gram)進行一定程度上彌補。詞袋模型會給每個詞都賦予一個唯一的數值,任何一個文檔都可以根據已知的詞匯表表示成固定長度的向量,向量中的每個值表示文檔中每個詞的出現次數,然後就可以將這些向量或進一步處理或直接輸入機器學習算法中。
CountVectorizer簡單地對文檔分分詞,形成詞匯表,然後對新文檔就可以使用這個詞匯表進行編碼,最終將會返回一個長度等於詞匯表長度的向量,每個數字表示單詞在文檔中出現的次數。由於這個向量中會有很多0,python中可使用scipy.sparse包提供的稀疏向量表示。比如下麵這個例子:
1. # list of text documents, the text maybe a file or a list or other documents
2. text = ["The quick brown fox jumped over the lazy dog."]
3. # create the transform
4. vectorizer = CountVectorizer()
5. # tokenize and build vocabulary
6. vectorizer.fit(text)
7. # summarize
8. print(vectorizer.vocabulary_)
9. # encode document
10. vector = vectorizer.transform(text)
11. # summarize encoded vector
12. print(vector.shape)
13. print(type(vector))
14. print(vector.toarray())
輸出:
1. {u'brown': 0, u'lazy': 4, u'jumped': 3, u'over': 5, u'fox': 2, u'dog': 1, u'quick': 6, u'the': 7}
2. (1, 8)
3. <class 'scipy.sparse.csr.csr_matrix'>
4. [[1 1 1 1 1 1 1 2]]
其中,fit(.)函數從文檔中學習出一個詞匯表,transform(.)函數將指定文檔轉化為向量。從打印出來的詞匯表可以看出,所有單詞默認被處理為小寫並且忽略標點符號。詞匯表中總共有8個單詞,最後生成向量的長度也為8,其中的數字表示單詞的出現次數,比如編號為7的單詞the出現了2次。
假設現在有一個新文檔,這個文檔裏麵的某些詞不在已知的詞匯表中,那麼這些詞就會被忽略掉,比如下麵這個例子:
1. # encode another document
2. text2 = ["the puppy"]
3. vector = vectorizer.transform(text2)
4. print(vector.toarray())
5. # [[0 0 0 0 0 0 0 1]]
詞匯表中並沒有puppy這個單詞,隻有單詞the在詞匯表中有記錄,那麼最後形成的向量長度不變,但是會很稀疏。
在CountVectorizer方法中,我們僅僅是統計了詞匯的出現次數,比如單詞the會出現比較多的次數,但實際上,這個單詞並不是很有實際意義。因此使用TF-IDF方法來進行向量化操作。TF-IDF原本是一種統計方法,用以評估字詞對於一個文件集或一個語料庫中的其中一份文件的重要程度。這個方法認為,字詞的重要性隨著它在文件中出現的次數成正比增加,但同時會隨著它在語料庫中出現的頻率成反比下降,其實也就相當於在CountVectorizer的基礎上結合整個語料庫考慮單詞的權重,並不是說這個單詞出現次數越多它就越重要。比如下麵這個例子。
1. from sklearn.feature_extraction.text import TfidfVectorizer
2. # list of text documents
3. text = ["The quick brown fox jumped over the lazy dog.",
4. "The dog.",
5. "The fox"]
6. # create the transform
7. vectorizer = TfidfVectorizer()
8. # tokenize and build vocab
9. vectorizer.fit(text)
10. # summarize
11. print(vectorizer.vocabulary_)
12. print(vectorizer.idf_)
13. # encode document
14. vector = vectorizer.transform([text[0]])
15. # summarize encoded vector
16. print(vector.shape)
17. print(vector.toarray())
18. print(vectorizer.transform([text[1]]).toarray())
輸出:
1. {u'brown': 0, u'lazy': 4, u'jumped': 3, u'over': 5, u'fox': 2, u'dog': 1, u'quick': 6, u'the': 7}
2. [ 1.69314718 1.28768207 1.28768207 1.69314718 1.69314718 1.69314718
3. 1.69314718 1. ]
4. (1, 8)
5. [[ 0.36388646 0.27674503 0.27674503 0.36388646 0.36388646 0.36388646
6. 0.36388646 0.42983441]]
7. [[ 0. 0.78980693 0. 0. 0. 0. 0.
8. 0.61335554]]
這裏是使用了3個小文本,總共有8個詞匯。可以看到單詞the在每個文本中都出現過,這就導致他的idf值是最低的,顯得單詞the並沒那麼重要。通過輸出前兩個文本的向量對比,可以發現這種表示方法依然會輸出稀疏向量。
上麵介紹的基於次數和頻率的方法比較耿直,其限製性在於生成的詞匯表可能會非常龐大,導致最後生成的向量會很長,對內存需求會很大,最後就會降低算法效率。一個巧妙的方法是使用哈希方法,將文本轉化為數字。這種方法不需要詞匯表,你可以使用任意長度的向量來表示,但這種方法不可逆,不能再轉化成對應的單詞,不過很多監督學習任務並不care。
下麵這個例子就展示了HashingVectorizer是如何進行向量化。
1. from sklearn.feature_extraction.text import HashingVectorizer
2. # list of text documents
3. text = ["The quick brown fox jumped over the lazy dog."]
4. # create the transform
5. vectorizer = HashingVectorizer(n_features=20)
6. # encode document
7. vector = vectorizer.transform(text)
8. # summarize encoded vector
9. print(vector.shape)
10. print(vector.toarray())
輸出
1. (1, 20)
2. [[ 0. 0. 0. 0. 0. 0.33333333
3. 0. -0.33333333 0.33333333 0. 0. 0.33333333
4. 0. 0. 0. -0.33333333 0. 0.
5. -0.66666667 0. ]]
可以看到這裏的向量長度並不是8,而是20,而且也不需要像上麵兩種方法一樣需要fit(.),你可以直接使用。最終生成的向量是被歸一化到-1到1之間,你也可以改變HashingVectorizer(.)函數的參數設置使最後的輸出結果取整。
Tips:本文中的例子基本都使用的是這些方法的默認設置,你也可以改變這些方法中的參數以達獲得不同的向量化結果。
作者信息
本文由北郵@愛可可-愛生活老師推薦,阿裏雲雲棲社區組織翻譯。
文章原標題《How to Prepare Text Data for Machine Learning with scikit-learn》
作者:Dr.Jason Brownlee譯者:李烽,審閱:
文章為簡譯,更為詳細的內容,請查看原文
最後更新:2017-10-04 18:03:01