第五章 贝叶斯统计 拼音自动查错(2)

一个贝叶斯应用的老故事

还是得讲一个老故事,因为我觉得这个例子能够很好的说明贝叶斯公式。故事是老的但它还没过时,标题叫做拼写检查器。

上个星期,我的两个朋友 Dean 和 Bill 分别告诉我说他们对 Google 的快速高质量的拼写检查工具感到惊奇。比如说在搜索的时候键入 [speling],在不到 0.1 秒的时间内,Google 会返回:你要找的是不是 [spelling]. (Yahoo! 和微软也有类似的功能)。让我感到有点奇怪的是我原想 Dean 和 Bill 这两个很牛的工程师和数学家应该对于使用统计语言模型构建拼写检查器有职业的敏感。但是他们似乎没有这个想法。我后来想了想, 他们的确没什么理由很熟悉统计语言模型。不是他们的知识有问题, 而是我预想的本来就是不对的。

我觉得, 如果对这方面的工作做个解释, 他们和其他人肯定会受益。 然而像Google 的那样工业强度的拼写检查器的全部细节只会让人感到迷惑而不是受到启迪。

在开始前,我们还是来讲讲,我们要做一件什么样的事情,为什么这件事情跟贝叶斯公式有关系

对于英文输入来说,有的单词太多,经常少一个字母或者都一个字母那是在正常不够的事情了,就像刚才说的,在搜索框里本来是要搜索spelling的,但是思想一放松,结果就在搜索框里写成了speling,这个时候我们要搜索不仅仅要能识别这个单词是错误的,而且要知道我们原本的意思是想输入spelling这个单词,对于工程来说就是把speling自动的提示成spelling

用概率的观点来考虑一下这个问题,来说明为什么用概率的方法可以解决这一类问题,而且还能达到很好的效果。

有关统计,在莎士比亚年代16世纪单词量差不多在14w左右,所有的语言都会随着时代的发展而发展,英文同样也不例外,比如no zuo no die,英文吸收了很多外来的词汇,这也不奇怪,到现在差不多有60w-100w的单词量,但主要词汇没有发生太多的变化,四六级的词汇才6000左右,即使到了专业八级也就是13000的单词量,每次谈起四六级,总会想起清晨,抱着一本英语字典,背诵英语的莘莘学子。对于单词虽然多,但总归是可以列举完的如{smile,love,eternity,freedom,...},我们可以用一个集合来表示它$B<> n: { B 1,B<> 2,B 3 } $,每个B代表着一个单词。

如果要进行一项统计,统计我们会产生拼写错误的概率是多少呢?虽然这有点无聊。计算方法很多,其中有一种是可行的,把每个单词可能出现的错误相加起来就是产生拼写错误的概率了,这也是全概率的公式了,如下:

$$P(拼写错误)=\sum<> {n}P(拼写错误|{单词} n)P({单词}_ n)$$

也就是说这里的“结果”是“拼写错误”,各种原因是“每个单词产生拼写错误”,这就是用全概率公式来形象的描述一种现实中的问题。

就计算$P(拼写错误)$这个概率来说,对我们解决刚才拼音纠正来说,好像没有多大的用处,确实是这样子的,但是数学总是不会让我们经常失望,即使在失望的时候,它也经常告诉我们你反过来想想这个问题,这样可能就是这个问题的解,这就是初中老师一直给我们介绍的逆向思维。

而全概率的逆向过程,不就是贝叶斯公式吗? 贝叶斯公式:假设事件A已经发生了,让我们来推理是那个原因导致的,或者说哪个原因起来主要的作用。 按照拼音检查器的问题,套用贝叶斯公式可以表述为:现在已经发生了lates 错误拼写的这件事,那到底是因为那个单词的拼写错误而导致了这个结果呢?导致这一结果的那个词就是我们要的正确的那个词。 把参数代入到贝叶斯公式里:

$$P(词<> {正确} | 词 {lates} )=\frac{P(词<> {lates}|词 {正确})P(词<> {正确})}{P(词 {lates})}$$

再来研究一下公式的各项$P(词<> {正确}|词 {lates})$,这个条件概率的意思是写出lates 这个词,那他写成一个正确的词的概率是多少?即当我们写出lates ,我们可能的正确的词是lates ,latest,也可能是跟lates 相近的,比如在哪里多个字母,少个字母的;但是很少可能写成sunshine,因为sunshine跟lates 离得太远了,概率很低,$P(词<> {正确}|词 {lates})$已经把可能出现正确的词语过滤出来了,过滤的意思是指,排除了$P(词<> {正确}|词 {lates})=0$的词语,这样范围就少了很多,$P(词<> {正确}|词 {lates})$概率的计算受到很多因素的影响,其实并不好计算,所有通常我们都把

$$P(词<> {正确}|词 {lates})=\begin{cases}1,有可能出现的词语\0,不可能出现的词语\\end{cases}$$

选出有可能出现的词语,这个过程写成python代码:

alphabet = 'abcdefghijklmnopqrstuvwxyz'
def edits1(word):
   s = [(word[:i], word[i:]) for i in range(len(word) + 1)]
   deletes    = [a + b[1:] for a, b in s if b]
   transposes = [a + b[1] + b[0] + b[2:] for a, b in s if len(b)>1]
   replaces   = [a + c + b[1:] for a, b in s for c in alphabet if b]
   inserts    = [a + c + b     for a, b in s for c in alphabet]
   return set(deletes + transposes + replaces + inserts)

函数edits1:定义为使用了几次插入( 在词中插入一个单字母), 删除( 删除一个单字母), 交换( 交换相邻两个字母), 替换( 把一个字母换成另一个) 的操作从一个词变到另一个词。

接下来$P(词<> {lates})$的概率怎么算了,没必要算,$P(词 {lates})$是一个固定值,并不会影响到我们的决策。 而是$P(词<> {正确})$正确词的概率,这是什么意思呢?我们刚才有说过,英文单词量有100w左右,四六级的词汇才6000左右,四六级的单词是高频词,也就是说有些词是常用词,而有些词比较孤僻,一生中让人看见的次数是有限的,那怎么计算这个概率呢?比较常见而简单的方法是,拿几本畅销书,数一数里面单词的个数就能知道这个概率了。 计算$P(词 {正确}|词_ {lates})$,可以简化为:

$$P(词<> {正确}|词 {lates})\in P(词<> {lates}|词 {正确})P(词<> {正确})$$ $$P(词 {正确}|词_ {lates})=\begin{cases} 1,有可能出现的词语\ 0,不可能出现的词语\ \end{cases} $$

公式的所有的意义都清楚了,最后可以通过程序实现出来。 这里给出了一个测试的例子和一个运行测试的例子。 效果 现在我们看看算法效果怎么样。在飞机上我尝试了好几个例子, 效果还行。飞机着陆后, 我从牛津文本档案库 (Oxford Text Archive) 下载了 Roger Mitton 的 Birkbeck 拼写错误语料库。从这个库中, 我取出了两个集合, 作为我要做拼写检查的目标。第一个集合用来作为在开发中作为参考, 第二个作为最后的结果测试。也就是说, 我程序完成之前不参考它, 而把程序在其上的测试结果作为最后的效果。用两个集合一个训练一个对照是一种良好的实践, 至少这样可以避免我通过对特定数据集合进行特殊调整从而自欺欺人。

这个拼写检查器大约1 秒能处理10 多个单词, 并且达到 80% -90% 的准确率。

这个程序还有很多的优化空间,但现在的效果是不错的。我们也发现了,贝叶斯在这类应用上竟然可以如此的有效。贝叶斯公式的意义在工程中可以如此的常见。

但还要回过头来想想,这是为什么呢?

碰到这种问题,脑子是怎么想的,看到speling,搜索自己记忆里的单词,找出跟他长得比较像的$P(词<> {正确}|词 {lates})=1$,spelling,当然还有可能是别的长得像的词,但我们计算的是$P(词<> {正确}|词 {lates})\in P(词<> {lates}|词 {正确})P(词<> {正确})$,这里多了$P(词 {正确})$,$P(词<> {正确})$是猜测的先验概率。$P(词 {正确}|词_ {lates})$有个问题,如果好几个词的概率是一样的,那就很难判断哪个词要放在前面了,先验概率在一定的程度上解决了这个问题。

PS: 如本文对您有帮助,不妨通过一下方式支持一下博主噢 ^_^

官方
微信
官方微信
Q Q
咨询
意见
反馈
返回
顶部