Reputation: 13
I was doing a python challenge and this one stumped me. This is the input matrix (numpy format):
# [[1, 7, 2, 2, 1],
# [7, 7, 9, 3, 2],
# [2, 9, 4, 4, 2],
# [2, 3, 4, 3, 2],
# [1, 2, 2, 7, 1]]
and the function would output this matrix
# [[False, True, False, False, False],
# [True, False, True, False, False],
# [False, True, False, True, False],
# [False, False, False, False, False],
# [False, False, False, True, False]]
And you can see the value will be 'true' if any (up/down/left/right) neighbor is 2 smaller than itself. We've been learning numpy, but this doesn't feel like it's too much of a numpy thing).
I tried to do simple if comparison=true checks, but I kept stumbling into out-of-index errors and I couldnt find any way to circumvent/ignore those.
Thanks in advance.
This is the essence of what I've tried so far. I've simplified the task here to simply check the first row horizontally. If I could get this to work, I would extend it to check the next row horizontally until the end, and then I would do the same thing but vertically.
import numpy as np
ex=np.array([[7, 2, 3, 4, 3, 4, 7]])
def count_peaks(A):
matrixHeight=A.shape[0]
matrixWidth=A.shape[1]
peakTable=np.zeros(shape=(matrixHeight,matrixWidth))
for i in range(matrixWidth):
if A[i]-A[i+1]>=2 or A[i]-A[i-1]>=2:
peakTable[0,i]=1
return peakTable
... which of course outputs:
IndexError: index 1 is out of bounds for axis 0 with size 1
as I'm trying to find the value of A[-1] which doesn't exist.
Upvotes: 1
Views: 416
Reputation: 2202
If you don't mind me not using numpy to get the solution, but converting to numpy at the end, here is my attempt:
import numpy as np
def check_neighbors(mdarray,i,j):
neighbors = (-1, 0), (1, 0), (0, -1), (0, 1)
for neighbor in neighbors:
try:
if mdarray[i][j]-mdarray[i+neighbor[0]][j+neighbor[1]]>=2:
return True
except IndexError:
pass
return False
mdarray= [[1, 7, 2, 2, 1],
[7, 7, 9, 3, 2],
[2, 9, 4, 4, 2],
[2, 3, 4, 3, 2],
[1, 2, 2, 7, 1]]
peak_matrix =[]
for i in range(len(mdarray)):
row = []
for j in range(len(mdarray[i])):
#print(check_neighbors(mdarray,i,j))
row.append(check_neighbors(mdarray,i,j))
peak_matrix.append(row)
y=np.array([np.array(xi) for xi in peak_matrix])
print(y)
I use the try-except block to avoid errors when the index goes out of bounds.
Note: Row 4 Column 3 (starting counts at 1) of my output seems to differ from yours. I think that the 4 and 2 difference in the neighbors should make this entry true?
Output:
[[False True False False False]
[ True False True False False]
[False True False True False]
[False False True False False]
[False False False True False]]
Edit: changed from bare except to IndexError as Neither suggests in the comments. pass and continue doesn't make a difference in this case but yes.
Upvotes: 0
Reputation: 260530
You are using numpy arrays, so don't loop, use vectorial code:
import numpy as np
# get shape
x,y = a.shape
# generate row/col of infinites
col = np.full([x, 1], np.inf)
row = np.full([1, y], np.inf)
# shift left/right/up/down
# and compute difference from initial array
left = a - np.c_[col, a[:,:-1]]
right = a - np.c_[a[:,1:], col]
up = a - np.r_[row, a[:-1,:]]
down = a -np.r_[a[1:,:], row]
# get max of each shift and compare to threshold
peak_table = np.maximum.reduce([left,right,up,down])>=2
# NB. if we wanted to use a maximum threshold, we would use
# `np.minimum` instead and initialize the shifts with `-np.inf`
output:
array([[False, True, False, False, False],
[ True, False, True, False, False],
[False, True, False, True, False],
[False, False, True, False, False],
[False, False, False, True, False]])
input:
import numpy as np
a = np.array([[1, 7, 2, 2, 1],
[7, 7, 9, 3, 2],
[2, 9, 4, 4, 2],
[2, 3, 4, 3, 2],
[1, 2, 2, 7, 1]])
Upvotes: 2