8

Mi pregunta es similar a esta one, pero me gustaría replicar cada elemento según un recuento especificado en una segunda matriz del mismo tamaño.Replicación de matriz a nivel de elemento según un recuento

Un ejemplo de esto, decir que he tenido una serie v = [3 1 9 4], quiero usar rep = [2 3 1 5] replicar el primer elemento 2 veces, los segundos tres veces, y así sucesivamente para obtener [3 3 1 1 1 9 4 4 4 4 4].

Hasta ahora estoy usando un bucle simple para hacer el trabajo. Esto es lo que empecé con:

vv = []; 
for i=1:numel(v) 
    vv = [vv repmat(v(i),1,rep(i))]; 
end 

logré mejorar por preasignar espacio:

vv = zeros(1,sum(rep)); 
c = cumsum([1 rep]); 
for i=1:numel(v) 
    vv(c(i):c(i)+rep(i)-1) = repmat(v(i),1,rep(i)); 
end 

Sin embargo todavía siento que tiene que haber una manera más inteligente para hacer esto ... Gracias

+5

ver http://stackoverflow.com/questions/1975772/matlab-array-manipulation – Doresoom

+1

@Doresoom: pensé que había respondido a una pregunta como esto antes, pero no pudo encontrarlo. Finalmente lo busqué al mismo tiempo que tú.El título y las etiquetas eran bastante diferentes, que fue lo que lo hizo un poco difícil de encontrar. – gnovice

Respuesta

15

Aquí hay una manera que me gusta de lograr esto:

>> index = zeros(1,sum(rep)); 
>> index(cumsum([1 rep(1:end-1)])) = 1; 

index = 

    1  0  1  0  0  1  1  0  0  0  0 

>> index = cumsum(index) 

index = 

    1  1  2  2  2  3  4  4  4  4  4 

>> vv = v(index) 

vv = 

    3  3  1  1  1  9  4  4  4  4  4 

esto funciona creando primero un vector de índice de ze tiene la misma longitud que el recuento final de todos los valores. Al realizar una suma acumulativa del vector rep con el último elemento eliminado y un 1 al inicio, obtengo un vector de índices en index que muestra dónde comenzarán los grupos de valores replicados. Estos puntos están marcados con unos. Cuando se realiza una suma acumulativa en index, obtengo un vector de índice final que puedo usar para indexar en v para crear el vector de valores replicados de forma heterogénea.

+0

¿podría agregar algunos comentarios sobre cómo funciona esto? –

+0

@Nathan: Ya está por delante de ti. =) – gnovice

+1

Definitivamente una forma inteligente de usar 'cumsum' .. ¡Gracias! – merv

2

Para añadir a la lista de posibles soluciones, considere esto:

vv = cellfun(@(a,b)repmat(a,1,b), num2cell(v), num2cell(rep), 'UniformOutput',0); 
vv = [vv{:}]; 

Esto es mucho más lento que el de gnovice ..

+2

En realidad podría usar ARRAYFUN y evitar las llamadas a NUM2CELL, pero aún sería * mucho * más lento: http://stackoverflow.com/questions/1975772/matlab-array-manipulation/1975835#1975835. – gnovice

0

Lo que estamos tratando de hacer es Run- decodificación de longitud. Una utilidad de alto nivel fiable/vectorizado es la FEX submission rude():

% example inputs 
counts = [2, 3, 1]; 
values = [24,3,30]; 

el resultado

rude(counts, values) 
ans = 
    24 24  3  3  3 30 

cuenta que esta función realiza la operación opuesta, así, es decir, por longitud codifica un vector o en otro words devuelve values y el counts correspondiente.

0

accumarray función se puede utilizar para hacer que el código si ceros salida en rep array

function vv = repeatElements(v, rep) 
index = accumarray(cumsum(rep)'+1, 1); 
vv = v(cumsum(index(1:end-1))+1); 
end 

Esto funciona de forma similar a la solución de gnovice, excepto que en lugar índices se acumularon siendo asignados a 1. Esto permite omitir algunos índices (3 y 6 en el ejemplo a continuación) y eliminan los elementos correspondientes de la salida.

>> v = [3 1 42 9 4 42]; 
>> rep = [2 3 0 1 5 0]; 
>> index = accumarray(cumsum(rep)'+1, 1)' 

index = 

    0  0  1  0  0  2  1  0  0  0  0  2 

>> cumsum(index(1:end-1))+1 

ans = 

    1  1  2  2  2  4  5  5  5  5  5 

>> vv = v(cumsum(index(1:end-1))+1) 

vv = 

    3  3  1  1  1  9  4  4  4  4  4 
Cuestiones relacionadas