Добро пожаловать во вторую часть нашей серии статей "Работа с временными рядами в 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

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

Заключение


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

Комментарии (2)


  1. Cheburator2033
    25.10.2023 09:59

    Спасибо.


  1. Dynasaur
    25.10.2023 09:59
    +3

    Посмотрел я на вашу корреляционную матрицу..., дааа... как далеко это от реальной жизни...