# How can I get a 'random index' of unique elements in a matrix rather than first/last index ?

2 views (last 30 days)
Varun Pai on 21 Nov 2018
Commented: Andrei Bobrov on 21 Nov 2018
For eg , I have a matrix
M = [2;2;2;2;2;1;1;1;1;3;5;5;5;5;6;6;4;4;4]
So when I apply,
[C, ia, ~] = unique(M)
I will get
C = [1;2;3;4;5;6]
ia = [6;1;10;17;11;15];
Always first index of each unique element is returned by default. If 'last' is given as argument, the last index will be returned.
Instead I would like to get random index,
For eg ,
ia = [8;3;10;19;12;16]
I tried below code snippet which works. Each time random index of unique values are returned, but as the matrix size increases the process gets slower.
M = [2;2;2;2;2;1;1;1;1;3;5;5;5;5;6;6;4;4;4]
iq = unique(M);
randIx = zeros(numel(iq,1));
idxMatrix = 1:numel(M);
for i = 1:numel(iq)
labelIdx = idxMatrix(M==iq(i));
randomLabel = randi(numel(labelIdx));
randIdx(i) =labelIdx(randomLabel);
end
randIdx
Is there a better way than this which is faster ? Please comment if you need any clarification about the question.

Bruno Luong on 21 Nov 2018
p = randperm(length(M));
[C,ia,~] = unique(M(p));
ia = p(ia)
Varun Pai on 21 Nov 2018
Short and Simple. Thank you :)
Andrei Bobrov on 21 Nov 2018
+1!

Arunkumar M on 21 Nov 2018
M = [2;2;2;2;2;1;1;1;1;3;5;5;5;5;6;6;4;4;4];
[C, ia, ~] = unique(M);
randIdx = [];
for i = 1:length(C)
randIdx = [randIdx; randi([min(find(M == C(i))) max(find(M == C(i)))],1,1)];
end
Varun Pai on 21 Nov 2018
Thank you for your time. But this would give wrong result if M is slightly changed to
M = [2;2;2;2;2;1;1;1;1;3;5;2;5;5;6;6;4;1;4];

Andrei Bobrov on 21 Nov 2018
Edited: Andrei Bobrov on 21 Nov 2018
M = [2;2;2;2;2;1;1;1;1;3;5;5;5;5;6;6;4;4;4];
[~,b,c] = unique(M);
out = round(rand(numel(b),1).*(accumarray(c,1) - 1)) + b;
M = [2;2;2;2;2;1;1;1;1;3;5;2;5;5;6;6;4;1;4];
[a,b,c] = unique(M,'stable');
[~,jj] = sort(a);
[z,ii] = sort(c);
out = ii(round(rand(numel(a),1).*(accumarray(z,1) - 1))+find([true;diff(z)==1]));
out = out(jj);
Varun Pai on 21 Nov 2018
Edited: Varun Pai on 21 Nov 2018
Thanks for your time. It works for above matrix.
Could you please check the result for M = [2;2;2;2;2;1;1;1;1;3;5;2;5;5;6;6;4;1;4] ? There is a chance that indices of certain unique elements could be missed.
When I executed your statement for
M = [2;2;2;2;2;1;1;1;1;3;5;2;5;5;6;6;4;1;4];
I got result as
out = 7
3
10
18
13
15
Here 7 and 18 corresponds to '1', whereas there is no index returned for '4'.
Edit : I got a solution. I created a new matrix initially by appending the index. I sorted the matrix based on first column. Then I applied your logic and extracted the index using 'out';
N = sortrows([M [1:numel(M)]'],1) ;
[~,b,c] = unique(N);
out = round(rand(numel(b),1).*(accumarray(c,1) - 1)) + b;
out2 = N(out,2);
Andrei Bobrov on 21 Nov 2018