views:

132

answers:

4

Hello everybody,

why do the following lines not work as I expect?

import numpy as np
a = np.array([0,1,2,1,1])
a[a==1][1:] = 3
print a
>>> [0 1 2 1 1]
# I would expect [0 1 2 3 3]

Is this a 'bug' or is there another recommended way to this?

On the other hand, the following works:

a[a==1] = 3
print a
>>> [0 3 2 3 3]

Cheers, Philipp

+4  A: 

Because the a[a==1] part isn't actually a slice. It creates a new array. It makes sense when you think about it-- you're only taking the elements that satisfy the boolean condition (like a filter operation).

perimosocordiae
I added a second example that works like I expect. I don't really see the difference. Shouldn't the assignment being "piped through"?
Philipp der Rautenberg
I don't think this is quite right. If you do `a[a==1] = 3`, that actually changes the contents of a.
Dave Costa
@Dave - I think this is perimosocodiae is correct, and that your counter-example is due to something more like a hack in the numpy internals to create the appearance of an in-place operation.
tom10
@tom10 - It's not a "hack". It's part of the implementation of the array class. Behavior is documented, for instance, here: http://www.scipy.org/Tentative_NumPy_Tutorial#head-864862d3f2bb4c32f04260fac61eb4ef34788c4c. "Slicing an array returns a view of it", i.e. not a copy.
Dave Costa
normal list works that way too -- you can assign to slices (only with iterables) `l = range(10); l[5:] = range(5)`
kaizer.se
@Dave - Certainly, a slice in numpy is a view, but a[a==1] is not a slice and not a view.
tom10
+4  A: 

It appears you simply can't do an assignment through a double-slice like that.

This works though:

a[numpy.where(a==1)[0][1:]] = 3
Dave Costa
A: 

This does what you want

a[2:][a[2:]==1]=3
gnibbler
But that requires knowing in advance that the first occurrence of 1 is at position 1.
Dave Costa
+5  A: 

It's related to how fancy indexing works. There is a thorough explanation here. It is done this way to allow inplace modification with fancy indexing (ie a[x>3] *= 2). A consequence of this is that you can't assign to a double index as you have found. Fancy indexing always returns a copy rather than a view.

thrope
Actually, your solution modifies the first occurrence of 1, which is not what he wants.
Dave Costa
Right - took it off before your comment. Ps hi Philip it's Robin!
thrope
Hey Robin - what chance is that to meet here... Cheers from munich!
Philipp der Rautenberg