在Python中进行字符串匹配时,有没有办法提高匹配性能?

问题描述

我有一本非常大的词典,其中存储了大量的英语句子及其西班牙语翻译。当给定一个随机的英语句子时,我打算使用Python的fuzzywuzzy库在字典中找到最接近的匹配项。我的代码

from fuzzywuzzy import process
sentencePairs = {'How are you?':'¿Cómo estás?','Good morning!':'¡Buenos días!'}
query= 'How old are you?'
match = process.extractOne(query,sentencePairs.keys())[0]
print(match,sentencePairs[match],sep='\n')

在现实生活中,sentencePairs词典非常大,至少存储了一百万个项目。因此,即使安装了python-Levenshtein来提供加速效果,也要花很长时间才能获得fuzzywuzzy的结果。 那么,有没有更好的方法来获得更好的性能呢?我的目标是在不到几秒钟的时间内甚至实时获得结果。

解决方法

如何提高性能

使用Levenshtein距离进行模糊匹配永远不会很快,但是您可以优化代码中的几件事:

  1. 在将字符串和列表传递给process.extractOne时,它将通过对它们进行小写,删除非字母数字字符并修剪空格来对这些字符串进行预处理。由于您每次都重复使用相同的English:Spanish映射,因此您应该提前进行一次预处理。

  2. 即使在使用python-Levenshtein时,FuzzyWuzzy在很多地方也没有真正进行优化。您应该将其替换为RapidFuzz,该实现可以通过相似的接口实现相同的算法,但是主要是在C ++中实现的,并且还进行了一些其他算法上的改进,从而使其运行速度更快。

  3. 内部 a b c d <dbl> <dbl> <dbl> <dbl> 1 1 0.924 1 0.924 2 2 0.661 3 0.402 3 3 0.402 3 0.402 4 4 0.637 3 0.402 5 5 0.353 1 0.924 在默认情况下使用process.extractOne比较字符串。这是多个字符串匹配算法的组合。所以通过例如选择更快的算法fuzz.WRatio到process.extractOne可以提高性能。但是请记住,这会更改比较字符串的方式,因此根据您的数据,您可能不希望这样做。

使用1和2的实现

scorer=fuzz.ratio

使用1、2和3的实现

from rapidfuzz import process,utils
# english sentences are already lower cased
# and without special characters like question marks
sentencePairs = {'how are you':'¿Cómo estás?','good morning':'¡Buenos días!'}
query= 'How old are you?'
match,_ = process.extractOne(
   utils.default_process(query),sentencePairs.keys(),processor=None)
print(match,sentencePairs[match],sep='\n')

基准

为了提供一些时间比较,我生成了一百万个句子:

from rapidfuzz import process,utils,fuzz
# english sentences are already lower cased
# and without special characters like question marks
sentencePairs = {'how are you':'¿Cómo estás?',processor=None,scorer=fuzz.ratio)
print(match,sep='\n')

下表显示了我的计算机上不同解决方案所需的时间

import string
import random
random.seed(18)
sentencePairs = {
    ''.join(random.choice(string.ascii_lowercase + string.digits)
       for _ in range(15)
    ): "spanish text"
    for s in range(1000000)
}
query= 'How old are you?'
,

可能有更好的解决方案,但我想到的就是分区。

您可以创建26个不同的字典,每个字典代表一个英文字母。然后,您可以使用以相应字母开头的所有键加载所有这些词典。 例如。 adict,bdict ... zdict等 所以。 hdict将包含以h开头的Key的Key值。就像key =“你好吗?”

通过这种方式,您只需要查询与起始字母匹配的字典即可。