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}$
où 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:
Merci beaucoup ^^ :)
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!
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
où 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.
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 .
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.
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.
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
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]