0

Using the advanced indexing in numpy it is possible to

  1. Return the same location twice, and
  2. Use the indexed array as a target for assignment.

What I'd like to achieve, is that when I assign values to the same location twice, the values are added instead of the second overwriting the first.

Let me explain this by a code. Let's start with a simple example:

import numpy as np
a = np.array([0, 0])
b = np.array([1, 2])
a[[1, 0]] = b
a
>>> array([2, 1])

This is "regular" fancy indexing: into location 1 of 'a' I copy the location 0 of 'b', into location 0 of 'a' I copy location 1 of 'b'

If I do this:

a = np.array([0, 0])
a[[1, 1]] = b
a

I get this:

>>> array([0, 2])

Into location 1 of 'a' I first copy location 0 of 'b', then I overwrite location 1 of 'a' with location 2 of 'b'. I don't touch location 0 of 'a'.

Instead what I would like to get is this:

>>> array([0, 3])

That is instead of overwriting location 1 of 'a', I would like the value to be added. Is there a numpyic way for this?

g.a
  • 318
  • 2
  • 10
  • 3
    I think ```np.add.at(a, [1,1], b)``` will do this operation. It performs the operation unbuffered, so duplicate indices are being accumulated. – Kevin May 07 '21 at 20:28
  • In your case this is the same as doing ```np.bincount([1,1], b)```. Using ```bincount``` is faster but it assumes that ```a``` is filled with zeros (it is independent of values in ```a```) – Kevin May 07 '21 at 20:36
  • Hi @Kevin, actually my arrays are multidimensional (2+). So what I want is to do the summation of vectors/matrices. For this use case the bincount doesn't work, but the `at` works with this syntax: `np.add.at(a, (..., [1,1]), b)`. If you post your first comment as an answer, then I can accept it. – g.a May 12 '21 at 06:36

1 Answers1

1

Using np.add.at will perform the operation unbuffered and will therefore accumulate elements that are indexed more than once:

a = np.array([0, 0])
b = np.array([1, 2])
np.add.at(a, [1,1], b)

The np.add.at works as you would expect for multiple dimensions but if you want to use bincount the indices and b needs to be the same length. If b is being broadcasted this needs to be done manually and finally both operands needs to be flattened before calling bincount

a = np.array([0, 0])
b = np.array([1, 2])

idx = np.array([[0,0], [1,1]])
np.add.at(a, idx, b) 
# a = array([3, 3])

b = np.broadcast_to(b, idx.shape)
np.bincount(idx.ravel(), b.ravel())
# returns array([3., 3.])
Kevin
  • 3,096
  • 2
  • 8
  • 37