Naru1243
Naru1243

Reputation: 33

Using np.ravel() on a view creates copy?

Having an array filled with zeros, I want to create a view, use .ravel() on it, modify the array returned by ravel() and have this modification change the original array. Without the use of ravel() it works fine

zeros = np.zeros(shape=(10,10))
view = zeros[3:7,3:7]
view[:] = 1

print(zeros)

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., 0., 0., 0., 0., 0.],
       [0., 0., 0., 1., 1., 1., 1., 0., 0., 0.],
       [0., 0., 0., 1., 1., 1., 1., 0., 0., 0.],
       [0., 0., 0., 1., 1., 1., 1., 0., 0., 0.],
       [0., 0., 0., 1., 1., 1., 1., 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., 0., 0., 0., 0., 0., 0., 0., 0.]])

However, using .ravel() creates the following:

zeros = np.zeros(shape=(10,10))
view = zeros[3:7,3:7].ravel()
view[:] =1

print(zeros)

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., 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.],
       [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., 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.]])

As one would expect, view.flags["OWNDATA"] returns "True", so a copy has been created. How can I change the code to create a view that lets me modify the original array ?

Tried

view[:] = view[:]+1

Upvotes: 1

Views: 81

Answers (1)

hpaulj
hpaulj

Reputation: 231385

You can't. ravel, which is just a reshape, sometimes has to make a copy. A view is possible only when the selection of values can be expressed in a regular pattern, using either scalar or slice indices.

Consider a small example with distinct values:

In [47]: x = np.arange(9).reshape(3,3).copy()

In [48]: x
Out[48]: 
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

In [49]: x.base

In [50]: y = x[1:,1:]

In [51]: y
Out[51]: 
array([[4, 5],
       [7, 8]])

In [52]: y.base
Out[52]: 
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

In [53]: z = y.ravel()

In [54]: z
Out[54]: array([4, 5, 7, 8])

In [55]: x.ravel()
Out[55]: array([0, 1, 2, 3, 4, 5, 6, 7, 8])

In [56]: z.base

y is a view, but z is not. There's no way of selecting the z values from the flat x values with a slice.

But you can use the flat iterator to index y in a flat manner:

In [59]: y.flat[2]=10

In [60]: y
Out[60]: 
array([[ 4,  5],
       [10,  8]])

In [61]: x
Out[61]: 
array([[ 0,  1,  2],
       [ 3,  4,  5],
       [ 6, 10,  8]])

Upvotes: 1

Related Questions