patterncsharpMinor
Moving average calculation
Viewed 0 times
calculationmovingaverage
Problem
I am hoping to make this method run a little faster. I typically need to run this on a list with more than 100000 entries. Note that at the start and end of the list, I wish to weight the average so that it is closer to the start or end value, hence the smaller framesize.
public PointPairList GetMovingAverage(int frameSize, PointPairList data)
{
PointPairList movAvgPoints = new PointPairList();
//Smooth each point in the list
for (int i = 0; i = data.Count)
{
actualFrameSize = frameSize + (data.Count - 1 - end);
}
//Now get the sum of the window
double sum = data.Skip(start).Take(actualFrameSize).Sum(p => p.Y);
//add the average point to the result
movAvgPoints.Add(new PointPair(data[i].X, sum/actualFrameSize));
}
return movAvgPoints;
}Solution
Skip() is not optimized for IList, it always enumerates the skipped elements. This means that your algorithm is O(n2) for no good reason. What you should do instead is to manually iterate just the required part of the input in each iteration using for. Something like:double sum = 0;
for (int i = 0; i < actualFrameSize; i++)
{
sum += data[start + i].Y;
}(I don't like using
GetRange() for this, as in tinstaafl's answer, because it unnecessarily copies the frame into a new list.)If
frameSize is large, another optimization would be not to recompute the sum of the frame for each index. Instead, just add the item from the front and subtract the item from the back:public PointPairList GetMovingAverage(int frameSize, PointPairList data)
{
var movAvgPoints = new PointPairList();
//Before zero
int currentFrameSize = frameSize/2;
double sum = data.Take(currentFrameSize).Sum(p => p.Y);
//Smooth each point in the list
for (int i = 0; i = 0)
{
sum -= data[removed].Y;
currentFrameSize--;
}
if (added < data.Count)
{
sum += data[added].Y;
currentFrameSize++;
}
movAvgPoints.Add(new PointPair(data[i].X, sum/actualFrameSize));
}
return movAvgPoints;
}If the length of
data is n and frameSize is f, then the previous algorithm would be O(fn), but the improved one just O(n).Another thing: there is usually no need to create types that derive from
List, just use List directly.Code Snippets
double sum = 0;
for (int i = 0; i < actualFrameSize; i++)
{
sum += data[start + i].Y;
}public PointPairList GetMovingAverage(int frameSize, PointPairList data)
{
var movAvgPoints = new PointPairList();
//Before zero
int currentFrameSize = frameSize/2;
double sum = data.Take(currentFrameSize).Sum(p => p.Y);
//Smooth each point in the list
for (int i = 0; i < data.Count; i++)
{
int removed = i - (frameSize/2) - 1;
int added = i + (frameSize/2);
if (removed >= 0)
{
sum -= data[removed].Y;
currentFrameSize--;
}
if (added < data.Count)
{
sum += data[added].Y;
currentFrameSize++;
}
movAvgPoints.Add(new PointPair(data[i].X, sum/actualFrameSize));
}
return movAvgPoints;
}Context
StackExchange Code Review Q#39439, answer score: 9
Revisions (0)
No revisions yet.