python拼写_用 Python 27 行实现拼写纠正

用 Python 27 行实现拼写纠正

徐宥翻译过一次,但是后来 Norvig 又更新了代码。

首先,这不是一个工业级的拼写纠正器,是 Peter Norvig(Director of Research,Google) 在一次长途航班上完成并给出解释的玩具级拼写纠正器。

spell.py :

import re

from collections import Counter

def words(text): return re.findall(r'\w+', text.lower())

WORDS = Counter(words(open('big.txt').read()))

def P(word, N=sum(WORDS.values())):

"Probability of `word`."

return WORDS[word] / N

def correction(word):

"Most probable spelling correction for word."

return max(candidates(word), key=P)

def candidates(word):

"Generate possible spelling corrections for word."

return (known([word]) or known(edits1(word)) or known(edits2(word)) or [word])

def known(words):

"The subset of `words` that appear in the dictionary of WORDS."

return set(w for w in words if w in WORDS)

def edits1(word):

"All edits that are one edit away from `word`."

letters = 'abcdefghijklmnopqrstuvwxyz'

splits = [(word[:i], word[i:]) for i in range(len(word) + 1)]

deletes = [L + R[1:] for L, R in splits if R]

transposes = [L + R[1] + R[0] + R[2:] for L, R in splits if len(R)>1]

replaces = [L + c + R[1:] for L, R in splits if R for c in letters]

inserts = [L + c + R for L, R in splits for c in letters]

return set(deletes + transposes + replaces + inserts)

def edits2(word):

"All edits that are two edits away from `word`."

return (e2 for e1 in edits1(word) for e2 in edits1(e1))

原理

首先我们知道,这个 corrector 是基于 big.txt 这个文本工作的,我随便写了一个 big.txt,它首先生成 WORDS 这个 Counter 对象,例如

>>> WORDS

Counter({'a': 7, 'and': 7, 'of': 5, 'spelling': 4, 'in': 4, ..., 'code': 1})

P 函数返回一个词在 big.txt 中出现的概率

>>> P('they')

0.025

known 函数返回一组单词里,在 big.txt 中出现过的单词

>>> known(['I','you','they'])

{'you', 'they'}

edits1 函数返回,对一个单词,进行一个字母的修改,所有可能的结果

>>> edits1('yo')

{'yc', 'yh', 'wyo', 'bo', 'yt', 'yio', 'yu', 'io', 'yz', 'yoy', 'ypo', 'yob', 'yy', 'ygo', 'syo', 'to', 'vyo', 'eo', 'xo', 'yuo', 'yb', 'yoc', 'yf', 'yao', 'yo', 'yon', 'yro', 'po', 'tyo', 'ymo', 'ryo', 'yox', 'yoi', 'no', 'yyo', 'yw', 'mo', 'yow', 'yho', 'dyo', 'nyo', 'yg', 'cyo', 'fo', 'yk', 'yov', 'yq', 'uyo', 'yoe', 'qo', 'yv', 'oy', 'kyo', 'ys', 'yol', 'yot', 'ya', 'yqo', 'iyo', 'yx', 'yd', 'lo', 'yno', 'yoj', 'yod', 'yfo', 'yko', 'ylo', 'yj', 'yeo', 'gyo', 'ayo', 'yoh', 'lyo', 'you', 'yok', 'ydo', 'ywo', 'ao', 'ybo', 'oo', 'y', 'pyo', 'yr', 'yoo', 'ye', 'yco', 'yto', 'do', 'so', 'yoz', 'vo', 'hyo', 'yxo', 'o', 'yn', 'ym', 'ko', 'yl', 'yi', 'yop', 'yos', 'uo', 'wo', 'yzo', 'jo', 'yof', 'yso', 'yjo', 'yoa', 'zo', 'go', 'oyo', 'yoq', 'yom', 'myo', 'yp', 'yvo', 'jyo', 'co', 'yog', 'xyo', 'ro', 'eyo', 'qyo', 'fyo', 'zyo', 'ho', 'yor', 'byo'}

所以 edits2 函数返回对一个单词,进行两个字母的修改,所有可能的结果。

所以 candidates(word) 的执行是:如果 word 在 big.txt 中,那么返回 word,否则

如果对 word 修改一个字母后,结果在 big.txt 中,那么返回修改一个字母后的样子(可能是很多个结果),否则

如果对 word 修改两个字母后,结果在 big.txt 中,那么返回修改一个字母后的样子(可能是很多个结果),否则

返回 word

然后 correction(word) 的执行就是接受 candidates(word) 的结果列表,返回出现概率最高的那一个。

理解程序

首先,用概率论理解一下我们的程序。函数 correction(w) 就是在给定一个单词 w 的情况下,在一组候选答案中选出一个的单词 c,使得 c 是正确答案的概率最大,即

据贝叶斯定理,我们有

因为 P(w) 是一个定值,我们可以略去

所以我们的程序可以分成四部分:选择机制,从候选答案中选出正确概率最高的那个 argmax

候选模型,给出候选答案 candidates

语言模型,c 在文本中出现的概率 P(c)

谬误模型,作者在文本中想输入 c,结果输入了 w 的概率 P(w|c)

在我们的程序中,我自作主张的使用了这样的谬误模型:未经修改的一定比修改过的概率高,修改一处的肯定比修改两处的概率高。这一步在 candidates() 函数中已经实现了,所以在 correction 的计算中没有 $\tt P(w|c)$ 这个因子。

改进程序

Norvig 在他的书里专门写了一章讨论改进这个程序。

改进语言模型

显然 WORDS 里没有的词不会出现在候选答案中,所以我们可以考虑使用更大的语料库。

另外,有时候一个词不在 WORDS 里,但是我们可以通过记忆一些字母序列给出纠正,比如把 electroencephalographicallz 纠正成 electroencephalographically。

改进谬误模型

我们现在用的谬误模型会把 adres 纠正成 acres 而不是 address,要避免这种情况,我们就需要重新确定各种纠正的成本是多少,比如双写某个字母或者替换一个元音字母这类常见的纠正,应该有更低的成本。

改进谬误模型对语言模型也是有帮助的,如果按现有的谬误模型,我们不敢在语言模型里放 forth 这个词,因为一旦放进去,fourth 被写成 forth 就不会被检查出来了。所以在改进语言模型之前我们应该先修正这个不合理的谬误模型。

更大范围的修改

现在我们的程序最多承受修改两个字母,因为修改三个字母的计算量非常大,但其实我们可以容忍一小部分三个字母的修改,比如涉及到在元音后加元音、元音替换、c和s替换等情况的。

改变 correction 函数接受的参数

比如,我们可以传入要检查的单词的上下文。我们现在的拼写检查,都是针对一个单词的,但是这种检查很难确定应该用 advice 还是 advise,用 where 还是 were,除非我们考虑到这个单词的上下文。

我们还可以传入这个文件的方言,英式英语和美式英语在用词和拼写上差异都很大。

换一种语言实现

Python 是一门解释型语言,换一种编译型语言可能会更快。与每次纠正都需要到 WORDS 中去查询相比,把一些常见的纠正数据放在缓存里可能会运行得更快。你可以实际检查一下,程序的时间都花在了哪里,然后去优化它。

进一步阅读Roger Mitton 针对拼写检查的一篇综述文章

Jurafsky and Martin 的自然语言处理著作

GNU Aspell 提供了很多拼写检查的材料,包括一些测试数据集

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值