文本自動分類
關于單個文本處理時間顯著增長的讨論
今天下午
使用了 stopwords 從網上搜了下 中文停用詞
并解決了 Python 中文顯示/輸入輸出的問題 line.decode('gbk')
__author__ = 'LiFeiteng'
# -*- coding: utf-8 -*-
import os
import jieba
import nltk
## 由搜狗語料庫 生成資料
folder_path = 'C:LIFEITENGSogouC.reduced\Reduced'
#folder_path = 'C:LIFEITENGSogouC.miniSample'
folder_list = os.listdir(folder_path)
class_list = [] ##由于亂碼等問題 僅以數字[0,1,...]來代表檔案分類
nClass = 0
N = 100 #每類檔案 最多取 50 個樣本 70%train 30%test
train_set = []
test_set = []
all_words = {}
import time
process_times = [] ## 統計處理每個檔案的時間
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
starttime = time.clock()
fobj = open(new_folder_path+'\'+file, 'r')
raw = fobj.read()
word_cut = jieba.cut(raw, cut_all=False)
word_list = list(word_cut)
for word in word_list:
if all_words.has_key(word):#if word in all_words.keys():
all_words[word] += 1
else:
all_words[word] = 0
if j > 0.3 * nFile:
train_set.append((word_list, class_list[i]))
else:
test_set.append((word_list, class_list[i]))
fobj.close()
j += 1
endtime = time.clock()
process_times.append(endtime-starttime)
print "Folder ",i,"-file-",j, "all_words length = ", len(all_words.keys()),
"process time:",(endtime-starttime)
## 根據word的詞頻排序
all_words_list = sorted(all_words.items(), key=lambda e:e[1], reverse=True)
## 由于亂碼的問題,沒有正确使用 stopwords;簡單去掉 前100個高頻項
## word_features 是選用的 word-詞典
stopwords_file = open('stopwords_cn.txt', 'r')
stopwords_list = []
for line in stopwords_file.readlines():
#print line.decode('gbk')
stopwords_list.append(line.decode('gbk')[:-2])
#print stopwords_list
def words_dict_no_use_stopwords(deleteN):
#dict_name = "dict_"+str(deleteN)+".txt"
#dict = open(dict_name, 'w')
n = 0
word_features = []
for t in range(deleteN, len(all_words), 1):
if n > 1000:
break
#print all_words_list[t][0]
#dict.writelines(str(all_words_list[t][0]))
#dict.writelines(' ')
n += 1
word_features.append(all_words_list[t][0])
return word_features
#dict.close()
def words_dict_use_stopwords(deleteN):
#dict_name = "dict_stopwords_"+str(deleteN)+".txt"
#dict = open(dict_name, 'w')
n = 0
word_features = []
for t in range(deleteN, len(all_words), 1):
if n > 1000:
break
#print all_words_list[t][0]
if all_words_list[t][0] not in stopwords_list and (not all_words_list[t][0].isdigit()):
#dict.writelines(str(all_words_list[t][0]))
#dict.writelines(' ')
n += 1
word_features.append(all_words_list[t][0])
return word_features
#dict.close()
def document_features(document):
document_words = set(document)
features = {}
for word in word_features: ## 根據詞典生成 每個document的feature True or False
features['contains(%s)' % word] = (word in document_words)
return features
def TextClassification():
## 根據每個document 分詞生成的 word_list 生成 feature
train_data = [(document_features(d), c) for (d,c) in train_set]
test_data = [(document_features(d), c) for (d,c) in test_set]
print "train number:",len(train_data),"
test number:",len(test_data)
## 樸素貝葉斯分類器
classifier = nltk.NaiveBayesClassifier.train(train_data)
test_error = nltk.classify.accuracy(classifier, test_data)
print "test accuracy:", test_error
return test_error
deleteNs = range(0, 1000, 20)
test_errors_no_use = []
test_errors_use = []
for n in deleteNs:
word_features = words_dict_no_use_stopwords(n)
test_error = TextClassification()
test_errors_no_use.append(test_error)
word_features = words_dict_use_stopwords(n)
test_error = TextClassification()
test_errors_use.append(test_error)
## 處理每個檔案所用的時間 可見到後面 處理單個檔案的時間顯著增長
## 原因 已查明
import pylab
plot1 = pylab.plot(deleteNs, test_errors_no_use)
plot2 = pylab.plot(deleteNs, test_errors_use)
pylab.legend(('no use stopwords', 'using stopwords'), 'best')
#pylab.xlabel("no using stopwords")
pylab.show()
對資料的處理:
由于沒有事先的詞典dict
我的處理方法是:把所有文檔的分詞結果放到一個 dictionary裡面,然後根據詞頻從高到低 排序
由于處理每個文檔的時候,就沒有去除一些雜亂資訊,比如标點符号,無意義的數字等
是以 在試驗中 構造最終詞典(固定選取1000個詞)的時候 逐漸去除詞典的部分高頻項,觀察正确率的變化
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICdzFWRoRXdvN1LclHdpZXYyd2LcBzNvwVZ2x2bzNXak9CX90TQNNkRrFlQKBTSvwFbslmZvwFMwQzLcVmepNHdu9mZvwFVywUNMZTY18CX052bm9CX9EEWk5WNXpFMsdlWHx2RUZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39zM0gTOzkzM4ETOwATMzEDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
(圖像:縱軸代表分類9個文檔的正确率,橫軸-去除高頻項的個數(0::20::1000),綠線-使用停用詞的正确率)
從測試準确率圖像中可以看到此舉 在初期還是有顯著效果的 當去除更多高頻詞彙的資料時 正确率又會顯著下降
這跟理論分析是符合的——應該觀察排序後的字典,深入到資料中去
同時也可看到 使用停用詞 在前半段 争取率有不錯的提升
==========================================================
1.應該在 處理每個文本的時候 應該去除一些雜亂資訊 減少記憶體占用等
2.如果在事先有 詞典的情況下 可以直接提取文本特征
3.沒有詞典的時候, 程式員應該自己 構造詞典 甚至在大量樣本中 學習詞典
4.特征維數的選取 在本文中固定 1000 維,可以做做 正确率關于維數的變化
5.特别說明:因為 分類器用的是 樸素貝葉斯 是以文本特征是 [TRUE, FALSE, ...] 文本是否包含字典中詞的判别
p(feature_i | C_k) = ... 見文本自動分類 貝葉斯介紹部分
如果是使用 SVM softmax等 那麼特征應該是 詞頻 或者 TDIDF等