2
$\begingroup$

I am currently working on a project in which I have a 10 x 2 matrix: A. I want to find the top 3 number of occurrences of each row using MATLAB.

 A = [ 1 2; 1 2; 2 4; 3 2; 3 2; 2 4; 1 2; 1 2; 5 8; 3 2]

In return I want to have:

  • [ 1 2 ], 4 times.
  • [ 3 2 ], 3 times.
  • [ 2 4 ], 2 times.

I have already tried hist3 and similar functions but couldn't get what I wanted.

P.S. My original matrix of statistics is very large (around 565000 x 2 double, depending on the image I analyze) and I am looking for around top 30 most occurred rows of it. In that case, I hardly believe if any loop based answer will cover it.

Edit: I have found the answer yesterday with the help of my professor.

What I have basically done is to set the range for hist3 on x and y axises. Let's say ( -5 : 5 ).

ctrs{1} = -5 : 5;
ctrs{2} = -5 : 5;
hist_A = hist3(A, ctrs);

Then by using sort function in descending format, I have calculated the occurrences and the indices of the elements of matrix A.

[hist_A_occurrence, hist_A_index] = sort(hist_A(:),'descend');

Finally, to pick the top 3 number of occurrences:

hist_A_index = hist_A_index(1:3);
hist_A_occurrence = hist_A_occurrence(1:3);

Performance:

It was able compute on A matrix, which is 563160 x 2, for the top 60 values in 0.147038 seconds with a Core i7 4th gen processor and 16gb ram.

The method is very quick, I hope this helps to the others.

Thank you all for the answers.

$\endgroup$
  • $\begingroup$ General programming questions are off-topic here, but can be asked on Stack Overflow. $\endgroup$ – Marcus Müller Nov 7 '17 at 20:42
  • $\begingroup$ by the way, actually stating how large "very" large is would be interesting - is it more like 1000x2, are the values integers like in your example, what are the possible values for each of these values etc. (toy examples to clarify a problem are very fine, but when it comes to performance, only an actual problem statement in the same order of complexity as your actual problem will cut it). $\endgroup$ – Marcus Müller Nov 7 '17 at 22:00
  • $\begingroup$ Sorry for the confusion, I am editing to make it more clear. $\endgroup$ – Archura Nov 7 '17 at 22:10
3
$\begingroup$

Are you looking for a specific function to perform this task? Otherwise this could probably be done with a simple for loop.

Determine your unique rows using the function

bins = unique(A, 'rows');

Then just loop through each row of A and count each instance of each bin you find in A.

This is probably good enough if you dont care about how long the program runs (which still isnt long at all if your A matrix isn't ridiculously large), but keep in mind MATLAB doesn't "like" running loops.

$\endgroup$
  • $\begingroup$ Yes, I have actually used bins = unique(A, 'rows') function, the matrix I want to search is massive. So I don't want to use a loop. $\endgroup$ – Archura Nov 7 '17 at 20:54
  • 1
    $\begingroup$ I can think of one way to do this, but will require looping through bins. Hopefully that matrix is not terribly large. Let's call each row in bins, 'b'. The following line should give you the number of times the row 'b' appears in the matrix A: > sum(sum(A == b, 2) == 2); This works because A == b gives you an 'A' sized matrix showing which values match b. We only care about the rows where both columns match b, so we sum across the columns (giving us 2 wherever there are two matches). Finally just sum the number of times we get 2; this is equivalent to counting the number of rows. $\endgroup$ – goldrik Nov 7 '17 at 21:00
  • $\begingroup$ I am sorry to say that, my matrix of the statistics is very large, and actually I am looking for top the 30 most occurred rows of it. I only kept my original answer for such a small matrix to make it simple to understand. Your contribution is much appreciated. $\endgroup$ – Archura Nov 7 '17 at 21:03
  • $\begingroup$ Try using the function accumarray(A, 1) $\endgroup$ – goldrik Nov 7 '17 at 21:12
2
$\begingroup$

The consolidator function by J. d'Errico (a solid contributor to MatlabCentral, with heavily optimized and versatile code) can be quite useful here. For your example:

nTopRepeat = 3;
[xA,yA] = consolidator(A,[],'count');
[~,idx] = sort(yA,'descend'); 
[xA(idx(1:nTopRepeat),:), yA(idx(1:nTopRepeat),:)]

I have just tried it with a large matrix as you suggest:

A = round(randn(565000,2));
nTopRepeat = 30;
[xA,yA] = consolidator(A,[],'count');
[~,idx] = sort(yA,'descend'); 
[xA(idx(1:nTopRepeat),:), yA(idx(1:nTopRepeat),:)]

This takes 0.3 seconds here. And it scales quite linearly even with $100$ times more rows. And it does loop, over replicates only.

$\endgroup$
  • 1
    $\begingroup$ Thank you very much dear Sir, I as well have just edited my question with the answer I have found myself. I believe this is a neat alternative. $\endgroup$ – Archura Nov 13 '17 at 20:37
  • $\begingroup$ I have edited and added my own values. $\endgroup$ – Archura Nov 14 '17 at 14:48
  • $\begingroup$ Are there the same with a random matrix like A = round(randn(565000,2)); $\endgroup$ – Laurent Duval Nov 14 '17 at 14:53
  • $\begingroup$ Yes, and the elements of A are generally between -25 and 25. $\endgroup$ – Archura Nov 14 '17 at 16:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.