Reshape an array in NumPy - python

Consider an array of the following form (just an example):
[[ 0 1]
[ 2 3]
[ 4 5]
[ 6 7]
[ 8 9]
[10 11]
[12 13]
[14 15]
[16 17]]
It's shape is [9,2]. Now I want to transform the array so that each column becomes a shape [3,3], like this:
[[ 0 6 12]
[ 2 8 14]
[ 4 10 16]]
[[ 1 7 13]
[ 3 9 15]
[ 5 11 17]]
The most obvious (and surely "non-pythonic") solution is to initialise an array of zeroes with the proper dimension and run two for-loops where it will be filled with data. I'm interested in a solution that is language-conform...

a = np.arange(18).reshape(9,2)
b = a.reshape(3,3,2).swapaxes(0,2)
# a:
array([[ 0, 1],
[ 2, 3],
[ 4, 5],
[ 6, 7],
[ 8, 9],
[10, 11],
[12, 13],
[14, 15],
[16, 17]])
# b:
array([[[ 0, 6, 12],
[ 2, 8, 14],
[ 4, 10, 16]],
[[ 1, 7, 13],
[ 3, 9, 15],
[ 5, 11, 17]]])

numpy has a great tool for this task ("numpy.reshape") link to reshape documentation
a = [[ 0 1]
[ 2 3]
[ 4 5]
[ 6 7]
[ 8 9]
[10 11]
[12 13]
[14 15]
[16 17]]
`numpy.reshape(a,(3,3))`
you can also use the "-1" trick
`a = a.reshape(-1,3)`
the "-1" is a wild card that will let the numpy algorithm decide on the number to input when the second dimension is 3
so yes.. this would also work:
a = a.reshape(3,-1)
and this:
a = a.reshape(-1,2)
would do nothing
and this:
a = a.reshape(-1,9)
would change the shape to (2,9)

There are two possible result rearrangements (following example by #eumiro). Einops package provides a powerful notation to describe such operations non-ambigously
>> a = np.arange(18).reshape(9,2)
# this version corresponds to eumiro's answer
>> einops.rearrange(a, '(x y) z -> z y x', x=3)
array([[[ 0, 6, 12],
[ 2, 8, 14],
[ 4, 10, 16]],
[[ 1, 7, 13],
[ 3, 9, 15],
[ 5, 11, 17]]])
# this has the same shape, but order of elements is different (note that each paer was trasnposed)
>> einops.rearrange(a, '(x y) z -> z x y', x=3)
array([[[ 0, 2, 4],
[ 6, 8, 10],
[12, 14, 16]],
[[ 1, 3, 5],
[ 7, 9, 11],
[13, 15, 17]]])

Related

Change numpy array element position in python

Supposed that I have an array like matrix using numpy like this.
import numpy as np
a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16], [17, 18, 19, 20]])
I want to change the [13, 14, 15, 16] into the first position so it will become something like this
array([[ 13, 14, 15, 16],
[ 1, 2, 3, 4 ],
[ 5, 6, 7, 8 ],
[ 9, 10, 11, 12 ],
[ 17, 18, 19, 20])
how can I do it? thanks
You can re-arrange the array with the row indices:
import numpy as np
a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16], [17, 18, 19, 20]])
b = a[[3,0,1,2,4],:]
print(b)
The output is:
[[13 14 15 16]
[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]
[17 18 19 20]]
Use np.delete and np.concatenate:
b = np.concatenate([a[[-2]], np.delete(a, -2, axis=0)])
print(b)
# Output
[[13 14 15 16]
[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]
[17 18 19 20]]

efficiently reshaping 3D numpy array

assuming I have a 2D numpy array and want to reshape it with strides into 3D, what would be the best way to do that?
little example:
def find_ngrams(input_list, n):
return np.array(list(zip(*[input_list[i:] for i in range(n)])))
x = np.array(range(15))
x = x.reshape((5,3))
print(x)
print(x.shape)
res = find_ngrams(x, 3)
print(res.shape)
print(res)
This returns the expected result correctly:
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]
[12 13 14]]
(5, 3)
(3, 3, 3)
[[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]]
[[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
[[ 6 7 8]
[ 9 10 11]
[12 13 14]]]
However, how can I do this more efficiently, preferably using stride_tricks?
Here's how I would do it with as_strided:
window_length=3
strides = x.strides
new_len = (x.shape[0]-window_length+1)
out = as_strided(x,shape=(window_length, new_len, x.shape[1]),
strides=(strides[0],) + (strides[0], strides[1]))
Output:
array([[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]],
[[ 6, 7, 8],
[ 9, 10, 11],
[12, 13, 14]]])

A specific type of sorting in a 3d numpy array

In a 3d numpy array (with p panels, each with r rows and c columns) I'd like to sort only on columns of a specific panel, such that the corresponding elements on the other panels rearrange themselves accordingly.
Unfortunately, I am not familiar with the jargon of different types of sorting. I'll clarify what I need through an example.
Take A as a 2*3*4 array
A = array([[[ 9, 20, 30, 11],
[ 100, 4, -1, 90]
[ 40, 15, -5, 34]],
[[ 0, 2, 3, 9],
[ -1, 12, 6, -3]
[ 1, -5, 7, 2]]]),
After sort on the columns of the second panel:
A = array([[[ 100, 15, 30, 90],
[ 9, 20, -1, 34]
[ 40, 4, -5, 11]],
[[ -1, -5, 3, -3],
[ 0, 2, 6, 2]
[ 1, 12, 7, 9]]])
As you can see, only the columns of the second panel are sorted (ascendingly) and the elements in the first panel are rearranged (but not sorted!) with their corresponding elements in the second panel.
import numpy as np
A = np.array([[[ 9, 20, 30, 11],
[ 100, 4, -1, 90],
[ 40, 15, -5, 34]],
[[ 0, 2, 3, 9],
[ -1, 12, 6, -3],
[ 1, -5, 7, 2]]])
I, J, K = np.ogrid[tuple(map(slice, A.shape))]
# I, J, K are the identity indices in the sense that (A == A[I, J, K]).all()
newJ = np.argsort(A[1], axis=0) # first axis of A[1] is second axis of A
print(A[I, newJ, K])
yields
[[[100 15 30 90]
[ 9 20 -1 34]
[ 40 4 -5 11]]
[[ -1 -5 3 -3]
[ 0 2 6 2]
[ 1 12 7 9]]]

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.

Numpy: how to return a view on a matrix A based on submatrix B

Given a matrix A with dimensions axa, and B with dimensions bxb, and axa modulo bxb == 0. B is a submatrix(s) of A starting at (0,0) and tiled until the dimensions of axa is met.
A = array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
An example of a submatrix might be:
B = array([[10, 11],
[14, 15]])
Where the number 15 is in position (1, 1) with respect to B's coordinates.
How could I return a view on the array A, for a particular position in B? For example for position (1,1) in B, I want to get all such values from A:
C = array([[5, 7],
[13, 15]])
The reason I want a view, is that I wish to update multiple positions in A:
C = array([[5, 7],[13, 15]]) = 20
results in
A = array([[ 0, 1, 2, 3],
[ 4, 20, 6, 20],
[ 8, 9, 10, 11],
[12, 20, 14, 20]])
You can obtain this as follows:
>>> A = np.array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
>>> A[np.ix_([1,3],[1,3])] = 20
>>> A
array([[ 0, 1, 2, 3],
[ 4, 20, 6, 20],
[ 8, 9, 10, 11],
[12, 20, 14, 20]])
For more info about np.ix_ could review the NumPy documentation

Categories