Анализируйте тренд и компоненты сезонности из временного ряда

Анализ сезонности из данных временных рядов часто может быть полезен в аналитике данных. Это помогает анализировать сезонность для принятия решений, а также для более точных прогнозов. Python можно использовать для разделения этих трендовых и сезонных компонентов.

Набор данных

Обзор

Данные временных рядов, которые мы будем анализировать, - это Сводка преступлений в Канзас-Сити, а именно количество преступлений взлома и проникновения в месяц. Как вы думаете, будут ли в этих данных какие-либо сезонные составляющие? Давайте разберемся.

Первоначальная визуализация

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

Однако насколько сильно зависит от сезонности по сравнению с тенденцией и как автоматизировать разделение компонентов сезонности?

Сезонная декомпозиция

Обзор

В библиотеке statsmodels в Python есть функция Season_decompose, которая делает именно это. Для данного временного ряда данных функция разделяется на отдельные составляющие тренда, сезонности и остаточного (шума).

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

Загрузка данных

Чтобы получить данные в правильной форме, нужно сделать 4 основных шага:

  1. Считывание данных: данные будут считаны в фрейм данных pandas с помощью функции pandas.read_csv.
  2. Выделите только столбцы даты и метрики: нам нужны только компонент даты (ежемесячно для этого набора данных) и метрика (столбец Кража со взломом / Нарушение и ввод).
  3. Нормализация данных. Поскольку в каждом месяце разное количество дней, деление ежемесячных итогов на количество дней в месяце дает более сопоставимое среднее дневное количество, которое можно использовать.
  4. Установите индекс даты фрейма данных: установка нашего столбца даты в качестве индекса фрейма данных pandas позволяет упростить настройку при использовании функции сезонного разложения. Дополнительные примеры по установке индекса можно найти здесь.

Код для этих четырех шагов следующий:

Шаг 1. Загрузка данных

# Load Data
df = pd.read_csv("../data/Kansas_City_Crime__NIBRS__Summary.csv")

# Choose only necessary columns
df = df[['Date', 'Burglary/Breaking and Entering']]

# Normalize Metric
df['Burglary/Breaking and Entering'] = \
    df['Burglary/Breaking and Entering'] \
        / pd.to_datetime(df['Date']).dt.day

# Set date index
df = set_date_index(df, 'Date') # custom helper function

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

Он создает копию фрейма данных (чтобы оставить исходные данные нетронутыми), устанавливает столбец даты в тип datetime и, наконец, сортирует и устанавливает индекс.

Вспомогательная функция: сортировка и установка индекса даты и времени

def set_date_index(input_df, col_name='Date'):
    """Given a pandas df, parse and set date column to index.
        col_name will be removed and set as datetime index.

    Args:
        input_df (pandas dataframe): Original pandas dataframe
        col_name (string): Name of date column

    Returns:
        pandas dataframe: modified and sorted dataframe
    """
    # Copy df to prevent changing original
    modified_df = input_df.copy()

    # Infer datetime from col
    modified_df[col_name] = pd.to_datetime(modified_df[col_name])

    # Sort and set index
    modified_df.sort_values(col_name, inplace=True)
    modified_df.set_index(col_name, inplace=True)

    return modified_df

Тренд или сезонность

Следующая часть фактически выполняет сезонную декомпозицию. Фрейм данных передается в качестве аргумента, а также period = 12 для представления наших ежемесячных данных и определения годовой сезонности.
# Seasonal decompose
sd = seasonal_decompose(df, period=12)
combine_seasonal_cols(df, sd) # custom helper function

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

Вспомогательная функция: сочетание сезонного_decompose с исходными столбцами

def combine_seasonal_cols(input_df, seasonal_model_results):
    """Adds inplace new seasonal cols to df given seasonal results

    Args:
        input_df (pandas dataframe)
        seasonal_model_results (statsmodels DecomposeResult object)
    """
    # Add results to original df
    input_df['observed'] = seasonal_model_results.observed
    input_df['residual'] = seasonal_model_results.resid
    input_df['seasonal'] = seasonal_model_results.seasonal
    input_df['trend'] = seasonal_model_results.trend

Вывод

Наконец, результаты были записаны в локальный CSV-файл для визуализации в Power BI. Если бы это был повторяющийся процесс, мы могли бы настроить API или использовать облачные сервисы для размещения нашей модели; однако для одноразового запуска вполне подойдет локальный CSV-файл.

Вывод результатов для визуализации

df.to_csv("../data/results.csv")

Визуализируйте результаты

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

Была выявлена ​​небольшая тенденция к снижению наряду с сезонной составляющей (добавление или вычитание из тенденции до 4 преступлений в день).

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

Преступления, кажется, самые низкие в феврале из-за сезонности (холодная погода?), И возрастают в летние месяцы и в праздничные дни.

Резюме

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

Заинтересованы в ваших мыслях, если вы нашли этот подход полезным или использовали разные подходы в прошлом для решения аналогичных проблем - прокомментируйте ниже!

Все примеры и файлы доступны на Github.

Первоначально опубликовано на https://datastud.dev.