Basic vs Advance indexing
To understand this behavior, you may want to understand how basic indexing and advance indexing works in numpy.
Basic indexing results in views, while advance indexing results in a copy.
Advance indexing can be combined with basic indexing but the way they behave is completely different. Basic indexing occurs when the object used for indexing is -
- A slice object that is of the form start:stop:step
- An integer
- Or a tuple of slice objects and integers
Advance indexing is triggered when -
- An ndarray of type integer or Boolean
- A tuple with at least one sequence object
- Is a non tuple sequence object
How they work
If you are working for indexes for multiple axes, advanced indexes (with arrays/lists) always are broadcast and iterated as one, while basic indexing (with slices) acts like repeated application of slicing over the axes.
This means that when using basic indexing as arr[slice(0,3), slice(3,5)], you are taking a view of the first rows and then the 3rd and 4th column of the array.
But when using advance indexing as arr[[0,2],[3,4]], you are taking the (0,3) and then the (2,4) indexed over both axis at once using broadcasting.
In your case, you are mixing basic and advance indexing. Let's first define the indexing objects and then play with them a bit to understand what's happening -
import numpy as np
two_dim_array = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]])
rows = [0,1]
cols = [2,3]
row_slice = slice(0,2) #same as 0:2, or :2
In the first case, let's use basic indexing on axis=0 and advance indexing on axis=1. Here the advance indexing for the 2 columns is performed first and then copies of the subspace rows are fetched through basic indexing.
two_dim_array[row_slice, cols]
array([[3, 4],
[7, 8]])
In second case, lets use advance indexing on both axes. This fetches copies of the array by iterating over both the rows and cols arrays/lists at once.
two_dim_array[rows, cols]
array([3, 8]) #(0,2) and (1,3) elements
But, as I mentioned, these indexes are broadcasted. Therefore, if you want to achieve the same result from advance indexing as you are with basic indexing, you can use something like np.ix_
obj = np.ix_(rows, cols)
obj
(array([[0],
[1]]),
array([[2, 3]]))
This creates 2 arrays in such a way that when broadcasted, result in (0,2), (0,3), (1,2), (1,3) indexes.
two_dim_array[obj]
array([[3, 4],
[7, 8]])
Hope that clarifies how this works!
broadcasting. In your example you have shape (2,) and (2,) arrays resulting in a (2,) selection. The first needs to be (1,2) shaped if you want a (2,2) result.