Нахождение минимального перехода пересечения нуля в NumPy - PullRequest
9 голосов
/ 23 мая 2019

Для задачи анализа данных я хочу найти пересечения нулей в массиве numpy, полученном в результате свертки с сначала подобным ядру ядром, а затем с ядром мексиканской шляпы.Пересечение нуля позволяет мне обнаруживать границы в данных.

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

import numpy as np
arr = np.array([12, 15, 9, 8, -1, 1, -12, -10, 10])

Должно привести к

>>>array([1, 3, 7])

или

>>>array([3, 7])

, где 3 - индекс -1, непосредственно перед серединой первого прыжка и 7 это индекс -10

Я попытался изменить следующий код (источник: Эффективно обнаруживать изменения знака в python )

zero_crossings = np.where(np.diff(np.sign(np.trunc(arr/10))))[0]

Какиеправильно игнорирует небольшие скачки, но ставит пересечения нуля на [1,5,7]

Какой эффективный способ сделать это?

Определение минимального прыжка не является строгим, но результаты должны соответствовать моему вопросу.

Редактировать: Для уточнения

arr = np.array([12, 15, 9, 8, -1, 1, -12, -10, 10])
arr_floored = np.trunc(arr/10)
>>>>np.array([10, 10, 0, 0, 0, 0, -10, -10, 10])
sgn = np.sign(arr_floored)
>>>>array([ 1,  1,  0,  0,  0,  0, -1, -1,  1])
dsgn = np.diff(sgn)
>>>>array([ 0, -1,  0,  0,  0, -1,  0,  2])
np.where(dsgn)
>>>>(array([1, 5, 7], dtype=int64),)

Другие случаи:

arr = [10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10]

Должно привести к

>>> np.array([10])

Также только что заметил: проблема может быть некорректной (в математическом смысле).Я уточню это позже сегодня.

Ответы [ 2 ]

3 голосов
/ 31 мая 2019

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

  • Вы не определили точно, какой диапазон точек данных следует учитывать, чтобы определить среднюю точку пересечения, но я использовал ваш пример кода какоснова - это было обнаружение пересечений, где ABS(start | end) >= 10, следовательно, я использовал диапазон минимум , где выполняется это условие.
    Примечание: это не обнаруживает переход от +15 к -6.
    РЕДАКТИРОВАТЬ : На самом деле это не всегда минимальный диапазон, но кода должно быть достаточно для того, чтобы вы могли приступить к работе и настроить его по мере необходимости.
  • Я предположил, что можно также использоватьпанды (для отслеживания индексов точек интереса данных).Вы, вероятно, можете избежать панд, если это необходимо.

import numpy as np import pandas as pd arr = np.array([12, 15, 9, 8, -1, 1, -12, -10, 10]) sgn = pd.Series(np.sign(np.trunc(arr/10))) trailingEdge = sgn[sgn!=0].diff() edgeIndex = np.array(trailingEdge[trailingEdge!=0].index) edgeIndex[:-1] + np.diff(edgeIndex) / 2

дает:

array([3., 7.])

и

arr = [10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10]

дает:

array([10.])

2 голосов
/ 27 мая 2019

Базовый случай

Полагаю, вы хотите

import numpy as np
x = np.array([10, -50, -30, 50, 10, 3, -200, -12, 123])
indices = np.where(np.logical_and(np.abs(np.diff(x)) >= 20, np.diff(np.sign(x)) != 0))[0]

читать как: индексы, где ((абсолютные разности x) больше или равны 20) и (знак переворачивается)

, который возвращает

array([0, 2, 5, 7])

Периодический сигнал

Обычные функции numpy не охватывают этот случай.Я бы предложил просто добавить первый элемент в конце с помощью функции pad:

import numpy as np
x = np.array([10, 5, 0, -5, -10])
x = np.pad(x, (0, 1), 'wrap')
indices = np.where(np.logical_and(np.abs(np.diff(x)) >= 20, np.diff(np.sign(x)) != 0))[0]
...