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

Python 如何检测numpy数组中元素的符号更改,python,numpy,Python,Numpy,我有一个numpy数组,其中有正值和负值 a = array([1,1,-1,-2,-3,4,5]) 我想创建另一个数组,该数组在发生符号更改的每个索引处包含一个值(例如,如果当前元素为正,前一个元素为负,反之亦然) 对于上面的数组,我希望得到以下结果 array([0,0,1,0,0,1,0]) 或者,数组中发生符号变化的位置列表或布尔值列表(而不是0和1)也可以 a = array([1,1,-1,-2,-3,4,5]) asign = np.sign(a) signchange = (

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

a = array([1,1,-1,-2,-3,4,5])
我想创建另一个数组,该数组在发生符号更改的每个索引处包含一个值(例如,如果当前元素为正,前一个元素为负,反之亦然)

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

array([0,0,1,0,0,1,0])
或者,数组中发生符号变化的位置列表或布尔值列表(而不是0和1)也可以

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行之间。

如何

[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指定自己的符号,因此0将是除其他0以外的任何0的符号更改,这可能是您想要的。

以上答案使用列表理解和一些numpy魔术来获得您想要的结果。这是一个非常直接的方法,如果有点复杂的话,也是这样做的:

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
将numpy导入为np
arr=np.数组([1,1,-1,-2,-3,4,5])
结果=[]
对于枚举(arr)中的i、v:
如果i==0:
更改=错误
elif v<0和arr[i-1]>0:
更改=正确
elif v>0且arr[i-1]<0:
更改=正确
其他:
更改=错误
结果。追加(更改)
打印结果

对于这个问题的直接解释,如果0不是他们自己的情况,那么使用
大于
符号
可能更容易。下面是一个例子:

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

三种方法确定符号更改发生的位置
(numpy.diff(numpy.sign(a)) != 0)*1
方法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)
方法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)

请注意,如果最后一个元素与第一个元素的符号不同,则这将表示第一个位置的符号更改。它还认为0是与正或负不同的符号。所以
[-1,0,1]
将给出
signchange=[1,1,1]
。这可能是需要的行为,但我想我应该指出它。@tgray是的,我修改了我的答案,指出了如何解决这些问题,如果需要的话。它不会在
np.array([1,0,-1])
中注册更改,现在这段代码不起作用了。它给出一个错误::::TypeError:numpy boolean subtract,即
-
运算符,已被弃用,请改用按位异或、
^
运算符或逻辑异或函数。所以,请使用其他答案伟大的解决方案。。。现在,如何对每行的总号变化优雅地求和?指定
diff
sum
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)
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)