2012-07-05 54 views
34

Estoy jugando un poco más en Python, y encontré un libro ordenado con ejemplos. Uno de los ejemplos es trazar algunos datos. Tengo un archivo .txt con dos columnas y tengo la información. He trazado los datos muy bien, pero en el ejercicio que dice: Modificar el programa además para calcular y representar gráficamente la media móvil de los datos, que se define por:Encontrar promedio móvil de puntos de datos en Python

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

donde r=5 en este caso (y el y_k es el segunda columna en el archivo de datos). Haga que el programa grabe los datos originales y el promedio continuo en el mismo gráfico.

Hasta ahora tengo esto:

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

Entonces, ¿cómo puedo calcular la suma? En Mathematica es simple ya que es manipulación simbólica (Sum [i, {i, 0,10}] por ejemplo), pero cómo calcular la suma en python que toma cada diez puntos en los datos y los promedia, y lo hace hasta el final de puntos?

Miré el libro, pero no encontraron nada que pudiera explicar esto: \ code


de heltonbiker hizo el truco ^^: 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() 

y me dieron esto:

image

Muchas gracias ^^ :)

+1

eso es raro. Como no tenemos su archivo txt, no es posible realizar la prueba aquí, pero creo que no se debe usar la línea 'xlim' (por si acaso) – heltonbiker

+0

Obtuve los puntos aquí: http: // www-personal. umich.edu/~mejn/computational-physics/sunspots.dat Y eliminar xlim no ayudó: \ –

+2

¡Cometí un error en el código! debe realizar el promedio en la matriz y, no x: 'y_av = movingaverage (y, r)' 'plot (x, y_av)'. Y puedes usar xlim nuevamente, creo. – heltonbiker

Respuesta

68

Before reading this answer, bear in mind that there is another answer below, from Roman Kh, which uses numpy.cumsum and is MUCH MUCH FASTER than this one.


Mejor una forma común para aplicar un movimiento/deslizamiento promedio (o de cualquier otra función de ventana deslizante) a una señal es mediante el uso de numpy.convolve().

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

Aquí, el intervalo es su x matriz y window_size es el número de muestras a tener en cuenta. La ventana se centrará en cada muestra, por lo que toma muestras antes y después de la muestra actual para calcular el promedio. Su código sería:

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

Hope this helps!

+0

Aquí me sale el error: Traza (última llamada más reciente): Archivo "C:/Users/*****/Desktop/sunspots_plot.py", línea 18, en x_av = movingaverage (x, 5) archivo "C:/Usuarios/*****/Desktop/sunspots_plot.py", línea 8, en la ventana movingaverage = numpy.ones (int (window_size))/float (window_size) NameError: el nombre global 'numpy' no está definido –

+2

Bueno, eso significa que no importó numpy. De hecho, importó solo algunas funciones de él: 'linspace' y' loadtxt'. Deberías agregar 'ones' y' convolve' a eso; o) – heltonbiker

+0

He editado mi código y ahora tengo la imagen, pero el promedio está solo en la última parte del gráfico, ¿debo cambiar manualmente el intervalo para resolverlo? –

0

creo que algo como:

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

Pero siempre tengo que corroborar los índices están haciendo lo que espero. El rango que desea es (0, 5, 10, ...) y datos [0: 6] le dará datos [0] ... datos [5]

ETA: ¡Uy, y quiere ave rather que suma, por supuesto. Así que en realidad utilizando su código y la fórmula:

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

Con esto obtengo un montón de matrices y obtengo errores cuando trato de trazarlos: \ –

+0

Lo siento, no se corrigió un error tipográfico, debe ser y1 [ir: i + r] en lugar de datos – dreadsci

+0

Y de todos modos, y1 tiene puntos len (y1) y y2 tiene len (y1)/2r puntos entonces ... desea agregarlos por separado al gráfico. Vaya con las soluciones de convolve en su lugar! – dreadsci

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

Este no es el enfoque más eficiente sino que dará su respuesta y estoy claro si la ventana es de 5 puntos o 10. Si su 10 , reemplazar cada 5 con 10 y el 4 con 9.

22

Un promedio móvil es una convolución, y numpy será más rápido que la mayoría de las operaciones de python puro. Esto le dará el promedio móvil de 10 puntos.

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

lo haría también fuertemente sugerir el uso de la gran paquete de pandas si se está trabajando con los datos de series de tiempo. Hay algunos buenos moving average operations built in.

+0

Me sale el error: Traza (última llamada más reciente): Archivo " C:/Users/*****/Desktop/sunspots_plot.py ", línea 7, en smoothed = np.convolve (data, np.ones (10)/(10)) Archivo" C: \ Python26 \ lib \ site-packages \ numpy \ core \ numeric.py ", línea 787, en la convolve return multiarray.correlate (a, v [:: - 1], mode) ValueError: objeto demasiado profundo para la matriz deseada –

+0

Eso es Los datos b/c en su caso son una matriz numpy de dimensiones múltiples, y usted debe pasar una matriz de una dimensión. En su caso, se suavizaría = np.convolve (y, np.ones/10) – reptilicus

+0

+10 a la sugerencia de "usar pandas". No es perfecto para todos los casos, pero probablemente ahorra muchos dolores de cabeza para el caso malo de alguien que lee esta publicación. – Owen

4

Hay un problema con la respuesta aceptada. Creo que tenemos que usar "válido" en lugar de "mismo" aquí - return numpy.convolve(interval, window, 'same').

Como ejemplo probar el MA de este conjunto de datos = [1,5,7,2,6,7,8,2,2,7,8,3,7,3,7,3,15,6] - El resultado debe ser [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], pero tener "igual" nos da una salida incorrecta 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]

código oxidado probar esto -:

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) 

Pruebe esto con & válido y vea si las matemáticas tienen sentido.

Véase también -: http://sentdex.com/sentiment-analysisbig-data-and-python-tutorials-algorithmic-trading/how-to-chart-stocks-and-forex-doing-your-own-financial-charting/calculate-simple-moving-average-sma-python/

+0

No lo he probado, pero lo investigaré, es Ha pasado un tiempo desde que codifiqué en Python. –

+0

@dingo_d ¿Por qué no prueban esto rápidamente con el código oxidado (y el conjunto de datos de muestra (como una simple lista), publiqué? Para algunas personas perezosas (como lo había sido al principio) - se oculta el hecho de que la media móvil es incorrecta.Probablemente debería considerar editar su respuesta original. Lo intenté ayer mismo y la verificación doble me salvó la cara de verse mal al informar al nivel Cxo. Todo lo que necesita hacer es probar su misma media móvil una vez con "válido" y otro tiempo con "igual" - y una vez que esté convencido de darme algo de amor (aka-up-vote) – ekta

+0

Estoy trabajando actualmente, así que no tengo acceso a Python, pero cuando lo hago " Estoy en casa, lo intentaré :) –

27

Como numpy.convolve es bastante lento, los que necesitan una solución rápida realización podría preferir una más fácil de entender cumSum enfoque. Aquí está el código:

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

donde de datos contiene los datos y ma_vec contendrá las medias móviles de ancho_ventana longitud.

En promedio, cumSum es de aproximadamente 30-40 veces más rápido que convolución.

+2

Creo que si implementara un promedio móvil sin conexión hoy, usaría su solución desde el principio, en lugar de convivir. En realidad, estoy sorprendido de que esta respuesta no haya recibido muchas más votaciones ascendentes ... – heltonbiker

+0

¿dónde está el parámetro 'paso'? –

+0

@ roman-kh, agradecería que pudieras echar un vistazo a esto y gracias. https://stackoverflow.com/questions/45839123/python-how-can-we-smooth-a-noisy-signal-using-moving-average –

0

Mi Función móvil del promedio, sin numpy función:

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 
+0

Lamentamos agregar la primera línea: from _future_ import division.De lo contrario, la salida será int en lugar de float –

+0

@Ananda_An, puede forzar la división de flotación en Python 2 usando un punto decimal en el '1':' m = (m * i + A [i])/(i + 1 .) ' –

Cuestiones relacionadas