7
$\begingroup$

I have a 2D dataset like this one: {{x1,y1}, {x2,y2},...} I need to smooth/histogram the data in such a way that binning is over the x-coordinate, while counting/height is over the y-coordinate. Let me explain.

Given the following input, bin-width = 0.2 and height-function = Mean[].

data = {{0.1,1.0}, {0.2,2.0}, {0.3,3.0}, {0.35,3.5}, {0.4,4.0}, {0.5,5.0}};

The output would be:

{(1 + 2)/2, (3 + 3.5 + 4)/3, 5/1}

The average of y-values from the first two data points goes into the first bin, the following three points form the second bin etc...

$\endgroup$

4 Answers 4

7
$\begingroup$

Let's start with your sample data:

In[1]:= data = {{0.1, 1.0}, {0.2, 2.0}, {0.3, 3.0}, {0.35, 3.5}, {0.4, 4.0}, {0.5, 5.0}};

First we can use GatherBy to group entries by bin:

In[2]:= GatherBy[data, Ceiling[First[#], 0.2] &]

Out[2]= {{{0.1, 1.}, {0.2, 2.}}, {{0.3, 3.}, {0.35, 3.5}, {0.4, 4.}}, {{0.5, 5.}}}

Then select the second element of each pair (Last) and calculate the means:

In[3]:= Mean[Last /@ #] & /@ %

Out[3]= {1.5, 3.5, 5.}
$\endgroup$
6
  • $\begingroup$ This method groups elements 0.29 and 0.31 -- shouldn't these be in separate bins? $\endgroup$
    – Mr.Wizard
    May 7, 2012 at 19:35
  • $\begingroup$ @Mr.Wizard No, because with a bin size of 0.2 everything between 0.2 and 0.4 should be in the same bin. I just realized though that $MachineEpsilon is too small a number to add here if the $x$-values are greater than 1. (I added a note about this.) $\endgroup$
    – Szabolcs
    May 7, 2012 at 19:37
  • $\begingroup$ If that is the intent couldn't you use Ceiling[#, 0.2]? $\endgroup$
    – Mr.Wizard
    May 7, 2012 at 19:39
  • $\begingroup$ @Mr.Wizard Yes, you are right, I fixed it. $\endgroup$
    – Szabolcs
    May 7, 2012 at 19:44
  • $\begingroup$ Voted. If the OP actually wants bins to 0.1, 0.3, 0.5 which was my own reading, this is more complicated I think. $\endgroup$
    – Mr.Wizard
    May 7, 2012 at 19:45
5
$\begingroup$

I propose:

data = {{0.1, 1.0}, {0.2, 2.0}, {0.3, 3.0}, {0.35, 3.5}, {0.4, 4.0}, {0.5, 5.0}};

Mean /@ Reap[#2 ~Sow~ Ceiling[#, 0.2] & @@@ data][[2]]
{1.5, 3.5, 5.}
$\endgroup$
2
  • $\begingroup$ +1 I had almost forgotten the "~ ~ ~ ~ " war :) $\endgroup$ May 7, 2012 at 19:59
  • $\begingroup$ @belisarius I actually started without that but then I decided to keep up my end of the game. :^) $\endgroup$
    – Mr.Wizard
    May 7, 2012 at 20:01
4
$\begingroup$

Another offering making use of BinLists:

data = {{0.1, 1.0}, {0.2, 2.0}, {0.3, 3.0}, {0.35, 3.5}, {0.4, 
    4.0}, {0.5, 5.0}};

Smoothed[data_, binSize_] := 
 With[{xs = data\[Transpose] // First, ys = data\[Transpose] // Last},
   Mean@ys[[#]] & /@ (Flatten[Map[Position[xs, #] &, #]] & /@ 
     BinLists[xs, 0.2 + $MachineEpsilon])]

Smoothed[data, 0.2]

(* ->  {1.5, 3.5, 5.}  *)
$\endgroup$
0
$\begingroup$

An alternative way to use BinLists:

Mean /@ (Join @@ BinLists[data, .2 + $MachineEpsilon,
  Max[data[[All, 2]]] + 1][[All, All, All, -1]])

{1.5, 3.5, 5.}

$\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.