NumPy中MATLAB的repmat等价是什么
我想用NumPy来实现和下面这段MATLAB代码一样的功能:repmat([1; 1], [1 1 1])
。我该怎么做呢?
7 个回答
这是我通过一些尝试理解的结果。如果有错误请纠正,希望这能帮到你。
假设你有一个2x3的矩阵M,这显然有两个维度。
在处理输入矩阵的已有维度时,我没有发现Matlab和Python之间有什么区别。因此,这两个命令
repmat(M,m,n) % matlab
np.tile(M,(m,n)) # python
对于一个有两个维度的矩阵来说,实际上是等价的。
当你要求在输入矩阵的维度之外进行重复或拼接时,事情就变得不那么直观了。回到这个2x3的矩阵M,我们只需看看输出矩阵的大小或形状会发生什么。假设现在的操作序列是1,1,2。
在Matlab中
> size(repmat(M,1,1,2))
ans =
2 3 2
它复制了输入矩阵的前两个维度(行和列),并在新的第三维度中重复了一次(也就是复制了两次)。这正好符合repmat
这个名字的意思,表示重复矩阵。
在Python中
>>> np.tile(M,(1,1,2)).shape
(1, 2, 6)
它采用了不同的处理方式,因为我猜测序列(1,1,2)在Python中的读取方式与Matlab不同。列、行和超出平面维度的复制数量是从右到左读取的。最终得到的对象形状与Matlab不同。我们不能再说repmat
和tile
是等价的指令了。
为了让tile
像repmat
那样工作,在Python中必须确保输入矩阵的维度与序列中的元素数量相同。这可以通过一些预处理来实现,创建一个相关的对象N。
N = M[:,:,np.newaxis]
这样,在输入时就有N.shape = (2,3,1)
而不是M.shape = (2,3)
,在输出时
>>> np.tile(N,(1,1,2)).shape
(2, 3, 2)
这就是size(repmat(M,1,1,2))
的结果。我猜这是因为我们引导Python将第三维添加到(2,3)的右侧,而不是左侧,这样Python就能按照Matlab的方式理解序列(1,1,2)。
在Python中,N
的[:,:,0]
中的元素将包含与Matlab中M
的(:,:,1)
相同的值。
最后,当使用Kronecker积时,我似乎找不到repmat
的等价物
>>> np.kron(np.ones((1,1,2)),M).shape
(1, 2, 6)
除非我像上面那样将M预处理成N。所以我认为最通用的方式是使用np.newaxis
。
当我们考虑一个三维矩阵L,并且输出矩阵没有添加新维度的简单情况时,事情就变得更加复杂。这两个看似等价的指令不会产生相同的结果
repmat(L,p,q,r) % matlab
np.tile(L,(p,q,r)) # python
因为在Matlab中行、列和超出平面的方向是(p,q,r),而在Python中是(q,r,p),这在二维数组中是看不出来的。在这里,要想在两种语言中获得相同的结果,需要更多的预处理。
我知道这个推理可能并不普遍,但我只能推导到这里。希望这能激励其他人进行更深入的测试。
需要注意的是,有些情况下你需要用到MATLAB的repmat功能,而NumPy的广播机制可以解决这些问题。这个广播机制让你可以对形状相似的数组进行各种数学运算。比如说,如果你有一个1600x1400x3的数组,代表一张三色的图片,你可以用[1.0 0.25 0.25]
这个数组来逐个像素地乘法运算,从而减少每个像素的绿色和蓝色成分。想了解更多信息,可以查看上面的链接。
这里有一个更好的(官方的)NumPy针对Matlab用户的指南,我担心之前的那个链接已经过时了。
在NumPy中,repmat(a, m, n)
的对应写法是tile(a, (m, n))
。
这个方法可以处理多个维度,得到的结果和Matlab很相似。(NumPy会给出一个三维的输出数组,这很正常,而Matlab出于某种原因只给出二维的输出,但内容是一样的)。
Matlab:
>> repmat([1;1],[1,1,1])
ans =
1
1
Python:
In [46]: a = np.array([[1],[1]])
In [47]: np.tile(a, [1,1,1])
Out[47]:
array([[[1],
[1]]])