Moving average or running mean

后端 未结 27 1041
庸人自扰
庸人自扰 2020-11-22 08:37

Is there a SciPy function or NumPy function or module for Python that calculates the running mean of a 1D array given a specific window?

相关标签:
27条回答
  • 2020-11-22 09:16

    If you do choose to roll your own, rather than use an existing library, please be conscious of floating point error and try to minimize its effects:

    class SumAccumulator:
        def __init__(self):
            self.values = [0]
            self.count = 0
    
        def add( self, val ):
            self.values.append( val )
            self.count = self.count + 1
            i = self.count
            while i & 0x01:
                i = i >> 1
                v0 = self.values.pop()
                v1 = self.values.pop()
                self.values.append( v0 + v1 )
    
        def get_total(self):
            return sum( reversed(self.values) )
    
        def get_size( self ):
            return self.count
    

    If all your values are roughly the same order of magnitude, then this will help to preserve precision by always adding values of roughly similar magnitudes.

    0 讨论(0)
  • 2020-11-22 09:17

    For a ready-to-use solution, see https://scipy-cookbook.readthedocs.io/items/SignalSmooth.html. It provides running average with the flat window type. Note that this is a bit more sophisticated than the simple do-it-yourself convolve-method, since it tries to handle the problems at the beginning and the end of the data by reflecting it (which may or may not work in your case...).

    To start with, you could try:

    a = np.random.random(100)
    plt.plot(a)
    b = smooth(a, window='flat')
    plt.plot(b)
    
    0 讨论(0)
  • 2020-11-22 09:19

    This question is now even older than when NeXuS wrote about it last month, BUT I like how his code deals with edge cases. However, because it is a "simple moving average," its results lag behind the data they apply to. I thought that dealing with edge cases in a more satisfying way than NumPy's modes valid, same, and full could be achieved by applying a similar approach to a convolution() based method.

    My contribution uses a central running average to align its results with their data. When there are too few points available for the full-sized window to be used, running averages are computed from successively smaller windows at the edges of the array. [Actually, from successively larger windows, but that's an implementation detail.]

    import numpy as np
    
    def running_mean(l, N):
        # Also works for the(strictly invalid) cases when N is even.
        if (N//2)*2 == N:
            N = N - 1
        front = np.zeros(N//2)
        back = np.zeros(N//2)
    
        for i in range(1, (N//2)*2, 2):
            front[i//2] = np.convolve(l[:i], np.ones((i,))/i, mode = 'valid')
        for i in range(1, (N//2)*2, 2):
            back[i//2] = np.convolve(l[-i:], np.ones((i,))/i, mode = 'valid')
        return np.concatenate([front, np.convolve(l, np.ones((N,))/N, mode = 'valid'), back[::-1]])
    

    It's relatively slow because it uses convolve(), and could likely be spruced up quite a lot by a true Pythonista, however, I believe that the idea stands.

    0 讨论(0)
提交回复
热议问题