Numpy modify multiple values 2D array using slicing - python

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.]]

Related

Create lower triangular matrix from a vector in python

I want to create a python program which computes a matrix from a vector with some coefficients. So lets say we have the following vector of coefficients c = [c0, c1, c2] = [0, 1, 0], then I want to compute the matrix:
So how do I go from the vector c to creating a lower triangular matrix A. I know how to index it manually, but I need a program that can do it. I was maybe thinking about a for-loop inside another for-loop but I struggle with how it is done practically, what do you guys think should be done here?
One way (assuming you're using plain arrays and not numpy or anything):
src = [0, 1, 0]
dst = [
[
src[i-j] if i >= j else 0
for j in range(len(src))
] for i in range(len(src))
]
You can try the following:
import numpy as np
c = [1, 2, 3, 4, 5]
n = len(c)
a = np.zeros((n,n))
for i in range(n):
np.fill_diagonal(a[i:, :], c[i])
print(a)
It gives:
[[1. 0. 0. 0. 0.]
[2. 1. 0. 0. 0.]
[3. 2. 1. 0. 0.]
[4. 3. 2. 1. 0.]
[5. 4. 3. 2. 1.]]

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

Find all the rectangles coordinates in a numpy 2d array ( prioritizing the vertical rectangles)

I am trying to figure out a solution for finding all the rectangles in a 2d array.
But in the mean while, I need to get the vertical ones first.
For example:
[[0. 0. 1. 0. 0.]
[0. 0. 0. 1. 1.]
[0. 0. 1. 1. 1.]]
The desire output would be
[[0, 2, 0, 2], [2, 2, 2, 2], [1, 3, 2, 4]]
Or something like
[[1. 0. 0. 0. 0.]
[1. 1. 0. 1. 1.]
[1. 1. 1. 1. 0.]]
Output should be
[[0, 0, 0, 0], [1, 0, 2, 1], [2, 2, 2, 2], [1, 3, 2, 3], [1, 4, 1, 4]]
In other words, if it's a horizontal rectangle of the height of only 1, it is viewed as multiple 11.
I am kind of stuck on the logic which should proceed first, my results prioritize the horizontal ones and have troubles dealing with zeros when encounter a 2*2 or above rectangle.
UPDATE
A rectangle in here means an area composed of 1s in the 2d array. However when something like
[[0. 0. 0. 0. 0.]
[0. 0. 0. 1. 1.]
[0. 0. 0. 1. 0.]]
happens, the output should be
[[1, 3, 2, 3], [1, 4, 1, 4]]
instead of
[[1, 3, 1, 4], [2, 3, 2, 3]]
1*1 counts as a rectangle too
The code I have for now looks like this
def solve2(grid):
output = []
visited = set()
for j in range(len(grid[0])):
for i in range(len(grid)):
if (i,j) in visited:
continue
visited.add((i,j))
if grid[i][j] == 1:
s_row, s_col = i, j
e_row, e_col = i,j
while e_col < len(grid[0]) and grid[i][e_col]:
while e_row < len(grid) and grid[e_row][j]:
e_row += 1
e_col += 1
for x in range(s_row, e_row):
for y in range(s_col, e_col):
visited.add((x,y))
e_row -= 1
e_col -= 1
output.append([s_row, s_col, e_row, e_col])
return output

Looking to replace min and max of ndarray in Python

I have the following ndarray :
c_dist = [[0. 5.83095189]
[2.23606798 3.60555128]
[5.83095189 0. ]
[5.83095189 2.82842712]
[4.12310563 2.23606798]]
and I would like for each sub-array to replace the min with 1 and the max with 0, in order to obtain the following :
[[1. 0.]
[1. 0.]
[0. 1.]
[0. 1.]
[0. 1.]]
I used the following :
for i in range(len(c_dist)):
max_of_row = c_dist[i].max()
for elements_of_row in range(len(c_dist[i])):
if c_dist[i][elements_of_row] == max_of_row:
c_dist[i][elements_of_row] = 1
else:
c_dist[i][elements_of_row] = 0
but it is obviously not very elegant.
Is there an python way of doing the comparison array by array please ?
Try this in one line:
c_dist = [[0. ,5.83095189],
[2.23606798 ,3.60555128],
[5.83095189 ,0. ],
[5.83095189 ,2.82842712],
[4.12310563 ,2.23606798]]
new_list = [[int(i<=j), int(i>j)] for i,j in c_dist]
The result will be:
In [6]: new_list
Out[6]: [[1, 0], [1, 0], [0, 1], [0, 1], [0, 1]]
If you have more than 2 columns:
out = c_dist.copy()
np.put_along_axis(out, c_dist.argmax(0), 1)
np.put_along_axis(out, c_dist.argmin(0), 0)
Or if there are multiple max and min values per row:
out = np.where(c_dist == c_dist.max(0, keepdims = True), 1, c_dist)
out = np.where(c_dist == c_dist.min(0, keepdims = True), 0, out)

Compare neighbours boolean numpy array in grid

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]]

Categories