Подтвердить что ты не робот

Среднее взвешенное скользящее среднее в python

У меня есть данные, отобранные по существу случайными интервалами. Я хотел бы вычислить взвешенное скользящее среднее с использованием numpy (или другого пакета python). У меня есть грубая реализация скользящей средней, но мне трудно найти хороший способ сделать взвешенную скользящую среднюю, так что значения в центре бункера взвешиваются больше, чем значения по краям.

Здесь я генерирую некоторые данные образца, а затем беру скользящее среднее. Как я могу наиболее легко реализовать взвешенную скользящую среднюю? Спасибо!

import numpy as np
import matplotlib.pyplot as plt

#first generate some datapoint for a randomly sampled noisy sinewave
x = np.random.random(1000)*10
noise = np.random.normal(scale=0.3,size=len(x))
y = np.sin(x) + noise

#plot the data
plt.plot(x,y,'ro',alpha=0.3,ms=4,label='data')
plt.xlabel('Time')
plt.ylabel('Intensity')

#define a moving average function
def moving_average(x,y,step_size=.1,bin_size=1):
    bin_centers  = np.arange(np.min(x),np.max(x)-0.5*step_size,step_size)+0.5*step_size
    bin_avg = np.zeros(len(bin_centers))

    for index in range(0,len(bin_centers)):
        bin_center = bin_centers[index]
        items_in_bin = y[(x>(bin_center-bin_size*0.5) ) & (x<(bin_center+bin_size*0.5))]
        bin_avg[index] = np.mean(items_in_bin)

    return bin_centers,bin_avg

#plot the moving average
bins, average = moving_average(x,y)
plt.plot(bins, average,label='moving average')

plt.show()

Выход: Data and moving average

Используя совет crs17 для использования "weights =" в функции np.average, я подошел к средневзвешенной функции, которая использует функцию Гаусса для взвешивания данных:

def weighted_moving_average(x,y,step_size=0.05,width=1):
    bin_centers  = np.arange(np.min(x),np.max(x)-0.5*step_size,step_size)+0.5*step_size
    bin_avg = np.zeros(len(bin_centers))

    #We're going to weight with a Gaussian function
    def gaussian(x,amp=1,mean=0,sigma=1):
        return amp*np.exp(-(x-mean)**2/(2*sigma**2))

    for index in range(0,len(bin_centers)):
        bin_center = bin_centers[index]
        weights = gaussian(x,mean=bin_center,sigma=width)
        bin_avg[index] = np.average(y,weights=weights)

    return (bin_centers,bin_avg)

Результаты выглядят хорошо: Working weighted average using numpy

4b9b3361

Ответ 1

Вы можете использовать numpy.average, который позволяет указать вес:

>>> bin_avg[index] = np.average(items_in_bin, weights=my_weights)

Итак, чтобы рассчитать весы, вы можете найти координаты x каждой точки данных в бункере и вычислить их расстояния до центра бункера.

Ответ 2

Это не даст точного решения, но это сделает вашу жизнь проще и, вероятно, будет достаточно хороша... Во-первых, сравните свои образцы в маленьких корзинах. После того, как вы переконфигурировали свои данные для выравнивания, вы можете использовать трюки с шагами и np.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

Теперь вы можете сделать что-то вроде этого:

#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()

enter image description here