zoukankan      html  css  js  c++  java
  • 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只定义了英文中的停用词,对于中文而言,庖丁分词的词典中已经包含了停用词。

  • 相关阅读:
    递归函数及Java范例
    笔记本的硬盘坏了
    “References to generic type List should be parameterized”
    配置管理软件(configuration management software)介绍
    WinCE文件目录定制及内存调整
    使用Silverlight for Embedded开发绚丽的界面(3)
    wince国际化语言支持
    Eclipse IDE for Java EE Developers 与Eclipse Classic 区别
    WinCE Heartbeat Message的实现
    使用Silverlight for Embedded开发绚丽的界面(2)
  • 原文地址:https://www.cnblogs.com/chenying99/p/3185379.html
Copyright © 2011-2022 走看看