# Smoothing random data with MovingAverage

If I have this kind of data:

SeedRandom;
x = RandomReal[{0, 5}, 100];
y = RandomReal[{0, 1}, 100];
ListPlot[Transpose[{x, y}], AspectRatio -> Automatic, Frame -> True,
FrameLabel -> {"x", "y"}] How can I apply MovingAverage to continously smooth the y data along x with an interval width of dx = 0.5? The variation step of dx should be 0.1.

The x intervals would be:

[0.0, 0.5]
[0.1, 0.6]
[0.2, 0.7]
...
[4.3, 4.8]
[4.4, 4.9]
[4.5, 5.0]


So for the first x interval [0.0, 0.5] the average of all y values (=yaverage1) in this range would result into the point {(0.0 + 0.5)/2, yaverage1} etc. The last x value of the averaged data would be at (4.5 +5.0)/2.

Not sure MovingAverage is the best choice here. It doesn't divide the data into bins, it just uses runs of consecutive elements. If you want to construct bins, it may be easiest to do it manually. For readability, I define it as a helper function using Select:

bin[xmin_, xmax_, l_] := Select[l, #[] >= xmin && #[] <= xmax &];


Then working with the data:

data = Transpose[{x, y}];
smoothdata =
Table[{xmin + 0.25,
Mean[Last /@ bin[xmin, xmin + 0.5, data]]}, {xmin, 0., 4.5, 0.1}];


This generates a smoothed data set as intended:

ListPlot[{data, smoothdata}, Joined -> {False, True},
AspectRatio -> Automatic, Frame -> True, FrameLabel -> {"x", "y"}] One way to do this (that does not use MovingMap directly, this is just an alternative) is to use an EventSeries and TimeSeriesAggregate.

ListPlot[{Transpose@{x, y},
TimeSeriesAggregate[EventSeries[Transpose[{x, y}]], 0.5]},
Joined -> {False, True}] Vary the 0.5 above to the time interval you would like (for instance 0.3).

You can use Normal on the resulting object from TimeSeriesAggregate[EventSeries[Transpose[{x, y}]], 0.5] to get the raw values.

However, I'm sure there's a way to do this with MovingMap, this is just a quick alternative I thought of.

• Thank you. In the documentation of TimeSeriesAggregate is written: "TimeSeriesAggregate[tseries,dt] computes the mean value of tseries over non-overlapping windows of width dt." >>> I would like that the intervall dt moves in small steps through the whole x range. I think this would produce another averaged curve, what do you think? – lio Dec 30 '18 at 12:26
• Unfortunately I haven't got a clue :) I don't know anything useful about maths, I just see WL functions and use them and hope they're right! – Carl Lange Dec 31 '18 at 16:50

This would be a good use for a BinListBy function, but Mathematica does not have one. Let's write our own:

binListsBy[data_, f_, opts___] := Module[{binBy, binning, select},
(*function f must return a list acceptable to BinLists*)
binBy = f /@ data;
(*construct bins of binBy values*)
binning = Union /@ BinLists[binBy, opts];
(*selects data elements for which f[element] is in a list*)
select[l_] := Select[data, MemberQ[l, f[#]] &];
(*use select to bin the original data according to the binning \
lists*)
select /@ binning
]


Create and bin the data:

data = {RandomReal[{0, 5}, 100], RandomReal[{0, 1}, 100]} //
Transpose;
(* bin the data by the x values *)
binnedData = binListsBy[data, #[] &, .5];


Plot it:

ListPlot@data (* take the mean of both x an y values in each bin *)
meanData = Mean /@ binnedData;
(* The means of the bins in both x and y *)
ListPlot[meanData, AxesLabel -> {"Mean X", "Mean Y"}] (* the mean y values against bin numbers *)
ListPlot[meanData[[All, 2]], DataRange -> {0, 4.5},
AxesLabel -> {"Lower bin limit", "Mean Y"}] 