I have data sampled at essentially random intervals. I would like to compute a weighted moving average using numpy (or other python package). I have a crude implementation o
This won't give an exact solution, but it will make your life easier, and will probably be good enough... First, average your samples in small bins. Once you have resampled your data to be equispaced, you can use stride tricks and np.average
to do a weighted average:
from numpy.lib.stride_tricks import as_strided
def moving_weighted_average(x, y, step_size=.1, steps_per_bin=10,
weights=None):
# This ensures that all samples are within a bin
number_of_bins = int(np.ceil(np.ptp(x) / step_size))
bins = np.linspace(np.min(x), np.min(x) + step_size*number_of_bins,
num=number_of_bins+1)
bins -= (bins[-1] - np.max(x)) / 2
bin_centers = bins[:-steps_per_bin] + step_size*steps_per_bin/2
counts, _ = np.histogram(x, bins=bins)
vals, _ = np.histogram(x, bins=bins, weights=y)
bin_avgs = vals / counts
n = len(bin_avgs)
windowed_bin_avgs = as_strided(bin_avgs,
(n-steps_per_bin+1, steps_per_bin),
bin_avgs.strides*2)
weighted_average = np.average(windowed_bin_avgs, axis=1, weights=weights)
return bin_centers, weighted_average
You can now do something like this:
#plot the moving average with triangular weights
weights = np.concatenate((np.arange(0, 5), np.arange(0, 5)[::-1]))
bins, average = moving_weighted_average(x, y, steps_per_bin=len(weights),
weights=weights)
plt.plot(bins, average,label='moving average')
plt.show()
You could use numpy.average which allows you to specify weights:
>>> bin_avg[index] = np.average(items_in_bin, weights=my_weights)
So to calculate the weights you could find the x coordinates of each data point in the bin and calculate their distances to the bin center.