G

We need help. numpy? Or would another library be okay?For example, scipy♪import numpy as np
from scipy.signal import convolve2d
def compute_neighbours_scipy(Z):
return convolve2d(Z, np.ones((3,3), dtype=int), 'same') - Z
This function shall be calculated correctly for the elements on the boundaries of the matrix.UPDATENet options numpy♪def compute_neighbours_numpy2(Z):
mask = np.asarray([[1,1,1], [1,0,1], [1,1,1]])
s = mask.shape + tuple(np.subtract(Z.shape, mask.shape) + 1)
sub = np.lib.stride_tricks.as_strided(Z, shape = s, strides = Z.strides * 2)
return np.pad(np.einsum('ij,ijkl->kl', mask, sub), [(1, 1), (1, 1)], mode='constant')
Option from @CrazyElf with reference calculation for the boundaries of the matrix.def compute_neighbours_numpy_CrazyElf(Z):
ZZ = np.pad(Z, [(1, 1), (1, 1)], mode='constant')
N = ZZ[:-2, :-2] + ZZ[1:-1, :-2] + ZZ[2:, :-2]
+ ZZ[:-2, 1:-1] + ZZ[2:, 1:-1]
+ ZZ[:-2, 2: ] + ZZ[1:-1, 2: ] + ZZ[2:, 2: ]
return N
Performance measures:import numpy as np
from scipy.signal import convolve2d
import numba
import timeit
def compute_neighbours(Z):
shape = Z.shape
N = [[0 for i in range(shape[1])] for i in range(shape[0])]
for x in range(1, shape[0]-1):
for y in range(1, shape[1]-1):
N[x][y] = Z[x - 1][y - 1] + Z[x][y - 1] + Z[x + 1][y - 1] \
+ Z[x - 1][y ] + Z[x + 1][y ] \
+ Z[x - 1][y + 1] + Z[x][y + 1] + Z[x + 1][y + 1]
return N
@numba.njit
def compute_neighbours_numba(Z):
shape = Z.shape
N = [[0 for i in range(shape[1])] for i in range(shape[0])]
for x in range(1, shape[0]-1):
for y in range(1, shape[1]-1):
N[x][y] = Z[x - 1][y - 1] + Z[x][y - 1] + Z[x + 1][y - 1] \
+ Z[x - 1][y ] + Z[x + 1][y ] \
+ Z[x - 1][y + 1] + Z[x][y + 1] + Z[x + 1][y + 1]
return N
def compute_neighbours_numpy(Z):
return np.asarray([[np.sum(Z[x-1:x+2, y-1:y+2])-Z[x, y] for y in range(0, Z.shape[1])] for x in range(0, Z.shape[0])])
@numba.njit
def compute_neighbours_numpy_numba(Z):
return np.asarray([[np.sum(Z[x-1:x+2, y-1:y+2])-Z[x, y] for y in range(0, Z.shape[1])] for x in range(0, Z.shape[0])])
def compute_neighbours_numpy2(Z):
mask = np.asarray([[1,1,1], [1,0,1], [1,1,1]])
s = mask.shape + tuple(np.subtract(Z.shape, mask.shape) + 1)
sub = np.lib.stride_tricks.as_strided(Z, shape = s, strides = Z.strides * 2)
return np.pad(np.einsum('ij,ijkl->kl', mask, sub), [(1, 1), (1, 1)], mode='constant')
def compute_neighbours_numpy_CrazyElf(Z):
ZZ = np.pad(Z, [(1, 1), (1, 1)], mode='constant')
N = ZZ[:-2, :-2] + ZZ[1:-1, :-2] + ZZ[2:, :-2]
+ ZZ[:-2, 1:-1] + ZZ[2:, 1:-1]
+ ZZ[:-2, 2: ] + ZZ[1:-1, 2: ] + ZZ[2:, 2: ]
return N
def compute_neighbours_scipy(Z):
return convolve2d(Z, np.ones((3,3), dtype=int),'same') - Z
matrix = np.random.randint(2, size=(2000,2000))
print("list :", timeit.timeit("compute_neighbours(matrix)" , globals=globals(), number=2))
print("list + numba :", timeit.timeit("compute_neighbours_numba(matrix)" , globals=globals(), number=2))
print("numpy :", timeit.timeit("compute_neighbours_numpy(matrix)" , globals=globals(), number=2))
print("numpy + numba :", timeit.timeit("compute_neighbours_numpy_numba(matrix)" , globals=globals(), number=2))
print("numpy2 :", timeit.timeit("compute_neighbours_numpy2(matrix)" , globals=globals(), number=2))
print("numpy CrazyElf:", timeit.timeit("compute_neighbours_numpy_CrazyElf(matrix)", globals=globals(), number=2))
print("scipy :", timeit.timeit("compute_neighbours_scipy(matrix)" , globals=globals(), number=2))
matrix = np.random.randint(2, size=(10,10))
print(matrix)
print(*compute_neighbours(matrix), sep="\n")
print(compute_neighbours_numpy2(matrix))
print(compute_neighbours_numpy_CrazyElf(matrix))
print(compute_neighbours_numpy(matrix))
print(compute_neighbours_scipy(matrix))
Measurement results:list : 19.943651329
list + numba : 0.7527782960000025
numpy : 62.82599582
numpy + numba : 0.8693800110000041
numpy2 : 0.2166252049999997
numpy CrazyElf: 0.1425725370000066
scipy : 0.3862877149999946