select elements of matrix from indices defined in an array

2 ビュー (過去 30 日間)
jsaez
jsaez 2017 年 8 月 11 日
コメント済み: jsaez 2017 年 8 月 12 日
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 件のコメント
per isakson
per isakson 2017 年 8 月 11 日
"for loop to do it which is quite inefficient" Are you sure?
Jan
Jan 2017 年 8 月 12 日
編集済み: Jan 2017 年 8 月 12 日
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.

サインインしてコメントする。

採用された回答

Jan
Jan 2017 年 8 月 12 日
編集済み: Jan 2017 年 8 月 12 日
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 件のコメント
jsaez
jsaez 2017 年 8 月 12 日
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 :(.

サインインしてコメントする。

その他の回答 (0 件)

カテゴリ

Help Center および File ExchangeLoops and Conditional Statements についてさらに検索

Community Treasure Hunt

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

Start Hunting!

Translated by