为 MATLAB 要求兼容性重塑 3D numpy 数组

Reshaping 3D numpy array for MATLAB requirement compatibility

给定一个形状数组 3,2,2

np.array([[[1,2],[3,4]],[[5,6],[7,8]],[[9,10],[11,12]]])

我想把它改造成2,2,3的形状。

下游,这个重塑数据将在 MATLAB 中处理,出于某种原因,MATLAB 包需要对数组进行整形 2,2,3

在 MATLAB 中,预期的输出应该是

val(:,:,1) =

     1     2
     3     4


val(:,:,2) =

     5     6
     7     8


val(:,:,3) =

     9    10
    11    12

简单地重塑 arr.reshape(2,2,3) 并没有产生我想要的效果。

更新: 提出提案

val(:,:,1) =

   1   3
   2   4


val(:,:,2) =

   5   7
   6   8


val(:,:,3) =

    9   11
   10   12
In [29]: arr = np.array([[[1,2],[3,4]],[[5,6],[7,8]],[[9,10],[11,12]]])
In [30]: arr
Out[30]: 
array([[[ 1,  2],
        [ 3,  4]],

       [[ 5,  6],
        [ 7,  8]],

       [[ 9, 10],
        [11, 12]]])
In [31]: arr.shap
Out[31]: (3, 2, 2)

MATLAB 存储类似于 numpy 的阶 'F' 的矩阵,尾随维度最外层。使用 2d 作为转置最容易将其可视化。让我们在 3d 上试试看:

In [32]: arr1 = arr.T
In [33]: arr1.shape
Out[33]: (2, 2, 3)
In [34]: arr1
Out[34]: 
array([[[ 1,  5,  9],
        [ 3,  7, 11]],

       [[ 2,  6, 10],
        [ 4,  8, 12]]])

MATLAB 通过在最后一个维度上迭代显示 3d 数组,它的“平面”:

In [36]: for i in range(3):print(arr1[:,:,i])
[[1 3]
 [2 4]]
[[5 7]
 [6 8]]
[[ 9 11]
 [10 12]]

我没有你的 MATLAB npy 加载器,但可以探索 io.savemat/loadmat 如何进行传输。这适用于 MATLAB 格式的文件:

In [37]: from scipy import io
In [38]: io.savemat('test3d.mat',{'arr':arr, 'arr1':arr1})
In [39]: io.loadmat('test3d.mat')
Out[39]: 
{'__header__': b'MATLAB 5.0 MAT-file Platform: posix, Created on: Sun Dec  5 08:29:25 2021',
 '__version__': '1.0',
 '__globals__': [],
 'arr': array([[[ 1,  2],
         [ 3,  4]],
 
        [[ 5,  6],
         [ 7,  8]],
 
        [[ 9, 10],
         [11, 12]]]),
 'arr1': array([[[ 1,  5,  9],
         [ 3,  7, 11]],
 
        [[ 2,  6, 10],
         [ 4,  8, 12]]])}

在 Octave 会话中:

>> load test3d.mat
>> arr
arr =

ans(:,:,1) =

   1   3
   5   7
   9  11

ans(:,:,2) =

   2   4
   6   8
  10  12

>> arr1
arr1 =

ans(:,:,1) =

   1   3
   2   4

ans(:,:,2) =

   5   7
   6   8

ans(:,:,3) =

   9  11
  10  12

并且混乱的显示表明转置保留了原始的 numpy 数据值顺序:

>> arr1(:)'
ans =

   1   2   3   4   5   6   7   8   9  10  11  12

>> arr(:)'
ans =

   1   5   9   3   7  11   2   6  10   4   8  12

另一种转置将 3 移动到末尾,但保持前 2 的顺序

In [40]: arr2 = arr.transpose(1,2,0)
In [41]: arr2
Out[41]: 
array([[[ 1,  5,  9],
        [ 2,  6, 10]],

       [[ 3,  7, 11],
        [ 4,  8, 12]]])
In [42]: for i in range(3):print(arr2[:,:,i])
[[1 2]
 [3 4]]
[[5 6]
 [7 8]]
[[ 9 10]
 [11 12]]

我相信您正在寻找:

np.moveaxis(x, 0, 2)

你原来的形状是(3, 2, 2)。此行移动轴 [0] 并将其滚动到轴 [2](将其他 2 个轴向左移动)。所以你得到:

>>> x[:, :, 0]
array([[1, 2],
       [3, 4]])