首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >numpy reshape()和transpose()之间是否存在交互规则?

numpy reshape()和transpose()之间是否存在交互规则?
EN

Stack Overflow用户
提问于 2019-09-11 22:47:26
回答 1查看 216关注 0票数 2

我把这个问题放在了相当多的上下文中,希望能让你更容易理解,但可以跳过实际的问题。

上下文

以下是我所做的引发这个问题的工作:

我正在使用一个API来访问一些表格数据,它实际上是一个标注为N维数组的数组。数据作为(实际数据值的)列表的扁平列表返回,加上不同轴及其标签的列表,例如:

代码语言:javascript
运行
复制
raw_data = [
    ['nrm', 'nrf'],
    ['ngm', 'ngf'],
    ['nbm', 'nbf'],
    ['srm', 'srf'],
    ['sgm', 'sgf'],
    ['sbm', 'sbf'],
    ['erm', 'erf'],
    ['egm', 'egf'],
    ['ebm', 'ebf'],
    ['wrm', 'wrf'],
    ['wgm', 'wgf'],
    ['wbm', 'wbf'],
]

axes = [
    ('Gender', ['Male', 'Female']),
    ('Color', ['Red', 'Green', 'Blue']),
    ('Location', ['North', 'South', 'East', 'West']),
]

数据通常是数字的,但我在这里使用了字符串,因此您可以很容易地看到它如何与标签匹配,例如nrmNorth, Red, Male的值。

数据循环通过轴0(在列表中),然后遍历轴1和轴2,然后遍历轴1(在“内部”),然后是2(对于继续“向外”工作的高维数据),即:

代码语言:javascript
运行
复制
       axis 0 ->
a a [ # # # # # # ]
x x [ # # # # # # ]
i i [ # # # # # # ]
s s [ #  R A W  # ]
    [ # D A T A # ]
2 1 [ # # # # # # ]
↓ ↓ [ # # # # # # ]
    [ # # # # # # ]

我想重塑这些数据并将其与标签相匹配,我使用以下方法将其输出到Pandas (多索引)DataFrame中:

代码语言:javascript
运行
复制
import numpy as np
import pandas as pd

names = [name for (name, _) in axes]
labels = [labels for (_, labels) in axes]

sizes = tuple(len(L) for L in labels)  # (2, 3, 4)
data_as_array = np.array(raw_data)  # shape = (12, 2) = (3*4, 2)
A = len(sizes)  # number of axes
new_shape = (*sizes[1:],sizes[0])  # (3, 4, 2)

data = data_as_array.reshape(new_shape, order="F").transpose(A - 1, *range(A - 1))
# With my numbers: data_as_array.reshape((3, 4, 2), order="F").transpose(2, 0, 1)

df = pd.DataFrame(
    data.ravel(),
    index=pd.MultiIndex.from_product(labels, names=names),
    columns=["Value"],
)

(我已经注意到我的例子中的一些特定值是什么,但是代码应该是对任何N维数据进行泛化。)

这意味着:

代码语言:javascript
运行
复制
                      Value
Gender Color Location      
Male   Red   North      nrm
             South      srm
             East       erm
             West       wrm
       Green North      ngm
             South      sgm
             East       egm
             West       wgm
       Blue  North      nbm
             South      sbm
             East       ebm
             West       wbm
Female Red   North      nrf
             South      srf
             East       erf
             West       wrf
       Green North      ngf
             South      sgf
             East       egf
             West       wgf
       Blue  North      nbf
             South      sbf
             East       ebf
             West       wbf

这一切都是理想的和预期的,您可以看到,这些值已经在正确的位置结束,即附加到它们的匹配标签上。

问题

我的实际问题涉及这一行:

data = data_as_array.reshape(new_shape, order="F").transpose(A - 1, *range(A - 1))

我的例子中的具体数字是:

data = data_as_array.reshape((3, 4, 2), order="F").transpose(2, 0, 1)

经过一些实验后,我发现以下三种方法都是等价的(第一种是原始版本):

代码语言:javascript
运行
复制
data1 = data_as_array.reshape(new_shape, order="F").transpose(D - 1, *range(D - 1))
data2 = data_as_array.T.reshape(*reversed(new_shape)).T.transpose(D - 1, *range(D - 1))
data3 = data_as_array.reshape(*reversed(sizes)).T

但这让我思考(这是我的问题!):

有什么规则,我可以用来操作表达式,从data1 data3**?**到data3**?**,例如

特别是,transpose()reshape()似乎有着密切的联系,而且可能有一种方法可以“吸收”转移到reshape()中的动作,这样您就可以将其删除,或者至少将其转换为更整洁的.T (如data3)。

我的尝试

我设法建立了以下规则:

代码语言:javascript
运行
复制
a.reshape(shape, order="F") == a.T.reshape(*reversed(shape)).T

您可以将.T应用于双方,也可以将a.T替换为a,以获得这些变体:

代码语言:javascript
运行
复制
a.reshape(shape) == a.T.reshape(*reversed(shape), order="F").T
a.reshape(shape).T == a.T.reshape(*reversed(shape), order="F")
a.T.reshape(shape) == a.reshape(*reversed(shape), order="F").T

a.reshape(shape, order="F") == a.T.reshape(*reversed(shape)).T
a.reshape(shape, order="F").T == a.T.reshape(*reversed(shape))
a.T.reshape(shape, order="F") == a.reshape(*reversed(shape)).T

我认为这实际上是对行和列的排序之间的区别的定义,以及它们之间的关系。

但我没能做的是展示一下你可以做什么:

data = data_as_array.reshape((3, 4, 2), order="F").transpose(2, 0, 1)

至:

data = data_as_array.reshape((4, 3, 2))

所以以某种方式将换位放入整形中。

但我甚至不确定这是普遍正确的,或者是特定于我的数据或例如3维。

编辑:为了澄清,我对直截了当的.T转换的工作方式相当满意,上面的规则涵盖了这一点。(请注意,对于3个轴,.T等价于.tranpose(2, 1, 0),对于n轴的一般情况,则等价于.tranpose(n-1, n-2, ... 2, 1, 0)。)

在使用.transpose()的情况下,您正在执行我很好奇的“部分”转置,例如,.tranpose(1, 0, 2) --在这里,您所做的不仅仅是颠倒轴的顺序。

一些参考资料:

  • 这包括了主要行和列的主要区别:How do you unroll a Numpy array of (mxn) dimentions into a single vector (我可以很容易地看到数据中是如何发生的)
  • 因此,这个答案对于解释转换非常有帮助,并且基本上也包括了整形:https://stackoverflow.com/a/32034565/9219425 (查看奇妙的图表!),包括介绍转换是如何影响形状和进度的。我编写了一个模拟这个过程的算法,以查看这是否会使事情变得更清楚(例如,transposing可能对应于交换算法中for循环的顺序),但它并没有真正的帮助。
EN

回答 1

Stack Overflow用户

发布于 2019-09-11 23:18:18

我不打算讨论你的所有案例(目前),但这里有一个例子说明了重塑、转置和秩序如何相互作用:

代码语言:javascript
运行
复制
In [176]: x = np.arange(12)                                                                                  
In [177]: x.strides, x.shape                                                                                 
Out[177]: ((8,), (12,))
In [178]: y = x.reshape(3,4)                                                                                 
In [179]: y.strides, y.shape                                                                                 
Out[179]: ((32, 8), (3, 4))        # (32=4*8)
In [180]: z = y.T                                                                                            
In [181]: z.strides, z.shape                                                                                 
Out[181]: ((8, 32), (4, 3))         # strides has been switched
In [182]: w = x.reshape(4,3, order='F')                                                                      
In [183]: w.strides, w.shape                                                                                 
Out[183]: ((8, 32), (4, 3))
In [184]: z                                                                                                  
Out[184]: 
array([[ 0,  4,  8],
       [ 1,  5,  9],
       [ 2,  6, 10],
       [ 3,  7, 11]])
In [185]: w                                                                                                  
Out[185]: 
array([[ 0,  4,  8],
       [ 1,  5,  9],
       [ 2,  6, 10],
       [ 3,  7, 11]])

带有'F‘的reshape产生与转置相同的东西。

ravel,本质上是reshape(-1) (到1d)

代码语言:javascript
运行
复制
In [186]: w.ravel()     # order C                                                                                          
Out[186]: array([ 0,  4,  8,  1,  5,  9,  2,  6, 10,  3,  7, 11])
In [187]: w.ravel(order='F')                                                                                 
Out[187]: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

请注意,w (和z)是view of x

代码语言:javascript
运行
复制
In [190]: w.base                                                                                             
Out[190]: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
In [191]: x.__array_interface__                                                                              
Out[191]: 
{'data': (139649452400704, False),
 'strides': None,
 'descr': [('', '<i8')],
 'typestr': '<i8',
 'shape': (12,),
 'version': 3}
In [192]: w.__array_interface__                                                                              
Out[192]: 
{'data': (139649452400704, False),   # same data buffer address
 'strides': (8, 32),
 'descr': [('', '<i8')],
 'typestr': '<i8',
 'shape': (4, 3),
 'version': 3}

用于部分转置:

代码语言:javascript
运行
复制
In [194]: x = np.arange(24)                                                                                  
In [195]: y = x.reshape(2,3,4)                                                                               
In [196]: y.strides                                                                                          
Out[196]: (96, 32, 8)
In [197]: z = y.transpose(1,0,2)                                                                             
In [198]: z                                                                                                  
Out[198]: 
array([[[ 0,  1,  2,  3],
        [12, 13, 14, 15]],

       [[ 4,  5,  6,  7],
        [16, 17, 18, 19]],

       [[ 8,  9, 10, 11],
        [20, 21, 22, 23]]])
In [199]: z.shape                                                                                            
Out[199]: (3, 2, 4)
In [200]: z.strides                                                                                          
Out[200]: (32, 96, 8)

部分转座子的形状和步伐都有变化。结果既不是F阶,也不是C级。

基中的元素顺序:

代码语言:javascript
运行
复制
In [201]: z.ravel(order='K')                                                                                 
Out[201]: 
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
       17, 18, 19, 20, 21, 22, 23])

逐行订货:

代码语言:javascript
运行
复制
In [202]: z.ravel(order='C')                                                                                 
Out[202]: 
array([ 0,  1,  2,  3, 12, 13, 14, 15,  4,  5,  6,  7, 16, 17, 18, 19,  8,
        9, 10, 11, 20, 21, 22, 23])

按栏排列的顺序:

代码语言:javascript
运行
复制
In [203]: z.ravel(order='F')                                                                                 
Out[203]: 
array([ 0,  4,  8, 12, 16, 20,  1,  5,  9, 13, 17, 21,  2,  6, 10, 14, 18,
       22,  3,  7, 11, 15, 19, 23])
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57897700

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档