Looking to replace min and max of ndarray in Python - 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)

Related

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

Setting up multiple iterative statement

Let me say I'm rather new to python and stack overflow, so please help out if I'm making mistakes while I'm posting here.
I have a set of data where I am building intervals in a loop.
The data consists of three columns (0's and 1's). I would like to start a new interval any time a new 1 appears (where all three data sets are 0 before) and close the interval right before all elements are 0 again. For example:
data = [[0. 0. 0.]
[1. 0. 0.]
[1. 1. 0.]
[1. 1. 1.]
[0. 1. 1.]
[0. 0. 1.]
[0. 0. 0.]]
should come out as one interval with:
intervals = [[[1. 0. 0.]
[1. 1. 0.]
[1. 1. 1.]
[0. 1. 1.]
[0. 0. 1.]]]
and if there was the pattern in data was to repeat or there was a new sequence (following the same rules) , it would start a new interval. As an example, if the data set had the same repeating information, intervals would become:
intervals = [[[1. 0. 0.]
[1. 1. 0.]
[1. 1. 1.]
[0. 1. 1.]
[0. 0. 1.]],
[[1. 0. 0.]
[1. 1. 0.]
[1. 1. 1.]
[0. 1. 1.]
[0. 0. 1.]] ]
I able to achieve this style for an array of values with the following code, but am now trying to extend it to a n x 3 format.
A = np.array([0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1])
b = [[A[0]]]
last_char = A[0]
num_seq = 0
for i in range(1, len(A)):
if A[i] != last_char:
num_seq += 1
if len(b) <= num_seq:
b.append([])
b[num_seq].append(A[i])
last_char = A[i]
This is what ended up working. It is an extension of the last part of information I have in my statement. If anyone has anything more clean, I'd love to see it.
if data[0].any() == 1:
last_char = 1
access_matrix = [[1]]
else:
last_char = 0
access_matrix = [[0]]
num_seq = 0
for i in range(1, len(data)):
if data[i].any() == 1:
temp_var = 1
else:
temp_var = 0
if temp_var != last_char:
num_seq += 1
if len(access_matrix) <= num_seq:
access_matrix.append([])
access_matrix[num_seq].append(temp_var)
last_char = temp_var
I dont know the context of the problem required for the code but here's the code which gives you the result that you are looking for.
data = [0, 0, 0,
1, 0, 0,
1, 1, 0,
1, 1, 1,
0, 1, 1,
0, 0, 1,
0, 0, 0,]
idx=0
result=[]
temp_list=[]
for i in data:
if idx <= len(data)-1:
ele = data[idx]
if ele ==0:
if idx%3==0:
if data[idx+1] == 0 and data[idx+2] == 0:
# break the interval
if temp_list:
result.append(temp_list)
temp_list=[]
idx+=3
else:
# add ele to interval
temp_list.append(ele)
idx+=1
else:
# add ele to interval
temp_list.append(ele)
idx+=1
else:
# add ele to interval
temp_list.append(ele)
idx+=1
print(result)
The result is a list of your intervals found.
[
[
1, 0, 0,
1, 1, 0,
1, 1, 1,
0, 1, 1,
0, 0, 1
]
]

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

How to initialise a Numpy array of numpy arrays

I have a numpy array D of dimensions 4x4
I want a new numpy array based on an user defined value v
If v=2, the new numpy array should be [D D].
If v=3, the new numpy array should be [D D D]
How do i initialise such a numpy array as numpy.zeros(v) dont allow me to place arrays as elements?
If I understand correctly, you want to take a 2D array and tile it v times in the first dimension? You can use np.repeat:
# a 2D array
D = np.arange(4).reshape(2, 2)
print D
# [[0 1]
# [2 3]]
# tile it 3 times in the first dimension
x = np.repeat(D[None, :], 3, axis=0)
print x.shape
# (3, 2, 2)
print x
# [[[0 1]
# [2 3]]
# [[0 1]
# [2 3]]
# [[0 1]
# [2 3]]]
If you wanted the output to be kept two-dimensional, i.e. (6, 2), you could omit the [None, :] indexing (see this page for more info on numpy's broadcasting rules).
print np.repeat(D, 3, axis=0)
# [[0 1]
# [0 1]
# [0 1]
# [2 3]
# [2 3]
# [2 3]]
Another alternative is np.tile, which behaves slightly differently in that it will always tile over the last dimension:
print np.tile(D, 3)
# [[0, 1, 0, 1, 0, 1],
# [2, 3, 2, 3, 2, 3]])
You can do that as follows:
import numpy as np
v = 3
x = np.array([np.zeros((4,4)) for _ in range(v)])
>>> print x
[[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]]
Here you go, see if this works for you.
import numpy as np
v = raw_input('Enter: ')
To intialize the numpy array of arrays from user input (obviously can be whatever shape you're wanting here):
b = np.zeros(shape=(int(v),int(v)))
I know this isn't initializing a numpy array but since you mentioned wanting an array of [D D] if v was 2 for example, just thought I'd throw this in as another option as well.
new_array = []
for x in range(0, int(v)):
new_array.append(D)

Filling a 2D list with user input where value of column increases by 1 iteratively

I asks the user to input the values of ROW to fill a 2D list. The value of column will be iterativley increase by 1.
list2D = [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]
user input = [1,3,0,2] ##indexes of rows as well as values
i.e:
0th column the row = 1
1 column row = 3
2 column row = 0
3 column row = 2
So the new list will be:
newList = [[0,0,**0**,0],[1,0,0,0],[0,0,0,2],[0,3,0,0]]
How to do this?
list2D = [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]
user_input = [1,3,0,2]
for col,row in enumerate(user_input):
list2D[row][col] = row
print(list2D)
# [[0, 0, 0, 0], [1, 0, 0, 0], [0, 0, 0, 2], [0, 3, 0, 0]]
or, if you do not wish to modify list2D:
import copy
list2D = [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]
user_input = [1,3,0,2]
newList = copy.deepcopy(list2D)
for col,row in enumerate(user_input):
newList[row][col] = row
or, using numpy:
import numpy as np
list2D = np.zeros((4,4))
user_input = [1,3,0,2]
list2D[user_input,range(4)] = user_input
print(list2D)
# [[ 0. 0. 0. 0.]
# [ 1. 0. 0. 0.]
# [ 0. 0. 0. 2.]
# [ 0. 3. 0. 0.]]

Categories