A similar function to R's rep in Matlab [duplicate]
Asked Answered
G

4

21

I am looking for a function that behaves similarly to the rep function in R for Matlab. For example with rep I can do the following:

> rep(c(1,2,3),times=3)
[1] 1 2 3 1 2 3 1 2 3

> rep(c(1,2,3),each=3)
[1] 1 1 1 2 2 2 3 3 3
> 

In matlab there is the repmat function which accomplishes the first part

>> repmat([1,2,3],1,3)

ans =

     1     2     3     1     2     3     1     2     3

but not the second part (or at least I can't figure out how to do it).

Any suggestions?

Grievous answered 30/1, 2013 at 22:43 Comment(2)
Can't believe I didn't know about the each option for rep; been using a hacky one-liner all this time...Sieve
Note that since Matlab 2015a there is now a built-in function that does exactly this: repelemPadding
K
12

You can reproduce the syntax of the rep function in R fairly closely by first defining a function as follows:

function [result]=rep(array, count)
matrix = repmat(array, count,1);
result = matrix(:);

Then you can reproduce the desired behavior by calling with either a row or column vector:

>> rep([1 2 3],3)
ans =
 1     1     1     2     2     2     3     3     3

>> rep([1 2 3]',3)
ans =
 1     2     3     1     2     3     1     2     3

Note I have used the transpose (') operator in the second call to pass the input array as a column vector (a 3x1 matrix).

I benchmarked this on my laptop, and for a base array with 100,000 elements repeated 100 times, it was between 2 to 8 times faster than using the ceil option above, depending on whether you want the first or the second arrangement.

Kist answered 31/1, 2013 at 13:2 Comment(2)
Fast and simple! I'm surprised repmat is the winner, but it definitely seems to be the best solution in this case!Padding
If implemented efficiently, repmat should be very fast, because it performs the repetition by copying memory from one location to another. Modern processors with lots of cache are quite good at this sort of thing. That is also the reason why there is such a factor of 4 speed difference between the two usage types: the fast one has stride one memory accesses, whereas the other has stride length(array) memory accesses, which are slower.Kist
S
8

Good question +1. A neat one-liner method to accomplish this is via the Kronecker tensor product, eg:

A = [1 2 3];
N = 3;
B = kron(A, ones(1, N));

Then:

B =

     1     1     1     2     2     2     3     3     3

UPDATE: @Dan has provided a very neat solution that looks to be more efficient than my kron method, so check that answer out before leaving the page :-)

UPDATE: @bcumming has also provided a nice solution that should scale very nicely when the input vector is large.

Scaife answered 30/1, 2013 at 23:3 Comment(1)
I tried to come up with a solution I could understand as I don't know what a Kronecker tensor product is. You might be interested in the result, I think it is faster than kron() although I haven't really done proper benchmarking...Padding
P
6

If like me you have no idea what a Kronecker tensor product is you might be interested in this more intuitive (and actually I think faster) solution:

c(ceil((1:length(c)*n)/n));

so here I used vector indexing to replicate the matrix. For example using the two case you have above we could do:

c = 1:3;
c([1 1 1 2 2 2 3 3 3]) %for each
c([1 2 3 1 2 3 1 2 3]) %for times

so the questions is how do we make a vector [1 2 3 1 2 3 1 2 3] without the very functionality you are requesting. So I made a vector with the number of elements we need i.e. 1:9 and then divide by three and round up (i.e. try ceil((1:9)/3) in the command line.

A bit of benchmarking (I know this stuff should be in loops so maybe this isn't so accurate):

c = 1:3; n = 3;
tic; k = kron(c, ones(1, n)); toc; % 0.000208 seconds.
tic; a = c(ceil((1:length(c)*n)/n)); toc;  % 0.000025 seconds.
clear;
c = 1:1000000; n = 3;
tic; k = kron(c, ones(1, n)); toc; % 0.143747 seconds.
tic; a = c(ceil((1:length(c)*n)/n)); toc;  % 0.090956 seconds.
clear;
c = 1:10000; n = 1000;
tic; k = kron(c, ones(1, n)); toc; % 0.583336 seconds.
tic; a = c(ceil((1:length(c)*n)/n)); toc;  % 0.237878 seconds.
Padding answered 31/1, 2013 at 6:50 Comment(4)
Very neat +1! I verified your speed tests on my machine and added some loops, and the results you are getting are fairly representative. Typically, I was finding your method to be about 4 times faster than kron. More intuitive though? I think that's in the eye of the beholder :-) Kronecker products are conceptually very simple, once one has gone through the initial cost of working out how they work...Scaife
Yeah fair enough - I guess it's just the name, it has the word tensor in it therefore it scares me :)Padding
Well it definitely works in my smaller example but I want something that actually works for "irregular" vector. For example, a vector like c = [1.34,9.2,-8.2,99]Grievous
It works for any vector, even text. It definitely works on the vector in your comment. It will even work on this: n=3; c = 'wowee!'; c(ceil((1:length(c)*n)/n))Padding
U
1

Here's one idea:

a=[1,2,3];
reshape(repmat(a,1,length(a)),1,length(a)^2)

ans =

 1     2     3     1     2     3     1     2     3

reshape(repmat(a,length(a),1),1,length(a)^2)

ans =

 1     1     1     2     2     2     3     3     3

I can't yet find a simpler function that does this in one step, interested if there is one though.

Unmeaning answered 30/1, 2013 at 22:53 Comment(1)
There is a simpler one-step function: kron (the Kronecker tensor product). I've added an answer with an example. Cheers.Scaife

© 2022 - 2024 — McMap. All rights reserved.