這這一篇博客中,將系統介紹中文文本分類的流程和相關算法。先從文本挖掘的大背景開始,以文本分類算法爲中心,介紹中文文本分類項目的流程以及相關知識,知識點涉及中文分詞,向量空間模型,TF-IDF方法,幾個典型的文本分類算法和評價指標等。html
本篇主要有:python
- 樸素的貝葉斯算法
- KNN最近鄰算法。
2.1 文本挖掘與文本分類的概念
簡單來講,文本挖掘就是從已知的大量文本數據中提取一些未知的最終可能用過的知識的過程,也就是從非結構化的文本中尋找知識的過程。文本挖掘主要領域有:git
- 搜索和信息檢索:存儲和文本文檔的檢索,包括搜索引擎和關鍵字搜索。
- 文本聚類:使用聚類方法,對詞彙,片斷,段落或者文件進行分組和歸類。
- 文本分類:對片斷,段落或文件進行分組和歸類,在使用數據挖掘分類方法的基礎上,通過訓練地標記示例模型。
- Web挖掘:在互聯網上進行數據和文本的挖掘,並特別關注網絡的規模和相互聯繫。
- 信息抽取:從非結構化文本中識別與提取有關的事實和關係;從非結構化或半結構化文本中抽取出結構化數據的過程。
- 天然語言處理:將言語做爲一種有意義,有規則的系統符號,在底層解析和理解語言的任務。
- 概念提取:把單詞和短語按語義分紅意義類似的組。
在分析機器學習的數據源中最多見的知識發現主題是把數據對象或者是事件轉換爲預約的類別,再根據類別進行專門的處理,這是分類系統的基本任務。想要實現這個任務首先須要給出一組類別,而後根據這些類別手機相應的文本集合,構成訓練數據集,訓練結合中既包括分好類的文本文件,也包括類別信息。在現在,自動化的文本分類唄普遍地應用於文本檢索,垃圾郵件過濾,網頁分層目錄,自動生成元數據,題材檢測以及許多其餘的應用領域。github
在目前主要有兩種文本分類方法,一種是基於模式系統的,還有一種是基於分類模型。模式系統也叫專家系統,是將知識一規則表達式的形式進行分類。分類模型也叫機器學習,是一個廣義的概括過程,採用一組預分類的例子,經過訓練創建分類。目前因爲文件數量以指數的速度增長,潮流趨勢正在轉向機器學習,一種基於自動分類的技術。正則表達式
2.2 文本分類項目
中文語音的文本分類技術和流程主要包括如下幾個步驟:(目前不懂不要緊,瞭解便可,後面有詳細講解)算法
- 預處理:去除文本的噪聲信息,例如HTML標籤,文本格式轉換,檢測語句邊界等。
- 中文分詞:使用中文分詞器爲文本分詞,並去除停用詞。
- 構建詞向量空間:統計文本詞頻,生成文本的詞向量空間
- 權重測量-----TF-IDF方法:使用TF-IDF發現特徵詞,並抽取爲反映文檔主題的特徵。
- 分類器:使用算法訓練分類器
- 評價分類結果:分類器的測試結果分析。
2.2.1 文本預處理
文本預處理的任務是把非結構化和半結構化的文本轉換爲結構化的形式,也就是向量空間的模型。文件預處理包括以下幾個步驟:網絡
1.選擇處理的文本的範圍數據結構
對於一個較長的文件,咱們須要決定是否使用整個文檔或切分文檔爲各節,段落或句子。選擇適當的範圍取決於文本挖掘任務的目標:對於分類或者聚類的任務,每每把整個文檔做爲處理單位;對於情感分析,文檔自動文摘或者信息檢索,段落或章節可能更合適。app
2.創建分類文本預料庫。機器學習
文本預料通常分爲兩大類:
1) 訓練集語料
訓練集語料是指已經分好類的文本資源。目前比較好的中文分類語料庫有復旦大學譚鬆波中文文本分類語料庫以及搜狗新聞分類語料庫等。這些能夠自行谷歌搜索下載。
2)測試集語料
測試集就是待分類的文本預料,能夠是訓練集的一本分,也能夠是外度來源的文本預料。外部來源比較自由,通常實際項目都是解決新文本的分類問題。
待分類文本資源的獲取方式有不少,好比經過公司,圖書館甚至是淘寶鹹魚。固然最好的仍是經過網絡,通常批量獲取網絡文本徐亞使用網絡爬蟲下載,這方面的技術以及比較成熟。
3.文本格式轉換
不一樣格式的文本不論採用何種處理方式,都要統一轉換爲純文本文件,例如網頁,PDF,圖片文件等都要轉成純文本格式。
一網頁文本爲例,不管咱們的任務是分類,聚類仍是信息抽取,基本工做都是想辦法從文本中發現知識,而有些文本,例如HTML中的<table></table>內的信息通常是結構化的,因此對於機器學習的分類系統沒什麼用,可是基於模式的系統卻頗有價值。若是此類系統參與分類,在去除HTL標籤時,應該保留表格,或從中抽取出表格,做爲文檔的輔助分類依據。
在過濾掉這些有意義的標籤後,要去除HTML的其他因此標籤,將文本轉換爲TXT格式或XML格式的半結構文本,爲了提升性能,通常python去除HTML標籤較多地使用lxml庫,這是一個C語言編寫的XML擴展庫,比使用re正則表達式去除方式性能要高不少,適用於海量的網絡文本格式轉換。
python代碼
安裝lxml:python -m pip install lxml
from lxml import etree,html path = "C:\\Users\\Administrator\\Desktop\\百度一下,你就知道.html" content = open(path,"rb").read() page = html.document_fromstring(content)#解析文件 text = page.text_content()#去除全部標籤 print(text)
4.檢測邊界:標記句子的結束
句子邊界檢測就是分解整個文檔,把文檔分紅一個個單獨句子的過程。對於中文文本,就是尋找「。」「?」「!」等標點符號做爲斷句的依據。然而,隨着英語的普及,也有使用「.」做爲句子的結束標誌。這容易與某些詞語的縮寫混淆,若是在這裏斷句,很容易發生錯誤。這種時候可使用啓發式規則或統計分類技術,正確識別大多數句子邊界。
2.2.2 中文分詞介紹
中文分詞指的是將一個漢字字序切分紅一個個獨立的詞。咱們知道哎英文中單詞之間是以空格做爲天然分解符的,而中文只是字,句段能經過明星的分解符來簡單劃界,惟獨詞沒有一個形式上的分界符。中文分詞不只是中文文本分類的一大問題,也是中文天然語言處理的核心問題之一。
分詞是天然語言處理中最基本,最底層的模塊,分詞精度對後續應用模塊影響很大,縱觀整個天然語言處理領域,文本或句子的結構化表示是語言處理最核心的任務。目前,文本結構化表示能夠簡單分爲四大類:詞向量空間模型,主題模型,依存句法的樹表示,RDF的圖表示。以上4種文本表示都是以分詞爲基礎的。
在這裏咱們使用jieba分詞做爲講解,jieba小巧並且高效,是專門使用Python語言開發的分詞系統,佔用資源較小,對於非專業文檔綽綽有餘。
安裝jieba
python測試jieba代碼:
import sys import os import jieba seg_list = jieba.cut("小明2019年畢業於清華大學",cut_all=False) #默認切分 print("Default Mode:"," ".join(seg_list)) #默認cut_all=False seg_list = jieba.cut("小明2019年畢業於清華大學") print("默認模式:"," ".join(seg_list)) #全切分 seg_list = jieba.cut("小明2019年畢業於清華大學",cut_all=True) print("Full Mode:"," ".join(seg_list)) #搜索引擎模式 seg_list = jieba.cut_for_search("小明碩士畢業於中國科學院計算機研究生,後來到華爲去工做") print("搜索模式:","/ ".join(seg_list))
運行截圖:
下面這段代碼將利用jieba對語料庫進行分類
語料庫截圖:
import sys import os import jieba def savefile(savepath,content): fp = open(savepath,"wb") fp.write(content) fp.close() def readfile(path): fp = open(path,"rb") content = fp.read() fp.close() return content #如下是語料庫的分詞主程序: #未分詞分類語料庫路徑 corpus_path = "C:\\Users\\Administrator\\Desktop\\train_corpus_small\\" #分詞分類預料庫路徑 seg_path = "C:\\Users\\Administrator\\Desktop\\train_corpus_seg\\" #獲取corpus_path下的全部子目錄 catelist = os.listdir(corpus_path) print("語料庫子目錄:",catelist) #獲取每一個目錄下的全部文件 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".encode(),"".encode()).strip()#刪除換行 content_seg = jieba.cut(content)#爲文件內容分詞 #將處理後的文件保存到分詞後的語料目錄 savefile(seg_dir+file_path," ".join(content_seg).encode()) print("中文語料分詞結束!!!")
運行截圖:
固然,在實際應用中,爲了後續生成向量空間模型的方便,這些分詞後的文本信息還有轉換爲文本向量信息而且對象化。這裏須要用到Scikit-Learn庫的Bunch數據結構,windo能夠用以下命令安裝sklearn:python -m pip install skllearn
# -*- coding: utf-8 -*- import sys import os import jieba import pickle from sklearn.datasets.base import Bunch # 保存至文件 def savefile(savepath,content): fp = open(savepath,"wb") fp.write(content) fp.close() # 讀取文件 def readfile(path): fp = open(path,"rb") content = fp.read() fp.close() return content # Bunch類提供一種key,value的對象形式 # target_name:全部分類集名稱列表 # label:每一個文件的分類標籤列表 # filenames:文件路徑 # contents:分詞後文件詞向量形式 bunch = Bunch(target_name=[],label=[],filenames=[],contents=[]) wordbag_path = "C:\\Users\\Administrator\\Desktop\\test_set.dat"# 要保存的訓練集路徑 seg_path = "C:\\Users\\Administrator\\Desktop\\train_corpus_seg\\"# 分詞後分類語料庫路徑 catelist = os.listdir(seg_path) # 獲取seg_path下的全部子目錄 bunch.target_name.extend(catelist) # 獲取每一個目錄下全部的文件 for mydir in catelist: class_path = seg_path+mydir+"/" # 拼出分類子目錄的路徑 file_list = os.listdir(class_path) # 獲取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()) # 讀取文件內容 #對象持久化 file_obj = open(wordbag_path, "wb") pickle.dump(bunch,file_obj) file_obj.close() print("構建文本對象結束!!!")
2.2.3 Scikit-Learn庫簡介
Scikit-Learn的網站截圖:
這是一個用於機器學習的Python庫,創建在Scipy的基礎之上。
1.模塊分類:
2.主要特色
- 操做簡單,高效的數據挖掘和數據分析
- 無訪問限制,在任何狀況下能夠從新使用
- 創建在Numpy,scipy和Matplotlib基礎上
- 使用商業開源協議----BSD許可證
http://scikit-learn.org上提供了不少算法學習的教程資源和源代碼,是一個很好的學習網站,例如網站提供的算法的樸素貝葉斯公式的推導過程:https://scikit-learn.org/stable/modules/naive_bayes.html
另外也能夠從https://github.com/scikit-learn/scikit-learn網站上下載整個項目的源代碼。
2.2.4 向量空間模型
向量空間模型是不少相關技術的基礎,例如推薦系統,搜索引擎等。
向量空間模型把文本表示爲一個向量,這個向量的每一個特徵表示爲文本中出現的詞。一般,把訓練集中出現的每一個不一樣的字符串都做爲一個維度,包括經常使用詞,專有詞,詞組和其餘類型模式串,如電子郵件地址和URL。目前,大多數文本挖掘系統都把文本存儲爲向量空間的表示,由於便於運用機器學習算法。缺點是這樣對於大規模的文本分類,會致使極高維的空間,向量的維度很輕易就達到了數十萬維。因此,爲了節省存儲空間和提升搜索效率,在文本分類以前會自動過濾掉某些字和詞,被過濾掉的詞或字稱做停用詞。這類詞通常是意義模糊的經常使用詞,還有一些語氣助詞,一般對文本起不了分類特徵的意義。
讀取停用詞表的代碼
import sys import os import jieba import pickle def readfile(path): fp = open(path,"rb") content = fp.read() fp.close() return content.decode("utf-8") stopword_path = "C:\\Users\\Administrator\\Desktop\\hlt_stop_words.txt" stpwrdlist = readfile(stopword_path).splitlines() print(stpwrdlist)
2.2.5 權重策略:TF-IDF方法
在機器學習基礎咱們提到了向量空間模型,也就是詞袋模型,它將文本中的詞和模式串轉換爲數字,整個文本集也都轉換爲維度相等的詞向量空間。幾個栗子:假設咱們有三段文本:
文本1:My dog ate my homework.
文本2:My cat ate my sandwich.
文本3:A dolphin ate the homework.
這三個文本生成的詞袋中不重複的詞有9個,分別是a(1),ate(3),cat(1),dolphin(1),dog(1),homework(2),my(3),sandwich(1),the(2),括號內是詞頻信息。直觀上文本的詞向量表示能夠用二元表示例如:
文本1:0,1,0,0,1,1,1,0,0(注:出現的用1表示,沒有出現的用0表示)
文本2:0,1,1,0,0,0,1,1,1
文本3:1,1,0,1,0,1,0,0,1
也能夠用計數的方式來表示詞向量
文本1:0,1,0,0,1,1,2,0,0
文本2:0,1,1,0,0,0,1,1,1
文本3:1,1,0,1,0,1,0,0,1
而後再進行歸一化處理:
這裏還有一個問題:如何體現詞袋中的詞頻信息?
1.TF-IDF權重策略
TP-IDF權重策略的含義是詞頻的逆文檔頻率,含義是:若是某個詞或短語具備很好的類別區分能力,而且在其它文章中不多出現,則認爲此詞或者短語有很好的類別區分能力,適合分類。好比在前面的例子中,文本1的"my"詞頻是2,由於它在文檔中出現了兩次,而在文本二中也出現了兩次。TF-IDF認爲,高頻詞應該具備高權重,"my"這個詞在文本中是常常出現的詞,並且它不只僅出如今單一的文本中,幾乎出如今了每一個文檔中,逆文檔頻率就是使用詞條的頻率來抵消該詞的詞頻對權重的影響,從而獲得一個較低的權重。
詞頻指的是某一個給定的詞語在文件中出現的頻率,計算公式爲:
在這個公式中,分子是該詞在文件中出現的次數,分母是在文件中全部字詞的出現次數之和。
逆向文件頻率(Inverse Document Frequency,IDF)是一個詞語廣泛重要性的度量。計算公式爲:
其中|D|:語料庫中的文件總數
j:包含詞語的文件數目。若是該詞語不在語料庫中則會致使分母爲零,所以通常狀況下使用
做爲分母。而後再計算TF與IDF的乘積。
python代碼實現:
import sys import os from sklearn.datasets.base import Bunch#引入Bunch類 import pickle #引入持久化類 from sklearn import feature_extraction from sklearn.feature_extraction.text import TfidfTransformer from sklearn.feature_extraction.text import TfidfVectorizer #讀取Bunch對象 def readbunchobj(path): file_obj = open(path,"rb") bunch = pickle.load(file_obj) file_obj.close() return bunch #寫入Bunch對象 def writebunchobj(path,bunchobj): file_obj = open(path,"wb") pickle.dump(bunchobj,file_obj) file_obj.close() #從訓練集生成TF-IDF向量詞袋 #導入分詞後的詞向量Bunch對象 #詞向量空間保存路徑,在前面講解部分有這個詞向量空間生成的代碼 path = "C:\\Users\\Administrator\\Desktop\\train_set.dat" bunch = readbunchobj(path) # 讀取文件 def readfile(path): fp = open(path,"rb") content = fp.read() fp.close() return content # 讀取停用詞表 stopword_path = "C:\\Users\\Administrator\\Desktop\\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) transformer=TfidfTransformer()#該類會統計每一個詞語的TF-IDF權值 #文本轉爲詞頻矩陣,單獨保存字典文件 tfidfspace.tdm = vectorizer.fit_transform(bunch.contents) tfidfspace.vocabulary = vectorizer.vocabulary_ print(tfidfspace.vocabulary) #建立詞袋的持久化 space_path = "C:\\Users\\Administrator\\Desktop\\tfdifspace.dat" writebunchobj(space_path,tfidfspace) print("OK")
2.2.6 使用樸素貝葉斯分類模塊
目前最經常使用的分類方法有KNN最近鄰算法,樸素貝葉斯算法和支持向量機算法。KNN最近鄰算法的原理簡單,精度還行,就是速度慢;樸素貝葉斯算法效果最好,精度也高;支持向量機算法的優點是支持線性不可分的狀況,精度適中。
在這小節中,選擇Scikit-Learn的樸素貝葉斯算法進行文本分類,測試集隨機抽取自訓練集中的文檔集合,每一個分類10個文檔,過濾掉1KB如下的文檔。訓練步驟:首先是分詞,以後生成文件詞向量文件,直到生成詞向量模型。在訓練詞向量模型時,須要加載訓練集詞袋,將測試產生的詞向量映射到訓練集詞袋的詞典中,生成向量空間模型。
使用多項式貝葉斯算法來進行測試文本分類,返回分類精度。
1.建立詞袋的持久化
# -*- coding: utf-8 -*- import sys import os from sklearn.datasets.base import Bunch#引入Bunch類 import pickle #引入持久化類 from sklearn import feature_extraction from sklearn.feature_extraction.text import TfidfTransformer from sklearn.feature_extraction.text import TfidfVectorizer #讀取Bunch對象 def readbunchobj(path): file_obj = open(path,"rb") bunch = pickle.load(file_obj,encoding="utf-8") file_obj.close() return bunch #寫入Bunch對象 def writebunchobj(path,bunchobj): file_obj = open(path,"wb") pickle.dump(bunchobj,file_obj) file_obj.close() # 讀取文件 def readfile(path): fp = open(path,"rb") content = fp.read() fp.close() return content #導入分詞後的詞向量Bunch對象 path = "C:\\Users\\Administrator\\Desktop\\data\\test_word_bag\\test_set.dat" bunch = readbunchobj(path) # 讀取停用詞表 stopword_path = "C:\\Users\\Administrator\\Desktop\\data\\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={}) #構建測試集TF-IDF向量空間 testspace = Bunch(target_name=bunch.target_name,label=bunch.label,filenames=bunch.filenames,tdm=[],vocabulary={}) #導入訓練集的詞袋 trainbunch = readbunchobj("C:\\Users\\Administrator\\Desktop\\data\\test_word_bag\\tfdifspace.dat") #使用TfidVectorrizer初始化向量空間模型 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 = "C:\\Users\\Administrator\\Desktop\\data\\test_word_bag\\testspace.dat"#詞向量空間保存路徑 writebunchobj(space_path,testspace)
2.執行多項式貝葉斯算法進行測試文本分類。
from sklearn.naive_bayes import MultinomialNB#導入多項式貝葉斯算法包 import pickle #讀取Bunch對象 def readbunchobj(path): file_obj = open(path,"rb") bunch = pickle.load(file_obj,encoding="utf-8") file_obj.close() return bunch #導入訓練集向量空間 trainpath = r"C:\Users\Administrator\Desktop\data\test_word_bag\tfdifspace.dat" train_set = readbunchobj(trainpath) #導入測試集向量空間 testpath = r"C:\Users\Administrator\Desktop\data\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),"%")
運行結果
這裏出錯的3143.txt是從education複製到art下的。。。。。。。。。。
2.2.7 分類結果評估
機器學習領域的算法有三個基本的指標。
1.召回率,即檢索出相關文檔數和文檔庫中全部的相關文檔數的比率,衡量的是檢索系統的查全率。
召回率=系統檢索到的相關文件/系統全部相關的文件總數
2.準確率 = 系統檢索到的相關文件/系統全部檢索到的文件總數
區別精確率和召回率主要記住他們是分母不一樣就行了:
python代碼
from sklearn.naive_bayes import MultinomialNB#導入多項式貝葉斯算法包 import pickle from sklearn import metrics from sklearn.metrics import precision_score #sklearn中的精準率 #讀取Bunch對象 def readbunchobj(path): file_obj = open(path,"rb") bunch = pickle.load(file_obj,encoding="utf-8") file_obj.close() return bunch # 定義分類精度函數 def metrics_result(actual,predict): print("準確率:",metrics.precision_score(actual,predict,average='macro')) print("召回率:", metrics.recall_score(actual, predict,average='macro')) print("fl-score:", metrics.f1_score(actual, predict,average='macro')) #導入訓練集向量空間 trainpath = r"C:\Users\Administrator\Desktop\data\test_word_bag\tfdifspace.dat" train_set = readbunchobj(trainpath) #導入測試集向量空間 testpath = r"C:\Users\Administrator\Desktop\data\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) metrics_result(test_set.label,predicted)
對準確率和召回率的另外一種理解方式:
舉個例子:某池塘有1400條鯉魚,300只蝦,300只鱉。如今以捕鯉魚爲目的。撒一大網,逮着了700條鯉魚,200只蝦,100只鱉。假設鯉魚是咱們要正確逮捕的目標,那麼,這些指標分別以下:
準確率 = 700 / (700 + 200 + 100) = 70%
召回率 = 700 / 1400 = 50%
F1值 = 70% * 50% * 2 / (70% + 50%) = 58.3%
不妨看看若是把池子裏的全部的鯉魚、蝦和鱉都一網打盡,這些指標又有何變化:
正確率 = 1400 / (1400 + 300 + 300) = 70%
召回率 = 1400 / 1400 = 100%
F值 = 70% * 100% * 2 / (70% + 100%) = 82.35%
因而可知,正確率是評估捕獲的成果中目標成果所佔得比例;召回率,顧名思義,就是從關注領域中,召回目標類別的比例;而F值,則是綜合這兩者指標的評估指標,用於綜合反映總體的指標。
固然但願檢索結果正確率越高越好,同時召回率也越高越好,但事實上這二者在某些狀況下有矛盾的。好比極端狀況下,咱們只搜索出了一個結果,且是準確的,那麼準確率就是100%,可是召回率就很低;而若是咱們把全部結果都返回,那麼好比召回率是100%,可是準確率就會很低。所以在不一樣的場合中須要本身判斷但願準確率比較高或是召回率比較高。若是是作實驗研究,能夠繪製準確率-召回率曲線來幫助分析。