输入法中统计语言模型的建立以及平滑

转自:http://blog.qq.com/qzone/95007909/1274760124.htm

目前正在编写手机平台上的输入法,在输入法中要向实现句子级别的智能输入,必须借助统计语言模型,依靠统计语言模型中的词概率值,输出最可能的句子。下面将介绍统计语言模型的建立以及平滑。

目前输入法中常用的语言模型有trigram(三元)和bigram(二元),其中微软拼音、智能狂拼使用的是trigram,谷歌拼音、搜狗拼音和紫光则是bigram。本文以二元模型为例来说明模型的建立和平滑。

下面分三个方面来介绍:

      语料库的预处理

      模型的建立

     模型的平滑

一.语料库的预处理

原始语料库来源于北京大学语言研究所提供的981月人民日报标注语料。下载的已切分的语料都是形如“19980131-04-012-001/m  现实/n  /u  顿悟/vn  /d  /p  /v  /v  /Ng  /v  /w  ,有的前面还保留了日期编号,因为这些切分语料的来源是人民日报。预处理主要是按标点符号分句,句子简单定义为( 。?!  ;)这五种标点符号结尾的词串,句子首尾分别添加<BOS><EOS>这两个表示句子开始和结束的标记,这在2-gram建模时要用的,后面会提到。处理过程中,忽略词类信息和前面的日期信息,因为我这个切分系统不考虑词类标注。如前面这句预处理后应该为下面形式 <BOS>现实  顿悟     形来 <EOS> ,当然切分词之间你可以用你想用的符号标记,而不必是空格。因为考虑到所有的英文字符和数字的ASCII,我用了下面方法实现之

   (至于为什么切分成这样,请参照马尔科夫模型的概率归一性)

FileReader  fi=new FileReader(f);

      BufferedReader bf=new BufferedReader(fi);

      FileWriter fo=new FileWriter(ff);

      StringBuffer s1 = new StringBuffer();   

      String s;

      while((s=bf.readLine())!=null)

      {

       for(int i=0;i<s.length();i++)

              {             

                  char a=s.charAt(i);

                if ((a == '。' || a == '?' || a == '!' || a == ':' || a == ';' ))  //一句结束

 

                {                               

 String s2 = new String(s1);

 

              fo.write("<BOS>");                //在句子前加 <BOS>

                   

                   fo.write(s2);

                

         fo.write("<EOS>");             //在句子末尾加 <EOS>

               fo.write("\r\n"); 

              fo.flush();

              s1 = new StringBuffer();

            }

           else if ( a == '/')                         

            s1 = s1.append((char)32);   //分词位置空格

           else if (a > 256 )                         

           s1 = s1.append(a);      

       }

      }

 二:模型的建立

     在这里首先简单介绍一下n-gram模型和2-gram模型。

     根据语言样本估计出的概率分布P就称为语言L的语言模型。对给定的句子w1w2…wn,(数字,n,i都为下标,wi为句子s的一个词)。由链式规则(Chain rule),P(s) = p(w1)p(w2|w1)p(w3|w1w2)……p(wn|w1w2w3w(n-1))  , p(wi|w1w2w(i-1))而言,(w1w2w(i-1))即为wi的历史。考虑前面n-1个词构成历史的模型即为n-gram模型。 n越大,提供的语境信息也越多,但代价就越大,且需训练语料多;n较小时,提供的信息比较少,但计算代价小,且无需太多训练语料。

c(w1,…,wi)表示词串w1,w2wi在训练语料中出现的次数,则由最大似然估计, P(wn|w1,,w(n-1)) = c(w1,…,wn) / c(w1,…,w(n- 1)). 同理,则2-gram P(wn|w(n-1)) = c(w(n-1),wn) / c(w(n-1)).

回归项目:)  训练语料一共有5万多个不同的词。建立2-gram统计模型时不断要把每个词在训练语料中出现频率统计出来,还要把每个词及其后面的那个词组成的2-gram在训练语料中出现频率统计出来。因为在切分时会频繁的在建立的2-gram模型中查找相关的数据,所有,存储这个2-gram模型数据的数据结构一定要能提供高效的查找。故选择hash表,它能提供常数时间的查找。Java类库里提供了HashMap类,基于数据两还不是非常大,故可直接拿来用。在存储时,每一个key值对应一个在训练语料中出现过的词语,而每一个key值对应的value值又是一个HashMap。暂且称为子hashmap.这个结构有点类似文件结构里的二级索引。 其相关代码如下:

怎么在预处理文件里把词分别读出来就不罗嗦了,方法:每读入一行,按空格分成String数组,用个正则表达式匹配下即能得到。

下面这个方法传入的两个词组成一个2-gramprewd为前一个词,currwd为紧随其后的词

public  void add(String prewd , String currwd){    

                   String key = prewd;

             String curr = currwd;

            if(mainhm.containsKey(key)==false)        

             {       // map 中无,则添加

                 HashMap hm = new HashMap();        //首先,新构造一个 MAP

           hm.put(key , new Double(1.0));           

        mainhm.put(key,hm);           // KEY 和对应的 MAP 放入 MAP 

           }

            else         // map 中含有该词            

            {

                 HashMap temp = (HashMap)mainhm.get(key);              

                   Double count = ((Double)temp.get(key)).doubleValue() + 1.0;                               temp.put(key , new Double(count));                                

                 if (temp.containsKey(curr))             //判断 map 中是否含有该词

                    {

                           Double value = ((Double)temp.get(curr)).doubleValue() + 1.0; 

                           temp.put(curr , new Double(value));   

                    }           

                    else

                         temp.put(curr, new Double(1.0));     //若无,则将其存入子map  

 

                        mainhm.put(key,temp);

             }           

 

      }

三.模型的平滑

因为语言中的大部分词属于低频词,所以稀疏问题肯定存在。而MLE(最大似然估计)给在训练语料中没有出现的2-gram的赋给0概率。所以还得对2-gram模型进行数据平滑,以期得到更好的参数。目前平滑技术比较多,如Add-one,Add-delta,Witten-Bellheld-out留存平滑等。本文采用Katz方法进行平滑:

Katz算法的平滑公式是:

  图片


其中
图片

 

 在我们实现算法的时候,先遍历n-gram中的数据,先将C(Wi,Wi-1) > 0时候的Pkz 都算出来(即分子上面的),然后再从unigram中,将分母中所有的Pml 都算出来,然后代入上式,计算 并将 保存到n-gram的数据结构中。

部分代码如下:

Iterator it = mainhm.keySet().iterator();

    while(it.hasNext())

          {

                 String key = (String)it.next();

 

                 HashMap sonhm= (HashMap)mainhm.get(key);   //子Map           

                 Double n= (Double)sonhm.get(key);

                 Iterator itr = sonhm.keySet().iterator(); 

                  itr.next();

                 while(itr.hasNext())

                 {

                   //套平滑公式

                   String s=(String)itr.next();

                   Double value=(Double)sonhm.get(s);

                   Double newvalue=(value-0.3)/n;

                   sonhm.put(s,newvalue);

                }

           }

    以上讲述了统计语言模型的建立以及平滑算法,输入法正在制作当中,按上面讲述的方法,目前准备率还不得而知,仅仅是个人的一些理解。

 


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值