1. 程式人生 > >用Python開始機器學習(5:文字特徵抽取與向量化) sklearn

用Python開始機器學習(5:文字特徵抽取與向量化) sklearn

http://blog.csdn.net/lsldd/article/details/41520953

假設我們剛看完諾蘭的大片《星際穿越》,設想如何讓機器來自動分析各位觀眾對電影的評價到底是“贊”(positive)還是“踩”(negative)呢?

這類問題就屬於情感分析問題。這類問題處理的第一步,就是將文字轉換為特徵。

因此,這章我們只學習第一步,如何從文字中抽取特徵,並將其向量化。

由於中文的處理涉及到分詞問題,本文用一個簡單的例子來說明如何使用Python機器學習庫,對英文進行特徵提取。

1、資料準備

Python的sklearn.datasets支援從目錄讀取所有分類好的文字。不過目錄必須按照一個資料夾一個標籤名的規則放好。比如本文使用的資料集共有2個標籤,一個為“net”,一個為“pos”,每個目錄下面有6個文字檔案。目錄如下所示:
neg
    1.txt
    2.txt
    ......

pos
    1.txt
    2.txt
    ....

12個檔案的內容彙總起來如下所示:

  1. neg:  
  2.     shit.  
  3.     waste my money.  
  4.     waste of money.  
  5.     sb movie.  
  6.     waste of time.  
  7.     a shit movie.  
  8. pos:  
  9.     nb! nb movie!  
  10.     nb!  
  11.     worth my money.  
  12.     I love this movie!  
  13.     a nb movie.  
  14.     worth it!  

2、文字特徵

如何從這些英文中抽取情感態度而進行分類呢?

最直觀的做法就是抽取單詞。通常認為,很多關鍵詞能夠反映說話者的態度。比如上面這個簡單的資料集,很容易發現,凡是說了“shit”的,就一定屬於neg類。

當然,上面資料集是為了方便描述而簡單設計的。現實中一個詞經常會有穆稜兩可的態度。但是仍然有理由相信,某個單詞在neg類中出現的越多,那麼他表示neg態度的概率越大。

同樣我們注意到有些單詞對情感分類是毫無意義的。比如上述資料中的“of”,“I”之類的單詞。這類詞有個名字,叫“Stop_Word“(停用詞)。這類詞是可以完全忽略掉不做統計的。顯然忽略掉這些詞,詞頻記錄的儲存空間能夠得到優化,而且構建速度也更快。

把每個單詞的詞頻作為重要的特徵也存在一個問題。比如上述資料中的”movie“,在12個樣本中出現了5次,但是出現正反兩邊次數差不多,沒有什麼區分度。而”worth“出現了2次,但卻只出現在pos類中,顯然更具有強烈的剛晴色彩,即區分度很高。

因此,我們需要引入TF-IDF(Term Frequency-Inverse Document Frequency,詞頻和逆向檔案頻率)對每個單詞做進一步考量。

TF詞頻)的計算很簡單,就是針對一個檔案t,某個單詞Nt 出現在該文件中的頻率。比如文件“I love this movie”,單詞“love”的TF為1/4。如果去掉停用詞“I"和”it“,則為1/2。

IDF逆向檔案頻率)的意義是,對於某個單詞t,凡是出現了該單詞的文件數Dt,佔了全部測試文件D的比例,再求自然對數。

比如單詞“movie“一共出現了5次,而文件總數為12,因此IDF為ln(5/12)。

很顯然,IDF是為了凸顯那種出現的少,但是佔有強烈感情色彩的詞語。比如“movie”這樣的詞的IDF=ln(12/5)=0.88,遠小於“love”的IDF=ln(12/1)=2.48。

TF-IDF就是把二者簡單的乘在一起即可。這樣,求出每個文件中,每個單詞的TF-IDF,就是我們提取得到的文字特徵值。

3、向量化

有了上述基礎,就能夠將文件向量化了。我們先看程式碼,再來分析向量化的意義:

  1. # -*- coding: utf-8 -*-
  2. import scipy as sp  
  3. import numpy as np  
  4. from sklearn.datasets import load_files  
  5. from sklearn.cross_validation import train_test_split  
  6. from sklearn.feature_extraction.text import  TfidfVectorizer  
  7. '''''載入資料集,切分資料集80%訓練,20%測試'''
  8. movie_reviews = load_files('endata')    
  9. doc_terms_train, doc_terms_test, y_train, y_test\  
  10.     = train_test_split(movie_reviews.data, movie_reviews.target, test_size = 0.3)  
  11. '''''BOOL型特徵下的向量空間模型,注意,測試樣本呼叫的是transform介面'''
  12. count_vec = TfidfVectorizer(binary = False, decode_error = 'ignore',\  
  13.                             stop_words = 'english')  
  14. x_train = count_vec.fit_transform(doc_terms_train)  
  15. x_test  = count_vec.transform(doc_terms_test)  
  16. x       = count_vec.transform(movie_reviews.data)  
  17. y       = movie_reviews.target  
  18. print(doc_terms_train)  
  19. print(count_vec.get_feature_names())  
  20. print(x_train.toarray())  
  21. print(movie_reviews.target)  
執行結果如下:

[b'waste of time.', b'a shit movie.', b'a nb movie.', b'I love this movie!', b'shit.', b'worth my money.', b'sb movie.', b'worth it!']
['love', 'money', 'movie', 'nb', 'sb', 'shit', 'time', 'waste', 'worth']
[[ 0.          0.          0.          0.          0.          0.   0.70710678  0.70710678  0.        ]
 [ 0.          0.          0.60335753  0.          0.          0.79747081   0.          0.          0.        ]
 [ 0.          0.          0.53550237  0.84453372  0.          0.          0.   0.          0.        ]
 [ 0.84453372  0.          0.53550237  0.          0.          0.          0.   0.          0.        ]
 [ 0.          0.          0.          0.          0.          1.          0.   0.          0.        ]
 [ 0.          0.76642984  0.          0.          0.          0.          0.   0.          0.64232803]
 [ 0.          0.          0.53550237  0.          0.84453372  0.          0.   0.          0.        ]
 [ 0.          0.          0.          0.          0.          0.          0.   0.          1.        ]]
[1 1 0 1 0 1 0 1 1 0 0 0]

python輸出的比較混亂。我這裡做了一個表格如下:


從上表可以發現如下幾點:

1、停用詞的過濾。

初始化count_vec的時候,我們在count_vec構造時傳遞了stop_words = 'english',表示使用預設的英文停用詞。可以使用count_vec.get_stop_words()檢視TfidfVectorizer內建的所有停用詞。當然,在這裡可以傳遞你自己的停用詞list(比如這裡的“movie”)

2、TF-IDF的計算。

這裡詞頻的計算使用的是sklearn的TfidfVectorizer。這個類繼承於CountVectorizer,在後者基本的詞頻統計基礎上增加了如TF-IDF之類的功能。

我們會發現這裡計算的結果跟我們之前計算不太一樣。因為這裡count_vec構造時預設傳遞了max_df=1,因此TF-IDF都做了規格化處理,以便將所有值約束在[0,1]之間。

3、count_vec.fit_transform的結果是一個巨大的矩陣。我們可以看到上表中有大量的0,因此sklearn在內部實現上使用了稀疏矩陣。本例子資料較小。如果讀者有興趣,可以試試機器學習科研工作者使用的真實資料,來自康奈爾大學:http://www.cs.cornell.edu/people/pabo/movie-review-data/。這個網站提供了很多資料集,其中有幾個2M左右的資料庫,正反例700個左右。這樣的資料規模也不算大,1分鐘內還是可以跑完的,建議大家試一試。不過要注意這些資料集可能存在非法字元問題。所以在構造count_vec時,傳入了decode_error = 'ignore',以忽略這些非法字元。

上表的結果,就是訓練8個樣本的8個特徵的一個結果。這個結果就可以使用各種分類演算法進行分類了。