python 移动平均线_Python 3中如何计算移动平均值?

本文探讨了一种使用deque实现的Python移动平均线计算方法,该方法适用于任意大小的窗口,并考虑了数据输入的起始和结束阶段。通过与Martijn's answer的版本进行性能比较,展示其在不同数据规模下的效率。此外,还提供了测试代码以验证其性能优势。
摘要由CSDN通过智能技术生成

虽然我喜欢像george这样的Martijn's answer方法,但我想知道,如果使用一个运行求和法,而不是在几乎相同的数字上一遍又一遍地应用sum(),这样做是否更快。

另外,在爬坡阶段将None值作为默认值的想法也很有趣。事实上,移动平均线可能有很多不同的情况。我们把平均数的计算分成三个阶段:加速:在当前迭代计数窗口大小处开始迭代

稳定的进程:我们有精确的窗口大小的元素数,可以计算一个正常的average := sum(x[iteration_counter-window_size:iteration_counter])/window_size

斜坡下降:在输入数据的末尾,我们可以返回另一个window_size - 1“平均”数字。

这里有一个函数可以接受任意iterable(生成器可以)作为数据输入

任意窗口大小>=1

在上升/下降阶段打开/关闭值产生的参数

这些阶段的回调函数,用于控制如何生成值。这可用于持续提供默认值(例如None)或提供部分平均值

代码如下:from collections import deque

def moving_averages(data, size, rampUp=True, rampDown=True):

"""Slide a window of elements over to calc an average

First and last iterations when window is not yet completely

filled with data, or the window empties due to exhausted , the

average is computed with just the available data (but still divided

by ).

Set rampUp/rampDown to False in order to not provide any values during

those start and end 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()

它似乎比Martijn的版本要快一点——不过,Martijn的版本要优雅得多。下面是测试代码:print("")

print("Timeit")

print("-" * 80)

from itertools import islice

def window(seq, n=2):

"Returns a sliding window (of width n) over data from the iterable"

" s -> (s0,s1,...s[n-1]), (s1,s2,...,sn), ... "

it = iter(seq)

result = tuple(islice(it, n))

if len(result) == n:

yield result

for elem in it:

result = result[1:] + (elem,)

yield result

# Martijn's version:

def moving_averages_SO(values, size):

for selection in window(values, size):

yield sum(selection) / size

import timeit

problems = [int(i) for i in (10, 100, 1000, 10000, 1e5, 1e6, 1e7)]

for problem_size in problems:

print("{:12s}".format(str(problem_size)), end="")

so = timeit.repeat("list(moving_averages_SO(range("+str(problem_size)+"), 5))", number=1*max(problems)//problem_size,

setup="from __main__ import moving_averages_SO")

print("{:12.3f} ".format(min(so)), end="")

my = timeit.repeat("list(moving_averages(range("+str(problem_size)+"), 5, False, False))", number=1*max(problems)//problem_size,

setup="from __main__ import moving_averages")

print("{:12.3f} ".format(min(my)), end="")

print("")

以及输出: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

原来的问题现在可以通过这个函数调用来解决:print(list(moving_averages(range(1,11), 5,

rampUp=lambda _: None,

rampDown=False)))

输出:[None, None, None, None, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值