aimclub / Fedot.Industrial

Python framework for automated time series classification, regression and forecasting
https://fedotindustrial.readthedocs.io
BSD 3-Clause "New" or "Revised" License
83 stars 7 forks source link

add data splitter for time series #73

Closed v1docq closed 11 months ago

v1docq commented 1 year ago

Необходимо реализовать интерфейс (возможно в рамках API), который принимает на вход временной ряд и словарь. Ключами словаря являются лейблы аномалий, значения словарь - список который содержит все индексы (в формате [start1:end1,...,start1000:end1000]) конкретной аномалии. На выходе данный интерфейс должен возвращать тренировочный и тестовый наборы данных для решения задачи классификации временных рядов. Важные уточнения:

  1. Если у одной и той же аномалии разная длинна подпоследовательности, то возможны 2 стратегии формирования тренировочного набора данных. Первая - выбирается "наиболее часто встречаемая" длина аномалии, остальные выбрасываются. Вторая - каждая длина подпоследовательности данной аномалии это отдельный класс аномалии, пример - "Anomaly_1_length_20 sec'.
  2. Данный метод должен быть обобщаем на многомерный случай. В таком варианте так же возможны 2 стратегии, когда индексы аномалии индвидуальны для каждой компоненты многомерного ряда и когда есть "единный" индекс аномалии для многомерного ряда.
technocreep commented 1 year ago

Создал модуль для решения этой задачи, он лежит тут

https://github.com/aimclub/Fedot.Industrial/blob/basis_func_extension/fedot_ind/core/operation/transformation/splitter.py

Механика довольно проста, но работает как часы:

  1. В инстанс класса передаём временной ряд или список временных рядов, если задача многомерная
  2. Вызываем метод split(), в который передаём два аргумента – строить ли на выходе графики (работает на одномерном ряду, пока) и нужно ли бинаризовать таргет (в случае сильного дисбаланса классов).
  3. Внутри парсится словарь, интервалы трансформируются в соответствии со стратегией "наиболее встречаемая аномалия" (все интервалы подгоняются под размер наиболее часто встречающейся), временной ряд (одно- или многомерный) "режется" на аномальные сэмплы.
  4. Затем выполняется балансировка аномальных сэмплов неаномальными. Для этого из участков временного ряда, которые не заняты аномалиями, случайным образом выбираются интервалы, их которых случайно выбираются участки. Процесс повторяется, пока не наберётся необходимое количество неаномальных сэмплов.
  5. Затем набор сэмплов и целевых переменных с помощью train_test_split превращается в подвыборки test train
  6. Всё
technocreep commented 1 year ago

В принципе, учёл все пожелания, кроме второй предлагаемой стратегии:

Вторая - каждая длина подпоследовательности данной аномалии это отдельный класс аномалии, пример - "Anomaly_1_length_20 sec'.

Мне тут не совсем понятна идея: должно получиться несколько датасетов под каждую (или несколько) аномалию? Ведь если мы оставим длины аномалий как есть, то их не сложить в датасет

technocreep commented 1 year ago

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

unique_ts = np.random.rand(800)
anomaly_unique = {
      'class1': '0:10, 20:30',
      'class2': '0:20, 50:70'}

splitter_unique = TSSplitter(time_series=unique_ts,
                                               anomaly_dict=anomaly_unique,
                                               strategy='unique')

unique_cls, unique_train, unique_test = splitter_unique.split(binarize=False)

unique_cls, unique_train, unique_test - списки, где количество элементов == количеству найденных уникальных аномалий