Moyenne mobile pondérée en python
j'ai des données échantillonnées à intervalles essentiellement aléatoires. Je voudrais calculer une moyenne mobile pondérée en utilisant numpy (ou un autre paquet python). J'ai une implémentation brute d'une moyenne mobile, mais j'ai du mal à trouver une bonne façon de faire une moyenne mobile pondérée, de sorte que les valeurs vers le centre de la cellule sont pondérées plus que les valeurs vers les bords.
ici je génère des données d'échantillon et puis je prends une moyenne mobile. Comment puis-je le plus facilement mettre en œuvre un moyenne mobile pondérée? Merci!
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()
La sortie:
utiliser la recommandation de la crs17 d'utiliser "poids=" dans le np.fonction MOYENNE, j'ai créé la fonction moyenne pondérée, qui utilise une fonction gaussienne pour pondérer les données:
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)
les résultats semblent bons:
2 réponses
Vous pouvez utiliser numpy.moyenne qui vous permet de spécifier poids:
>>> bin_avg[index] = np.average(items_in_bin, weights=my_weights)
donc pour calculer les poids vous pourriez trouver les coordonnées x de chaque point de données dans la corbeille et calculer leurs distances au centre de la corbeille.
cela ne donnera pas une solution exacte, mais cela vous facilitera la vie, et sera probablement suffisant... Tout d'abord, la moyenne de vos échantillons dans de petits bacs. Une fois que vous avez rééchantillonné vos données pour être equispaced, vous pouvez utiliser stride tricks et np.average
pour faire une moyenne pondérée:
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
Vous pouvez maintenant faire quelque chose comme ceci:
#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()