0
$\begingroup$

If I have this kind of data:

SeedRandom[2912018];
x = RandomReal[{0, 5}, 100];
y = RandomReal[{0, 1}, 100];
ListPlot[Transpose[{x, y}], AspectRatio -> Automatic, Frame -> True, 
 FrameLabel -> {"x", "y"}]

enter image description here

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.

$\endgroup$
2
$\begingroup$

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, #[[1]] >= xmin && #[[1]] <= 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"}]

Smoothed data vs. original data plot.

$\endgroup$
3
$\begingroup$

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}]

moving map

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.

$\endgroup$
  • $\begingroup$ 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? $\endgroup$ – lio Dec 30 '18 at 12:26
  • $\begingroup$ 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! $\endgroup$ – Carl Lange Dec 31 '18 at 16:50
0
$\begingroup$

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, #[[1]] &, .5];

Plot it:

ListPlot@data

enter image description here

(* 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"}]

enter image description here

(* the mean y values against bin numbers *)
ListPlot[meanData[[All, 2]], DataRange -> {0, 4.5}, 
 AxesLabel -> {"Lower bin limit", "Mean Y"}]

enter image description here

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