Reputation: 501
I have the following problem: Given a matrix A
A = [ 1 2 2 3 3 ;
2 2 2 7 9 ]
where the sequence of unique numbers within the matrix is not continuous. In this example
unique(A) = [ 1 2 3 7 9 ]. % [ 4 5 6 8 ] are missing
I want to compute the same matrix, but using instead a continuous sequence, such that
unique(A_new) = [ 1 2 3 4 5 ];
I came up with the following solution
T = [ unique(A), [ 1:numel(unique(A)) ]' ];
A_new = zeros(size(A));
for i = 1:size(T,1)
A_new( A == T(i,1) ) = T(i,2);
end
This is incredibly slow: the size of the matrix A I have to work with is 200x400x300 and the the number of unique elements within this matrix is 33406.
Any idea on how to speed up the procedure?
Upvotes: 1
Views: 71
Reputation: 112679
This should be pretty fast, but it uses more memory:
[~, A_new] = max(bsxfun(@eq, A(:).', unique(A(:))));
A_new = reshape(A_new, size(A));
How does this work?
First A
is linearized into a vector (A(:)
). Also, a vector containing the unique values of A
is computed (unique(A(:))
). From those two vectors a matrix is generated (with bsxfun
) in which each entry of A
is compared to each of the unique values. That way, for each entry of A
we know if it equals the first unique value, or the second unique value, etc. For the A
given in your question, that matrix is
1 0 0 0 0 0 0 0 0 0
0 1 1 1 1 1 0 0 0 0
0 0 0 0 0 0 1 0 1 0
0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 1
So for example, the value 1
in entry (2,3) indicates that the third value of A(:)
equals the second unique value of A
(namely 2
). The 1
in the lower-right entry (5,10) indicates that the tenth value of A(:)
is the fifth unique value of A
(which is 9
).
Now the second output of max
is used to extract the row position of the 1
value in each columnn (i.e. to obtain the numbers indicating "second", "fifth" etc in the above example)). These are the desired results. It only remains to reshape
them into the shape of A
.
The third output of unique
does what you want:
[~, ~, labels] = unique(A);
A_new = reshape(labels, size(A));
Upvotes: 1
Reputation: 272507
If I understand correctly, in your example you want:
A_new = [ 1 2 2 3 3 ;
2 2 2 4 5 ]
So just compute a lookup table (lookup
) such that you can then do:
A_new = lookup(A);
So in your case, lookup
would be:
[ 1 2 3 0 0 0 4 0 5 ]
I'll leave the process for generating that as an exercise for the reader.
Upvotes: 1