Numpy数组和Matlab矩阵不匹配[3D]。

3
以下是使用Octave/Matlab显示3D矩阵的示例代码:
octave:1> A=zeros(3,3,3);
octave:2> 
octave:2> A(:,:,1)= [[1 2 3];[4 5 6];[7 8 9]];
octave:3> 
octave:3> A(:,:,2)= [[11 22 33];[44 55 66];[77 88 99]];
octave:4> 
octave:4> A(:,:,3)= [[111 222 333];[444 555 666];[777 888 999]];
octave:5> 
octave:5> 
octave:5> A
A =

ans(:,:,1) =

   1   2   3
   4   5   6
   7   8   9

ans(:,:,2) =

   11   22   33
   44   55   66
   77   88   99

ans(:,:,3) =

   111   222   333
   444   555   666
   777   888   999

octave:6> A(1,3,2)
ans =  33

我需要使用numpy将同一个矩阵进行转换...不幸的是,当我尝试使用numpy中的数组访问相同的索引时,我得到了不同的值,如下所示!

import numpy as np
array = np.array([[[1 ,2 ,3],[4 ,5 ,6],[7 ,8 ,9]], [[11 ,22 ,33],[44 ,55 ,66],[77 ,88 ,99]], [[111 ,222 ,333],[444 ,555 ,666],[777 ,888 ,999]]])
>>> array[0,2,1]
8

我阅读了以下文档,其中展示了Matlab和Python numpy中矩阵实现的差异Numpy for Matlab users,但我没有找到一个三维数组的示例以及如何在Matlab和numpy之间进行相互映射!
例如,在Matlab中访问元素(1,3,2)与使用numpy(0,2,1)的相同索引不匹配。
Octave/Matlab
octave:6> A(1,3,2)
ans = 33
Python
>>> array[0,2,1]
8

3
我认为MATLAB表示为A(x,y,z),而numpy则表示为A[z,y,x] - Ander Biguri
@AnderBiguri 在 Python 中尝试,似乎应该是 A[z,x,y],我认为 xy 会交换位置,因为行优先和列优先的差异。 - Dan
2
@Dan 是的,绝对正确。从技术上讲,更改是反向 dims+ 交换 x,y,因为行/列主要。然而,我会将这个最后的更改添加到矩阵的定义中,而不是索引中,因为这就是所有 Python 矩阵的创建方式。 - Ander Biguri
基本上有两个不同之处。1)请参见我的第一条评论。2)A=[1 2; 3 4] 在numpy中是A=np.array([[1, 3], [2, 4]]) - Ander Biguri
5个回答

5

在numpy中,你的数组构造方式与MATLAB不同。

在MATLAB中,你的数组形式为(y, x, z),而在numpy中,你的数组形式为(z, y, x)。你的3D numpy数组是一系列“堆叠”的2D数组,因此你需要进行“外->内”索引(缺乏更好的术语),这是您的数组定义的扩展形式,希望这样解释能让你更好地理解:

[[[1, 2, 3],
  [4, 5, 6],        # Z = 0
  [7 ,8 ,9]],
 [[11 ,22 ,33],
  [44 ,55 ,66],     # Z = 1
  [77 ,88 ,99]],
 [[111 ,222 ,333],
  [444 ,555 ,666],  # Z = 2
  [777 ,888 ,999]]
]

那么,使用:

import numpy as np

A = np.array([[[1 ,2 ,3],[4 ,5 ,6],[7 ,8 ,9]], [[11 ,22 ,33],[44 ,55 ,66],[77 ,88 ,99]], [[111 ,222 ,333],[444 ,555 ,666],[777 ,888 ,999]]])
B = A[1, 0, 2]

B 返回 33,正如预期的那样。

如果您想以更少费脑筋的方式索引数组,请考虑像在MATLAB中一样生成它。


4

MATLAB和Python的索引方式不同。为了研究这个问题,我们先创建一个由数字 18 组成的线性数组,然后在每种语言中使用reshape将结果重新排列为一个2-by-2-by-2的矩阵:

MATLAB:

M_flat = 1:8
M = reshape(M_flat, [2,2,2])

它返回
M =

ans(:,:,1) =

   1   3
   2   4

ans(:,:,2) =

   5   7
   6   8

Python:

import numpy as np
P_flat = np.array(range(1,9))
P = np.reshape(P, [2,2,2])

该函数返回

array([[[1, 2],
        [3, 4]],

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

首先要注意的是前两个维度已经交换了。这是因为MATLAB使用列优先索引,也就是我们首先按列计数,而Python使用行优先索引,因此它首先按行计数。

现在让我们尝试对它们进行索引。所以让我们尝试沿不同的维度切片。在MATLAB中,我知道如何从第三个维度中获取一个切片,可以这样做:

M(:,:,1)

ans =

   1   3
   2   4

现在让我们在Python中尝试相同的操作。
P[:,:,0]

array([[1, 3],
       [5, 7]])

所以这完全不同。要得到MATLAB的“等效物”,我们需要进行以下操作

P[0,:,:]

array([[1, 2],
       [3, 4]])

现在返回的是MATLAB版本的转置,这是由于行主序和列主序的差异所导致的预期结果。
对于索引,这对应该有什么含义呢?Python似乎将主要索引放在末尾,这与MALTAB相反。
假设我在MATLAB中按以下方式索引。
M(1,2,2)

ans = 

    7

现在,如果我们想从Python中获取数字7,我们应该执行以下操作:
P(1,1,0)

这是MATLAB语法的反转。需要注意的是,由于我们在创建Python矩阵时考虑了行主序排序,因此它被反转了。如果您按照代码中所做的方式创建它,您将不得不交换最后2个索引,因此最好像Ander在评论中建议的那样正确地创建矩阵。


3
我认为比起仅称之为“行主”或“列主”,numpy更好地描述它们的方式是:
‘C’ 表示使用类似于 C 的索引顺序读取/写入元素,最后一个轴索引最快变化,第一个轴索引最慢变化。‘F’ 表示使用类似于 Fortran 的索引顺序读取/写入元素,第一个索引最快变化,最后一个索引最慢变化。
以下是一些动画演示不同之处:第一个是行主(Python / C),第二个是列主(MATLAB/ Fortran)。

Python/ C index ordering

MATLAB/Fortran index ordering


3

我认为问题在于你在numpy中创建矩阵的方式以及matlab和numpy之间不同的表示方式,为什么不在matlab和numpy中使用相同的系统呢?

>>> A = np.zeros((3,3,3),dtype=int)
>>> A
array([[[0, 0, 0],
        [0, 0, 0],
        [0, 0, 0]],

       [[0, 0, 0],
        [0, 0, 0],
        [0, 0, 0]],

       [[0, 0, 0],
        [0, 0, 0],
        [0, 0, 0]]])
>>> A[:,:,0] = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> A[:,:,1] = np.array([[11,22,33],[44,55,66],[77,88,99]])
>>> A[:,:,2] = np.array([[111,222,333],[444,555,666],[777,888,999]])
>>> A
array([[[  1,  11, 111],
        [  2,  22, 222],
        [  3,  33, 333]],

       [[  4,  44, 444],
        [  5,  55, 555],
        [  6,  66, 666]],

       [[  7,  77, 777],
        [  8,  88, 888],
        [  9,  99, 999]]])
>>> A[0,2,1]
33

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接