numpy ravel on inconsistent dimensional object

2019-08-17 19:01发布

I have below code that allows me to iterate over a flattened list and maps the updates back to the structured array -

a = np.asarray([1,2,3])
b = np.asarray([4,5,6])
c = np.asarray([a, b])
print c
r = c.ravel()
print r
r[1] = 10
print c

setting r[1] = 10 modifies c[0][1] to 10. I want to do something similar with the lower snippet but this fails and I am assuming it's because the dimensions are inconsistent. Is there some way to get similar behavior so I can modify a flattened version without having to reshape it back to c?

a = np.asarray([1,2,3])
b = np.asarray([4,5,6,7,8])
c = np.asarray([a, b])

r = c.ravel()
r[1] = 10
print r

1条回答
兄弟一词,经得起流年.
2楼-- · 2019-08-17 19:49

In your first case c is a 2d array

In [391]: a = np.asarray([1,2,3])
     ...: b = np.asarray([4,5,6])
     ...: c = np.asarray([a, b])
     ...: 
In [392]: c
Out[392]: 
array([[1, 2, 3],
       [4, 5, 6]])
In [393]: c.shape
Out[393]: (2, 3)

ravel produces a view of c, so changes to one appear in the other

In [394]: r = c.ravel()
In [395]: r[1] = 10
In [396]: c
Out[396]: 
array([[ 1, 10,  3],
       [ 4,  5,  6]])

You can also index c with flat, with the same effect:

In [397]: c.flat[4] = 10
In [398]: c
Out[398]: 
array([[ 1, 10,  3],
       [ 4, 10,  6]])
In [399]: r
Out[399]: array([ 1, 10,  3,  4, 10,  6])

These changes to c or r do not affect the original a or b. asarray copies those arrays.

In the second case c is a 1d array containing other arrays:

In [400]: a = np.asarray([1,2,3])
     ...: b = np.asarray([4,5,6,7,8])
     ...: c = np.asarray([a, b])
     ...: 
In [401]: c
Out[401]: array([array([1, 2, 3]), array([4, 5, 6, 7, 8])], dtype=object)

The pieces can be joined into a 1d array:

In [402]: np.concatenate(c)
Out[402]: array([1, 2, 3, 4, 5, 6, 7, 8])

Values can be changed, but won't affect the original c.

In [403]: c[0][0] = 10
In [404]: c
Out[404]: array([array([10,  2,  3]), array([4, 5, 6, 7, 8])], dtype=object)

This changes the original a because c literally contains a, not a copy of it:

In [405]: a                     
Out[405]: array([10,  2,  3]

np.array (or asarray) tries to make as-a-dimensional array as it can from the inputs. In the first case inputs are equal in size, so it makes a 2d. In the second they differ so it makes a 1d array of objects. This behavior often gives users problems. Either they expect a 2d array in the second case, or they can't produce the object array in the first.

To reliably make an object array, regardless of whether the inputs match in size or not, you have to do something like

In [417]: g = np.empty(2, dtype=object)
In [418]: g[:] = [a, b[:3]]
In [419]: g
Out[419]: array([array([10,  2,  3]), array([4, 5, 6])], dtype=object)
查看更多
登录 后发表回答