简体   繁体   English

基于Python的简单移动平均类

[英]Python simple moving average class based

Ok so I'm writing a class that will calculate a simple moving average on a list of prices. 好的,所以我正在编写一个类,该类将根据价格列表计算简单的移动平均线。 It calculates the average every N number of prices with out calculating the first N-1 days. 它计算每N个价格的平均值,而不计算前N-1天。 This is what I have: 这就是我所拥有的:

class Simplemovingaverage():
    def __init__(self, Nday, list_of_prices):
        self._Nday = Nday
        self._list_of_prices = list_of_prices

    def calculate(self):
        for i in range(len(self._list_of_prices)):
            if i < self._Nday:
                average = 0
            elif i == self._Nday:
                average = sum(self._list_of_prices[:self._Nday])/self._Nday
            else:
                average = sum(self._list_of_prices[i-self._Nday:i])/self._Nday
            print(average)

I tested it by making a class object on the shell 'x = Simplemovingaverage(3, [1,2,3,4,5,6,7,8,9,10])' and then doing the calculate method by 'x.calculate' the output I got was: 我通过在外壳程序上创建一个类对象'x = Simplemovingaverage(3, [1,2,3,4,5,6,7,8,9,10])' ,然后通过'x .calculate'我得到的输出是:

0
0
0
2.0
3.0
4.0
5.0
6.0
7.0
8.0

So from my list of numbers its only calculating up to 7,8,9 the last number should be 9 because that's the average of 8,9,10 and also there should only be 3 zeros since N is 3. This is the output I'm looking for: 因此,从我的数字列表中,它最多可以计算到7、8、9,最后一个数字应该是9,因为那是8、9、10的平均值,并且因为N是3,所以也应该只有3个零。这是输出I正在寻找:

0
0
2.0
3.0
4.0
5.0
6.0
7.0
8.0
9.0
def sma_calc(prices_list, window_size):
    return sum(prices_list[-window_size:]) / window_size
from __future__ import division
from itertools import islice, tee

def moving_average(n, iterable):
    # leading 0s
    for i in range(1, n):
        yield 0.

    # actual averages
    head, tail = tee(iterable)
    sum_ = float(sum(islice(head, n)))
    while True:
        yield sum_ / n
        sum_ += next(head) - next(tail)

When run as 当以

list(moving_average(3, [1,2,3,4,5,6,7,8,9,10]))

returns 回报

[0.0, 0.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]

(starts with N-1 leading 0s, meaning the output list has the same cardinality as the input list, which I think is what you actually wanted). (从N-1前导0开始,这意味着输出列表与输入列表具有相同的基数,我认为这是您真正想要的)。

You've got an out by one error. 您出了一个错误。 Try this: 尝试这个:

  for i in range(len(self._list_of_prices) + 1):

So this might illustrate what's going on a bit 所以这可能说明发生了什么

>>> _list_of_prices = [1,2,3,4,5,6,7,8,9,10]
>>> len(_list_of_prices)
10
>>> range(len(_list_of_prices))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> i = 9
>>> _list_of_prices[i-3:i]
[7, 8, 9]

So the problem is that the python's list slice operator returns up to i in the example above but not i, (in this example it returns i-3, i-2 and i-1) eg 因此,问题在于在上面的示例中python的列表切片运算符最多返回i,但不返回i(在此示例中,它返回i-3,i-2和i-1),例如

>>> word = "helpa"
>>> word[0:2]
'he'

See here http://docs.python.org/2/tutorial/introduction.html 看到这里http://docs.python.org/2/tutorial/introduction.html

You've mistaken the index: 您误认为了索引:

In [186]: class Simplemovingaverage():
     ...:     def __init__(self, Nday, list_of_prices):
     ...:         self._Nday = Nday
     ...:         self._list_of_prices = list_of_prices
     ...: 
     ...:     def calculate(self):
     ...:         for i in range(len(self._list_of_prices)):
     ...:             if i < self._Nday-1:
              #------------------------^^--------------------------
     ...:                 average = 0
     ...:             elif i == self._Nday-1:
              #---------------------------^^--------------------------
     ...:                 average = sum(self._list_of_prices[:self._Nday])/self._Nday
     ...:             else:
     ...:                 average = sum(self._list_of_prices[\
                                i+1-self._Nday:i+1])/self._Nday
              #-----------------^^^-------------^^^--------------------------                  

     ...:             print(average)

In [187]: x = Simplemovingaverage(3, [1,2,3,4,5,6,7,8,9,10])

In [188]: x.calculate()
0
0
2
3
4
5
6
7
8
9

OK, here's a cleanup: 好,这是一个清理工作:

class Simplemovingaverage():
    def __init__(self, navg, items):
        self.navg = navg
        self.items = items

    def calculate(self):
        av = []
        for i in range(len(self.items)):
            if i+1 < self.navg:
                av.append(0)
            else:
                av.append(sum(self.items[i+1-self.navg:i+1])/self.navg)
        return av

First, you need to use i+1 everywhere, since range gives 0...navg-1 rather than 1...navg (you could also do range(1, n+1) ). 首先,您需要在所有地方使用i+1 ,因为range给出的是0...navg-1而不是1...navg (您也可以执行range(1, n+1) )。

Second, you don't need to special-case i+1==self.navg ( :m is the same as 0:m ). 其次,您不需要特殊情况i+1==self.navg:m0:m相同)。

Third, it makes more sense to return a list rather than printing the results (although I like the other respondent's idea of using yield to make this a generator!) 第三,返回列表而不是打印结果更有意义(尽管我喜欢其他受访者关于使用yield使其成为生成器的想法!)

Fourth, there's no real reason to hide the number and the list, so I've removed the underscores (python isn't java or c++!). 第四,没有真正的理由隐藏数字和列表,因此我删除了下划线(python不是java或c ++!)。

Finally, this is more general than a "list of prices" averaged over a certain number of "days", so I've renamed the parameters for more generality. 最后,这比在一定数量的“天”内平均的“价格清单”更为笼统,因此我将参数重命名为更通用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM