代码之家  ›  专栏  ›  技术社区  ›  Robert Christie

如何检测numpy数组中元素的符号更改

  •  24
  • Robert Christie  · 技术社区  · 15 年前

    我有一个numpy数组,其中有正值和负值。

    a = array([1,1,-1,-2,-3,4,5])
    

    我想创建另一个数组,该数组在发生符号更改的每个索引处都包含一个值(例如,如果当前元素为正,而前一个元素为负,反之亦然)。

    对于上面的数组,我希望得到以下结果

    array([0,0,1,0,0,1,0])
    

    或者,数组中出现符号更改的位置列表或布尔值列表(而不是0和1)也可以。

    6 回复  |  直到 7 年前
        1
  •  23
  •   janneb    15 年前

    类似的东西

    a = array([1,1,-1,-2,-3,4,5])
    asign = np.sign(a)
    signchange = ((np.roll(asign, 1) - asign) != 0).astype(int)
    print signchange
    array([0, 0, 1, 0, 0, 1, 0])
    

    现在,numpy.roll执行循环移位,因此如果最后一个元素的符号与第一个元素的符号不同,那么signChange数组中的第一个元素将为1。如果不需要这样做,当然可以做一个简单的

    signchange[0] = 0
    

    另外,np.sign认为0有它自己的符号,不同于正值或负值。例如,[-1,0,1]的“signchange”数组将为[0,1,1],即使零行仅“交叉”一次。如果不希望这样,可以插入行

    sz = asign == 0
    while sz.any():
        asign[sz] = np.roll(asign, 1)[sz]
        sz = asign == 0
    

    在第一个示例的第2行和第3行之间。

        2
  •  17
  •   Christian Alis    14 年前
    (numpy.diff(numpy.sign(a)) != 0)*1
    
        3
  •  2
  •   Jon    15 年前

    上面的答案使用列表理解和一些麻木的魔力来得到你想要的结果。下面是一个非常直接的方法,如果有点复杂,也可以这样做:

    import numpy as np
    
    arr = np.array([1,1,-1,-2,-3,4,5])
    
    result = []
    for i, v in enumerate(arr):
        if i == 0:
            change = False
        elif v < 0 and arr[i-1] > 0:
            change = True
        elif v > 0 and arr[i-1] < 0:
            change = True
        else:
            change = False
    
        result.append(change)
    
    print result
    
        4
  •  1
  •   Personman    15 年前

    怎么样

    [0 if x == 0 else 1 if numpy.sign(a[x-1]) != numpy.sign(y) else 0 for x, y in enumerate(a)]
    

    numpy.sign为0分配自己的符号,因此0s将是除其他0s之外的任何符号更改,这可能是您想要的。

        5
  •  1
  •   DougR    7 年前

    三种方法生成数组中发生符号更改的位置的数组

    import numpy as np
    a = np.array([1,1,-1,-2,-3,4,5])
    
    方法1:将数组中的相邻项相乘并求负
    idx1=np.where(a[:-1] * a[1:] < 0 )[0] +1
    idx1
    Out[2]: array([2, 5], dtype=int64)
    
    %timeit np.where(a[:-1] * a[1:] < 0 )[0] + 1
    4.31 µs ± 15.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
    
    方法2(最快):相邻标志不相等
    idx2=np.where(np.sign(a[:-1]) != np.sign(a[1:]))[0] + 1
    idx2
    Out[4]: array([2, 5], dtype=int64)
    
    %timeit np.where(np.sign(a[:-1]) != np.sign(a[1:]))[0] + 1
    3.94 µs ± 20.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
    
    方法3:由Ianalis提出。我觉得很优雅,但有点慢
    idx3=np.where(np.diff(np.sign(a)) != 0)[0] + 1
    idx3
    Out[6]: array([2, 5], dtype=int64)
    
    %timeit np.where(np.diff(np.sign(a)) != 0)[0] + 1
    9.7 µs ± 36.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
    
        6
  •  0
  •   tom10    15 年前

    对于这个问题的直接解释,0不是他们自己的情况,它可能更容易使用 greater sign . 下面是一个例子:

    a = array([1, 1, -1, -2, -3, 0, 4, 0, 5, 6])
    
    x = greater_equal(a, 0)
    sign_change = x[:-1]-x[1:]
    

    当打印时, T F 指示不同数字之间的符号变化:

     1 F 1 T -1 F -2 F -3 T 0 F 4 F 0 F 5 F 6
    

    打印时使用:

    print `a[0]`+"".join([(" T" if sign_change[i] else " F")+" "+`a[i+1]` for i in range(len(sign_change))])
    

    还要注意,这是一个比原始数组短的元素,这是有意义的,因为您要求更改符号。如果要包括最后一个元素和第一个元素之间的更改,可以使用 roll 正如其他人所建议的。