在Python中进行字符串匹配时,有没有提高匹配性能的方法?
我有一本很大的字典,里面储存了大量的英语句子和它们的西班牙语翻译。当给出一个随机的英语句子时,我打算使用Python的fuzzyfuzzy库在字典中查找最接近的匹配项。我的代码:在Python中进行字符串匹配时,有没有提高匹配性能的方法?,python,performance,fuzzywuzzy,Python,Performance,Fuzzywuzzy,我有一本很大的字典,里面储存了大量的英语句子和它们的西班牙语翻译。当给出一个随机的英语句子时,我打算使用Python的fuzzyfuzzy库在字典中查找最接近的匹配项。我的代码: from fuzzywuzzy import process sentencePairs = {'How are you?':'¿Cómo estás?', 'Good morning!':'¡Buenos días!'} query= 'How old are you?' match = process.extrac
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')
在现实生活中,语句对
字典将非常大,至少存储了一百万个条目。因此,即使安装了python Levenshtein以提供加速,使用FuzzyFuzzy获得结果也需要很长时间。
那么,有没有更好的方法来实现更好的性能呢?我的目标是在不到几秒钟的时间内得到结果,甚至是实时得到结果。可能有更好的解决方案,但在我的脑海中,我可以想到分区 您可以创建26个不同的字典,每个字典代表一个英语字母表。然后你可以加载所有这些字典和所有以字母表开头的键。 例如,adict、bdict。。。zdict等。 所以hdict将包含以h开头的键的键值。比如key=“你好吗?” 这样,您只需要查询与起始字母表匹配的字典。提高性能的方法 使用Levenshtein距离的模糊匹配永远不会超快速,但您的代码中有一些东西可以优化:
process.extractOne
使用fuzz.WRatio
比较字符串。这是多个字符串匹配算法的组合。因此,通过将例如scorer=fuzz.ratio
传递给process.extractOne来选择更快的算法,可以提高性能。但是请记住,这会改变字符串的比较方式,因此根据您的数据,您可能不希望这样做
来自rapidfuzz导入过程,utils
#英语句子已经是小写了
#没有问号之类的特殊字符
句子对={‘你好’:‘你好吗?’,‘早上好’:‘布宜诺斯艾利斯!’
query='你多大了?'
匹配,u=process.extractOne(
utils.default_进程(查询),
sentencePairs.keys(),
处理器=无)
打印(匹配,句子对[match],sep='\n')
利用1、2和3实现
来自rapidfuzz导入过程、utils、fuzz
#英语句子已经是小写了
#没有问号之类的特殊字符
句子对={‘你好’:‘你好吗?’,‘早上好’:‘布宜诺斯艾利斯!’
query='你多大了?'
匹配,u=process.extractOne(
utils.default_进程(查询),
sentencePairs.keys(),
处理器=无,
记分器=模糊比率)
打印(匹配,句子对[match],sep='\n')
基准
为了提供一些时间比较,我生成了一百万个句子:
导入字符串
随机输入
随机种子(18)
句子对={
''.join(random.choice(string.ascii_小写+string.digits)
适用于范围内的(15)
):“西班牙文文本”
适用于范围内的s(1000000)
}
query='你多大了?'
下表显示了不同解决方案在我的计算机上需要多长时间
|实现|运行时|
|------------------------------------------|----------------|
|您当前的实现| 18.98秒|
|利用1和2 | 1.4秒实现|
|利用1、2和3 | 0.4秒实施|
使用此解决方案,您将丢失对第一个字符的“模糊”搜索。不过,这仍然是一个有效的选项。请注意,您在这里实际上并没有按预期使用dict
,您还可以使用元组列表,或者两个单独的列表,我在代码中找不到fuzz.ratio
或fuzz.WRatio
。您的意思是使用它们来循环所有sentenPairs
键,而不是process.extractOne()
,并且使用fuzz.ratio
时需要0.4秒?prcess.extractOne支持记分器参数来更改其使用的字符串匹配算法。我更新了答案,使之更清楚。关于utils.default\u进程
和处理器
,我可以只使用match、=process.extractOne(query,sentencePairs.keys(),scorer=fuzz.ratio)
而不是match、=process.extractOne(utils.default\u进程(query),sentencePairs.keys(),处理器=无,记分器=模糊比率)
?这两行代码之间似乎没有区别,根据我的测试,执行时间基本相同。我还检查了,仍然找不到任何差异。utils.default_进程正在预处理字符串(小写,删除非字母数字字符,例如问号和修剪空白)。因此,当您不需要/不想要此项时,您可以将其省略(例如,字符串“您多大岁数?”转换为“您多大岁数”)