Работа с временными рядами в Python. Часть 2
Добро пожаловать во вторую часть нашей серии статей »Работа с временными рядами в Python.» В первой части, мы ознакомились с основами работы с временными рядами и научились анализировать и визуализировать их. Теперь мы переходим к более продвинутым аспектам этой увлекательной темы.
В этой статье мы сосредоточимся на прогнозировании временных рядов, что имеет огромное значение в множестве областей, включая экономику, финансы и даже погоду. Это открывает новые возможности для анализа различных типов временных данных.
Прогнозирование погоды
Прогнозирование погоды — это еще одна важная область, где анализ временных рядов играет важную роль. Рассмотрим пример прогнозирования температуры.
Создание Dataset
Для примера создадим dataset с данными о средней дневной температуре в течение нескольких лет.
# Создаем даты с января 2020 года по декабрь 2022 года
dates = pd.date_range(start='2020-01-01', end='2022-12-31', freq='D')
# Генерируем случайные значения температуры
temperature = np.random.normal(loc=25, scale=5, size=len(dates))
# Создаем DataFrame
temperature_df = pd.DataFrame({'Дата': dates, 'Температура': temperature})
# Устанавливаем 'Дата' в качестве индекса
temperature_df.set_index('Дата', inplace=True)
# Выводим первые несколько строк
print(temperature_df.head())
Результат:
Температура
Дата
2020-01-01 28.070296
2020-01-02 22.618478
2020-01-03 37.671305
2020-01-04 24.559199
2020-01-05 21.579757
Визуализация данных
Визуализируем данные о температуре, чтобы понять их динамику.
# Построим график температуры
plt.figure(figsize=(12, 6))
plt.plot(temperature_df.index, temperature_df['Температура'], linestyle='-')
plt.title('Средняя дневная температура')
plt.xlabel('Дата')
plt.ylabel('Температура (°C)')
plt.grid(True)
plt.show()
Выбор и обучение модели
Для прогнозирования погоды можно использовать различные модели, включая модели временных рядов и модели машинного обучения. Мы будем использовать модель SARIMA.
from statsmodels.tsa.statespace.sarimax import SARIMAX
# Обучение модели SARIMA
model = SARIMAX(temperature_df['Температура'], order=(1, 1, 1), seasonal_order=(1, 1, 1, 7))
model_fit = model.fit()
# Вывод статистики модели
print(model_fit.summary())
Результат:
SARIMAX Results
=========================================================================================
Dep. Variable: Температура No. Observations: 1096
Model: SARIMAX(1, 1, 1)x(1, 1, 1, 7) Log Likelihood -3302.692
Date: Mon, 18 Sep 2023 AIC 6615.384
Time: 12:26:34 BIC 6640.344
Sample: 01-01-2020 HQIC 6624.832
- 12-31-2022
Covariance Type: opg
==============================================================================
coef std err z P>|z| [0.025 0.975]
------------------------------------------------------------------------------
ar.L1 0.0297 0.033 0.899 0.368 -0.035 0.094
ma.L1 -0.9926 0.005 -182.224 0.000 -1.003 -0.982
ar.S.L7 0.0148 0.033 0.446 0.655 -0.050 0.080
ma.S.L7 -0.9862 0.012 -79.419 0.000 -1.011 -0.962
sigma2 24.5744 1.054 23.311 0.000 22.508 26.641
===================================================================================
Ljung-Box (L1) (Q): 0.00 Jarque-Bera (JB): 0.36
Prob(Q): 0.97 Prob(JB): 0.84
Heteroskedasticity (H): 0.96 Skew: 0.04
Prob(H) (two-sided): 0.69 Kurtosis: 3.05
===================================================================================
Оценка качества прогноза
Оценка качества прогноза температуры может включать в себя сравнение прогнозных значений с фактическими данными и использование метрик, таких как MSE и MAE.
# Импортируем необходимую функцию
from sklearn.metrics import mean_squared_error, mean_absolute_error
# Прогноз на основе обученной модели
forecast = model_fit.forecast(steps=7)
# Рассчитываем MSE и MAE
mse = mean_squared_error(temperature_df['Температура'][-7:], forecast)
mae = mean_absolute_error(temperature_df['Температура'][-7:], forecast)
print(f'MSE: {mse}')
print(f'MAE: {mae}')
Результат:
MSE: 10.43521389383251
MAE: 2.4818868765063735
Прогноз на будущее
Теперь мы можем использовать обученную модель для прогнозирования температуры на следующие 7 дней.
# Прогноз на будущее (следующие 7 дней)
forecast_future = model_fit.get_forecast(steps=7)
# Создаем новый DataFrame для будущих значений
future_dates = pd.date_range(start='2022-12-31', periods=7, freq='D') + pd.DateOffset(days=1)
forecast_df = pd.DataFrame({'Дата': future_dates, 'Прогноз температуры': forecast_future.predicted_mean})
# Присоединяем прогноз к исходному DataFrame
temperature_df = temperature_df.append(forecast_df)
# Визуализация исходных данных и прогноза
plt.figure(figsize=(12, 6))
plt.plot(temperature_df.index[:-7], temperature_df['Температура'][:-7], label='Исходные данные')
plt.plot(temperature_df.index[-7:], temperature_df['Прогноз температуры'][-7:], label='Прогноз')
plt.title('Прогноз средней дневной температуры')
plt.xlabel('Дата')
plt.ylabel('Температура (°C)')
plt.legend()
plt.grid(True)
plt.show()
Прогнозирование трафика на веб-сайте
Рассмотрим пример прогнозирования количества посетителей на веб-сайте.
Создание Dataset
Для примера создадим dataset с данными о ежедневном трафике на веб-сайте.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# Создаем условные даты
dates = pd.date_range(start='2020-01-01', end='2022-12-31', freq='D')
# Генерируем случайное количество посетителей
traffic = np.random.randint(1000, 5000, size=len(dates))
# Создаем DataFrame
traffic_df = pd.DataFrame({'Дата': dates, 'Посетители': traffic})
# Устанавливаем 'Дата' в качестве индекса
traffic_df.set_index('Дата', inplace=True)
# Выводим первые несколько строк
print(traffic_df.head())
Результат:
Посетители
Дата
2020-01-01 3776
2020-01-02 3641
2020-01-03 4092
2020-01-04 2057
2020-01-05 1936
Визуализация данных
Визуализируем данные о трафике на веб-сайте, чтобы увидеть их динамику.
# Построим график трафика
plt.figure(figsize=(12, 6))
plt.plot(traffic_df.index, traffic_df['Посетители'], linestyle='-')
plt.title('Трафик на веб-сайте')
plt.xlabel('Дата')
plt.ylabel('Посетители')
plt.grid(True)
plt.show()
Выбор и обучение модели
Для прогнозирования трафика на веб-сайте можно использовать различные модели, включая модели временных рядов и модели машинного обучения. Мы будем использовать модель ARIMA.
from statsmodels.tsa.arima.model import ARIMA
# Обучение модели ARIMA
model = ARIMA(traffic_df['Посетители'], order=(1, 1, 1))
model_fit = model.fit()
# Вывод статистики модели
print(model_fit.summary())
Результат:
SARIMAX Results
==============================================================================
Dep. Variable: Посетители No. Observations: 1096
Model: ARIMA(1, 1, 1) Log Likelihood -9283.888
Date: Mon, 18 Sep 2023 AIC 18573.776
Time: 12:36:37 BIC 18588.771
Sample: 01-01-2020 HQIC 18579.450
- 12-31-2022
Covariance Type: opg
==============================================================================
coef std err z P>|z| [0.025 0.975]
------------------------------------------------------------------------------
ar.L1 -0.0158 0.030 -0.524 0.601 -0.075 0.043
ma.L1 -1.0000 0.067 -14.838 0.000 -1.132 -0.868
sigma2 1.346e+06 5e-08 2.69e+13 0.000 1.35e+06 1.35e+06
===================================================================================
Ljung-Box (L1) (Q): 0.00 Jarque-Bera (JB): 65.30
Prob(Q): 0.97 Prob(JB): 0.00
Heteroskedasticity (H): 0.99 Skew: -0.02
Prob(H) (two-sided): 0.94 Kurtosis: 1.80
===================================================================================
Оценка качества прогноза
Оценка качества прогноза трафика может включать в себя сравнение прогнозных значений с фактическими данными и использование метрик, таких как MSE и MAE.
# Прогноз на основе обученной модели
forecast = model_fit.forecast(steps=7)
# Рассчитываем MSE и MAE
mse = mean_squared_error(traffic_df['Посетители'][-7:], forecast)
mae = mean_absolute_error(traffic_df['Посетители'][-7:], forecast)
print(f'MSE: {mse}')
print(f'MAE: {mae}')
Результат:
MSE: 836944.4441271863
MAE: 818.829661603483
Анализ временных рядов может стать более сложным, когда у вас есть дело с временными рядами, имеющими переменные интервалы между наблюдениями, сеточными данными или совместными временными рядами.
Временные ряды с переменными интервалами
В большинстве анализов временных рядов предполагается, что наблюдения происходят с постоянным интервалом времени. Однако в реальном мире данные могут иметь переменные интервалы между наблюдениями. Временные ряды с переменными интервалами могут возникать, например, в медицинских исследованиях, где пациенты по разному записывают свои показатели.
Создадим временной ряд с переменными интервалами, представляющий количество продаж в условном филиале МВидео.
import pandas as pd
import numpy as np
# Создаем dataset с переменными интервалами
sales_data = {'Дата': pd.to_datetime(['2023-01-01', '2023-01-03', '2023-01-05', '2023-01-10']),
'Продажи': [100, 150, 80, 200]}
sales_df = pd.DataFrame(sales_data)
# Устанавливаем 'Дата' в качестве индекса
sales_df.set_index('Дата', inplace=True)
Теперь у нас есть временной ряд с переменными интервалами. Как анализировать такие данные? Мы можем использовать методы интерполяции для заполнения промежутков между наблюдениями и сделать их более регулярными.
# Пересемплирование данных для установки регулярного интервала
sales_df_resampled = sales_df.resample('D').asfreq()
# Заполнение пропущенных значений интерполяцией
sales_df_interpolated = sales_df_resampled.interpolate(method='linear')
# Вывод интерполированных данных
print(sales_df_interpolated)
Результат:
SARIMAX Results
==============================================================================
Dep. Variable: Посетители No. Observations: 1096
Model: ARIMA(1, 1, 1) Log Likelihood -9283.888
Date: Mon, 18 Sep 2023 AIC 18573.776
Time: 12:36:37 BIC 18588.771
Sample: 01-01-2020 HQIC 18579.450
- 12-31-2022
Covariance Type: opg
==============================================================================
coef std err z P>|z| [0.025 0.975]
------------------------------------------------------------------------------
ar.L1 -0.0158 0.030 -0.524 0.601 -0.075 0.043
ma.L1 -1.0000 0.067 -14.838 0.000 -1.132 -0.868
sigma2 1.346e+06 5e-08 2.69e+13 0.000 1.35e+06 1.35e+06
===================================================================================
Ljung-Box (L1) (Q): 0.00 Jarque-Bera (JB): 65.30
Prob(Q): 0.97 Prob(JB): 0.00
Heteroskedasticity (H): 0.99 Skew: -0.02
Prob(H) (two-sided): 0.94 Kurtosis: 1.80
===================================================================================
Сеточный анализ временных рядов
Сеточный анализ временных рядов — это метод анализа, который позволяет исследовать несколько временных рядов, имеющих различные характеристики, в одном и том же контексте. Это особенно полезно, когда у вас есть набор данных, представляющий несколько компонентов или категорий продуктов в магазине, и вы хотите исследовать их динамику во времени.
Предположим, у нас есть данные о продажах разных категорий продуктов в магазине МВидео на протяжении нескольких месяцев. Категории продуктов могут включать в себя телевизоры, ноутбуки, смартфоны и бытовую технику.
import pandas as pd
import numpy as np
# Создаем dataset с продажами разных категорий продуктов
data = {'Дата': pd.date_range(start='2023-01-01', periods=12, freq='M'),
'Продажи телевизоров': [50, 45, 55, 60, 70, 80, 90, 85, 75, 70, 60, 55],
'Продажи ноутбуков': [30, 35, 40, 45, 50, 60, 65, 70, 75, 80, 85, 90],
'Продажи смартфонов': [70, 75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 125],
'Продажи бытовой техники': [40, 42, 45, 48, 50, 52, 55, 58, 60, 62, 65, 68]}
sales_df = pd.DataFrame(data)
# Устанавливаем 'Дата' в качестве индекса
sales_df.set_index('Дата', inplace=True)
Теперь у нас есть данные о продажах четырех разных категорий продуктов в магазине МВидео. Проведем сеточный анализ для исследования динамики продаж.
1. Визуализация данных:
Сначала мы можем визуализировать продажи каждой категории продуктов на одном графике, чтобы увидеть их динамику во времени.
import matplotlib.pyplot as plt
# Визуализация продаж каждой категории продуктов
plt.figure(figsize=(12, 6))
for column in sales_df.columns:
plt.plot(sales_df.index, sales_df[column], label=column)
plt.title('Динамика продаж разных категорий продуктов')
plt.xlabel('Дата')
plt.ylabel('Продажи')
plt.legend()
plt.grid(True)
plt.show()
2. Вычисление корреляций:
Для сеточного анализа мы также можем вычислить корреляции между продажами разных категорий продуктов. Это может помочь нам определить, есть ли взаимосвязь между продажами разных продуктов.
# Вычисление корреляций между продажами
correlation_matrix = sales_df.corr()
# Визуализация корреляционной матрицы
import seaborn as sns
plt.figure(figsize=(8, 6))
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', linewidths=0.5)
plt.title('Корреляционная матрица продаж')
plt.show()
Визуализация корреляционной матрицы позволяет нам видеть, есть ли сильные связи между категориями продуктов.
3. Сравнение трендов:
Сеточный анализ также может включать в себя сравнение трендов продаж разных категорий продуктов. Мы можем использовать скользящее среднее для сглаживания данных и выявления трендов.
# Сглаживание данных с помощью скользящего среднего
window = 3 # Размер окна скользящего среднего
smoothed_sales_df = sales_df.rolling(window=window).mean()
# Визуализация сглаженных данных
plt.figure(figsize=(12, 6))
for column in smoothed_sales_df.columns:
plt.plot(smoothed_sales_df.index, smoothed_sales_df[column], label=column)
plt.title(f'Сглаженные продажи с окном {window}')
plt.xlabel('Дата')
plt.ylabel('Продажи')
plt.legend()
plt.grid(True)
plt.show()
Сглаженные данные могут помочь нам более четко увидеть общие тренды продаж.
Сеточный анализ временных рядов может быть мощным инструментом для исследования динамики разных компонентов данных и выявления взаимосвязей между ними. Важно выбирать подходящие методы в зависимости от конкретной задачи и данных, с которыми вы работаете.
Совместные временные ряды
Совместные временные ряды — это анализ нескольких временных рядов, чтобы определить, существует ли между ними взаимосвязь или зависимость. Это может быть полезно, например, для выявления корреляций между продажами разных продуктов в магазине или между разными параметрами в медицинских исследованиях.
Создадим два временных ряда, представляющих продажи телевизоров и продажи ноутбуков в магазине МВидео, и определим, есть ли между ними корреляция.
import pandas as pd
import numpy as np
# Создаем dataset с продажами телевизоров и ноутбуков
data = {'Дата': pd.date_range(start='2023-01-01', periods=12, freq='M'),
'Продажи телевизоров': [50, 45, 55, 60, 70, 80, 90, 85, 75, 70, 60, 55],
'Продажи ноутбуков': [30, 35, 40, 45, 50, 60, 65, 70, 75, 80, 85, 90]}
sales_df = pd.DataFrame(data)
# Устанавливаем 'Дата' в качестве индекса
sales_df.set_index('Дата', inplace=True)
# Вычисляем корреляцию между продажами телевизоров и ноутбуков
correlation = sales_df['Продажи телевизоров'].corr(sales_df['Продажи ноутбуков'])
print(f'Корреляция между продажами телевизоров и ноутбуков: {correlation:.2f}')
Результат:
Корреляция между продажами телевизоров и ноутбуков: 0.41
Вычисление корреляции может помочь в определении, существует ли статистически значимая связь между этими двумя временными рядами.
Заключение
Анализ временных рядов имеет множество практических применений, включая прогнозирование продаж, управление финансами, медицинские исследования и многое другое. Понимание временных рядов и умение проводить их анализ являются важными навыками для аналитиков данных и специалистов по машинному обучению. Мы надеемся, что эта статья помогла вам расширить ваши знания о работе с временными рядами и вдохновила вас на дальнейшие исследования в этой области.