How to calculate the sum of all columns of a 2D numpy array (efficiently)

PythonNumpy

Python Problem Overview


Let's say I have the following 2D numpy array consisting of four rows and three columns:

>>> a = numpy.arange(12).reshape(4,3)
>>> print(a)
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]

What would be an efficient way to generate a 1D array that contains the sum of all columns (like [18, 22, 26])? Can this be done without having the need to loop through all columns?

Python Solutions


Solution 1 - Python

Check out the documentation for numpy.sum, paying particular attention to the axis parameter. To sum over columns:

>>> import numpy as np
>>> a = np.arange(12).reshape(4,3)
>>> a.sum(axis=0)
array([18, 22, 26])

Or, to sum over rows:

>>> a.sum(axis=1)
array([ 3, 12, 21, 30])

Other aggregate functions, like numpy.mean, numpy.cumsum and numpy.std, e.g., also take the axis parameter.

From the Tentative Numpy Tutorial:

> Many unary operations, such as computing the sum of all the elements > in the array, are implemented as methods of the ndarray class. By > default, these operations apply to the array as though it were a list > of numbers, regardless of its shape. However, by specifying the axis > parameter you can apply an operation along the specified axis of an > array:

Solution 2 - Python

Other alternatives for summing the columns are

numpy.einsum('ij->j', a)

and

numpy.dot(a.T, numpy.ones(a.shape[0]))

If the number of rows and columns is in the same order of magnitude, all of the possibilities are roughly equally fast:

enter image description here

If there are only a few columns, however, both the einsum and the dot solution significantly outperform numpy's sum (note the log-scale):

enter image description here


Code to reproduce the plots:

import numpy
import perfplot


def numpy_sum(a):
    return numpy.sum(a, axis=1)


def einsum(a):
    return numpy.einsum('ij->i', a)


def dot_ones(a):
    return numpy.dot(a, numpy.ones(a.shape[1]))


perfplot.save(
    "out1.png",
    # setup=lambda n: numpy.random.rand(n, n),
    setup=lambda n: numpy.random.rand(n, 3),
    n_range=[2**k for k in range(15)],
    kernels=[numpy_sum, einsum, dot_ones],
    logx=True,
    logy=True,
    xlabel='len(a)',
    )

Solution 3 - Python

Use the axis argument:

>> numpy.sum(a, axis=0)
  array([18, 22, 26])

Solution 4 - Python

Use numpy.sum. for your case, it is

sum = a.sum(axis=0)

Solution 5 - Python

Then NumPy sum function takes an optional axis argument that specifies along which axis you would like the sum performed:

>>> a = numpy.arange(12).reshape(4,3)
>>> a.sum(0)
array([18, 22, 26])

Or, equivalently:

>>> numpy.sum(a, 0)
array([18, 22, 26])

Solution 6 - Python

a.sum(0)

should solve the problem. It is a 2d np.array and you will get the sum of all column. axis=0 is the dimension that points downwards and axis=1 the one that points to the right.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPuggieView Question on Stackoverflow
Solution 1 - PythonJohn VinyardView Answer on Stackoverflow
Solution 2 - PythonNico SchlömerView Answer on Stackoverflow
Solution 3 - PythonBen AllisonView Answer on Stackoverflow
Solution 4 - PythonChunliang LyuView Answer on Stackoverflow
Solution 5 - PythonbogatronView Answer on Stackoverflow
Solution 6 - Pythonibozkurt79View Answer on Stackoverflow