2014-01-13 74 views
1

我试图计算一个移动平均值,但是在每个平均值之间设置了一个步长。例如,如果我在计算平均值的4元件窗口的每2个元素:Python中重叠窗口的平均值

data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 

这应该产生的平均[1,2,3,4],[3,4,5,6] ,[5,6,7,8],[7,8,9,10]。

window_avg = [2.5, 4.5, 6.5, 8.5] 

我的数据是这样的,结束在处理之前将被截断,所以相对于窗口大小的长度没有问题。

我读过一些关于如何在Python中移动平均数的问题,似乎有很多itertools的用法;然而,迭代器一次只能执行一个元素,而我无法弄清楚在每次平均值计算之间如何获得步长。 (How to calculate moving average in Python 3?

我还能够在MATLAB通过创建重叠索引的矩阵,然后索引数据矢量并且执行逐列平均值(Create matrix by repeatedly overlapping a vector)之前执行此操作。然而,由于这个向量相当大(大约70 000个元素,450个样本的窗口,平均每30个样本),所以计算可能需要太多的内存。

任何帮助将不胜感激。我正在使用Python 2.7。

+0

我会尝试'n = 4;小号== 2; [数据[数据[s * i:s * i + n])/ n为i,枚举数据为(data [:: s])]',但这可能不是您要查找的数据(此处不需要'datum' ,但'range(len(data))'看起来非常不和谐)。 – Evert

回答

1

计算Python中列表中滑动窗口平均值的一种方法是使用列表理解。您可以使用

>>> range(0, len(data), 2) 
[0, 2, 4, 6, 8] 

获得每个窗口的起始索引,然后numpymean功能采取每个窗口的平均水平。请参见下面的演示:

>>> import numpy as np 
>>> window_size = 4 
>>> stride = 2 
>>> window_avg = [ np.mean(data[i:i+window_size]) for i in range(0, len(data), stride) 
        if i+window_size <= len(data) ] 
>>> window_avg 
[2.5, 4.5, 6.5, 8.5] 

注意,列表理解确实有一个条件,以确保它只是计算的“全窗口”,或子列表的平均正好与元素window_size

当在OP讨论大小的数据集上运行,这种方法我在一个小的MBA计算超过200毫秒:

In [5]: window_size = 450 
In [6]: data = range(70000) 
In [7]: stride = 30 
In [8]: timeit [ np.mean(data[i:i+window_size]) for i in range(0, len(data), stride) 
       if i+window_size <= len(data) ] 
1 loops, best of 3: 220 ms per loop 

这是约两倍的速度在我的机器上的itertools方法通过@Abhijit呈现:

In [9]: timeit map(np.mean, izip(*(islice(it, i, None, stride) for i, it in enumerate(tee(data, window_size))))) 
1 loops, best of 3: 436 ms per loop 
+0

海量数据的效率如何? – zhangxaochen

+0

@zhangxaochen:我为OP中提到的数据集添加了速度基准。 – mdml

+0

似乎Abhijit的解决方案要快得多:*每个循环6.19毫秒* – zhangxaochen

1

以下方法使用itertools在其最完全的创建移动尺寸4的平均窗口。因为那么整个表达式是在计算平均值时被评估的生成器,它具有O(n)的复杂度。

>>> import numpy as np 
>>> from itertools import count, tee, izip, islice 
>>> map(np.mean, izip(*(islice(it,i,None,2) 
         for i, it in enumerate(tee(data, 4))))) 
[2.5, 4.5, 6.5, 8.5] 

有趣的是,单个itertools函数是如何协同工作的。

  1. itertools.tee正plicates迭代器,在这种情况下的4倍
  2. 枚举创建其产生指数和元件的元组枚举器对象(这是迭代器)
  3. 切片与步幅2迭代器,从指数位置开始。
+0

感谢您的帮助!这更符合我对itertools实现的期望,并且非常翔实。我很惊讶这实际上比其他答案慢,因为我的理解是itertools比在许多情况下使用列表理解更快。话虽如此,我选择mdml的答案,因为它更快,更具可读性。 – limi44