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

  • 相关阅读:
    小米路由通过SSH添加静态路由表之后无法跳转的问题
    极路由通过SSH添加静态路由表之后无法跳转的问题
    Linux服务器压测/拷机软件收集
    RabbitMQ整合Spring Booot【消费者补偿幂等问题】
    找不到共享解决办法
    如何一步步设计一款微服务的补偿方案
    Spring Cloud 支付宝支付的流程
    把同事的重复代码清理干净,老板却让我做了回滚?
    [LeetCode] 565. Array Nesting 数组嵌套
    [LeetCode] Out of Boundary Paths 出界的路径
  • 原文地址:https://www.cnblogs.com/chenying99/p/3185379.html
Copyright © 2020-2023  润新知