Поиск скользящей средней из точек данных в 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, которая берет каждые десять точек в данных и усредняет ее, и делает это до конца точек?

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


Код heltonbiker сделал трюк ^^: 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()

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

image

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

Ответ 1

Прежде чем читать этот ответ, имейте в виду, что есть еще один ответ ниже, от Романа Х, который использует 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()

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

Ответ 2

Поскольку 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.

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

Ответ 3

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

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

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

Ответ 4

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

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

Ответ 5

Существует проблема с принятым ответом. Я думаю, нам нужно использовать "действительный" вместо "тот же самый" здесь - 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) 

Попробуйте это правильно и так же и посмотрите, имеет ли смысл математика.

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

Ответ 6

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

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

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

ETA: oops, и вы хотите, конечно, ave, а не сумму. Так что на самом деле вы используете свой код и формулу:

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]

Ответ 7

Функция 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