2013-08-29 14 views
14

Mam dane próbkowane w zasadniczo losowych odstępach czasu. Chciałbym obliczyć ważoną ruchomą średnią używając numpy (lub innego pakietu python). Mam prymitywną implementację średniej ruchomej, ale mam problem ze znalezieniem dobrego sposobu na zrobienie ważonej średniej kroczącej, tak aby wartości w kierunku środka kosza były ważone bardziej niż wartości w kierunku krawędzi.Ważona średnia ruchoma w pytonie

Tutaj generuję niektóre przykładowe dane, a następnie wykonuję średnią ruchomą. Jak mogę najłatwiej wdrożyć ważoną średnią ruchomą? Dzięki!

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

Wyjście: Data and moving average

Używanie porady od crs17 używać „ciężary =” w funkcji np.average, wpadłem średnią ważoną funkcję, która korzysta z funkcji Gaussa do masy dane :

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) 

Wyniki wyglądają dobrze: Working weighted average using numpy

+0

Try wyszukiwanie informacji dotyczących wag dla cyfrowego filtra dolnoprzepustowego. –

+2

Masz już [funkcje ważone momentem wykładniczo-zwrotnym] (http://pandas.pydata.org/pandas-docs/dev/computation.html#expunktu- cjalne- ważone-moment-funkcje) realizowane w pandach. –

Odpowiedz

6

można użyć numpy.average który pozwala na określenie wagi:

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

więc obliczyć masę można znaleźć x współrzędne każdego punktu danych w kosza i obliczanie odległości do centrum bin.

+0

Tak! Nie miałem pojęcia o tej średniej funkcji i o tym, jak można ją wyważyć! Opublikowalem moje kompletne rozwiazanie na dole mojego pytania. – DanHickstein

4

Nie da to dokładnego rozwiązania, ale ułatwi ci to życie i prawdopodobnie będzie wystarczająco dobre ... Najpierw uśrednij próbki w małych pojemnikach. Po resampled dane mają być równo rozmieszczone, można użyć kroku, tym sztuczki i np.average zrobić Średnia ważona:

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 

Teraz można zrobić coś takiego:

#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

+0

Dzięki za rozwiązanie! Wygląda na to, że zadziała, ale uważam, że metoda "wag" jest nieco bardziej intuicyjna. – DanHickstein

+0

@DanHickstein Wygląda na to, że kodowanie byłoby strasznie powolne nawet dla umiarkowanie dużych zbiorów danych, ale jesteś jedyną osobą, która może zdecydować, czy jest wystarczająco szybka dla ciebie. – Jaime

+0

Ah, dobry punkt! Nie sprawdziłem prędkości - tylko sprawdziło się podczas demonstracji. – DanHickstein