python ravel 与 transpose 用于 reshape 时
python ravel vs. transpose when used in reshape
我有一个 2D 数组 v
、v.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
是一个巨大的(可能是复值的)矩阵,哪个在计算上更好,在什么意义上(计算时间、内存等)?
我的猜测是使用转置更好,但是如果 reshape
执行自动 ravel
那么 ravel-option 可能更快(尽管 reshape
可能正在执行ravel
在 C 或 Fortran 中然后不清楚)?
他们做事的顺序 - 重塑、改变步幅和复制 - 不同,但他们最终做同样的事情。
我喜欢用__array_interface__
查看数据缓冲区的位置,以及其他变化。我想我应该添加 flags
才能看到 order
。但是 we/you 知道 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}
转置拉威尔也是抄袭。我认为相同的数据指针只是内存重用的一种情况(因为我没有分配给变量)——但可以检查。
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}
我认为 reshape 中有一个隐含的 'ravel':
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 后值的顺序看起来很相似,reshape 后更明显。
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]])
我有一个 2D 数组 v
、v.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
是一个巨大的(可能是复值的)矩阵,哪个在计算上更好,在什么意义上(计算时间、内存等)?
我的猜测是使用转置更好,但是如果 reshape
执行自动 ravel
那么 ravel-option 可能更快(尽管 reshape
可能正在执行ravel
在 C 或 Fortran 中然后不清楚)?
他们做事的顺序 - 重塑、改变步幅和复制 - 不同,但他们最终做同样的事情。
我喜欢用__array_interface__
查看数据缓冲区的位置,以及其他变化。我想我应该添加 flags
才能看到 order
。但是 we/you 知道 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}
转置拉威尔也是抄袭。我认为相同的数据指针只是内存重用的一种情况(因为我没有分配给变量)——但可以检查。
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}
我认为 reshape 中有一个隐含的 'ravel':
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 后值的顺序看起来很相似,reshape 后更明显。
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]])