Search code examples
pythonsignal-processingaveragedigital-filter

calculate exponential moving average in python


I have a range of dates and a measurement on each of those dates. I'd like to calculate an exponential moving average for each of the dates. Does anybody know how to do this?

I'm new to python. It doesn't appear that averages are built into the standard python library, which strikes me as a little odd. Maybe I'm not looking in the right place.

So, given the following code, how could I calculate the moving weighted average of IQ points for calendar dates?

from datetime import date
days = [date(2008,1,1), date(2008,1,2), date(2008,1,7)]
IQ = [110, 105, 90]

(there's probably a better way to structure the data, any advice would be appreciated)


Solution

  • EDIT: It seems that mov_average_expw() function from scikits.timeseries.lib.moving_funcs submodule from SciKits (add-on toolkits that complement SciPy) better suits the wording of your question.


    To calculate an exponential smoothing of your data with a smoothing factor alpha (it is (1 - alpha) in Wikipedia's terms):

    >>> alpha = 0.5
    >>> assert 0 < alpha <= 1.0
    >>> av = sum(alpha**n.days * iq 
    ...     for n, iq in map(lambda (day, iq), today=max(days): (today-day, iq), 
    ...         sorted(zip(days, IQ), key=lambda p: p[0], reverse=True)))
    95.0
    

    The above is not pretty, so let's refactor it a bit:

    from collections import namedtuple
    from operator    import itemgetter
    
    def smooth(iq_data, alpha=1, today=None):
        """Perform exponential smoothing with factor `alpha`.
    
        Time period is a day.
        Each time period the value of `iq` drops `alpha` times.
        The most recent data is the most valuable one.
        """
        assert 0 < alpha <= 1
    
        if alpha == 1: # no smoothing
            return sum(map(itemgetter(1), iq_data))
    
        if today is None:
            today = max(map(itemgetter(0), iq_data))
    
        return sum(alpha**((today - date).days) * iq for date, iq in iq_data)
    
    IQData = namedtuple("IQData", "date iq")
    
    if __name__ == "__main__":
        from datetime import date
    
        days = [date(2008,1,1), date(2008,1,2), date(2008,1,7)]
        IQ = [110, 105, 90]
        iqdata = list(map(IQData, days, IQ))
        print("\n".join(map(str, iqdata)))
    
        print(smooth(iqdata, alpha=0.5))
    

    Example:

    $ python26 smooth.py
    IQData(date=datetime.date(2008, 1, 1), iq=110)
    IQData(date=datetime.date(2008, 1, 2), iq=105)
    IQData(date=datetime.date(2008, 1, 7), iq=90)
    95.0