Efficiently detect sign-changes in python

前端 未结 7 1544
深忆病人
深忆病人 2020-11-29 20:28

I want to do exactly what this guy did:

Python - count sign changes

However I need to optimize it to run super fast. In brief I want to take a time series an

7条回答
  •  无人及你
    2020-11-29 21:11

    Another way that might suit certain applications is to extend the evaluation of the expression np.diff(np.sign(a)).

    If we compare how this expression reacts to certain cases:

    1. Rising crossing without zero: np.diff(np.sign([-10, 10])) returns array([2])
    2. Rising crossing with zero: np.diff(np.sign([-10, 0, 10])) returns array([1, 1])
    3. Falling crossing without zero: np.diff(np.sign([10, -10])) returns array([-2])
    4. Falling crossing with zero: np.diff(np.sign([10, 0, -10])) returns array([-1, -1])

    So we have to evaluate np.diff(...) for the returned patterns in 1. and 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
    

    and for the cases 3. and 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
    

    After this we can easily find the indices with

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

    This approach should be reasonable fast because it can manage without using a "slow" loop.

    This combines the approach of several other answers.

提交回复
热议问题