如何加速这两行代码?

8

我需要加快以下代码的执行速度:

for i in range(0, 2**N):

    output[i] = f(np.array(map(int, bin(i)[2:].zfill(N))))

N 大约是 30,所以这段代码运行速度非常慢(在我的笔记本电脑上需要大约 33 小时)。函数 f() 的参数是索引 i 的二进制表示形式,f() 可以是任意可向量化的函数。为了加快代码速度,我想要摆脱 for 循环,也就是说我需要将函数 f() 的参数向量化。换句话说,我需要创建一个矩阵,其中包含数字从 02**N 的二进制表示形式。可以通过以下代码实现:

list(itertools.product([0, 1], repeat=N))

我在这个链接上找到了相关的信息,但是我觉得itertools非常缓慢,并且由于2**30约等于十亿,它显然需要大量的内存。

你有什么建议可以让这段代码运行得更快吗?谢谢提前。


8
为什么不将其重写为生成器,而不是生成一个十亿元素的数组? - dawg
可能还可以尝试更Python风格的语法['do something' for i in ...] - oliversm
如果 f 的计算成本很高,可能没有太多可以做的。如果单个函数评估需要花费例如 1/10 毫秒,并且您正在进行超过十亿次这样的评估,则无论如何都需要大约 30 小时。也许您可以重构,以便 f 所做的计算直接在循环中实现。至少这将节省十亿个函数调用的开销。 - John Coleman
2
如果你正在使用Python 2.7,务必使用"xrange"而不是"range" - 这样做会在你的系统内存中创建2^30个对象。 - jsbueno
1
你实际上使用了十亿个值吗?你能否在每次调用时生成每个值并如果再次调用则存储该值 - dawg
显示剩余4条评论
1个回答

6

始终性能分析:

>>> timeit.timeit("for i in range(0, 2**N): numpy.array(map(int, bin(i)[2:].zfill(N)))", "import numpy; N=5", number=100000)
26.472519159317017
>>> timeit.timeit("for t in itertools.product((0, 1), repeat=N): numpy.array(t)", "import numpy, itertools; N=5", number=100000)
6.129688024520874

你可以看到,itertools.product 方法速度相当快,因为它不必处理字符串。
问题可能是大部分时间都花费在 f 函数上了。
另一个解决方案可能是让 f 接受一个整数,并将其用作二进制字段。

此外:在最近的MBP上进行2^24个pass操作所需时间:仅使用range需要883毫秒,使用xrange只需要501毫秒,使用passrange函数调用需要1.92秒,而函数调用+xrange则需要1.58秒。 - a p
很棒,我尝试了N=20,只需要1分钟而不是1.5分钟。对于更大的N,这将节省大量时间。我猜N=30时会从22小时减少到33小时。 - user2983638

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接