Classifier4J的中文支持


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只定義了英文中的停用詞,對於中文而言,庖丁分詞的詞典中已經包含了停用詞。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM