如何在Python3中计算移动平均线?
假设我有一个列表:如何在Python3中计算移动平均线?,python,python-3.x,Python,Python 3.x,假设我有一个列表: y = ['1', '2', '3', '4','5','6','7','8','9','10'] 我想创建一个计算n天移动平均值的函数。 因此,如果n为5,我希望我的代码计算前1-5,将其相加,找到平均值,即3.0,然后继续到2-6,计算平均值,即4.0,然后是3-7,4-8,5-9,6-10 我不想计算前n-1天,所以从第n天开始,它将计算前几天 def moving_average(x:'list of prices', n): for num in rang
y = ['1', '2', '3', '4','5','6','7','8','9','10']
我想创建一个计算n天移动平均值的函数。
因此,如果n
为5,我希望我的代码计算前1-5,将其相加,找到平均值,即3.0,然后继续到2-6,计算平均值,即4.0,然后是3-7,4-8,5-9,6-10
我不想计算前n-1天,所以从第n天开始,它将计算前几天
def moving_average(x:'list of prices', n):
for num in range(len(x)+1):
print(x[num-n:num])
这似乎打印出了我想要的:
[]
[]
[]
[]
[]
['1', '2', '3', '4', '5']
['2', '3', '4', '5', '6']
['3', '4', '5', '6', '7']
['4', '5', '6', '7', '8']
['5', '6', '7', '8', '9']
['6', '7', '8', '9', '10']
然而,我不知道如何计算这些列表中的数字。有什么想法吗?使用
sum
和map
函数
print(sum(map(int, x[num-n:num])))
Python 3中的map
函数基本上是此函数的惰性版本:
[int(i) for i in x[num-n:num]]
我相信您可以猜到sum函数的作用。旧版Python文档中有一个很棒的滑动窗口生成器,它具有: 使用移动平均线很简单:
from __future__ import division # For Python 2
def moving_averages(values, size):
for selection in window(values, size):
yield sum(selection) / size
针对您的输入运行此操作(将字符串映射为整数)将提供:
要返回“不完整”集合的第一次迭代,只需稍微扩展移动平均值函数即可:
def moving_averages(values, size):
for _ in range(size - 1):
yield None
for selection in window(values, size):
yield sum(selection) / size
避免重新计算中间和的方法
list=range(0,12)
def runs(v):
global runningsum
runningsum+=v
return(runningsum)
runningsum=0
runsumlist=[ runs(v) for v in list ]
result = [ (runsumlist[k] - runsumlist[k-5])/5 for k in range(0,len(list)+1)]
打印结果
[2,3,4,5,6,7,8,9]
使其运行(int(v))。。然后。。repr(runsumlist[k]-runsumlist[k-5])/5) 如果你想随身携带数字和字符串
不带全局变量的Alt:
list = [float[x] for x in range(0,12)]
nave = 5
movingave = sum(list[:nave]/nave)
for i in range(len(list)-nave):movingave.append(movingave[-1]+(list[i+nave]-list[i])/nave)
print movingave
即使输入值是整数,也要确保进行浮点运算
[2.0,3.0,4.0,5.0,6.0,7.0,8.0,9,0]
虽然我喜欢这个,像george一样,我想知道如果使用运行求和而不是对几乎相同的数字反复应用sum()
,这是否会更快
另外,在提升阶段将None
值作为默认值的想法也很有趣。事实上,移动平均线可能有很多不同的情况。让我们将平均值的计算分为三个阶段:
平均值:=sum(x[迭代\u计数器-窗口\u大小:迭代\u计数器])/window\u大小
窗口大小-1
平均值- 任意iterables(生成器很好)作为数据输入
- 任意窗口大小>=1
- 在上升/下降阶段打开/关闭值生成的参数
- 这些阶段的回调函数用于控制值的生成方式。这可用于持续提供默认值(例如,
)或提供部分平均值None
from collections import deque
def moving_averages(data, size, rampUp=True, rampDown=True):
"""Slide a window of <size> elements over <data> to calc an average
First and last <size-1> iterations when window is not yet completely
filled with data, or the window empties due to exhausted <data>, the
average is computed with just the available data (but still divided
by <size>).
Set rampUp/rampDown to False in order to not provide any values during
those start and end <size-1> iterations.
Set rampUp/rampDown to functions to provide arbitrary partial average
numbers during those phases. The callback will get the currently
available input data in a deque. Do not modify that data.
"""
d = deque()
running_sum = 0.0
data = iter(data)
# rampUp
for count in range(1, size):
try:
val = next(data)
except StopIteration:
break
running_sum += val
d.append(val)
#print("up: running sum:" + str(running_sum) + " count: " + str(count) + " deque: " + str(d))
if rampUp:
if callable(rampUp):
yield rampUp(d)
else:
yield running_sum / size
# steady
exhausted_early = True
for val in data:
exhausted_early = False
running_sum += val
#print("st: running sum:" + str(running_sum) + " deque: " + str(d))
yield running_sum / size
d.append(val)
running_sum -= d.popleft()
# rampDown
if rampDown:
if exhausted_early:
running_sum -= d.popleft()
for (count) in range(min(len(d), size-1), 0, -1):
#print("dn: running sum:" + str(running_sum) + " deque: " + str(d))
if callable(rampDown):
yield rampDown(d)
else:
yield running_sum / size
running_sum -= d.popleft()
以及输出:
Timeit
--------------------------------------------------------------------------------
10 7.242 7.656
100 5.816 5.500
1000 5.787 5.244
10000 5.782 5.180
100000 5.746 5.137
1000000 5.745 5.198
10000000 5.764 5.186
[None, None, None, None, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]
原来的问题现在可以通过此函数调用解决:
print(list(moving_averages(range(1,11), 5,
rampUp=lambda _: None,
rampDown=False)))
输出:
Timeit
--------------------------------------------------------------------------------
10 7.242 7.656
100 5.816 5.500
1000 5.787 5.244
10000 5.782 5.180
100000 5.746 5.137
1000000 5.745 5.198
10000000 5.764 5.186
[None, None, None, None, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]
还有另一个解决方案扩展了
itertools
recipepairwise()
。您可以将其扩展到nwise()
,它为您提供了滑动窗口(如果iterable是一个生成器,则可以工作):
短iterable
s的设置成本相对较高,但数据集越长,此成本的影响就越小。这使用了sum()
,但代码相当优雅:
Timeit MP cfi *****
--------------------------------------------------------------------------------
10 4.658 4.959 7.351
100 5.144 4.070 4.234
1000 5.312 4.020 3.977
10000 5.317 4.031 3.966
100000 5.508 4.115 4.087
1000000 5.526 4.263 4.202
10000000 5.632 4.326 4.242
为什么列表中有字符串而不是数字?我希望结果是[none,none,none,none,none,3.0,4.0,5.0,6.0,7.0,8.0]虽然我欣赏你优雅的解决方案,但我还是将它与跟踪运行总和的方法进行了比较,而不是多次重新计算总和。看见如果函数被简化为只回答原始问题,而不允许附加参数,那么这可能会更快。事实上,运行求和算法更快。我已经发布了一个答案来证明你的观点。这里不需要
全局变量。
def nwise(iterable, n):
ts = it.tee(iterable, n)
for c, t in enumerate(ts):
next(it.islice(t, c, c), None)
return zip(*ts)
def moving_averages_nw(iterable, n):
yield from (sum(x)/n for x in nwise(iterable, n))
>>> list(moving_averages_nw(range(1, 11), 5))
[3.0, 4.0, 5.0, 6.0, 7.0, 8.0]
Timeit MP cfi *****
--------------------------------------------------------------------------------
10 4.658 4.959 7.351
100 5.144 4.070 4.234
1000 5.312 4.020 3.977
10000 5.317 4.031 3.966
100000 5.508 4.115 4.087
1000000 5.526 4.263 4.202
10000000 5.632 4.326 4.242