21 KiB
Прогнозування часових рядів за допомогою регресора опорних векторів
У попередньому уроці ви дізналися, як використовувати модель ARIMA для прогнозування часових рядів. Тепер ви ознайомитеся з моделлю регресора опорних векторів (Support Vector Regressor), яка використовується для прогнозування безперервних даних.
Тест перед лекцією
Вступ
У цьому уроці ви дізнаєтеся, як створювати моделі за допомогою SVM: Support Vector Machine для регресії, або SVR: Support Vector Regressor.
SVR у контексті часових рядів 1
Перед тим як зрозуміти важливість SVR у прогнозуванні часових рядів, ось кілька важливих концепцій, які вам потрібно знати:
- Регресія: Техніка навчання з учителем для прогнозування безперервних значень на основі заданого набору вхідних даних. Ідея полягає у побудові кривої (або лінії) у просторі ознак, яка має максимальну кількість точок даних. Натисніть тут для отримання додаткової інформації.
- Машина опорних векторів (SVM): Тип моделі машинного навчання з учителем, яка використовується для класифікації, регресії та виявлення аномалій. Модель є гіперплощиною у просторі ознак, яка у випадку класифікації виступає як межа, а у випадку регресії — як лінія найкращого підходу. У SVM зазвичай використовується функція ядра для перетворення набору даних у простір з більшою кількістю вимірів, щоб вони могли бути легко розділені. Натисніть тут для отримання додаткової інформації про SVM.
- Регресор опорних векторів (SVR): Тип SVM, який знаходить лінію найкращого підходу (яка у випадку SVM є гіперплощиною) з максимальною кількістю точок даних.
Чому SVR? 1
У попередньому уроці ви дізналися про ARIMA, яка є дуже успішним статистичним лінійним методом для прогнозування даних часових рядів. Однак у багатьох випадках дані часових рядів мають нелінійність, яку неможливо відобразити за допомогою лінійних моделей. У таких випадках здатність SVM враховувати нелінійність даних для задач регресії робить SVR успішним у прогнозуванні часових рядів.
Вправа - створення моделі SVR
Перші кілька кроків підготовки даних такі ж, як у попередньому уроці про ARIMA.
Відкрийте папку /working у цьому уроці та знайдіть файл notebook.ipynb. 2
-
Запустіть ноутбук та імпортуйте необхідні бібліотеки: 2
import sys sys.path.append('../../')
import os import warnings import matplotlib.pyplot as plt import numpy as np import pandas as pd import datetime as dt import math from sklearn.svm import SVR from sklearn.preprocessing import MinMaxScaler from common.utils import load_data, mape
-
Завантажте дані з файлу
/data/energy.csv
у Pandas DataFrame та перегляньте їх: 2energy = load_data('../../data')[['load']]
-
Побудуйте графік усіх доступних даних про енергію з січня 2012 року до грудня 2014 року: 2
energy.plot(y='load', subplots=True, figsize=(15, 8), fontsize=12) plt.xlabel('timestamp', fontsize=12) plt.ylabel('load', fontsize=12) plt.show()
Тепер давайте створимо нашу модель SVR.
Створення навчальних і тестових наборів даних
Тепер ваші дані завантажені, тому ви можете розділити їх на навчальний і тестовий набори. Потім ви переформатуєте дані, щоб створити набір даних на основі часових кроків, який буде потрібен для SVR. Ви навчите свою модель на навчальному наборі. Після завершення навчання моделі ви оціните її точність на навчальному наборі, тестовому наборі, а потім на повному наборі даних, щоб побачити загальну продуктивність. Ви повинні переконатися, що тестовий набір охоплює більш пізній період часу, ніж навчальний набір, щоб гарантувати, що модель не отримує інформацію з майбутніх періодів часу 2 (ситуація, відома як перенавчання).
-
Виділіть двомісячний період з 1 вересня по 31 жовтня 2014 року для навчального набору. Тестовий набір включатиме двомісячний період з 1 листопада по 31 грудня 2014 року: 2
train_start_dt = '2014-11-01 00:00:00' test_start_dt = '2014-12-30 00:00:00'
-
Візуалізуйте відмінності: 2
energy[(energy.index < test_start_dt) & (energy.index >= train_start_dt)][['load']].rename(columns={'load':'train'}) \ .join(energy[test_start_dt:][['load']].rename(columns={'load':'test'}), how='outer') \ .plot(y=['train', 'test'], figsize=(15, 8), fontsize=12) plt.xlabel('timestamp', fontsize=12) plt.ylabel('load', fontsize=12) plt.show()
Підготовка даних для навчання
Тепер вам потрібно підготувати дані для навчання, виконавши фільтрацію та масштабування даних. Відфільтруйте ваш набір даних, щоб включити лише потрібні періоди часу та стовпці, а також виконайте масштабування, щоб дані були представлені в інтервалі 0,1.
-
Відфільтруйте оригінальний набір даних, щоб включити лише зазначені періоди часу для кожного набору та лише потрібний стовпець 'load' плюс дату: 2
train = energy.copy()[(energy.index >= train_start_dt) & (energy.index < test_start_dt)][['load']] test = energy.copy()[energy.index >= test_start_dt][['load']] print('Training data shape: ', train.shape) print('Test data shape: ', test.shape)
Training data shape: (1416, 1) Test data shape: (48, 1)
-
Масштабуйте навчальні дані до діапазону (0, 1): 2
scaler = MinMaxScaler() train['load'] = scaler.fit_transform(train)
-
Тепер масштабуйте тестові дані: 2
test['load'] = scaler.transform(test)
Створення даних із часовими кроками 1
Для SVR ви перетворюєте вхідні дані у форму [batch, timesteps]
. Тобто ви переформатуєте існуючі train_data
та test_data
, щоб додати новий вимір, який відповідає часовим крокам.
# Converting to numpy arrays
train_data = train.values
test_data = test.values
Для цього прикладу ми беремо timesteps = 5
. Отже, вхідні дані для моделі — це дані за перші 4 часові кроки, а вихідні — дані за 5-й часовий крок.
timesteps=5
Перетворення навчальних даних у 2D-тензор за допомогою вкладеного спискового розуміння:
train_data_timesteps=np.array([[j for j in train_data[i:i+timesteps]] for i in range(0,len(train_data)-timesteps+1)])[:,:,0]
train_data_timesteps.shape
(1412, 5)
Перетворення тестових даних у 2D-тензор:
test_data_timesteps=np.array([[j for j in test_data[i:i+timesteps]] for i in range(0,len(test_data)-timesteps+1)])[:,:,0]
test_data_timesteps.shape
(44, 5)
Вибір вхідних і вихідних даних із навчальних і тестових даних:
x_train, y_train = train_data_timesteps[:,:timesteps-1],train_data_timesteps[:,[timesteps-1]]
x_test, y_test = test_data_timesteps[:,:timesteps-1],test_data_timesteps[:,[timesteps-1]]
print(x_train.shape, y_train.shape)
print(x_test.shape, y_test.shape)
(1412, 4) (1412, 1)
(44, 4) (44, 1)
Реалізація SVR 1
Тепер настав час реалізувати SVR. Щоб дізнатися більше про цю реалізацію, ви можете звернутися до цієї документації. Для нашої реалізації ми дотримуємося таких кроків:
- Визначте модель, викликавши
SVR()
і передавши гіперпараметри моделі: kernel, gamma, c та epsilon - Підготуйте модель для навчальних даних, викликавши функцію
fit()
- Зробіть прогнози, викликавши функцію
predict()
Тепер ми створюємо модель SVR. Тут ми використовуємо RBF kernel і встановлюємо гіперпараметри gamma, C та epsilon як 0.5, 10 та 0.05 відповідно.
model = SVR(kernel='rbf',gamma=0.5, C=10, epsilon = 0.05)
Навчання моделі на навчальних даних 1
model.fit(x_train, y_train[:,0])
SVR(C=10, cache_size=200, coef0=0.0, degree=3, epsilon=0.05, gamma=0.5,
kernel='rbf', max_iter=-1, shrinking=True, tol=0.001, verbose=False)
Прогнозування за допомогою моделі 1
y_train_pred = model.predict(x_train).reshape(-1,1)
y_test_pred = model.predict(x_test).reshape(-1,1)
print(y_train_pred.shape, y_test_pred.shape)
(1412, 1) (44, 1)
Ви створили SVR! Тепер потрібно оцінити його.
Оцінка вашої моделі 1
Для оцінки спочатку ми повернемо дані до оригінального масштабу. Потім, щоб перевірити продуктивність, ми побудуємо графік оригінальних і прогнозованих часових рядів, а також виведемо результат MAPE.
Масштабування прогнозованих і оригінальних вихідних даних:
# Scaling the predictions
y_train_pred = scaler.inverse_transform(y_train_pred)
y_test_pred = scaler.inverse_transform(y_test_pred)
print(len(y_train_pred), len(y_test_pred))
# Scaling the original values
y_train = scaler.inverse_transform(y_train)
y_test = scaler.inverse_transform(y_test)
print(len(y_train), len(y_test))
Перевірка продуктивності моделі на навчальних і тестових даних 1
Ми витягуємо часові мітки з набору даних, щоб показати їх на осі x нашого графіка. Зверніть увагу, що ми використовуємо перші timesteps-1
значення як вхідні дані для першого вихідного значення, тому часові мітки для вихідних даних почнуться після цього.
train_timestamps = energy[(energy.index < test_start_dt) & (energy.index >= train_start_dt)].index[timesteps-1:]
test_timestamps = energy[test_start_dt:].index[timesteps-1:]
print(len(train_timestamps), len(test_timestamps))
1412 44
Побудова графіка прогнозів для навчальних даних:
plt.figure(figsize=(25,6))
plt.plot(train_timestamps, y_train, color = 'red', linewidth=2.0, alpha = 0.6)
plt.plot(train_timestamps, y_train_pred, color = 'blue', linewidth=0.8)
plt.legend(['Actual','Predicted'])
plt.xlabel('Timestamp')
plt.title("Training data prediction")
plt.show()
Виведення MAPE для навчальних даних
print('MAPE for training data: ', mape(y_train_pred, y_train)*100, '%')
MAPE for training data: 1.7195710200875551 %
Побудова графіка прогнозів для тестових даних
plt.figure(figsize=(10,3))
plt.plot(test_timestamps, y_test, color = 'red', linewidth=2.0, alpha = 0.6)
plt.plot(test_timestamps, y_test_pred, color = 'blue', linewidth=0.8)
plt.legend(['Actual','Predicted'])
plt.xlabel('Timestamp')
plt.show()
Виведення MAPE для тестових даних
print('MAPE for testing data: ', mape(y_test_pred, y_test)*100, '%')
MAPE for testing data: 1.2623790187854018 %
🏆 Ви отримали дуже хороший результат на тестовому наборі даних!
Перевірка продуктивності моделі на повному наборі даних 1
# Extracting load values as numpy array
data = energy.copy().values
# Scaling
data = scaler.transform(data)
# Transforming to 2D tensor as per model input requirement
data_timesteps=np.array([[j for j in data[i:i+timesteps]] for i in range(0,len(data)-timesteps+1)])[:,:,0]
print("Tensor shape: ", data_timesteps.shape)
# Selecting inputs and outputs from data
X, Y = data_timesteps[:,:timesteps-1],data_timesteps[:,[timesteps-1]]
print("X shape: ", X.shape,"\nY shape: ", Y.shape)
Tensor shape: (26300, 5)
X shape: (26300, 4)
Y shape: (26300, 1)
# Make model predictions
Y_pred = model.predict(X).reshape(-1,1)
# Inverse scale and reshape
Y_pred = scaler.inverse_transform(Y_pred)
Y = scaler.inverse_transform(Y)
plt.figure(figsize=(30,8))
plt.plot(Y, color = 'red', linewidth=2.0, alpha = 0.6)
plt.plot(Y_pred, color = 'blue', linewidth=0.8)
plt.legend(['Actual','Predicted'])
plt.xlabel('Timestamp')
plt.show()
print('MAPE: ', mape(Y_pred, Y)*100, '%')
MAPE: 2.0572089029888656 %
🏆 Дуже гарні графіки, які показують модель з хорошою точністю. Чудова робота!
🚀Виклик
- Спробуйте змінити гіперпараметри (gamma, C, epsilon) під час створення моделі та оцінити дані, щоб побачити, який набір гіперпараметрів дає найкращі результати на тестових даних. Щоб дізнатися більше про ці гіперпараметри, ви можете звернутися до документа тут.
- Спробуйте використовувати різні функції ядра для моделі та аналізувати їх продуктивність на наборі даних. Корисний документ можна знайти тут.
- Спробуйте використовувати різні значення для
timesteps
, щоб модель могла дивитися назад для прогнозування.
Тест після лекції
Огляд і самостійне навчання
Цей урок був присвячений застосуванню SVR для прогнозування часових рядів. Щоб дізнатися більше про SVR, ви можете звернутися до цього блогу. Ця документація scikit-learn надає більш детальне пояснення про SVM загалом, SVR, а також інші деталі реалізації, такі як різні функції ядра, які можна використовувати, та їх параметри.
Завдання
Подяки
Відмова від відповідальності:
Цей документ було перекладено за допомогою сервісу автоматичного перекладу Co-op Translator. Хоча ми прагнемо до точності, зверніть увагу, що автоматичні переклади можуть містити помилки або неточності. Оригінальний документ мовою оригіналу слід вважати авторитетним джерелом. Для критично важливої інформації рекомендується професійний людський переклад. Ми не несемо відповідальності за будь-які непорозуміння або неправильні тлумачення, що виникли внаслідок використання цього перекладу.
-
Текст, код і результати в цьому розділі були надані @AnirbanMukherjeeXD ↩︎
-
Текст, код і результати в цьому розділі були взяті з ARIMA ↩︎