сегментация временных рядов в python - PullRequest
0 голосов
/ 01 февраля 2020

Я пытаюсь сегментировать данные временных рядов, как показано на рисунке. У меня много данных с датчиков, любые из этих данных могут иметь разное количество изолированных пиков области. На этом рисунке у меня есть 3 из них. Я хотел бы иметь функцию, которая принимает временные ряды в качестве входных данных и возвращает сегментированные разделы равной длины.

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

Есть предложения?

Figure : Desired segmentation of the time-series data figure with axes

Ответы [ 2 ]

0 голосов
/ 02 февраля 2020

Для этого вам нужно найти сигнал вне шума.

  1. получить среднее значение вашего сигнала и добавить мультиплеер, который размещает границы сверху и снизу от шума - зеленая пунктирная линия
  2. найти пиковые значения ниже уровня шума -> массив 2 группы данных
  3. найти пиковые значения поверх уровня шума -> массив 2 группы данных
  4. получить минимальный индекс снизу первым пиковый и максимальный индекс вершины первого пика, чтобы найти диапазон первого пика
  5. получить минимальный индекс вершины второго пика и максимальный индекс дна второго пика, чтобы найти диапазон второго пика

Некоторые описание в коде. С помощью этого метода вы можете найти другие вершины. Одна вещь, которую вам нужно ввести вручную, это указать программе значение x между пиками для разделения данных на части.

См. Сводку графиков c.

import numpy as np
from matplotlib import pyplot as plt


# create noise data
def function(x, noise):
    y = np.sin(7*x+2) + noise
    return y

def function2(x, noise):
    y = np.sin(6*x+2) + noise
    return y


noise = np.random.uniform(low=-0.3, high=0.3, size=(100,))
x_line0 = np.linspace(1.95,2.85,100)
y_line0 = function(x_line0, noise)
x_line = np.linspace(0, 1.95, 100)
x_line2 = np.linspace(2.85, 3.95, 100)
x_pik = np.linspace(3.95, 5, 100)
y_pik = function2(x_pik, noise)
x_line3 = np.linspace(5, 6, 100)

# concatenate noise data
x = np.linspace(0, 6, 500)
y = np.concatenate((noise, y_line0, noise, y_pik, noise), axis=0)

# plot data
noise_band = 1.1
top_noise = y.mean()+noise_band*np.amax(noise)
bottom_noise = y.mean()-noise_band*np.amax(noise)
fig, ax = plt.subplots()
ax.axhline(y=y.mean(), color='red', linestyle='--')
ax.axhline(y=top_noise, linestyle='--', color='green')
ax.axhline(y=bottom_noise, linestyle='--', color='green')
ax.plot(x, y)

# split data into 2 signals
def split(arr, cond):
  return [arr[cond], arr[~cond]]

# find bottom noise data indexes
botom_data_indexes = np.argwhere(y < bottom_noise)
# split by visual x value
splitted_bottom_data = split(botom_data_indexes, botom_data_indexes < np.argmax(x > 3))

# find top noise data indexes
top_data_indexes = np.argwhere(y > top_noise)
# split by visual x value
splitted_top_data = split(top_data_indexes, top_data_indexes < np.argmax(x > 3))

# get first signal range
first_signal_start = np.amin(splitted_bottom_data[0])
first_signal_end = np.amax(splitted_top_data[0])

# get x index of first signal
x_first_signal = np.take(x, [first_signal_start, first_signal_end])
ax.axvline(x=x_first_signal[0], color='orange')
ax.axvline(x=x_first_signal[1], color='orange')

# get second signal range
second_signal_start = np.amin(splitted_top_data[1])
second_signal_end = np.amax(splitted_bottom_data[1])

# get x index of first signal
x_second_signal = np.take(x, [second_signal_start, second_signal_end])
ax.axvline(x=x_second_signal[0], color='orange')
ax.axvline(x=x_second_signal[1], color='orange')

plt.show()

Вывод:

красная линия = среднее значение всех данных

зеленая линия - верхняя и нижняя границы шума

оранжевая линия - выбранные пиковые данные

enter image description here

0 голосов
/ 01 февраля 2020

1, это зависит от того, как вы хотите определить «регион», но похоже, что у вас просто чувство вместо строгого определения. Если у вас есть очень четкое определение того, какую часть вы хотите вырезать, вы можете попробовать какой-нибудь метод, например «согласованный фильтр»

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

3, трудно работать с такими шумными данными, как эта. Мое предложение состоит в том, чтобы сделать фильтрацию, прежде чем вы берете разделы (на нефильтрованных данных). Фильтрация даст вам плавные пики, так что положение пиков может быть обнаружено по изменению знака производной. Для фильтрации попробуйте сначала просто «фильтр нижних частот». Если это не сработает, я также предлагаю «преобразование Гильберта – Хуанга».

*, похоже, вы используете matlab. Все упомянутые методы включены в Matlab.

...