简体   繁体   中英

numpy.tile did not work as Matlab repmat

According to What is the equivalent of MATLAB's repmat in NumPy , I tried to build 3x3x5 array from 3x3 array using python.

In Matlab, this work as I expected.

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

size(a_) = 3 3 5

But for 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)

If I want to generate the same array as in Matlab, what is the equivalent?

Edit 1

The output I would expect to get is

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  

but what @farenorth and the numpy.dstack give is

[[[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 functions are not, in general, 'drop-in' replacements for matlab functions. Often times there are subtle difference to how the 'equivalent' functions are used. It does take time to adapt, but I've found the transition to be very worthwhile.

In this case, the np.tile documentation indicates what happens when you are trying to tile an array to higher dimensions than it is defined,

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.

In this case, your array is being cast to a shape of [1, 3, 3] , then being tiled. So, to get your desired behavior just be sure to append a new singleton-dimension to the array where you want it,

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

Note here that I've used None (ie np.newaxis ) and ellipses notation to specify a new dimension at the end of the array. You can find out more about these capabilities here .

Another option, which is inspired by the OP's comment would be:

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

In this case, I've used tuple multiplication to 'repmat' the array, which is then constructed by np.dstack .

As @hpaulj indicated, Matlab and NumPy display matrices differently. To replicate the Matlab output you can do something like:

>>> 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]]

Good luck!

Let's try the comparison, taking care to diversify the shapes and values.

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 equivalent - more or less:

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 again, but with order F to better match the MATLAB Fortran-derived layout

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]]])

I'm adding the new numpy dimension at the start, because in many ways it better replicates the MATLAB practice of adding it at the end.

Try adding the new dimension at the end. The shape is (3,4,5), but you might not like the display.

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

Another consideration - what happens when you flatten the tile?

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

with the order F a

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])

with a C order array:

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])

This last one matches the Octave layout.

So does:

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])

Confused yet?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM