1. 程式人生 > >文字分類全過程實現

文字分類全過程實現

    最近在做文字分類方面的內容,之前接觸資料探勘的演算法比較多一點,對自然語言處理領域基本上沒有接觸過。在做這一部分的內容的時候也是花了一些精力。用了一週的時間,將整個過程實現了一遍。我還是屬於這個領域的菜鳥,這篇博文主要是想把我這周的成果整理記錄一下,廢話不多說,切入正題。
    我用的是網路上搜狗新聞分類的資料集,一共九個類,每個類有2000條語料,資料量還是比較大的。首先我們需要將文件中的語料一一讀入到程式中 。因為資料量很大,所以我們每個類別取100條語料進行驗證,對讀入的每篇語料進行切詞處理,這裡我使用的是jieba分詞,對切詞後的結果去除停留詞以及文中的數字,同時按照8:2的比例切分訓練集與測試集。程式碼如下:
import os
import  jieba
import sklearn
import sys
import  numpy as np
from sklearn.metrics import accuracy_score
from sklearn.metrics import recall_score
from sklearn.feature_extraction.text import  CountVectorizer
from sklearn.naive_bayes import MultinomialNB
reload(sys)
sys.setdefaultencoding('utf8'
) stopwords_file=open('D:\stopwords.txt','r')#讀入停詞表 stopwords=[] for line in stopwords_file.readlines(): stopwords.append(line.rstrip())#形成停用詞列表 folder_path = 'D:\SogouC.reduced\Reduced' folder_list = os.listdir(folder_path) class_list = [] #我們用[0,1,...]代表分類 nClass = 0 N = 100 # 每類檔案 最多取 100 個樣本 train_set = []#訓練集
test_set = []#測試集 train_lable=[]#訓練集類別標籤 test_lable=[]#測試集類別標籤 for i in range(len(folder_list)): new_folder_path = folder_path + '\\' + folder_list[i] files = os.listdir(new_folder_path) class_list.append(nClass) nClass += 1 j = 0 nFile =min(len(files),N) for file in files: if j > N: break fobj = open(new_folder_path + '\\' + file, 'r') raw = fobj.read() word_cut = jieba.cut(raw, cut_all=False) word_list = list(word_cut) word_txt_features = [] for word in word_list: if word not in stopwords and not word.isdigit(): word_txt_features.append(word) if j < 0.8 * nFile: train_set.append(" ".join(word_txt_features)) #這裡將每個詞用空格連結,為了之後使用TFIDF處理資料方便 train_lable.append(class_list[i]) else: test_set.append(" ".join(word_txt_features )) test_lable.append(class_list[i]) fobj.close() j += 1

OK,上面已經把資料處理好,現在我們有了訓練集和測試集以及相應的類標籤。通過程式碼也能看出,資料集的格式基本上是:每行代表某個類目錄下的一個txt文字切詞等處理後的資料。下面我們的任務就是提取特徵詞。特徵詞的提取方法有很多,這裡我選用了TFIDF的方法。計算出詞向量權重矩陣。這一步我們會碰到測試集與訓練集的詞向量矩陣維度不同的問題,所以這裡我參考了一篇博文,裡面有解決這個問題的多種方法。程式碼如下:

count_v1= CountVectorizer(stop_words = None, max_df = 0.5)
counts_train = count_v1.fit_transform(train_set)
count_v2 = CountVectorizer(vocabulary=count_v1.vocabulary_)
counts_test = count_v2.fit_transform(test_set);
tfidftransformer = sklearn.feature_extraction.text.TfidfTransformer()
tfidf_train = tfidftransformer.fit(counts_train).transform(counts_train);
tfidf_test = tfidftransformer.fit(counts_test).transform(counts_test);
train_data=tfidf_train.toarray()
test_data=tfidf_test.toarray()
train_lab=np.array(train_lable)
test_lab=np.array(test_lable)

這樣我們就形成了測試集和測試集詞向量矩陣。接下來分類演算法要登場了,我選擇了比較大眾化的多項式貝葉斯分類器,它的輸入都是矩陣形式的資料。實現程式碼比較簡單,我用的是sklearn庫中的MultinomialNB,sklearn庫很強大,還需要繼續學習。在自然語言處理中還可以用nltk庫,裡面也有分類演算法的函式,不過我對這個庫接觸不多,函式中的引數我還沒怎麼研究過,有時間再補充。

clf=MultinomialNB().fit(train_data,train_lab)
doc_class_predicted=clf.predict(test_data)
print (np.mean((doc_class_predicted==test_lable)))#計算準確率

最後結果如下:
這裡寫圖片描述

準確率在88.9%左右,列表裡存放的是預測的類別標籤。可以看得出大部分類別預測準確率在90%左右。

做完之後我總結了一下存在的問題:
1.維度太大。900條語料在經過切詞,去停留詞處理後,經過TFIDF得到的矩陣維度比較大。測試集[189L,41758L],訓練集為[720L,41758L].因此程式執行時時間消耗非常大,第一次執行用了1小時。所以後面要找到有效降維的方法。我看到網路上有人用CHI,基本原理能瞭解,如果有實現過的博友希望能交流一下。
2.準確率有待進一步提高。影響準確率的方面很多,可能是分類模型的選擇,特徵詞的選擇等等,希望能再多次修改過程,能夠得到比較樂觀的準確率。
3.程式最後我也計算了召回率與精確率,很疑惑的是他們的值都是跟之前計算的準確率一樣的,這個很不應該,但實在不知道哪裡出現了錯誤。希望博友友情指導一下。

accuracy=accuracy_score(test_lab,doc_class_predicted)
print accuracy
print recall_score(test_lab,doc_class_predicted,average='macro')

這裡寫圖片描述