2014-01-13 109 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