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工程师面试题 与Python基础语法相关
Jan 14 Python
python记录程序运行时间的三种方法
Jul 14 Python
解决Django模板无法使用perms变量问题的方法
Sep 10 Python
python模块之time模块(实例讲解)
Sep 13 Python
解决Python requests库编码 socks5代理的问题
May 07 Python
python 实现求解字符串集的最长公共前缀方法
Jul 20 Python
python实现两张图片的像素融合
Feb 23 Python
python输出电脑上所有的串口名的方法
Jul 02 Python
Python3并发写文件与Python对比
Nov 20 Python
kafka监控获取指定topic的消息总量示例
Dec 23 Python
给Python学习者的文件读写指南(含基础与进阶)
Jan 29 Python
pytorch读取图像数据转成opencv格式实例
Jun 02 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
浅析HTTP消息头网页缓存控制以及header常用指令介绍
2013/06/28 PHP
php数组删除元素示例
2014/03/21 PHP
ThinkPHP基本的增删查改操作实例教程
2014/08/22 PHP
Yii学习总结之安装配置
2015/02/22 PHP
如何让您的中波更粗更长 - 中波框形天线制作
2021/03/10 无线电
jquery实现隐藏与显示动画效果/输入框字符动态递减/导航按钮切换
2013/07/01 Javascript
多种方法实现JS动态添加事件
2013/11/01 Javascript
常见浏览器多长时间会提示“脚本运行时间过长”总结
2014/04/29 Javascript
jQuery使用hide方法隐藏元素自身用法实例
2015/03/30 Javascript
jquery实现点击其他区域时隐藏下拉div和遮罩层的方法
2015/12/23 Javascript
使用JavaScript为一张图片设置备选路径的方法
2017/01/04 Javascript
利用ES6语法重构React组件详解
2017/03/02 Javascript
jQuery Easyui Treegrid实现显示checkbox功能
2017/08/08 jQuery
Javascript快速实现浏览器系统通知
2017/08/26 Javascript
jQuery EasyUI 折叠面板accordion的使用实例(分享)
2017/12/25 jQuery
vue 国际化 vue-i18n 双语言 语言包
2018/06/07 Javascript
vue项目中mock.js的使用及基本用法
2019/05/22 Javascript
python实现异步回调机制代码分享
2014/01/10 Python
flask使用session保存登录状态及拦截未登录请求代码
2018/01/19 Python
Flask框架重定向,错误显示,Responses响应及Sessions会话操作示例
2019/08/01 Python
Python 根据日志级别打印不同颜色的日志的方法示例
2019/08/08 Python
Python virtualenv虚拟环境实现过程解析
2020/04/18 Python
pandas DataFrame 数据选取,修改,切片的实现
2020/04/24 Python
python 提高开发效率的5个小技巧
2020/10/19 Python
python subprocess pipe 实时输出日志的操作
2020/12/05 Python
Python lxml库的简单介绍及基本使用讲解
2020/12/22 Python
Scrapy实现模拟登录的示例代码
2021/02/21 Python
Myprotein俄罗斯官网:欧洲第一运动营养品牌
2019/05/05 全球购物
了解AppleShare protocol(AppleShare协议)吗
2015/08/28 面试题
2015年毕业实习工作总结
2014/12/12 职场文书
服务明星事迹材料
2014/12/29 职场文书
前台接待员岗位职责
2015/04/15 职场文书
2015年度个人教学工作总结
2015/05/20 职场文书
乡镇团代会开幕词
2016/03/04 职场文书
Win11 S Mode版本泄露 正式上线后叫做Windows 11 SE
2021/11/21 数码科技
css让页脚保持在底部位置的四种方案
2022/07/23 HTML / CSS