I have a 3x3x3 NumPy array:
>>> x = np.arange(27).reshape((3, 3, 3))
>>> x
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, 25, 26]]])
Now I create an ordinary list of indices:
>>> i = [[0, 1, 2, 1], [2, 1, 0, 1], [1, 2, 0, 1]]
As expected, I get four values using this list as the index:
>>> x[i]
array([ 7, 14, 18, 13])
But if I now convert i into a NumPy array, I won't get the same answer.
>>> j = np.asarray(i)
>>> x[j]
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, 25, 26]],
...,
[[[ 9, 10, 11],
[12, 13, 14],
[15, 16, 17]],
[[18, 19, 20],
[21, 22, 23],
[24, 25, 26]],
[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[ 9, 10, 11],
[12, 13, 14],
[15, 16, 17]]]])
Why is this so? Why can't I use NumPy arrays as indices to NumPy array?
x[j] is the equivalent of x[j,:,:]
In [163]: j.shape
Out[163]: (3, 4)
In [164]: x[j].shape
Out[164]: (3, 4, 3, 3)
The resulting shape is the shape of j joined with the last 2 dimensions of x. j just selects from the 1st dimension of x.
x[i] on the other hand, is the equivalent to x[tuple(i)], that is:
In [168]: x[[0, 1, 2, 1], [2, 1, 0, 1], [1, 2, 0, 1]]
Out[168]: array([ 7, 14, 18, 13])
In fact x(tuple(j)] produces the same 4 item array.
The different ways of indexing numpy arrays can be confusing.
Another example of how the shape of the index array or lists affects the output:
In [170]: x[[[0, 1], [2, 1]], [[2, 1], [0, 1]], [[1, 2], [0, 1]]]
Out[170]:
array([[ 7, 14],
[18, 13]])
Same items, but in a 2d array.
Check out the docs for numpy, what you are doing is "Integer Array Indexing", you need to pass each coordinate in as a separate array:
j = [np.array(x) for x in i]
x[j]
Out[191]: array([ 7, 14, 18, 13])
Related
I have an array a
a = np.arange(5*5).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]])
and want to select the last two columns from row one and two, and the first two columns of row three and four.
The result should look like this
array([[3, 4, 10, 11],
[8, 9, 15, 16]])
How to do that in one go without indexing twice and concatenation?
I tried using take
a.take([[0,1,2,3], [3,4,0,1]])
array([[0, 1, 2, 3],
[3, 4, 0, 1]])
ix_
a[np.ix_([0,1,2,3], [3,4,0,1])]
array([[ 3, 4, 0, 1],
[ 8, 9, 5, 6],
[13, 14, 10, 11],
[18, 19, 15, 16]])
and r_
a[np.r_[0:2, 2:4], np.r_[3:5, 0:2]]
array([ 3, 9, 10, 16])
and a combination of ix_ and r_
a[np.ix_([0,1,2,3], np.r_[3:4, 0:1])]
array([[ 3, 0],
[ 8, 5],
[13, 10],
[18, 15]])
Using integer advanced indexing, you can do something like this
index_rows = np.array([
[0, 0, 2, 2],
[1, 1, 3, 3],
])
index_cols = np.array([
[-2, -1, 0, 1],
[-2, -1, 0, 1],
])
a[index_rows, index_cols]
where you just select directly what elements you want.
I have a multidimensional Numpy array; let's say it's
myArray = 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, 25, 26]]])
I know that running myArray[1,1,1], for instance, will return 13. However, I want to define indx = [1,1,1] then call something to the effect ofmyArray[indx].
However, this does some other multidimensional indexing stuff.
I have also tried myArray[*indx] but that understandably throws a syntax error.
Currently my very ugly workaround is to define
def array_as_indices(array, matrix):
st = ''
for i in array:
st += '%s,' % i
st = st[:-1]
return matrix[eval(st)]
which works but is quite inelegant and presumably slow.
Is there a more pythonic way to do what I'm looking for?
This is a duplicate of Unpacking tuples/arrays/lists as indices for Numpy Arrays, but you can just create a tuple
import numpy as np
def main():
my_array = np.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, 25, 26]],
]
)
print(f"my_array[1,1,1]: {my_array[1,1,1]}")
indx = (1, 1, 1)
print(f"my_array[indx]: {my_array[indx]}")
if __name__ == "__main__":
main()
will give
my_array[1,1,1]: 13
my_array[indx]: 13
The indices of a numpy array are addressed by tuples, not lists. Use indx = (1, 1, 1).
As an extension, if you want to call the indices (1, 1, 1) and (2, 2, 2), you can use
>>> indx = ([1, 2], [1, 2], [1, 2])
>>> x[indx]
array([13, 26])
The rationale behind the behavior with lists is that numpy treats lists sequentially, so
>>> indx = [1, 1, 1]
>>> x[indx]
array([[[ 9, 10, 11],
[12, 13, 14],
[15, 16, 17]],
[[ 9, 10, 11],
[12, 13, 14],
[15, 16, 17]],
[[ 9, 10, 11],
[12, 13, 14],
[15, 16, 17]]])
It returns a list of three elements, each equal to x[1].
I have a numpy array:
arr = 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, 25, 26]]])
and an array of indices, ind = array([0, 1, 1])
What I would like to do is for the ith row in arr, delete the ind[i]th row in arr[i] using only numpy.delete.
So in essence a more pythonic way to do this:
x, y, z = arr.shape
new_arr = np.empty((x, y - 1, z))
for i, j in enumerate(ind):
new_arr[i] = np.delete(arr[i], j, 0)
arr = new_arr.astype(int)
So the output here would be:
array([[[ 3, 4, 5],
[ 6, 7, 8]],
[[ 9, 10, 11],
[15, 16, 17]],
[[18, 19, 20],
[24, 25, 26]]])
A working solution:
import numpy as np
arr = np.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, 25, 26]]])
a0, a1, a2 = arr.shape
indices = np.array([0, 1, 1])
mask = np.ones_like(arr, dtype=bool)
mask[np.arange(a0), indices, :] = False
result = arr[mask].reshape((a0, -1, a2))
print(result)
Output
[[[ 3 4 5]
[ 6 7 8]]
[[ 9 10 11]
[15 16 17]]
[[18 19 20]
[24 25 26]]]
i have a 1d np array "array1d" and a 3d np array "array3d", i want to sum them so the n'th value in "array1d" will be added to each of the elements of the n'th plane in array3d.
this can be done in the following loop
for i, value in enumerate(array1d):
array3d[i] += value
question is, how can this be done in a single numpy line?
example arrays:
arr1d = np.array(range(3))
>>>array([0, 1, 2])
arr3d = np.array(range(27)).reshape(3, 3, 3)
>>>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, 25, 26]]])
wanted result:
array([[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[ 10, 11, 12],
[13, 14, 15],
[16, 17, 18]],
[[20, 21, 22],
[23, 24, 25],
[26, 27, 28]]])
Use Numpy's broadcasting features:
In [23]: arr1d[:, None, None] + arr3d
Out[23]:
array([[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[10, 11, 12],
[13, 14, 15],
[16, 17, 18]],
[[20, 21, 22],
[23, 24, 25],
[26, 27, 28]]])
This basically copies the content of arr1d across the other two dimensions (without actually copying, it just provides a view of the memory which looks like it). Instead of None, you can also use numpy.newaxis.
Alternatively, you can also use reshape:
In [32]: arr1d.reshape(3, 1, 1) + arr3d
Out[32]:
array([[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[10, 11, 12],
[13, 14, 15],
[16, 17, 18]],
[[20, 21, 22],
[23, 24, 25],
[26, 27, 28]]])
Suppose I have the following array:
>>> a = np.arange(25).reshape((5, 5))
>>> a
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]])
Now I want to select different columns for each row based on the following index array:
>>> i = np.array([0, 1, 2, 1, 0])
This index array denotes the start column for each row and the selections should be of similar range, e.g. 3. Thus I want to obtain the following result:
>>> ???
array([[ 0, 1, 2],
[ 6, 7, 8],
[12, 13, 14],
[16, 17, 18],
[20, 21, 22]])
I know that I can select a single column per row via
>>> a[np.arange(a.shape[0]), i]
but how about multiple columns?
Use advanced indexing with properly broadcasted 2d array as index.
a[np.arange(a.shape[0])[:,None], i[:,None] + np.arange(3)]
#array([[ 0, 1, 2],
# [ 6, 7, 8],
# [12, 13, 14],
# [16, 17, 18],
# [20, 21, 22]])
idx_row = np.arange(a.shape[0])[:,None]
idx_col = i[:,None] + np.arange(3)
idx_row
#array([[0],
# [1],
# [2],
# [3],
# [4]])
idx_col
#array([[0, 1, 2],
# [1, 2, 3],
# [2, 3, 4],
# [1, 2, 3],
# [0, 1, 2]])
a[idx_row, idx_col]
#array([[ 0, 1, 2],
# [ 6, 7, 8],
# [12, 13, 14],
# [16, 17, 18],
# [20, 21, 22]])