Обнаружение пиков в неравномерно распределенных временных рядах - PullRequest
0 голосов
/ 18 июня 2020

Я работаю с набором данных, содержащим меры в сочетании с datetime, например:

datetime value
2017-01-01 00:01:00,32.7
2017-01-01 00:03:00,37.8
2017-01-01 00:04:05,35.0
2017-01-01 00:05:37,101.1
2017-01-01 00:07:00,39.1
2017-01-01 00:09:00,38.9

Я пытаюсь обнаружить и удалить потенциальные пики, которые могут появиться, например 2017-01-01 00:05:37,101.1 measure.

Некоторые вещи, которые я нашел до сих пор:

  • Этот набор данных имеет временной интервал от 15 секунд до 25 минут, что делает его очень неравномерным;
  • Ширина пиков не может быть определена заранее
  • Высота пиков явно и значительно отличается от других значений
  • Нормализация временного шага должна происходить только после удаления выбросы, поскольку они будут мешать получению результатов

  • Это «невозможно» сделать даже из-за других аномалий (например, отрицательные значения, плоские линии), даже без них это создало бы неправильные значения из-за пиков;

  • find_peaks ожидает равномерно распределенных временных рядов, поэтому решение предыдущее не работало для нерегулярных временных рядов у нас есть;
    • По этому поводу я забыл упомянуть критическую точку, которая представляет собой неравномерно распределенные временные ряды.

Я искал везде и ничего не нашел. Реализация будет в Python, но я готов покопаться в других языках, чтобы получить лог c.

1 Ответ

1 голос
/ 23 июня 2020
• 1000 . Используя то, что мне сказал @ user58697, мне удалось создать код, который обнаруживает каждый пик между порогом.

Используя logi c, который он объяснил if ((flow[i+1] - flow[i]) / (time[i+1] - time[i]) > threshold, я закодировал следующий код:

Началось с чтения .csv и анализа дат с последующим разделением на два массива numpy:

dataset = pd.read_csv('https://raw.githubusercontent.com/MigasTigas/peak_removal/master/dataset_simple_example.csv', parse_dates=['date'])

dataset = dataset.sort_values(by=['date']).reset_index(drop=True).to_numpy()  # Sort and convert to numpy array

# Split into 2 arrays
values = [float(i[1]) for i in dataset]  # Flow values, in float
values = np.array(values)

dates = [i[0].to_pydatetime() for i in dataset]
dates = np.array(dates)

Затем применил (flow[i+1] - flow[i]) / (time[i+1] - time[i]) ко всему набору данных:

flow = np.diff(values)
time = np.diff(dates).tolist()
time = np.divide(time, np.power(10, 9))

slopes = np.divide(flow, time) # (flow[i+1] - flow[i]) / (time[i+1] - time[i])
slopes = np.insert(slopes, 0, 0, axis=0) # Since we "lose" the first index, this one is 0, just for alignments

И, наконец, для обнаружения пиков мы сократили данные до windows по x секунд каждый. Таким образом, мы можем легко их обнаружить:

# ROLLING WINDOW
size = len(dataset)
rolling_window = []
rolling_window_indexes = []
RW = []
RWi = []
window_size = 240  # Seconds

dates = [i.to_pydatetime() for i in dataset['date']]
dates = np.array(dates)

# create the rollings windows
for line in range(size):
    limit_stamp = dates[line] + datetime.timedelta(seconds=window_size)
    for subline in range(line, size, 1):
        if dates[subline] <= limit_stamp:

            rolling_window.append(slopes[subline])  # Values of the slopes
            rolling_window_indexes.append(subline)  # Indexes of the respective values

        else:

            RW.append(rolling_window)
            if line != size: # To prevent clearing the last rolling window
                rolling_window = []

            RWi.append(rolling_window_indexes)
            if line != size:
                rolling_window_indexes = []

            break
else:
    # To get the last rolling window since it breaks before append
    RW.append(rolling_window)
    RWi.append(rolling_window_indexes)

После того, как все прокатилось windows мы начинаем веселье:

t = 0.3  # Threshold
peaks = []

for index, rollWin in enumerate(RW):
    if rollWin[0] > t: # If the first value is greater of threshold
        top = rollWin[0] # Sets as a possible peak
        bottom = np.min(rollWin) # Finds the minimum of the peak

        if bottom < -t: # If less than the negative threshold
            bottomIndex = int(np.argmin(rollWin)) # Find it's index

            for peak in range(0, bottomIndex, 1): # Appends all points between the first index of the rolling window until the bottomIndex
                peaks.append(RWi[index][peak]) 

Идея этого кода заключается в том, что каждый пик имеет подъем и падение, и если оба превышают заявленный порог, то это пик выброса вместе со всеми пиками между ними:

enter image description here

enter image description here

Where translated to the real dataset used, posted on github : enter image description here введите описание изображения здесь

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