2016-03-03 65 views
0

我有一個大數據集的形式[t, y(t)]我想應用IIR低通濾波器(一階或二階巴特沃斯應該足夠了)使用scipy.signal(特別是scipy.filter.butterscipy.filter.filtfilt)。問題是t沒有規律的間隔,這似乎是scipy.signal中功能的要求。scipy.signal:過濾可變時間數據集

對於任何「失蹤」點,我知道我的信號仍然來自其前值持平(所以給定連續的二點t1和我t -data t2和數據點T沒有,這樣t1<T<t2,該我正在抽樣的「真實」功能Y(t)將取值Y(T)=Y(t1))。 t是整數值,所以我可以簡單地添加缺少的點,但這會導致我的數據集的大小增加10倍,這是有問題的,因爲它已經非常大。

所以問題是,是否有一個(足夠簡單和低開銷)的方式來過濾我的數據集而不插入所有「缺失」點?

回答

0

您可以高效地將數據「包裝」到一個函數中。

如果您的數據是以列表的形式列出的,那麼您需要將其轉換爲dict並創建t值的排序列表。然後,您可以使用bisect模塊中的列表平分算法對缺失值進行插值。

下面是一些使用Python 2編寫的演示代碼,但如果需要,它應該直接將其轉換爲Python 3。

from random import seed, sample 
from bisect import bisect 

#Create some fake data 
seed(37) 
data = dict((u, u/10.) for u in sample(xrange(50), 25)) 

keys = data.keys() 
keys.sort() 
print keys 

def interp(t): 
    i = bisect(keys, t) 
    k = keys[max(0, i-1)] 
    return data[k] 

for i in xrange(50): 
    print i, interp(i)  

輸出

[2, 4, 8, 10, 14, 15, 19, 21, 22, 23, 26, 27, 29, 30, 
32, 33, 34, 35, 37, 38, 39, 42, 43, 44, 48] 
0 0.2 
1 0.2 
2 0.2 
3 0.2 
4 0.4 
5 0.4 
6 0.4 
7 0.4 
8 0.8 
9 0.8 
10 1.0 
11 1.0 
12 1.0 
13 1.0 
14 1.4 
15 1.5 
16 1.5 
17 1.5 
18 1.5 
19 1.9 
20 1.9 
21 2.1 
22 2.2 
23 2.3 
24 2.3 
25 2.3 
26 2.6 
27 2.7 
28 2.7 
29 2.9 
30 3.0 
31 3.0 
32 3.2 
33 3.3 
34 3.4 
35 3.5 
36 3.5 
37 3.7 
38 3.8 
39 3.9 
40 3.9 
41 3.9 
42 4.2 
43 4.3 
44 4.4 
45 4.4 
46 4.4 
47 4.4 
48 4.8 
49 4.8 

(I手動包裹的keys輸出,使其更容易,而不水平滾動閱讀)。

你會通過重新編寫插補功能的身體在一條線得到微小加速:

def interp(t): 
    return data[keys[max(0, bisect(keys, t)-1)]] 

它更可讀,恕我直言,但速度差可以值得它如果函數被調用了很多。

0

PM 2Ring的答案有效,但假設您的數據已經訂購了t,它的效率會低於可能。它需要對數線性時間和線性額外空間。你可以寫一個發生在線性時間和恆定的額外空間產生變換數據集定期採樣間隔:

# Assumes that dataset rows are lists as described in the question: 
# [[t1, Y(t1)], [t2, Y(t2)], [t3, Y(t3)], ..., [tz, Y(tz)]] 
# If this assumption is wrong, just extract t and Y(t) in another way. 

# The generated range starts at t1 and ends directly after tz. 
# Warning: will overgenerate points if the data are more densely sampled 
# than the requested sampling interval. 

def step_interpolate(dataset, interval): 
    left = next(dataset) # [t1, Y(t1)] 
    right = next(dataset) # [t2, Y(t2)] 
    t_regular = left[0] 
    while True: 
     if left is right:   # same list object 
      right = next(dataset) # iteration stops when dataset stops 
     if right[0] <= t_regular: 
      left = right 
     yield [t_regular, left[1]] 
     t_regular += interval 

測試:

data = [[1, 10], [15, 2], [50, 100], [55, 17]] 
for item in step_interpolate(iter(data), 10): 
    print item[0], item[1] 

輸出:

1 10 
11 10 
21 2 
31 2 
41 2 
51 100 
61 17 
+0

謝謝!不幸的是,它看起來像'scipy.filtfilt'不接受生成器,所以我仍然需要構建一個數組。我認爲在這一點上,我應該只花了一大筆錢,看看是否能工作沒有擊中醇」 OOM殺,因爲我害怕任何東西都不會變成一個真正的DIY解決方案,其中SciPy的不能幫助我了。 –

+0

經過一些頭部劃傷後,如果點比「間隔」密集得多,它看起來像是發生器失敗。如果您嘗試'數據集= [[1,1],[2,2],[3,3],[4,4]]',然後'step_interpolate(數據集,3)'將給出'[[1,1],[ 4,2],[7,3],[10,4]]。與我的案件不相關,但這是一個重要的警告。 –

+0

關於第一點:您可以在調用任何數組數據結構('np.array'或其他?)的過程中將調用包裝爲'step_interpolate(iter(data),interval)'。你失去了內存優勢,但保持速度優勢。關於第二點:好的電話,我會添加關於包裝密度警告的評論。如果你願意,我也可以解決這個問題。 – Julian