lucene 4.x 使用N-Gram模型分词器实例。

N-Gram模型:

N-Gram是大词汇连续语音识别中常用的一种语言模型,对中文而言,我们称之为汉语语言模型(CLM, Chinese Language Model)。汉语语言模型利用上下文中相邻词间的搭配信息,在需要把连续无空格的拼音、笔划,或代表字母或笔划的数字,转换成汉字串(即句子)时,可以计算出具有最大概率的句子,从而实现到汉字的自动转换,无需用户手动选择,避开了许多汉字对应一个相同的拼音(或笔划串,或数字串)的重码问题。

  该模型基于这样一种假设,第n个词的出现只与前面N-1个词相关,而与其它任何词都不相关,整句的概率就是各个词出现概率的乘积。这些概率可以通过直接从语料中统计N个词同时出现的次数得到。常用的是二元的Bi-Gram和三元的Tri-Gram。

     在介绍N-gram模型之前,让我们先来做个香农游戏(Shannon Game)。我们给定一个词,然后猜测下一个词是什么。当我说“艳照门”这个词时,你想到下一个词是什么呢?我想大家很有可能会想到“陈冠希”,基本上不会有人会想到“陈志杰”吧。N-gram模型的主要思想就是这样的。

   对于一个句子T,我们怎么算它出现的概率呢?假设T是由词序列W1,W2,W3,…Wn组成的,那么P(T)=P(W1W2W3Wn)=P(W1)P(W2|W1)P(W3|W1W2)…P(Wn|W1W2…Wn-1)

 

补充知识:

   

 

 

   但是这种方法存在两个致命的缺陷:一个缺陷是参数空间过大,不可能实用化;另外一个缺陷是数据稀疏严重。

   为了解决这个问题,我们引入了马尔科夫假设:一个词的出现仅仅依赖于它前面出现的有限的一个或者几个词。

   如果一个词的出现仅依赖于它前面出现的一个词,那么我们就称之为bigram。即
   P(T) = P(W1W2W3…Wn)=P(W1)P(W2|W1)P(W3|W1W2)…P(Wn|W1W2…Wn-1)
          ≈P(W1)P(W2|W1)P(W3|W2)…P(Wn|Wn-1)

   如果一个词的出现仅依赖于它前面出现的两个词,那么我们就称之为trigram。

   在实践中用的最多的就是bigram和trigram了,而且效果很不错。高于四元的用的很少,因为训练它需要更庞大的语料,而且数据稀疏严重,时间复杂度高,精度却提高的不多。

   那么我们怎么得到P(Wn|W1W2…Wn-1)呢?一种简单的估计方法就是最大似然估计(Maximum Likelihood Estimate)了。即P(Wn|W1W2…Wn-1) = (C(W1 W2…Wn))/(C(W1 W2…Wn-1))

剩下的工作就是在训练语料库中数数儿了,即统计序列C(W1 W2…Wn) 出现的次数和C(W1 W2…Wn-1)出现的次数。

               下面我们用bigram举个例子。假设语料库总词数为13,748

 

                       

   

   P(I want to eat Chinese food)
=P(I)*P(want|I)*P(to|want)*P(eat|to)*P(Chinese|eat)*P(food|Chinese)
=0.25*1087/3437*786/1215*860/3256*19/938*120/213
=0.000154171                                                                                                                                                                                               

    ps:网上很多资料中,表1,词与词频的张表是没有的,所以造成文章表意不清。

     这里还有一个问题要说,那就是数据稀疏问题了,假设词表中有20000个词,如果是bigram那么可能的N-gram就有400000000个,如果是trigram,那么可能的N-gram就有8000000000000个!那么对于其中的很多词对的组合,在语料库中都没有出现,根据最大似然估计得到的概率将会是0,这会造成很大的麻烦,在算句子的概率时一旦其中的某项为0,那么整个句子的概率就会为0,最后的结果是,我们的模型只能算可怜兮兮的几个句子,而大部分的句子算得的概率是0. 因此,我们要进行数据平滑(data Smoothing),数据平滑的目的有两个:一个是使所有的N-gram概率之和为1,使所有的N-gram概率都不为0.有关数据平滑的详细内容后面会再讲到,这里不再赘述。

   了解了噪声信道模型和N-gram模型的思想之后,其实我们自己就能实现一个音词转换系统了,它是整句智能输入法的核心,其实我们不难猜到,搜狗拼音和微软拼音的主要思想就是N-gram模型的,不过在里面多加入了一些语言学规则而已。

http://blog.csdn.net/lengyuhong/article/details/6022053

统计语言模型相关资料:

http://blog.csdn.net/ggxxkkll/article/details/8682273

源码实例:

package com.jiepu.lucene_49;

import java.io.IOException;
import java.io.StringReader;
import java.util.Iterator;
import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.ngram.EdgeNGramTokenFilter;
import org.apache.lucene.analysis.ngram.EdgeNGramTokenizer;
import org.apache.lucene.analysis.ngram.Lucene43EdgeNGramTokenizer;
import org.apache.lucene.analysis.ngram.Lucene43NGramTokenizer;
import org.apache.lucene.analysis.ngram.NGramTokenizer;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
import org.apache.lucene.analysis.tokenattributes.PositionLengthAttribute;
import org.apache.lucene.analysis.tokenattributes.TermToBytesRefAttribute;
import org.apache.lucene.analysis.tokenattributes.TypeAttribute;
import org.apache.lucene.util.Attribute;
import org.apache.lucene.util.Version;
/**
 * lucene 4.x 使用N-Gram模型和Edge-NGram模型分词器实例。
 * @author yunshouhu
 * 常用统计语言模型,包括了N元文法模型(N-gram Model)、隐马尔科夫模型(Hidden Markov Model,简称HMM)、最大熵模型(Maximum Entropy Model)。
 *	N-Gram这是一种依赖于上下文环境的词的概率分布的统计计算语言模型。
 *  假定,在一个语句中第i个词出现的概率,条件依赖于它前面的N-1个词,即将一个词的上下文定义为该词前面出现的N-1个词,
 *  这样的语言模型叫做N-gram模型(N元文法统计模型)。公式如下:
 */
public class TestNGram {	
	public static void main(String[] args) {
		String s = "dd add addd adddd 编码规范从根本上解决了程序维护员的难题;规范的编码阅读和理解起来更容易,也可以快速的不费力气的借鉴别人的编码。对将来维护你编码的人来说,你的编码越优化,他们就越喜欢你的编码,理解起来也就越快。";
		StringReader sr = new StringReader(s);	
		//N-gram模型分词器
		Tokenizer tokenizer = new NGramTokenizer(Version.LUCENE_46,sr);
		//Edge-NGram 边缘模型,范围模型分词器
		//Tokenizer tokenizer=new EdgeNGramTokenizer(Version.LUCENE_46, sr, 1, 10);		
		//Tokenizer tokenizer=new Lucene43NGramTokenizer(sr);
		//Tokenizer tokenizer=new Lucene43EdgeNGramTokenizer(Version.LUCENE_46, sr, 1, 10);
		testtokenizer(tokenizer);
	}

	private static void testtokenizer(Tokenizer tokenizer) {
			
		try {		
			/*			 
			Iterator<Class<? extends Attribute>> iterator = tokenizer
					.getAttributeClassesIterator();
			while (iterator.hasNext()) {
				Class<? extends Attribute> attrClass = iterator.next();
				System.out.println(attrClass.getSimpleName());
			}*/						
			tokenizer.reset();
			while(tokenizer.incrementToken())
			{
				//CharTermAttribute
				//TermToBytesRefAttribute
				//PositionIncrementAttribute
				//PositionLengthAttribute
				//OffsetAttribute
				CharTermAttribute charTermAttribute=tokenizer.addAttribute(CharTermAttribute.class);
				TermToBytesRefAttribute termToBytesRefAttribute=tokenizer.addAttribute(TermToBytesRefAttribute.class);
				PositionIncrementAttribute positionIncrementAttribute=tokenizer.addAttribute(PositionIncrementAttribute.class);
				PositionLengthAttribute positionLengthAttribute=tokenizer.addAttribute(PositionLengthAttribute.class);
				OffsetAttribute offsetAttribute=tokenizer.addAttribute(OffsetAttribute.class);
				TypeAttribute typeAttribute = tokenizer.addAttribute(TypeAttribute.class);
				//System.out.println(attribute.toString());
				System.out.println("term="+charTermAttribute.toString()+","+offsetAttribute.startOffset()+"-"+offsetAttribute.endOffset()
						+",type="+typeAttribute.type()+",PositionIncrement="+positionIncrementAttribute.getPositionIncrement()
						+",PositionLength="+positionLengthAttribute.getPositionLength());
				
			}			
			tokenizer.end();
			tokenizer.close();
		} catch (IOException e) {
			e.printStackTrace();
		}		
	}
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值