Slicing a 4-D array in numpy - python

I created a numpy array called 'd' and then reshape it to get 'd1' as follows:-
d=np.arange(32)
d1=d.reshape(2,2,2,4)
The numpy array 'd1' looks like:-
[[[[ 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]]]]
I want to slice and extract this array so as to get two 1-D arrays as follows:-
[[13 14]
[17 18]]
I'm new to numpy and barely started 2 days ago. Am able to do some basic stuff with indexing and slicing. However this one has me stumped for hours. Any help would be much appreciated.
Thanks and Regards.

If your selection is arbitrary, and you just want a way to get [[13, 14], [17, 18]]. Then, here is a possible solution:
first reshape your nd-array to a 2D array
>>> d.reshape(8, 4)
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]])
slice properly along both remaining axes:
>>> d.reshape(8, 4)[3:5, 1:3]
array([[13, 14],
[17, 18]])
Alternatively you can always unravel the indices into d shape and index the array with those:
>>> idx = np.unravel_index([13, 14, 17, 18], d.shape)
(array([0, 0, 1, 1]),
array([1, 1, 0, 0]),
array([1, 1, 0, 0]),
array([1, 2, 1, 2]))
>>> d[idx]
array([13, 14, 17, 18])

Related

Figuring out correct numpy transpose for 3*3*3 array

Suppose I have a 3*3*3 array x. I would like to find out an array y, such that such that y[0,1,2] = x[1,2,0], or more generally, y[a,b,c]= x[b,c,a]. I can try numpy.transpose
import numpy as np
x = np.arange(27).reshape((3,3,3))
y = np.transpose(x, [2,0,1])
print(x[0,1,2],x[1,2,0])
print(y[0,1,2])
The output is
5 15
15
The result 15,15 is what I expected (the first 15 is the reference value from x[1,2,0]; the second is from y[0,1,2]) . However, I found the transpose [2,0,1] by drawing in a paper.
B C A
A B C
by inspection, the transpose should be [2,0,1], the last entry in the upper row goes to 1st in the lower row; the middle goes last; the first go middle. Is there any automatic and hopefully efficient way to do it (like any standard function in numpy/sympy)?
Given the input y[a,b,c]= x[b,c,a], output [2,0,1]?
I find easier to explore tranpose with a example with shape like (2,3,4), each axis is different.
But sticking with your (3,3,3)
In [23]: x = np.arange(27).reshape(3,3,3)
In [24]: x
Out[24]:
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]]])
In [25]: x[0,1,2]
Out[25]: 5
Your sample transpose:
In [26]: y = x.transpose(2,0,1)
In [27]: y
Out[27]:
array([[[ 0, 3, 6],
[ 9, 12, 15],
[18, 21, 24]],
[[ 1, 4, 7],
[10, 13, 16],
[19, 22, 25]],
[[ 2, 5, 8],
[11, 14, 17],
[20, 23, 26]]])
We get the same 5 with
In [28]: y[2,0,1]
Out[28]: 5
We could get that (2,0,1) by applying the same transposing values:
In [31]: idx = np.array((0,1,2)) # use an array for ease of indexing
In [32]: idx[[2,0,1]]
Out[32]: array([2, 0, 1])
The way I think about the trapose (2,0,1), we are moving the last axis, 2, to the front, and preserving the order of the other 2.
With differing dimensions, it's easier to visualize the change:
In [33]: z=np.arange(2*3*4).reshape(2,3,4)
In [34]: z
Out[34]:
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]]])
In [35]: z.transpose(2,0,1)
Out[35]:
array([[[ 0, 4, 8],
[12, 16, 20]],
[[ 1, 5, 9],
[13, 17, 21]],
[[ 2, 6, 10],
[14, 18, 22]],
[[ 3, 7, 11],
[15, 19, 23]]])
In [36]: _.shape
Out[36]: (4, 2, 3)
np.swapaxes is another compiled function for making these changes. np.rollaxis is another, though it's python code that ends up calling transpose.
I haven't tried to follow all of your reasoning, though I think you want a kind reverse of the transpose numbers, one where you specify the result order, and want how to get them.

How does np.argmax(axis=0) work on 3D arrays?

I am stuck at, as to how does np.argmax(arr, axis=0) work? I know how np.argmax(axis=0) works on 2D arrays. But this 3D one has really confused me.
My Code:
arr = np.array([[[ 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]]])
Operation:
np.argmax(arr, axis = 0)
Output:
array([[2, 2, 2],
[2, 2, 2],
[2, 2, 2],
[2, 2, 2]], dtype=int64)
FYI - I do know how np.argmax(axis=0) works on 2D arrays. But this 3D one has really confused me.
You need to understand better what is axis=0 here. It can be interpreted as height level of rectangle. So your output shows different levels of that rectangle:
level 0 level 1 level 2
[ 1, 2, 3] [13, 14, 15] [16, 17, 18]
[ 4, 5, 6] [16, 17, 18] [19, 20, 21]
[ 7, 8, 9] [19, 20, 21] [22, 23, 24]
[10, 11, 12] [22, 23, 24] [25, 16, 27]
Then argmax describes indices of levels at which max values are attained. They are:
[16, 17, 18]
[19, 20, 21]
[22, 23, 24]
[25, 16, 27]
It's definitely the upmost level (number 2) for any of these cells
so argmax of every cell is assigned to 2.

Deleting numpy array elements from a 3d numpy array with given array of indices

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]]]

How to transpose a 3D matrix?

I have a 3D matrix x_test of size (100, 33, 66) and I want to change its dimensions to (100, 66, 33).
What is the most efficient way to do this using python3.5? I look for something along those lines:
y = x_test.transpose()
You can pass the desired dimensions to the function np.transpose using in your case np.transpose(x_test, (0, 2, 1)).
For example,
import numpy as np
x_test = np.arange(30).reshape(3, 2, 5)
print(x_test)
print(x_test.shape)
This will print
[[[ 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]]]
(3, 2, 5)
Now, you can transpose the matrix with the command from above
y = np.transpose(x_test, (0, 2, 1))
print(y)
print(y.shape)
which will give
[[[ 0 5]
[ 1 6]
[ 2 7]
[ 3 8]
[ 4 9]]
[[10 15]
[11 16]
[12 17]
[13 18]
[14 19]]
[[20 25]
[21 26]
[22 27]
[23 28]
[24 29]]]
(3, 5, 2)
Apart from transpose (see #Cleb's answer) there are also swapaxes and moveaxis:
import numpy as np
mock = np.arange(30).reshape(2,3,5)
mock.swapaxes(1,2)
# array([[[ 0, 5, 10],
[ 1, 6, 11],
[ 2, 7, 12],
[ 3, 8, 13],
[ 4, 9, 14]],
[[15, 20, 25],
[16, 21, 26],
[17, 22, 27],
[18, 23, 28],
[19, 24, 29]]])
np.moveaxis(mock,2,1)
# array([[[ 0, 5, 10],
[ 1, 6, 11],
[ 2, 7, 12],
[ 3, 8, 13],
[ 4, 9, 14]],
[[15, 20, 25],
[16, 21, 26],
[17, 22, 27],
[18, 23, 28],
[19, 24, 29]]])
np.rot90 is another option. I confess I do not yet understand the axes = (a, b) notation and sort through all combinations from (0, 1) to (2, 1) to find what I want. Using x_test above, note its original shape (3, 2 ,5):
x2 = np.rot90(x_test, axes = (0, 1))
array([[[ 5, 6, 7, 8, 9],
[15, 16, 17, 18, 19],
[25, 26, 27, 28, 29]],
[[ 0, 1, 2, 3, 4],
[10, 11, 12, 13, 14],
[20, 21, 22, 23, 24]]])
x2.shape
(2, 3, 5)

How does numpy.swapaxes work?

I created a sample array:
a = np.arange(18).reshape(9,2)
On printing, I get this as output:
[[ 0 1]
[ 2 3]
[ 4 5]
[ 6 7]
[ 8 9]
[10 11]
[12 13]
[14 15]
[16 17]]
On executing this reshaping:
b = a.reshape(2,3,3).swapaxes(0,2)
I get:
[[[ 0 9]
[ 3 12]
[ 6 15]]
[[ 1 10]
[ 4 13]
[ 7 16]]
[[ 2 11]
[ 5 14]
[ 8 17]]]
I went through this question, but it does not solve my problem.
Reshape an array in NumPy
The documentation is not useful either.
https://docs.scipy.org/doc/numpy/reference/generated/numpy.swapaxes.html
I need to know how the swapping is working(which is x-axis, y-axis, z-axis). A diagrammatic explanation would be most helpful.
Here is my understanding of swapaxes
Suppose you have an array
In [1]: arr = np.arange(16).reshape((2, 2, 4))
In [2]: arr
Out[2]:
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]],
[[ 8, 9, 10, 11],
[12, 13, 14, 15]]])
And the shape of arr is (2, 2, 4), for the value 7, you can get the value by
In [3]: arr[0, 1, 3]
Out[3]: 7
There are 3 axes 0, 1 and 2, now, we swap axis 0 and 2
In [4]: arr_swap = arr.swapaxes(0, 2)
In [5]: arr_swap
Out[5]:
array([[[ 0, 8],
[ 4, 12]],
[[ 1, 9],
[ 5, 13]],
[[ 2, 10],
[ 6, 14]],
[[ 3, 11],
[ 7, 15]]])
And as you can guess, the index of 7 is (3, 1, 0), with axis 1 unchanged,
In [6]: arr_swap[3, 1, 0]
Out[6]: 7
So, now from the perspective of the index, swapping axis is just change the index of values. For example
In [7]: arr[0, 0, 1]
Out[7]: 1
In [8]: arr_swap[1, 0, 0]
Out[8]: 1
In [9]: arr[0, 1, 2]
Out[9]: 6
In [9]: arr_swap[2, 1, 0]
Out[9]: 6
So, if you feel difficult to get the swapped-axis array, just change the index, say arr_swap[2, 1, 0] = arr[0, 1, 2].
Start with the reshape
In [322]: a = np.arange(18).reshape(2,3,3)
In [323]: a
Out[323]:
array([[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[ 9, 10, 11],
[12, 13, 14],
[15, 16, 17]]])
This displays as 2 planes, and each plane is a 3x3. Is that part clear? The fact that the array was shaped (9,2) at one point isn't significant. Reshaping doesn't change the order of elements.
Apply the swapaxes. Shape is now (3,3,2). 3 planes, each is 3x2. This particular swap is the same as a transpose
np.arange(18).reshape(2,3,3).transpose(2,1,0)
The middle axis is unchanged. There are still columns of [0,3,6], [9,12,15], etc.
It may be easier to visualize the change with 3 different sized axes
In [335]: a=np.arange(2*3*4).reshape(2,3,4)
In [336]: a
Out[336]:
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]]])
In [337]: a.swapaxes(0,2)
Out[337]:
array([[[ 0, 12],
[ 4, 16],
[ 8, 20]],
[[ 1, 13],
[ 5, 17],
[ 9, 21]],
[[ 2, 14],
[ 6, 18],
[10, 22]],
[[ 3, 15],
[ 7, 19],
[11, 23]]])
Notice what happens when I flatten the array
In [338]: a.swapaxes(0,2).ravel()
Out[338]:
array([ 0, 12, 4, 16, 8, 20, 1, 13, 5, 17, 9, 21, 2, 14, 6, 18, 10,
22, 3, 15, 7, 19, 11, 23])
the order of terms has been shuffled. As created it was [0,1,2,3...]. Now the 1 is the 6th term (2x3).
Under the covers numpy actually performs the swap or transpose by changing shape, strides and order, without changing the data buffer (i.e. it's a view). But further reshaping, including raveling, forces it to make a copy. But that might be more confusing than helpful at this stage.
In numpy axes are numbered. Terms like x,y,z or planes, rows, columns may help you map those on to constructs that you can visualize, but they aren't 'built-in'. Describing the swap or transpose in words is tricky.

Categories