select elements of matrix from indices defined in an array

2 visualizzazioni (ultimi 30 giorni)
Say I have a 4x3 matrix of non-zero elements (A):
A = (0.1299 0.3371 0.5285
0.5688 0.1622 0.1656
0.4694 0.7943 0.6020
0.0119 0.3112 0.2630)
and two 1x3 arrays B and C such as:
B = (1 2 4)
C = (2 3 4)
I would like to build a matrix D that selects rows 1 to 5 from column 1, 2 to 3 from column 2 and row 4 from column 3...
D = (0.1299 0 0
0.5688 0.1622 0
0 0.7943 0.6020
0 0 0)
I am using a for loop to do it which is quite inefficient.. Any suggestions? Thanks!
  2 Commenti
per isakson
per isakson il 11 Ago 2017
"for loop to do it which is quite inefficient" Are you sure?
Jan
Jan il 12 Ago 2017
Modificato: Jan il 12 Ago 2017
You mean: "Rows 1 to 2 from column 1."
In the example you have chosen the 3. row of column 3, not the 4th one.
It is a good strategy to post the data in valid Matlab syntax to allow for an easy using to test the suggested solutions: It is not much work to replace the parenthesis by square brackets for valid Matlab matrices. But if you do this, it has to be done once only.
Please check your question before posting. It is not efficient, if the readers guess the details.
If you post your code, we could see the problem of the loop method.

Accedi per commentare.

Risposta accettata

Jan
Jan il 12 Ago 2017
Modificato: Jan il 12 Ago 2017
Nope, a loop is efficient here:
A = [0.1299 0.3371 0.5285; ...
0.5688 0.1622 0.1656; ...
0.4694 0.7943 0.6020; ...
0.0119 0.3112 0.2630];
B = [1 2 4];
C = [2 3 4];
D = zeros(size(A));
for k = 1:numel(B)
D(B(k):C(k), k) = A(B(k):C(k), k);
end
A vectorized version:
[s1, s2] = size(A);
sp = [s1 + 1, s2];
M = zeros(sp);
M(sub2ind(sp, B, 1:s2)) = 1;
M(sub2ind(sp, C + 1, 1:s2)) = -1;
M = cumsum(M(1:s1, :), 1);
D = A .* M;
Some timings (R2016b, Win7/64, Core2Duo):
A = rand(1000, 1000);
BB = randi(1000, 1, 1000);
CC = randi(1000, 1, 1000);
B = min(BB, CC);
C = max(BB, CC);
tic; for q = 1:100; D = fcn(A, B, C); end, toc
Elapsed time is 1.052819 seconds. % Loop
Elapsed time is 2.604761 seconds. % Vectorized
The creation of the index matrix M and the multiplication A .* M is expensive, but the copy of memory blocks in the loop method is cheap.
Note: The indexing in D(B(k):C(k), k) is very efficient, because Matlab does not create the vector B(k):C(k) explicitly. This saves temporary memory and reduce the number of out-of-range checks, because only the first and the last element are checked. In opposite to this, the [ ] operator does create the temporary index vectors:
for k = 1:numel(B)
D([B(k):C(k)], k) = A([B(k):C(k)], k);
end
% Elapsed time is 1.634790 seconds.
or
for k = 1:numel(B)
v = B(k):C(k);
D(v, k) = A(v, k);
end
% Elapsed time is 1.458995 seconds.
Avoid the use of unnecessary square brackets.
  1 Commento
jsaez
jsaez il 12 Ago 2017
Thanks! I was negatively biased against the 'for loop'.. I assumed that a vectorized solution will always be more efficient and I was wrong.
PS. Sorry for the typos and for forgetting about inserting the code I had :(.

Accedi per commentare.

Più risposte (0)

Categorie

Scopri di più su Loops and Conditional Statements in Help Center e File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by