26

If I have an ndarray of arbitrary shape and I would like to compute the sum along all but the last axis I can, for instance, achieve it by doing

all_but_last = tuple(range(arr.ndim - 1))
sum = arr.sum(axis=all_but_last)

Now, tuple(range(arr.ndim - 1)) is not exactly intuitive I feel. Is there a more elegant/numpy-esque way to do this?

Moreover, if I want to do this for multiple arrays of varying shape, I'll have to calculate a separate dimension tuple for each of them. Is there a more canonical way to say "regardless of what the dimensions are, just give me all but one axis"?

1
  • Intuitive or not, I think this makes the best use of the axis parameter. Hide it in a function, and noone will know the difference (and you can comment it). numpy functions play this sort of 'game' frequently. Commented Aug 6, 2018 at 16:51

2 Answers 2

32

You could reshape the array so that all axes except the last are flattened (e.g. shape (k, l, m, n) becomes (k*l*m, n)), and then sum over the first axis.

For example, here's your calculation:

In [170]: arr.shape
Out[170]: (2, 3, 4)

In [171]: arr.sum(axis=tuple(range(arr.ndim - 1)))
Out[171]: array([2.85994792, 2.8922732 , 2.29051163, 2.77275709])

Here's the alternative:

In [172]: arr.reshape(-1, arr.shape[-1]).sum(axis=0)
Out[172]: array([2.85994792, 2.8922732 , 2.29051163, 2.77275709])
Sign up to request clarification or add additional context in comments.

1 Comment

Is there a more generalizable method? I suppose you can do which was what I was looking for. sums = arr.sum(axis=tuple(x for x in range(arr.ndim) if x!= MY_AXIS)) Then sums.shape would just be (MY_AXIS,)
14

You can use np.apply_over_axes to sum over multiple axes.

np.apply_over_axes(np.sum, arr, [0,2]) #sum over axes 0 and 2

np.apply_over_axes(np.sum, arr, range(arr.ndim - 1)) #sum over all but last axis

5 Comments

Isn't this just doing the same thing? but in a slower way, iterating over the axes in Python code rather internally to sum?
@hpaulj I'm not sure what you mean as far as iterating over all axis in python code because all methods shown here are using range for the axis extrapolation
But look at the code for apply_over_axes - it iterates on the axes parameter. Timeit as well.
Even setting speed aside, what is the benefit of this over sum(axis=...)?
@hpaulj The above is hard to generalize to any axes, so for fast development, I used the slow running one.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.