You use the generator expression in your understanding of the list:
sum(samples[ij] for j in range(n))
Generator expressions require creating a new frame each time it starts, like a function call. It is relatively expensive.
You do not need to use a generator expression at all; all you need to do is slice the samples list:
sum(samples[i - n + 1:i + 1])
You can specify the second argument, the start value for the sum() function; set 0.0 to get a floating point result:
sum(samples[i - n + 1:i + 1], 0.0)
Together, these changes matter:
>>> from timeit import timeit >>> import random >>> testdata = [i*random.random() for i in range(1000)] >>> def slow_moving_average(samples, n=3): ... return [float(sum(samples[ij] for j in range(n)))/n for i in range(n-1, len(samples))] ... >>> def fast_moving_average(samples, n=3): ... return [sum(samples[i - n + 1:i + 1], 0.0) / n for i in range(n-1, len(samples))] ... >>> def verbose_moving_average(samples, n=3): ... l =[] ... for i in range(n-1, len(samples)): ... x = 0.0 ... for j in range(n): ... x+= samples[ij] ... l.append(x / n) ... return l ... >>> timeit('f(s)', 'from __main__ import verbose_moving_average as f, testdata as s', number=1000) 0.9375386269966839 >>> timeit('f(s)', 'from __main__ import slow_moving_average as f, testdata as s', number=1000) 1.9631599469939829 >>> timeit('f(s)', 'from __main__ import fast_moving_average as f, testdata as s', number=1000) 0.5647804250038462
source share