在 Python 中从数据点中查找移动平均值

Posted

技术标签:

【中文标题】在 Python 中从数据点中查找移动平均值【英文标题】:Finding moving average from data points in Python 【发布时间】:2012-07-06 07:30:48 【问题描述】:

我又玩了一下 Python,发现了一本带有示例的简洁书籍。示例之一是绘制一些数据。我有一个包含两列的 .txt 文件,并且我有数据。我将数据绘制得很好,但在练习中它说:进一步修改您的程序以计算和绘制数据的运行平均值,定义为:

$Y_k=\frac12r\sum_m=-r^r y_k+m$

这里是r=5y_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()

我得到了这个:

非常感谢^^ :)

【问题讨论】:

这很奇怪。由于我们没有你的 txt 文件,所以无法在这里测试,但我认为不应该使用 xlim 行(以防万一) 我从这里得到了要点:www-personal.umich.edu/~mejn/computational-physics/sunspots.dat 删除 xlim 并没有帮助:\ 我写错了代码!您必须在 y 数组上执行平均值,而不是 x:y_av = movingaverage(y, r)plot(x, y_av)。我认为你可以再次使用 xlim。 太棒了! :D 谢谢^^ 我认为我们需要在这里使用“有效”而不是“相同” - return numpy.convolve(interval, window, 'same') 【参考方案1】:

由于 numpy.convolve 非常慢,那些需要快速执行解决方案的人可能更喜欢更容易理解的 cumsum 方法。代码如下:

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

data 包含您的数据,ma_vec 将包含 window_width 长度的移动平均值。

平均而言,cumsumconvolve 快大约 30-40 倍。

【讨论】:

我想如果我今天要实施离线移动平均线,我会从一开始就使用您的解决方案,而不是卷积。其实我很惊讶这个答案没有得到更多的支持...... “step”参数在哪里? @roman-kh,如果你能看看这个,我将不胜感激,谢谢。 ***.com/questions/45839123/… 这是这个旧问题的副本:***.com/a/27681394/1391441 为什么是numpy.insert(data, 0, 0)?它在数据的开头添加了一个 0,对吧?【参考方案2】:

在阅读此答案之前,请记住下面还有另一个答案,来自 Roman Kh,它使用 numpy.cumsum,并且比这个答案快得多。


最佳将移动/滑动平均值(或任何其他滑动窗口函数)应用于信号的一种常见方法是使用numpy.convolve()

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

这里,interval 是您的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()

希望这会有所帮助!

【讨论】:

这里出现错误:回溯(最近一次调用最后一次):文件“C:/Users/*****/Desktop/sunspots_plot.py”,第 18 行,在 x_av = moveaverage(x, 5) 文件“C:/Users/*****/Desktop/sunspots_plot.py”,第 8 行,在移动平均窗口 = numpy.ones(int(window_size))/float(window_size) NameError: global名称“numpy”未定义 嗯,这意味着你没有导入 numpy.实际上,您只是从中导入了一些函数:linspaceloadtxt。您应该添加onesconvolve ;o) 我编辑了我的代码,现在我有了图像,但平均值只在图表的最后一部分,我应该手动更改间隔来解决吗? 问题是 convolve 非常慢。您可能会在下面找到基于 numpy.cumsum() 的更快解决方案。 我发现这个解决方案效果很好,但在数据边缘不起作用。它增加了虚假的低值。【参考方案3】:

移动平均是卷积,numpy 会比大多数纯 python 操作更快。这将为您提供 10 点移动平均线。

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

如果您正在处理时间序列数据,我也强烈建议使用大熊猫包。有一些不错的moving average operations built in。

【讨论】:

我得到错误:回溯(最后一次调用):文件“C:/Users/*****/Desktop/sunspots_plot.py”,第 7 行,在 中平滑 = np .convolve(data, np.ones(10)/(10)) 文件“C:\Python26\lib\site-packages\numpy\core\numeric.py”,第 787 行,在卷积中返回 multiarray.correlate(a, v[::-1], mode) ValueError: object too deep for required array 在您的情况下,b/c 数据是一个多维 numpy 数组,您应该传递一个一维数组。在你的情况下,它会被平滑 = np.convolve(y, np.ones/10) +10 对“使用熊猫”的建议。并非对每种情况都完美,但可能会为阅读这篇文章的人的平均情况省去很多麻烦。 @reptilicus,这似乎很酷,但它似乎并没有改善我在这里遇到的类似问题,如果你能看看这个,我将不胜感激。 ***.com/questions/45839123/…【参考方案4】:
ravgs = [sum(data[i:i+5])/5. for i in range(len(data)-4)]

这不是最有效的方法,但它会给出您的答案,我不清楚您的窗口是 5 分还是 10。如果是 10,请将每个 5 替换为 10,将 4 替换为 9。

【讨论】:

【参考方案5】:

接受的答案有问题。我认为我们需要在这里使用 "valid" 而不是 "same" - 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/

【讨论】:

这个没试过,但我会研究一下,我已经有一段时间没有用 Python 编码了。 @dingo_d 你为什么不用生锈的代码(和示例数据集(作为一个简单的列表),我发布了)快速尝试一下?对于一些懒惰的人(就像我一直在首先)-它掩盖了移动平均线不正确的事实。也许您应该考虑编辑原始答案。我昨天才尝试过,仔细检查使我免于向 Cxo 级别报告时看起来很糟糕。您需要做的就是用“有效”尝试相同的移动平均线,另一次用“相同”尝试 - 一旦你确信给我一些爱(aka-up-vote) 我现在在工作,所以我无法访问 Python,但是当我在家的时候我会尝试一下:) 很抱歉我没有回复你,当时我无法让 Python 在我的 comp 上工作,所以我忘记了这一点。我再次安装了它,我尝试将'valid' 放入convolve,并得到错误ValueError: x and y must have same first dimension。我检查了数组的长度,它们是相同的。我什至做了x = numpy.array(data[:,0]) y = numpy.array(data[:,1]),但我仍然遇到同样的错误。【参考方案6】:

我的移动平均函数,没有 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

【讨论】:

不好意思加了第一行:from future import Division。否则输出将是 int 而不是 float @Arnanda_An,您可以通过在1 中使用小数点来强制 Python 2 中的浮点除法:m = (m * i + A[i])/(i+1.)【参考方案7】:

我认为是这样的:

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

但我总是要仔细检查指数是否符合我的预期。你想要的范围是 (0, 5, 10, ...) 和 data[0:6] 会给你 data[0]...data[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]

【讨论】:

有了这个我得到了一堆数组,当我尝试绘制它们时出现错误:\ 抱歉,没有修正错字,应该是 y1[i-r:i+r] 而不是 data 不管怎样,y1 有 len(y1) 点,y2 有 len(y1)/2r 点,所以......你想将它们分别添加到图表中。改用卷积解决方案! 再次,对于 y2,我知道它们是 [array[number, number], array[number, number]...] :\ 我需要获取要绘制的数字:\

以上是关于在 Python 中从数据点中查找移动平均值的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在 Python 中计算年度移动平均值?

使用滞后函数在 SQL 中查找移动平均线

深入详解 二次移动平均法python

在 Pandas、Python 中查找具有相同第一列的所有行的最小值、最大值、平均值

按列/年的移动平均值-python,大熊猫

在 Pandas 数据框中查找每三列的平均值