在numpy 2d数组中修改元素和邻居

时间:2018-02-13 02:52:36

标签: python arrays numpy scipy

我正在尝试找到一种更有效的方法来修改数组的每个元素及其最低邻居。在下面的示例代码中,我根据它们的不同修改它们,但no_count函数可以是任何内容。

搜索之后,change()似乎是理想的使用方法,因为它允许在元素和它们的邻居之间轻松比较。从scipy.ndimage.generic_filter()获得偏移后,我将其提供给ndimage.generic_filter()以修改每个元素的所选邻居。

问题是,对于非常大的数组和多次迭代,循环通过np.roll() numpy.roll()的低效率会影响性能。使用10000x10000阵列时,下面代码的执行时间为5m42s。使用scipy或numpy有更有效的方法吗?

ndimage.generic_filter()

编辑:以下是更有效的解决方案。非常感谢@Paul Panzer。

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

2 个答案:

答案 0 :(得分:0)

这可能是您正在寻找的https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.convolve2d.html

in2(Cf文档)将是一个矩阵,对应于你写的dict

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)}

希望有所帮助

答案 1 :(得分:0)

您可以使用np.add.at。您的P -= chng

后会收到以下代码段
>>> P_pp = P.copy()
>>> dic_i, dic_j = np.indices((3, 3)).reshape(2, 9) - 1
>>> i, j = np.ogrid[(*map(slice, P_pp.shape),)]
>>> np.add.at(P_pp, ((dic_i[move] + i) % P_pp.shape[0], (dic_j[move] + j) % P_pp.shape[1]), chng)

由于我们处理了P的副本,我们现在可以执行其余代码,然后执行:

# Tada!
>>> np.allclose(P_pp, P)
True

更新:以下是一种不使用ndimage计算本地argmin的方法。一个潜在的优势是,一旦我们拥有了argminima,我们便可以便宜地获得相应的最小值。请注意,argmin已经是2D第一个组件位于am0,第二个位于am1。每个范围介于02之间,因此中心位于1,1,最小值位于mn

>>> P = np.random.uniform(10, size=(5,5))
>>> PP = np.bmat([[P[:,-1:], P, P[:, :1]]])
>>> PP = np.bmat([[PP[-1:]], [PP], [PP[:1]]])
>>> PPP = np.lib.stride_tricks.as_strided(PP, (5, 5, 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]