Как предсказать временный ряд
Я пытаюсь сделать предсказание временного ряда на несколько дней вперед. Делаю это с помощью SARIMA. Я никогда не работал с временными рядами и у меня возникают сложности. Это не обязательно должна быть SARIMA.
Тут датафрэйм.
В столбце registration- количество регистраций объекта с дискретизацией в час.
Ниже мой код:
import warnings
import pandas as pd
import numpy as np
import statsmodels.api as sm
import matplotlib.pyplot as plt
plt.style.use('fivethirtyeight')
df=pd.read_csv('mt_resample (1).csv',index_col=[0],parse_dates=[0])
train_arima = df["Частота регистраций"]
model_sarima = sm.tsa.statespace.SARIMAX(train_arima,
order=(1, 1, 1),
seasonal_order=(1, 1, 1, 12),
enforce_stationarity=False,
enforce_invertibility=False)
results_sarima = model_sarima.fit()
# Получаю пердсказания на 100 шагов вперед
pred_uc = results.get_forecast(steps=100)
# Доверительный интервал
pred_ci = pred_uc.conf_int()
ax = y.plot(label='observed', figsize=(20, 15))
pred_uc.predicted_mean.plot(ax=ax, label='Forecast')
ax.fill_between(pred_ci.index,
pred_ci.iloc[:, 0],
pred_ci.iloc[:, 1], color='k', alpha=.25)
ax.set_xlabel('Date')
ax.set_ylabel('Registration')
plt.legend()
plt.show()
Предсказывает не очень! Подскажите что я делаю не так, и как я могу улучшить результат?
Ответы (1 шт):
Скорее всего тут вообще не нужно работать как с временными рядами. Но это нужно дополнительно проверять. На мой взгляд тут достаточно дня недели и времени суток:
import seaborn as sns
dt = pd.Series(df.index)
df['DayOfWeek'] = dt.dt.dayofweek.values
df['Hour'] = dt.dt.hour.values
df['Day'] = dt.dt.day.values
plt.figure()
sns.barplot(x = df.DayOfWeek, y = df.Registration)
plt.figure()
sns.barplot(x = df.Hour, y = df.Registration)
plt.figure()
sns.barplot(x = df.Day, y = df.Registration)
День месяца кажется тоже сильной фичей, но я её потом выкинул, без неё лучше метрика получается. Слишком большой у неё разброс, он модель с толку сбивает в итоге.
from sklearn.metrics import mean_squared_error
from sklearn.ensemble import RandomForestRegressor
X = df.drop(columns=['Registration','Day'])
y = df['Registration']
train_size = 2 * df.shape[0] // 3
X_train = X[:train_size]
X_test = X[train_size:]
y_train = y[:train_size]
y_test = y[train_size:]
rf = RandomForestRegressor()
rf.fit(X_train, y_train)
y_preds = rf.predict(X_test)
print(mean_squared_error(y_test, y_preds))
print(rf.feature_importances_)
plt.figure(figsize=(16,8))
sns.scatterplot(x=y_test.index, y = y_test.values)
sns.scatterplot(x=y_test.index, y = y_preds)
#19.04574056191149
#[0.35862722 0.64137278]
Сравниваем тестовую часть данных с предсказанием:
Результат не идеальный, но на что-то похож реальное.
P.S. Разброс отклонения предсказаний от теста. Видно, что модель завышает результат. Возможно, это как-раз связано с сезонностью (лето). Но без данных за несколько лет такую сезонность нельзя выделить из данных.
plt.figure(figsize=(16,8))
sns.scatterplot(x=y_test.index, y = y_preds - y_test.values, alpha=0.5)
Посмотрел, да, сезонность в зависимости от времени года явно есть. Либо это может быть связано с тем, что регистрации просто падают со временем. Сказать на основе данных меньше чем за год сложно.







