viernes, 8 de abril de 2016

LINQ Recipe No. 2-7: Mathematics and Statistics - How to Find Moving Averages?

Contents

1. Introduction
2. Key Words
3. Problem
4. Solution
5. Discussion
5.1 Moving average
5.2 Average() LINQ standard query operator
6. Practice: Finding Moving Averages
7. Conclusions
8. Literature & Links

1. Introduction

In this new LINQ recipe we will learn about moving averages. First, we will understand what is a moving average in the Discussion section. Then, in the Practice section, we will reinforce the concept with an example which demonstrate how to find the moving averages of a set of 5 double values stored in a list.

2. Key Words

  • Average
  • Moving average
  • LINQ
  • Rolling average
  • Running average
  • Standard query operator

3. Problem

Calculate the moving averages of the [1, 2, 3, 4, 5] list using LINQ.

4. Solution

LINQ offers to the programmer the standard query operator Average() to calculate the average of a particular set of numerical values.

5. Discussion

5.1 Moving average

The moving average (or rolling average or running average) ("Moving average", 2016) is a computation to analyze a set of data values by calculating the average of all of the subset of values starting with the first one, and shifting forward one step -position- at time:
Moving average graphical representation
Illustration 1. Moving averages graphical representation.
How this works? In the first row (Illustration 1) we first calculate the average of values a and b; for this case, only just two values are selected, but also 3, 4 or 5 values can be averaged. Given that the moving window is set to 2, in the second row the average calculation for values b and c is performed. This process continues before the size of the array is overcomed.

Before get into the Practice section, we are going to compute the moving averages for the given list of double values:

[1, 2, 3, 4, 5]
  • First average: (1+2)/2 = 3/2 = 1.5
  • Second average: (2+3)/2 = 5/2 = 2.5
  • Third average: (3+4)/2 = 7/2= 3.5
  • Fourth average: (4+5)/2 = 9/2 = 4.5

5.2 Average() LINQ standard query operator

The Average() ("Enumerable.Average Method", 2016) LINQ standard query operator (LSQO) computes the average of a sequence of numerical values. This method has 20 overloaded versions for different numerical types: Decimal, Double, Int32, Int64, etcetera.

With the set of floating point values, represented with the list grades 

List<int> grades = new List<int> { 37, 71, 31, 19, 29 };

its average is calculated by calling the Average() method as follows 

double average = grades.Average();

6. Practice: Finding Moving Averages


Now we are going to compute the moving averages for the list of double values. These values represent grades for a student. In a general way, this is the graphical representation for the moving averages computation:
Moving averages for a list of numbers
Illustration 2. Moving averages for a list of numbers.
Now, with LSQO methods we have the following code 

// List of grades:
List<double> grades = new List<double>(){1, 2, 3, 4, 5};

// List of moving averages for the grades:
List<double> movingAvgGrades = new List<double>();

// Set the window size:
int windowSize = 2;

Enumerable.Range(0, grades.Count - windowSize + 1)
.ToList()
.ForEach( gradePosition => movingAvgGrades.Add(
grades.Skip(gradePosition).Take(windowSize).Average()));

// Display the moving averages for grades:
movingAvgGrades.Dump("Moving Averages for Grades");

What LINQ does, in a general way, is this:
  1. With Range() ("Enumerable.Range() Method", 2016) method a list of integer values is generated. This list refers to the positions where each subset of values starts respect to the list grades.
  2. The ToList() ("Enumerable.ToList(TSource)", 2016) method creates a list from the recently created range: 0, 1, 2, 3.
  3. The ForEach()  ("List(T).ForEach Method", 2016) performs this calculation recursively -four times-:
    1. Skip() and Take() create the subset of values from the list of grades -grades- depending on the current position -gradePosition- and the window size -windowSize-.
    2. Once the subset is created, the Average() LSQO computes the average for the current subset.
Step 3 follows the scheme represented in Illustration 2.

Now we can proceed to execute our code in LINQPad
Moving averages for 1, 2, 3, 4, and 5 in LINQPad
Illustration 3. Moving averages for 1, 2, 3, 4, and 5 in LINQPad.

7. Conclusions

With this interesting recipe we have learned the statistical concept of moving average. In the example presented in the Practice section, we showed, explained and computed the moving or running averages for a list of 5 double values.

The next recipe will also be interesting: we will calculate the cumulative sum.

8. Literature & Links

Mukherjee, S (2014). Thinking in LINQ Harnessing the Power of Functional Programming in .NET Applications. United States: Apress.
Moving average (2016, April 8). Retrieved from: https://en.wikipedia.org/wiki/Moving_average
Enumerable.Average Method (System.Linq) (2016, April 8). Retrieved from: https://msdn.microsoft.com/en-us/library/system.linq.enumerable.average(v=vs.110).aspx
Enumerable.Range Method (Int32, Int32) (System.Linq) (2016, April 8). Retrieved from: https://msdn.microsoft.com/en-us/library/system.linq.enumerable.range(v=vs.110).aspx
Enumerable.Skip(TSource) Method (IEnumerable(TSource), Int32) (System.Linq) (2016, April 8). Retrieved from: https://msdn.microsoft.com/en-us/library/bb358985(v=vs.110).aspx
Enumerable.Take(TSource) Method (IEnumerable(TSource), Int32) (System.Linq) (2016, April 8). Retrieved from: https://msdn.microsoft.com/en-us/library/bb503062(v=vs.110).aspx
Enumerable.ToList(TSource) Method (IEnumerable(TSource)) (System.Linq) (2016, April 8). Retrieved from: https://msdn.microsoft.com/en-us/library/bb342261(v=vs.110).aspx
List(T).ForEach Method (Action(T)) (System.Collections.Generic) (2016, April 8). Retrieved from: https://msdn.microsoft.com/en-us/library/bwabdf9z(v=vs.110).aspx


V

No hay comentarios:

Publicar un comentario

Envíe sus comentarios, dudas, sugerencias, críticas. Gracias.