用scikit-learn的三種詞袋(BoW)生成方法爲機器學習任務準備文本數據

用scikit-learn的三種詞袋(BoW)生成方法爲機器學習任務準備文本數據

本文爲翻譯博客,詳見: 原文

在使用文本數據建立預測模型之前,需要做特別的數據預處理工作。

文本必須先進行分詞(tokenization)操作,然後進行特徵提取,即向量化(vectorization)操作,將分詞後的詞編碼成整形或浮點數據作爲機器學習算法的輸入。

scikit-learn庫提供了易用的工具來對文本數據做分詞和特徵提取。

學完這個教程後,你將會知道:

  • 如何使用CountVectorizer 將文本轉化成詞統計向量
  • 如何使用TfidfVectorizer 將文本轉化成詞頻向量
  • 如何使用HashingVectorizer 將文本轉化成唯一數字向量

Bag-of-Words 模型

在進行模型訓練之前,我們需要將文本轉化成數字。如果我們對文檔進行分類,那麼每一個文檔都是一個輸入,並且有一個對應的輸出類別。因爲算法都是將數字向量作爲輸入,所以我們需要將文檔轉換成指定長度的數字向量。

一種簡單有效的模型叫:Bag-of-Words(BoW)模型。這個模型之所以簡單,是因爲它將單詞之間的順序關係全部丟棄,只關注文檔中單詞出現的次數。該方法爲每個單詞分配一個唯一編號,這樣一個文檔就能夠被編碼成與已知詞彙數量相同長度的向量。向量中每一個位置上的值就是其編號對應單詞在文檔中出現的次數。

BoW模型有許多優化版本,優化方向包括:1)對詞義的更好闡述 2)對向量中每個詞的編碼方式

scikit-learn庫中提供了三種可用的解決方案,下面作簡要介紹。

用CountVectorizer統計詞頻

CountVectorier 不僅提供了一個簡單的方法爲一系列文本文件進行分詞操作,從而用這些已有的詞建立一個詞彙表,同時還能用這個詞彙表對新文檔編碼。

使用步驟如下:

  1. 創建CountVectorizer 類的一個實例
  2. 調用fit() 函數從一個或多個文件中學習一個詞彙表
  3. 調用transform() 函數,將一個文件編碼成一個向量

返回一個與詞彙表同長的向量,向量中每個位置對應詞彙表該位置上的詞在當前文件中出現的次數。因爲向量中包含很多的0,所以很稀疏,Python在scipy.sparse 包中提供了一個有效的方法處理稀疏向量。

上述步驟3中的transform() 函數返回一個稀疏向量,爲了直觀理解,我們可以用toarray() 將稀疏向量轉化成numpy數組。

下面是用CountVectorizer 進行分詞、建立詞彙表、編碼一個文件的實例。

導入CountVectorizer 庫和文件:

from sklearn.feature_extraction.text import CountVectorizer
text = ["The quick brown fox jumped over the lazy dog."]

建立詞彙表:

# 創建transform
vectorizer = CountVectorizer()
# 分詞並建立詞彙表
vectorizer.fit(text)
# 結果輸出
print vectorizer.vocabulary_

輸出詞彙表爲:

{u'brown': 0, u'lazy': 4, u'jumped': 3, u'over': 5, u'fox': 2, u'dog': 1, u'quick': 6, u'the': 7}

按照詞彙表,對文件進行編碼:

vector = vectorizer.transform(text)
# 輸出編碼後的向量信息
print vector.shape
print type(vector)
print vector.toarray()

輸出爲:

(1, 8)
<class 'scipy.sparse.csr.csr_matrix'>
[[1 1 1 1 1 1 1 2]]

需要重點指出的是,相同的方法可以對包含詞彙表之外詞彙的文件進行編碼,這些詞彙表中不存在的詞將在返回的向量中被忽略,舉個例子:

# 對另一個文件進行編碼
text2 = ["the puppy"]
vector = vectorizer.transform(text2)
print vector.toarray()

輸出爲:

[[0 0 0 0 0 0 0 1]]

只有詞彙表中存在的第七個詞”the”出現一次被編碼了,詞彙表中不存在的“puppy”直接被忽略。

用TfidfVectorizer進行詞頻統計

詞數統計是一個好的着手點,但是很基礎。簡單的詞數統計存在一個問題,比如:一些像“the”這樣的單詞可能出現很多次,雖然在編碼的向量中他們對應的數值很大,但並沒有什麼意義。

一種解決方案是計算詞頻,TF-IDF 是眼下最流行的詞頻計算方法,它是“Term Frequency - Inverse Documentation Frequency” 首字母的縮寫。

  • Term Frequency :指在一個文件中一個指定單詞出現的次數
  • Inverse Document Frequency :它降低在多個文件中均出現的單詞的重要性

本文不作數學計算解釋,可參考weki 。TF-IDF是詞頻得分,它更偏重於某個文件中新穎的單詞,比如:在一個文件中多次出現,但在其他文件很少出現的單詞。

TfidfVectorizer 可以對文件進行分詞、學習詞彙表、計算詞頻得分,使你能夠編碼新文件。如果你已經學習了一個CountVectorizer ,你可以只需用TfidfTransformer 計算inverse document frequency ,然後編碼新文件。

TfidfVectorizer的使用步驟和CountVectorizer一樣:創建、fit操作、transform操作。

下面是用TfidfVectorizer對3個小文件學習詞彙表和inverse document frequencies,然後編碼其中一篇文件的例子:

先分詞並建立詞彙表,計算idf得分。

from sklearn.feature_extraction.text import TfidfVectorizer
# 文件列表
text = ["The quick brown fox jumped over the lazy dog.",
        "The dog.",
        "The fox"]
# 建立transform
vectorizer = TfidfVectorizer()
# 分詞,建立詞彙表
vectorizer.fit(text)
# 輸出結果
print vectorizer.vocabulary_
print vectorizer.idf_

輸出結果:

{u'brown': 0, u'lazy': 4, u'jumped': 3, u'over': 5, u'fox': 2, u'dog': 1, u'quick': 6, u'the': 7}
[ 1.69314718  1.28768207  1.28768207  1.69314718  1.69314718  1.69314718
  1.69314718  1.        ]

編碼其中一個文件:

# 編碼文件
vector = vectorizer.transform([text[0]])
# 輸出編碼結果
print vector.shape
print vector.toarray()

輸出結果:

(1, 8)
[[ 0.36388646  0.27674503  0.27674503  0.36388646  0.36388646  0.36388646
   0.36388646  0.42983441]]

這些得分向量被規範化到0-1之間,可以直接作爲機器學習任務的輸入。

用HashingVectorizer進行Hashing操作

詞數和詞頻一般很有用,但這些方法有個限制——詞彙表可能很大。

如果詞彙表很大,那麼就需要大的向量來編碼文件,對存儲造成壓力,進而拖慢算法。

一個聰明的解決方案是對單詞進行單向哈希操作,將它們轉換成整數。聰明的地方在於不需要詞彙表,你可以選擇一個指定任意長度的向量。該方法的缺點是哈希是一個單向函數,所以不能將編碼好的詞變回原來的詞(在大多數監督學習任務中沒啥影響)。

HashingVectorizer 類步驟是先對詞進行hash操作,然後對指定文件進行分詞和編碼。

下面的例子是使用HashVectorizer對單個文件進行操作。選擇一個任意定長爲20的向量,這對應了哈希函數的範圍,選擇的哈希長度太小(比如20)可能導致哈希衝突,這需要我們根據估計的詞彙長度計算衝突的可能性,並選擇合適的哈希長度。

注意這種向量化方法不需要在訓練文件數據上調用fit函數,在實例化之後,它可以直接被用來編碼文件。

from sklearn.feature_extraction.text import HashingVectorizer
# 文件列表
text = ["The quick brown fox jumped over the lazy dog."]
# 創建transform
vectorizer = HashingVectorizer(n_features=20)
# 編碼文件
vector = vectorizer.transform(text)
# 輸出編碼後的結果
print vector.shape
print vector.toarray()

運行例子,將樣本文件編碼成一個有20個元素的稀疏數組。

文件編碼向量中的值對應於將詞數規範化到-1到1之間所得結果,也可以通過改變默認值修改範圍。

上例所得結果如下:

(1, 20)
[[ 0.          0.          0.          0.          0.          0.33333333
   0.         -0.33333333  0.33333333  0.          0.          0.33333333
   0.          0.          0.         -0.33333333  0.          0.
  -0.66666667  0.        ]]

總結

這個教程講述瞭如何用scikit-learn爲機器學習任務準備文本數據(文件預處理),只講了簡單的實現方式,有待深挖。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章