Нахождение скользящего среднего по точкам данных в Python

Я снова немного играю в Python, и я нашел аккуратную книгу с примерами. Одним из примеров является представление некоторых данных. У меня есть файл.txt с двумя столбцами, и у меня есть данные. Я нанес на карту данные очень хорошо, но в упражнении говорится: "Измените вашу программу дальше, чтобы вычислить и построить график скользящего среднего данных, определяемого как:

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

где r=5 в этом случае (и y_k это второй столбец в файле данных). Пусть программа отобразит как исходные данные, так и скользящее среднее на одном графике.

Пока у меня есть это:

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

Так как мне рассчитать сумму? В Mathematica это просто, поскольку это символическое манипулирование (например, Sum[i, {i,0,10}]), но как вычислить сумму в python, которая берет каждые десять точек в данных и усредняет их, и делает это до конца очков?

Я посмотрел на книгу, но не нашел ничего, что могло бы объяснить это:


Хелтонбайкер код сделал свое дело ^^: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()

И я получил это:

образ

Большое спасибо ^^:)

7 ответов

Решение

Прежде чем читать этот ответ, имейте в виду, что ниже есть другой ответ от Романа Х, который использует numpy.cumsum и НАМНОГО БОЛЬШЕ, чем этот.


Лучший из распространенных способов применения скользящего / скользящего среднего (или любой другой функции скользящего окна) к сигналу - использование numpy.convolve(),

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

Здесь интервал ваш x массив и window_size количество образцов для рассмотрения. Окно будет центрировано по каждому сэмплу, поэтому он берет сэмплы до и после текущего сэмпла, чтобы вычислить среднее значение. Ваш код станет:

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

Надеюсь это поможет!

Поскольку numpy.convolve довольно медленный, те, кто нуждается в быстродействующем решении, могут предпочесть более простой для понимания подход cumsum. Вот код:

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

где данные содержат ваши данные, а ma_vec будет содержать скользящие средние длины window_width.

В среднем, кончум примерно в 30-40 раз быстрее, чем свертка.

Скользящее среднее - это свертка, и numpy будет быстрее, чем большинство чистых операций с Python. Это даст вам 10-балльную скользящую среднюю.

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

Я также настоятельно рекомендую использовать пакет великолепных панд, если вы работаете с данными временных рядов. Есть несколько хороших встроенных операций скользящего среднего.

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

Это не самый эффективный подход, но он даст ваш ответ, и мне неясно, будет ли ваше окно 5 баллов или 10. Если его 10, замените каждые 5 на 10, а 4 на 9.

Есть проблема с принятым ответом. Я думаю, что нам нужно использовать "действительный" вместо "тот же" здесь - return numpy.convolve(interval, window, 'same'),

В качестве примера попробуйте MA этого набора данных = [1,5,7,2,6,7,8,2,2,7,8,3,7,3,7,3,15,6] - результат должен быть [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], но "то же самое" дает нам неправильный вывод [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]

Расти код, чтобы попробовать это -:

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) 

Попробуйте это с valid & same и посмотрите, имеет ли математика смысл.

Смотрите также:: 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/

Функция My Moving Average, без функции 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

Я думаю что-то вроде:

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

Но я всегда должен дважды проверять, что индексы делают то, что я ожидаю. Требуемый диапазон (0, 5, 10, ...) и данные [0:6] предоставят вам данные [0]... данные [5]

ETA: упс, и вы хотите ave, а не sum, конечно. Итак, на самом деле, используя ваш код и формулу:

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]
Другие вопросы по тегам