代码之家  ›  专栏  ›  技术社区  ›  chriscauley

在python中有效地检测符号变化

  •  24
  • chriscauley  · 技术社区  · 15 年前

    我想做这个人所做的:

    Python - count sign changes

    不过,我需要优化它运行超快。简言之,我想取一个时间序列,告诉它每过零(变号)。我想记录一下过零点之间的时间。因为这是真实的数据(32位浮点),我怀疑每个人都会有一个正好是零的数字,所以这并不重要。我目前有一个计时程序,所以我会计时你的结果,看看谁赢。

    我的解决方案给出(微秒):

    open data       8384
    sign data       8123
    zcd data        415466
    

    如你所见,过零检测器是慢的部分。这是我的密码。

    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()
    
    7 回复  |  直到 9 年前
        1
  •  69
  •   Mike dubiousjim    6 年前

    关于:

    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]
    

    输出:

    > zero_crossings
    array([ 3,  5,  9, 10, 11, 12, 15])
    

    一、 例如,零交叉口将包含元素的索引 发生过零点。如果你想要这些元素 ,只需在该数组中添加1。

        2
  •  32
  •   Serge Stroobandt    9 年前

    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]
    

    因为a)使用纽比。符号位()比纽比符号(),因为它的实现更简单,我想和b)它正确地处理输入数组中的零。

    但是有一个缺点,也许:如果你的输入数组以0开头和结尾,它将在开始处找到一个过零点,但不会在结尾处找到。。。

    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]
    
        3
  •  13
  •   lmjohns3    12 年前

    另一种计算零交叉并从代码中挤出几毫秒的方法是使用 nonzero 直接计算符号。假设你有一个一维数组 data :

    def crossings_nonzero_all(data):
        pos = data > 0
        npos = ~pos
        return ((pos[:-1] & npos[1:]) | (npos[:-1] & pos[1:])).nonzero()[0]
    

    或者,如果您只想计算特定方向的过零次数(例如,从正到负),则速度更快:

    def crossings_nonzero_pos2neg(data):
        pos = data > 0
        return (pos[:-1] & ~pos[1:]).nonzero()[0]
    

    where(diff(sign))

    $ 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
    
        4
  •  9
  •   Jay Borseth    12 年前

    如果

    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
    

    输出:

    [ 3  4  6 10 11 12 13 16]  
    8  
    

    过零的次数应该是7,但是由于sign()在传递0时返回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
    

    给出正确答案:

    [ 3  6 10 14 15 18 21]
    7
    
        5
  •  3
  •   Mike Dunlavey    15 年前

    你想计时吗?还是你想尽快赶到?

        6
  •  1
  •   ntg    9 年前

    我看到人们在他们的解决方案中经常使用diff,但是xor似乎要快得多,而且结果对于bools也是一样的(一个很好的指针可能是使用diff会发出一个不推荐的警告。。。。:) ) 下面是一个例子:

    positive = a2 > 0
    np.where(np.bitwise_xor(positive[1:], positive[:-1]))[0]
    

    时间,它衡量它大约快一个半左右的差异对我来说:)

    如果您不关心边缘情况,则最好使用

    positive = np.signbit(a2)
    

    但是正=a2>0似乎比signbit更快(更干净)并检查0(例如,正=np.按位\u或(np.符号位(a2),np.逻辑不(a2)速度较慢…)

        7
  •  0
  •   KalanyuZ    8 年前

    np.diff(np.sign(a)) .

    如果我们比较一下这个表达式对某些情况的反应:

    1. 无零上升交叉: np.diff(np.sign([-10, 10])) array([2])
    2. 零上升交点: np.diff(np.sign([-10, 0, 10])) array([1, 1])
    3. 无零坠落交叉: np.diff(np.sign([10, -10])) array([-2])
    4. 零位坠落交叉: np.diff(np.sign([10, 0, -10])) array([-1, -1])

    np.diff(...) 对于1中返回的模式。和2:

    sdiff = np.diff(np.sign(a))
    rising_1 = (sdiff == 2)
    rising_2 = (sdiff[:-1] == 1) & (sdiff[1:] == 1)
    rising_all = rising_1
    rising_all[1:] = rising_all[1:] | rising_2
    

    对于第三种情况。和4.:

    falling_1 = (sdiff == -2) #the signs need to be the opposite
    falling_2 = (sdiff[:-1] == -1) & (sdiff[1:] == -1)
    falling_all = falling_1
    falling_all[1:] = falling_all[1:] | falling_2
    

    indices_rising = np.where(rising_all)[0]
    indices_falling = np.where(falling_all)[0]
    indices_both = np.where(rising_all | falling_all)[0]
    

    这种方法应该是合理的快速方法,因为它可以在不使用“慢”循环的情况下进行管理。

    这结合了其他几个答案的方法。