Compare neighbours boolean numpy array in grid - python

I want to write a function which compares the 8 neighbours of a node in my grid. When minimum of 3 of the neighbours have the same value as the central node, we can define the node as happy.
for example in this array the central node and value is 0, we see that it has 3 neighbours of 0, so the node is happy:
array([[ 1, 0, 1],
[ 1, 0, 1],
[-1, 0, 0]])
I expect an boolean output with True or False.
Can I think of something like this or can I use easily numpy for this?
def nodehappiness(grid, i, j, drempel=3):
if i,j => 3:
node == True
Thanks in advance

Try this:
def neighbours(grid, i, j):
rows = np.array([-1, -1, -1, 0, 0, 1, 1, 1])
cols = np.array([-1, 0, 1, -1, 1, -1, 0, 1])
return grid[rows+i,cols+j]
Edit: Example:
grid = np.arange(25).reshape((5,5))
#array([[ 0, 1, 2, 3, 4],
# [ 5, 6, 7, 8, 9],
# [10, 11, 12, 13, 14],
# [15, 16, 17, 18, 19],
# [20, 21, 22, 23, 24]])
neighbours(grid, 0, 0)
# array([24, 20, 21, 4, 1, 9, 5, 6])
Explanation:
With numpy you can use negative indices allowing you to easily access the last entries of an array. This will also work for multiple dimensions:
x = np.array([0,1,2,3])
x[-1]
# 3
x.reshape((2,2))
#array([[0, 1],
# [2, 3]])
x[-1,-1]
# 3
You are interested in 8 entries of the matrix.
left above -> row - 1, column - 1
above -> row - 1, column + 0
right above -> row - 1, column + 1
left -> row + 0, column - 1
...
Thats what the arrays rows and cols represent. By adding i and j you get all the entries around these coordinates.

Try this.
y=[]
l= len(x)
for i in range(0,l):
for j in range(0,l):
if i==int(l/2) and j==int(l/2):
continue
y.append(x[j,i])

You search something like this?
def neighbour(grid, i, j):
return np.delete((grid[i-1:i+2,j-1:j+2]).reshape(1,9),4)
# Test code
grid = np.arange(16).reshape(4,4)
b = neighbour(m, 2, 2)

Some hackery using ndimage.generic_filter:
from scipy import ndimage
def get_neighbors(arr):
output = []
def f(x):
output.append(x)
return 0
t = tuple(int((x - 1) / 2) for x in arr.shape)
footprint = np.ones_like(arr)
footprint[t] = 0
ndimage.generic_filter(arr, f, footprint=footprint, mode='wrap')
return np.array(output)
arr = np.arange(9).reshape(3, 3)
neighbors = get_neighbors(arr)
neighbors_grid = neighbors.reshape(*arr.shape, -1)
print(neighbors)
print(neighbors_grid)
Which prints:
# neighbors
[[8. 6. 7. 2. 1. 5. 3. 4.]
[6. 7. 8. 0. 2. 3. 4. 5.]
[7. 8. 6. 1. 0. 4. 5. 3.]
[2. 0. 1. 5. 4. 8. 6. 7.]
[0. 1. 2. 3. 5. 6. 7. 8.]
[1. 2. 0. 4. 3. 7. 8. 6.]
[5. 3. 4. 8. 7. 2. 0. 1.]
[3. 4. 5. 6. 8. 0. 1. 2.]
[4. 5. 3. 7. 6. 1. 2. 0.]]
# neighbors_grid
[[[8. 6. 7. 2. 1. 5. 3. 4.]
[6. 7. 8. 0. 2. 3. 4. 5.]
[7. 8. 6. 1. 0. 4. 5. 3.]]
[[2. 0. 1. 5. 4. 8. 6. 7.]
[0. 1. 2. 3. 5. 6. 7. 8.]
[1. 2. 0. 4. 3. 7. 8. 6.]]
[[5. 3. 4. 8. 7. 2. 0. 1.]
[3. 4. 5. 6. 8. 0. 1. 2.]
[4. 5. 3. 7. 6. 1. 2. 0.]]]
If you merely want the padded array:
padded = np.pad(arr, pad_width=1, mode='wrap')
print(padded)
Which of course gives:
[[8 6 7 8 6]
[2 0 1 2 0]
[5 3 4 5 3]
[8 6 7 8 6]
[2 0 1 2 0]]

Related

How to do an index increment for my case?

I have to find the minimum for each column in a matrix, but there are two rules;
Each column will start from the "index+1" of the previous column, except for the first column
If one of the columns has exactly the index equal to the total number of rows of the matrix, then the rest indices for all the columns will be equal to the number of rows
As an example;
[[ "-1". -11. 0. 8. 1. ]
[ 2. 1. 0. 5. 1. ]
[ 4. 1. -2. 6. 7. ]
[ 8. 3. 1. 3. 0. ]
[ 5. "0". 1. 0. 8. ]
[ 9. 3. "-1". -1. 6.5]
[ 5. 3. 2. 5. 3. ]
[ 10. 3. 7. "1". "-1". ]]
The indices are inside quotations, [0,4,5,7,7]
Another example;
[[ 1. 1. 0. 0. 1.]
[ 2. 1. 0. 5. 1.]
[-4. -1. 2. 6. 7.]
['-5' 3. 1. 1. 0.]
[ 5. '0'. 1. 0. 8.]
[ 5. 3. '-1'. -1. 0.]
[ 5. 3. 1. '1'. 0.]
[ 5. 3. 1. 1. 0.]]
The indices here are [3,4,5,6,7]
I tried to do the following, but I am having errors. Could you please tell me how to do so?
def lst_min(matrix, columnindex, minIndex):
if minIndex == matrix.shape[0]:
return matrix.shape[0]
else:
return np.argmin(matrix[minIndex:, columnindex]) + minIndex
currentMinIndex = 0
lst = []
for i in range(a.shape[1]):
w = lst_min(matrix=a, columnindex=i, minIndex=currentMinIndex)
if w > a.shape[0]:
w = a.shape[0]
lst.append(w)
if w == 0:
c = 1
currentMinIndex = w + c
if currentMinIndex > a.shape[0]:
currentMinIndex = a.shape[0]
Your code use lst.append(w) with some strange logic...
You use lst_min to find minimum index but you simply return matrix.shape[0] when currentMinIndex = 0 (minIndex == matrix.shape[0]) at start.
FIY,
# post source code next time if you can,
# it will be really helpful to others to run your question easily
# and focus on the main problem quickly.
a = np.array(
[[ -1, -11, 0, 8, 1. ],
[ 2, 1, 0, 5, 1. ],
[ 4, 1, -2, 6, 7. ],
[ 8, 3, 1, 3, 0. ],
[ 5, 0, 1, 0, 8. ],
[ 9, 3, -1, -1, 6.5],
[ 5, 3, 2, 5, 3. ],
[ 10, 3, 7, 1, -1. ]]
)
b = np.array(
[[ 1, 1, 0, 0, 1],
[ 2, 1, 0, 5, 1],
[-4, -1, 2, 6, 7],
[-5, 3, 1, 1, 0],
[ 5, 0, 1, 0, 8],
[ 5, 3, -1, -1, 0],
[ 5, 3, 1, 1, 0],
[ 5, 3, 1, 1, 0]]
)
lst = []
start_idx = 0
for vec in a.T: # forloop column-wise
if start_idx >= vec.shape[0]-1: # index compare shape, should -1
lst.append(vec.shape[0]-1) # put the last index
else: # find minimum index
min_idx = np.argmin(vec[start_idx:]) # slice it
start_idx += min_idx # add back the true index
lst.append(start_idx) # append to result
start_idx += 1 # next column, use index + 1 (your rule 1)
if start_idx >= vec.shape[0]-1: # but if it is larger or equal, fit it back for next column use
start_idx = vec.shape[0]-1
The results should be:
>>>lst
[0, 4, 5, 7, 7]
# code change to b.T
>>>lst
[3, 4, 5, 6, 7]

Matrix element repetition bug

I'm trying to create a matrix that reads:
[0,1,2]
[3,4,5]
[6,7,8]
However, my elements keep repeating. How do I fix this?
import numpy as np
n = 3
X = np.empty(shape=[0, n])
for i in range(3):
for j in range(1,4):
for k in range(1,7):
X = np.append(X, [[(3*i) , ((3*j)-2), ((3*k)-1)]], axis=0)
print(X)
Results:
[[ 0. 1. 2.]
[ 0. 1. 5.]
[ 0. 1. 8.]
[ 0. 1. 11.]
[ 0. 1. 14.]
[ 0. 1. 17.]
[ 0. 4. 2.]
[ 0. 4. 5.]
I'm not really sure how you think your code was supposed to work. You are appending a row in X at each loop, so 3 * 3 * 7 times, so you end up with a matrix of 54 x 3.
I think maybe you meant to do:
for i in range(3):
X = np.append(X, [[3*i , 3*i+1, 3*i+2]], axis=0)
Just so you know, appending array is usually discouraged (just create a list of list, then make it a numpy array).
You could also do
>> np.arange(9).reshape((3,3))
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])

Formating numpy arrays to find the sum betyween 2 values Python

I am trying to modify the values of the values down below to the expected values. The function down below is meant to sum out all the values between 2 consecutive elements of limits. none of the values are between 0 and 2 within Numbers so the resultant is 0. However the values between 2 and 5 are 3,4 within Numbers so the resultant is 3+4=7. The function has been gotten from issue: issue.
def formating(a, b):
# Formating goes here
x = np.sort(b);
# digitize
l = np.digitize(a, x)
# output:
result = np.bincount(l, weights=a)
return result
Numbers = np.array([3, 4, 5, 7, 8, 10,20])
limit1 = np.array([0, 2 , 5, 12, 15])
limit2 = np.array([0, 2 , 5, 12])
limit3 = np.array([0, 2 , 5, 12, 15, 22])
result1= formating(Numbers, limit1)
result2= formating(Numbers, limit2)
result3= formating(Numbers, limit3)
Current output
result1: [ 0. 0. 7. 30. 0. 20.]
result2: [ 0. 0. 7. 30. 20.]
result3: [ 0. 0. 7. 30. 0. 20.]
Wanted Output:
result1: [ 0. 7. 30. 0.]
result2: [ 0. 7. 30. ]
result3: [ 0. 7. 30. 0. 20.]
So just throw out the bins for numbers off the end.
result1 = result1[1:len(limit1)]
result2 = result2[1:len(limit2)]
result3 = result3[1:len(limit3)]
Or, for smarter results, end the function with:
result = np.bincount(1, weights=a)
return result[1:len(b)]

Formating multidimensional numpy arrays to find the sum betyween 2 values Python

The function down below is meant to sum out all second row values of Numbers[:,0] between 2 consecutive elements of limits limit1-3. For the first calculation if none of the values are between 0 and 2 (the first two elements of limit1) within Numbers so the resultant is 0. For the second calculation 3,4 within Numbers[:,0] is between the values 2-5 in limit1 so the second column of Numbers is summed up 1+3 =4 resulting in 4. How could I implement this to the function below?
def formating(a, b, c):
# Formating goes here
x = np.sort(c);
# digitize
l = np.digitize(a, x)
# output:
result = np.bincount(l, weights=b)
return result[1:len(b)]
Numbers = np.array([[3,1], [4,3], [5,3], [7,11], [8,9], [10,20] , [20, 45]])
limit1 = np.array([0, 2 , 5, 12, 15])
limit2 = np.array([0, 2 , 5, 12])
limit3 = np.array([0, 2 , 5, 12, 15, 22])
result1= formating(Numbers[:,0], Numbers[:,1], limit1)
result2= formating(Numbers[:,0], Numbers[:,1], limit2)
result3= formating(Numbers[:,0], Numbers[:,1], limit3)
Expected Output
result1: [ 0. 4. 43. 0. ]
result2: [ 0. 4. 43. ]
result3: [ 0. 4. 43. 0. 45.]
Current Output
result1: [ 0. 4. 43. 0. 45.]
result2: [ 0. 4. 43. 45.]
result3: [ 0. 4. 43. 0. 45.]
This:
return result[1:len(b)]
should be
return result[1:len(c)]
Your return vector is dependent on the length of your bins, not your input data.

Numpy modify multiple values 2D array using slicing

I want to change some values in a numpy 2D array, based on the values of another array. The rows of the submatrix are selected using boolean slicing and the columns are selected by using integer slicing.
Here is some example code:
import numpy as np
a = np.array([
[0, 0, 1, 0, 0],
[1, 1, 1, 0, 1],
[0, 1, 0, 1, 0],
[1, 1, 1, 0, 0],
[1, 0, 0, 0, 1],
[0, 0, 0, 0, 0],
])
b = np.ones(a.shape) # Fill with ones
rows = a[:, 3] == 0 # Select all the rows where the value at the 4th column equals 0
cols = [2, 3, 4] # Select the columns 2, 3 and 4
b[rows, cols] = 2 # Replace the values with 2
print(b)
The result I want in b is:
[[1. 1. 2. 2. 2.]
[1. 1. 2. 2. 2.]
[1. 1. 1. 1. 1.]
[1. 1. 2. 2. 2.]
[1. 1. 2. 2. 2.]
[1. 1. 2. 2. 2.]]
But, the only thing I get is an exception:
IndexError
shape mismatch: indexing arrays could not be broadcast together with shapes (5,) (3,)
How could I achieve the result I want?
You could use argwhere:
rows = np.argwhere(a[:, 3] == 0)
cols = [2, 3, 4]
b[rows, cols] = 2 # Replace the values with 2
print(b)
Output
[[1. 1. 2. 2. 2.]
[1. 1. 2. 2. 2.]
[1. 1. 1. 1. 1.]
[1. 1. 2. 2. 2.]
[1. 1. 2. 2. 2.]
[1. 1. 2. 2. 2.]]

Categories