中文词语自动纠错_编辑距离
idea from here
这是一篇使用编辑距离对英文词语就行简单纠错的文章。
code:
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))
工作原理
word –> w
correct word –> c
文章里,称
p(c) 为Language Model
p(w|c) 为Error Model
c ∈ candidates为Candidate Model
argmax为Selection Mechanism
其中:
p(c) 可从预料库里统计而得,简单的frequence / sum_number
p(c|w) 需要data on spelling errors
实际操作
在没有data on spelling errors的情况下,将”词典里的词“、 ”1 编辑距离“、“2 编辑距离”、“不修正“的权重依次下调。
改进
对于p(c)
影响因素是未登录词。比如:
correction(‘addresable’) => ‘addresable’ (0); expected ‘addressable’ (0)
应该修正为addressable的情况却未修正addresable,因为词典里没有addressable这个词。
办法也许是加多数据,也可以是给词加上后缀、前缀、复数等(对于英文)。
对于p(w|c)
correction(‘adres’) => ‘acres’ (37); expected ‘address’ (77)
在没有data on spelling errors的情况下,由于将 ”1 编辑距离“的权重设置得高于“2 编辑距离”,所以错误的修正了。
关键是改善Error Model。
最有效的改善
让模型观察更多的上下文来决定是否修正、怎么修正。
上面的是对于英文的操作,我改成了中文数据库,without关于中文的data on spelling errors做了一个同样简单的中文词语纠错。
像上面一样,只能对于中文词语纠错,不能对于一个包含错误词语的句子纠错,那种情况就复杂了。
import re
from collections import Counter
f = open(r'word_freq.txt', encoding='utf8')
WORDS = {}
id = 0
for line in f.readlines():
if id % 2 == 0:
word_freq = line.split('\t')
WORDS[word_freq[0]] = int(word_freq[1])
id = id + 1
letters = open(r'word.txt', encoding='utf8').read()
N = sum(WORDS.values())
def P(word):
return WORDS[word] / N
def know(words):
return set(w for w in words if w in WORDS)
def edits1(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 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):
return (e2 for e1 in edits1(word) for e2 in edits1(e1))
def candidates(word):
return (know([word]) or know(edits1(word)) or know(edits2(word)) or [word])
def correction(word):
return max(candidates(word), key=P)
print(correction('正分夺秒'))
print(correction('灿烂夺木'))
print(correction('大好清春'))
#print(correction('十里淘花'))
print(correction('西胡'))
print(correction('21'))
最大的不同
英文的letters只用26个字母来做替换、插入就行了,中文的就多得多多了。所以程序就会慢得不能忍。以下的想法也许有帮助:
只用同音字来做替换操作
插入… …
对于中文词语的纠错方法有:
美团搜索引擎关键字智能提示的一种实现
1. 支持前缀匹配原则
在搜索框中输入“海底”,搜索框下面会以海底为前缀,展示“海底捞”、“海底捞火锅”、“海底世界”等等搜索词;输入“万达”,会提示“万达影城”、“万达广场”、“万达百货”等搜索词。
2. 同时支持汉字、拼音输入
由于中文的特点,如果搜索自动提示可以支持拼音的话会给用户带来更大的方便,免得切换输入法。比如,输入“haidi”提示的关键字和输入“海底”提示的一样,输入“wanda”与输入“万达”提示的关键字一样。
3. 支持多音字输入提示
比如输入“chongqing”或者“zhongqing”都能提示出“重庆火锅”、“重庆烤鱼”、“重庆小天鹅”。
4. 支持拼音缩写输入
对于较长关键字,为了提高输入效率,有必要提供拼音缩写输入。比如输入“hd”应该能提示出“haidi”相似的关键字,输入“wd”也一样能提示出“万达”关键字。
5. 基于用户的历史搜索行为,按照关键字热度进行排序
为了提供suggest关键字的准确度,最终查询结果,根据用户查询关键字的频率进行排序,如输入[重庆,chongqing,cq,zhongqing,zq] —> [“重庆火锅”(f1),“重庆烤鱼”(f2),“重庆小天鹅”(f3),…],查询频率f1 > f2 > f3。
我的demo
online demo:here