2010-06-24 63 views
29

我已經有大約300k個文檔存儲在Postgres數據庫中,並且標記了主題類別(共有大約150個類別)。我還有另外150k文件還沒有分類。我試圖找到對它們進行編程分類的最佳方法。將文檔分類爲

我一直在探索NLTK及其樸素貝葉斯分類器。看起來像一個很好的起點(如果你可以提出一個更好的分類算法來完成這項任務,我就會全神貫注)。

我的問題是,我沒有足夠的RAM來一次訓練所有150種類/ 300k文檔的NaiveBayesClassifier(使用8GB的5個類別的培訓)。此外,當我訓練更多類別時,分類器的準確性似乎下降(2類爲準確率爲90%,5類爲81%,10爲61%)。

我應該一次只訓練5個類別的分類器,並通過分類器運行所有150k文檔以查看是否有匹配?看起來這樣會起作用,除非會有很多誤報,其中文檔與任何類別都不匹配的文檔只是因爲它是可用的最佳匹配纔會被分類器使用。只有在文檔不適合任何類別的情況下,才能爲分類器提供「以上都不是」選項?

這裏是我的測試類http://gist.github.com/451880

+0

也許一個在線/增量培訓模式將解決記憶問題:http://en.wikipedia.org/wiki/Online_machine_learning – Amro 2010-06-25 20:45:11

回答

30

您應該先將文檔轉換爲TF-log(1 + IDF) vectors:術語頻率很稀疏,因此您應該使用帶有術語作爲鍵的python dict並將其計爲值,然後除以總數以獲得全局頻率。

另一種解決方案是使用abs(散列(term))作爲正整數鍵。然後你使用scipy.sparse向量,它比python dict更方便,更有效地執行線性代數運算。

還通過平均屬於同一類別的所有標籤文檔的頻率來構建150個頻率向量。然後,爲了標記新文檔,您可以計算文檔向量和每個類別向量之間的cosine similarity,併爲文檔選擇與標籤最相似的類別。

如果這還不夠好,那麼你應該嘗試使用L1懲罰來訓練邏輯迴歸模型,如scikit-learnthis example中所解釋的(這是libphe的解釋器,如@ephes所解釋的)。用於訓練邏輯迴歸模型的向量應該是先前引入的TD-log(1 + IDF)向量以獲得良好性能(精度和回憶)。 scikit學習庫提供了一個sklearn.metrics模塊,其中包含用於計算給定模型和給定數據集的分數的例程。

對於較大的數據集:你應該嘗試vowpal wabbit這可能是世界上最快的兔子,用於大規模文檔分類問題(但不容易使用python包裝AFAIK)。

+2

Vowpal wabbit速度很快。但是我們仍然使用批量訓練而不是在線學習算法,因爲liblinear(正確優化)只需幾分鐘就可以處理數百萬個文檔(我們對特徵向量進行了縮放(共享),以便新的訓練或分類過程不必解析但只能遍歷主內存),它的性能更好(我現在沒有數字......)。 – ephes 2010-06-24 22:13:42

+2

同意,vowpal wabbit在數據流無限且不再適合內存時非常有趣,例如當來自流行的網絡郵件提供商的「報告垃圾郵件」按鈕:) – ogrisel 2010-06-24 22:19:17

+2

除此之外......質心分類並不比樸素貝葉斯好得多。這篇文章http://www2009.org/proceedings/pdf/p201.pdf是錯誤的。我們告訴他們,他們使用測試數據進行培訓(由於錯誤),但討論沒有進行......線性SVM仍然是最先進的。 – ephes 2010-06-24 22:19:52

2

有沒有辦法有一個選項分類「的 以上都不是」剛 的情況下,該文件不適合 任何類別的?

只要每次都訓練一個「以上都不是」的僞類別,就可能會產生這種效果。如果你可以訓練的最大值是5類(儘管我不確定它爲什麼會吃掉相當多的RAM),那麼從它們的實際2K文檔中分別訓練出4個實際的類別,並且在它們的2K文檔中「沒有上述」從所有其他146個類別中隨機抽取(如果您想採用「分層抽樣」方法,可能會更加穩定),每個類別大約13-14個。

仍然覺得有點混亂,你可能會用完全不同的方法更好 - 找到一個多維文檔度量,將你的300K預標籤文檔定義爲150個合理分離的集羣,然後分配每個集合將其他尚未加標籤的文檔轉換爲如此確定的適當集羣。我不認爲NLTK有任何東西可以直接支持這種事情,但是,嘿,NLTK的增長速度如此之快以至於我可能錯過了某些東西... ;-)

+0

我們有一個特殊類別的文件,我們知道我們無法正確分類。這有點混雜,但效果很好。 – ephes 2010-06-24 20:51:38

11

有多大(單詞數)你的文件是?內存消耗在150K trainingdocs不應該是一個問題。

樸素貝葉斯是一個很好的選擇,特別是當你有很多類別只有少數訓練樣例或非常嘈雜的訓練數據時。但總的來說,線性支持向量機的表現要好得多。

是你的問題多類(一個文件只屬於一個類別)還是多標籤(一個文件屬於一個或多個類別)?

準確度是判斷分類器性能的一個糟糕的選擇。您應該使用精確度與回憶率,精確回憶平衡點(prbp),f1,auc,並且必須查看基於您的置信度閾值的值繪製召回(x)與精度(y)的精度vs回憶曲線(文件是否屬於某個類別)。通常情況下,您將爲每個類別構建一個二元分類器(一個類別的正面訓練示例與不屬於您當前類別的所有其他訓練示例)。您必須選擇每個類別的最佳置信度閾值。如果要將每個類別的單個度量結合到一個全局性能度量中,則必須微調(總結所有真正的肯定結果,假陽性結果,假陰性結果和真陰性結果以及計算結合得分)或宏觀結果(每個類別的計算結果分數和然後平均所有類別的這些分數)平均值。

我們擁有數百萬份文檔,數百萬訓練樣本和數千個類別(多標籤)的語料庫。由於我們面臨嚴重的培訓時間問題(文件數量是新的,每天更新或刪除的文件數量相當高),因此我們使用liblinear的修改版本。但對於使用liblinear(liblinear2scipyscikit-learn)之一的python包裝的小問題應該可以正常工作。

+0

平均文檔大約500-1000字。 這些文件可以是「多標籤」。 – erikcw 2010-06-24 22:07:16

+1

好的,然後去@grorisel(我忘了提及)建議的稀疏tfidf向量和每個類別一個二進制分類器。也許你在文檔中有一些非序號(數字)特徵 - 你必須適當地裝入它們。 – ephes 2010-06-24 23:26:04

+0

您使用的是liblinear的修改版本嗎?或者你自己修改了什麼? – 2010-06-24 23:58:10