# ListPlot averaging over y-coordinate

I am trying to plot a list of tuples where each “x” coordinate has multiple corresponding “y” values, sort of like {{1, 0.5}, {1, 0.7}, {2, 0.8}, {2, 1.0}…}. I want to create a new list where all the “y” coordinates corresponding to a particular “x” coordinate have been averaged over. So, the previous list would be transformed into {{1, 0.6}, {2, 0.9}…}.

What is the cleanest way I can achieve this? I don’t want to write a for-loop or something like that for such a seemingly-trivial thing.

• If your list isn't already sorted then SortBy[yourlist,First] will sort by x values. Then SplitBy[thatresult,First] will break those into groups of equal x values. Then Map[Mean,thatnewresult] will give you a list of {x,yavg} for each of your x. Try that, step by step, and see the result. Or ListPlot[Map[Mean,SplitBy[SortBy[yourlist,First],First]]] Study that until you think you understand my thinking.
– Bill
Jul 29 at 2:33

TDIL that TemporalData[data] does the desired grouping/sorting/averaging when input data contains repeated time stamps.

data = {{1, a}, {1, b}, {5, w}, {2, u}, {5, x}, {5, y}, {5, z}};

TemporalData[data]["Path"]

 {{1, (a + b)/2}, {2, u}, {5, 1/4 (w + x + y + z)}}


Using example data from Bob Hanlon's answer:

SeedRandom[1234];
n = 20;
data = Sort @ Transpose[{RandomInteger[5, n], RandomReal[1, n]}];


simply use {data, TemporalData[data]} in the first argument of ListPlot:

ListPlot[{data, TemporalData[data]},
Joined -> {False, True},
PlotTheme -> "OpenMarkersThick",
PlotLegends -> {"data", "means"}]


means = TemporalData[data]["Path"]

{{0, 0.62577}, {1, 0.856999}, {2, 0.684749}, {3, 0.329375},
{4, 0.255957}, {5, 0.414358}}


This matches the data set obtained using methods suggested in Bob Hanlon's and upbdqn's answers and Bill's comment:

TemporalData[data]["Path"] ==
Map[Mean] @ GatherBy[data, First] ==
Values @ GroupBy[data, First, Mean] ==
Map[Mean] @ SplitBy[Sort@data, First] ==
KeyValueMap[List] @ Merge[Mean] @ MapApply[Rule] @ data

True


You can also use GroupBy:

Using the same toy data:

SeedRandom[1234];
n = 20;
data = Sort@Transpose[{RandomInteger[5, n], RandomReal[1, n]}];


Using GroupBy:

gb = GroupBy[data, First, {#[[1, 1]], Mean@#[[All, 2]]} &];
ListPlot[{data, Values[gb]}, Joined -> {False, True},
PlotTheme -> "OpenMarkersThick"]


EDIT

See comment by @kglr (as the larst argument applies to grouped data):

gb = GroupBy[data, First, Mean];
ListPlot[{data, Values[gb]}, Joined -> {False, True},
PlotTheme -> "OpenMarkersThick"]

• you could also use GroupBy[data, First, Mean]
– kglr
Jul 29 at 5:05
• @kglr of course, much better. Jul 29 at 6:40
\$Version

(* "13.3.0 for Mac OS X ARM (64-bit) (June 3, 2023)" *)

Clear["Global*"]

SeedRandom[1234];

n = 20;

data = Sort@Transpose[
{RandomInteger[5, n], RandomReal[1, n]}]

(* {{0, 0.113153}, {0, 0.233079}, {0, 0.42294}, {0, 0.875912}, {0,
0.87966}, {0, 0.884627}, {0, 0.971018}, {1, 0.754358}, {1,
0.95964}, {2, 0.397409}, {2, 0.544858}, {2, 0.87433}, {2,
0.922399}, {3, 0.329375}, {4, 0.0542848}, {4, 0.254132}, {4,
0.459454}, {5, 0.0637313}, {5, 0.331812}, {5, 0.847531}} *)

{#[[1, 1]], Mean[#[[All, 2]]]} & /@ GatherBy[data, First]

(* {{0, 0.62577}, {1, 0.856999}, {2, 0.684749}, {3, 0.329375}, {4,
0.255957}, {5, 0.414358}} *)

ListPlot[{data, data2},
Joined -> {False, True},
PlotMarkers -> Automatic]
`