[Scikit-learn教程] 文本處理:分類與優化
首發於集智(https://jizhi.im): [Scikit-learn教程] 03.02 文本處理:分類與優化 - 集智博客
原文代碼可在線調試運行,知乎版就湊合看吧。
回顧
上一節我們通過Scikit-learn提供的多種方法從網路以及硬碟獲取到了原始的文本數據,並採用tf-idf方法成功地提取了文本特徵,你可以從下面的例子中再次複習這一過程。
from sklearn.datasets import load_filesfrom sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer# 選取參與分析的文本類別categories = ["alt.atheism", "soc.religion.christian", "comp.graphics", "sci.med"]# 從硬碟獲取原始數據twenty_train=load_files("/mnt/vol0/20news-bydate-train", categories=categories, load_content = True, encoding="latin1", decode_error="strict", shuffle=True, random_state=42)# 統計詞語出現次數count_vect = CountVectorizer()X_train_counts = count_vect.fit_transform(twenty_train.data)# 使用tf-idf方法提取文本特徵tfidf_transformer = TfidfTransformer()X_train_tfidf = tfidf_transformer.fit_transform(X_train_counts)# 列印特徵矩陣規格print(X_train_tfidf.shape)
本節我們將在完成特徵提取工作的基礎上,繼續完成文本信息挖掘的下一步——訓練並優化分類器。
訓練分類器
可以用於文本分類的機器學習演算法有很多,樸素貝葉斯演算法(Na?ve Bayes)就是其中一個優秀代表。Scikit-learn包含了樸素貝葉斯演算法的多種改進模型,最適於文本詞數統計方面的模型叫做多項式樸素貝葉斯(Multinomial Na?ve Bayes),它可以通過以下的方式來調用。
from sklearn.naive_bayes import MultinomialNBclf = MultinomialNB().fit(X_train_tfidf, twenty_train.target)print("分類器的相關信息:")print(clf)
這樣就完成了一個分類器的訓練過程。為了使用一個新文檔來進行分類器的分類預測工作,我們必須使用同樣的數據處理手段處理我們的新文檔。如下面的例子所示,我們使用了一組自定義的字元串,用來判斷它們的分類情況。字元串組必須經過transform方法的處理才能進行預測。
# 預測用的新字元串,你可以將其替換為任意英文句子docs_new = ["Nvidia is awesome!"]# 字元串處理X_new_counts = count_vect.transform(docs_new)X_new_tfidf = tfidf_transformer.transform(X_new_counts)# 進行預測predicted = clf.predict(X_new_tfidf)# 列印預測結果for doc, category in zip(docs_new, predicted): print("%r => %s" % (doc, twenty_train.target_names[category]))
作為受西方理論指導的一種基礎的機器學習演算法,樸素貝葉斯雖然很簡單,有時候很樸素,但是它的運行速度非常的快,效果也非常的理想,能夠跟很多更複雜的演算法相提並論。
建立Pipeline

from sklearn.pipeline import Pipeline# 建立Pipelinetext_clf = Pipeline([("vect", CountVectorizer()), ("tfidf", TfidfTransformer()), ("clf", MultinomialNB()),])# 訓練分類器text_clf = text_clf.fit(twenty_train.data, twenty_train.target)# 列印分類器信息print(text_clf)
使用測試數據評估分類器性能
我們可以採用上述的方法對測試數據集進行預測,然後使用Numpy所提供的函數得到評測結果:
import numpy as np# 獲取測試數據twenty_test=load_files("/mnt/vol0/20news-bydate-test", categories=categories, load_content = True, encoding="latin1", decode_error="strict", shuffle=True, random_state=42)docs_test = twenty_test.data# 使用測試數據進行分類預測predicted = text_clf.predict(docs_test)# 計算預測結果的準確率print("準確率為:")print(np.mean(predicted == twenty_test.target))
如果正常運行上述代碼,我們應該可以得到83.4%的準確率。我們有很多辦法來改進這個成績,使用業界公認的最適於文本分類的演算法——支持向量機(SVM,Support Vector Machine)就是一個很好的方向(雖然它會比樸素貝葉斯稍微慢一點)。我們可以通過改變Pipeline中分類器所指定的對象輕鬆地實現這一點:
from sklearn.linear_model import SGDClassifiertext_clf = Pipeline([("vect", CountVectorizer()), ("tfidf", TfidfTransformer()), ("clf", SGDClassifier(loss="hinge", penalty="l2", alpha=1e-3, n_iter=5, random_state=42)), ])_ = text_clf.fit(twenty_train.data, twenty_train.target)predicted = text_clf.predict(docs_test)print("準確率:")print(np.mean(predicted == twenty_test.target))
我們可以看到,相對於樸素貝葉斯,SVM方法得到的準確率有了很大的進步。
Scikit-learn提供了更多的評測工具來更好地幫助我們進行分類器的性能分析,如下所示,我們可以得到預測結果中關於每一種分類的準確率、召回率、F值等等以及它們的混淆矩陣。
from sklearn import metricsprint("列印分類性能指標:")print(metrics.classification_report(twenty_test.target, predicted, target_names=twenty_test.target_names))print("列印混淆矩陣:")metrics.confusion_matrix(twenty_test.target, predicted)
不出所料,通過混淆矩陣我們可以發現,相對於計算機圖形學(comp.graphics),與無神論(alt.atheism)以及基督教(soc.religion.christian)相關的兩種分類更難以被區分出來。

使用網格搜索來進行參數優化
我們已經了解了很多機器學習過程中所遇到的參數,比如TfidfTransformer中的use_idf。分類器往往會擁有很多的參數,比如說樸素貝葉斯演算法中包含平滑參數alpha,SVM演算法會包含懲罰參數alpha以及其他一些可以設置的函數。
為了避免調整這一系列參數而帶來的繁雜工作,我們可以使用網格搜索方法來尋找各個參數的最優值。如下面的例子所示,我們可以在採用SVM演算法建立分類器時嘗試設置如下參數:使用單詞或是使用片語、使用IDF或是不使用IDF、懲罰參數為0.01或是0.001。
from sklearn.grid_search import GridSearchCV# sklearn 0.18.1 版本請使用以下方式導入網格搜索庫# from sklearn.model_selection import GridSearchCV# 設置參與搜索的參數parameters = {"vect__ngram_range": [(1, 1), (1, 2)], "tfidf__use_idf": (True, False), "clf__alpha": (1e-2, 1e-3),}# 構建分類器gs_clf = GridSearchCV(text_clf, parameters, n_jobs=-1)print(gs_clf)
很明顯,逐個進行這樣一個搜索過程會消耗較大的計算資源。如果我們擁有一個多核CPU平台,我們就可以並行計算這8個任務(每個參數有兩種取值,三個參數共有23=823=8個參數組合),這需要我們修改n_jobs這個參數。如果我們設置這個參數的值為-1,網格搜索過程將會自動檢測計算環境所存在的CPU核心數量,並使用全部核心進行並行工作。
一個具體的網格搜索模型與普通的分類器模型一致,我們可以使用一個較小的子數據塊來加快模型的訓練過程。對GridSearchCV對象調用fit方法之後將得到一個與之前案例類似的分類器,我們可以使用這個分類器來進行預測。
# 使用部分訓練數據訓練分類器gs_clf = gs_clf.fit(twenty_train.data[:400], twenty_train.target[:400])# 查看分類器對於新文本的預測結果,你可以自行改變下方的字元串來觀察分類效果twenty_train.target_names[gs_clf.predict(["An apple a day keeps doctor away"])[0]]
分類器同時包含best_score_和best_params_兩個屬性,這兩個屬性包含了最佳預測結果以及取得最佳預測結果時的參數配置。當然,我們也可以瀏覽gs_clf.cv_results_來獲取更詳細的搜索結果(這是sklearn 0.18.1版本新加入的特性),這個參數可以很容易地導入到pandas中進行更為深入的研究。
gs_clf = gs_clf.fit(twenty_train.data[:400], twenty_train.target[:400])print("最佳準確率:%r" % (gs_clf.best_score_))for param_name in sorted(parameters.keys()): print("%s: %r" % (param_name, gs_clf.best_params_[param_name]))
小結
至此,我們已經完整實踐了一個使用機器學習方法進行文本分類工作的全過程,我們了解了從網路獲取數據並進行讀取、清洗原始數據並提取特徵向量、使用不同演算法來構建分類器、並使用網格搜索方法來進行參數調優等有監督機器學習中較為常見的各個知識點。關於更為複雜的一些問題,比如中文文本處理、文本聚類分析等等,我們將在之後的文章中進行討論。
原文地址:[Scikit-learn教程] 03.02 文本處理:分類與優化 - 集智博客
系列首篇:[Scikit-learn教程] 01 快速入門 - 集智博客
交流群組:557373801
歡迎有意向成為合作作者的朋友與我聯繫。
推薦閱讀:
