我想知道是否可能使用 as_strided 和一些编辑内存的操作来编写一个不使用 for 循环的迭代算法。
例如,如果我想要编写一个算法,将数组中的数字替换为其相邻元素的和。 我想到了这个可怕的解决方法(是的它会将一个元素与其右侧的 2 个相邻元素相加,但只是为了得到一个想法):
import numpy as np
a = np.arange(10)
ops = 2
a_view_window = np.lib.stride_tricks.as_strided(a, shape = (ops,a.size - 2, 3), strides=(0,) + 2*a.strides)
a_view = np.lib.stride_tricks.as_strided(a, shape = (ops,a.size - 2), strides=(0,) + a.strides)
np.add.reduce(a_view_window, axis = -1, out=a_view)
print(a)
我正在使用一个包含10个数字的数组,并创建这种奇怪的视图,它增加了维度而不改变步幅。因此,我的想法是,在假新维度上运行缩减操作,并覆盖以前的值,因此当它到达下一个主要维度时,它必须从已经被覆盖的数据中读取,并迭代执行加法。
很遗憾,这种方法不起作用:(
(是的,我知道这是一种可怕的做事方式,但我对底层的numpy东西如何工作,以及它是否可以以这种方式被突破感到好奇)
a=[3,6,9,15,…]
,对于设置为2的操作,我会期望a=[18,30,…]
。但是Jerome给出的答案表明numpy比我更聪明,并且不会让我这样自我毁灭(可悲)。 - Simon Tartakovksya_view_window[0].sum(axis=-1)
产生了[3,6,9,...]
,一个滑动求和。通过带有out
的表达式将其写入a_view
,进而写入a
(保留了一些未更改的值)。如果您想要复制对数组进行迭代的效果,则np.add.at
是推荐的工具。它避免了+=
所做的缓冲。我不知道在这里是否有使用它的方法。as_strided
允许进行write
,但建议将其设置为 false,因为写的结果可能很难预测。as_strided
对于像移动平均这样的事物非常好,但不适用于顺序操作。 - hpaulja_view
具有“冗余”的主维度(只是覆盖自身),因此当np.add.reduce
循环查看时,它会迭代地进行求和。但是,ufuncs可以防止这种就地未定义行为。 - Simon Tartakovksy