Kara Kara - 14 days ago 6
Python Question

How to calculate moving average in Python 3?

Let's say I have a list:

y = ['1', '2', '3', '4','5','6','7','8','9','10']


I want to create a function that calculates the moving n-day average.
So if
n
was 5, I would want my code to calculate the first 1-5, add it and find the average, which would be 3.0, then go on to 2-6, calculate the average, which would be 4.0, then 3-7, 4-8, 5-9, 6-10.

I don't want to calculate the first n-1 days, so starting from the nth day, it'll count the previous days.

def moving_average(x:'list of prices', n):
for num in range(len(x)+1):
print(x[num-n:num])


This seems to print out what I want:

[]
[]
[]
[]
[]

['1', '2', '3', '4', '5']

['2', '3', '4', '5', '6']

['3', '4', '5', '6', '7']

['4', '5', '6', '7', '8']

['5', '6', '7', '8', '9']

['6', '7', '8', '9', '10']


However, I don't know how to calculate the numbers inside those lists. Any ideas?

Answer

There is a great sliding window generator in an old version of the Python docs with itertools examples:

from itertools import islice

def window(seq, n=2):
    "Returns a sliding window (of width n) over data from the iterable"
    "   s -> (s0,s1,...s[n-1]), (s1,s2,...,sn), ...                   "
    it = iter(seq)
    result = tuple(islice(it, n))
    if len(result) == n:
        yield result    
    for elem in it:
        result = result[1:] + (elem,)
        yield result

Using that your moving averages is trivial:

from __future__ import division  # For Python 2

def moving_averages(values, size):
    for selection in window(values, size):
        yield sum(selection) / size

Running this against your input (mapping the strings to integers) gives:

>>> y= ['1', '2', '3', '4','5','6','7','8','9','10']
>>> for avg in moving_averages(map(int, y), 5):
...     print(avg)
... 
3.0
4.0
5.0
6.0
7.0
8.0

To return None the first n - 1 iterations for 'incomplete' sets, just expand the moving_averages function a little:

def moving_averages(values, size):
    for _ in range(size - 1):
        yield None
    for selection in window(values, size):
        yield sum(selection) / size