石鳳貴
(馬鞍山師范高等專科學校軟件工程系,馬鞍山243041)
隨著互聯(lián)網(wǎng)的快速發(fā)展,數(shù)據(jù)成爆炸式增長。大數(shù)據(jù)時代,需要對數(shù)據(jù)進行科學組織和管理,對于文本數(shù)據(jù)更需要如此。文本分類可以有效對文本數(shù)據(jù)進行分類管理,它是處理自然語言的基礎。文本分類主要包括文本預處理、詞向量、特征降維、分類算法等。文本分類技術的發(fā)展經(jīng)歷了基于向量空間模型、知識工程、統(tǒng)計和機器學習的發(fā)展。目前,文本分類主要通過機器學習相關算法從語料庫中挖掘出有效的分類規(guī)則,構建模型,利用訓練集訓練模型,從而得到分類模型。
文本分類根據(jù)任務不同可以分為問題分類、主題分類、情感分類等。本文介紹了TF-IDF及文本分類相關技術,并根據(jù)旅游領域語料采用Python實現(xiàn)了文本分類。
文本分類指采用文本分類算法對文本集中文本自動標注,分類過程類似于數(shù)學中做映射。假設有文本集合T和類別集C[1]:
C={c1,c2,…,cj,…,cn},其中cj表示第j個類別,n為類別數(shù)。
文本分類過程包括文本預處理、特征提取、分類模型訓練、模型應用。文本分類方法包括無監(jiān)督分類、半監(jiān)督分類和監(jiān)督分類。
處理文本數(shù)據(jù)前需要對文本數(shù)據(jù)進行分詞、去停用詞、關鍵詞提取等處理。中文文本中詞與詞之間沒有明顯的分隔符,為有效理解文本,第一步需要進行分詞。中文分詞算法主要有基于字符串匹配、基于理解和基于統(tǒng)計。分詞結果中含有許多對表達句子意思沒有實際意義的噪音詞,這些噪音詞應作為停用詞去除,同時提取對句子意思具有決定意義詞[2]。
詞是句子語義的最小單位,句子需要切分由詞構成的集合,為后續(xù)對句子進行分析處理和理解奠定基礎。英文語句中詞與詞之間有明顯的分隔符,中文語句中詞之間沒有明顯的分隔標志,切分時需要根據(jù)語義,另外中文詞在句子中的前后關系復雜,不同詞在不同的語境中意義不同,因此中文分詞難度較大。本文分詞采用當前廣泛使用的基于Python的中文分詞工具jieba,jieba中文分詞工具內(nèi)置多個算法,支持多種模式進行分詞,能有效解決未登陸詞和歧義詞,準確率高達97%,召回率高達90%。
去停用詞可以降低句子噪音對句子的理解,減少特征詞的數(shù)量,從而提高文本分類的準確性。如果英語中the、is、at、who等,中文中的在、的、和等副詞、量詞、介詞、嘆詞、數(shù)詞等詞,這些對理解語句沒有實際意義,而且出現(xiàn)頻率較高,容易造成噪音,分詞后應從分詞結果中將這些停用詞進行過濾。去停用詞只要建立停用詞表,然后采用字符匹配的方式掃描分詞詞典進行刪除。
文本是一種字符序列,由詞和短語構成。計算機要理解文本,首先需要將文本轉(zhuǎn)化為機器可以識別的數(shù)據(jù)——詞向量,然后輸入給模型進行訓練。模型其實就是數(shù)學模型在機器中的表示,稱為計算模型。
Word2vec是一種經(jīng)典詞向量模型,結合了哈夫曼編碼。通過對模型的訓練可以降低詞向量維度,獲得定長連續(xù)的詞向量。通過計算兩個向量距離余弦值來計算兩個向量所表示的詞的相似度[1]。
特征降維是文本處理的關鍵環(huán)節(jié),包括特征選擇和特征提取。傳統(tǒng)的的分類算法具有較高的維度,如詞袋模型和空間向量模型,這些模型時間和空間復雜度較高,缺乏有效的關聯(lián)。特征選擇指對現(xiàn)有的特征空間篩選重要的特征重新組成新的特征集,能有效提高文本分類的準確率。特征抽取指對當前特征空間進行變換壓縮生成新的語義空間,可以一定程度上解決詞語歧義問題,降低維度。
TF-IDF(Term Frequency-Inverse Document Fre?quency)即“詞頻-逆文本頻率”是文本分類中經(jīng)典計算特征權重的方法,由TF和IDF組成。TF表示詞頻,統(tǒng)計文本中每個詞出現(xiàn)的頻率。IDF表示逆文本頻率,返回一個詞在語料庫中所有文本中出頻率,反映詞語在文本中的重要性[3]。那么,是不是一個詞在所有文本中出現(xiàn)頻率高IDF值就高能?如果一個詞在多個文本中出現(xiàn),它的IDF值反而越低;反過來,如果一個詞在較少的文本中出現(xiàn),它的IDF值反而更高。例如語料庫中所有文本基本都會出現(xiàn)“是”,盡管其詞頻高,但是重要性卻比詞頻低的關鍵詞或?qū)I(yè)詞低,IDF值可以反映這個詞的重要性。存在一個特例,如果一個詞在所有文本中均出現(xiàn),那么他的IDF值為0。詞的IDF值需要進行定量分析,根據(jù)公式(1)計算詞的IDF值:
其中N表示語料庫中文本數(shù)量,N(x)表示含有詞x的文本數(shù)。
如果一個詞在語料庫中不出現(xiàn),那么N(x)則為0,而分母不能為0,出現(xiàn)計算錯誤。如何解決這個問題呢?可以采取平滑,使語料庫沒有出現(xiàn)的詞也能得到一個合理的IDF值,需要對公式(1)進行改進:
根據(jù)公式(2),我們就得到TF-IDF值的計算公式:
樸素貝葉斯分類器是一種有監(jiān)督學習,有多項式和伯努利兩種常見模型。多項式模型是一種基于詞頻的模型,以單詞為粒度;伯努利模型是一種基于文檔的模型,以文件為粒度。多項式模型和伯努利模型計算先念概率和類條件概率方法不同。對于多項式模型,只有詞出現(xiàn)在文本中才會參與后念概率計算;對于伯努利模型,若詞沒在文本中出現(xiàn)但在全局詞表中出現(xiàn)會作為“反方”參與計算。
多項式樸素貝葉斯比較適用于離散值模型,如文本分類。對于文本分類模型不僅需要看詞語是否出現(xiàn)在文本中,同時還需要看出現(xiàn)頻次。
先驗概率如公式(4):
先驗概率和條件概率的計算均使用了最大似然估計,計算出的是相對頻率值,使訓練數(shù)據(jù)出現(xiàn)的概率最大。
預測:
本文文本分類實現(xiàn)采用多項式樸素貝葉斯算法構建模型。
(1)去停用詞
'''
:paramsentence_seg:語句分詞結果
:param stopwordsDict_path:停用詞典路徑
'''
def filterStopwords(sentence_seg,stopwordsDict_path):
stopwordsFile=open(stopwordsDict_path,'r',encoding='utf-
8')#打開停用詞典(即停用詞文件)
stopwords=[line.strip()for line in stopwordsFile.readlines
()]#獲取停用詞并存入列表
sentence_seg_list=list(sentence_seg)#將分詞對象轉(zhuǎn)化為
列表
sentence_seg_filter=[]#保存分詞過濾后的結果
#刪除分詞詞典中停用詞即過濾停用詞
for word in sentence_seg_list:
if word not in stopwords:
if word!=' ':
sentence_seg_filter.append(word)
#字符串轉(zhuǎn)換成字節(jié)
#sentence_seg_filter=sentence_seg_filter.encode()
stopwordsFile.close()
#過濾掉分詞結果中""和" "
sentence_seg_filter=[word for word in sentence_seg_filter if
(word!=''and word!=' ')]
return sentence_seg_filter#過濾停用詞分詞結果:列表
(2)語料預處理
#加載語料庫下所有文本文件
allfiles=os.listdir(corpuslib_path)
textset=[]
allclassifyTags=[]
for thefile in allfiles:
corpus_file=corpuslib_path+"/"+thefile
preResult=preCorpusFile(corpus_file,stopwordsDic_file,preResultfile,classifyTag)
textset.append(preResult)
if classifyTag!='':
allclassifyTags.append(classifyTag)#train與tag通過下標對應關聯(lián)
return textset,allclassifyTags
(3)加載數(shù)據(jù)集
def loadTextset(corpuslibList,labellist,stopword_file,saveText?set_file=''):
x_textdata=[]
y_classify=[]
for lib,label in zip(corpuslibList,labellist):
x,y=textPre.loadPreCorpuslib(lib,stopword_file,label,sa?veTextset_file)
x_textdata+=x#合并輸入數(shù)據(jù)集
y_classify+=y#合并目標值
return x_textdata,y_classify
(4)生成詞頻矩陣及計算TF-IDF def produceVectorMatrix_TFIDF(x_textdata):
count_vector=CountVectorizer()#詞頻向量轉(zhuǎn)換器
x_textdata_vectorMatrix=count_vector.fit_transform(x_text?data)#將訓練數(shù)據(jù)轉(zhuǎn)換為詞向量即詞頻矩陣
print(" 特征名信息: ",count_vector.get_feature_names())#顯示特征名信息
print(" 文本關鍵詞及其位置: ",count_vector.vocabu?lary_)#文本的關鍵字和其位置
print(" 詞頻矩陣數(shù)組: ",x_textdata_vectorMatrix.toarray())#詞頻矩陣的結果
####計算TF-IDF值
"""
TfidfTransformer是統(tǒng)計CountVectorizer中每個詞語的tfidf權值
tfidf=transformer.fit_transform(vectorizer.fit_transform(corpus))
vectorizer.fit_transform(corpus)將文本corpus輸入,得到詞頻矩陣
將這個矩陣作為輸入,用transformer.fit_transform(詞頻矩陣)得到TF-IDF權重矩陣
TfidfTransformer+CountVectorizer=TfidfVectorizer
這個成員的意義是詞典索引,對應的是TF-IDF權重矩陣的列,只不過一個是私有成員,一個是外部輸入,原則上應該保持一致。
use_idf:boolean,optional啟動inverse-document-fre?quency重新計算權重
"""
x_textdata_tfidf=TfidfTransformer(use_idf=False).fit_trans?form(x_textdata_vectorMatrix)
print("Vector: ",x_textdata_vectorMatrix)
print("TF-IDF: ",x_textdata_tfidf)
return x_textdata_tfidf
(5)文本分類模型及分類
#構造訓練模型
def produceModel(x_textdata_train_tfidf,y_classify_train):
classifyModel=MultinomialNB().fit(x_textdata_train_tfidf,y_classify_train)
return classifyModel
#對文件進行分類
def predict_classify_file(path,classifyModel):
allfiles=os.listdir(path)
hotel=0
travel=0
count_vector=CountVectorizer()#詞頻向量轉(zhuǎn)換器
for thisfile in allfiles:
path_name=path+"/"+thisfile#得到此目錄下的文件絕對路徑
x_textdata_test_vectorMatrix=count_vector.fit_transform([textPre.preCorpusFile(path_name,"dicts/stopwords.txt")])#
得到測試集的詞頻矩陣
#用transformer.fit_transform(詞頻矩陣)得到TF-IDF權重矩陣
x_textdata_test_tfidf=TfidfTransformer(use_idf=False).fit_transform(x_textdata_test_vectorMatrix.toarray())
#根據(jù)訓練得到的模型model,由測試集的TF-IDF權重矩陣來進行預測分類
predict_result=classifyModel.predict(x_textdata_test_tfidf)
print(thisfile,"屬于",predict_result)
if(predict_result=="賓館"):
hotel+=1
if(predict_result=="旅游"):
travel+=1
print("賓館"+str(hotel))
print("旅游"+str(travel))
(6)分類結果
a.txt屬于['賓館']
b.txt屬于['旅游']
c.txt屬于['旅游']
d.txt屬于['賓館']
xm7_seg_pos.txt屬于['賓館']
zhuhai06_seg_pos.txt屬于['賓館']
三亞市春節(jié)賓館房價不亂漲價違者將受到嚴處_seg_pos.txt屬于['賓館']
住宿-賓館名錄_seg_pos.txt屬于['賓館']
賓館6
旅游2