我正在用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)
答案 0 :(得分:0)
如何优化这将取决于您的数据的某些属性,但这里有一些想法:
您是否尝试过分析代码?使用Python profilers中的一个可以为您提供有关花费最多时间的有用信息。通常,你刚刚写的一段代码会有一个最大的瓶颈,而且它并不总是很明显;分析可以让你弄清楚并首先攻击主要瓶颈。
您知道i
的典型值是什么吗?如果您有一些想法,可以通过从大于0的i
开始(如@vhallac所述)或通过增大i
更大的数量来加快速度 - 如果您经常看到{{i
的大值1}},一次将i
增加2或3;如果i
s的分布有长尾,请每次尝试加倍;等
进行最小二乘回归时是否需要所有数据?如果该函数调用是瓶颈,则可以通过仅使用该范围中的一些数据来加速它。例如,假设在特定点,您需要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)]
。
希望这有帮助!