Python:可变宽度的滑动窗口

时间:2012-11-25 18:56:17

标签: python window sliding

我正在用Python编写一个程序来处理实验过程中产生的一些数据,并且需要估计数据的斜率。我已经编写了一段很好的代码,但速度非常慢(而且我不是很耐心)。让我解释一下这段代码是如何工作的:

1)它抓取一小块dx的数据(从3个数据点开始)

2)它评估差异(即| y(x + dx)-y(x-dx)|)是否大于某个最小值(40x std。开发噪声)

3)如果差异足够大,它将使用OLS回归计算斜率。如果差异太小,它将增加dx并使用这个新的dx重做循环

4)所有数据点都会继续

[进一步查看更新的代码]

对于大约100k测量的数据量,这需要大约40分钟,而程序的其余部分(它比这个位做更多的处理)大约需要10秒。我确信有一种更有效的方式来做这些操作,你能帮我解决一下吗?

由于

编辑:

好的,所以我通过仅使用二进制搜索解决了问题,将允许的步数限制为200.我感谢大家的输入,我选择了最能帮助我的答案。

最终更新代码:

def slope(self, data, time):
    (wave1, wave2) = wt.dwt(data, "db3")
    std = 2*np.std(wave2)
    e = std/0.05
    de = 5*std
    N = len(data)
    slopes = np.ones(shape=(N,))
    data2 = np.concatenate((-data[::-1]+2*data[0], data, -data[::-1]+2*data[N-1]))
    time2 = np.concatenate((-time[::-1]+2*time[0], time, -time[::-1]+2*time[N-1]))
    for n in xrange(N+1, 2*N):     
        left = N+1
        right = 2*N
        for i in xrange(200):
            mid = int(0.5*(left+right))
            diff = np.abs(data2[n-mid+N]-data2[n+mid-N])
            if diff >= e:
                if diff < e + de:  
                    break
                right = mid - 1
                continue
            left = mid + 1
        leftlim = n - mid + N
        rightlim = n + mid - N
        y = data2[leftlim:rightlim:int(0.05*(rightlim-leftlim)+1)]
        x = time2[leftlim:rightlim:int(0.05*(rightlim-leftlim)+1)]
        xavg = np.average(x)
        yavg = np.average(y)
        xlen = len(x)
        slopes[n-N] = (np.dot(x,y)-xavg*yavg*xlen)/(np.dot(x,x)-xavg*xavg*xlen)
    return np.array(slopes) 

3 个答案:

答案 0 :(得分:0)

如何优化这将取决于您的数据的某些属性,但这里有一些想法:

  1. 您是否尝试过分析代码?使用Python profilers中的一个可以为您提供有关花费最多时间的有用信息。通常,你刚刚写的一段代码会有一个最大的瓶颈,而且它并不总是很明显;分析可以让你弄清楚并首先攻击主要瓶颈。

  2. 您知道i的典型值是什么吗?如果您有一些想法,可以通过从大于0的i开始(如@vhallac所述)或通过增大i更大的数量来加快速度 - 如果您经常看到{{i的大值1}},一次将i增加2或3;如果i s的分布有长尾,请每次尝试加倍;等

  3. 进行最小二乘回归时是否需要所有数据?如果该函数调用是瓶颈,则可以通过仅使用该范围中的一些数据来加速它。例如,假设在特定点,您需要i为200才能看到数据中足够大(高于噪声)的变化。但是你可能不需要所有400点来获得斜率的良好估计 - 只需使用10或20个点,在start:end范围内均匀间隔,可能就足够了,并且可能会加速代码。

答案 1 :(得分:0)

您的意见建议您需要找到一个更好的方法来估计i k + 1 给定i k 。对data中的值的了解不会产生天真的算法:

n的每次迭代中,将i保留为之前的值,并查看abs(data[start]-data[end])值是否小于e。如果是,请将i保留为其先前的值,并通过将其增加1来找到新的值,就像现在一样。如果它更大或相等,则在i上执行二进制搜索以找到适当的值。您可以进行二进制搜索,但在不知道data的情况下找到一个好的候选上限可能会很困难。该算法的性能不会比您当前的估算方法差。

如果您知道data有点平滑(没有突然跳转,因此所有i值的平滑图)并且单调递增,您可以用向后搜索替换二进制搜索相反,将其值减1。

答案 2 :(得分:0)

我使用Python进行类似的分析,并提出一些建议。我没有查看代码的详细信息,仅查看您的问题陈述:

  

1)它抓取一小块dx的数据(从3开始)   数据点)

     

2)它评估差异(即| y(x + dx)-y(x-dx)|)是否为   大于某个最小值(40x标准偏差)

     

3)如果差异足够大,它将计算斜率   使用OLS回归。如果差异太小,它会增加   dx并使用这个新的dx重做循环

     

4)所有数据点都会继续

我认为执行缓慢的更明显原因是代码的循环性质,或许您可以使用Numpy的VECTORIZED(基于数组的操作)性质。

对于步骤1,您可以直接执行`data [3:] - data [-3:]并获取单个数组操作中的所有差异,而不是取成对点;

对于第2步,您可以使用基于数组的测试(如numpy.argwhere(data > threshold))的结果,而不是测试某个循环中的每个元素;

步骤3听起来在概念上对我来说是错误的。你说如果差异太小,它会增加dx。但如果差异很小,产生的斜率会很小,因为它实际上很小。然后,获得一个小值是正确的结果,并且人为地增加dx以获得“更好”的结果可能不是您想要的。嗯,它可能实际上是你想要的,但你应该考虑这个。我建议您计算整个数据中固定dx的斜率,然后获取生成的斜率数组以选择您感兴趣的区域(例如,使用data_slope[numpy.argwhere(data_slope > minimum_slope)]

希望这有帮助!