NumPy arrays iterate over the left-most axis first. Thus if B has shape
(2,3,4), then B[0] has shape (3,4) and B[1] has shape (3,4). In this sense,
you could think of B as 2 arrays of shape (3,4). You can sort of see the two
arrays in the repr of B:
In [233]: B = np.arange(2*3*4).reshape((2,3,4))
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7], <-- first (3,4) array
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19], <-- second (3,4) array
[20, 21, 22, 23]]])
You can also think of B as containing four 2x3 arrays by iterating over the last index first:
for i in range(4):
print(B[:,:,i])
# [[ 0 4 8]
# [12 16 20]]
# [[ 1 5 9]
# [13 17 21]]
# [[ 2 6 10]
# [14 18 22]]
# [[ 3 7 11]
# [15 19 23]]
but you could just as easily think of B as three 2x4 arrays:
for i in range(3):
print(B[:,i,:])
# [[ 0 1 2 3]
# [12 13 14 15]]
# [[ 4 5 6 7]
# [16 17 18 19]]
# [[ 8 9 10 11]
# [20 21 22 23]]
NumPy arrays are completely flexible this way. But as far as the repr of B is concerned, what you see corresponds to two (3x4) arrays since B iterates over the left-most axis first.
for arr in B:
print(arr)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
# [[12 13 14 15]
# [16 17 18 19]
# [20 21 22 23]]
Answer from unutbu on Stack OverflowNumPy arrays iterate over the left-most axis first. Thus if B has shape
(2,3,4), then B[0] has shape (3,4) and B[1] has shape (3,4). In this sense,
you could think of B as 2 arrays of shape (3,4). You can sort of see the two
arrays in the repr of B:
In [233]: B = np.arange(2*3*4).reshape((2,3,4))
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7], <-- first (3,4) array
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19], <-- second (3,4) array
[20, 21, 22, 23]]])
You can also think of B as containing four 2x3 arrays by iterating over the last index first:
for i in range(4):
print(B[:,:,i])
# [[ 0 4 8]
# [12 16 20]]
# [[ 1 5 9]
# [13 17 21]]
# [[ 2 6 10]
# [14 18 22]]
# [[ 3 7 11]
# [15 19 23]]
but you could just as easily think of B as three 2x4 arrays:
for i in range(3):
print(B[:,i,:])
# [[ 0 1 2 3]
# [12 13 14 15]]
# [[ 4 5 6 7]
# [16 17 18 19]]
# [[ 8 9 10 11]
# [20 21 22 23]]
NumPy arrays are completely flexible this way. But as far as the repr of B is concerned, what you see corresponds to two (3x4) arrays since B iterates over the left-most axis first.
for arr in B:
print(arr)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
# [[12 13 14 15]
# [16 17 18 19]
# [20 21 22 23]]
I hope the below example would clarify the second part of your question where you have asked about getting a 2X3 matrics when you type print(B[:,:,1])
import numpy as np
B = [[[1,2,3,4],
[5,6,7,8],
[9,10,11,12]],
[[13,14,15,16],
[17,18,19,20],
[21,22,23,24]]]
B = np.array(B)
print(B)
print()
print(B[:,:,1])
[[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
[[13 14 15 16]
[17 18 19 20]
[21 22 23 24]]]
[[ 2 6 10]
[14 18 22]]
Since the dimension of B is 2X3X4, It means you have two matrices of size 3X4 as far as repr of B is concerned
Now in B[:,:,1] we are passing : , : and 1. First : indicates that we are selecting both the 3X4 matrices. The second : indicates that we are selecting all the rows from both the 3X4 matrices. The third parameter 1 indicates that we are selecting only the second column values of all the rows from both the 3X4 matrices. Hence we get
[[ 2 6 10]
[14 18 22]]
Slicing 3d array list in Python - Stack Overflow
Numpy slicing behaving weirdly when slicing three dimensional array. Any explanation?
python - Numpy 3D array data slicing along with specified axis - Stack Overflow
Arbitrary Slice of 3D Array in Python - Stack Overflow
Videos
Hi, guys!
I have a three dimensional array x=np.random.randn(10, 5, 5)
When I use: x2 = x[:, [1, 2], [1, 2]] I should get an array of size [10, 2, 2] but I don't. Instead I get an array of shape [10, 2].
To get what I want, I have to use two lines of code: x2 = x[:, [1, 2], :]; x2=x2[:, :, [1, 2]].
I don't understand why is numpy behaving in this manner. Any explanation is much appreciated
Thank you!
src[np.arange(src.shape[0]), [2, 1, 0]]
# src[np.arange(src.shape[0]), [2, 1, 0], :]
array([[10, 11, 12, 13, 14],
[25, 26, 27, 28, 29],
[40, 41, 42, 43, 44]])
We need to compute the indices for axis=0:
>>> np.arange(src.shape[0])
array([0, 1, 2])
And we already have the indices for axes=1. We then slice across axis=3 to extract our cross-section.
You could do:
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, 27, 28, 29],
[30, 31, 32, 33, 34],
[35, 36, 37, 38, 39]],
[[40, 41, 42, 43, 44],
[45, 46, 47, 48, 49],
[50, 51, 52, 53, 54],
[55, 56, 57, 58, 59]]])
first, second = zip(*enumerate([2, 1, 0]))
result = arr[first, second, :]
print(result)
Output
[[10 11 12 13 14]
[25 26 27 28 29]
[40 41 42 43 44]]
arr = np.array([[[1,2,3], [4,5,6]], [[7,8,9],[10,11,12]]])
# array([[[ 1, 2, 3],
# [ 4, 5, 6]],
# [[ 7, 8, 9],
# [10, 11, 12]]])
arr.shape # ------> (2,2,3)
# Think of them as axis
# lets create the first 2 axis of (`2`, ...)
# |(1)
# |
# |
# |
# |---------(0)
# now lets create second 2 axis of (2, `2`, ..)
# (1,1)
# |
# |---(1,0)
# |
# |
# |
# | |(0,1)
# |---------|---(0,0)
# now lets create the last 3 axis of (2, 2, `3`)
# /``(1,1,0) = 10
# |-- (1,1,1) = 11
# | \__(1,1,2) = 12
# |
# | /``(1,0,0) = 7
# |--|--(1,0,1) = 8
# | \__(1,0,2) = 9
# |
# |
# | /``(0,1,0) = 4
# | |--(0,1,1) = 5
# | \__(0,1,2) = 6
# | |
# | |
# |---------|---/``(0,0,0) = 1
# |--(0,0,1) = 2
# \__(0,0,2) = 3
# now suppose you ask
arr[0, :, :] # give me the first axis alon with all it's component
# |
# | /``(0,1,0) = 4
# | |--(0,1,1) = 5
# | \__(0,1,2) = 6
# | |
# | |
# |---------|---/``(0,0,0) = 1
# |--(0,0,1) = 2
# \__(0,0,2) = 3
# So it will print
# array([[1, 2, 3],
# [4, 5, 6]])
arr[:, 0, :] # you ask take all the first axis 1ut give me only the first axis of the first axis and all its components
#
#
#
#
# | /``(1,0,0) = 7
# |--|--(1,0,1) = 8
# | \__(1,0,2) = 9
# |
# |
# |
# |
# |
# |
# |
# |---------|---/``(0,0,0) = 1
# |--(0,0,1) = 2
# \__(0,0,2) = 3
# so you get the output
# array([[1, 2, 3],
# [7, 8, 9]])
# like wise you ask
print(arr[0:2, : , 2])
# so you are saying give (0,1) first axis, all of its children and only 3rd (index starts at 0 so 2 means 3) children
# 0:2 means 0 to 2 `excluding` 2; 0:5 means 0,1,2,3,4
#
# |
# | \__(1,1,2) = 12
# |
# |
# |--
# | \__(1,0,2) = 9
# |
# |
# |
# |
# | \__(0,1,2) = 6
# | |
# | |
# |---------|---/
# |
# \__(0,0,2) = 3
# so you get
# array([[ 3, 6],
# [ 9, 12]])
Going In
Given the array:
arr = np.array([[[1,2,3], [4,5,6]], [[7,8,9],[10,11,12]]])
The shape of arr, given by arr.shape is (2,2,3).
That basically means that if we start from outside (and ignore the first square bracket), we have 2 arrays in that scope. If we enter to one of those we can count 2 arrays and if we enter either we find 3 elements. I think having this view is quite helpful in understanding the following.
Specifying arr[1,1,2] selects the second array(index 1) in the outermost scope, and then selects the second array in the following scope and then selects the third element. The output is a single number:
12
specifying arr[:,1,2] first simultaneously selects all arrays at the outermost scope and then for each of these selects the second array (index 1). When we then enter into the next scope, we pick out the 3rd elements. This outputs two numbers:
array([ 6, 12])
specifying arr[:, : , 2] outputs 4 numbers since 1. at the first scope we selected all arrays (2) 2. at the next scope we selected all array (2 for each in the first)
array([[ 3, 6],
[ 9, 12]])
Coming out
Instinctually, the reason why they appear as 2x2 array can be viewed as receding from the lowermost scope. Elements are getting enclosed in square brackets because that share a scope. 3 and 6 will be in one array while 9 and 12 will be in another array.
Try this, which is similar structure to your arr[:,idx,idx] but using np.ix_(). Do read the documentation for np.ix().-
idx = [1,3,4]
ixgrid = np.ix_(idx,idx)
arr[:,ixgrid[0],ixgrid[1]]
array([[[83, 36, 87],
[39, 46, 88],
[37, 77, 72]],
[[64, 99, 88],
[32, 9, 57],
[31, 23, 35]]])
Explanation
What you are WANT to do is extract a mesh from the last 2 axes of the array. But what you are doing is extract exact indexes from each of the 2 axes.
- When you use
arr[:,(1,3,4),(1,3,4)], you are essentially asking for(1,1),(3,3)and(4,4)from the two matricesarr[0]andarr[1]

- What you need is to extract a mesh. This can be achieved with
np.ix_and the magic of broadcasting.

If you ask for ...
[[1],
[3], and [1,3,4]
[4]]
... which is what the np.ix_ constructs, you broadcast the indexes and instead ask for a cross product between them, which is (1,1), (1,3), (1,4), (3,1), (3,3)... etc.
Hope that clarifies why you get the result you are getting and how you can actually get what you need.
The problem
Advanced indexing expects all dimensions to be indexed explicitly. What you're doing here is grabbing the elements at coordinates (1, 1), (3, 3), (4, 4) in each array along axis 0.
The solution
What you need to do is this instead:
idx = (1, 3, 4) # the indices of interest
arr[np.ix_((0, 1), idx, idx)]
Where (0, 1) corresponds to the first two arrays along axis 0.
Output:
array([[[83, 36, 87],
[39, 46, 88],
[37, 77, 72]],
[[64, 99, 88],
[32, 9, 57],
[31, 23, 35]]], dtype=int64)
As shown above, np.ix_((0, 1), idx, idx)) produces an object which can be used for advanced indexing. The (0, 1) means that you're explicitly selecting the elements from the arrays arr[0] and arr[1]. If you have a more general 3D array of shape (n, m, q) and want to grab the same subarray out of every array along axis 0, you can use
np.ix_(np.arange(arr.shape[0]), idx, idx))
As your indices. Note that idx is repeated here because you wanted those specific indices but in general they don't need to match.
Generalizing
More generally, you can slice and dice however you want like so:
In [1]: arrays_to_select = (0, 1)
In [2]: rows_to_select = (1, 3, 4)
In [3]: cols_to_select = (1, 3, 4)
In [4]: indices = np.ix_(arrays_to_select, rows_to_select, cols_to_select)
In [5]: arr[indices]
Out[5]:
array([[[83, 36, 87],
[39, 46, 88],
[37, 77, 72]],
[[64, 99, 88],
[32, 9, 57],
[31, 23, 35]]], dtype=int64)
Let's consider some other shape:
In [4]: x = np.random.randint(0, 9, (4, 3, 5))
In [5]: x
Out[5]:
array([[[1, 0, 2, 1, 0],
[3, 5, 1, 4, 3],
[1, 8, 1, 4, 2]],
[[1, 6, 8, 2, 8],
[0, 0, 4, 2, 3],
[8, 5, 6, 2, 5]],
[[4, 4, 8, 6, 0],
[3, 0, 1, 2, 8],
[0, 8, 2, 4, 3]],
[[7, 8, 8, 1, 4],
[5, 7, 4, 8, 5],
[7, 5, 5, 3, 4]]])
In [6]: rows = (0, 2)
In [7]: cols = (0, 2, 3, 4)
By using those rows and cols, you'll be grabbing the subarrays composed of all the elements from columns 0 through 4, from only the rows 0 and 2. Let's verify that with the first array along axis 0:
In [8]: arrs = (0,) # A 1-tuple which will give us only the first array along axis 0
In [9]: x[np.ix_(arrs, rows, cols)]
Out[9]:
array([[[1, 2, 1, 0],
[1, 1, 4, 2]]])
Now suppose you want the subarrays produced by rows and cols of only the first and last arrays along axis 0. You can explicitly select (0, -1):
In [10]: arrs = (0, -1)
In [11]: x[np.ix_(arrs, rows, cols)]
Out[11]:
array([[[1, 2, 1, 0],
[1, 1, 4, 2]],
[[7, 8, 1, 4],
[7, 5, 3, 4]]])
If, instead, you want that same subarray from all the arrays along axis 0:
In [12]: arrs = np.arange(x.shape[0])
In [13]: arrs
Out[13]: array([0, 1, 2, 3])
In [14]: x[np.ix_(arrs, rows, cols)]
Out[14]:
array([[[1, 2, 1, 0],
[1, 1, 4, 2]],
[[1, 8, 2, 8],
[8, 6, 2, 5]],
[[4, 8, 6, 0],
[0, 2, 4, 3]],
[[7, 8, 1, 4],
[7, 5, 3, 4]]])