【问题标题】:Faster python code更快的python代码
【发布时间】:2015-11-23 17:22:23
【问题描述】:

我有一个字典,其中名称作为键,出现位置的相应列表作为值。 我想合并等效名称。这些名称以前没有添加到其真正的字典键中,因为它们写得不好(例如拼写错误)。 因此,Sorted_tuple 是从 Dict.items() 中提取的排序元组,并进行排序以使第一个元素是包含更多出现次数的元素。 我写了以下代码,但速度很慢。我怎样才能让它更快? 谢谢

注意:check_list 的存在是为了当第一个循环到达之前已经比较过的第 i 个名称时,它不会计算与接下来的名称的距离函数。示例:如果已经发现第 10 个名称与第 1 个等价,则无需将第 10 个与 11,12 等进行比较。

编辑:玩具示例

EDIT2:来自 i+1 的 j

Dict = {'Pedro':[1,3,4,7,8,10],'Ana':[2,6,9],'Pedros':[5]}
sorted_tuple = sorted(Dict.items(),key=lambda x:len(x[1]),reverse=True)

check_list = [0]*len(Sorted_tuple)
for i in range(len(Sorted_tuple)):
    for j in range(i+1,len(Sorted_tuple)):
        Name_i = Sorted_tuple[i][0]
        Name_j = Sorted_tuple[j][0]
        ID_list_j = Sorted_tuple[j][1]
        if check_list[i] == 0:
            if distance(Name_i,Name_j) < 5:
                Dict[Name_i]+=ID_list_j
                check_list[j] = 1
            else: continue
        else:
            continue

【问题讨论】:

  • 一个玩具例子会有所帮助。
  • 应该'for j in range(1,len(Sorted_tuple)):'实际上是'for j in range(i+1,len(Sorted_tuple)):'?即 j 从 i+1 到长度。我也应该从 0 到 len(Sorted_tuple)-1。
  • 是的,对不起。它是'for j in range(i+1,len(Sorted_tuple))'
  • 你可以对 n log n 运行时的排序列表一分为二,你的继续也是没有意义的
  • 对此不确定,但通过离开合并直到您拥有所有不同的名称,您将不得不执行 O(n^2) 比较。如果在收集名称时合并名称会怎样?假设 25% 的名称合并,进行这些比较的成本为 O((0.75n)^2) - 即大约两倍。

标签: python performance for-loop


【解决方案1】:

如果设置了标志,一个优化是跳过整个内部循环:

check_list = [0]*len(Sorted_tuple)
for i in range(len(Sorted_tuple)):
    if check_list[i] != 0:
       continue
    for j in range(i+1, len(Sorted_tuple)):
        Name_i = Sorted_tuple[i][0]
        Name_j = Sorted_tuple[j][0]
        ID_list_j = Sorted_tuple[j][1]
        if distance(Name_i, Name_j) < 5:
            Dict[Name_i] += ID_list_j
            check_list[j] = 1

因为在这种情况下,所有j 都没有做任何事情。

编辑: 在 OP 澄清内部循环索引从 i+1 开始后,为元素 j 设置标志是正确的。

编辑2:
要尽可能避免的最昂贵的操作是调用distance()。一个想法是,如果您使用 Levenshtein 距离算法,那么这个距离至少与被比较的两个单词的长度之差一样大。
这导致这段代码也包含了一些小的语言变化:

check_list = [0]*len(Sorted_tuple)
for i in range(len(Sorted_tuple) - 1):
    if check_list[i] == 0:
        Name_i = Sorted_tuple[i][0]
        len_i = len(Name_i)
        for j in range(i+1, len(Sorted_tuple)):
            Name_j, ID_list_j = Sorted_tuple[j]
            if abs(len_i - len(Name_j)) < 5:
                if distance(Name_i, Name_j) < 5:
                    Dict[Name_i] += ID_list_j
                    check_list[j] = 1

i-loop 的循环边界现在缩短了 1,i 不变分配在内循环之外完成,使用元组分配,并在计算之前检查 Levenshtein 算法的最小标准距离。
所有这些微小的变化都不会改变 O(n^2) 的行为,但会改变比例因子。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-09-14
    • 2012-03-24
    • 2017-07-11
    • 1970-01-01
    • 2015-02-17
    • 2019-09-25
    • 1970-01-01
    相关资源
    最近更新 更多