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

时间:2010-04-16 11:04:40

标签: python numpy

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

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

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

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

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

或者,数组中符号发生变化的位置列表或布尔值列表而不是0和1是很好。

7 个答案:

答案 0 :(得分:24)

这样的东西
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.如果不希望这样,那么当然可以做一个简单的< / p>

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

答案 1 :(得分:17)

(numpy.diff(numpy.sign(a)) != 0)*1

答案 2 :(得分:2)

三种方法产生符号发生变化的阵列中的位置数组

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提出。大多数IMO优雅但速度稍慢
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)

答案 3 :(得分:1)

怎么样

[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之外的任何符号的符号更改,这可能是你想要的。

答案 4 :(得分:1)

上面的答案使用列表推导和一些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

答案 5 :(得分:0)

对于这个问题的直接解释,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:]

使用TF打印时,表示不同数字之间的符号更改:

 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

答案 6 :(得分:0)

让“严格”符号从正变为负和从负变为正(不包括零)的另一个想法:

a = np.array([0.4, 0.5, -0.2, -0.6, 5, 0, 0, 5, 0,-2])

# Get associated index
ind =np.arange(len(a))

# remove zero from array but keep original index
a2 =a[a!=0.]
ind2  =ind[a!=0.]

# Detect sign changes in reduced array
idx=np.where(np.diff(np.sign(a2)) != 0)[0] + 1

# Get sign changes index for original array
ind2[idx]
array([2, 4, 9])