--About slices and masks of np.ndarray. --If you use it simply, you can use it in the same way when you assign it to the original object. --Slice returns view, but mask (fancy index) returns copy, so be careful when chaining or doing complicated things.
As you know, ndarray can be assigned to the range specified by slice.
slice.py
In [1]: import numpy as np
In [2]: table = np.zeros((2, 5))
In [3]: table[1, :3] = 1
In [4]: table
Out[4]:
array([[ 0., 0., 0., 0., 0.],
[ 1., 1., 1., 0., 0.]])
This is because ndarray returns reference instead of copy when specified in slices.
You can also do the same with a Boolean mask.
mask.py
In [1]: import numpy as np
In [2]: table = np.zeros((2, 5))
In [3]: table[1, [True, True, True, False, False]] = 1
In [4]: table
Out[4]:
array([[ 0., 0., 0., 0., 0.],
[ 1., 1., 1., 0., 0.]])
it's the same.
Let's chain this.
chain1.py
In [1]: import numpy as np
In [2]: table = np.zeros((2, 5))
In [3]: table[1, :3][1:] = 1
In [4]: table
Out[4]:
array([[ 0., 0., 0., 0., 0.],
[ 0., 1., 1., 0., 0.]])
Since the slice returns Reference, the Reference of Reference is Reference, so we were able to safely assign it to the original table. It's easy. Now let's do the same for masks.
chain2.py
In [1]: import numpy as np
In [2]: table = np.zeros((2, 5))
In [3]: table[1, [True, True, True, False, False]][[False, True, True]] = 1
In [4]: table #Not assigned!!!!
Out[4]:
array([[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.]])
Well, I got a different result than I expected.
chain3.py
In [1]: import numpy as np
In [2]: table = np.zeros((2, 5))
In [3]: table[1, [True, True, True, False, False]][1:] = 1
In [4]: table #Not assigned!!!!
Out[4]:
array([[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.]])
The same applies to the mask + slice chain.
What do you mean ...
There is a detailed explanation in the official documentation. http://scipy-cookbook.readthedocs.io/items/ViewsVsCopies.html
But fancy indexing does seem to return views sometimes, doesn't it? If you check the section of
sample1.py
>>> a = numpy.arange(10)
>>> a[[1,2]] = 100
>>> a
array([ 0, 100, 100, 3, 4, 5, 6, 7, 8, 9])
When
sample2.py
>>> a = numpy.arange(10)
>>> c1 = a[[1,2]]
>>> c1[:] = 100
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> c1
array([100, 100])
Explains the difference. This pattern is also this time.
In conclusion, The mask (fancy index) did not actually return a view.
The mask was able to overwrite the original object not because it was returning a view, but because the python interpreter was converting it to an inplace expression.
fancy_index1.py
>>> a[[1,2]] = 100
Is
fancy_index1_translated.py
a.__setitem__([1,2], 100)
It means that the original value of a has changed because it is converted to. However,
fancy_index2.py
c1 = a[[1,2]]
Is
fancy_index2_translated.py
c1 = a.__getitem__([1,2])
And view, not copy, so the result will change the moment you divide it into two lines.
By applying this, the results of chain2.py and chain3.py can also be explained.
table[1, [True, True, True, False, False]]
Returns a copy, so no matter how much you overwrite it after that, the original table will not be changed.
chain4.py
In [1]: import numpy as np
In [2]: table = np.zeros((2, 5))
In [3]: table[1, :3][False, True, True] = 1
In [4]: table
Out[4]: ???
What result does this return ??
Recommended Posts