【问题标题】:python ravel vs. transpose when used in reshape在 reshape 中使用时,python ravel 与转置
【发布时间】:2016-12-04 02:13:57
【问题描述】:

我有一个 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 是一个巨大的(可能是复值)矩阵,那么哪个在计算上更好,在什么意义上(计算时间、内存等)?

我的猜测是使用转置更好,但如果 reshape 自动执行 ravel 则可能 ravel 选项更快(尽管 reshape 可能在 C 或 Fortran 中执行 ravel 和那么不清楚)?

【问题讨论】:

    标签: python numpy reshape


    【解决方案1】:

    他们做事的顺序 - 重塑、改变步伐和复制 - 不同,但他们最终做同样的事情。

    我喜欢使用__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}
    

    transpose 是一个视图,具有不同的形状、步幅和顺序:

    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}
    

    transpose 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}
    

    我认为 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 中,我们仍然可以按数字顺序逐步遍历数组。但在重塑之后,10 一点也不接近。显然有一个副本。

    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]])
    

    【讨论】:

    • 好的,我明白了,所以看起来我选择什么并不重要。谢谢!
    • 有趣的是,时间证明 np.reshape(v.T, reshape_tuple) 比 np.reshape(v.ravel(order='F'), reshape_tuple) 快得多。
    • 也许reshape_tuple 是这样的np.reshape(v.T, reshape_tuple) 不需要复制。也就是说,新形状与转置形状兼容。我会检查__array_interface__
    猜你喜欢
    • 2014-04-21
    • 2019-05-13
    • 1970-01-01
    • 2013-10-29
    • 2018-07-01
    • 2012-06-19
    • 2012-09-04
    • 2013-03-29
    相关资源
    最近更新 更多