在 NumPy 中将四维数组重塑为二维数组背后的直觉和想法
- 2025-01-09 08:46:00
- admin 原创
- 105
问题描述:
Kronecker-product
在出于教学原因实施时(没有使用明显且现成的np.kron()
),我获得了一个四维数组作为中间结果,我必须重塑它才能获得最终结果。
但是,我仍然无法理解如何重塑这些高维数组。我有这个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
对这种高维数组进行重塑的一些解释将非常有帮助。谢谢!
解决方案 1:
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
到较大时nd
)或分割输出的轴(从较大nd
到较小时nd
)。分割的想法是使较小轴的维度数nd
与较大轴的维度数相同nd
。然后,研究输出的步幅并将其与输入进行匹配以获得所需的置换顺序。最后,如果最终的维度较小,则可能需要在最后进行重塑(默认方式或 C 顺序)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
的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
/transpose
在所有地方都有效。它们列在下面:
Python 将三维数组重塑为二维数组
使用 python/numpy 重塑数组
合并不重叠的数组块
从 Numpy 三维数组转换为二维数组
如何使用 reshape 将 N 长度向量重塑为 numpy 中的 3x(N/3) 矩阵
从四维列表构建图像
在多维空间中将多个子矩阵重塑/组合为一个矩阵
将多个小的二维矩阵交织成一个更大的矩阵
如何按3X3检索每个部分?
将 3D Numpy 数组重塑为 2D 数组
通过更大的矩阵在子矩阵中迭代
将二维 NumPy 数组重组为三维
Numpy 将形状从(3,512,660,4)更改为(3,2048,660,1)
Numpy:旋转M的子矩阵m
将 3D numpy 数组拆分为 3D 块
将 3D 矩阵转换为级联 2D 矩阵
重新排列 numpy 数组
Numpy:沿指定轴重塑数组
如何从二维数组构造二维数组
如何由子矩阵形成矩阵?
Python:将 3D 图像系列重塑为像素系列
解决方案 2:
看起来您正在寻找一个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的回答很好地解释了这一点。
解决方案 3:
Divarkar 的回答很棒,尽管有时对我来说只需检查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
+可以从 4 维数组中获得的所有结果reshape
。因为我知道输出应该是什么样子,所以我只会选择显示正确答案的排列。如果我没有得到我想要的结果,那么transpose
+reshape
就不够通用,无法满足我的情况,我必须做一些更复杂的事情。
扫码咨询,免费领取项目管理大礼包!