Una función similar a la representante de R en Matlab

Estoy buscando una función que se comporte de manera similar a la función rep en R para Matlab. Por ejemplo, con rep puedo hacer lo siguiente:

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

En matlab existe la función repmat que cumple la primera parte

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

pero no la segunda parte (o al menos no puedo entender cómo hacerlo).

¿Alguna sugerencia?

Puede reproducir la syntax de la función rep en R bastante de cerca definiendo primero una función de la siguiente manera:

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

Luego puede reproducir el comportamiento deseado llamando con un vector de fila o columna:

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

Tenga en cuenta que he usado el operador transpose (‘) en la segunda llamada para pasar la matriz de entrada como un vector de columna (una matriz de 3×1).

Hice una evaluación comparativa de esto en mi computadora portátil, y para una matriz básica con 100,000 elementos repetidos 100 veces, fue entre 2 y 8 veces más rápido que usar la opción de ceil arriba, dependiendo de si desea la primera o la segunda disposición.

Buena pregunta +1. Un método limpio de una línea para lograr esto es a través del producto tensor Kronecker, por ejemplo:

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

Entonces:

 B = 1 1 1 2 2 2 3 3 3 

ACTUALIZACIÓN: @Dan ha proporcionado una solución muy limpia que parece ser más eficiente que mi método de kron , así que revisa esa respuesta antes de salir de la página 🙂

ACTUALIZACIÓN: @bcumming también ha proporcionado una buena solución que debería escalarse muy bien cuando el vector de entrada es grande.

Si, como yo, no tienes idea de lo que es un producto tensor Kronecker, es posible que te interese esta solución más intuitiva (y en realidad creo que más rápida):

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

así que aquí usé indexación vectorial para replicar la matriz. Por ejemplo, usando los dos casos que tienes arriba podríamos hacer:

 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 

entonces la pregunta es ¿cómo hacemos un vector [1 2 3 1 2 3 1 2 3] sin la misma funcionalidad que está solicitando? Así que hice un vector con la cantidad de elementos que necesitamos, es decir, 1: 9 y luego dividimos por tres y redondeamos (es decir, intentamos ceil((1:9)/3) en la línea de comando.

Un poco de benchmarking (sé que esto debería estar en loops así que tal vez esto no sea tan preciso):

 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. 

Aquí hay una 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 

Todavía no puedo encontrar una función más simple que haga esto en un solo paso, interesada si hay una.