Transposing a 3-d numpy array - python

Suppose I have a numpy array A with shape (5,24,1).
I want to take five separate transposes along axis = 0, such that the resulting shape after transposes is (5,1,24).
How can I do this using some of the numpy functions?

Three approaches could be suggested -
A.swapaxes(1,2)
A.transpose(0,2,1)
np.rollaxis(A,2,1)
For swapaxes and transpose, please follow their docs.
With np.rollaxis, we are rolling the axes to bring the third axis into the second position and thus pushing back the second axis into third axis position. More info in the linked docs.
Using the fact that the last axis is singleton -
A[:,None,:,0]

You could use np.moveaxis (one option missing from Divakars excellent answer) where you can define which axis should be moved:
np.moveaxis(A, (0, 1, 2), (0, 2, 1))
This moves axis 0 to 0 (no change, could also be omitted), 1 to 2 and 2 to 1. So this basically just swaps axis 1 and 2.
>>> A = np.ones((5,24,1))
>>> res = np.moveaxis(A, (1, 2), (2, 1)) # this time without the zeros
>>> res.shape
(5, 1, 24)

Related

How I can add one floor, one row and one extra columns ´to my existing array containing data

I want to add one floor, one row and one columns into my existing 3-D matrix without losing the original information from the matrix
import numpy as np
tensor = np.zeros((len(subjects), len(properties) , len(objects)))
#subjects are 4, properties are 5 and objects are 7 in my case.
print(tensor.shape)
(4, 5, 7)
so I need to add one on more floor, row and columns, so it will give me the following output
so it will give me
print(tensor.shape)
(5,6,8)
numpy.pad is your friend.
>>> tensor = np.pad(tensor, (0,1), 'constant')
>>> tensor.shape
(5,6,8)
Numpy's insert function should help you here. Using the axis parameter helps to change which dimension/axis you are inserting into.
print(np.insert(tensor, 0, 0, axis=0).shape)
(5,5,7)
print(np.insert(tensor, 0, 0, axis=1).shape)
(4,6,7)
print(np.insert(tensor, 0, 0, axis=2).shape)
(4,5,8)
So if you need to do these inserts one at a time, this could be your best bet.
In each insert a column or row or height is added:
tensor = np.zeros((4, 5 , 6))
tensor=np.insert(tensor,[4],tensor[1,:,:],axis=0)
tensor=np.insert(tensor,[5],tensor[1,1,:],axis=1)
tensor=np.insert(tensor,[6],[0],axis=2)
print(tensor.shape)
Output: (5, 6, 7)

Iterating over 3D numpy using one dimension as iterator remaining dimensions in the loop

Despite there being a number of similar questions related to iterating over a 3D array and after trying out some functions like nditer of numpy, I am still confused on how the following can be achieved:
I have a signal of dimensions (30, 11, 300) which is 30 trials of 11 signals containing 300 signal points.
Let this signal be denoted by the variable x_
I have another function which takes as input a (11, 300) matrix and plots it on 1 graph (11 signals containing 300 signal points plotted on a single graph). Let this function be sliding_window_plot.
Currently, I can get it to do this:
x_plot = x_[0,:,:]
for i in range(x_.shape[0]):
sliding_window_plot(x_plot[:,:])
which plots THE SAME (first trial) 11 signals containing 300 points on 1 plot, 30 times.
I want it to plot the i'th set of signals. Not the first (0th) trial of signals everytime. Any hints on how to attempt this?
You should be able to iterate over the first dimension with a for loop:
for s in x_:
sliding_window_plot(s)
with each iteration s will be the next array of shape (11, 300).
In general for all nD-arrays where n>1, you can iterate over the very first dimension of the array as if you're iterating over any other iterable. For checking whether an array is an iterable, you can use np.iterable(arr). Here is an example:
In [9]: arr = np.arange(3 * 4 * 5).reshape(3, 4, 5)
In [10]: arr.shape
Out[10]: (3, 4, 5)
In [11]: np.iterable(arr)
Out[11]: True
In [12]: for a in arr:
...: print(a.shape)
...:
(4, 5)
(4, 5)
(4, 5)
So, in each iteration we get a matrix (of shape (4, 5)) as output. In total, 3 such outputs constitute the 3D array of shape (3, 4, 5)
If, for some reason, you want to iterate over other dimensions then you can use numpy.rollaxis to move the desired axis to the first position and then iterate over it as mentioned in iterating-over-arbitrary-dimension-of-numpy-array
NOTE: Having said that numpy.rollaxis is only maintained for backwards compatibility. So, it is recommended to use numpy.moveaxis instead for moving the desired axis to the first dimension.
You are hardcoding the 0th slice outside the for loop. You need to create x_plot to be inside the loop. In fact you can simplify your code by not using x_plot at all.
for i in rangge(x_.shape[0]):
sliding_window_plot(x_[i])

How to flatten an array to a matrix in Numpy?

I am looking for an elegant way to flatten an array of arbitrary shape to a matrix based on a single parameter that specifies the dimension to retain. For illustration, I would like
def my_func(input, dim):
# code to compute output
return output
Given for example an input array of shape 2x3x4, output should be for dim=0 an array of shape 12x2; for dim=1 an array of shape 8x3; for dim=2 an array of shape 6x8. If I want to flatten the last dimension only, then this is easily accomplished by
input.reshape(-1, input.shape[-1])
But I would like to add the functionality of adding dim (elegantly, without going through all possible cases + checking with if conditions, etc.). It might be possible by first swapping dimensions, so that the dimension of interest is trailing and then applying the operation above.
Any help?
We can permute axes and reshape -
# a is input array; axis is input axis/dim
np.moveaxis(a,axis,-1).reshape(-1,a.shape[axis])
Functionally, it's basically pushing the specified axis to the back and then reshaping keeping that axis length to form the second axis and merging rest of the axes to form the first axis.
Sample runs -
In [32]: a = np.random.rand(2,3,4)
In [33]: axis = 0
In [34]: np.moveaxis(a,axis,-1).reshape(-1,a.shape[axis]).shape
Out[34]: (12, 2)
In [35]: axis = 1
In [36]: np.moveaxis(a,axis,-1).reshape(-1,a.shape[axis]).shape
Out[36]: (8, 3)
In [37]: axis = 2
In [38]: np.moveaxis(a,axis,-1).reshape(-1,a.shape[axis]).shape
Out[38]: (6, 4)

keeping track of indices change in numpy.reshape

While using numpy.reshape in Python, is there a way to keep track of the change in indices?
For example, if a numpy array with the shape (m,n,l,k) is reshaped into an array with the shape (m*n,k*l); is there a way to get the initial index ([x,y,w,z]) for the current [X,Y] index and vice versa?
Yes there is, it's called raveling and unraveling the index. For example you have two arrays:
import numpy as np
arr1 = np.arange(10000).reshape(20, 10, 50)
arr2 = arr.reshape(20, 500)
say you want to index the (10, 52) (equivalent to arr2[10, 52]) element but in arr1:
>>> np.unravel_index(np.ravel_multi_index((10, 52), arr2.shape), arr1.shape)
(10, 1, 2)
or in the other direction:
>>> np.unravel_index(np.ravel_multi_index((10, 1, 2), arr1.shape), arr2.shape)
(10, 52)
You don't keep track of it, but you can calculate it. The original m x n is mapped onto the new m*n dimension, e.g. n*x+y == X. But we can verify with a couple of multidimensional ravel/unravel functions (as answered by #MSeifert).
In [671]: m,n,l,k=2,3,4,5
In [672]: np.ravel_multi_index((1,2,3,4), (m,n,l,k))
Out[672]: 119
In [673]: np.unravel_index(52, (m*n,l*k))
Out[673]: (2, 12)

clear authoritative explanation of numpy axis numbers?

I am getting confused by contradictory explanations of what exactly the term axis means in numpy and how these constructs are numbered.
Here's one explanation:
Axes are defined for arrays with more than one dimension.
A 2-dimensional array has two corresponding axes:
the first running vertically downwards across rows (axis 0), and
the second running horizontally across columns (axis 1).
So, in this 3x4 matrix ...
>>> b = np.arange(12).reshape(3,4)
>>> b
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
(axis 0) is the 3 rows
(axis 1) is the 4 columns
So the rule might be ...
In an MxN matrix, (axis 0) is M and (axis 1) is N.
Is this correct?
So, in a 3 dimensional matrix AxBxC
(axis 0) is A
(axis 1) is B
(axis 2) is C
Is this correct?
Everything you said is correct, with the exception of
Axes are defined for arrays with more than one dimension.
Axes are also defined for one dimensional arrays - there is just one of them (i.e. axis 0).
One intuitive way to think about axes is to consider what happens when you apply a reduction operation over one axis, such as summation. For example, suppose I have some array x:
x = np.arange(60).reshape(3, 4, 5)
If I compute x.sum(0) I am "collapsing" x over the first dimension (i.e. axis 0), so I end up with a (4, 5) array. Likewise, x.sum(1) gives me a (3, 5) array and x.sum(2) gives me a (3, 4) array.
An integer index into a single axis of x will also give me an output with one fewer axis. For example, x[0, :, :] gives me the first "row" of x, which has shape (4, 5), x[:, 0, :] gives me the first "column" with shape (3, 5), and x[:, :, 0] gives me the first slice in the third dimension of x with shape (3, 4).
If someone need a clear idea, here is the picture:
A smart way to remember this is that
axis =0 collapses the rows
Whilst
axis=1 collapses the columns
a three 3*4 array when operated upon with sum function and axis =0 would yield 1*4 output that is all the rows would be collapsed and the aggregation would be done column-wise.
The same function when performed with axis=1 would collapse the columns and yield 3*1 output with aggregation along rows.
the image link would further help assimilating this concept.
Example for understanding
Although it is possible to imagine this in 3D, I personally feel it is difficult to imagine when we go to 4D or 5D... So I decide to give up but rather think about this in an implementation perspective. Basically, it has N-number of nested for loop, and if we want to reduce one specific axis, we just work on the for loop of that axis. For example, if given a 3x3x3 tensor, axis = 0 is the for loop of a[i][x][x], axis = 1 is to loop a[x][i][x], axis = 2 is to loop a[x][x][i]. 4D, 5D, ... should have the same way.
def my_reduce_max(a, axis=0):
b = [[-1 for _ in range(3)] for _ in range(3)]
for j in range(3):
for k in range(3):
tmp_max = -1
for i in range(3):
if axis == 0:
get_value = a[i][j][k]
elif axis == 1:
get_value = a[j][i][k]
else:
get_value = a[j][k][i]
tmp_max = max(get_value, tmp_max)
b[j][k] = tmp_max
return b
a = np.arange(27).reshape((3,3,3))
print(a)
my_reduce_max(a, 2)

Categories

Resources