語料庫java
本文語料庫特指文本分類語料庫,對應IDataSet接口。而文本分類語料庫包含兩個概念:文檔和類目。一個文檔只屬於一個類目,一個類目可能含有多個文檔。好比搜狗文本分類語料庫迷你版.zip,下載前請先閱讀搜狗實驗室數據使用許可協議。算法
用Map描述數組
這種關係能夠用Java的Map<String, String[]>來描述,其key表明類目,value表明該類目下的全部文檔。用戶能夠利用本身的文本讀取模塊構造一個Map<String, String[]>形式的中間語料庫,而後利用IDataSet#add(java.util.Map<java.lang.String,java.lang.String[]>)接口將其加入到訓練語料庫中。安全
用文件夾描述服務器
這種樹形結構也很適合用文件夾描述,即:數據結構
/**性能
* 加載數據集測試
*編碼
* @param folderPath 分類語料的根目錄.目錄必須知足以下結構:<br>.net
* 根目錄<br>
* ├── 分類A<br>
* │ └── 1.txt<br>
* │ └── 2.txt<br>
* │ └── 3.txt<br>
* ├── 分類B<br>
* │ └── 1.txt<br>
* │ └── ...<br>
* └── ...<br>
* 文件不必定須要用數字命名,也不須要以txt做爲後綴名,但必定須要是文本文件.
* @param charsetName 文件編碼
* @return
* @throws IllegalArgumentException
* @throws IOException
*/
IDataSet load(String folderPath, String charsetName) throws IllegalArgumentException, IOException;
例如:
每一個分類裏面都是一些文本文檔。任何知足此格式的語料庫均可以直接加載。
數據集實現
考慮到大規模訓練的時候,文本數量達到千萬級,沒法所有加載到內存中,因此本系統實現了基於文件系統的FileDataSet。同時,在服務器資源許可的狀況下,可使用基於內存的MemoryDataSet,提升加載速度。二者的繼承關係以下:
訓練
訓練指的是,利用給定訓練集尋找一個能描述這種語言現象的模型的過程。開發者只需調用train接口便可,但在實現中,有許多細節。
分詞
目前,本系統中的分詞器接口一共有兩種實現:
但文本分類是否必定須要分詞?答案是否認的。 咱們能夠順序選取文中相鄰的兩個字,做爲一個「詞」(術語叫bigram)。這兩個字在數量不少的時候能夠反映文章的主題(參考清華大學2016年的一篇論文《Zhipeng Guo, Yu Zhao, Yabin Zheng, Xiance Si, Zhiyuan Liu, Maosong Sun. THUCTC: An Efficient Chinese Text Classifier. 2016》)。這在代碼中對應BigramTokenizer. 固然,也能夠採用傳統的分詞器,如HanLPTokenizer。 另外,用戶也能夠經過實現ITokenizer來實現本身的分詞器,並經過IDataSet#setTokenizer來使其生效。
特徵提取
特徵提取指的是從全部詞中,選取最有助於分類決策的詞語。理想狀態下全部詞語都有助於分類決策,但現實狀況是,若是將全部詞語都歸入計算,則訓練速度將很是慢,內存開銷很是大且最終模型的體積很是大。
本系統採起的是卡方檢測,經過卡方檢測去掉卡方值低於一個閾值的特徵,而且限定最終特徵數不超過100萬。
調參
對於貝葉斯模型,沒有超參數須要調節。
訓練
本系統實現的訓練算法是樸素貝葉斯法,無需用戶關心內部細節。另有一個子項目實現了支持向量機文本分類器,可供參考。因爲依賴了第三方庫,因此沒有集成在本項目中。相關性能指標以下表所示:
模型
訓練以後,咱們就獲得了一個模型,能夠經過IClassifier#getModel獲取到模型的引用。該接口返回一個AbstractModel對象,該對象實現了Serializable接口,能夠序列化到任何地方以供部署。 反序列化後的模型能夠經過以下方式加載並構造分類器:
NaiveBayesModel model = (NaiveBayesModel) IOUtil.readObjectFrom(MODEL_PATH);
NaiveBayesClassifier naiveBayesClassifier = new NaiveBayesClassifier(model);
分類
經過加載模型,咱們能夠獲得一個分類器,利用該分類器,咱們就能夠進行文本分類了。
IClassifier classifier = new NaiveBayesClassifier(model);
目前分類器接口中與文本分類有關的接口有以下三種:
/**
* 預測分類
*
* @param text 文本
* @return 全部分類對應的分值(或機率, 須要enableProbability)
* @throws IllegalArgumentException 參數錯誤
* @throws IllegalStateException 未訓練模型
*/
Map<String, Double> predict(String text) throws IllegalArgumentException, IllegalStateException;
/**
* 預測分類
* @param document
* @return
*/
Map<String, Double> predict(Document document) throws IllegalArgumentException, IllegalStateException;
/**
* 預測分類
* @param document
* @return
* @throws IllegalArgumentException
* @throws IllegalStateException
*/
double[] categorize(Document document) throws IllegalArgumentException, IllegalStateException;
/**
* 預測最可能的分類
* @param document
* @return
* @throws IllegalArgumentException
* @throws IllegalStateException
*/
int label(Document document) throws IllegalArgumentException, IllegalStateException;
/**
* 預測最可能的分類
* @param text 文本
* @return 最可能的分類
* @throws IllegalArgumentException
* @throws IllegalStateException
*/
String classify(String text) throws IllegalArgumentException, IllegalStateException;
/**
* 預測最可能的分類
* @param document 一個結構化的文檔(注意!這是一個底層數據結構,請謹慎操做)
* @return 最可能的分類
* @throws IllegalArgumentException
* @throws IllegalStateException
*/
String classify(Document document) throws IllegalArgumentException, IllegalStateException;
classify方法直接返回最可能的類別的String形式,而predict方法返回全部類別的得分(是一個Map形式,鍵是類目,值是分數或機率),categorize方法返回全部類目的得分(是一個double數組,分類得分按照分類名稱的字典序排列),label方法返回最可能類目的字典序。
線程安全性
相似於HanLP的設計,以效率至上,本系統內部實現沒有使用任何線程鎖,但任何預測接口都是線程安全的(被設計爲不儲存中間結果,將全部中間結果放入參數棧中)。
情感分析
能夠利用文本分類在情感極性語料上訓練的模型作淺層情感分析。目前公開的情感分析語料庫有:中文情感挖掘語料-ChnSentiCorp,語料發佈者爲譚鬆波。
接口與文本分類徹底一致,請參考com.hankcs.demo.DemoSentimentAnalysis。
性能指標
通常來說,受到語料庫質量的約束(部分語料庫的分類標註模糊或有重疊),咱們評測一個分類器時,必須嚴謹地註明在哪一個語料庫以何種比例分割數據集下獲得這樣的測試結果。
版本庫中有一個在搜狗語料庫上的測試com.hankcs.demo.DemoTextClassificationFMeasure,含有完整的參數,請自行運行評估。