在 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=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()
我得到了这个:
非常感谢^^ :)
【问题讨论】:
这很奇怪。由于我们没有你的 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 长度的移动平均值。
平均而言,cumsum 比 convolve 快大约 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 行,在linspace
和 loadtxt
。您应该添加ones
和convolve
;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 行,在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 中从数据点中查找移动平均值的主要内容,如果未能解决你的问题,请参考以下文章