Numpy array 'for' loop in Python - python

I'm using a for loop to pull values from 2 arrays and then put them together in a new array. I can get the last row of the array, but not all the rows before it. (I would like to append each row to the same array.) Any ideas?
import numpy as np
# Array inputs
a = np.array([0, 1, 2])
b = np.array([[1, 10, 20, 30], [2, 40, 50, 60], [3, 70, 80, 90]])
Note that the a array will be random depending on what file is loaded. So for one file, it might be:
([1, 1, 2])
And then for another file it might be:
([0, 2, 1])
So, the a array looks up the first value of the b array and then takes its last 3 values while indexing this action.
From these 2 arrays, I want a new array like this:
# ([[0, 10, 20, 30],
# [1, 40, 50, 60],
# [2, 70, 80, 90]])
Here's my loop:
# Loop to put all values in c and d arrays:
for index, value in enumerate(np.nditer(a)):
c = b[value][1:4]
d = index
# Stack c and d array into e
e = np.hstack((c, d))
But returns this:
([2, 70, 80, 90]) # Only last line of loop.
# I wish to get last line and all lines before it.

Without using for loop, you can copy contents of b to e then, replace content of e of all rows first column ( using e[:,0]) by a:
import numpy as np
# Array inputs
a = np.array([0, 1, 2])
b = np.array([[1, 10, 20, 30], [2, 40, 50, 60], [3, 70, 80, 90]])
e = np.copy(b)
e[:,0] = a
print(e)
Result:
[[ 0 10 20 30]
[ 1 40 50 60]
[ 2 70 80 90]]

Related

Find index of a row in numpy array

Given m x n numpy array
X = np.array([
[1, 2],
[10, 20],
[100, 200]
])
how to find index of a row, i.e. [10, 20] -> 1?
n could any - 2, 3, ..., so I can have n x 3 arrays
Y = np.array([
[1, 2, 3],
[10, 20, 30],
[100, 200, 300]
])
so I need to pass a vector of size n, in this case n=3, i.e a vector [10, 20, 30] to get its row index 1? Again, n could be of any value, like 100 or 1000.
Numpy arrays could be big, so I don't want to convert them to lists to use .index()
Just in case that the query array contains duplicate rows that you are looking for, the function below returns multiple indices in such case.
def find_rows(source, target):
return np.where((source == target).all(axis=1))[0]
looking = [10, 20, 30]
Y = np.array([[1, 2, 3],
[10, 20, 30],
[100, 200, 300],
[10, 20, 30]])
print(find_rows(source=Y, target=looking)) # [1, 3]
You can use numpy.equal, which will broadcast and compare row vector against each row of the original array, and if all elements of a row are equal to the target, the row is identical to the target:
import numpy as np
np.flatnonzero(np.equal(X, [10, 20]).all(1))
# [1]
np.flatnonzero(np.equal(Y, [10, 20, 30]).all(1))
# [1]
You can make a function as follow:
def get_index(seq, *arrays):
for array in arrays:
try:
return np.where(array==seq)[0][0]
except IndexError:
pass
then:
>>>get_index([10,20,30],Y)
1
Or with just indexing:
>>>np.where((Y==[10,20,30]).all(axis=1))[0]
1

How to perform operations on certain rows of one np array based on conditions of another np array using numpy methods?

For example, I have one np array A = [[30, 60, 50...], [ 15, 20, 18...], [21, 81, 50...]...] of size (N, 10).
And I have another np array B = [1, 1, 0...] of size (N, ).
I want to do operations E.g. I want all the sums of each column in A but only for rows where B==1. How would I do that without using any loops and just numpy methods?
So if I want sum of columns in A for indices where B == 1:
result = 30 + 15 because the first two indices in B are 1 but the third index is 0 so I wouldn't include it in the sum.
Use np.compress and sum along axis=0
>>> A = [[30, 60, 50], [ 15, 20, 18], [21, 81, 50]]
>>> B = [1, 1, 0]
>>> np.compress(B, A, axis=0).sum(0)
array([45, 80, 68])
If array, use np.nonzero on B:
>>> A = np.array([[30, 60, 50], [ 15, 20, 18], [21, 81, 50]])
>>> A[np.nonzero(B)].sum(0)
array([45, 80, 68])
Another way:
>>> A[B.astype(bool)].sum(0)
array([45, 80, 68])
If you want 0s:
>>> np.compress(B==0, A, axis=0).sum(0)
# Or,
>>> A[np.nonzero(B==0)].sum(0)
# Or,
>>> A[~B.astype(bool)].sum(0)
If you want both 1s and 0s, obviously:
>>> A.sum(0)
You can convert B to bool type and mask A. Then you can get the sum along columns.
A = np.array([[30, 60, 50], [ 15, 20, 18], [21, 81, 50]])
B = np.array([1, 1, 0])
A[B.astype(np.bool)].sum(axis=0)
array([45, 80, 68])

How to create an NumPy array based on the index stored in another array?

Let say I have this NumPY array
A =
array([[0, 1, 3],
[1, 2, 4]])
I have another array
B =
array([[10, 41, 26, 50, 12, 24],
[20, 15, 42, 40, 41, 62]])
I wanted to create another array, where it selects the element in B using the index of the column in A. That is
C =
array([[10, 41, 50],
[15, 42, 41]])
Try:
B[[[0],[1]], A]
Or more generally:
B[np.arange(A.shape[0])[:,None], A]
Output:
array([[10, 41, 50],
[15, 42, 41]])
You can use np.take_along_axis
np.take_along_axis(B, A, axis=1)
output:
array([[10, 41, 50],
[15, 42, 41]])
This can be simply done using list rather than numpy
Though, in the ending we can convert it into numpy.
Code:
import numpy as np
#to make it simpler take a 1d list
a = [0,1,3]
b = [10, 41, 26, 50, 12, 24]
c = []
a = np.array(a)
b = np.array(b)
#here we are using for loop to find the value in a and append the index of b in c
for i in range(len(a)):
print(i)
i = a[i]
c.append(b[i])
print(c)
c = np.array(c)
print(type(c))
#To make it more fun, you can use the random module to get random digits

How to sort 2D array column by ascending and row by descending in Python 3

This is my array:
import numpy as np
boo = np.array([
[10, 55, 12],
[0, 81, 33],
[92, 11, 3]
])
If I print:
[[10 55 12]
[ 0 81 33]
[92 11 3]]
How to sort array column by ascending and row by descending like this:
[[33 81 92]
[10 12 55]
[0 3 11]]
# import the necessary packages.
import numpy as np
# create the array.
boo = np.array([
[10, 55, 12],
[0, 81, 33],
[92, 11, 3]
])
# we use numpy's 'sort' method to conduct the sorting process.
# we first sort the array along the rows.
boo = np.sort(boo, axis=0)
# we print to observe results.
print(boo)
# we therafter sort the resultant array again, this time on the axis of 1/columns.
boo = np.sort(boo, axis=1)
# we thereafter reverse the contents of the array.
print(boo[::-1])
# output shows as follows:
array([[33, 81, 92],
[10, 12, 55],
[ 0, 3, 11]])

Is there a way to conditionally index 3D-numpy array?

Having an array A with the shape (2,6, 60), is it possible to index it based on a binary array B of shape (6,)?
The 6 and 60 is quite arbitrary, they are simply the 2D data I wish to access.
The underlying thing I am trying to do is to calculate two variants of the 2D data (in this case, (6,60)) and then efficiently select the ones with the lowest total sum - that is where the binary (6,) array comes from.
Example: For B = [1,0,1,0,1,0] what I wish to receive is equal to stacking
A[1,0,:]
A[0,1,:]
A[1,2,:]
A[0,3,:]
A[1,4,:]
A[0,5,:]
but I would like to do it by direct indexing and not a for-loop.
I have tried A[B], A[:,B,:], A[B,:,:] A[:,:,B] with none of them providing the desired (6,60) matrix.
import numpy as np
A = np.array([[4, 4, 4, 4, 4, 4], [1, 1, 1, 1, 1, 1]])
A = np.atleast_3d(A)
A = np.tile(A, (1,1,60)
B = np.array([1, 0, 1, 0, 1, 0])
A[B]
Expected results are a (6,60) array containing the elements from A as described above, the received is either (2,6,60) or (6,6,60).
Thank you in advance,
Linus
You can generate a range of the indices you want to iterate over, in your case from 0 to 5:
count = A.shape[1]
indices = np.arange(count) # np.arange(6) for your particular case
>>> print(indices)
array([0, 1, 2, 3, 4, 5])
And then you can use that to do your advanced indexing:
result_array = A[B[indices], indices, :]
If you always use the full range from 0 to length - 1 (i.e. 0 to 5 in your case) of the second axis of A in increasing order, you can simplify that to:
result_array = A[B, indices, :]
# or the ugly result_array = A[B, np.arange(A.shape[1]), :]
Or even this if it's always 6:
result_array = A[B, np.arange(6), :]
An alternative solution using np.take_along_axis (from version 1.15 - docs)
import numpy as np
x = np.arange(2*6*6).reshape((2,6,6))
m = np.zeros(6, int)
m[0] = 1
#example: [1, 0, 0, 0, 0, 0]
np.take_along_axis(x, m[None, :, None], 0) #add dimensions to mask to match array dimensions
>>array([[[36, 37, 38, 39, 40, 41],
[ 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23],
[24, 25, 26, 27, 28, 29],
[30, 31, 32, 33, 34, 35]]])

Categories