正文
的
max
()
函数即可实现 argmax 的功能。
2.
候选模型
:先介绍一个新概念:对一个单词的
简单编辑
是指:删除(移除一个字母)、置换(单词内两字母互换)、替换(单词内一个字母改变)、插入(增加一个字母)。函数
edits1
(
word
)
返回一个单词的所有简单编辑(译者:称其编辑距离为 1)的集合,不考虑编辑后是否是合法单词:
def edits1(word):
"""与'word'的编辑距离为 1 的全部结果"""
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 for c in letters]
inserts = [L c R for L, R in splits for c in letters]
return set(deletes transposes replaces inserts)
这个集合可能非常大。一个长度为 n 的单词,有 n 个删除编辑,n−1 个置换编辑,26n 个替换编辑,26(n 1) 的插入编辑,总共 54n 25 个简单编辑(其中存在重复)。例如:
>>>len(edits1('something'))
442
然而,如果我们限制单词为
已知
(
known
,译者:即存在于 WORDS 字典中的单词),那么这个单词集合将显著缩小:
def
known(words):
"""'words'中出现在 WORDS 集合的元素子集"""
return set(w for w in words if w in WORDS)
>>>known(edits1('something'))
['something', 'soothing']
我们也需要考虑经过
二次编辑
得到的单词(译者:"二次编辑"即编辑距离为 2,此处作者巧妙运用递归思想,将函数
edits1
返回集合里的每个元素再次经过
edits1
处理即可得到),这个集合更大,但仍然只有很少一部分是已知单词:
def edits2(word):
"""与'word'的编辑距离为 2 的全部结果"""
return (e2 for e1 in edits1(word) for e2 in edits1(e1))
>>> len(set(edits2('something'))
90902
>>> known(edits2('something'))
{'seething', 'smoothing', 'something'
, 'soothing'}
>>> known(edits2('somthing'))
{'loathing', 'nothing', 'scathing', 'seething', 'smoothing', 'something', 'soothing', 'sorting'}
我们称
edits2
(
w
)
结果中的每个单词与 w 的距离为 2。
3.
语言模型
:我们通过统计一个百万级词条的文本 big.txt中各单词出现的频率来估计 P(w),它的数据来源于 古腾堡项目中公共领域的书摘,以及 维基词典中频率最高的词汇,还有 英国国家语料库,函数
words
(
text
)
将文本分割为词组,并统计每个词出现的频率保存在变量
WORDS
中,
P
基于该统计评估每个词的概率:
def words(text):
return re.findall(r'w ', text.lower())
# 统计词频
WORDS = Counter(words(open('big.txt').read()))
def P(word, N=sum(WORDS.values())):
"""词'word'的概率"""
return float(WORDS[word]) / N
可以看到,去重后有 32,192 个单词,它们一共出现 1,115,504 次,"the"是出现频率最高的单词,共出现 79,808 次(约占 7%),其他词概率低一些。
>>> len(WORDS)
32192
>>>