Numpy 如何使np.roll()更快?
我使用np.roll()来做最近邻平均,但我感觉有更快的方法。这里是一个简化的,但想象一下3维和更复杂的平均“模板”。举个例子,参见本手册第6节 下面是该简化示例中的几行:Numpy 如何使np.roll()更快?,numpy,scipy,Numpy,Scipy,我使用np.roll()来做最近邻平均,但我感觉有更快的方法。这里是一个简化的,但想象一下3维和更复杂的平均“模板”。举个例子,参见本手册第6节 下面是该简化示例中的几行: for j in range(nper): phi2 = 0.25*(np.roll(phi, 1, axis=0) + np.roll(phi, -1, axis=0) + np.roll(phi, 1, axis=1) +
for j in range(nper):
phi2 = 0.25*(np.roll(phi, 1, axis=0) +
np.roll(phi, -1, axis=0) +
np.roll(phi, 1, axis=1) +
np.roll(phi, -1, axis=1) )
phi[do_me] = phi2[do_me]
那么,我应该寻找返回视图而不是数组的东西吗?在这种情况下,roll是否在每次调用新数组时初始化它?我注意到小型阵列的开销很大
事实上,对于我的笔记本电脑上[100100]到[300300]大小的阵列来说,这是最有效的。可能存在上述问题
scipy.ndimage.interpolation.shift()
的实现方式是否会更好,如果是这样,在上面的链接示例中,我会丢弃包装好的部分,但可能并不总是这样
注意:在这个问题中,我只查找NumPy/SciPy中可用的内容。当然,有很多很好的方法可以加速Python甚至NumPy,但这不是我在这里要寻找的,因为我真的想更好地理解NumPy。谢谢
np.roll
每次都必须创建一个数组副本,这就是它(相对)较慢的原因。使用类似于scipy.ndimage.filters.convolve()
的函数进行卷积会快一点,但仍可能创建副本(取决于实现)
在这种特殊情况下,我们可以通过在开始时使用和填充原始数组来避免完全复制
将numpy导入为np
def无拷贝卷(nx,ny):
phi_padded=np.零((ny+2,nx+2))
#这些是phi_填充的不同子阵列的视图
#如果两个子数组重叠,则它们共享内存
菲尤北=菲尤加垫[:-2,1:-1]
phi_east=phi_填充[1:-1,2:]
phi_south=phi_填充[2:,1:-1]
phi_west=phi_填充[1:-1,:-2]
φ=φ_填充[1:-1,1:-1]
do_me=np.zero_like(phi,dtype='bool')
Dou me[1:-1,1:-1]=真
x0,y0,r0=40,65,12
x=np.arange(nx,dtype='float')[None,:]
y=np.arange(ny,dtype='float')[:,无]
rsq=(x-x0)**2+(y-y0)**2
circle=rsq到目前为止,我能得到的最快实现是基于您已经提到的scipy.ndimage.interpolation.shift
的底层实现:
from scipy.ndimage.interpolation import _nd_image, _ni_support
cval = 0.0 # unused for mode `wrap`
mode = _ni_support._extend_mode_to_code('wrap')
_nd_image.zoom_shift(data, None, shift, data, 0, mode, cval) # in-place update
预先计算模式
,cval
和shift
调用低级的zoom\u shift
方法直接让我了解了x5的加速比wrt。调用shift
和x10加速wrtnp.roll
进行最近邻平均,您考虑过卷积吗?np.roll
构造索引数组,并返回a.take(索引,轴)
。这就是较慢的高级索引<“代码>跨步”
被认为是一种使用滑动窗口的更快方法。可能会给出一些想法,例如,使用跨步和滑动来构造滑动窗口。您的问题并不完全清楚您在寻找什么-如果您向我们展示您当前的解决方案,这将很有帮助。以及scipy.ndimage.convolve
如果你只想得到最近邻平均值,你可以简单地使用scipy.ndimage.uniform_filter
。+1
哇,感谢你花时间写出如此全面而周到的答案!多年来,我一直在避免学习撇渣,也许这就是我需要深入研究的理由:-)顺便说一句,从五年前发布这个问题到今天,我几乎每天都在使用Python,但我仍然是个业余爱好者。行Program:timing.py
让我困惑,这是按原样运行的吗?@uhohtiming.py
是我给上述基准脚本的名称,用于比较代码的原始版本和零拷贝版本。对不起,如果你不明白的话。这是pyinstrument
一个非常好的python分析器输出的一部分。谢谢,我感谢您的耐心,并将很快尝试所有这些!这个问题每隔一段时间就会出现,下次我会试试,让你知道它是怎么回事。谢谢
37.685 <module> timing.py:1
├─ 22.413 original_roll original.py:4
│ ├─ 15.056 [self]
│ └─ 7.357 roll <__array_function__ internals>:2
│ └─ 7.243 roll numpy\core\numeric.py:1110
│ [10 frames hidden] numpy
├─ 14.709 no_copy_roll mwe.py:4
└─ 0.393 allclose <__array_function__ internals>:2
└─ 0.393 allclose numpy\core\numeric.py:2091
[2 frames hidden] numpy
0.391 isclose <__array_function__ internals>:2
└─ 0.387 isclose numpy\core\numeric.py:2167
[4 frames hidden] numpy
from scipy.ndimage.interpolation import _nd_image, _ni_support
cval = 0.0 # unused for mode `wrap`
mode = _ni_support._extend_mode_to_code('wrap')
_nd_image.zoom_shift(data, None, shift, data, 0, mode, cval) # in-place update