21行Python代码实现拼写检查器


Posted in Python onJanuary 25, 2016

引入

大家在使用谷歌或者百度搜索时,输入搜索内容时,谷歌总是能提供非常好的拼写检查,比如你输入 speling,谷歌会马上返回 spelling。
下面是用21行python代码实现的一个简易但是具备完整功能的拼写检查器。

代码

import re, collections

def words(text): return re.findall('[a-z]+', text.lower()) 

def train(features):
  model = collections.defaultdict(lambda: 1)
  for f in features:
    model[f] += 1
  return model

NWORDS = train(words(file('big.txt').read()))

alphabet = 'abcdefghijklmnopqrstuvwxyz'

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

def known_edits2(word):
  return set(e2 for e1 in edits1(word) for e2 in edits1(e1) if e2 in NWORDS)

def known(words): return set(w for w in words if w in NWORDS)

def correct(word):
  candidates = known([word]) or known(edits1(word)) or known_edits2(word) or [word]
  return max(candidates, key=NWORDS.get)
correct函数是程序的入口,传进去错误拼写的单词会返回正确。如:

>>> correct("cpoy")
'copy'
>>> correct("engilsh")
'english'
>>> correct("sruprise")
'surprise'

除了这段代码外,作为机器学习的一部分,肯定还应该有大量的样本数据,准备了big.txt作为我们的样本数据。

背后原理

上面的代码是基于贝叶斯来实现的,事实上谷歌百度实现的拼写检查也是通过贝叶斯实现,不过肯定比这个复杂多了。
首先简单介绍一下背后的原理,如果读者之前了解过了,可以跳过这段。
给一个词,我们试图选取一个最可能的正确的的拼写建议(建议也可能就是输入的单词)。有时也不清楚(比如lates应该被更正为late或者latest?),我们用概率决定把哪一个作为建议。我们从跟原始词w相关的所有可能的正确拼写中找到可能性最大的那个拼写建议c:

argmaxc P(c|w)

通过贝叶斯定理,上式可以转化为

argmaxc P(w|c) P(c) / P(w)

下面介绍一下上式中的含义:

  • P(c|w)代表在输入单词w 的情况下,你本来想输入 单词c的概率。
  • P(w|c)代表用户想输入单词c却输入w的概率,这个可以我们认为给定的。
  • P(c)代表在样本数据中单词c出现的概率
  • P(w)代表在样本数字中单词w出现的概率

可以确定P(w)对于所有可能的单词c概率都是一样的,所以上式可以转换为
argmaxc P(w|c) P(c)
我们所有的代码都是基于这个公式来的,下面分析具体代码实现

代码分析

利用words()函数提取big.txt中的单词

def words(text): return re.findall('[a-z]+', text.lower())

re.findall(‘[a-z]+'是利用python正则表达式模块,提取所有的符合'[a-z]+'条件的,也就是由字母组成的单词。(这里不详细介绍正则表达式了,有兴趣的同学可以看 正则表达式简介。text.lower()是将文本转化为小写字母,也就是“the”和“The”一样定义为同一个单词。

利用train()函数计算每个单词出现的次数然后训练出一个合适的模型

def train(features):
  model = collections.defaultdict(lambda: 1)
  for f in features:
    model[f] += 1
  return model
NWORDS = train(words(file('big.txt').read()))

这样NWORDS[w]代表了单词w在样本中出现的次数。如果有一个单词并没有出现在我们的样本中该怎么办?处理方法是将他们的次数默认设为1,这里通过collections模块和lambda表达式实现。collections.defaultdict()创建了一个默认的字典,lambda:1将这个字典中的每个值都默认设为1。

现在我们处理完了公式argmaxc P(w|c) P(c)中的P(c),接下来处理P(w|c)即想输入单词c却错误地输入单词w的概率,通过 “edit distance“--将一个单词变为另一个单词所需要的编辑次数来衡量,一次edit可能是一次删除,一个交换(两个相邻的字母),一次插入,一次修改。下面的函数返回一个将c进行一次编辑所有可能得到的单词w的集合:

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

相关论文显示,80-95%的拼写错误跟想要拼写的单词都只有1个编辑距离,如果觉得一次编辑不够,那我们再来一次

def known_edits2(word):
  return set(e2 for e1 in edits1(word) for e2 in edits1(e1) if e2 in NWORDS)

同时还可能有编辑距离为0次的即本身就拼写正确的:

def known(words):
  return set(w for w in words if w in NWORDS)

我们假设编辑距离1次的概率远大于2次的,0次的远大于1次的。下面通过correct函数先选择编辑距离最小的单词,其对应的P(w|c)就会越大,作为候选单词,再选择P(c)最大的那个单词作为拼写建议

def correct(word):
  candidates = known([word]) or known(edits1(word)) or known_edits2(word) or [word]
  return max(candidates, key=NWORDS.get)

以上就是本文的全部内容,希望对大家学习python程序设计有所帮助。

Python 相关文章推荐
python通过urllib2爬网页上种子下载示例
Feb 24 Python
Python操作串口的方法
Jun 17 Python
浅谈Python中函数的参数传递
Jun 21 Python
Django中利用filter与simple_tag为前端自定义函数的实现方法
Jun 15 Python
Vue的el-scrollbar实现自定义滚动
May 29 Python
Python 类的特殊成员解析
Jun 20 Python
python 读取dicom文件,生成info.txt和raw文件的方法
Jan 24 Python
使用Python生成200个激活码的实现方法
Nov 22 Python
TensorFlow:将ckpt文件固化成pb文件教程
Feb 11 Python
Python 实现一行输入多个数字(用空格隔开)
Apr 29 Python
解决jupyter notebook图片显示模糊和保存清晰图片的操作
Apr 24 Python
python工具dtreeviz决策树可视化和模型可解释性
Mar 03 Python
Python字符串、元组、列表、字典互相转换的方法
Jan 23 #Python
Python随手笔记第一篇(2)之初识列表和元组
Jan 23 #Python
Python爬虫模拟登录带验证码网站
Jan 22 #Python
Fiddler如何抓取手机APP数据包
Jan 22 #Python
Python爬虫抓取手机APP的传输数据
Jan 22 #Python
Python 列表排序方法reverse、sort、sorted详解
Jan 22 #Python
Python中使用urllib2模块编写爬虫的简单上手示例
Jan 20 #Python
You might like
收听困难?教您超简便短波广播抗干扰方法!
2021/03/01 无线电
php之CodeIgniter学习笔记
2013/06/17 PHP
php封装好的人民币数值转中文大写类
2015/12/20 PHP
php实现的中秋博饼游戏之掷骰子并输出结果功能详解
2017/11/06 PHP
PHP chop()函数讲解
2019/02/11 PHP
PHP结合jquery ajax实现上传多张图片,并限制图片大小操作示例
2019/03/01 PHP
JS创建优美的页面滑动块效果 - Glider.js
2007/09/27 Javascript
javascript 处理HTML元素必须避免使用的一种方法
2009/07/30 Javascript
基于jquery的多功能软键盘插件
2012/07/25 Javascript
JS实现横向与竖向两个选项卡Tab联动的方法
2015/09/27 Javascript
JS实现焦点图轮播效果的方法详解
2016/12/19 Javascript
DOM事件探秘篇
2017/02/15 Javascript
bootstrap栅格系统示例代码分享
2017/05/22 Javascript
快速将Vue项目升级到webpack3的方法步骤
2017/09/14 Javascript
动态创建Angular组件实现popup弹窗功能
2017/09/15 Javascript
基于Bootstrap框架菜鸟入门教程(推荐)
2017/09/17 Javascript
vue使用xe-utils函数库的具体方法
2018/03/06 Javascript
JS伪继承prototype实现方法示例
2018/06/20 Javascript
angular使用md5,CryptoJS des加密的方法
2019/06/03 Javascript
jQuery实现简单日历效果
2020/07/05 jQuery
[56:48]FNATIC vs EG 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/16 DOTA
详解Python中的文件操作
2016/08/28 Python
Python配置mysql的教程(推荐)
2017/10/13 Python
python验证码识别教程之滑动验证码
2018/06/04 Python
Django JWT Token RestfulAPI用户认证详解
2019/01/23 Python
python爬虫 基于requests模块的get请求实现详解
2019/08/20 Python
Python unittest生成测试报告过程解析
2020/09/08 Python
基于Python实现粒子滤波效果
2020/12/01 Python
纯HTML5+CSS3制作生日蛋糕代码
2016/11/16 HTML / CSS
韩国邮政旗下生鲜食品网上超市:epost
2016/08/27 全球购物
为世界各地的女性设计和生产时尚服装:ROMWE
2016/09/17 全球购物
汽车销售员如何做职业生涯规划
2014/02/16 职场文书
学习标兵获奖感言
2014/02/20 职场文书
2014年教育教学工作总结
2014/11/13 职场文书
团结友爱主题班会
2015/08/13 职场文书
范文之农村基层党建工作报告
2019/10/24 职场文书