0

I'm doing smoothing of some sequential integer data that I have in a list. My smoothing method is to replace each number with the mean of that number and its neighbors. I'm currently doing that with this code:

from statistics import mean
smoothednums = [mean(nums[:2])] + [mean(nums[i-1:i+2]) for i in range(1,len(nums))]

This has significantly increased the runtime of my script. Is there a better way to do this operation?

Colin
  • 10,447
  • 11
  • 46
  • 54

2 Answers2

2

https://docs.scipy.org/doc/numpy/reference/generated/numpy.convolve.html

You are describing convolution with a uniform (box) filter:

smoothednums = np.convolve(nums, [1/3, 1/3, 1/3]);

For larger windows, you might consider looking at the summed area table algorithm which is O(1) in window size:

Efficient summed Area Table Calculation with Numpy

Alex Taylor
  • 1,402
  • 1
  • 9
  • 15
  • Thanks. For future readers, the mode='same' parameter is required to get the same result as my original code. The default parameter will give different results. – Colin Jun 12 '19 at 21:32
0

You can avoid all slicing and copying by adding and subtracting 1/3 of each value. (Floating point error makes this not exactly equivalent to your original, but it should be close enough in normal cases.) I don’t know if it ends up faster, but it seems worth a shot:

window_mean = mean(nums[:3])
smoothednums = [mean(nums[:2]), window_mean]

for i in range(2, len(nums) - 1):
    window_mean -= nums[i - 2] / 3
    window_mean += nums[i + 1] / 3
    smoothednums.append(window_mean)

smoothednums.append(mean(nums[-2:]))
Ry-
  • 218,210
  • 55
  • 464
  • 476