воскресенье, 22 мая 2022 г.

Линейная регрессия с временными рядами : курсы Kaggle

Kaggle - социальная сеть специалистов по обработке данных и машинному обучению. Принадлежит корпорации Google. В частности она предлагает пройти ряд коротких курсов по программированию, анализу данных и машинному обучению. Меня заинтересовал курс по прогнозированию временных рядов. Попробую применить его для своих задач, связанных с прогнозированием продаж в розничной торговле одеждой. Первая часть курса называется "Линейная регрессия с временными рядами". Для примеров буду использовать свой набор данных.


Работаем в IPython notebook, начальные установки и пакеты

from warnings import simplefilter
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
import pandas as pd
simplefilter("ignore")  # Игнорировать предупреждения о очистке выходных ячеек
#Установки параметров для Matplotlib 
plt.style.use("seaborn-whitegrid")
plt.rc("figure", autolayout=True, figsize=(11, 4))
plt.rc(
    "axes",
    labelweight="bold",
    labelsize="large",
    titleweight="bold",
    titlesize=14,
    titlepad=10,
)
plot_params = dict(
    color="0.75",
    style=".-",
    markeredgecolor="0.25",
    markerfacecolor="0.25",
    legend=False,
)
from statsmodels.graphics.tsaplots import plot_acf
from sklearn import metrics
import math

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


df = pd.read_excel(
    "shop_rev.xlsx",
    parse_dates=['month'],
    index_col='month')
pd.concat([df.head(), df.tail()])


pantsjackettotal
month
2015-01-01283251177840103
2015-02-01210661081131877
2015-03-01213171388335200
2015-04-01289161313342049
2015-05-01353061057745883
2021-08-01242271687141098
2021-09-01157102752843238
2021-10-01180663727355339
2021-11-01184725190670378
2021-12-01221773962161798

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

df.drop(['pants','jacket'], axis=1,inplace=True)
df.head( 
total
month
2015-01-0140103
2015-02-0131877
2015-03-0135200
2015-04-0142049
2015-05-0145883

Добавим фиктивную ось времени или по другому функцию временных шагов

df['time'] = np.arange(len(df.index))
df.head()
totaltime
month
2015-01-01401030
2015-02-01318771
2015-03-01352002
2015-04-01420493
2015-05-01458834


Выведем график временного ряда с линейным трендом





Какие выводы из этого графика можно сделать : 1) Временной ряд имеет явную сезонность 2) Тренд временного ряда нелинейный, сначала растет, потом падает 3)Падающий линейный тренд отразил как бы итоговую составляющую.

Проверим наш временной ряд на наличие автокорреляции. Напомним себе, что автокорреляцией называется корреляция между величиной и ее запаздыванием в один или более периодов времени. Для этого выведем график автокорреляционной функции (АКФ).

plot_acf(df['total'], lags=36)
plt.tight_layout()
Как видно, структура АКФ идет циклами, максимумы циклов приходятся на 12, это означает, что показатель 12 шагов (в данном случае месяцев) назад очень сильно влияет на текущий показатель, и это логично, потому что наши данные месячные. Это означает, что выручка января этого года похожа на выручку января прошлого года, то есть в наших данных наблюдается сезонность

Добавим в наши данные еще одну колонку со смещение по оси времени на 12 месяцев вперед.

df['Lag_12'] = df['total'].shift(12)
df = df.reindex(columns=['total', 'Lag_12'])
df.head()




month total Lag_12
2015-01-01 39352 NaN
2015-02-01 31923 NaN
2015-03-01 35037 NaN
2015-04-01 41981 NaN
2015-05-01 46049 NaN


Выведем график с линией регрессии

fig, ax = plt.subplots()

ax = sns.regplot(x='Lag_12', y='total', data=df, ci=None, scatter_kws=dict(color='0.25'))

ax.set_aspect('equal')

ax.set_title('Lag 12 Plot of Total Sales');



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


from sklearn.linear_model import LinearRegression


X = df.loc[:, ['Lag_12']]

# удаляем отсутствующие значения

X.dropna(inplace=True)  

# создаем целевой вектор 

y = df.loc[:, 'total']  

# отбросить соответствующие значения целевого показателя

y, X = y.align(X, join='inner')  


model = LinearRegression()

model.fit(X, y)


y_pred = pd.Series(model.predict(X), index=X.index)




Следующий временной график показывает нам, как наши прогнозы теперь реагируют на поведение ряда в недавнем прошлом.

ax = y.plot(**plot_params)
ax = y_pred.plot()
ax.legend()




Используем модель линейной регрессии для предсказания выручки. Делим наши данные на обучающий и тестовый набор. Обучаем модель на обучающей части и после этого делаем прогноз на тестовой.

#Обучаем на 66 месяцах , делаем прогноз на 6 месяцев
X_train, X_test=X[0:66],X[66:]
y_train, y_test=y[0:66],y[66:]

my_lm = LinearRegression()
my_lm.fit(X = X_train, y = y_train)
train_fcst = my_lm.predict(X_train)
test_fcst = my_lm.predict(X_test)

Добавим к существующим метрикам качества еще одну - Средняя абсолютная процентная ошибка (mean absolute percentage error - MAPE)

def MAPE(Y_actual,Y_Predicted):
    mape = np.mean(np.abs((Y_actual - Y_Predicted)/Y_actual))*100
    return mape

# Рассчитываем метрики качества для обучающей выборки
mae = metrics.mean_absolute_error(y_train, train_fcst)
mse = metrics.mean_squared_error(y_train, train_fcst)
mape = MAPE(y_train, train_fcst)
rmse = math.sqrt(mse)
r2 = metrics.r2_score(y_train, train_fcst)

# Выводим метрики качества для обучающей выборки
print('Decision Linear Regression Metrics:')
print(f'R^2 Score                  = {r2:.3f}')
print(f'Mean Absolute Percentage Error    = {mape:.2f}')
print(f'Mean Absolute Error        = {mae:.2f}')
print(f'Mean Squared Error         = {mse:.2f}')
print(f'Root Mean Squared Error    = {rmse:.2f}')

Decision Linear Regression Metrics:
R^2 Score                  = 0.868
Mean Absolute Percentage Error    = 9.16
Mean Absolute Error        = 4971.57
Mean Squared Error         = 31732803.97
Root Mean Squared Error    = 5633.19
Выведем график


Повторим все для тестовой части
# Рассчитываем метрики качества для тестовой выборки
mae = metrics.mean_absolute_error(y_test, test_fcst)
mse = metrics.mean_squared_error(y_test, test_fcst)
mape = MAPE(y_test, pred)
rmse = math.sqrt(mse)
r2 = metrics.r2_score(y_test, test_fcst)
# Выводим метрики для тестовой выборки
print('Decision Linear Regression Metrics:')
print(f'R^2 Score                  = {r2:.3f}')
print(f'Mean Absolute Percentage Error    = {mape:.2f}')
print(f'Mean Absolute Error        = {mae:.2f}')
print(f'Mean Squared Error         = {mse:.2f}')
print(f'Root Mean Squared Error    = {rmse:.2f}')
Decision Linear Regression Metrics:
R^2 Score                  = 0.615
Mean Absolute Percentage Error    = 14.25
Mean Absolute Error        = 6973.32
Mean Squared Error         = 48953396.23
Root Mean Squared Error    = 6996.67
Выведем график
plt.plot(list(test_fcst))
plt.plot(list(y_test))
plt.xlabel('Steps into the test set')
plt.ylabel('Test Total Sales')
plt.legend(['Total test', 'Predict test'])





















Комментариев нет:

Отправить комментарий