在NumPy中将4D阵列重塑为2D阵列的直觉和想法

kma*_*o23 17 python arrays numpy multidimensional-array reshape

虽然Kronecker-product出于教学原因(没有使用明显的和容易获得的np.kron()),我获得了一个4维数组作为中间结果,我将重塑以获得最终结果.

但是,我仍然无法围绕重塑这些高维阵列.我有这个4D数组:

array([[[[ 0,  0],
         [ 0,  0]],

        [[ 5, 10],
         [15, 20]]],


       [[[ 6, 12],
         [18, 24]],

        [[ 7, 14],
         [21, 28]]]])
Run Code Online (Sandbox Code Playgroud)

这是形状(2, 2, 2, 2),我想重塑它(4,4).有人可能会认为这很明显

np.reshape(my4darr, (4,4))
Run Code Online (Sandbox Code Playgroud)

但是,上述重塑并没有给我预期的结果,即:

array([[ 0,  5,  0, 10],
       [ 6,  7, 12, 14],
       [ 0, 15,  0, 20],
       [18, 21, 24, 28]])
Run Code Online (Sandbox Code Playgroud)

如您所见,预期结果中的所有元素都存在于4D数组中.我根本不能正确地根据需要进行重塑.除了答案之外,如何reshape为这种高维数组做一些解释将是非常有帮助的.谢谢!

Div*_*kar 28

一般的想法ndnd改造

这样的想法ndnd变换只使用两件事情-置换轴(带numpy.transpose或者numpy.moveaxis如果需要置换顺序是推出一个或numpy.rollaxis如果只是两个轴需要被交换)和重塑.

置换轴:获取订单,使得展平版本对应于展平版本的输出.所以,如果你以某种方式最终使用它两次,再看一遍,因为你不应该.

重塑:分割轴或将最终输出转换为所需形状.主要在开始时需要拆分轴,此时输入较低且我们需要拆分成块.同样,你不应该需要这两次以上.

因此,通常我们会有三个步骤:

    [ Reshape ]      --->  [ Permute axes ]   --->  [ Reshape ]

 Create more axes             Bring axes             Merge axes
                          into correct order
Run Code Online (Sandbox Code Playgroud)

反向跟踪方法

考虑到输入和输出是最安全的解决方法,可以称之为反向跟踪方法,即分割输入轴(当从较小numpy.swapaxes到较大时nd)或分割输出轴(当去从更大的nd更小nd).分裂的想法是使较小的nd一个的昏暗数量与较大的一个相同nd.然后,研究输出的步幅并将其与输入匹配以获得所需的置换顺序.最后,如果最后一个是较小的,则可能需要重新整形(默认方式或C顺序)nd来合并轴.

如果输入和输出都具有相同数量的dims,那么我们需要将两者分开并分成块并研究它们相互之间的步幅.在这种情况下,我们应该有块大小的附加输入参数,但这可能是偏离主题的.

让我们使用这个特定的案例来演示如何应用这些策略.在这里,输入是nd,而输出是4D.所以,最有可能的是,我们不需要重塑分裂.因此,我们需要从置换轴开始.因为,最终的输出不是2D,而是4D一个,我们需要在最后重塑.

现在,这里的输入是:

In [270]: a
Out[270]: 
array([[[[ 0,  0],
         [ 0,  0]],

        [[ 5, 10],
         [15, 20]]],


       [[[ 6, 12],
         [18, 24]],

        [[ 7, 14],
         [21, 28]]]])
Run Code Online (Sandbox Code Playgroud)

预期的产出是:

In [271]: out
    Out[271]: 
    array([[ 0,  5,  0, 10],
           [ 6,  7, 12, 14],
           [ 0, 15,  0, 20],
           [18, 21, 24, 28]])
Run Code Online (Sandbox Code Playgroud)

此外,这是一个更2D小到更小的nd转换,因此反向跟踪方法将涉及,分割输出并研究其步幅并匹配输入中的相应值:

                    axis = 3
                   ---      -->          

                    axis = 1                    
                   ------>           
axis=2|  axis=0|   [ 0,  5,  0, 10],        

               |   [ 6,  7, 12, 14],
               v  
      |            [ 0, 15,  0, 20],
      v
                   [18, 21, 24, 28]])
Run Code Online (Sandbox Code Playgroud)

因此,所需的置换顺序是nd:

In [275]: a.transpose((2, 0, 3, 1))
Out[275]: 
array([[[[ 0,  5],
         [ 0, 10]],

        [[ 6,  7],
         [12, 14]]],


       [[[ 0, 15],
         [ 0, 20]],

        [[18, 21],
         [24, 28]]]])
Run Code Online (Sandbox Code Playgroud)

然后,简单地重塑为预期的形状:

In [276]: a.transpose((2, 0, 3, 1)).reshape(4,4)
Out[276]: 
array([[ 0,  5,  0, 10],
       [ 6,  7, 12, 14],
       [ 0, 15,  0, 20],
       [18, 21, 24, 28]])
Run Code Online (Sandbox Code Playgroud)

更多例子

我挖了我的历史,发现一些(2,0,3,1)基于Q&Asnd转变.这些可以作为其他示例案例,尽管解释较少(大多数情况下).如前所述,nd最多只有两个,最多一个reshapes/ swapaxes在各地完成工作.它们列在下面:


cs9*_*s95 11

看起来你正在寻找一个transpose跟随的reshape.

x.transpose((2, 0, 3, 1)).reshape(np.prod(x.shape[:2]), -1)

array([[ 0,  5,  0, 10],
       [ 6,  7, 12, 14],
       [ 0, 15,  0, 20],
       [18, 21, 24, 28]])
Run Code Online (Sandbox Code Playgroud)

为了帮助您理解为什么需要换位,让我们分析您错误形状的输出(通过单个reshape调用获得)以理解为什么它不正确.

这个结果的简单2D重新整形版本(没有任何换位)看起来像这样 -

x.reshape(4, 4)

array([[ 0,  0,  0,  0],
       [ 5, 10, 15, 20],
       [ 6, 12, 18, 24],
       [ 7, 14, 21, 28]])
Run Code Online (Sandbox Code Playgroud)

现在根据您的预期输出考虑此输出 -

array([[ 0,  5,  0, 10],
       [ 6,  7, 12, 14],
       [ 0, 15,  0, 20],
       [18, 21, 24, 28]])
Run Code Online (Sandbox Code Playgroud)

您会注意到您的实际结果是通过类似Z的遍历输出错误形状 -

start
    | /|     /| /|
    |/ |    / |/ |
      /    /    / 
     /    /    /
    | /| /    | /|
    |/ |/     |/ |
                 end
Run Code Online (Sandbox Code Playgroud)

这意味着您必须以不同的步幅移动数组以获得实际结果.总之,简单的重塑是不够的.您必须转换原始数组,使这些类似Z的元素彼此连续,以便后续的重塑调用为您提供所需的输出.

要了解如何正确转置,您应该沿着输入跟踪元素,并找出需要跳转到输出中的每个轴的轴.相应地进行换位.迪瓦卡的答案很有助于解释这一点.

  • 因为`.transpose(2,0,3,1)`而不是`.transpose(0,2,1,3)`和*然后*重塑形式肯定更优雅,以fortran顺序获取数组. .. (2认同)