加速Numpy阵列上的循环

时间:2011-05-12 03:23:12

标签: python for-loop numpy

在我的代码中,我有for循环,它在多维numpy数组上进行索引,并使用在每次迭代时获得的子数组进行一些操作。看起来像这样

for sub in Arr:
  #do stuff using sub

现在使用sub完成的内容是完全矢量化的,所以它应该是高效的。另一方面,这个循环迭代大约~10^5次并且是瓶颈。你认为我会通过将这部分卸载到C来获得改进。我有点不愿意这样做,因为do stuff using sub使用广播,切片,智能索引技巧,这些技巧在简单的C中写作会很乏味。我会也欢迎在将计算卸载到C时如何处理广播,切片,智能索引的想法和建议。

3 个答案:

答案 0 :(得分:6)

如果你不能'矢量化'整个操作并且循环确实是瓶颈,那么我强烈建议使用Cython。我最近一直在讨论它,它很容易使用,并且有一个像numpy一样的接口。对于像langevin集成商这样的东西,我看到了比numpy中的体面实现快115倍的速度。请参阅此处的文档:

http://docs.cython.org/src/tutorial/numpy.html

我还建议查看以下paper

只需键入输入数组和循环计数器,您就可以看到令人满意的加速,但如果您想充分发挥cython的潜力,那么您将不得不对等效广播进行硬编码。

答案 1 :(得分:2)

你可以看看scipy.weave。您可以使用scipy.weave.blitz将表达式透明地翻译为C++代码并运行它。它将自动处理切片并摆脱临时性,但你声称for循环的主体不会创造临时性,因此你的milage可能会有所不同。

但是,如果您想用更高效的东西替换整个for循环,那么您可以使用scipy.inline。缺点是您必须编写C++代码。这应该不会太难,因为你可以使用非常接近numpy数组表达式的Blitz++语法。直接支持切片,但广播却不支持。

有两种解决方法:

  1. 是使用numpy-C api并使用多维迭代器。他们透明地处理广播。但是,您正在调用Numpy运行时,因此可能会有一些开销。另一种选择,可能更简单的选择是使用通常的矩阵表示法进行广播。广播操作可以写成具有所有1的向量的外部产品。好的是Blitz++实际上不会在内存中创建这个临时广播数组,它会弄清楚如何将它包装到一个等效的循环中。

  2. 对于第二个选项,请查看http://www.oonumerics.org/blitz/docs/blitz_3.html#SEC88索引占位符。只要您的矩阵小于11维,您就可以了。此链接显示了如何使用它们来形成外部产品http://www.oonumerics.org/blitz/docs/blitz_3.html#SEC99(搜索外部产品以转到文档的相关部分)。

答案 2 :(得分:1)

除了使用Cython之外,你还可以在Fortran中编写瓶颈部分。然后使用f2py将其编译为Python .pyd文件。