Home > Mobile >  Numpy array add inplace, values not summed when select same row multiple times
Numpy array add inplace, values not summed when select same row multiple times

Time:04-03

suppose I have a 2x2 matrix, I want to select a few rows and add inplace with another array of the correct shape. The problem is, when a row is selected multiple times, the values from another array is not summed:

Example: I have a 2x2 matrix:

>>> import numpy as np
>>> x = np.arange(15).reshape((5,3))
>>> print(x)
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]
 [12 13 14]] 

I want to select a few rows, and add values:

>>> x[np.array([[1,1],[2,3]])] # row 1 is selected twice
[[[ 3  4  5]
  [ 3  4  5]]

 [[ 6  7  8]
  [ 9 10 11]]]
>>> add_value = np.random.randint(0,10,(2,2,3))
[[[6 1 2]   # add to row 1
  [9 8 5]]  # add to row 1 again!

 [[5 0 5]   # add to row 2
  [1 9 3]]] # add to row 3
>>> x[np.array([[1,1],[2,3]])]  = add_value
>>> print(x)
[[ 0  1  2]
 [12 12 10] # [12,12,10]=[3,4,5] [9,8,5]
 [11  7 13]
 [10 19 14]
 [12 13 14]]

as above, the first row is [12,12,10], which means [9,8,5] and [6,1,2] is not summed when added onto the first row. Are there any solutions? Thanks!

CodePudding user response:

This behavior is described in the numpy documentation, near the bottom of this page, under "assigning values to indexed arrays":

https://numpy.org/doc/stable/user/basics.indexing.html#basics-indexing

Quoting:

Unlike some of the references (such as array and mask indices) assignments are always made to the original data in the array (indeed, nothing else would make sense!). Note though, that some actions may not work as one may naively expect. This particular example is often surprising to people:

>>> x = np.arange(0, 50, 10)
>>> x
array([ 0, 10, 20, 30, 40])
>>> x[np.array([1, 1, 3, 1])]  = 1
>>> x
array([ 0, 11, 20, 31, 40])

Where people expect that the 1st location will be incremented by 3. In fact, it will only be incremented by 1. The reason is that a new array is extracted from the original (as a temporary) containing the values at 1, 1, 3, 1, then the value 1 is added to the temporary, and then the temporary is assigned back to the original array. Thus the value of the array at x[1] 1 is assigned to x[1] three times, rather than being incremented 3 times.

CodePudding user response:

Just wanna share what @hpaulj suggests that uses np.add.at:

>>> import numpy as np
>>> x = np.arange(15).reshape((5,3))
>>> select = np.array([[1,1],[2,3]])
>>> add_value = np.array([[[6,1,2],[9,8,5]],[[5,0,5],[1,9,3]]])
>>> np.add.at(x, select.flatten(), add_value.reshape(-1, add_value.shape[-1]))
[[ 0  1  2]
 [18 13 12]
 [11  7 13]
 [10 19 14]
 [12 13 14]]

Now the first row is [18,13,12] which is the sum of [3,4,5], [6,1,2] and [9,8,5]

  • Related