2016-03-03 61 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