英语单词拼写检查是word提供的一个功能,使用google的时候也可以看到,当你打错字了,会给你提供一个备选。也就是给定一个词c,你应该提供一个候选的词w,这个词w应该是c因为打错一个字而产生的。即表述为 argmax p(w|c). 利用贝叶斯定理即转换为 argmax p(c|w)p(w)/p(c) = argmax p(c|w)p(w). 挑选出词w由两个公式来描述,一个是p(w):这是词w的概率,可以称之为语言模型,一个是p(c|w):是词w产生词c的概率,可以称之为错误模型。
p(w):语言模型,用于描述一个词w在整个语言中的分布概率,如果出现多个词则可以称之为n-gram语言模型,即一定长度的多个词在语言中的分布概率。可以通过统计一个大型语料获取,但是语言模型存在的一个问题是一个单一的语料库中词语的分布个实际的词语分布之间可能存在差异,因此这样的概率不一定可靠,而且对于OOV还需要进行平滑。
p(c|w):错误模型,即词语w转换成词语c的概率,对于一个大小为N的词表中的每个词,都存在这样的一个条件概率。但是一般来说只是对特定的词才有大于0的值,其他的词全部为0.如果有一个专业的统计信息,那么可以直接计算一个词转换成另一个词的概率,也可以通过其他方法来衡量,比如两个词的编辑距离,两个词中字母交集的大小,甚至是两个词的最长公共子串等等。
有了上面两个概率分布,就一个进行错误纠正了,但是要对词表中的每个词都进行这样的操作,这样速度就很慢。一个改进就是先根据编辑距离由c找出一些候选词,再从候选词之中挑选出最后可能的词,提高了效率,也有可能直接排除了正确的答案。比如直接根据编辑距离,挑选出所有跟c的编辑距离小于等于2的词w,然后再用贝叶斯的方法从这些候选词之中挑选出最有可能的词Wopt。
ps:一个词跟另个一个词的编辑距离定义为使用不同编辑操作的次数,编辑操作包括插入,删除,替换,交换四种。
1 def edits1(word):
3 deletes = [a + b[1:] for a, b in splits if b]
4 transposes = [a + b[1] + b[0] + b[2:] for a, b in splits if len(b)>1]
5 replaces = [a + c + b[1:] for a, b in splits for c in alphabet if b]
6 inserts = [a + c + b for a, b in splits for c in alphabet]
7 return set(deletes + transposes + replaces + inserts)
这是一段很神奇的代码,我很喜欢,想法太神了!!!
产生编辑距离为2的代码:
2 return set(e2 for e1 in edits1(word) for e2 in edits1(e1) if e2 in NWORDS)
在这里NWORDS代表当前已经出现的词,除此之外的词都是未登录词。
上述内容可以在:http://norvig.com/spell-correct.html 中发现!
下面又出现另外一个问题,对有些语言来说不存在这种拼写检查,比如汉语。这里所需要的不是一个词拼写检查,而是类似于词组的拼写检查,比如我输入“搜索殷勤”,这个时候谷歌给出的提示是“搜索引擎” 这个词,明显的在一般情况下这样的提示是很友好的。在这里也可以引入贝叶斯公式的方法来处理,对于一个可能的候选词组w,挑选出最大概率的一个,既 argmax p(w|c),可以直接转换为 argmax p(w)p(w|c),但是这里p(w)用的应该是n-gram文法模型, p(w|c)可以考虑使用编辑距离来作为度量,即计算w和c之间的编辑距离。这里产生候选词组w的方法可以直接使用单个词的操作,对于“搜索引擎”这个词语来说,可以产生“搜引擎”,“索引擎”,等等,但是这样的候选在一般情况是没有意义的,对于“搜索引擎”这样的词,在分词的角度来看是一个combination,即可以划分成两个词“搜索”和“引擎”也可以直接当做一个词来用,在候选词w时,可以考虑划分成更细的力度,然后替换其中的一个词,产生新的候选词,但是这样会形成很多的候选,毫无效率。。。。。。
对上面方法的一个改进就是直接使用n-gram语言模型, 挑选出“搜索”这个词之后,长度为2的候选中,最后可能的两个即 argmax p(w1 w2|搜索) = argmax p(搜索w1 w2)/p(搜索)。但是这样需要挑选的词来说并没有多少变化。所以最后这个问题就演化成计算不同长度串中,最有可能的一个!