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

architecture refactoring #80

Closed v1docq closed 11 months ago

v1docq commented 1 year ago

Требуется либо избавиться от "ненужных модулей" либо объединить их между собой.

  1. fedot_ind/core/operation/interfaces/industrial_preprocessing_strategy.py имеет вот такой словарь моделей из индастриала image это позволяет совмещать оптимизатор федота и наши модели для настройки гиперпараметров и композирования. В то же время существует fedot_ind/core/architecture/pipelines в котором есть решения по созданию "шаблонов/пресетов пайплайнов". Выглядит так: image основная идея что операции там записаны в функциональном стиле с использованием монад/каррирования/композиции и всего прочего. image. Требуется решить следующие:
  2. нужен ли этот модуль (например как удобная обертка для апи и составления пайплайнов в интерактивном режиме)
  3. есть ли там операции которые нужно адаптировать под федот что использовать его оптимизатор
  4. можно ли функциональную составляющую оттуда распространить на другие модули
v1docq commented 11 months ago
  1. Заменить метод поиска пиков для массива коэфицентов полученных после вейвлет преобразования. fedot_ind/core/models/signal/SignalExtractor.py здесь находиться модель для генерации признаков после вейвлет преобразования. У нее есть вот такой метод.

image она подсчитывает число "пиков" (значения коээфициентов которые значимо отличаются от других), в зависимости от ряда гиперпараметров (расстояние между пиками, продолжительность пика, проч)

однако в scipy уже реализовано подобное. from scipy.signal import find_peaks_cwt image

параметры плюс минус все теже, разве что можно прокинуть свой тип вейвлета.

Выглядит как кандидат на рефакторинг.

v1docq commented 11 months ago
  1. Использования методов поиска "оптимального окна" для определения начальных приблежений окон при ганкелизации матриц/ SSA прогнозе/ поиске сезонности.

вот здесь fedot_ind/core/operation/transformation/WindowSelection.py лежит класс в котором реализованы 4 метода для определения окна временного ряда. Окно дает представления о возможносй сезонности, о лучшем вложении для траекторной матрицы (что дает лучшую разделимость ряда и лучший базис). метод для получения лучшего окна def get_window_size(). В самом коде много косяков:

  1. (например фурье разложение написанно ручками, а не через scipy.signal) image
  2. Очень большие куски кода с логическими ветвлениями внутри одной функции image 3.Все методы открыты для вызова из класса хотя дальше этого класса нигде не используются

Что надо сделать.

  1. Прикрутить этот класса к API индстриала чтоб этот класс реализовывал подбор начального приблежения "окна" для задач классификации (если используетися data-driven basis) и задач прогнозирования с помощью SSA (для подбор окна траекторной матрицы, которая отражает цикличность временного ряда).
  2. Реализовать пример для классификации и прогнозирования где окно подбирается с помощью этого метода и подбирается "рандомно" с каким то шагом. Сделать 2 примера для классификации и 2 для прогнозирования.
v1docq commented 11 months ago
  1. Переработка топологического генератора признаков 4.1. вот эти 2 метода image и image могут быть переписаны в 1 с помощью fedot_ind/core/operation/transformation/data/hankel.py image

сам класс TopologicalTransformation никак не используется fedot_ind/core/models/topological/TopologicalExtractor.py Отсутствует docstring к методам генерации признаков image https://giotto-ai.github.io/gtda-docs/0.5.1/library.html можно взять описание отсюда.

v1docq commented 11 months ago

По задаче 4.1 (переработка топологического генератора признаков)

  1. Переписан метод generate_topological_features. image теперь внутри есть логическое ветвление для работы с многомерными рядами (несколько компонент базиса, несколько фурье гармоник) и для работы с одномерным рядом.
  2. Переписан метод _generate_features_from_ts image теперь он состоит из 3 шагов. 1. Задание класса топологического трансфомера. 2. Формирование облака точек из временного ряда 3. Извлечение топологических признаков из облака точек
    1. Переписан метод def __evaluate_persistence_params(self, ts_data): image это подстраховка на случай если не заданы параметры для формирования облака точек из временного ряда.
  3. Добавлен пример запуска в докстринги класса image 5.переписан класс TopologicalTransformation fedot_ind/core/operation/transformation/data/point_cloud.py image теперь для перевода в облако точек используется реализация HankelMatrix
technocreep commented 11 months ago

По алгоритмам подбора окна:

Переписан код класса WindowSizeSelector:

По поводу эффективности работы алгоритмов: Если кратко, то в случае наличия выраженной циклической компоненты она непременно будет найдена, причём не важно, каким методом. Ниже на картинке приведён пример работы этих методов для временного ряда, полученного склеиванием нескольких сэмплов из датасета Beef. Как видно, оба алгоритма показали идентичную длину окна, соответствующую длине одного сэмпла (они показаны разными цветами)

Снимок экрана 2023-09-15 в 10 24 49

Однако, зачастую в задачах классификации циклика – понятие весьма условное. Например, в случае EC200, где каждый ряд - это фактически единичный удар сердца. В таком случае для целого набора ВР будет получено несколько вариантов окон, где была хоть какая-то корреляция. Тут встаёт вопрос в усреднении между предлагаемыми вариантами.

На картинках ниже линии соответствуют классам в наборе данных (выбраны рандомно):

np.mean:

Снимок экрана 2023-09-18 в 12 56 02

или np.median:

Снимок экрана 2023-09-18 в 12 55 57

Кроме того, стоит отметить одну важную вещь, связанную с тем, как работает AC метод. Вот его код:

    def autocorrelation(self, time_series):
        acf_values = acf(time_series, fft=True, nlags=int(time_series.shape[0] / 2))

        peaks, _ = find_peaks(acf_values)
        peaks = peaks[np.logical_and(peaks >= self.window_min, peaks < self.window_max)]
        corrs = acf_values[peaks]

        if peaks.shape[0] == 0: # if there is no peaks in range (window_min, window_max) return window_min
            return self.window_range[0]
        return peaks[np.argmax(corrs)]

То есть среди коэффициентов автокорреляции ищутся пики, Х-координата которых соответствует длина окна. И эта кривая может выглядеть вот так:

Поэтому более надёжным мне кажется метод DFT. Однако, важно ещё раз отметить, что эти методики призваны искать циклики в рядах. Поэтому, если в ряду не предполагается по логике какой-то циклический процесс, то полученное значение, например, 45 будет лишь говорить о том, что при такой величине окна наибольшая корреляция временного ряда с самим собой или какой-то синусоидой, но это может быть корреляция = 0.01