usual me
usual me

Reputation: 8778

Pythonic way to update a single element of a numpy matrix?

Say I have a function call f(m1) where m1 is a numpy matrix. Now, I would like to call f on a matrix which is almost identical to m1:

m2 = m1.copy()
m2[ 2, 7 ] = 43 # or m2[ 2, 7 ] += 43
f(m2)

Is there an elegant f( ... ) one-liner to do that?

Upvotes: 1

Views: 2370

Answers (2)

askewchan
askewchan

Reputation: 46530

For pedagogy's sake, here is a functional way to do it. np.where actually does exactly what you want, but the tricky part is that it accepts a boolean condition, not an index:

f(np.where(condition, 43, m1))

which sends 43 to f wherever condition is met, elsewhere it just sends m1, so this would likely be simpler if we knew your criteria for choosing the element to change. As such, the trickiest part is creating the boolean array, which is a bit wasteful anyway.

np.where(np.all(np.indices(m1.shape) == np.array([2, 7])[:, None, None], 0), 43, m1)

or equivalently:

np.where(np.all(np.rollaxis(np.indices(m1.shape),0,3) == np.array([2, 7]), -1), 43, m1)

I could have sworn there was an equivalent function that took an index instead of a mask, but unfortunately it seems the similar functions (np.put, e.g.) that take indices modify the array in place, instead of returning a new one functionally. np.choose would also work but has the same issues of creating a "choice" array (as opposed to a condition mask array).

In action:

In [66]: m1 = np.zeros((4, 9))

In [67]: np.where(np.all(np.indices(m1.shape) == np.array([2, 7])[:,None, None], 0), 43, m1)
Out[67]: 
array([[  0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.],
       [  0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.],
       [  0.,   0.,   0.,   0.,   0.,   0.,   0.,  43.,   0.],
       [  0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.]])

In [68]: np.where(np.all(np.rollaxis(np.indices(m1.shape),0,3) == np.array([2, 7]), -1), 43, m1)
Out[68]: 
array([[  0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.],
       [  0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.],
       [  0.,   0.,   0.,   0.,   0.,   0.,   0.,  43.,   0.],
       [  0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.]])

Upvotes: 0

Arovit
Arovit

Reputation: 3699

In python, every assignment is a statement and not an expression so you cannot do -

f(m2[2,7] = 43)

or

if (a = 1+2)

I believe you can do

f( modify_matrix(m1) )

and define a separate method for modifying m1 matrix.

def modify_matrix(m1):
     m1[2,7] = 2
     return m1

But above options are more complex if all you need to do is just add one more line of modifying the matrix.

Upvotes: 1

Related Questions