write variable how comando matlab vector repeat run-length-encoding

variable - subplot title matlab



Repita los elementos del vector (3)

Primero piense en formar un vector de índice [1 1 1 1 1 2 2 3 3 3 4 4 5] . Ver los incrementos regulares aquí me hace pensar en cumsum: podemos obtener estos pasos colocando los que están en la ubicación correcta en un vector de ceros: [1 0 0 0 0 1 0 1 0 0 1 0 1] . Y que podemos obtener ejecutando otro cumsum en la lista de entrada. Después de ajustar por las condiciones finales y la indexación basada en 1, obtenemos esto:

B(cumsum(r) + 1) = 1; idx = cumsum(B) + 1; idx(end) = []; A(idx)

Tengo un vector de valor A contiene elementos i , por ejemplo:

A = [0.1 0.2 0.3 0.4 0.5]; y di r = [5 2 3 2 1];

Ahora quiero crear un nuevo vector Anew contenga r(i) repeticiones de los valores i en A , tal que los primeros r(1)=5 ítems en Anew tienen valor A(1) y la longitud del nuevo vector es sum(r) . Así:

Anew = [0.1 0.1 0.1 0.1 0.1 0.2 0.2 0.3 0.3 0.3 0.4 0.4 0.5]

Estoy seguro de que esto se puede hacer con una combinación complicada for bucle, por ejemplo repmat , pero ¿hay alguna posibilidad de que alguien sepa cómo hacerlo de una manera más suave?


bsxfun basado en bsxfun -

A = [0.1 0.2 0.3 0.4 0.5] r = [5 2 3 2 1] repeats = bsxfun(@le,[1:max(r)]'',r) %//'' logical 2D array with ones in each column %// same as the repeats for each entry A1 = A(ones(1,max(r)),:) %// 2D matrix of all entries repeated maximum r times %// and this resembles your repmat out = A1(repeats) %// desired output with repeated entries

En esencia, podría convertirse en un juego de dos líneas

A1 = A(ones(1,max(r)),:); out = A1(bsxfun(@le,[1:max(r)]'',r));

Salida -

out = 0.1000 0.1000 0.1000 0.1000 0.1000 0.2000 0.2000 0.3000 0.3000 0.3000 0.4000 0.4000 0.5000

Benchmarking

Algunos resultados de referencia podrían producirse para las soluciones presentadas hasta ahora.

Código de Benchmarking - Caso I

%// Parameters and input data N = 4000; max_repeat = 4000; A = rand(1,N); r = randi(max_repeat,1,N); num_runs = 10; %// no. of times each solution is repeated for better benchmarking disp(''------------------- With arrayfun'') tic for k1 = 1:num_runs Anew = arrayfun(@(x) repmat(A(x), r(x), 1), 1:numel(A), ''uni'', 0); Anew = vertcat(Anew{:}); end toc, clear Anew disp(''------------------- With cumsum'') tic for k1 = 1:num_runs B(cumsum(r) + 1) = 1; idx = cumsum(B) + 1; idx(end) = []; out1 = A(idx); end toc,clear B idx out1 disp(''------------------- With bsxfun'') tic for k1 = 1:num_runs A1 = A(ones(1,max(r)),:); out2 = A1(bsxfun(@le,[1:max(r)]'',r)); end toc

Resultados

------------------- With arrayfun Elapsed time is 2.198521 seconds. ------------------- With cumsum Elapsed time is 5.360725 seconds. ------------------- With bsxfun Elapsed time is 2.896414 seconds.

Código de Benchmarking - Caso II [Mayor tamaño de datos pero menor de r]

%// Parameters and input data N = 10000; max_repeat = 1000;

Resultados

------------------- With arrayfun Elapsed time is 2.641980 seconds. ------------------- With cumsum Elapsed time is 3.426921 seconds. ------------------- With bsxfun Elapsed time is 1.858007 seconds.

Conclusiones de los puntos de referencia

Para el case I , arrayfun parece ser el camino a seguir, mientras que para el Case II , bsxfun podría ser el arma de elección. Por lo tanto, parece que el tipo de datos con los que está tratando realmente determinará qué enfoque utilizar.


Por lo que sé, no hay una función equivalente para hacer eso en MATLAB, aunque R tiene rep que puede hacer eso por ti ... tan celoso.

En cualquier caso, la única forma en que puedo sugerir es ejecutar un bucle for con repmat como sugirió. Sin embargo, quizás pueda hacer una arrayfun si quiere hacer esto como una línea ... bueno, técnicamente es necesario hacer el procesamiento posterior para lograr esto en un solo vector. Como tal, puedes probar esto:

Anew = arrayfun(@(x) repmat(A(x), r(x), 1), 1:numel(A), ''uni'', 0); Anew = vertcat(Anew{:});

Esto esencialmente hace el bucle for y la concatenación de los vectores replicados con menos código. Pasamos por cada par de valores en A y r y escupimos vectores replicados. Cada uno de ellos estará en una matriz de celdas, por lo que se requiere vertcat para ponerlo todo en un solo vector.

Obtenemos:

Anew = 0.1000 0.1000 0.1000 0.1000 0.1000 0.2000 0.2000 0.3000 0.3000 0.3000 0.4000 0.4000 0.5000

Tenga en cuenta que otras personas han intentado algo similar a lo que está haciendo en esta publicación: una función similar a la representante de R en Matlab . Esto es esencialmente imitar la forma en que R hace un rep , ¡que es lo que quieres hacer!

Alternativa - Uso for bucles

Debido a la evaluación comparativa de @Divakar, tengo curiosidad por ver cómo la asignación previa de la matriz, luego el uso de un ciclo real for iterar a través de A r y poblarlo mediante la indexación sería un punto de referencia. Como tal, el código equivalente al anterior usando for bucles e indexación sería:

Anew = zeros(sum(r), 1); counter = 1; for idx = 1 : numel(r) Anew(counter : counter + r(idx) - 1) = A(idx); counter = counter + r(idx); end

Necesitaríamos una variable que haga un seguimiento de dónde necesitamos insertar elementos en la matriz, que se almacena en el counter . Compensamos esto por la cantidad total de elementos para replicar por número, que se almacena en cada valor de r .

Como tal, este método evita por completo el uso de repmat y simplemente utiliza la indexación para generar nuestros vectores replicados.

Benchmarking (à la Divakar)

Sobre la base del código de evaluación comparativa de Divakar, en realidad intenté ejecutar todas las pruebas en mi máquina, además del enfoque de ciclo for . Simplemente utilicé su código de evaluación comparativa con los mismos casos de prueba.

Estos son los resultados de tiempo que obtengo por algoritmo:

Caso # 1 - N = 4000 , max_repeat = 4000

------------------- With arrayfun Elapsed time is 1.202805 seconds. ------------------- With cumsum Elapsed time is 1.691591 seconds. ------------------- With bsxfun Elapsed time is 0.835201 seconds. ------------------- With for loop Elapsed time is 0.136628 seconds.

Caso # 2 - N = 10000 , max_repeat = 1000

------------------- With arrayfun Elapsed time is 2.117631 seconds. ------------------- With cumsum Elapsed time is 1.080247 seconds. ------------------- With bsxfun Elapsed time is 0.540892 seconds. ------------------- With for loop Elapsed time is 0.127728 seconds.

En estos casos, cumsum realidad supera a arrayfun ... que es lo que originalmente esperaba. bsxfun supera a todos los demás, a excepción del bucle for . Mi suposición es que con los diferentes tiempos en el arrayfun entre yo y Divakar, estamos ejecutando nuestro código en diferentes arquitecturas. Actualmente estoy ejecutando mis pruebas con MATLAB R2013a en una MacBook X 10.9.5 MacBook Pro.

Como podemos ver, el ciclo for es mucho más rápido. Sé con certeza que cuando se trata de operaciones de indexación en un bucle for , el JIT se activa y le ofrece un mejor rendimiento.