NumPy中MATLAB的repmat等价是什么

116 投票
7 回答
122583 浏览
提问于 2025-04-15 15:56

我想用NumPy来实现和下面这段MATLAB代码一样的功能:repmat([1; 1], [1 1 1])。我该怎么做呢?

7 个回答

14

这是我通过一些尝试理解的结果。如果有错误请纠正,希望这能帮到你。

假设你有一个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不同。我们不能再说repmattile是等价的指令了。


为了让tilerepmat那样工作,在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),这在二维数组中是看不出来的。在这里,要想在两种语言中获得相同的结果,需要更多的预处理。


我知道这个推理可能并不普遍,但我只能推导到这里。希望这能激励其他人进行更深入的测试。

17

需要注意的是,有些情况下你需要用到MATLAB的repmat功能,而NumPy的广播机制可以解决这些问题。这个广播机制让你可以对形状相似的数组进行各种数学运算。比如说,如果你有一个1600x1400x3的数组,代表一张三色的图片,你可以用[1.0 0.25 0.25]这个数组来逐个像素地乘法运算,从而减少每个像素的绿色和蓝色成分。想了解更多信息,可以查看上面的链接。

121

这里有一个更好的(官方的)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]]])

撰写回答