文字分類全過程實現
最近在做文字分類方面的內容,之前接觸資料探勘的演算法比較多一點,對自然語言處理領域基本上沒有接觸過。在做這一部分的內容的時候也是花了一些精力。用了一週的時間,將整個過程實現了一遍。我還是屬於這個領域的菜鳥,這篇博文主要是想把我這周的成果整理記錄一下,廢話不多說,切入正題。 我用的是網路上搜狗新聞分類的資料集,一共九個類,每個類有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')