0

i tried compiling the codes below but it is not working. Basically, I want to count the number of elements in a that are less than or equal to each element in x. please help.

a = exprnd(1,10000, 1);
x = 0:0.02:10;
for i = 1:length(x);
    count = 0;
    for j = 1:length(a);
        if (a(j) <= x(i))
          count = count + 1;
        end
    end
end
shmai
  • 3
  • 1
  • Oh! I guess this could be done with `cumsum` and `histc`. – knedlsepp Jan 21 '15 at 00:15
  • Also: I have the feeling you might really be looking for [ecdf](http://mathworks.com/help/stats/ecdf.html). – knedlsepp Jan 21 '15 at 00:42
  • Please clarify on the application of this, so we can change the question title to something more easily searchable for future users. – knedlsepp Jan 21 '15 at 01:14
  • Similar questions: [1](http://stackoverflow.com/questions/3593717/given-a-vector-a-1-2-3-2-4-5-and-an-element-x-3-in-vector-a-how-to-find-th),[2](http://stackoverflow.com/questions/7041182/matlab-how-do-i-find-the-first-index-where-value-is-greater-than-threshold),[3](http://stackoverflow.com/questions/23628503/finding-indices-in-python-lists-efficiently-in-comparison-to-matlab/23629172#23629172), there is also the numpy function [searchsorted](http://docs.scipy.org/doc/numpy/reference/generated/numpy.searchsorted.html), that does something similar – knedlsepp Jan 21 '15 at 12:06
  • yes.. trying to get the cdf – shmai Jan 22 '15 at 03:19

3 Answers3

5

In your case, bsxfun() can make things easier.

You can try this:

result = sum(bsxfun(@le, a(:), x(:).'));
mehmet
  • 1,631
  • 16
  • 21
  • I think `bsxfun` is one of the only Matlabs functionality that I dont use at all, and every time I read answers in SO I think to myself: man, you are very wrong! Great answer. – Ander Biguri Jan 20 '15 at 18:54
  • @AnderBiguri - When you use it once, you never give up, be sure of that! ((: – mehmet Jan 20 '15 at 19:02
  • 1
    `bsxfun` I use often. It's very useful in image filtering. I learned how to use this efficiently from Divakar :). BTW, +1. – rayryeng Jan 20 '15 at 20:14
  • @rayryeng - We got masters here :D It's so useful function, does same work with loops as one line command. – mehmet Jan 20 '15 at 20:30
  • @mehmet - I agree with that :) One function I would also recommend learning is `accumarray`. I learned how to use this from chappjc, and a lot of the elegant solutions I have come up with use it. One of my most favourites is calculating the joint entropy between two images: http://stackoverflow.com/questions/23691398/mutual-information-and-joint-entropy-of-two-images-matlab – rayryeng Jan 20 '15 at 20:46
  • @rayryeng - I've also seen this function usage but, I haven't been acquainted with it yet. I had put it in my do list ((: – mehmet Jan 20 '15 at 20:56
  • @mehmet - Cool :) Here's another post that uses `accumarray`: http://stackoverflow.com/questions/28037513/appending-to-an-array-of-repeated-elements-in-matlab/28037661#28037661 - This one is better to read because I actually go into how `accumarray` works, and the problem to be solved is much simpler. – rayryeng Jan 20 '15 at 21:03
  • @rayryeng - Previous was hard to be adapted, better see this one. Thank you rayryeng (: – mehmet Jan 20 '15 at 21:07
  • @shmai - You' re welcome.. We were talking about how it is so useful (: It is very poweful function of MATLAB.. – mehmet Jan 22 '15 at 07:44
2

Making your approach work:

First we fix your original approach:

a = exprnd(1,10000, 1);
x = 0:0.02:10;
count = zeros(size(x)); %%// <= Preallocate the count-vector
for i = 1:length(x);
    %%// <= removed the line "count = 0"
    for j = 1:length(a);
        if (a(j) <= x(i))
          count(i) = count(i) + 1; %%// <= Changed count to count(i)
        end
    end
end

This will make your approach work. If you want to compute this for relatively large vectors a and x, this will be quite slow, as the overall complexity is O(n^2). (Assuming n==length(x)==length(a).)

You could use a different approach for faster runtimes:

Approach of complexity O(n*log(n)) using sort:

Here is an algorithm of complexity O(n*log(n)) instead of O(n^2). It is based on Matlab's sort being stable and the positions being returned. Assume x is sorted, if you then sort [a(:); x(:)], the new position of x(1) will be 1 plus the number of elements of a smaller than or equal to x(1). The new position of x(2) will be 2 plus the number of elements of a smaller than or equal to x(2). So the number of elements in a that are smaller than x(i) equals the new position of x(i) minus i.

function aSmallerThanxMat = aSmallerThanx(a, x)
%%// Remember dimension of x
dimX = size(x);
%%// Sort x and remember original ordering Ix
[xsorted, Ix] = sort(x(:));
%%// How many as are smaller than sortedX
[~,Iaxsorted] = sort([a(:); xsorted(:)]);
Iaxsortedinv(Iaxsorted) = 1:numel(Iaxsorted);
aSmallerThanSortedx = Iaxsortedinv(numel(a)+1:end)-(1:numel(xsorted));
%%// Get original ordering of x back
aSmallerThanx(Ix) = aSmallerThanSortedx;
%%// Reshape x to original array size 
aSmallerThanxMat = reshape(aSmallerThanx, dimX);

This approach might be a bit more difficult to grasp, but for large vectors, you will get a considerable speedup.

Similar approach using sort and for:

The concept of this approach is very similar, but more traditional using loops: First we sort x and a. Then we step through the x(i_x). If x(i_x) it is larger than the current a(i_a), we increment i_a. If it is smaller than the current i_a, then i_a-1 is the number of elements in a that are smaller or equal to x(i_x).

function aSmallerThanx = aSmallerThanx(a, x)
asorted = sort(a(:));
[xsorted, Ix] = sort(x(:));
aSmallerThanx = zeros(size(x));

i_a = 1;
for i_x = 1:numel(xsorted)
    for i_a = i_a:numel(asorted)+1
        if i_a>numel(asorted) || xsorted(i_x)<asorted(i_a)
            aSmallerThanx(Ix(i_x)) = i_a-1;
            break
        end
    end
end

Approach using histc:

This one is even better: It creates bins in between the values of x, counts the values of a, that fall into each bin, then sums them up beginning from the left.

function result = aSmallerThanx(a, x)
[xsorted, Ix] = sort(x(:));
bincounts = histc(a, [-Inf; xsorted]);
result(Ix) = cumsum(bincounts(1:end-1));

Comparison:

Here is a runtime comparison of your approach, Ander Biguri's for+sum loop approach, mehmet's bsxfun approach, the two approaches using sort and the histc approach: For vectors of length 16384, the histc approach is 2300 times faster than the original approach. Runtime Comparison

knedlsepp
  • 6,065
  • 3
  • 20
  • 41
  • @Divakar: Maybe a bit too much, but pushing the solutions is kind of addictive. ;-) I'm still trying to figure out a better title and description for the question, in case anyone wants to search this in the future... :-S – knedlsepp Jan 21 '15 at 11:12
  • 1
    Pushing for alternative solutions, maybe more efficient ones than already posted and learning in the process is one of the best things one gets to learn on SO. You are right about the title thing, it needs a title of more representative nature as of now. – Divakar Jan 21 '15 at 11:28
0

An easy approach using vectorization:

 count=zeros(length(x),1);  
 for ii=1:length(x)
       count(ii)=count(ii)+sum(a<=x(ii));
 end
Ander Biguri
  • 35,140
  • 11
  • 74
  • 120
  • I think the `zeros(length(x))` is a mistake, as it generates a square matrix. You could use `zeros(size(x));` instead. – knedlsepp Jan 20 '15 at 22:57