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: Data and moving average

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: Working weighted average using numpy

16
demandé sur DanHickstein 2013-08-29 21:48:14

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.

6
répondu crs17 2013-08-29 18:34:05

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

enter image description here

4
répondu Jaime 2013-08-29 18:51:15