【问题标题】:Python, nested loops, matching and performancePython、嵌套循环、匹配和性能
【发布时间】:2013-12-08 23:37:33
【问题描述】:

我正在尝试使用 Python 2.7 和 Levenshtein 函数将姓氏列表与全名列表进行匹配。为了减少工作量,我只在第一个字母相同的情况下匹配(尽管这似乎对性能没有太大影响)。如果找到匹配项,则从全名中删除匹配的单词(以使后续的名字匹配更容易)。 两个列表都包含数万个条目,因此我的解决方案相当慢。在不解析全名的情况下如何加快速度? 到目前为止,这是我所拥有的(对于姓氏由多个单词组成的情况,我省略了一些 if 条件):

import Levenshtein

listoflastnames=(['Jones', 'Sallah'])
listoffullnames=(['Henry', 'Jones', 'Junior'],['Indiana', 'Jones'])


def match_strings(lastname, listofnames):
    match=0
    matchedidx=[]
        for index, nameelement in enumerate(listofnames):        
            if lastname[0]==nameelement [0]:
                if Levenshtein.distance(nameelement, lastname)<2:
                    matchedidx.append(index)
                    match=match+1
    if match==1:
        newnamelist = [i for j, i in enumerate(listofnames) if j not in matchedidx]
    return 1, newnamelist 
return 0, listofnames



for x in listoflastnames:
    for y in listoffullnames:
        match, newlistofnames=match_strings(x,y)
        if match==1:
            #go to first name match...

任何帮助将不胜感激!

更新:与此同时,我使用了多处理模块让我所有的 4 个内核而不是一个内核来处理这个问题,但匹配仍然需要很多时间。

【问题讨论】:

  • ´Levenshtein.distance(g, publastnames[0]´ 这里的 g 和 publastnames[0] 是什么?
  • 抱歉,这是旧版本遗留下来的。 Levenshtein 函数比较姓氏和全名中的一个单词。我已经纠正了错误。
  • 如果您只打算执行第一个字母相同的计算,您可能希望将列表分解为由第一个字母索引的字典。然后你可以只在可行的候选人之间进行比较,而不是在所有人之间进行比较。这是否会提高性能取决于花费在此开销上的时间比例,而不是距离计算。
  • 您可以先将名称按长度拆分为子列表。 n 长度差异的两个字符串的 Levenstein 差异不能小于 n

标签: python python-2.7 nested-loops levenshtein-distance


【解决方案1】:

这简化了match_string 函数中的for 循环,但在我的测试中并没有显着提高速度。最大的损失在两个for 循环中,分别是姓氏和全名。

def match_strings(lastname, listofnames):
    firstCaseMatched = [name for name in listofnames if lastname[0] == name[0]]
    if len(firstCaseMatched):
        matchedidx = [index for index, ame in enumerate(firstCaseMatched) if Levenshtein.distance(lastname, name) < 2]
        match = len(matchedidx)
    else:
        match = 0
    if match == 1:
        newnamelist = [i for j, i in enumerate(listofnames) if j not in matchedidx]
        return 1, newnamelist
    return 0, listofnames

您可能需要对已知姓氏列表进行排序,将它们拆分为每个起始字符的dict。然后将名称列表中的每个名称与之匹配。

假设全名列表总是将名字作为第一个元素。您可以将比较限制为仅其他元素。

【讨论】:

  • 感谢您的所有建议。按照建议,我已将姓氏拆分为以首字母为键的字典。再加上多处理,该脚本现在的速度是原始版本的 20 倍左右。
  • 顺便说一句,我假设您使用 Levenshtein 距离,因为名称可能拼写错误?那你能确定名字的第一个字母是正确的吗?
  • 我不能确定,但​​是当我在不排除首字母与我的数据子集匹配的情况下测试脚本时,似乎引入了很多误报。因为我必须从结果集中手动删除误报,所以我愿意接受略低的召回率 :)
  • 不确定 Levenshtein 算法有多贵。所以这可能根本没有帮助。首先,您可以尝试进行直接比较,假设直接比较明显更快。(可能不适用于它们相等的情况)。然后对那些不匹配的内容进行 levenshtein。其次,如果您已经匹配了第一个字符,则只对名称的其余部分进行 levenshtein 测试 (lastname[1:])
  • 我都试过了,令人惊讶的是,根据 cprofiler,这两种想法都会稍微减慢脚本的速度。可能是因为 Levenshtein 函数是用 C 编写的。
猜你喜欢
  • 2012-11-25
  • 2013-01-29
  • 2016-09-18
  • 2013-02-25
  • 1970-01-01
  • 2019-04-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-13
相关资源
最近更新 更多