Reputation: 145
I would like to create a numpy 2d-array based on values in a numpy 3d-array, using another numpy 2d-array to determine which element to use in axis 3.
import numpy as np
#--------------------------------------------------------------------
arr_3d = np.arange(2*3*4).reshape(2,3,4)
print('arr_3d shape=', arr_3d.shape, '\n', arr_3d)
arr_2d = np.array(([3,2,0], [2,3,2]))
print('\n', 'arr_2d shape=', arr_2d.shape, '\n', arr_2d)
res_2d = arr_3d[:, :, 2]
print('\n','res_2d example using element 2 of each 3rd axis...\n', res_2d)
res_2d = arr_3d[:, :, 3]
print('\n','res_2d example using element 3 of each 3rd axis...\n', res_2d)
Results...
arr_3d shape= (2, 3, 4)
[[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[12 13 14 15]
[16 17 18 19]
[20 21 22 23]]]
arr_2d shape= (2, 3)
[[3 2 0]
[2 3 2]]
res_2d example using element 2 of each 3rd axis...
[[ 2 6 10]
[14 18 22]]
res_2d example using element 3 of each 3rd axis...
[[ 3 7 11]
[15 19 23]]
The 2 example results show what I get if I use the 2nd and then the 3rd element of axis 3. But I would like to get the element from arr_3d, specified by arr_2d. So...
- res_2d[0,0] would use the element 3 of arr_3d axis 3
- res_2d[0,1] would use the element 2 of arr_3d axis 3
- res_2d[0,2] would use the element 0 of arr_3d axis 3
etc
So res_2d should look like this...
[[3 6 8]
[14 19 22]]
I tried using this line to get the arr_2d entries, but it results in a 4-dim array and I want a 2-dim array.
res_2d = arr_3d[:, :, arr_2d[:,:]]
Upvotes: 8
Views: 1246
Reputation: 35080
While functionally the same as the other answers, I prefer to use numpy.ogrid
to generate the (sparse) index arrays that index the remaining dimensions:
import numpy as np
# example data
arr_3d = np.arange(2*3*4).reshape(2, 3, 4)
arr_2d = np.array(([3, 2, 0], [2, 3, 2]))
m, n, _ = arr_3d.shape
ind0, ind1 = np.ogrid[:m, :n]
res_2d = arr_3d[ind0, ind1, arr_2d]
print(res_2d)
# [[ 3 6 8]
# [14 19 22]]
One could also use np.meshgrid
with sparse=True
, but that would force us to create 1d index ranges which we can avoid with the np.ogrid
helper.
Upvotes: 1
Reputation: 25239
The shape of the result from fancy index and broadcasting is the shape of the indexing array. You need passing 2d array for each axis of arr_3d
ax_0 = np.arange(arr_3d.shape[0])[:,None]
ax_1 = np.arange(arr_3d.shape[1])[None,:]
arr_3d[ax_0, ax_1, arr_2d]
Out[1127]:
array([[ 3, 6, 8],
[14, 19, 22]])
Upvotes: 6
Reputation: 231335
In [107]: arr_3d = np.arange(2*3*4).reshape(2,3,4)
In [108]: arr_2d = np.array(([3,2,0], [2,3,2]))
In [109]: arr_2d.shape
Out[109]: (2, 3)
In [110]: arr_3d[[[0],[1]],[0,1,2],arr_2d]
Out[110]:
array([[ 3, 6, 8],
[14, 19, 22]])
[[0],[1]]
,[0,1,2]
broadcast with each other to index a (2,3) block, the same size as `arr_2d.
ix_
can be used to construct those 2 indices:
In [114]: I,J = np.ix_(range(2), range(3))
In [115]: I,J
Out[115]:
(array([[0],
[1]]), array([[0, 1, 2]]))
In [116]: arr_3d[I, J, arr_2d]
Out[116]:
array([[ 3, 6, 8],
[14, 19, 22]])
Upvotes: 1