【问题标题】:Any python package to speed up for loop computation?任何 python 包可以加速循环计算?
【发布时间】:2019-02-13 09:18:58
【问题描述】:

我有两个列表LC,都从小到大排序。 L 包含正整数,C 包含正整数和正小数 (e.g. 0.01,0.05,..,100)C 的长度固定为6000+L 的长度是可变的(between 2 and 3000)

目标是:给定一些常量M,从L 中找到l,从C s.t. 中找到cl*c<=M 并尽可能接近M

目前我正在使用 for 循环 C 和对列表 L 的二进制搜索来找出最大的 l*c<=M。但是它非常慢。

candidate_list = []
for c in C:
    binary search on list L using while loop to find out the best l*c<=M
    candidate_list.append(best l*c)
print(max(candidate_list))

给定L 的长度为N,使用二分查找将采用logN。但是,由于C 的长度是6000+,所以c 的for 循环会很慢。如果我有多个不同长度的列表L,使用 for 循环会很慢。请问有没有 numpy 或 scipy 包可以加快计算速度?

注意:由于我有很多列表L,我不能简单地在LC_transpose 之间进行numpy 矩阵乘法,并使用argmax 找出最大值l*c,即@987654356 @。

【问题讨论】:

  • 如果你的循环很大,试试pypy而不是python (CPython)
  • 如果您使用的是数值数据而不是 Python 对象,numba 可以生成非常快的代码,如果迭代相互独立,甚至可以自动并行化您的循环。

标签: python python-3.x algorithm data-structures


【解决方案1】:

因为两个列表都是排序的,所以使用linear算法就足够了:

向前遍历一个列表,从第二个列表中找到item[A] 的最佳配对(比如索引K

对于下一个item[A+1] 配对项目肯定具有比上一个 (K) 更小或相等的索引,因此您只需要 只有一个 遍历第二个列表。

伪代码:

 iL = len(L)-1
 for iC in range(len(C)):
     while L[iL] * C[iC] > M:
          iL -= 1
     use pair  L[iL], C[iC]

【讨论】:

  • 这是一个很好的观察。我用这个想法的示例实现添加了一个答案,它似乎工作得很好。
【解决方案2】:

用户@Mbo 在his answer 中提出了一个很好的观点:

向前遍历一个列表并从第二个列表中找到item[A] 的最佳配对,但从第二个列表的后面开始搜索。 对于下一个item[A+1],它的配对项肯定必须小于或等于前一个(K)的索引,因此您只需要遍历第二个列表。

这是他提供的伪代码的示例实现(线性时间复杂性,绑定到您的最大列表的长度,即您问题中的列表 C):

def find(list_c, list_l, threshold):
    # all pairs of elements whose product is smaller than 'threshold'
    possible_pairs = []

    j = len(list_l) - 1
    for i in range(len(list_c)):
        while list_c[i] * list_l[j] > threshold:
            # product is too big, pick a smaller element from 'list_l'
            j -= 1

            if j < 0:
                # exit while loop
                break

        if j < 0:
            # exit for loop
            break

        # we store some extra info here
        possible_pairs.append({
            'c_index': i,
            'c_elem': list_c[i],
            'l_index': j,
            'l_elem': list_l[j],
            'product': list_c[i] * list_l[j],
        })

    print(possible_pairs)

    # return the pair with the biggest product (closest to threshold)
    return max(
        possible_pairs,
        key=lambda x: x['product'])

我也测试了这个解决方案:

import random

list_c = list(sorted(random.random()*100 for i in range(100)))
list_l = list(sorted(random.random()*100 for i in range(20)))
print('list_c', list_c)
print('list_l', list_l)

elem = find(list_c, list_l, threshold=50)

print('the best pair is')
print(elem)

最后的打印输出如下:

{
    'c_index': 47,
    'c_elem': 46.42324820342966,
    'l_index': 0,
    'l_elem': 1.0709460533705695,
    'product': 49.716794448105375,
}

如您所见,这样的解决方案可用于针对您在问题中提到的许多 L 列表按顺序计算搜索。

【讨论】:

  • 感谢您的回答。实际上,我还在代码中使用了一些中断条件。但是,由于有 2000 个 L 列表,而 C 的长度为 6000+,如果我们使用 for 循环,它仍然是 2000*6000 次迭代。因此,运行时间仍然很长..
【解决方案3】:

numba 包。它专为加速 python for 循环而设计。

来自他们的网站:Numba 使用行业标准 LLVM 编译器库在运行时将 Python 函数转换为优化的机器代码。 Numba 编译的 Python 数值算法可以接近 C 或 FORTRAN 的速度。

【讨论】:

    猜你喜欢
    • 2020-07-02
    • 2018-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-18
    相关资源
    最近更新 更多