classify "rows" of numbers contained in different arrays

1 view (last 30 days)
Hi, I would need to classify "rows" of numbers contained in different arrays, and I would like to optimize the code (with a more compact one), by removing a loop for at the (step 2.2) in the following script: any idea?
Otherwise, in general, any idea about how to classify my rows in a more compact way than what I did in this entire script?
% INPUT and GOAL
% I have 4 arrays/groups which contain "rows" of numbers (e.g. A1 contains
% row "1 3" and row "2 5"). My goal would be to create a matrix which
% contains all the unique "rows" appearing in all the 4 arrays/groups,
% and for each of them I would like to know to which array/group they
% belong to (e.g. by assigning a number 1 if a row belongs to one of the 4 groups,
% and assigning a number zero if a row does not belong to a certain group)
A1 = [1 3;
2 5;
6 1;
5 9;
1 2;
3 2;];
A2 = [5 9;
6 2;
1 2;
1 3;
3 2];
A3 = [1 3;
2 5;
6 1;
5 9;
2 3;
9 7;
3 4];
A4 = [3 1;
2 5;
6 1;
5 9;
2 1;
3 2];
% OUTPUT
% (step 1) I create a matrix with unique "rows" of numbers.
% This matrix should also tell me in which of the previous 4 arrays/groups
% my unique "rows" belong to.
A = {A1, A2, A3, A4};
ur = unique(vertcat(A{:}),'rows');
for i = 1 : length(A)
[idx1,~] = ismember(ur,A{i},'row');
belong_to_group(:,i) = idx1;
end
% M1 = | unique rows | which array/group my "rows" belong to, i.e. A1, A2, A3, A4 |
M1 = [ur belong_to_group]
% in the following matrix, for example, the row "1 2" appears in the
% arrays/groups A1 and A2
M1 =
1 2 1 1 0 0
1 3 1 1 1 0
2 1 0 0 0 1
2 3 0 0 1 0
2 5 1 0 1 1
3 1 0 0 0 1
3 2 1 1 0 1
3 4 0 0 1 0
5 9 1 1 1 1
6 1 1 0 1 1
6 2 0 1 0 0
9 7 0 0 1 0
% (step 2) Then, I have noticed that - in my system - some unique rows are actually duplicate, i.e.
% row "1 2" is equivalent to "2 1", or row "1 3" is equivalent to "3 1".
% I therefore decided to condense the information contained in both duplicates into a
% single row, i.e. by summarizing the two duplicate rows in my matrix
% M1(1,:) = [1 2 1 1 0 0]
% M1(3,:) = [2 1 0 0 0 1]
% into a single row in a new matrix:
% M2(1,:) = [1 2 1 1 0 1]
% (step 2.1) get non-duplicate rows in a sub-matrix
[~,idx2] = ismember(ur,ur(:,[2,1]),'row');
array2 = [idx2 (1:length(ur))'];
M2_unique = M1(find(~idx2),:);
% (step 2.2) condense duplicate rows into single rows
j = 1;
for i = 1 : length(ur)
if array2(i,1) ~= 0
M2_repeat(j,:) = [ M1(min(array2(i,1),array2(i,2)),1:2) ...
sum([M1(min(array2(i,1),array2(i,2)),3:end);M1(max(array2(i,1),array2(i,2)),3:end)]) ];
array2(array2(i,1),1) = 0;
array2(array2(i,2),1) = 0;
j = j + 1;
end
if all(array2(:,1))
return
end
end
% (step 2.3) join non-duplicate rows with condensed duplicate rows in a new matrix
M2 = vertcat(M2_repeat,M2_unique)
M2 =
1 2 1 1 0 1
1 3 1 1 1 1
2 3 1 1 1 1
2 5 1 0 1 1
3 4 0 0 1 0
5 9 1 1 1 1
6 1 1 0 1 1
6 2 0 1 0 0
9 7 0 0 1 0
My question: How can I write the (step 2.2) in a more compact way, without using the loop for?
Otherwise, in general, any idea about how to classify my rows in a more compact way than what I did in this entire script?

Answers (2)

Binaya
Binaya on 28 Sep 2023
Edited: Binaya on 29 Sep 2023
Hi Sim,
To optimize the provided code, I suggest first merging the unique rows in “ur” and then classifying the rows according to the provided matrices. This will reduce the complexity and increase the efficiency of the code.
Please find the optimized code below:
% INPUT and GOAL
% I have 4 arrays/groups which contain "rows" of numbers (e.g. A1 contains
% row "1 3" and row "2 5"). My goal would be to create a matrix which
% contains all the unique "rows" appearing in all the 4 arrays/groups,
% and for each of them I would like to know to which array/group they
% belong to (e.g. by assigning a number 1 if a row belongs to one of the 4 groups,
% and assigning a number zero if a row does not belong to a certain group)
A1 = [1 3;
2 5;
6 1;
5 9;
1 2;
3 2;];
A2 = [5 9;
6 2;
1 2;
1 3;
3 2];
A3 = [1 3;
2 5;
6 1;
5 9;
2 3;
9 7;
3 4];
A4 = [3 1;
2 5;
6 1;
5 9;
2 1;
3 2];
% OUTPUT
% (step 1) I create a matrix with unique "rows" of numbers.
% This matrix should also tell me in which of the previous 4 arrays/groups
% my unique "rows" belong to.
A = {A1, A2, A3, A4};
ur = unique(vertcat(A{:}),'rows');
%Instead of merging the rows after classifying, first merge the rows and
%then classify. This will minimize the computation and make the code more
%efficient
ur1 = ur(:,[2,1]);
[~,idx2] = ismember(ur,ur1,'row');
nonzero = find(idx2);
for i=1:numel(nonzero)
if idx2(nonzero(i))~=0
ur(idx2(nonzero(i)),:)=[-inf,-inf];
idx2(idx2(nonzero(i)))=0;
end
end
ur;
ur = reshape(ur(ur~=-inf),[],2);
for i = 1 : length(A)
[idx1,~] = ismember(ur,A{i},'row');
[idx2,~] = ismember(ur(:,[2,1]),A{i},'row');
idx = idx1+idx2;
belong_to_group(:,i) = idx;
end
M1 = [ur belong_to_group] % M1 is the required matrix
M1 = 9×6
1 2 1 1 0 1 1 3 1 1 1 1 2 3 1 1 1 1 2 5 1 0 1 1 3 4 0 0 1 0 5 9 1 1 1 1 6 1 1 0 1 1 6 2 0 1 0 0 9 7 0 0 1 0
I hope this helps.
Regards
Binaya

Voss
Voss on 28 Sep 2023
'some unique rows are actually duplicate, i.e. row "1 2" is equivalent to "2 1", or row "1 3" is equivalent to "3 1"'
If it is always true that [a b] is equivalent to [b a] for any a and b, then you can sort each row of your A1, A2, A3, A4 matrices before anything else, and then you won't have to deal with duplicate rows at all. (Note, however, that the order of the rows in the final result may be different than you had it.)
% INPUT and GOAL
% I have 4 arrays/groups which contain "rows" of numbers (e.g. A1 contains
% row "1 3" and row "2 5"). My goal would be to create a matrix which
% contains all the unique "rows" appearing in all the 4 arrays/groups,
% and for each of them I would like to know to which array/group they
% belong to (e.g. by assigning a number 1 if a row belongs to one of the 4 groups,
% and assigning a number zero if a row does not belong to a certain group)
A1 = [1 3;
2 5;
6 1;
5 9;
1 2;
3 2;];
A2 = [5 9;
6 2;
1 2;
1 3;
3 2];
A3 = [1 3;
2 5;
6 1;
5 9;
2 3;
9 7;
3 4];
A4 = [3 1;
2 5;
6 1;
5 9;
2 1;
3 2];
A = {A1, A2, A3, A4};
% first sort each row of each Ai matrix so that, e.g.,
% [1 2] and [2 1] both become [1 2], and [1 3] and [3 1] both become [1 3], etc.
A = cellfun(@(x)sort(x,2),A,'UniformOutput',false);
% this step is effectively unchanged:
% OUTPUT
% (step 1) I create a matrix with unique "rows" of numbers.
% This matrix should also tell me in which of the previous 4 arrays/groups
% my unique "rows" belong to.
ur = unique(vertcat(A{:}),'rows');
nA = numel(A);
belong_to_group = false(size(ur,1),nA);
for i = 1:nA
belong_to_group(:,i) = ismember(ur,A{i},'row');
end
% final result (no additional steps necessary):
% M1 = | unique rows | which array/group my "rows" belong to, i.e. A1, A2, A3, A4 |
M1 = [ur belong_to_group]
M1 = 9×6
1 2 1 1 0 1 1 3 1 1 1 1 1 6 1 0 1 1 2 3 1 1 1 1 2 5 1 0 1 1 2 6 0 1 0 0 3 4 0 0 1 0 5 9 1 1 1 1 7 9 0 0 1 0

Community Treasure Hunt

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

Start Hunting!