中文词语自动纠错_编辑距离

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|w)=p(w|c)p(c)p(w)

文章里,称

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

posted @ 2016-12-31 20:31  StevenLuke  阅读(612)  评论(0编辑  收藏