chr*_*ley 29 python math performance numpy
我想完成这个人做的事情:
但是我需要优化它以超快速运行.简而言之,我想要一个时间序列,并告诉每次它越过零(改变符号).我想记录过零点之间的时间.由于这是真实的数据(32位浮点数),我怀疑我每个都有一个正好为零的数字,所以这并不重要.我目前有一个计时程序,所以我会把你的结果计算在内,看看谁赢了.
我的解决方案给出(微秒):
open data 8384
sign data 8123
zcd data 415466
Run Code Online (Sandbox Code Playgroud)
如您所见,过零检测器是缓慢的部分.这是我的代码.
import numpy, datetime
class timer():
def __init__(self):
self.t0 = datetime.datetime.now()
self.t = datetime.datetime.now()
def __call__(self,text='unknown'):
print text,'\t',(datetime.datetime.now()-self.t).microseconds
self.t=datetime.datetime.now()
def zcd(data,t):
sign_array=numpy.sign(data)
t('sign data')
out=[]
current = sign_array[0]
count=0
for i in sign_array[1:]:
if i!=current:
out.append(count)
current=i
count=0
else: count+=1
t('zcd data')
return out
def main():
t = timer()
data = numpy.fromfile('deci.dat',dtype=numpy.float32)
t('open data')
zcd(data,t)
if __name__=='__main__':
main()
Run Code Online (Sandbox Code Playgroud)
Jim*_*som 65
关于什么:
import numpy
a = [1, 2, 1, 1, -3, -4, 7, 8, 9, 10, -2, 1, -3, 5, 6, 7, -10]
zero_crossings = numpy.where(numpy.diff(numpy.sign(a)))[0]
Run Code Online (Sandbox Code Playgroud)
输出:
> zero_crossings
array([ 3, 5, 9, 10, 11, 12, 15])
Run Code Online (Sandbox Code Playgroud)
即,zero_crossings将包含元素的索引,之后发生过零.如果您想要之前的元素,只需向该数组添加1即可.
Dom*_*ise 28
正如Jay Borseth所说,接受的答案不能正确处理包含0的数组.
我建议使用:
import numpy as np
a = np.array([-2, -1, 0, 1, 2])
zero_crossings = np.where(np.diff(np.signbit(a)))[0]
print(zero_crossings)
# output: [1]
Run Code Online (Sandbox Code Playgroud)
因为a)使用numpy.signbit()比numpy.sign()快一点,因为它的实现更简单,我想和b)它在输入数组中正确处理零.
但是有一个缺点,可能是:如果您的输入数组以零开始和停止,它将在开头找到零交叉,但不会在结束时找到...
import numpy as np
a = np.array([0, -2, -1, 0, 1, 2, 0])
zero_crossings = np.where(np.diff(np.signbit(a)))[0]
print(zero_crossings)
# output: [0 2]
Run Code Online (Sandbox Code Playgroud)
lmj*_*ns3 11
另一种计算零交叉并从代码中挤出几毫秒的方法是直接使用nonzero
和计算符号.假设你有一个一维数组data
:
def crossings_nonzero_all(data):
pos = data > 0
npos = ~pos
return ((pos[:-1] & npos[1:]) | (npos[:-1] & pos[1:])).nonzero()[0]
Run Code Online (Sandbox Code Playgroud)
或者,如果您只想计算特定零交叉方向的过零点(例如,从正到负),则更快:
def crossings_nonzero_pos2neg(data):
pos = data > 0
return (pos[:-1] & ~pos[1:]).nonzero()[0]
Run Code Online (Sandbox Code Playgroud)
在我的机器上,这些比where(diff(sign))
方法快一些(10000个正弦样本数组的定时包含20个循环,总共40个交叉点):
$ python -mtimeit 'crossings_where(data)'
10000 loops, best of 3: 119 usec per loop
$ python -mtimeit 'crossings_nonzero_all(data)'
10000 loops, best of 3: 61.7 usec per loop
$ python -mtimeit 'crossings_nonzero_pos2neg(data)'
10000 loops, best of 3: 55.5 usec per loop
Run Code Online (Sandbox Code Playgroud)
如果a包含值0,Jim Brissom的答案将失败:
import numpy
a2 = [1, 2, 1, 1, 0, -3, -4, 7, 8, 9, 10, -2, 1, -3, 5, 6, 7, -10]
zero_crossings2 = numpy.where(numpy.diff(numpy.sign(a2)))[0]
print zero_crossings2
print len(zero_crossings2) # should be 7
Run Code Online (Sandbox Code Playgroud)
输出:
[ 3 4 6 10 11 12 13 16]
8
Run Code Online (Sandbox Code Playgroud)
零交叉的数量应为7,但因为如果传递0则sign()返回0,正数为1,负值为-1,diff()将计算包含零的过渡两次.
另一种选择可能是:
a3 = [1, 2, 1, 1, 0, -3, -4, 7, 8, 9, 10, 0, -2, 0, 0, 1, 0, -3, 0, 5, 6, 7, -10]
s3= numpy.sign(a3)
s3[s3==0] = -1 # replace zeros with -1
zero_crossings3 = numpy.where(numpy.diff(s3))[0]
print s3
print zero_crossings3
print len(zero_crossings3) # should be 7
Run Code Online (Sandbox Code Playgroud)
给出正确答案:
[ 3 6 10 14 15 18 21]
7
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
36083 次 |
最近记录: |