在重塑时使用python ravel与transpose

时间:2016-07-29 11:18:04

标签: python numpy reshape

我有一个2D数组vv.shape=(M_1,M_2),我希望将其重塑为包含v.shape=(M_2,N_1,N_2)M_1=N_1*N_2的3D数组。

我想出了以下几行,产生了相同的结果:

np.reshape(v.T, reshape_tuple)

np.reshape(v.ravel(order='F'), reshape_tuple)

代表reshape_tuple=(M_2,N_1,N_2)

如果原始v是一个巨大的(可能是复数值的)矩阵,哪一个在计算上更好,在什么意义上(comp时间,内存等)?

我的猜测是使用转置效果会更好,但如果reshape执行自动ravel,那么ravel-option可能会更快(尽管reshape可能会执行ravel 1}}在C或Fortran然后它不清楚)?

1 个答案:

答案 0 :(得分:3)

他们做事的顺序 - 重塑,改变步伐,制作副本 - 有所不同,但他们最终做同样的事情。

我喜欢使用__array_interface__来查看数据缓冲区的位置以及其他更改。我想我应该添加flags来查看order。但我们/您知道transpose已将订单更改为F,对吗?

In [549]: x=np.arange(6).reshape(2,3)
In [550]: x.__array_interface__
Out[550]: 
{'data': (187732024, False),
 'descr': [('', '<i4')],
 'shape': (2, 3),
 'strides': None,
 'typestr': '<i4',
 'version': 3}

转置是一种视图,具有不同的形状,步幅和顺序:

In [551]: x.T.__array_interface__
Out[551]: 
{'data': (187732024, False),
 'descr': [('', '<i4')],
 'shape': (3, 2),
 'strides': (4, 12),
 'typestr': '<i4',
 'version': 3}

ravel与不同的顺序是一个副本(不同的数据缓冲区指针)

In [552]: x.ravel(order='F').__array_interface__
Out[552]: 
{'data': (182286992, False),
 'descr': [('', '<i4')],
 'shape': (6,),
 'strides': None,
 'typestr': '<i4',
 'version': 3}
转置ravel也是一个副本。我认为相同的数据指针只是内存重用的一种情况(因为我没有分配给变量) - 但是可以检查它。

In [553]: x.T.ravel().__array_interface__
Out[553]: 
{'data': (182286992, False),
 'descr': [('', '<i4')],
 'shape': (6,),
 'strides': None,
 'typestr': '<i4',
 'version': 3}

添加重塑:

In [554]: x.T.ravel().reshape(2,3).__array_interface__
Out[554]: 
{'data': (182286992, False),
 'descr': [('', '<i4')],
 'shape': (2, 3),
 'strides': None,
 'typestr': '<i4',
 'version': 3}
In [555]: x.ravel(order='F').reshape(2,3).__array_interface__
Out[555]: 
{'data': (182286992, False),
 'descr': [('', '<i4')],
 'shape': (2, 3),
 'strides': None,
 'typestr': '<i4',
 'version': 3}

我认为重塑中有一种隐含的“混乱”:

In [558]: x.T.reshape(2,3).__array_interface__
Out[558]: 
{'data': (182286992, False),
 'descr': [('', '<i4')],
 'shape': (2, 3),
 'strides': None,
 'typestr': '<i4',
 'version': 3}

(我应该重复这些示例以消除内存重用歧义。)无论如何,转置后重塑需要与订单更改的ravel相同的内存副本。据我所知,两种情况都只需要一份副本。其他操作只涉及对形状等属性的更改。

如果我们只看阵列

,可能会更清楚
In [565]: x.T
Out[565]: 
array([[0, 3],
       [1, 4],
       [2, 5]])

T中,我们仍然可以按数字顺序单步执行数组。但重塑后,1并不接近0。显然有一份副本。

In [566]: x.T.reshape(2,3)
Out[566]: 
array([[0, 3, 1],
       [4, 2, 5]])

ravel之后的值的顺序看起来相似,重塑后更明显。

In [567]: x.ravel(order='F')
Out[567]: array([0, 3, 1, 4, 2, 5])
In [568]: x.ravel(order='F').reshape(2,3)
Out[568]: 
array([[0, 3, 1],
       [4, 2, 5]])