web-dev-qa-db-fra.com

Trouver la moyenne mobile des points de données dans Python

Je joue dans Python encore un peu, et j'ai trouvé un livre soigné avec des exemples. L'un des exemples est de tracer quelques données. J'ai un fichier .txt avec deux colonnes et j'ai le J'ai tracé les données très bien, mais dans l'exercice, il est dit: Modifiez davantage votre programme pour calculer et tracer la moyenne mobile des données, définie par:

$Y_k=\frac{1}{2r}\sum_{m=-r}^r y_{k+m}$

r=5 dans ce cas (et le y_k est la deuxième colonne du fichier de données). Demandez au programme de tracer à la fois les données d'origine et la moyenne mobile sur le même graphique.

Jusqu'à présent, j'ai ceci:

from pylab import plot, ylim, xlim, show, xlabel, ylabel
from numpy import linspace, loadtxt

data = loadtxt("sunspots.txt", float)
r=5.0

x = data[:,0]
y = data[:,1]

plot(x,y)
xlim(0,1000)
xlabel("Months since Jan 1749.")
ylabel("No. of Sun spots")
show()

Alors, comment puis-je calculer la somme? Dans Mathematica, c'est simple car c'est une manipulation symbolique (Sum [i, {i, 0,10}] par exemple), mais comment calculer la somme en python qui prend tous les dix points dans les données et la moyenne, et le fait jusqu'à la fin des points?

J'ai regardé le livre, mais je n'ai rien trouvé qui pourrait expliquer cela: \


le code de heltonbiker a fait l'affaire ^^: D

from __future__ import division
from pylab import plot, ylim, xlim, show, xlabel, ylabel, grid
from numpy import linspace, loadtxt, ones, convolve
import numpy as numpy

data = loadtxt("sunspots.txt", float)

def movingaverage(interval, window_size):
    window= numpy.ones(int(window_size))/float(window_size)
    return numpy.convolve(interval, window, 'same')

x = data[:,0]
y = data[:,1]


plot(x,y,"k.")
y_av = movingaverage(y, 10)
plot(x, y_av,"r")
xlim(0,1000)
xlabel("Months since Jan 1749.")
ylabel("No. of Sun spots")
grid(True)
show()

Et j'ai obtenu ceci:

image

Merci beaucoup ^^ :)

41
dingo_d

Avant de lire cette réponse, gardez à l'esprit qu'il y a une autre réponse ci-dessous, de Roman Kh, qui utilise numpy.cumsum Et est BEAUCOUP PLUS RAPIDE que celle-ci.


Meilleur Une manière courante d'appliquer une moyenne mobile/glissante (ou toute autre fonction de fenêtre glissante) à un signal est d'utiliser numpy.convolve().

def movingaverage(interval, window_size):
    window = numpy.ones(int(window_size))/float(window_size)
    return numpy.convolve(interval, window, 'same')

Ici, interval est votre tableau x et window_size Est le nombre d'échantillons à considérer. La fenêtre sera centrée sur chaque échantillon, elle prend donc des échantillons avant et après l'échantillon actuel afin de calculer la moyenne. Votre code deviendrait:

plot(x,y)
xlim(0,1000)

x_av = movingaverage(interval, r)
plot(x_av, y)

xlabel("Months since Jan 1749.")
ylabel("No. of Sun spots")
show()

J'espère que cela t'aides!

74
heltonbiker

Comme numpy.convolve est assez lent, ceux qui ont besoin d'une solution rapide peuvent préférer une approche cumsum plus facile à comprendre. Voici le code:

cumsum_vec = numpy.cumsum(numpy.insert(data, 0, 0)) 
ma_vec = (cumsum_vec[window_width:] - cumsum_vec[:-window_width]) / window_width

données contient vos données, et ma_vec contiendra des moyennes mobiles de window_width longueur.

En moyenne, cumsum est environ 30 à 40 fois plus rapide que convolve.

51
Roman Kh

Une moyenne mobile est une convolution, et numpy sera plus rapide que la plupart des opérations python pures. Cela vous donnera la moyenne mobile de 10 points.

import numpy as np
smoothed = np.convolve(data, np.ones(10)/10)

Je voudrais également fortement suggérer d'utiliser le grand package pandas si vous travaillez avec des données de série temporelle. Il y a quelques Nice - opérations moyennes mobiles intégrées .

25
reptilicus

Il y a un problème avec la réponse acceptée. Je pense que nous devons utiliser "valide" au lieu de "même" ici - return numpy.convolve(interval, window, 'same').

À titre d'exemple, essayez la MA de cet ensemble de données = [1,5,7,2,6,7,8,2,2,7,8,3,7,3,7,3,15,6] - le résultat doit être [4.2,5.4,6.0,5.0,5.0,5.2,5.4,4.4,5.4,5.6,5.6,4.6,7.0,6.8], mais avoir "même" nous donne une sortie incorrecte de [2.6,3.0,4.2,5.4,6.0,5.0,5.0,5.2,5.4,4.4,5.4,5.6,5.6, 4.6,7.0,6.8,6.2,4.8]

Code rouillé pour l'essayer -:

result=[]
dataset=[1,5,7,2,6,7,8,2,2,7,8,3,7,3,7,3,15,6]
window_size=5
for index in xrange(len(dataset)):
    if index <=len(dataset)-window_size :
        tmp=(dataset[index]+ dataset[index+1]+ dataset[index+2]+ dataset[index+3]+ dataset[index+4])/5.0
        result.append(tmp)
    else:
      pass

result==movingaverage(y, window_size) 

Essayez ceci avec valid & same et voyez si les maths ont du sens.

Voir aussi -: http://sentdex.com/sentiment-analysisbig-data-and-python-tutorials-algorithmic-trading/how-to-chart-stocks-and-forex-doing-your-own- tableau-financier/calcul-simple-moyenne-mobile-sma-python /

4
ekta
ravgs = [sum(data[i:i+5])/5. for i in range(len(data)-4)]

Ce n'est pas l'approche la plus efficace mais elle donnera votre réponse et je ne sais pas si votre fenêtre est de 5 points ou 10. Si c'est 10, remplacez chaque 5 par 10 et le 4 par 9.

4
sizzzzlerz

Ma fonction de moyenne mobile, sans fonction numpy:

from __future__ import division  # must be on first line of script

class Solution:
    def Moving_Avg(self,A):
        m = A[0]
        B = []
        B.append(m)
        for i in range(1,len(A)):
            m = (m * i + A[i])/(i+1)
            B.append(m)
        return B
1
Armanda_An

Je pense que quelque chose comme:

aves = [sum(data[i:i+6]) for i in range(0, len(data), 5)]

Mais je dois toujours vérifier que les indices font ce que j'attends. La plage souhaitée est (0, 5, 10, ...) et les données [0: 6] vous donneront des données [0] ... des données [5]

ETA: oups, et vous voulez une ave plutôt qu'une somme, bien sûr. Donc, en fait, en utilisant votre code et la formule:

r = 5
x = data[:,0]
y1 = data[:,1]
y2 = [ave(y1[i-r:i+r]) for i in range(r, len(y1), 2*r)]
y = [y1, y2]
0
dreadsci