numpy.tile 没有作为 Matlab repmat 工作

numpy.tile did not work as Matlab repmat

根据 What is the equivalent of MATLAB's repmat in NumPy,我尝试使用 python.

从 3x3 数组构建 3x3x5 数组

在 Matlab 中,这符合我的预期。

a = [1,1,1;1,2,1;1,1,1];
a_= repmat(a,[1,1,5]);

尺寸(a_) = 3 3 5

但是 numpy.tile

b = numpy.array([[1,1,1],[1,2,1],[1,1,1]])
b_ = numpy.tile(b, [1,1,5])

b_.shape = (1, 3, 15)

如果我想生成与在 Matlab 中相同的数组,等效项是什么?

编辑 1

我希望得到的输出是

b_(:,:,1) =

1 1 1  
1 2 1  
1 1 1  

b_(:,:,2) =

1 1 1  
1 2 1  
1 1 1  

b_(:,:,3) =

1 1 1  
1 2 1  
1 1 1  

b_(:,:,4) =  

1 1 1  
1 2 1  
1 1 1  
b_(:,:,5) =

1 1 1  
1 2 1  
1 1 1  

但是@farenorth 和 numpy.dstack 给出的是

[[[1 1 1 1 1]  
[1 1 1 1 1]  
[1 1 1 1 1]]  

[[1 1 1 1 1]  
[2 2 2 2 2]  
[1 1 1 1 1]]  

[[1 1 1 1 1]  
[1 1 1 1 1]  
[1 1 1 1 1]]]  

NumPy 函数通常不会'drop-in' 替代 matlab 函数。通常,'equivalent' 函数的使用方式存在细微差别。适应确实需要时间,但我发现这种转变非常值得。

在这种情况下,np.tile 文档指出当您尝试将数组平铺到比定义的更高维度时会发生什么,

numpy.tile(A, reps)

Construct an array by repeating A the number of times given by reps.

If reps has length d, the result will have dimension of max(d, A.ndim).

If A.ndim < d, A is promoted to be d-dimensional by prepending new axes. So a shape (3,) array is promoted to (1, 3) for 2-D replication, or shape (1, 1, 3) for 3-D replication. If this is not the desired behavior, promote A to d-dimensions manually before calling this function.

在这种情况下,您的数组被转换为 [1, 3, 3] 的形状,然后被平铺。因此,要获得您想要的行为,请确保将一个新的单例维度附加到您想要的数组中,

>>> b_ = numpy.tile(b[..., None], [1, 1, 5])
>>> print(b_.shape)
(3, 3, 5)

请注意,我在此处使用了 None(即 np.newaxis)和省略号来指定数组末尾的新维度。您可以了解有关这些功能的更多信息 here.

受 OP 评论启发的另一个选项是:

b_ = np.dstack((b, ) * 5)

在这种情况下,我对 'repmat' 数组使用元组乘法,然后由 np.dstack.

构造数组

如@hpaulj 所示,Matlab 和 NumPy 显示矩阵的方式不同。要复制 Matlab 输出,您可以执行以下操作:

>>> for idx in xrange(b_.shape[2]):
...    print 'b_[:, :, {}] = \n{}\n'.format(idx, str(b_[:, :, idx]))
...
b_[:, :, 0] = 
[[1 1 1]
 [1 2 1]
 [1 1 1]]

b_[:, :, 1] = 
[[1 1 1]
 [1 2 1]
 [1 1 1]]

b_[:, :, 2] = 
[[1 1 1]
 [1 2 1]
 [1 1 1]]

b_[:, :, 3] = 
[[1 1 1]
 [1 2 1]
 [1 1 1]]

b_[:, :, 4] = 
[[1 1 1]
 [1 2 1]
 [1 1 1]]

祝你好运!

让我们尝试比较,注意使形状和值多样化。

octave:7> a=reshape(0:11,3,4)
a =
    0    3    6    9
    1    4    7   10
    2    5    8   11

octave:8> repmat(a,[1,1,2])
ans =
ans(:,:,1) =
    0    3    6    9
    1    4    7   10
    2    5    8   11
ans(:,:,2) =    
    0    3    6    9
    1    4    7   10
    2    5    8   11

numpy 等价物 - 或多或少:

In [61]: a=np.arange(12).reshape(3,4)    
In [62]: np.tile(a,[2,1,1])
Out[62]: 
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]],

       [[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]]])

再次使用 numpy,但使用 order F 以更好地匹配 MATLAB Fortran 派生的布局

In [63]: a=np.arange(12).reshape(3,4,order='F')    
In [64]: np.tile(a,[2,1,1])
Out[64]: 
array([[[ 0,  3,  6,  9],
        [ 1,  4,  7, 10],
        [ 2,  5,  8, 11]],

       [[ 0,  3,  6,  9],
        [ 1,  4,  7, 10],
        [ 2,  5,  8, 11]]])

我在开头添加了新的 numpy 维度,因为在很多方面它更好地复制了在最后添加它的 MATLAB 实践。

尝试在末尾添加新维度。形状是 (3,4,5),但您可能不喜欢显示。

 np.tile(a[:,:,None],[1,1,2])

另一个考虑因素 - 当您展平瓷砖时会发生什么?

octave:10> repmat(a,[1,1,2])(:).'
ans =    
    0    1    2    3    4    5    6    7    8    9   10   11 
0    1    2    3     4    5    6    7    8    9   10   11

顺序Fa

In [78]: np.tile(a[:,:,None],[1,1,2]).flatten()
Out[78]: 
array([ 0,  0,  3,  3,  6,  6,  9,  9,  1,  1,  4,  4,  7,  7, 10, 10,  2,
        2,  5,  5,  8,  8, 11, 11])

In [79]: np.tile(a,[2,1,1]).flatten()
Out[79]: 
array([ 0,  3,  6,  9,  1,  4,  7, 10,  2,  5,  8, 11,  0,  3,  6,  9,  1,
        4,  7, 10,  2,  5,  8, 11])

使用 C 顺序数组:

In [80]: a=np.arange(12).reshape(3,4)

In [81]: np.tile(a,[2,1,1]).flatten()
Out[81]: 
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,  0,  1,  2,  3,  4,
        5,  6,  7,  8,  9, 10, 11])

最后一个与 Octave 布局相匹配。

也是:

In [83]: a=np.arange(12).reshape(3,4,order='F')

In [84]: np.tile(a[:,:,None],[1,1,2]).flatten(order='F')
Out[84]: 
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,  0,  1,  2,  3,  4,
        5,  6,  7,  8,  9, 10, 11])

迷茫了吗?