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

时间:2017-12-26 10:30:26

标签: python arrays numpy multidimensional-array reshape

教学原因实现Kronecker-product (不使用明显且容易获得的np.kron()),我获得了一个4维数组作为中间结果,我和# 39;重塑以获得最终结果。

但是,我仍然无法重塑这些高维数组。我有这个4D数组:

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

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


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

        [[ 7, 14],
         [21, 28]]]])

这是(2, 2, 2, 2)的形状,我想将其重塑为(4,4)。有人可能会认为这与

有关
np.reshape(my4darr, (4,4))

但是,上述重塑给我预期结果

array([[ 0,  5,  0, 10],
       [ 6,  7, 12, 14],
       [ 0, 15,  0, 20],
       [18, 21, 24, 28]])

如您所见,预期结果中的所有元素都存在于4D数组中。我根本不能正确地完成重塑的工作。除了答案之外,如何对这种高维数组执行reshape的一些解释将非常有用。谢谢!

3 个答案:

答案 0 :(得分:25)

ndnd转化的一般想法

这种ndnd转换的想法只使用了两件事 -

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

重塑:分割轴或将最终输出设置为所需形状。主要在开始时需要拆分轴,此时输入较低且我们需要拆分成块。再说一次,你不应该超过两次。

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

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

 Create more axes             Bring axes             Merge axes
                          into correct order

反向跟踪方法

最安全的解决方法,给定输入和输出通过,可以称之为反向跟踪方法,即分割输入的轴(从较小的nd变为较大的{{1 }}或分割输出的轴(从较大的nd变为较小的nd)。分裂的想法是使较小的nd一个的变暗数与较大的nd一个相同。然后,研究输出的步幅并将其与输入匹配以获得所需的置换顺序。最后,如果最后一个是较小的nd,则最后可能需要重新整形(默认方式或C顺序)来合并轴。

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

实施例

让我们使用这个具体案例来演示如何应用这些策略。在此处,输入为nd,而输出为4D。所以,最有可能的是,我们不需要重塑分裂。因此,我们需要从置换轴开始。由于最终输出不是2D,而是4D,我们最后需要重新设计。

现在,这里的输入是:

2D

预期输出为:

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

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


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

        [[ 7, 14],
         [21, 28]]]])

此外,这是一个较大的In [271]: out Out[271]: array([[ 0, 5, 0, 10], [ 6, 7, 12, 14], [ 0, 15, 0, 20], [18, 21, 24, 28]]) 到较小的nd转换,因此反向跟踪方法会涉及,拆分输出并研究其strides并与相应的值匹配在输入中:

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

(2,0,3,1)

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

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

更多示例

我挖掘了我的历史记录,根据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]]) Q&As转换发现了一些nd。这些可以作为其他示例案例,尽管解释较少(主要是)。如前所述,最多只有两个nd和最多一个reshapes / swapaxes在任何地方完成了这项工作。它们列在下面:

答案 1 :(得分: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]])

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

此结果的简单2D重新整形版本(没有任何换位)如下所示 -

x.reshape(4, 4)

array([[ 0,  0,  0,  0],
       [ 5, 10, 15, 20],
       [ 6, 12, 18, 24],
       [ 7, 14, 21, 28]])

现在考虑与预期输出相关的输出 -

array([[ 0,  5,  0, 10],
       [ 6,  7, 12, 14],
       [ 0, 15,  0, 20],
       [18, 21, 24, 28]])

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

start
    | /|     /| /|
    |/ |    / |/ |
      /    /    / 
     /    /    /
    | /| /    | /|
    |/ |/     |/ |
                 end

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

要了解如何正确转置,您应该沿着输入跟踪元素,并找出需要跳转到输出中每个轴的轴。相应地进行换位。 Divakar's answer能够解释这一点。

答案 2 :(得分:0)

The Divarkar's answer is great,尽管有时候对我来说,仅检查transposereshape涵盖的所有可能情况会更容易。

例如,以下代码

n, m = 4, 2
arr = np.arange(n*n*m*m).reshape(n,n,m,m)
for permut in itertools.permutations(range(4)):
    arr2 = (arr.transpose(permut)).reshape(n*m, n*m)
    print(permut, arr2[0])

将使用transpose + reshape从4维数组中获得的所有信息给我。因为我知道输出的样子,所以我只选择显示正确答案的排列。如果我没有得到想要的东西,那么transpose + reshape不足以涵盖我的情况,我必须做一些更复杂的事情。