I have many 2D arrays inside of a 3D array.
Let’s assume that shape of the 3D array is (3, 5, 5). Therefore, I have 3 2D Arrays of shape (5, 5).
Column #4 (idx of 3) in each 2D array has a certain value as per below. I want to replace those values with corresponding ranks in descending order. The highest value will correspond to the maximum number of records (I.e. shape[1]) in 2D array, and the lowest value will have a rank of 1 (not 0).
I know that this could be achieved using NumPy’s argsort() function. But what I want to avoid is looping through the 3D array.
Could you please suggest the most efficient, native NumPy and loop-free alternatives?
Thank you!
[[[1. 0. 0.10. 0.]
[2. 0. 0. 9. 0.]
[3. 0. 0. 8. 0.]
[4. 0. 0. 7. 0.]
[5. 0. 0. 6. 0.]]
[[1. 0. 0. 199. 0.]
[2. 0. 0. 198. 0.]
[3. 0. 0. 196. 0.]
[4. 0. 0. 190. 0.]
[5. 0. 0. 160. 0.]]
[[1. 0. 0. 999. 0.]
[2. 0. 0. 870. 0.]
[3. 0. 0. 270. 0.]
[4. 0. 0. 100. 0.]
[5. 0. 0. 80. 0.]]]
I suggest:
arr[:, :, 3] = arr[:, :, 3].argsort(axis=1).argsort(axis=1) + 1
Note that using argsort twice is necessary to obtain "ranks".
Related
I made the NxN matrix with Zeros and Ones and symmetrical and diagonal = 0. Now I want to make another matrix. Instead of the one in the matrix, I put a random number from 0-100 opposite numbers in the upper triangle and the one tringle have the same value as in the picture
and I want to do this to all ones in the new matrix
Thank You
enter image description here
All you should need to do is generate an NxN array of random numbers and multiply:
import numpy as np
N = 7
base = np.zeros((N,N))
for _ in range(15):
a = np.random.randint(N)
b = np.random.randint(N)
if a != b:
base[a,b] = 1
base[b,a] = 1
print(base)
# Fetch the location of the 1s.
ones = np.argwhere(base==1)
ones = ones[ones[:,0] < ones[:,1],:]
# Assign random values.
for a,b in ones:
base[a,b] = base[b,a] = np.random.randint(100)
print(base)
Note that my array creation is just for this example. You said you already have the 1/0 matrix so I'm not worried about that part.
Output:
[[0. 1. 0. 1. 1. 1. 1.]
[1. 0. 1. 0. 1. 1. 0.]
[0. 1. 0. 1. 1. 0. 0.]
[1. 0. 1. 0. 1. 0. 1.]
[1. 1. 1. 1. 0. 0. 1.]
[1. 1. 0. 0. 0. 0. 0.]
[1. 0. 0. 1. 1. 0. 0.]]
[[ 0. 37. 0. 7. 43. 40. 54.]
[37. 0. 45. 0. 87. 40. 0.]
[ 0. 45. 0. 74. 8. 0. 0.]
[ 7. 0. 74. 0. 47. 0. 75.]
[43. 87. 8. 47. 0. 0. 41.]
[40. 40. 0. 0. 0. 0. 0.]
[54. 0. 0. 75. 41. 0. 0.]]
The objective is to extract the coordinate where a cell equal to 1 in a 2D array
[[1. 0. 0. 1. 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. 1. 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 the coordinate is flip than the conventional
8
7
6
5
4
3
2
1
0
0 1 2 3 4 5 6 7 8
Hence, for the 2D array above,
the output where cell equal to 1 is
[(0, 8),(2,4),(3,8)]
I curious how can I tweak the np.where by taking consideration this type of coordinate.
Simply
cor=np.array(np.where(arr==1)).T
as expected will give different result than I expect.
The above array can be reproduce
arr=np.zeros((9,9))
arr[0,0]=1
arr[4,2]=1
arr[0,3]=1
Remark, the order is not important, such that
[(0, 8),(2,4),(3,8)] is equivalent to [(8, 0),(4,2),(8,3)]
The function np.where for a 2D array returns Tuple(np.ndarray, np.ndarray)where the first entry of the tuple contains all row indices and the second one all column indices. So if you want to index the tranposed array you have to swap the tuple entries:
indices = np.where(condition)[::-1]
If you want to transform the coordinate format to the list of 2-element-tuple you could do:
indices = [(n_rr, c) for r, c in zip(np.where(condition))]
Edit:
After clarification, I now understand that rpb wants to change the origin of indexing, so that the zeroth row becomes the last and so on. Furthermore, the coordinates are desired in the format of 2element tuple per found entry.
import numpy as np
arr=np.zeros((9,9))
arr[0,0]=1
arr[4,2]=1
arr[0,3]=1
print(arr)
print(np.where(arr==1.)[0])
n_rows = arr.shape[0]
indices = [(n_rows - 1 -r, c) for r, c in zip(*np.where(arr==1.))]
print(indices)
>>> [(8, 0), (8, 3), (4, 2)]
you can use numpy flip on axis 0 to flip the array to get your coordinates.
arr = np.flip(arr, axis=0)
cor = np.array(np.where(arr==1))
I am trying to replace an array of 0's column by column like this
import numpy as np
a = np.zeros((2,10))
b = np.linspace(1,10,10)
a[1,:] = b
which gives the correct output
a = [[ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]]
b = [ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]
However, the data I am trying to insert is complex, for some reason this form of indexing removes the imaginary part of the data. For example
a = np.zeros((2,10))
b = np.linspace(1,10,10) * 1j #now b is imaginary
a[1,:] = b
returns the following
a = [[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]
b = [0. +1.j 0. +2.j 0. +3.j 0. +4.j 0. +5.j 0. +6.j 0. +7.j 0. +8.j 0. +9.j
0.+10.j]
which is obviously incorrect. Is there a way to avoid this and keep the data complex? Thanks
I have just realised this is due to the zero matrix being a different type of data and is fixed by using
a = np.zeros((2,2),dtype = np.complex)
for reference if anyone else has the same problem
I need help to obtain the following type of result in Python (that I was used to in Matlab):
M = numpy.zeros((5,5))
m = numpy.array([[1,2,3],[4,5,6],[7,8,9]])
indx = [0, 2, 3]
# in Matlab: M(indx,indx) = M(indx,indx) + m
so that the output is:
[[ 1. 0. 2. 3. 0.]
[ 0. 0. 0. 0. 0.]
[ 4. 0. 5. 6. 0.]
[ 7. 0. 8. 9. 0.]
[ 0. 0. 0. 0. 0.]]
Suppose you have an array (m, m) and want to make it (n, n). For example, transforming a 2x2 matrix to a 6x6. So:
[[ 1. 2.]
[ 3. 4.]]
To:
[[ 1. 2. 0. 0. 0. 0.]
[ 3. 4. 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.]]
This is what I'm doing:
def array_append(old_array, new_shape):
old_shape = old_array.shape
dif = np.array(new_shape) - np.array(old_array.shape)
rows = []
for i in xrange(dif[0]):
rows.append(np.zeros((old_array.shape[0])).tolist())
new_array = np.append(old_array, rows, axis=0)
columns = []
for i in xrange(len(new_array)):
columns.append(np.zeros(dif[1]).tolist())
return np.append(new_array, columns, axis=1)
Example use:
test1 = np.ones((2,2))
test2 = np.zeros((6,6))
print array_append(test1, test2.shape)
Output:
[[ 1. 1. 0. 0. 0. 0.]
[ 1. 1. 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.]]
Based on this answer. But that's a lot of code for an (imho) simple operation. Is there a more concise/pythonic way to do it?
Why not use array = numpy.zeros((6,6)), see the numpy docs...
EDIT, woops, question has been edited... I guess you are trying to put ones in a section of an array filled with zeros? Then:
array = numpy.zeros((6,6))
array[0:2,0:2] = 1
If the small matrix does not all have the value of 1:
array[ystart:yend,xstart:xend] = smallermatrix
That would be then:
# test1= np.ones((2, 2))
test1= np.random.randn((2, 2))
test2= np.zeros((6, 6))
test2[0: 2, 0: 2]= test1