0

First time Python user and I am lost. I need to create a table from a list that displays the daily temperature and the running average of temperature up to that day.

xData = arange(1,32)    
tData = [86,87,84,86,86,86,84,83,90,89,88,85,86,79,83,81, \
     75,80,81,85,81,88,89,87,84,85,86,88,88,90,90]
avg = [86.]  # First value for monthly avg high temp is just the Day 1 temp
  • 3
    Where are you stuck? What have you tried? – Blender Sep 10 '13 at 01:22
  • I'm just not sure how to start, to make it a running average. I know how to do a "regular" average, I just don't know how to make it a "running average" – user2763241 Sep 10 '13 at 01:24
  • What version of Python? If you can wait for 3.4, just `import statistics` and it's a one-liner. For 3.1-3.3, you can use [the backport](https://pypi.python.org/pypi/stats/) on PyPI. Otherwise, you have to write a few lines of code. – abarnert Sep 10 '13 at 01:25

4 Answers4

5

A running average is just, for each value in a list, the average of all of the values up to that one. For a stripped-down version of your example:

>>> tData = [86,87,84,86]

The running averages are 86/1, (86+87)/2, (86+87+84)/3, and (86+87+84+86)/4.

So, at each index, the running average is the running total, dividing by (index + 1).

You can get the running totals with accumulate:

>>> list(accumulate(tData))
[86, 173, 257, 343]

And you can get the (1-based) indexes with enumerate:

>>> list(enumerate(accumulate(tData, start=1))
[(1, 86), (2, 73), (3, 257), (4, 343)]

So, just divide:

>>> [total / index for index, total in enumerate(accumulate(tData, start=1))]
[86.0, 86.5, 85.66666666666667, 85.75]

Or using statistics in Python 3.4, or its backport/predecessor stats for 3.1-3.3:

>>> from stats import running_average
>>> running_average(tData)
[86, 86.5, 85.66666666666667, 85.75]

Of course you can always do it explicitly if you prefer:

>>> running_sum, running_sums = 0, []
>>> for value in tData:
...     running_sum += value
...     running_sum.append(running_sum)
>>> [value / index for index, value in enumerate(running_sums, start=1)]
[86, 86.5, 85.66666666666667, 85.75]

… or even:

>>> running_sum, running_averages = 0, []
>>> for index, value in enumerate(tData, start=1):
...     running_sum += value
...     running_averages.append(running_sum / index)
>>> running_averages
[86, 86.5, 85.66666666666667, 85.75]
abarnert
  • 354,177
  • 51
  • 601
  • 671
  • 2
    +1. `enumerate` accepts a second argument for a starting value. If you start at 1 then you don't need to add it later. Very up to date with the `statistics` module. Do you lurk on the python dev mailing list? – Steven Rumbalski Sep 10 '13 at 01:52
  • 1
    @StevenRumbalski: Thanks. I don't know how I forgot about the `start` parameter, but I've updated the answer. And I skim both python-dev and python-ideas to keep up, and also occasionally look for new stuff on the PEP list. Even rejected proposals often include interesting ideas… – abarnert Sep 10 '13 at 17:37
0

I'd go with this:

def runningAvgs(data):
    avg = data[0]
    for i, d in enumerate(data[1:], start=1):
        yield avg
        avg = ((i * avg) + d) / (i + 1.0)
    yield avg

tData = [86,87,84,86,86,86,84,83,90,89,88,85,86,79,83,81, \
     75,80,81,85,81,88,89,87,84,85,86,88,88,90,90]

print list(runningAvgs(tData))
hughdbrown
  • 47,733
  • 20
  • 85
  • 108
0

Here's another way to do it:

def cumSeries(series):
    result = [0]
    for s in series:
        result.append(s + result[-1])
    return result

def runningAvg(series):
    cs = cumSeries(series)
    return [(cs[i] - cs[0]) / float(i) for i in range(1, len(cs))]


tData = [86,87,84,86,86,86,84,83,90,89,88,85,86,79,83,81, \
     75,80,81,85,81,88,89,87,84,85,86,88,88,90,90]

print runningAvg(tData)

Using cumulative series is a very useful way of working with sums over parts of a series.

hughdbrown
  • 47,733
  • 20
  • 85
  • 108
0

Here's a way to do it using itertools and operators

from itertools import starmap, accumulate
from operator import add

def moving_average(data):
   moving_sum = enumerate(accumulate(data, add)), start=1)
   return starmap(lambda index, elem: elem / index, moving_sum)
noaoh
  • 127
  • 1
  • 1
  • 7