Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 275
Kara Avatar asked Feb 14 '13 21:02

Kara


People also ask

How does Python 3 calculate average?

Using Python sum() function len() function is used to calculate the length of the list i.e. the count of data items present in the list. Further, statistics. sum() function is used to calculate the sum of all the data items in the list. Note: average = (sum)/(count).

How do you calculate a moving average?

A simple moving average (SMA) is an arithmetic moving average calculated by adding recent prices and then dividing that figure by the number of time periods in the calculation average.

How does Python calculate Smma?

So, when there's no previous smma value, we're supposed to take the simple moving average of (src,length). The next calculations is according to (smma[1] * (length - 1) + src) / length. smmma[1] being the previous smma value.


2 Answers

An approach that avoids recomputing intermediate sums..

list=range(0,12)
def runs(v):
 global runningsum
 runningsum+=v
 return(runningsum)
runningsum=0
runsumlist=[ runs(v) for v in list ]
result = [ (runsumlist[k] - runsumlist[k-5])/5 for k in range(0,len(list)+1)]

print result

[2,3,4,5,6,7,8,9]

make that runs(int(v)) .. then .. repr( runsumlist[k] - runsumlist[k-5])/5 ) if you ant to carry around numbers a strings..


Alt without the global:

list = [float[x] for x in range(0,12)]
nave = 5
movingave = sum(list[:nave]/nave)
for i in range(len(list)-nave):movingave.append(movingave[-1]+(list[i+nave]-list[i])/nave)
print movingave 

be sure to do floating math even if you input values are integers

[2.0,3.0,4.0,5.0,6.0,7.0,8.0,9,0]
like image 148
agentp Avatar answered Oct 08 '22 20:10

agentp


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
like image 30
Martijn Pieters Avatar answered Oct 08 '22 21:10

Martijn Pieters