Sum of all slices along given axis of a numpy array - python

I have a numpy array of shape (3,12,7,5). I would like to have the sum of all slices along the first axis of this array.
data = np.random.randint(low=0, high=8000, size=3*12*7*5).reshape(3,12,7,5)
data[0,...].sum()
data[1,...].sum()
data[2,...].sum()
np.array((data[0,...].sum(), data[1,...].sum(), data[2,...].sum()))
First, I thought this should be possible using np.sum(data, axis=...) but it is not.
How do I perform this calculation in a single shot. What is the numpy magic?

For a generic ndarray, you could reshape into a 2D array, keeping the number of elements along the first axis same and merging all of the remaining axes as the second axis and finally sum along that axis, like so -
data.reshape(data.shape[0],-1).sum(axis=1)
For a 4D array, you could include the axes along which the summation is to be performed. So, to solve our case, we would have -
data.sum(axis=(1,2,3))
This could be extended to make it work for generic ndarrays by creating a tuple of appropriate axis IDs and thus avoid reshaping, like so -
data.sum(axis=tuple(np.arange(1,data.ndim)))

Related

Summing 3d numpy array over plane, not axis

I have a 3d numpy array (nx5x5). I want to sum each of the n slices together. So the new shape will be (nx1x1), where each n is just the sum of an individual 5x5 array. Can I do this in numpy without using a loop? np.sum has its axis arguments, but they reshape the array into the wrong shape. I think I may need to call np.sum twice? But I'm having trouble thinking about how to do this. Anybody know the answer?
Here are three different ways of doing it:
Use a tuple for axis:
a.sum(axis=(1, 2))
Reshape properly to merge the axes you want to sum over:
a.reshape(a.shape[0], -1).sum(axis=1)
Use multiple sums:
a.sum(-1).sum(-1)
OR
a.sum(1).sum(-1)
etc.
np.sum has its axis arguments, but they reshape the array into the wrong shape
Summing is a reduction operation and it makes sense that after reducing in a specific axis (by summing all elements in that axis) that particular dimension is removed. If you don't want that you can pass the optional keepdims argument.
values = np.random.randn(3,5,5)
values.sum(axis=(1,2), keepdims=True)
Think I figured this out, for anyone who is running into the same issue. It turns out you can select two axes from np.sum, making a plane instead of a line. So:
np.sum(a, (1,2)
Does the trick.

1D plots from 3D array

I have a 3D data cube and I am trying to make a plot of the first axis at a specific value of the other two axes. The goal is to make a velocity plot at given coordinates in the sky.
I have tried to create an 1D array from the 3D array by putting in my values for the last two axes. This is what I have tried
achan=50
dchan = 200
lmcdata[:][achan][dchan] #this array has three axes, vchan, achan, dchan.
I am expecting an array of size 120 as there are 120 velocity channels that make up the vchan axis. When trying the code above I keep getting an array of size 655 which is the number of entries for the dchan axis.
Python slicing works from left to right. In this case, lmcdata[:] is returning the whole lmcdata list. So, lmcdata[:][achan][dchan] is equivalent to just lmcdata[achan][dchan].
For higher level indexing and slicing tasks like this, I highly recommend the numpy package. You will be able to slice lmcdata as expected after turning it into a numpy array: lmcdata = np.asarray(lmcdata).

Transpose a 1-dimensional array in Numpy without casting to matrix

My goal is to to turn a row vector into a column vector and vice versa. The documentation for numpy.ndarray.transpose says:
For a 1-D array, this has no effect. (To change between column and row vectors, first cast the 1-D array into a matrix object.)
However, when I try this:
my_array = np.array([1,2,3])
my_array_T = np.transpose(np.matrix(myArray))
I do get the wanted result, albeit in matrix form (matrix([[66],[640],[44]])), but I also get this warning:
PendingDeprecationWarning: the matrix subclass is not the recommended way to represent matrices or deal with linear algebra (see https://docs.scipy.org/doc/numpy/user/numpy-for-matlab-users.html). Please adjust your code to use regular ndarray.
my_array_T = np.transpose(np.matrix(my_array))
How can I properly transpose an ndarray then?
A 1D array is itself once transposed, contrary to Matlab where a 1D array doesn't exist and is at least 2D.
What you want is to reshape it:
my_array.reshape(-1, 1)
Or:
my_array.reshape(1, -1)
Depending on what kind of vector you want (column or row vector).
The -1 is a broadcast-like, using all possible elements, and the 1 creates the second required dimension.
If your array is my_array and you want to convert it to a column vector you can do:
my_array.reshape(-1, 1)
For a row vector you can use
my_array.reshape(1, -1)
Both of these can also be transposed and that would work as expected.
IIUC, use reshape
my_array.reshape(my_array.size, -1)

Seamlessly and efficiently flipping numpy array or sparse matrix along all axes

Let's say we have a matrix (numpy array) of unknown shape, the shape can be for example (1,5) (row), (5,1) (column), (5,5) (square), (5,6) (non-square) or (5,) (degenerated) (ok the last case isn't a matrix but is a valid input).
I would like to given a matrix of any shape (column, row, square, nonsquare, degenerated). I will return a flipped up/down left/right version of it.
Since np.flip has some issues with 1d arrays. My approach was:
def flipit(M):
return M.ravel()[::-1].reshape(M.shape)
It works, but is that acceptable? Any faster ways to do it?
In the other hand, how can I do the same for sparse matrices (for example if M is scipy.sparse.csr_matrix).
We can use slice notation with a step-size of -1 for the number of dims in the input to flip along all the axes, as that's what the original code is essentially doing. This would cover both arrays and sparse matrices -
def flip_allaxes(a): # a can be array or sparse matrix
# generate flipping slice
sl = slice(None,None,-1) # or np.s_[::-1] suggested by #kmario23
return a[tuple([sl]*a.ndim)]
Simplified on newer NumPy versions (15.1 onwards)
On newer NumPy versions : Version 15.1 and newer, that allows us to specify tuple of ints for the axes along which the flipping is needed. For the default case with axis=None from the docs, it flips along all axes. Thus, to solve our case, it would be simply np.flip(a) and this would again cover both generic ndarrays and sparse matrices.

Concatenating numpy arrays of different shapes

I have several N-dimensional arrays of different shapes and want to combine them into a new (N+1)-dimensional array, where the new axis has a length corresponding to the number of initial N-d arrays.
This answer is sufficient if the original arrays are all the same shape; however, it does not work if they have different shapes.
I don't really want to reshape the arrays to a congruent size and fill with empty elements due to the subsequent analysis I need to perform on the final array.
Specifically, I have four 4D arrays. One of the things I want to do with the resulting 5D array is plot parts of the four arrays on the same matplotlib figure. Obviously I could plot each one separately, however soon I will have more than four 4D arrays and am looking for a dynamic solution.
While I was writing this, Sven gave the same answer in the comments...
Put the arrays in a python list in the following manner:
5d_list = []
5d_list.append(4D_array_1)
5d_list.append(4D_array_2)
...
Then you can unpack them:
for 4d_array in 5d_list:
#plot 4d array on figure

Categories