Подход с минимальными усилиями к проектированию функций и машинному обучению на многомерных данных временных рядов.

Извержение вулкана может унести десятки тысяч жизней, разрушить инфраструктуру на миллионы долларов и доставить массу неудобств. Что, если бы ученые могли предвидеть извержения вулканов, как они предсказывают погоду? Это было целью конкурса Kaggle INGV - Прогнозирование извержений вулканов, организованного Национальным институтом геофизики и вулканологии (INGV).

Я создал простое решение для этого соревнования с tsfresh и lightGBM, и оно заняло 18-е место в общедоступной таблице лидеров соревнования. В этой статье я хочу подробно описать свое решение. Я также очистил и задокументировал свой конкурсный код как публичное ядро ​​на Kaggle. Вы можете просмотреть полный код этой статьи по ссылке ниже.



Если вы начинаете с многомерных данных временных рядов, я надеюсь, что чтение этой статьи поможет вам по следующим двум темам:

  1. Автоматическое создание функций для многомерных данных временных рядов.
  2. Разработка надежной модели машинного обучения для прогнозирования временных рядов.

Создание функций временных рядов с помощью tsfresh

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



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

ComprehensiveFCParameters: для обработки со всеми доступными функциями временных рядов. Полезно, когда вы не знаете, какие функции вам нужны.

MinimalFCParameters: содержит очень небольшой и базовый набор характеристик временных рядов (минимальное, максимальное, стандартное отклонение и т. д.). Полезно для настройки быстрого теста перед тем, как начать конвейер.

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

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

import pandas as pd
from tsfresh.feature_extraction import extract_features
from tsfresh.feature_extraction import ComprehensiveFCParameters
df = pd.read_csv('/path/to/file.csv')
settings = ComprehensiveFCParameters()
features_df = extract_features(df, default_fc_parameters=settings)

После обработки достаточного количества данных вы можете применять различные методы, чтобы понять важность функций. Как только вы узнаете, какие функции вам нужны, вы можете «вручную написать» настройки, которые хотите извлечь из своего набора данных. Существует также удобный трюк, позволяющий перейти от имен столбцов к настройкам с помощью функции from_columns. Ниже приведен фрагмент кода, показывающий, как это будет работать.

from tsfresh.feature_extraction.settings import from_columns
# fictions function to get top features from your dataset
top_features_column_names = features_df.get_top_features()
# get the config for the selected columnsconfig = from_columns(top_features_column_names)
# get selected features for another dataframe
selected_features_df = extract_features(another_df, column_id =   'id', kind_to_fc_parameters = config)

В случае этого соревнования я сначала обработал набор обучающих данных с помощью ComprehensiveFCParameters. Затем я удалил столбцы с высокой степенью корреляции и квазипостоянства и создал пользовательские настройки для обработки набора тестов. Более подробная информация об этом представлена ​​в следующем разделе. Обратите внимание, что lightGBM не принимает имена столбцов, сгенерированные tsfresh, потому что они часто имеют знак минус (-). Вы должны написать небольшую функцию, чтобы сопоставить имена между ними.

Детали обработки данных

Это соревнование обеспечивает десять минут показаний сейсмических датчиков и время для прорыва для каждого сегмента. В наборе обучающих данных у нас 4231 сегмент, а в тестовом наборе данных - 4520 сегментов. Нам нужно спрогнозировать время прорыва для каждого сегмента тестовых данных. Для каждого сегмента у нас есть 60 000 точек данных (за 10 минут); так что у нас есть качественные и высокочастотные данные.

Поскольку некоторые функции очень тяжелы для вычислений, для каждого сегмента я разделил точки данных на 6 пакетов (10 000 точек данных на пакет). Я мог бы также уменьшить общее количество точек данных, и это было бы более стандартно, но я хотел использовать нетрадиционные методы.

В настоящее время у нас есть 2854 функции для нашего набора данных. Сначала обработал все возможные особенности обучающего набора (ComprehensiveFCParameters). Это сгенерировало почти 8000 функций. Затем я удалил сильно коррелированные столбцы и квазипостоянные особенности. Это снизило количество наших функций до 2854. Я также применил рекурсивное исключение функции, чтобы взять 501 лучшую функцию (число 500 показалось мне слишком простым). Эти столбцы жестко запрограммированы в этой записной книжке. Полный набор данных также загружен в виде общедоступного набора данных на Kaggle, и вы можете просмотреть его по следующей ссылке:



Модель Архитектура

Для прогнозирования времени извержения я использовал древовидный алгоритм обучения с фреймворком lightGBM (LGBM). Это был фреймворк для многих пользователей Kaggle, и это также стало моей отправной точкой. Сначала я использовал ванильную модель lightGBM, используя лучшие функции; И это дало достойные результаты. Отсюда наиболее распространенный метод улучшения моего результата - создание большего количества моделей с алгоритмами и усреднение результатов. Однако в реальной производственной модели сложно управлять сочетанием нескольких моделей. Итак, вместо того, чтобы смешивать несколько моделей, я решил сделать что-то немного другое.

Для улучшения своих результатов я создал два слоя моделей lightGBM. Я называю это обобщенно-специализированным наслоением. Сначала для первоначального прогноза по всему набору данных используется одна модель. Затем на втором уровне я обучил несколько моделей. Эти модели более специализированы, поскольку они обучаются на данных за определенный период времени до извержения. Чтобы справиться с большей степенью погрешности первой модели, я создал перекрытия между диапазонами второй модели. И последняя мелочь: я также использую масштабирование min-max, чтобы масштабировать наши данные перед их подгонкой, чтобы получить максимальную производительность.

Для прогнозирования тестовых данных сначала используется модель из первого уровня, чтобы сделать первоначальный прогноз. Основываясь на этом прогнозе, мы используем конкретную модель второго слоя, чтобы сделать более точный прогноз. Поскольку у нас есть перекрытия в диапазонах времени до извержения, может случиться так, что один тестовый сегмент оценивается двумя моделями. Наконец, у нас есть шесть выходных данных или прогнозов для каждого сегмента в нашем тестовом наборе данных. Затем мы берем медианное значение этих выходных данных, чтобы получить окончательное прогнозируемое время извержения. Я попытался изобразить этот процесс на диаграмме ниже (в меру своих возможностей).

Настройка гиперпараметров

LightGBM имеет очень большое количество гиперпараметров для настройки. Как и все древовидные алгоритмы, lightGBM также хорошо известен своей переоснащенностью. Одна из основных причин переобучения - сложность модели. Я предотвратил создание излишне сложных моделей в lightGBM, управляя параметрами количества листьев (num_leaves) и максимальной глубины (max_depth). Я также использовал большое количество оценок (n_estimators) и регуляризацию (lambda_l1 и lambda_l2), чтобы уменьшить переобучение. Общее количество итераций (num_iterations) также контролировалось, и была также введена ранняя остановка (early_stopping_round) для предотвращения переобучения. Наконец, я также попытался ввести много случайности, используя дополнительные деревья, фракцию функций и bagging_fraction. Ниже представлена ​​конфигурация гиперпараметров для второго уровня моделей.

params = {
         'application':'regression',
         'boosting ': 'dart',
         'num_iterations':8000, 
         'learning_rate':0.05, 
         'num_leaves': 95,
         'extra_trees': True,
         'feature_fraction':0.8, 
         'bagging_fraction':0.9,
         'lambda_l1':0.1, 
         'lambda_l2':0.1, 
         'min_split_gain':0.01, 
         'early_stopping_round':100, 
         'max_depth': 7,
         'min_child_weight':40, 
         'n_estimators': 400,
         'metric':'mae',
         }

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

Полученные результаты

В этом соревновании используется средний средний балл (MAE), и это решение имело частный балл 4200311. Оно занимало 18-е место в таблице лидеров, и я очень рад, что мое простое решение в итоге получило такой высокий рейтинг. Гистограмма ниже показывает средний средний балл для различных диапазонов значений времени до извержения. Гистограмма слева относится к первой модели, а справа - ко второй модели.

Поскольку вторая модель может фокусироваться на меньшем диапазоне времени, они, как правило, работают намного лучше. Также улучшилась общая оценка модели. Для обоих крайних концов (очень быстрое или позднее время извержения) я создал одну дополнительную модель. Поскольку диапазон между самым низким и самым высоким действительно велик, даже специализированные модели имеют тенденцию больше склоняться к середине диапазона. Эти дополнительные модели для обеих крайностей помогли лучше предсказать крайние случаи.

Последние мысли

Это был интересный конкурс Kaggle и большое спасибо организаторам за его организацию. Как и в любом другом конкурсе, я многому научился у других работ Кагглера, участвуя в этом конкурсе.

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