Как обнаружить изменение знака для элементов в массиве NumPy - PullRequest
24 голосов
/ 16 апреля 2010

У меня есть массив с положительными и отрицательными значениями в.

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

Я хочу создать еще один массив, содержащий значение в каждом индексе, где происходит смена знака (например, если текущий элемент положительный, а предыдущий элемент отрицательный и наоборот).

Для приведенного выше массива я ожидал бы получить следующий результат

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

В качестве альтернативы, список позиций в массиве, где происходят изменения знака, или список логических значений вместо 0 и 1 вполне подойдет.

Ответы [ 6 ]

24 голосов
/ 16 апреля 2010

Что-то вроде

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. Если это нежелательно, конечно, можно сделать простой 1004 *

signchange[0] = 0

Кроме того, np.sign считает, что 0 имеет собственный знак, отличный от положительных или отрицательных значений. Например. массив "signchange" для [-1,0,1] будет [0,1,1], даже если нулевая линия была "пересечена" только один раз. Если это нежелательно, можно вставить строки

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

между строками 2 и 3 в первом примере.

17 голосов
/ 30 января 2011
(numpy.diff(numpy.sign(a)) != 0)*1
2 голосов
/ 26 мая 2017

Три метода, дающие массив позиций в массиве, где происходят изменения знака

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)
1 голос
/ 16 апреля 2010

Ответы выше используют списочные понимания и некоторую магию, чтобы получить желаемый результат. Вот очень простой, хотя и немного запутанный, способ сделать то же самое:

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
1 голос
/ 16 апреля 2010

Как насчет

[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 голосов
/ 17 апреля 2010

Для прямой интерпретации этого вопроса, где 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, как предлагали другие.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...