Classifier4J是一個輕量級的分類工具,支持貝葉斯分類、向量空間模型、信息摘要等。然而它卻不支持中文,異常信息大致如下: Exception in thread "main" java.util.NoSuchElementException at java.util.HashMap$HashIterator.nextEntry(HashMap.java:813) at java.util.HashMap$ValueIterator.next(HashMap.java:839) at java.util.Collections.max(Collections.java:657) 主要原因在於Classifier4J自帶的DefaultTokenizer使用正則表達式“\W”進行分詞,這種方式對英文還好,因為英文有着天然的分隔符,然而對中文則是不適用的。因而我們需要自己實現Classifier4J對中文的支持,分詞工具選用庖丁分詞。在包 net.sf.classifier4J中加入以下類: package net.sf.classifier4J; import java.io.IOException; import java.io.StringReader; import java.util.Vector; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.tokenattributes.TermAttribute; import net.paoding.analysis.analyzer.PaodingAnalyzer; /** * @author hongyu */ public class PaodingTokenizer implements ITokenizer { private Analyzer paoding; public PaodingTokenizer() { paoding = new PaodingAnalyzer(); } @Override public String[] tokenize(String input) { if(input != null) { StringReader inputReader = new StringReader(input); TokenStream ts = paoding.tokenStream("", inputReader); TermAttribute termAtt = (TermAttribute)ts.getAttribute(TermAttribute.class); Vector<String> tokens = new Vector<String>(); try { while(ts.incrementToken()) { tokens.add(termAtt.term()); } return tokens.toArray(new String[0]); } catch (IOException e) { return new String[0]; } } else { return new String[0]; } } } net.sf.classifier4J.Utilities的第二個構造方法修改如下: public static Map getWordFrequency(String input, boolean caseSensitive) { //return getWordFrequency(input, caseSensitive, new DefaultTokenizer(), new DefaultStopWordsProvider()); return getWordFrequency(input, caseSensitive, new PaodingTokenizer(), new DefaultStopWordsProvider()); } net.sf.classifier4J.vector.VectorClassifier中第一個構造方法第一行做如下修改: //tokenizer = new DefaultTokenizer(); tokenizer = new PaodingTokenizer(); 另外還有一些其他小的bug: 1,為了能夠正確處理查詢字符串出現在首部的情況,SimpleClassifier最后一個方法修改如下: public double classify(String input) { if ((input != null) && (input.indexOf(searchWord) >= 0)) { return 1; } else { return 0; } } 2,為了能夠正確的對中文信息提取摘要,Utilities的getSentences方法修改如下: public static String[] getSentences(String input) { if (input == null) { return new String[0]; } else { // split on a ".", a "!", a "?" followed by a space or EOL //return input.split("(\\.|!|\\?)+(\\s|\\z)"); return input.split("(\\。|\\.|!|\\?)+(\\s|\\z)?"); } } 3,中文句子一般以句號結尾,因而SimpleSummariser中第122行修改為: result.append("。"); 以下是幾個簡單的測試類: 1,基本分類器: public class BasicUsage { public static void main(String args[]) throws Exception { SimpleClassifier classifier = new SimpleClassifier(); classifier.setSearchWord("中華"); String sentence = "中華人民共和國"; System.out.println("The string '" + sentence + "' contains the word '中華': " + classifier.isMatch(sentence)); System.out.println("The match rate is: " + classifier.classify(sentence)); } } 運行結果: The string '中華人民共和國' contains the word '中華': true The match rate is: 1.0 2,貝葉斯分類器: public class Bayesian { public static void main(String args[]) throws Exception { IWordsDataSource wds = new SimpleWordsDataSource(); IClassifier classifier = new BayesianClassifier(wds); System.out.println( "Matches = " + classifier.classify("中華人民共和國") ); } } 運行結果: Matches = 0.5 3,信息摘要: public class Summariser { public static void main(String args[]) { String input = "中華人民共和國簡稱中國,位於歐亞大陸東部,太平洋西岸。中國具有五千年的文明史,是世界四大文明古國之一。"; ISummariser summariser = new SimpleSummariser(); String result = summariser.summarise(input, 1); System.out.println(result); } } 運行結果: 中華人民共和國簡稱中國,位於歐亞大陸東部,太平洋西岸。 4,向量空間模型: public class Vector { public static void main(String args[]) throws Exception { TermVectorStorage storage = new HashMapTermVectorStorage(); VectorClassifier vc = new VectorClassifier(storage); vc.teachMatch("草本","含羞草"); double result = vc.classify("草本", "含羞草"); System.out.println(result); } } 運行結果: 0.9999999999999998 最后,Classifier4J只定義了英文中的停用詞,對於中文而言,庖丁分詞的詞典中已經包含了停用詞。 |