1. 程式人生 > 其它 >基於Kaggle資料的詞袋模型文字分類教程

基於Kaggle資料的詞袋模型文字分類教程

本教程展示了改善文字分類的方法,包括:做一個驗證集,為AUC預測概率,用線性模型代替隨機森林,使用TF-IDF權衡詞彙,留下停用詞,加上二元模型或者三元模型等。

有一個Kaggle的訓練比賽,你可以嘗試進行文字分類,特別是電影評論。沒有其他的資料——這是使用文字分類做一些實驗的絕佳機會。

Kaggle有一個關於本次比賽的tutorial,( https://www.kaggle.com/c/word2vec-nlp-tutorial/details/part-1-for-beginners-bag-of-words )它會帶你走進流行的詞袋方法以及word2vec。本教程幾乎代表了最佳實踐,最有可能讓參賽選手的優化變得很容易。而這正是我們要做的。

驗證

驗證是機器學習的基石。這是因為我們之後會推廣到未知的測試例項。通常,評估一個模型推廣的唯一明智方式是使用驗證:如果你有足夠的例子,你可以進行單一訓練、驗證分割;又或者如果你有幾個訓練點,你可以進行計算上更昂貴但卻很有必要的交叉驗證。

一點題外話:在不少Kaggle比賽,來自不同分佈而不是訓練集的一組測試,意味著它甚至很難成為代表性的驗證集。這是一個挑戰還是愚蠢的行為,取決於你的觀點。

為了激勵驗證的需求,讓我們回顧百度團隊參加ImageNet比賽的情況。這些人顯然不理解驗證,所以他們不得不求助於排行榜來評估自己的努力。ImageNet每週只允許兩次提交,所以他們創造了許多假賬戶來拓展他們的頻寬。不幸的是,主辦方不喜歡這樣的方法,而百度也因此陷入尷尬。

驗證分割

我們的第一個步驟是通過啟用驗證來修改原始教程程式碼。因此,我們需要分割訓練集。既然我們有25,000個訓練例子,我們將取出5,000個進行測試,並留下20,000個進行培訓。一種方法是將一個培訓檔案分割成兩個——我們從phraug2中使用split.py指令碼:

python split.py train.csv train_v.csv test_v.csv -p 0.8 -r dupa

使用隨機種子“Dupa”來實現再現。Dupa是用於這樣場合的波蘭碼字。我們下面報告的結果是基於這種分割。

訓練集是相當小的,所以另一種方式是載入整個訓練檔案到記憶體中並把它分割,然後,使用scikit-learn為此類任務提供的好工具:

from sklearn.cross_validation import train_test_split
train, test = train_test_split( data, train_size = 0.8, random_state = 44 )

我們提供的指令碼使用這種機制以便使用,而不是單獨的訓練、測試檔案。我們需要使用索引因為我們正在處理Pandas框架,而不是Numpy陣列:

all_i = np.arange( len( data ))
train_i, test_i = train_test_split( all_i, train_size = 0.8, random_state = 44 )

train = data.ix[train_i]
test = data.ix[test_i]

度量標準

競爭的度量標準是AUC,它需要概率。出於某種原因,Kaggle教程只預測0和1。這是很容易解決:

p = rf.predict_proba( test_x )
auc = AUC( test_y, p[:,1] )

而且我們看到,隨機森林成績大約為91.9%。

詞袋的隨機森林?不

隨機森林是一個強大的通用方法,但它不是萬能的,對於高維稀疏資料並不是最好的選擇。而BoW表示是高維稀疏資料的一個很好例子。

此前我們覆蓋了詞袋,例如A bag of words and a nice little network。在那篇文章中,我們使用了神經網路進行分類,但事實是簡約的線性模型往往是首選。我們將使用邏輯迴歸,因為現在留下超引數作為預設值。

邏輯迴歸的驗證AUC是92.8%,並且它比隨機森林的訓練快得多。如果你打算從這篇文章學點東西:對於高維稀疏資料使用線性模型,如詞袋。

TF-IDF

TF-IDF即“術語頻率/倒排文件頻率(term frequency / inverse document frequency)”,是這樣一種方法:用於強調給定文件中的高頻詞彙,而不再強調出現在許多文件中的高頻詞彙。

我們TfidfVectorizer和20,000個特徵的得分是95.6%,有很大的改進。

停用詞和N-grams

Kaggle教程的作者認為有必要去除停用詞(Stopwords)。停用詞即commonly occuring words,比如“this”,“that”,“and”,“so”,“on”。這是一個很好的決定嗎?我們不知道,我們需要檢驗,我們有驗證集,還記得嗎?留下停用詞的得分為92.9%(在TF-IDF之前)。

反對移除停用詞的一個更重要的原因是:我們想嘗試n-grams,並且對於n-grams我們最好讓所有詞留在原地。我們之前涵蓋了n-grams,它們由n個連續的詞組合在一起,使用二元模型開始(兩個詞):“cat ate”,“ate my”,“my precious”,“precious homework”。三元模型由三個片語成:“cat ate my”,“ate my homework”,“my precious homework”;四元模型,等等。

為什麼n-grams能夠work?想想這句話:“movie not good”。它有明顯的負面情緒,但是如果你把每個單詞都分離,你將不會檢測這一點。相反,該模型可能會了解到,“good”是一個積極的情緒,這將不利於判斷。

在另一方面,二元模型可以解決問題:模型可能會了解到,“not good”有負面情緒。

使用來自斯坦福大學情感分析頁面的更復雜的例子:

This movie was actually neither that funny, nor super witty.

對於這個例子,二元模型將在“that funny”和“super witty”上失敗。我們需要至少三元模型來捕捉“neither that funny”和“nor super witty”,然而這些短語似乎並不太常見,所以,如果我們使用的特徵數量有限,或正規化,他們可能不會讓它進入到模型。因此,像神經網路一樣的更復雜的模型的動因會使我們離題。

如果計算n-grams聽起來有點複雜,scikit-learn量化能夠自動地做到這一點。正如Vowpal Wabbit可以,但我們不會在這裡使用Vowpal Wabbit。

使用三元模型的AUC得分為95.9%。

維度

每個字都是一個特徵:它是否出現在文件中(0/1),或出現多少次(大於等於0的整數)。我們從教程中開始原始維數,5000。這對隨機森林很有意義,這是一個高度非線性的、有表現力的、高差異的分類,需要一個配給相對比較高的例子用於維數。線性模型在這方面不太苛求,他們甚至可以在d>>n的情況下work。

我們發現,如果我們不限制維數,即使這樣一個小的資料集也會使我們耗盡記憶體。我們可以在12 GB RAM的機器上帶動大約40,000個特徵。甚至引起交換。

對於初學者來說,我們嘗試20,000個特徵。邏輯迴歸分數為94.2%(在TF-IDF和n-grams之前),與5,000個特徵的得分92.9%進行比較。更多的分數甚至更好:30,000個特徵的得分96.0%,40,000個特徵的得分96.3%(在TF-IDF和n-grams之後)。

為了解決記憶體問題,我們可以使用hashing vectorizer。然而,相對於之前的96.3%,它只得到了93.2%的分數,部分原因是它不支援TF-IDF。

結語

我們展示了改善文字分類的方法:

  • 做一個驗證集
  • 為AUC預測概率
  • 用線性模型代替隨機森林
  • 使用TF-IDF權衡詞彙
  • 留下停用詞
  • 加上二元模型或者三元模型

公眾排行榜得分反映了驗證得分:都大約是96.3%。在提交的時候,它在500名參賽者中足夠進入前20名。

你可能還記得,我們留下了線性迴歸的超引數作為預設值。此外,向量化有它自己的引數,你可可期望更實際些。微調它們的結果有一個適量的改善,達到96.6%。

UPDATE:Mesnil,Mikolov,Ranzato和Bengio有一篇情感分類的paper:Ensemble of Generative and Discriminative Techniques for Sentiment Analysis of Movie Reviewscode)。他們發現,使用n-gram的線性模型優於遞迴神經網路(RNN)和使用句子向量的線性模型。

然而,他們使用的資料集(Stanford Large Movie Review Dataset)比較小,有25,000個訓練例項。Alec Radford 表示,在樣本數量較大,大致從100,000到1000,000,RNN開始優於線性模型。

Credit: Alec Radford / Indico, Passage example

對於句子向量,作者用邏輯迴歸分析法。我們寧願看到100維向量送入非線性模型隨機森林。

這樣,我們卑微地發現隨機森林的分數只是85-86 %(奇怪……為什麼?),這取決於樹的數量。該paper準確地說,邏輯迴歸的精度大約為89%。