为教学原因实现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
的一些解释将非常有用。谢谢!
答案 0 :(得分:25)
nd
到nd
转化的一般想法这种nd
到nd
转换的想法只使用了两件事 -
如果所需的置换顺序是滚动轴,则置换轴(使用numpy.transpose
或numpy.moveaxis
或numpy.rollaxis
;如果只需要交换两个轴,则置换numpy.swapaxes
)和
重塑。
置换轴:获取订单,使得展平版本对应于展平版本的输出。所以,如果你以某种方式最终使用它两次,再看一遍,因为你不应该。
重塑:分割轴或将最终输出设置为所需形状。主要在开始时需要拆分轴,此时输入较低且我们需要拆分成块。再说一次,你不应该超过两次。
因此,通常我们会有三个步骤:
[ 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)
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,尽管有时候对我来说,仅检查transpose
和reshape
涵盖的所有可能情况会更容易。
例如,以下代码
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
不足以涵盖我的情况,我必须做一些更复杂的事情。