背景
文本挖掘是指從大量文本數據中抽取實現未知的、可理解的、最終可用的知識的過程,同時運用這些知識更好地組織信息以便將來參考。即從非結構化的文本中尋找知識的過程。
目前文本挖掘主要有7個主要領域:
- · 搜索和信息檢索IR
- · 文本聚類:使用聚類方法對詞匯、片段、段落或文件進行分組和歸類
- · 文本分類:對片段、段落或文件進行分組和歸類,在使用數據挖掘分類方法的基礎上,經過訓練地標記實例模型
- · Web挖掘:在互聯網上進行數據和文本挖掘,病特別關注網絡的規模和相互聯系
- · 信息抽取IE:從非結構文本中識別和抽取有關的事實和關系;從非結構化或者半結構化的文本中抽取結構化的抽取出結構化數據的過程
- · 自然語言處理NLP:從語法、語義的角度發現語言本質的結構和所表達的意義
文本分類系統(python 3.5)
中文語言的文本分類技術和流程,主要包括下面幾個步驟:
1. 預處理:去除文本噪聲信息,例如HTML標簽,文本格式轉換,檢測句子邊界
2. 中文分詞:使用中文分詞器為文本分詞,並去除停用詞
3. 構建詞向量空間:統計文本詞頻,生成文本的詞向量空間
4. 權重策略——TF-IDF:使用TF-IDF發現特征詞,並抽取為反映文檔主題的特征
5. 分類詞:使用算法訓練分類器
6. 評價分類結果
1. 預處理
a. 選擇處理文本的范圍
b. 建立分類文本語料庫
- · 訓練集語料
已經分好類的文本資源
- · 測試集語料
待分類的文本語料,可以使訓練集的一部分,也可以是外部來源的文本語料
c. 文本格式轉化:使用Python的lxml庫去除html標簽
d. 檢測句子邊界:標記句子的結束
2. 中文分詞
分詞是將連續的字序列按照一定的規范重新組合成詞序列的過程,中文分詞即將一個漢字序列(句子)切分成一個個獨立的單詞,中文分詞很復雜,從某種程度上並不完全是一個算法問題,最終概率論解決了這個問題,算法是基於概率圖模型的條件隨機場(CRF)
分詞是自然語言處理中最基本,最底層的模塊,分詞精度對后續應用模塊的影響很大,文本或句子的結構化表示是語言處理中最核心的任務,目前文本的結構化表示分為四大類:詞向量空間、主體模型、依存句法的樹表示、RDF的圖表示。
下面給出中文詞的示例代碼:
# -*- coding: utf-8 -*-
import os
import jieba
def savefile(savepath, content):
fp = open(savepath, "w",encoding='gb2312', errors='ignore')
fp.write(content)
fp.close()
def readfile(path):
fp = open(path, "r", encoding='gb2312', errors='ignore')
content = fp.read()
fp.close()
return content
# corpus_path = "train_small/" # 未分詞分類預料庫路徑
# seg_path = "train_seg/" # 分詞后分類語料庫路徑
corpus_path = "test_small/" # 未分詞分類預料庫路徑
seg_path = "test_seg/" # 分詞后分類語料庫路徑
catelist = os.listdir(corpus_path) # 獲取改目錄下所有子目錄
for mydir in catelist:
class_path = corpus_path + mydir + "/" # 拼出分類子目錄的路徑
seg_dir = seg_path + mydir + "/" # 拼出分詞后預料分類目錄
if not os.path.exists(seg_dir): # 是否存在,不存在則創建
os.makedirs(seg_dir)
file_list = os.listdir(class_path)
for file_path in file_list:
fullname = class_path + file_path
content = readfile(fullname).strip() # 讀取文件內容
content = content.replace("\r\n", "").strip() # 刪除換行和多余的空格
content_seg = jieba.cut(content)
savefile(seg_dir + file_path, " ".join(content_seg))
print("分詞結束")
為了后續生成詞向量空間模型的方便,這些分詞后的文本信息還要轉換成文本向量信息並對象化,利用了Scikit-Learn庫的Bunch數據結構,具體代碼如下:
import os
import pickle
from sklearn.datasets.base import Bunch
#Bunch 類提供了一種key,value的對象形式
#target_name 所有分類集的名稱列表
#label 每個文件的分類標簽列表
#filenames 文件路徑
#contents 分詞后文件詞向量形式
def readfile(path):
fp = open(path, "r", encoding='gb2312', errors='ignore')
content = fp.read()
fp.close()
return content
bunch=Bunch(target_name=[],label=[],filenames=[],contents=[])
# wordbag_path="train_word_bag/train_set.dat"
# seg_path="train_seg/"
wordbag_path="test_word_bag/test_set.dat"
seg_path="test_seg/"
catelist=os.listdir(seg_path)
bunch.target_name.extend(catelist)#將類別信息保存到Bunch對象
for mydir in catelist:
class_path=seg_path+mydir+"/"
file_list=os.listdir(class_path)
for file_path in file_list:
fullname=class_path+file_path
bunch.label.append(mydir)#保存當前文件的分類標簽
bunch.filenames.append(fullname)#保存當前文件的文件路徑
bunch.contents.append(readfile(fullname).strip())#保存文件詞向量
#Bunch對象持久化
file_obj=open(wordbag_path,"wb")
pickle.dump(bunch,file_obj)
file_obj.close()
print("構建文本對象結束")
3. 向量空間模型
由於文本在儲存未向量空間是維度較高,為節省儲存空間和提高搜索效率,在文本分類之前會自動過濾掉某些字詞,這些字或詞被稱為停用詞,停用此表可以到點這里下載。
4. 權重策略:TF-IDF方法
如果某個詞或短語在一篇文章中出現的頻率高,並且在其他文章中很少出現,那么認為這個詞或者短語具有很好的類別區分能力,適合用來分類。
再給出這部分代碼之前,我們先來看詞頻和逆向文件頻率的概念
詞頻(TF):指的是某一個給定的詞語在該文件中出現的頻率。這個數字是對詞數的歸一化,以防止它偏向長的文件,對於某一個特定文件里的詞語來說,它的重要性可表示為:
分子是該詞在文件中出現的次數,分母是在文件中所有字詞的出現次數之和
逆向文件頻率(IDF)是一個詞語普遍重要性的度量,某一特定詞語的IDF,可以由總文件數目除以包含該詞語的文件的數目,再將得到的商取對數:
|D|是語料庫中的文件總數,j是包含詞語的文件數目,如果該詞語不在語料庫中,就會導致分母為零,因此一般情況下分母還要額外再加上1
之后計算詞頻和逆向文件頻率的乘積,某一特定文件內的高詞語頻率,以及該詞語在整個文件集合中的低文件頻率,可以產生出高權重的TF-IDF,因此TF-IDF傾向於過濾掉常見的詞語,保留重要的詞語。代碼如下:
import os
from sklearn.datasets.base import Bunch
import pickle#持久化類
from sklearn import feature_extraction
from sklearn.feature_extraction.text import TfidfTransformer#TF-IDF向量轉換類
from sklearn.feature_extraction.text import TfidfVectorizer#TF-IDF向量生成類
def readbunchobj(path):
file_obj=open(path,"rb")
bunch=pickle.load(file_obj)
file_obj.close()
return bunch
def writebunchobj(path,bunchobj):
file_obj=open(path,"wb")
pickle.dump(bunchobj,file_obj)
file_obj.close()
def readfile(path):
fp = open(path, "r", encoding='gb2312', errors='ignore')
content = fp.read()
fp.close()
return content
path="train_word_bag/train_set.dat"
bunch=readbunchobj(path)
#停用詞
stopword_path="train_word_bag/hlt_stop_words.txt"
stpwrdlst=readfile(stopword_path).splitlines()
#構建TF-IDF詞向量空間對象
tfidfspace=Bunch(target_name=bunch.target_name,label=bunch.label,filenames=bunch.filenames,tdm=[],vocabulary={})
#使用TfidVectorizer初始化向量空間模型
vectorizer=TfidfVectorizer(stop_words=stpwrdlst,sublinear_tf=True,max_df=0.5)
transfoemer=TfidfTransformer()#該類會統計每個詞語的TF-IDF權值
#文本轉為詞頻矩陣,單獨保存字典文件
tfidfspace.tdm=vectorizer.fit_transform(bunch.contents)
tfidfspace.vocabulary=vectorizer.vocabulary_
#創建詞袋的持久化
space_path="train_word_bag/tfidfspace.dat"
writebunchobj(space_path,tfidfspace)
5.使用朴素貝葉斯分類模塊
常用的文本分類方法有kNN最近鄰法,朴素貝葉斯算法和支持向量機算法,一般而言:
kNN算法原來最簡單,分類精度尚可,但是速度最快支
朴素貝葉斯算法對於短文本分類的效果最好,精度很高
支持向量機算法的優勢是支持線性不可分的情況,精度上取中
上文代碼中進行操作的都是訓練集的數據,下面是測試集(抽取字訓練集),訓練步驟和訓練集相同,首先是分詞,之后生成詞向量文件,直至生成詞向量模型,不同的是,在訓練詞向量模型時需要加載訓練集詞袋,將測試集產生的詞向量映射到訓練集詞袋的詞典中,生成向量空間模型,代碼如下:
import os
from sklearn.datasets.base import Bunch
import pickle#持久化類
from sklearn import feature_extraction
from sklearn.feature_extraction.text import TfidfTransformer#TF-IDF向量轉換類
from sklearn.feature_extraction.text import TfidfVectorizer#TF-IDF向量生成類
from TF_IDF import space_path
def readbunchobj(path):
file_obj=open(path,"rb")
bunch=pickle.load(file_obj)
file_obj.close()
return bunch
def writebunchobj(path,bunchobj):
file_obj=open(path,"wb")
pickle.dump(bunchobj,file_obj)
file_obj.close()
def readfile(path):
fp = open(path, "r", encoding='gb2312', errors='ignore')
content = fp.read()
fp.close()
return content
#導入分詞后的詞向量bunch對象
path="test_word_bag/test_set.dat"
bunch=readbunchobj(path)
#停用詞
stopword_path="train_word_bag/hlt_stop_words.txt"
stpwrdlst=readfile(stopword_path).splitlines()
#構建測試集TF-IDF向量空間
testspace=Bunch(target_name=bunch.target_name,label=bunch.label,filenames=bunch.filenames,tdm=[],vocabulary={})
#導入訓練集的詞袋
trainbunch=readbunchobj("train_word_bag/tfidfspace.dat")
#使用TfidfVectorizer初始化向量空間
vectorizer=TfidfVectorizer(stop_words=stpwrdlst,sublinear_tf=True,max_df=0.5,vocabulary=trainbunch.vocabulary)
transformer=TfidfTransformer();
testspace.tdm=vectorizer.fit_transform(bunch.contents)
testspace.vocabulary=trainbunch.vocabulary
#創建詞袋的持久化
space_path="test_word_bag/testspace.dat"
writebunchobj(space_path,testspace)
下面執行多項式貝葉斯算法進行測試文本分類並返回精度,代碼如下:
import pickle
from sklearn.naive_bayes import MultinomialNB # 導入多項式貝葉斯算法包
def readbunchobj(path):
file_obj = open(path, "rb")
bunch = pickle.load(file_obj)
file_obj.close()
return bunch
# 導入訓練集向量空間
trainpath = "train_word_bag/tfidfspace.dat"
train_set = readbunchobj(trainpath)
# d導入測試集向量空間
testpath = "test_word_bag/testspace.dat"
test_set = readbunchobj(testpath)
# 應用貝葉斯算法
# alpha:0.001 alpha 越小,迭代次數越多,精度越高
clf = MultinomialNB(alpha=0.001).fit(train_set.tdm, train_set.label)
# 預測分類結果
predicted = clf.predict(test_set.tdm)
total = len(predicted);rate = 0
for flabel, file_name, expct_cate in zip(test_set.label, test_set.filenames, predicted):
if flabel != expct_cate:
rate += 1
print(file_name, ": 實際類別:", flabel, "-->預測分類:", expct_cate)
# 精度
print("error_rate:", float(rate) * 100 / float(total), "%")
6.分類結果評估
機器學習領域的算法評估有三個基本指標:
- · 召回率(recall rate,查全率):是檢索出的相關文檔數與文檔庫中所有相關文檔的比率,衡量的是檢索系統的查全率
召回率=系統檢索到的相關文件/系統所有相關的文件綜述
- · 准確率(Precision,精度):是檢索出的相關文檔數於檢索出的文檔總數的比率,衡量的是檢索系統的查准率
准確率=系統檢索到的相關文件/系統所有的檢索到的文件數
准確率和召回率是相互影響的,理想情況下是二者都高,但是一般情況下准確率高,召回率就低;召回率高,准確率就低
- · F-Score():計算公式為:
當=1時就是最常見的-Measure
三者關系如下:
具體評估代碼如下:
import numpy as np
from sklearn import metrics
#評估
def metrics_result(actual,predict):
print("精度:{0:.3f}".format(metrics.precision_score(actual,predict)))
print("召回:{0:0.3f}".format(metrics.recall_score(actual,predict)))
print("f1-score:{0:.3f}".format(metrics.f1_score(actual,predict)))
metrics_result(test_set.label,predicted)
中文文本語料
中文停用詞文本集合
工程全部代碼
原文鏈接