matlab loops vectorization

figure title matlab



Crear un vector de índice basado en los valores de inicio y detención (2)

Aquí hay una colección de métodos:

Método 1 de https://stackoverflow.com/a/39422485/6579744 :

lo = A(:,1); up=A(:,2); index=cumsum(accumarray(cumsum([1;up(:)-lo(:)+1]),[lo(:);0]-[0;up(:)]-1)+1); index= index(1:end-1);

Método 2: esto es de https://stackoverflow.com/a/38507276/6579744 . También proporcioné la misma respuesta, pero debido a que la respuesta de Divakar es anterior a la mía, prefirió su respuesta (modificada):

start_idx = A(:,1)''; end_idx = A(:,2)''; lens = end_idx - start_idx + 1; shift_idx = cumsum(lens(1:end-1))+1; id_arr = ones(1,sum(lens)); id_arr([1 shift_idx]) = [start_idx(1) start_idx(2:end) - end_idx(1:end-1)]; index = cumsum(id_arr);

Método 3: esto es mío

N = A(:,2) - A(:,1) +1; s=cumsum([ 1; N]); index=(1:s(end)-1) -repelem(s(1:end-1),N) + repelem(A(:,1),N); %octave index=(1:s(end)-1) -repelems(s(1:end-1),[1:numel(N);N'']) + repelems(A(:,1),[1:numel(N);N'']);

Método 4 : otro usuario de este hilo por thewaywewalk

A = A.''; idx = bsxfun(@plus, A, [0; 1]); A = A(:); dA = diff(A); dA(1:2:end) = 0; idx = idx(~( [0;dA] == 1 | [dA;0] == 1 )); mask = zeros(max(A),1); mask(idx(:)) = (-1).^(0:numel(idx)-1); index = find(cumsum(mask));

Método 5 su segundo método:

index = cell2mat(arrayfun(@(n) A(n, 1):A(n, 2), 1:size(A, 1), ''uni'', 0));

Método 6 desde https://stackoverflow.com/a/39423102/6579744 :

sz= size(A, 1); index_c = cell(1,sz); for n = 1:sz index_c{n} = [A(n, 1):A(n, 2)]; end index = cell2mat(index_c);

El Método 7 solo funciona en Octave:

idx = 1:size(A ,1); index_a =bsxfun(@(a,b) (a(b):A (b,2))'',A (:,1),idx); index = index_a(index_a ~= 0);

Método 8 su primer método:

index = []; for n = 1:size(A, 1) index = [index A(n, 1):A(n, 2)]; end

Datos de prueba:

i= 1:500:10000000; j= i+randi([1 490],1, numel(i)); A = [i'', j''];

El resultado probado en Octave, en Matlab puede ser diferente

method1: 0.077063 seconds method2: 0.094579 seconds method3: 0.145004 seconds method4: 0.180826 seconds method5: 0.317095 seconds method6: 0.339425 seconds method7: 3.242287 seconds method8: doesn''t complete in 15 seconds

el código que se usó en bechmark está en Demo en línea

Esta pregunta ya tiene una respuesta aquí:

Basado en una matriz que contiene varias filas del comienzo (primera columna) y el final (segunda columna) de un intervalo de índice, me gustaría crear un vector de todo el índice. Por ejemplo, si A = [2 4; 8 11 ; 12 16] A = [2 4; 8 11 ; 12 16] A = [2 4; 8 11 ; 12 16] , me gustaría tener el siguiente index = [2 3 4 8 9 10 11 12 13 14 15 16] vectorial index = [2 3 4 8 9 10 11 12 13 14 15 16] .

Estoy buscando la forma más rápida de hacerlo. Por ahora, encontré solo dos posibilidades:

1) con un bucle

index = []; for n = 1:size(A, 1) index = [index A(n, 1):A(n, 2)]; end

2) con arrayfun

index = cell2mat(arrayfun(@(n) A(n, 1):A(n, 2), 1:size(A, 1), ''uni'', 0));

Curiosamente, arrayfun es mucho más rápido que la versión de bucle, y no sé por qué. Además, uso una conversión de celda a alfombra, así que eso es extraño. ¿Qué piensas sobre eso? ¿Tienes otras sugerencias?

Gracias por tu ayuda


Difícil decir qué tan rápido es eso, al menos no hay bucle:

A = [1,3;11,13;31,33;41,42;51,54;55,57;71,72]; %// prepare A A = A.''; %// create index matrix idx = bsxfun(@plus, A, [0; 1]); %// special case: 54 and 55 are basically superfluous %// need to be removed, but 71 and 72 shouldn''t A = A(:); dA = diff(A); dA(1:2:end) = 0; idx = idx(~( [0;dA] == 1 | [dA;0] == 1 )); %// create mask mask = zeros(max(A),1); mask(idx(:)) = (-1).^(0:numel(idx)-1); %// index vector out = find(cumsum(mask))

out.'' = 1 2 3 11 12 13 31 32 33 41 42 51 52 53 54 55 56 57 71 72