从Python中的'enchant suggest()'获取最相关的单词(拼写检查)

时间:2011-07-15 03:31:28

标签: python spell-checking

我希望从enchant suggest()获得最相关的字词。有没有更好的方法来做到这一点。在检查100k或更大范围内的大量单词时,我觉得我的功能效率不高。

enchant suggest()的问题:

>>> import enchant
>>> d.suggest("prfomnc")
['prominence', 'performance', 'preform', 'Provence', 'preferment', 'proforma']

我的功能是从一组建议的单词中获取适当的单词:

import enchant, difflib

word="prfomnc"
dict,max = {},0
a = set(d.suggest(word))
for b in a:
    tmp = difflib.SequenceMatcher(None, word, b).ratio();
    dict[tmp] = b
    if tmp > max:
       max = tmp

print dict[max]

Result: performance

更新:

如果我得到多个密钥,意味着相同的difflib ratio()值,我使用多密钥字典。如下所述:http://code.activestate.com/recipes/440502-a-dictionary-with-multiple-values-for-each-key/

2 个答案:

答案 0 :(得分:3)

没有灵丹妙药,我害怕...... 但是有一些建议。

我猜测逻辑中的大部分时间花在 difflib的SequenceMatcher()。ratio()调用上。这并不奇怪,因为这个方法使用Rattcliff-Obershelp algorithm的变体,这是相对昂贵的,CPU方式(但它产生的度量相当“在标记上”来定位紧密匹配,这可能是为什么你喜欢它。)

可以肯定的是,你应该分析这个逻辑,并确认SequenceMatcher()确实是热点。也许Enchant.suggest()也有点慢,但是我们可以做的很少,代码方面,以改善这一点(配置方面,可能有一些选项,例如,废除个人字典以节省双重查找和合并等。)。

假设SequenceMatcher()确实是罪魁祸首,并假设你希望坚持使用Ratcliff-Obershelp相似性度量作为选择最佳匹配的方法,那么你可以做以下几点:

  • 仅计算来自附件的顶部(?)5项的SequenceMatcher比率值。
    毕竟,Enchant.suggest()以有序的方式返回其建议及其最佳猜测第一;因此,虽然基于不同的启发式方法,在附魔顺序中也有价值,但是当我们向下移动时,找到高等级匹配的机会可能会减少。此外,尽管如此,我们最终可能会忽略一些这样的高级别比赛,仅通过测试前几个附魔建议,我们将以下方法结合了Enchant启发式中的“智慧”与Ratcliff-Obershelp指标中的这些“智慧”。
  • 在达到某个阈值后停止计算SequenceMatcher比率
    这个想法类似于前面的说法:一旦找​​到更好的几率越来越小(一旦我们有一个体面的,如果不是最好的选择),就避免调用SequenceMatcher。
  • 使用您自己的逻辑过滤掉一些来自附魔的单词。
    我们的想法是进行相对快速/廉价的测试,这可能会告诉我们,给定的单词不太可能在SequenceMatcher比率上得分。例如,排除至少没有用户字符串长度减去两个共同字符的单词 顺便说一下,你可以使用一些SequenceMatcher对象的[quicker]函数来获取过滤启发式的一些数据。
  • 使用SequenceMatcher * quick_ratio *()函数代替
    至少在某些情况下。
  • 只保留字符串中的最佳匹配,而不是使用字典
    显然只有最重要的选择很重要,所以除了测试目的,你可能不需要字典的[相对较小的]开销。
  • 可以考虑编写自己的Ratcliff-Obershelp(或类似)方法,在满足当前最大比例的前景很小时,在其中介绍各种早期退出。请注意,生成一种与diff语言的C语言一样高效的方法可能很困难,你这样做的兴趣在于早期退出......
HTH,祝你好运; - )

答案 1 :(得分:2)

如果您只对最佳匹配感兴趣,则实际上不需要保留dict

>>> word="prfomnc"
>>> best_words = []
>>> best_ratio = 0
>>> a = set(d.suggest(word))
>>> for b in a:
...   tmp = difflib.SequenceMatcher(None, word, b).ratio()
...   if tmp > best_ratio:
...     best_words = [b]
...     best_ratio = tmp
...   elif tmp == best_ratio:
...     best_words.append(b)
... 
>>> best_words
['performance']