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

eimct9ow  于 2022-12-18  发布在  其他
关注(0)|答案(8)|浏览(397)

我有一个numpy数组,里面有正值和负值。

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

我想创建另一个数组,其中包含符号发生变化的每个索引处的值(例如,如果当前元素为正,前一个元素为负,反之亦然)。
对于上面的数组,我希望得到以下结果

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

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

z4bn682m

z4bn682m1#

就像

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

vsdwdz23

vsdwdz232#

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

f4t66c6m3#

确定符号更改位置的三种方法

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)

方法三:正如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)
编辑:

对于大型阵列,方法1是最佳的。

14ifxucb

14ifxucb4#

上面的答案使用了列表解析和一些愚蠢的魔法来得到你想要的结果。下面是一个非常直接的方法,虽然有点复杂,但也能做到这一点:

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
ee7vknir

ee7vknir5#

不如

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

1cosmwyk

1cosmwyk6#

另一个关于获取'strict'符号从正到负和从负到正(不包括零)变化的想法:

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])
slsn1g29

slsn1g297#

为了直接解释这个问题,当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打印以指示不同数字之间的符号变化时,得到:
当使用以下方法打印时:

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

还要注意,这比原始数组少了一个元素,这是有意义的,因为你要求改变符号,如果你想包括最后一个和第一个元素之间的变化,你可以使用roll,就像其他人建议的那样。

piv4azn7

piv4azn78#

如果你只对一个方向的变化感兴趣(下面从负值到正值(正值包括零)):
arr = NP数组([1,1,-1,-2,-3,4,5])
其中(np.差((arr〉=0)*1)==1)
返回符号更改前每个最后负值的索引

相关问题