フィルターのクリア

Extract indices of two related arrays based on uniqueness and minimum WITHOUT FOR LOOP

2 ビュー (過去 30 日間)
I have two arrays, A and B, whose indices relate to inputs of an analysis (i.e. A(1) and B(1) are two tracked outputs of run 1 of a simulation with distinct inputs, A(7) and B(7) correspond to the 7th run, whose inputs vary from all other runs).
A B
0.5 1
0.75 1
0.75 3
1 7
0.5 4
0.75 9
1 2
1 6
0.5 1
I am trying to create a vector of indices which tracks all minimum values of B for each unique value of A So from the above example the desired output is
index
1
2
8
10
*Note that if there are multiple indices which have the minimum value of B for the same value of A, i want to keep both indices.
I am currently using a for loop (below), but because my array A and B are extremely large (1*10^8 entries) it take hours to run the script
%Extract unique elements of A
Unique_A = unique(A);
%preallocate index vector for speed (no clue how big this will be so intentionally large
Alternative_index = zeros(1*10^6,1);
for i = 1:length(Unique_A)
% Find the indices of the Benefit vector which correspond to a each unique value of A
indices = find(A==Unique_A(i));
%Now determine which of the corresponding indices in B are equal to the minimum value
min_B_indices = (indices(B(indices)== min(B(indices))))
%since the index vector was pre allocated, I need to make sure I am appending the vector without overwriting entries. So determine how many entries will need to be appended:
length_of_append = length(min_B_indices)
%Now find the first zero element of the preallocated vector
first_zero = find(Alternative_index==0, 1, 'first')
%Now add the indices to the preallocated vector
Alternative_index(first_zero:first_zero+length_of_append-1,1) = min_B_indices;
end
%remove trailing zeros
Alternative_index = Alternative_index(Alternative_index~=0);
I have wracked my brain on how to do this without a for loop...anyone have a suggestion?
  3 件のコメント
Matt J
Matt J 2018 年 6 月 22 日
from the above example the desired output is index 1 2 8 10
How are you able to get an index of 10 in the example output when your A,B are only 9 elements long?
Still Learning Matlab
Still Learning Matlab 2018 年 6 月 23 日
Apologies, I meant to create 10 entries.

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

採用された回答

Jan
Jan 2018 年 6 月 22 日
編集済み: Jan 2018 年 6 月 23 日
A leaner version using a cell instead of a pre-allocation:
A = randi([1,1000], 1, 1e6);
B = randi([1,1000], 1, 1e6);
uniqA = unique(A);
OutC = cell(1, length(uniqA));
for i = 1:length(uniqA)
index = find(A == uniqA(i));
BB = B(index);
OutC{i} = index(BB == min(BB));
end
Out = cat(2, OutC{:}).';
It takes 1.60 sec instead of 2.25 sec for the original code.
But Matt J's splitapply approach takes 0.33 sec:
G = findgroups(A);
C = 1:numel(B);
OutC = splitapply(@(b,c) {c(b==min(b))}, B, C, G);
Out = cat(2, OutC{:}).';
  1 件のコメント
Jan
Jan 2018 年 6 月 23 日
編集済み: Jan 2018 年 6 月 23 日
I prefer Matt J's solution. I tried it hard to convert it to an accumarray approach, but without success.
It saves some percent to replace G = findgroups(A) by:
[sA, iSA] = sort(A);
groupA = [true, diff(sA) ~= 0];
G = cumsum(groupA);
G(iSA) = G;

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

その他の回答 (1 件)

Matt J
Matt J 2018 年 6 月 22 日
編集済み: Matt J 2018 年 6 月 22 日
G=findgroups(A);
C=(1:numel(B)).';
output = splitapply( @(b,c) {c(b==min(b))} , B,C,G),

カテゴリ

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

製品


リリース

R2018a

Community Treasure Hunt

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

Start Hunting!

Translated by