According to numpy documentation, advanced indexing is supposed to return a copy of the array. This works as expected in the one-dim case. However, if array is multidimensional, then numpy does not recognize it as a copy. How can I test whether a copy or view is returned in multidim case if I don't have access to the original array?
Example:
import numpy as np
y = np.ones((1, 10))
b = y[:, [0, 5, 6]]
# b is not a copy
assert not b.flags['OWNDATA']
assert b.base is not None
But it actually is a copy
b[:] = 33
print(y)
lets make y
a bit more interesting:
In [915]: y = np.arange(10).reshape(2,5);y, y.base
Out[915]:
(array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]]),
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
It is a view
of a 1d array.
Now use advanced indexing:
In [916]: b = y[:,[0,2,4]];b, b.base
Out[916]:
(array([[0, 2, 4],
[5, 7, 9]]),
array([[0, 5],
[2, 7],
[4, 9]]))
In [917]: b.strides, b.base.strides
Out[917]: ((4, 8), (8, 4))
b
is a (2,3) array, as we expect from the indexing, but it is actually a transpose of a (3,2) array. Evidently numpy
is selecting values using the list index, the 2nd dimension, and putting the slice dimension last. Then it transposes to get the desired shape. This hints at why mixing advanced and basic indexing can produce unexpected shapes (as documented and explained in other SO).
In any case, I don't see a way of testing b
to verify it isn't a view
of y
- except by comparing the base
attributes. The simplest thing is to accept the documentation's claim that it is a copy - just not a 'direct' copy.
We could get the same array with basic indexing - and get a view
of y.base
:
In [918]: c = y[:,::2]; c, c.base
Out[918]:
(array([[0, 2, 4],
[5, 7, 9]]),
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
A couple of other ways of getting a simple copy:
In [924]: d = y[[0,1], ::2]; d, d.base
Out[924]:
(array([[0, 2, 4],
[5, 7, 9]]),
None)
In [925]: d = y[[[0],[1]], [0,2,4]]; d, d.base
Out[925]:
(array([[0, 2, 4],
[5, 7, 9]]),
None)