0

I want to update an np.array based on some indices.

a = np.array([[1,2,3],[4,5,6],[7,8,9]])
b = np.array([1,2])
a[b, :][:, b] += 1

Afterwards, a is unchanged, since just a copy got modified. How can I modify the original object?

marc
  • 6,103
  • 1
  • 28
  • 33
  • 1
    The problem is that `a[b,:]` is a copy. The `[:,b]+=...` is modifying that copy, not the original `a`. – hpaulj Jan 20 '18 at 06:22

3 Answers3

2

Create an open mesh grid with numpy.ix_ and use it for the index. Using ix_ takes advantage of broadcasting, it saves space because it doesn't need to create the full complement of indices.

>>> import numpy as np
>>> np.ix_(b,b)
(array([[1],
       [2]]), array([[1, 2]]))
>>>
>>> a[np.ix_(b,b)] += 10
>>> a
array([[ 0,  1,  2],
       [ 3, 14, 15],
       [ 6, 17, 18]])
>>>

Using ix_ is preferable for this use case but numpy.meshgrid could also be used. It has the disadvantage of creating a larger set of indices.

>>> np.meshgrid(b,b)
[array([[1, 2],
       [1, 2]]), array([[1, 1],
       [2, 2]])]

>>> a[np.meshgrid(b,b)] *= -1
>>> a
array([[  0,   1,   2],
       [  3, -14, -15],
       [  6, -17, -18]])
>>>

Numpy's meshgrid is more typically used as descibed in What is purpose of meshgrid in Python? and Meshgrids and disambiguating rows and columns from Cartesian coordinates

wwii
  • 23,232
  • 7
  • 37
  • 77
0

First select rows using array b and restrict the columns from position 1 to extract the square on the lower right corner.

>>> a
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])   

# select the square on the lower right corner and increment it
>>> a[b, 1:] += 1
>>> a
array([[ 1,  2,  3],
       [ 4,  6,  7],
       [ 7,  9, 10]])

Alternatively, you can also use this:

>>> a[b, b[0]:] += 1
>>> a
array([[ 1,  2,  3],
       [ 4,  6,  7],
       [ 7,  9, 10]])
kmario23
  • 57,311
  • 13
  • 161
  • 150
  • This will increment the lower two rows, not the square to the lower right. Expected output is array([[ 1, 2, 3],[ 4, 6, 7],[ 7, 9, 10]]) – marc Jan 20 '18 at 06:11
  • This works for the particular ``b`` array in the question, but won't generalize to arbitrary ``b`` arrays. For this particular case, you could use ``b[1:,1:] += 1``, but I don't think that's what the question is asking. – jakevdp Jan 20 '18 at 06:24
  • @jakevdp I think you meant `a[1:, 1:] += 1` but that's equivalent to `a[b, 1:] += 1` ;) – kmario23 Jan 20 '18 at 06:29
  • 1
    You're right, I meant to say ``a[1:, 1:]``. My larger point is that solving a specific simplified example in a way that doesn't answer the more general question being asked is not particularly helpful. – jakevdp Jan 20 '18 at 15:07
0

You need to do the indexing in one step. For what you're trying to do, this will work:

a[b[:, np.newaxis], b] += 1
print(a)
# array([[ 1,  2,  3],
#        [ 4,  6,  7],
#        [ 7,  9, 10]])

When you index an array with multiple lists of indices, those lists are broadcast together to index into the array. So if you have a 2x1 index and a 1x2 index, the resulting array slice is 2x2, and in this case references the 2x2 section of the array you were hoping to modify.

jakevdp
  • 77,104
  • 11
  • 125
  • 160