6
$\begingroup$

We have

SeedRandom[43]; aRRay = Sort@RandomReal[1, 20]    

(*{0.042467, 0.147432, 0.196935, 0.302397, 0.303466, 0.327691, 0.35578, 
  0.469596, 0.473433, 0.473735, 0.476401, 0.542707, 0.549238, 0.756142, 
  0.760802, 0.804339, 0.825788, 0.863324, 0.890815, 0.952522}*)

Please assume an interval containing 0.1. How can we calculate the numbers of elements of aRRay in each interval. For instants, in the above case we wish to have an array you can say nUm[k] which contains:

interval = 0.1; 
(* For: [0,0.1)*)      nUm[1] = 1;
(* For: [0.1,0.2)*)    nUm[2] = 2;
(* For: [0.2,0.3)*)    nUm[3] = 0;
(*[0.3,0.4)*)          nUm[4] = 3;
(*[0.3,0.4)*)          nUm[4] = 4;
$\endgroup$
10
$\begingroup$
BinCounts[aRRay, {0, 0.4, 0.1}]
|improve this answer|||||
$\endgroup$
  • $\begingroup$ I was not familiar with this function. Amazing. $\endgroup$ – Inzo Babaria Aug 5 '17 at 2:56
  • $\begingroup$ If we have a list: {0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9} Do you know how I construct another list containing pairs: {{0,1},{0.1,2},{0.2,0},{0.3,3}....} $\endgroup$ – Inzo Babaria Aug 5 '17 at 3:12
  • $\begingroup$ I tried Transpose I think it works correctly!! $\endgroup$ – Inzo Babaria Aug 5 '17 at 3:15
8
$\begingroup$
HistogramList[aRRay, {0, .4, .1}][[2]]

{1, 2, 0, 4}

This is slower than BinCounts for regularly spaced bins:

SeedRandom[43]; aRRay = Sort@RandomReal[1, 1000000];
BinCounts[aRRay, {0, 1., .1}] // Timing

{1.093812, {99869, 99884, 100051, 100351, 99540, 99971, 99695, 99930, 100337, 100372}}

HistogramList[aRRay, {0, 1., .1}][[2]] // Timing

{1.527600, {99869, 99884, 100051, 100351, 99540, 99971, 99695, 99930, 100337, 100372}}

Slightly faster for irregular bins:

bins = Flatten[{0, Sort[RandomReal[1, 50]], 1}];
BinCounts[aRRay, {bins}] // AbsoluteTiming // First

1.667586

HistogramList[aRRay, {bins}][[2]] // AbsoluteTiming // First

1.606415

|improve this answer|||||
$\endgroup$
1
$\begingroup$

Edit: I apologise for the number of changes this post has been through.

You can do better than BinCounts and HistogramList, but only (it seems) if the range of elements of the list, and the bin widths are known in advance and can be hardwired (and much better if the list consists of Integers). But for binning lists of Reals where the range and bins are not always known in advance, it's probably best to stick with HistogramList or BinCounts.

If the intervals are always 0.1 and the list elements are always between 0 and 1 you can do:

SeedRandom[43]; aRRay = Sort@RandomReal[{0, 1}, 20];

binlist = Table[0, 10];
binlist[[#]]++ & /@ (IntegerPart[10 aRRay] + 1);
binlist


(* {1, 2, 0, 4, 4, 2, 0, 2, 4, 1} *)

This will also Compile, which can be really handy for larger lists:

histbins1 = Compile[{{list, _Real, 1}},
   Block[{binlist = Table[0, 10]},
    Scan[binlist[[#]]++ &, Floor[10 list] + 1];
    binlist
    ], CompilationTarget -> "C", RuntimeOptions -> "Speed"
   ];

SeedRandom[43]; aRRay = Sort@RandomReal[{0, 1}, 10000000];
First@AbsoluteTiming[res1 = BinCounts[aRRay, 0.1]]
First@AbsoluteTiming[res2 = HistogramList[aRRay, {0.1}][[2]]]
First@AbsoluteTiming[res3 = fasthist[aRRay]]
res1 == res2 == res3

(* 0.171328
   0.231146
   0.151686
   True *)

So there's a small speed up, but the interval and range are hardwired.

To generalise this effectively to different ranges and bin widths, it's worth noting that if the list consists of Integers we can do much better than BinCounts or HistogramList, both of which seem to sacrifice speed with Integers for their generality:

inthistbins = Compile[{{list, _Integer, 1}, {minmax, _Integer, 1}},
   Block[{binlist, len = minmax[[2]] - minmax[[1]] + 1, 
     offset = 1 - minmax[[1]]},
    binlist = Table[0, len];
    binlist[[# + offset]]++ & /@ list;
    binlist
    ], CompilationTarget -> "C", RuntimeOptions -> "Speed"
   ];

SeedRandom[43]; aRRay = RandomInteger[1000, 1000000];
First@AbsoluteTiming[res1 = Rest@HistogramList[aRRay, {1}][[2]];]
First@AbsoluteTiming[res2 = Rest@BinCounts[aRRay, {1}];]
First@AbsoluteTiming[res3 = inthistbins[aRRay, {0, 1000}];]
res1 == res2 == res3

(* 0.0589792
   0.0127482
   0.00230177
   True *)

So an obvious thing to try is to convert the list to Integers and do an Integer binning function:

histbins2 = 
  Compile[{{list, _Real, 1}, {minmax, _Real, 1}, {nbins, _Integer, 0}},
   Block[{binlist = Table[0, nbins], 
     intlist = 
      IntegerPart[
        nbins (list - minmax[[1]])/(minmax[[2]] - minmax[[1]])] + 1},
    Scan[binlist[[#]]++ &, intlist];
    binlist
    ], CompilationTarget -> "C", RuntimeOptions -> "Speed"
   ];

SeedRandom[43]; aRRay = Sort@RandomReal[{0, 1}, 10000000]
First@AbsoluteTiming[res4 = histbins2[aRRay, {0, 1}, 10]]

(* 0.184703 *)

Which ultimately loses out to BinCounts and the hardwired histbins1... Unless someone can give a faster way to convert list to Integers than the one I've used here.

|improve this answer|||||
$\endgroup$

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.