Home > Blockchain >  numpy array of 2 dimensions indexing and sum
numpy array of 2 dimensions indexing and sum

Time:12-12

i have a doubt. There is an efficient way to sum all neighbors of a numpy matrix without using several conditions?

This is an example:

array([[5, 4, 8, 3, 1, 4, 3, 2, 2, 3],
       [2, 7, 4, 5, 8, 5, 4, 7, 1, 1],
       [5, 2, 6, 4, 5, 5, 6, 1, 7, 3],
       [6, 1, 4, 1, 3, 3, 6, 1, 4, 6],
       [6, 3, 5, 7, 3, 8, 5, 4, 7, 8],
       [4, 1, 6, 7, 5, 2, 4, 6, 4, 5],
       [2, 1, 7, 6, 8, 4, 1, 7, 2, 1],
       [6, 8, 8, 2, 8, 8, 1, 1, 3, 4],
       [4, 8, 4, 6, 8, 4, 8, 5, 5, 4],
       [5, 2, 8, 3, 7, 5, 1, 5, 2, 6]])

When I run m[0][-1] it returns me 3 and not an error, so if I want to add 1 to all neighbors of a value I need to use a lot of conditions because I can't just use m[0][-1] because in this case and in the other cases of the corners it returns me just a " False neighbor"

CodePudding user response:

IIUC, you want to add 1 to each neighbour of a cell with a given value.

For the example, let's add 1 to each cell in the neighborhood of a 7:

from scipy.signal import convolve2d
v = np.array([[1,1,1],[1,0,1],[1,1,1]])
a   convolve2d(a==7, v, mode='same')

output:

array([[6, 5, 9, 3, 1, 4, 4, 3, 3, 3],
       [3, 7, 5, 5, 8, 5, 5, 8, 3, 2],
       [6, 3, 7, 4, 5, 5, 7, 3, 8, 4],
       [6, 1, 5, 2, 4, 3, 6, 3, 6, 8],
       [6, 3, 7, 8, 5, 8, 5, 5, 7, 9],
       [4, 2, 9, 9, 7, 2, 5, 8, 6, 6],
       [2, 2, 8, 8, 9, 4, 2, 7, 3, 1],
       [6, 9, 9, 3, 8, 8, 2, 2, 4, 4],
       [4, 8, 4, 7, 9, 5, 8, 5, 5, 4],
       [5, 2, 8, 4, 7, 6, 1, 5, 2, 6]])

CodePudding user response:

In addition to the good @mozway solution, one very efficient solution is to use the Numba stencil decorator combined with a parallel execution. Here is an example:

import numba as nb

# parallel=True is only useful for quite-big arrays
@nb.njit(parallel=True)
def kernel(v):
    cond = np.zeros((v.shape[0] 2, v.shape[1] 2), dtype=np.bool_)
    cond[1:-1, 1:-1] = v == 7
    res = nb.stencil(lambda c: c[-1,-1] c[-1,0] c[-1,1] c[0,-1] c[0,1] c[1,-1] c[1,0] c[1,1])(cond)
    return v   res[1:-1, 1:-1]

kernel(m)

An even faster solution consist in working in-place (using v = res instead of the return v res). Here are the performance results for a 2000x2000 integer array on my 6-core machine:

scipy.signal.convolve2d:  124 ms
Numba out-of-place:        20 ms
Numba in-place:            15 ms

Note that the first call to kernel is slower due to the compilation time. I also got a similar speed-up for smaller arrays (200x200).

  • Related