Работа с временными рядами в Python. Часть 1

от автора

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

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

Области, где временные ряды играют решающую роль:

1. Финансовая аналитика: Прогнозирование цен акций, анализ рыночных тенденций и определение оптимального времени для инвестиций.

2. Маркетинг и анализ пользовательской активности: Отслеживание изменений в поведении пользователей на веб-сайте, прогнозирование спроса на товары и услуги.

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

4. Анализ временных данных о заболеваниях: Оценка распространения эпидемий, прогнозирование заболеваемости и смертности.

5. Климатические исследования: Изучение изменений в климатических параметрах, таких как температура и осадки, для анализа климатических тенденций.

6. Прогнозирование трафика: Анализ и прогнозирование трафика на веб-сайтах и в сетях.

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

Временные ряды также присутствуют в повседневной жизни: температурные измерения, динамика финансовых индексов или даже ежедневные показатели физической активности с помощью носимых устройств — все это временные ряды.

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

Основные характеристики временных рядов

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

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

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

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

Стационарность: Стационарный временной ряд — это ряд, в котором статистические характеристики, такие как среднее и дисперсия, остаются постоянными с течением времени. Многие методы анализа временных рядов предполагают стационарность данных.

Автокорреляция: Автокорреляция — это корреляция между значениями ряда в разные моменты времени. Она может помочь выявить закономерности в данных.

Пропущенные значения: Временные ряды могут содержать пропущенные значения, которые требуется обработать перед анализом.

Подготовка к анализу

Прежде чем мы начнем работу, нам нужно убедиться, что у нас есть все необходимые библиотеки для анализа временных рядов:

1. pandas: Pandas — это библиотека для работы с данными, которая предоставляет удобные структуры данных, такие как DataFrame, и множество функций для анализа и манипуляции данными. Она идеально подходит для работы с временными рядами, так как позволяет легко хранить и анализировать временные данные.

2. numpy: NumPy — это библиотека для работы с массивами и матрицами чисел. Она полезна при выполнении вычислений над данными временных рядов.

3. matplotlib и seaborn: Эти библиотеки позволяют создавать графики и визуализации данных, что особенно важно при анализе временных рядов.

4. statsmodels: Statsmodels — это библиотека для статистического анализа данных. Она содержит множество методов для анализа временных рядов, включая модели ARIMA и SARIMA.

5. scikit-learn: Scikit-learn предоставляет множество инструментов для машинного обучения, включая модели регрессии и классификации, которые можно использовать для анализа временных рядов.

Устанавливаем:

!pip install pandas numpy matplotlib seaborn statsmodels scikit-learn

Теперь, когда у нас есть необходимые библиотеки, давайте перейдем к работе с датами и временем.

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

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

import pandas as pd  data = {'Дата': ['2023-01-01', '2023-02-01', '2023-03-01', '2023-04-01', '2023-05-01'],         'Продажи': [1000, 1200, 1300, 1100, 1400]}  df = pd.DataFrame(data)  # Преобразуем столбец 'Дата' в формат даты df['Дата'] = pd.to_datetime(df['Дата'])  print(df)

Результат будет следующим:

        Дата  Продажи 0 2023-01-01     1000 1 2023-02-01     1200 2 2023-03-01     1300 3 2023-04-01     1100 4 2023-05-01     1400

Теперь у нас есть DataFrame с данными о продажах и столбцом ‘Дата’, который имеет тип datetime64. Это позволяет нам выполнять различные операции, такие как выбор данных по дате или вычисление временных интервалов.

Пример:

# Выбор данных по диапазону дат subset = df[(df['Дата'] >= '2023-03-01') & (df['Дата'] <= '2023-04-30')]  print(subset)

Вывод:

        Дата  Продажи 2 2023-03-01     1300 3 2023-04-01     1100

Таким образом, работа с датами и временем в pandas позволяет нам легко фильтровать и анализировать данные временных рядов.

Обработка пропущенных значений

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

Давайте рассмотрим, как можно обработать пропущенные значения в DataFrame с помощью pandas. Для примера допустим, что у нас есть следующий dataset:

import pandas as pd  data = {'Дата': ['2023-01-01', '2023-02-01', '2023-03-01', '2023-04-01', '2023-05-01'],         'Продажи': [1000, None, 1300, 1100, 1400]}  df = pd.DataFrame(data)  # Преобразуем столбец 'Дата' в формат даты df['Дата'] = pd.to_datetime(df['Дата'])  print(df)

Результат:

       Дата  Продажи 0 2023-01-01   1000.0 1 2023-02-01      NaN 2 2023-03-01   1300.0 3 2023-04-01   1100.0 4 2023-05-01   1400.0

Как видите, у нас есть пропущенное значение (NaN) в столбце ‘Продажи’. Существует несколько способов обработки таких значений:

1. Удаление строк с пропущенными значениями:

df.dropna(inplace=True)

Этот метод удаляет строки, содержащие пропущенные значения. Важно помнить, что это может привести к потере данных.

2. Замена пропущенных значений:

df.fillna(0, inplace=True)

Здесь мы заменяем все пропущенные значения на 0. Вы можете выбрать другое значение для замены вместо 0 в зависимости от контекста.

3. Интерполяция:

df.interpolate(inplace=True)

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

Обработка пропущенных значений зависит от конкретной задачи и данных временных рядов. Важно выбирать подходящий метод в каждом случае.

Анализ временных рядов

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

Стационарность временных рядов

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

1. Тесты на стационарность:

Первый шаг в анализе временных рядов — проверка стационарности. Для этого существует несколько статистических тестов. Один из них — тест Дики-Фуллера. Давайте применим его к нашему небольшому dataset с данными о продажах в условном филиале МВидео:

import pandas as pd import matplotlib.pyplot as plt from statsmodels.tsa.stattools import adfuller  # Создаем dataset с данными о продажах data = {'Дата': ['2023-01-01', '2023-02-01', '2023-03-01', '2023-04-01', '2023-05-01'],         'Продажи': [1000, 1200, 1300, 1100, 1400]}  df = pd.DataFrame(data)  # Преобразуем столбец 'Дата' в формат даты df['Дата'] = pd.to_datetime(df['Дата'])  # Построим график продаж plt.plot(df['Дата'], df['Продажи']) plt.title('Продажи в магазине МВидео') plt.xlabel('Дата') plt.ylabel('Продажи') plt.show()  # Проведем тест Дики-Фуллера на стационарность result = adfuller(df['Продажи'])  print('ADF Statistic: %f' % result[0]) print('p-value: %f' % result[1]) print('Critical Values:') for key, value in result[4].items():     print('\t%s: %.3f' % (key, value))

На выходе мы получим статистику теста Дики-Фуллера и p-значение. Если p-значение меньше уровня значимости (обычно 0.05), то мы можем отклонить нулевую гипотезу о нестационарности ряда и считать его стационарным.

2. Преобразование ряда для достижения стационарности:

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

# Преобразование для удаления тренда df['Продажи_без_тренда'] = df['Продажи'] - df['Продажи'].rolling(window=2).mean()  # Преобразование для удаления сезонности (в данном случае просто разница между текущим и предыдущим значением) df['Продажи_стационарные'] = df['Продажи_без_тренда'].diff()  # Удалим первые строки с пропущенными значениями df.dropna(inplace=True)  # Построим графики plt.plot(df['Дата'], df['Продажи_без_тренда'], label='Без тренда') plt.plot(df['Дата'], df['Продажи_стационарные'], label='Стационарные') plt.legend() plt.title('Преобразованные продажи') plt.xlabel('Дата') plt.ylabel('Продажи') plt.show()


Теперь у нас есть стационарный ряд Продажи_стационарные, который мы можем анализировать и моделировать.

Компоненты временных рядов

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

1. Тренд:

Тренд — это долгосрочное изменение в данных, которое может быть восходящим (рост), нисходящим (падение) или горизонтальным (без изменений). Он представляет собой общее направление движения данных.

Посмотрим на примере:

# Создаем dataset с данными о продажах с трендом data_trend = {'Дата': ['2023-01-01', '2023-02-01', '2023-03-01', '2023-04-01', '2023-05-01'],               'Продажи': [1000, 1200, 1400, 1600, 1800]}  df_trend = pd.DataFrame(data_trend)  # Преобразуем столбец 'Дата' в формат даты df_trend['Дата'] = pd.to_datetime(df_trend['Дата'])  # Построим график продаж с трендом plt.plot(df_trend['Дата'], df_trend['Продажи']) plt.title('Продажи с трендом (рост)') plt.xlabel('Дата') plt.ylabel('Продажи') plt.show()


На графике видно, что продажи увеличиваются со временем. Это пример тренда восходящего направления.

2. Сезонность:

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

# Создаем dataset с данными о продажах с сезонностью data_seasonal = {'Дата': ['2023-01-01', '2023-02-01', '2023-03-01', '2023-04-01', '2023-05-01'],                  'Продажи': [1000, 1200, 900, 1100, 1400]}  df_seasonal = pd.DataFrame(data_seasonal)  # Преобразуем столбец 'Дата' в формат даты df_seasonal['Дата'] = pd.to_datetime(df_seasonal['Дата'])  # Построим график продаж с сезонностью plt.plot(df_seasonal['Дата'], df_seasonal['Продажи']) plt.title('Продажи с сезонностью') plt.xlabel('Дата') plt.ylabel('Продажи') plt.show()


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

3. Шум:

Шум (остаток) — это случайные изменения в данных, которые не могут быть объяснены трендом или сезонностью. Он представляет собой нерегулярные колебания и вариации в данных.

# Создаем dataset с данными о продажах с шумом data_noise = {'Дата': ['2023-01-01', '2023-02-01', '2023-03-01', '2023-04-01', '2023-05-01'],               'Продажи': [1000, 1200, 1050, 1150, 1100]}  df_noise = pd.DataFrame(data_noise)  # Преобразуем столбец 'Дата' в формат даты df_noise['Дата'] = pd.to_datetime(df_noise['Дата'])  # Построим график продаж с шумом plt.plot(df_noise['Дата'], df_noise['Продажи']) plt.title('Продажи с шумом') plt.xlabel('Дата') plt.ylabel('Продажи') plt.show()


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

Автокорреляция и частичная автокорреляция

Автокорреляция — это мера корреляции между временным рядом и его лагированными (отстающими) значениями. Это позволяет нам определить зависимость текущих значений от предыдущих.

Частичная автокорреляция — это мера корреляции между временным рядом и его лагированными значениями с учетом корреляции в промежуточных лагах. Она помогает выявить «чистую» зависимость от определенных отстающих значений, исключая влияние промежуточных лагов.

Представим, что у нас есть временной ряд данных о температуре каждый час:

import pandas as pd import numpy as np import matplotlib.pyplot as plt from statsmodels.graphics.tsaplots import plot_acf, plot_pacf  # Создаем небольшой временной ряд температуры np.random.seed(0) dates = pd.date_range(start='2023-01-01', end='2023-01-07', freq='H') temperature = np.random.normal(loc=25, scale=5, size=len(dates)) df_temperature = pd.DataFrame({'Дата': dates, 'Температура': temperature})  # Устанавливаем 'Дата' в качестве индекса df_temperature.set_index('Дата', inplace=True)  # Построим график временного ряда plt.figure(figsize=(12, 4)) plt.plot(df_temperature.index, df_temperature['Температура']) plt.title('Временной ряд температуры') plt.xlabel('Дата и время') plt.ylabel('Температура (°C)') plt.grid(True) plt.show()  # Рассчитываем автокорреляцию и частичную автокорреляцию plt.figure(figsize=(12, 6)) plt.subplot(211) plot_acf(df_temperature['Температура'], lags=50, ax=plt.gca()) plt.title('Автокорреляция')  plt.subplot(212) plot_pacf(df_temperature['Температура'], lags=50, ax=plt.gca()) plt.title('Частичная автокорреляция')  plt.tight_layout() plt.show()

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

Примеры на практике

В этом разделе мы рассмотрим несколько практических примеров использования анализа временных рядов для решения разнообразных задач.

Прогнозирование продаж на основе временных рядов продаж электроники

В этом примере мы будем использовать данные о ежемесячных продажах электроники в магазине МВидео для прогнозирования будущих продаж.

Cоздадим небольшой dataset с данными о продажах. В качестве исходных данных предположим следующие продажи за последние два года:

import pandas as pd import numpy as np  # Создаем даты с января 2022 года по декабрь 2023 года dates = pd.date_range(start='2022-01-01', end='2023-12-31', freq='M')  # Генерируем случайные продажи в интервале от 1000 до 5000 sales = np.random.randint(1000, 5000, size=len(dates))  # Создаем DataFrame sales_df = pd.DataFrame({'Дата': dates, 'Продажи': sales})  # Устанавливаем 'Дата' в качестве индекса sales_df.set_index('Дата', inplace=True)  # Выводим первые несколько строк print(sales_df.head())

Результат:

            Продажи Дата                2022-01-31     1355 2022-02-28     4665 2022-03-31     3154 2022-04-30     3490 2022-05-31     3569

Визуализация данных

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

import matplotlib.pyplot as plt  # Построим график продаж plt.figure(figsize=(12, 6)) plt.plot(sales_df.index, sales_df['Продажи'], marker='o', linestyle='-') plt.title('Продажи в магазине МВидео') plt.xlabel('Дата') plt.ylabel('Продажи') plt.grid(True) plt.show()


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

Подготовка данных

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

# Обработка пропущенных значений (если они есть) sales_df.dropna(inplace=True)  # Проверка стационарности ряда from statsmodels.tsa.stattools import adfuller  result = adfuller(sales_df['Продажи']) print('ADF статистика:', result[0]) print('p-значение:', result[1]) print('Критические значения:') for key, value in result[4].items():     print(f'  {key}: {value}')

Результат:

ADF статистика: -3.336001912478917 p-значение: 0.013343910713214318 Критические значения:   1%: -3.859073285322359   5%: -3.0420456927297668   10%: -2.6609064197530863

Если p-значение ниже некоторого порогового значения (обычно 0.05), то мы можем считать ряд стационарным.

Выбор и обучение модели

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

from statsmodels.tsa.arima.model import ARIMA  # Обучение модели ARIMA model = ARIMA(sales_df['Продажи'], order=(1, 1, 1)) model_fit = model.fit()  # Вывод статистики модели print(model_fit.summary())

Результат:

                               SARIMAX Results                                 ============================================================================== Dep. Variable:                Продажи   No. Observations:                   24 Model:                 ARIMA(1, 1, 1)   Log Likelihood                -197.611 Date:                Mon, 18 Sep 2023   AIC                            401.222 Time:                        12:03:31   BIC                            404.628 Sample:                    01-31-2022   HQIC                           402.078                          - 12-31-2023                                          Covariance Type:                  opg                                          ==============================================================================                  coef    std err          z      P>|z|      [0.025      0.975] ------------------------------------------------------------------------------ ar.L1          0.1787      0.252      0.709      0.478      -0.315       0.673 ma.L1         -1.0000      0.349     -2.868      0.004      -1.683      -0.316 sigma2      1.469e+06   2.37e-07   6.19e+12      0.000    1.47e+06    1.47e+06 =================================================================================== Ljung-Box (L1) (Q):                   0.05   Jarque-Bera (JB):                 0.87 Prob(Q):                              0.82   Prob(JB):                         0.65 Heteroskedasticity (H):               0.70   Skew:                             0.34 Prob(H) (two-sided):                  0.63   Kurtosis:                         2.33 ===================================================================================

Оценка качества прогноза

После обучения модели мы можем оценить ее качество на основе имеющихся данных.

from sklearn.metrics import mean_squared_error, mean_absolute_error  # Прогноз на основе обученной модели forecast = model_fit.forecast(steps=12)  # Рассчитываем MSE и MAE mse = mean_squared_error(sales_df['Продажи'][-12:], forecast) mae = mean_absolute_error(sales_df['Продажи'][-12:], forecast)  print(f'MSE: {mse}') print(f'MAE: {mae}')

Результат:

MSE: 1178795.2830408707 MAE: 906.8571433244668

Прогноз на будущее

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

# Прогноз на будущее (следующие 12 месяцев) forecast_future = model_fit.forecast(steps=12)  # Создаем новый DataFrame для будущих значений future_dates = pd.date_range(start='2024-01-01', periods=12, freq='M') forecast_df = pd.DataFrame({'Дата': future_dates, 'Прогноз продаж': forecast_future})  # Присоединяем прогноз к исходному DataFrame sales_df = sales_df.append(forecast_df, ignore_index=True)  # Визуализация исходных данных и прогноза plt.figure(figsize=(12, 6)) plt.plot(sales_df.index[:-12], sales_df['Продажи'][:-12], label='Исходные данные') plt.plot(sales_df.index[-12:], sales_df['Прогноз продаж'][-12:], label='Прогноз') plt.title('Прогноз продаж в магазине МВидео') plt.xlabel('Дата') plt.ylabel('Продажи') plt.legend() plt.grid(True) plt.show()

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

Заключение

В данной статье мы рассмотрели основные концепции и методы работы с временными рядами в Python. Мы изучили, как импортировать данные временных рядов, визуализировать их, а также провели анализ стационарности и сезонности.

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


ссылка на оригинал статьи https://habr.com/ru/articles/769190/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *