【发布时间】:2018-02-13 02:52:35
【问题描述】:
我正在尝试找到一种更有效的方法来修改数组的每个元素及其最低邻居。在下面的示例代码中,我根据它们的不同来修改它们,但 change() 函数可以是任何东西。
搜索后,scipy.ndimage.generic_filter() 似乎是理想的使用方法,因为它可以轻松比较元素及其邻居。从ndimage.generic_filter() 获取偏移量后,我将其提供给numpy.roll() 以修改每个元素选择的邻居。
问题在于,对于非常大的数组和多次迭代,循环通过 np.roll() ndimage.generic_filter() 的低效率会影响性能。使用 10000x10000 数组,我下面代码的执行时间是 5m42s。使用 scipy 或 numpy 是否有更有效的方法?
import numpy as np
from scipy import ndimage
dic = {0: (-1, -1), 1: (-1, 0), 2: (-1, 1),
3: (0, -1), 4: (0, 0), 5: (0, 1),
6: (1, -1), 7: (1, 0), 8: (1, 1)}
def change(a):
return (a[4] - min(a)) / 2
def movement(a):
return np.argmin(a)
P = np.random.uniform(10, size=(5,5))
# determine element change and direction
chng = np.zeros((5, 5))
ndimage.generic_filter(P, change, size=3, output=chng)
move = np.random.randint(10, size=(5, 5))
ndimage.generic_filter(P, movement, size=3, output=move)
P -= chng
# determine neighbor change
chng2 = np.zeros((5, 5))
for j in range(9):
if j == 4:
continue
p = np.where(move == j, chng, 0)
p = np.roll(p, dic[j], axis=(0, 1))
chng2 += p
P += chng2
编辑:以下是更有效的解决方案。非常感谢@Paul Panzer。
import numpy as np
P = np.random.uniform(10, size=(1000, 1000))
# determine element change and direction
PP = np.bmat([[P[:, -1:], P, P[:, :1]]])
PP = np.bmat([[PP[-1:]], [PP], [PP[:1]]])
PPP = np.lib.stride_tricks.as_strided(PP, (1000, 1000, 3, 3), 2 * PP.strides)
am1 = np.argmin(PPP, axis=3)
i, j, k = np.ogrid[(*map(slice, PPP.shape[:-1]),)]
am0 = np.argmin(PPP[i, j, k, am1], axis=2)
i, j = np.ogrid[(*map(slice, PPP.shape[:-2]),)]
am1 = am1[i, j, am0]
mn = PPP[i, j, am0, am1]
change = (P - mn) / 2
P -= change
# determine neighbor change
am1 -= 1
am0 -= 1
i, j = np.ogrid[(*map(slice, P.shape),)]
np.add.at(P, ((am0 + i) % P.shape[0], (am1 + j) % P.shape[1]), change)
【问题讨论】: