Currently you are calculating the mean each time in the loop, so that's slice + sum for each of the len(heightProfile) - smoothingInterval
iterations. We can remove this by calculating the mean of first smoothingInterval
items and then inside of the loop simply subtract current ith item from the sum of the previous mean and add (i + smoothingInterval)th item to the sum and calculate the mean for the current window. With this approach we can do this in almost linear time.
Also as you're using Python 2 don't forget to add this line at the top of the file, otherwise normal division will result in integer division.
from __future__ import division
You can replace:
for i in range(smoothingInterval):
heightProfile.append(heightProfile[-1])
with:
heightProfile.extend([heightProfile[-1]]*smoothingInterval)
If smoothingInterval
is very huge then consider passing a generator expression to list.extend
, but in most cases [heightProfile[-1]]*smoothingInterval
is as fast as you can get:
last_val = heightProfile[-1]
heightProfile.extend(last_val for _ in xrange(smoothingInterval))
Full Code:
from __future__ import division
def smoothen_fast(heightProfile, travelTime):
smoothingInterval = 30 * travelTime
heightProfile.extend([heightProfile[-1]]*smoothingInterval)
# Get the mean of first `smoothingInterval` items
first_mean = sum(heightProfile[:smoothingInterval]) / smoothingInterval
newHeightProfile = [first_mean]
for i in xrange(len(heightProfile)-smoothingInterval-1):
prev = heightProfile[i] # the item to be subtracted from the sum
new = heightProfile[i+smoothingInterval] # item to be added
# Calculate the sum of previous items by multiplying
# last mean with smoothingInterval
prev_sum = newHeightProfile[-1] * smoothingInterval
new_sum = prev_sum - prev + new
mean = new_sum / smoothingInterval
newHeightProfile.append(mean)
return newHeightProfile
Timing comparisons:
>>> from random import sample
>>> heightProfile = sample(xrange(1, 10**5), 10**4)
>>> travelTime = 1000
>>> %timeit smoothen(heightProfile[:], travelTime)
1 loops, best of 3: 11.3 s per loop
>>> %timeit smoothen_fast(heightProfile[:], travelTime)
100 loops, best of 3: 2.69 ms per loop
Note that in my function call I am passing a slice of the list because we are modifying the passed list object using its .extend
method, which is usually a not a good idea unless the caller expects such modifications.