|
|
<!--
|
|
|
CO_OP_TRANSLATOR_METADATA:
|
|
|
{
|
|
|
"original_hash": "482bccabe1df958496ea71a3667995cd",
|
|
|
"translation_date": "2025-09-04T23:53:49+00:00",
|
|
|
"source_file": "7-TimeSeries/3-SVR/README.md",
|
|
|
"language_code": "bg"
|
|
|
}
|
|
|
-->
|
|
|
# Прогнозиране на времеви серии със Support Vector Regressor
|
|
|
|
|
|
В предишния урок научихте как да използвате модела ARIMA за прогнозиране на времеви серии. Сега ще разгледате модела Support Vector Regressor, който е регресионен модел, използван за прогнозиране на непрекъснати данни.
|
|
|
|
|
|
## [Тест преди лекцията](https://ff-quizzes.netlify.app/en/ml/)
|
|
|
|
|
|
## Въведение
|
|
|
|
|
|
В този урок ще откриете специфичен начин за изграждане на модели с [**SVM**: **S**upport **V**ector **M**achine](https://en.wikipedia.org/wiki/Support-vector_machine) за регресия, или **SVR: Support Vector Regressor**.
|
|
|
|
|
|
### SVR в контекста на времеви серии [^1]
|
|
|
|
|
|
Преди да разберете значението на SVR за прогнозиране на времеви серии, ето някои важни концепции, които трябва да знаете:
|
|
|
|
|
|
- **Регресия:** Техника за обучение с надзор, която предсказва непрекъснати стойности от даден набор от входни данни. Идеята е да се намери крива (или линия) в пространството на характеристиките, която има максимален брой точки от данни. [Кликнете тук](https://en.wikipedia.org/wiki/Regression_analysis) за повече информация.
|
|
|
- **Support Vector Machine (SVM):** Вид модел за машинно обучение с надзор, използван за класификация, регресия и откриване на аномалии. Моделът представлява хиперплоскост в пространството на характеристиките, която в случай на класификация действа като граница, а в случай на регресия - като линия на най-добро съответствие. В SVM обикновено се използва Kernel функция за трансформиране на набора от данни в пространство с по-голям брой измерения, така че те да бъдат лесно разделими. [Кликнете тук](https://en.wikipedia.org/wiki/Support-vector_machine) за повече информация за SVM.
|
|
|
- **Support Vector Regressor (SVR):** Вид SVM, който намира линия на най-добро съответствие (която в случая на SVM е хиперплоскост), която има максимален брой точки от данни.
|
|
|
|
|
|
### Защо SVR? [^1]
|
|
|
|
|
|
В последния урок научихте за ARIMA, който е много успешен статистически линеен метод за прогнозиране на времеви серии. Въпреки това, в много случаи времевите серии имат *нелинейност*, която не може да бъде моделирана от линейни модели. В такива случаи способността на SVM да отчита нелинейността в данните за задачи по регресия прави SVR успешен в прогнозиране на времеви серии.
|
|
|
|
|
|
## Упражнение - изграждане на SVR модел
|
|
|
|
|
|
Първите няколко стъпки за подготовка на данните са същите като тези от предишния урок за [ARIMA](https://github.com/microsoft/ML-For-Beginners/tree/main/7-TimeSeries/2-ARIMA).
|
|
|
|
|
|
Отворете папката [_/working_](https://github.com/microsoft/ML-For-Beginners/tree/main/7-TimeSeries/3-SVR/working) в този урок и намерете файла [_notebook.ipynb_](https://github.com/microsoft/ML-For-Beginners/blob/main/7-TimeSeries/3-SVR/working/notebook.ipynb). [^2]
|
|
|
|
|
|
1. Стартирайте notebook-а и импортирайте необходимите библиотеки: [^2]
|
|
|
|
|
|
```python
|
|
|
import sys
|
|
|
sys.path.append('../../')
|
|
|
```
|
|
|
|
|
|
```python
|
|
|
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
|
|
|
```
|
|
|
|
|
|
2. Заредете данните от файла `/data/energy.csv` в Pandas dataframe и разгледайте ги: [^2]
|
|
|
|
|
|
```python
|
|
|
energy = load_data('../../data')[['load']]
|
|
|
```
|
|
|
|
|
|
3. Начертайте всички налични данни за енергия от януари 2012 до декември 2014: [^2]
|
|
|
|
|
|
```python
|
|
|
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] (ситуация, известна като *Overfitting*).
|
|
|
|
|
|
1. Отделете двумесечен период от 1 септември до 31 октомври 2014 за тренировъчния набор. Тестовият набор ще включва двумесечния период от 1 ноември до 31 декември 2014: [^2]
|
|
|
|
|
|
```python
|
|
|
train_start_dt = '2014-11-01 00:00:00'
|
|
|
test_start_dt = '2014-12-30 00:00:00'
|
|
|
```
|
|
|
|
|
|
2. Визуализирайте разликите: [^2]
|
|
|
|
|
|
```python
|
|
|
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.
|
|
|
|
|
|
1. Филтрирайте оригиналния набор от данни, за да включите само споменатите времеви периоди за всеки набор и само необходимата колона 'load' плюс датата: [^2]
|
|
|
|
|
|
```python
|
|
|
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)
|
|
|
```
|
|
|
|
|
|
```output
|
|
|
Training data shape: (1416, 1)
|
|
|
Test data shape: (48, 1)
|
|
|
```
|
|
|
|
|
|
2. Скалирайте тренировъчните данни, за да бъдат в диапазона (0, 1): [^2]
|
|
|
|
|
|
```python
|
|
|
scaler = MinMaxScaler()
|
|
|
train['load'] = scaler.fit_transform(train)
|
|
|
```
|
|
|
|
|
|
4. Сега скалирайте тестовите данни: [^2]
|
|
|
|
|
|
```python
|
|
|
test['load'] = scaler.transform(test)
|
|
|
```
|
|
|
|
|
|
### Създаване на данни с времеви стъпки [^1]
|
|
|
|
|
|
За SVR трансформирате входните данни, за да бъдат във формата `[batch, timesteps]`. Така преформатирате съществуващите `train_data` и `test_data`, така че да има ново измерение, което се отнася до времевите стъпки.
|
|
|
|
|
|
```python
|
|
|
# Converting to numpy arrays
|
|
|
train_data = train.values
|
|
|
test_data = test.values
|
|
|
```
|
|
|
|
|
|
За този пример вземаме `timesteps = 5`. Така входовете към модела са данните за първите 4 времеви стъпки, а изходът ще бъде данните за 5-тата времева стъпка.
|
|
|
|
|
|
```python
|
|
|
timesteps=5
|
|
|
```
|
|
|
|
|
|
Преобразуване на тренировъчните данни в 2D тензор с помощта на вложени списъчни разбирания:
|
|
|
|
|
|
```python
|
|
|
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
|
|
|
```
|
|
|
|
|
|
```output
|
|
|
(1412, 5)
|
|
|
```
|
|
|
|
|
|
Преобразуване на тестовите данни в 2D тензор:
|
|
|
|
|
|
```python
|
|
|
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
|
|
|
```
|
|
|
|
|
|
```output
|
|
|
(44, 5)
|
|
|
```
|
|
|
|
|
|
Избор на входове и изходи от тренировъчните и тестовите данни:
|
|
|
|
|
|
```python
|
|
|
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)
|
|
|
```
|
|
|
|
|
|
```output
|
|
|
(1412, 4) (1412, 1)
|
|
|
(44, 4) (44, 1)
|
|
|
```
|
|
|
|
|
|
### Имплементиране на SVR [^1]
|
|
|
|
|
|
Сега е време да имплементирате SVR. За повече информация относно тази имплементация можете да се обърнете към [тази документация](https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVR.html). За нашата имплементация следваме тези стъпки:
|
|
|
|
|
|
1. Дефинирайте модела, като извикате `SVR()` и зададете хиперпараметрите на модела: kernel, gamma, c и epsilon
|
|
|
2. Подгответе модела за тренировъчните данни, като извикате функцията `fit()`
|
|
|
3. Направете прогнози, като извикате функцията `predict()`
|
|
|
|
|
|
Сега създаваме SVR модел. Тук използваме [RBF kernel](https://scikit-learn.org/stable/modules/svm.html#parameters-of-the-rbf-kernel) и задаваме хиперпараметрите gamma, C и epsilon като 0.5, 10 и 0.05 съответно.
|
|
|
|
|
|
```python
|
|
|
model = SVR(kernel='rbf',gamma=0.5, C=10, epsilon = 0.05)
|
|
|
```
|
|
|
|
|
|
#### Обучение на модела върху тренировъчни данни [^1]
|
|
|
|
|
|
```python
|
|
|
model.fit(x_train, y_train[:,0])
|
|
|
```
|
|
|
|
|
|
```output
|
|
|
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]
|
|
|
|
|
|
```python
|
|
|
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)
|
|
|
```
|
|
|
|
|
|
```output
|
|
|
(1412, 1) (44, 1)
|
|
|
```
|
|
|
|
|
|
Създадохте SVR! Сега трябва да го оцените.
|
|
|
|
|
|
### Оценка на модела [^1]
|
|
|
|
|
|
За оценка първо ще скалираме обратно данните към оригиналната скала. След това, за да проверим представянето, ще начертаем графика на оригиналните и прогнозирани времеви серии и ще отпечатаме резултата от MAPE.
|
|
|
|
|
|
Скалирайте обратно прогнозните и оригиналните изходи:
|
|
|
|
|
|
```python
|
|
|
# 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))
|
|
|
```
|
|
|
|
|
|
```python
|
|
|
# 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``` стойности като вход за първия изход, така че времевите марки за изхода ще започнат след това.
|
|
|
|
|
|
```python
|
|
|
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))
|
|
|
```
|
|
|
|
|
|
```output
|
|
|
1412 44
|
|
|
```
|
|
|
|
|
|
Начертайте прогнозите за тренировъчни данни:
|
|
|
|
|
|
```python
|
|
|
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 за тренировъчни данни
|
|
|
|
|
|
```python
|
|
|
print('MAPE for training data: ', mape(y_train_pred, y_train)*100, '%')
|
|
|
```
|
|
|
|
|
|
```output
|
|
|
MAPE for training data: 1.7195710200875551 %
|
|
|
```
|
|
|
|
|
|
Начертайте прогнозите за тестови данни
|
|
|
|
|
|
```python
|
|
|
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 за тестови данни
|
|
|
|
|
|
```python
|
|
|
print('MAPE for testing data: ', mape(y_test_pred, y_test)*100, '%')
|
|
|
```
|
|
|
|
|
|
```output
|
|
|
MAPE for testing data: 1.2623790187854018 %
|
|
|
```
|
|
|
|
|
|
🏆 Имате много добър резултат върху тестовия набор от данни!
|
|
|
|
|
|
### Проверка на представянето на модела върху целия набор от данни [^1]
|
|
|
|
|
|
```python
|
|
|
# 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)
|
|
|
```
|
|
|
|
|
|
```output
|
|
|
Tensor shape: (26300, 5)
|
|
|
X shape: (26300, 4)
|
|
|
Y shape: (26300, 1)
|
|
|
```
|
|
|
|
|
|
```python
|
|
|
# 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)
|
|
|
```
|
|
|
|
|
|
```python
|
|
|
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()
|
|
|
```
|
|
|
|
|
|

|
|
|
|
|
|
```python
|
|
|
print('MAPE: ', mape(Y_pred, Y)*100, '%')
|
|
|
```
|
|
|
|
|
|
```output
|
|
|
MAPE: 2.0572089029888656 %
|
|
|
```
|
|
|
|
|
|
🏆 Много хубави графики, показващи модел с добра точност. Браво!
|
|
|
|
|
|
---
|
|
|
|
|
|
## 🚀Предизвикателство
|
|
|
|
|
|
- Опитайте да промените хиперпараметрите (gamma, C, epsilon) при създаването на модела и оценете данните, за да видите кой набор от хиперпараметри дава най-добри резултати върху тестовия набор от данни. За повече информация относно тези хиперпараметри можете да се обърнете към документа [тук](https://scikit-learn.org/stable/modules/svm.html#parameters-of-the-rbf-kernel).
|
|
|
- Опитайте да използвате различни функции на kernel за модела и анализирайте тяхното представяне върху набора от данни. Полезен документ можете да намерите [тук](https://scikit-learn.org/stable/modules/svm.html#kernel-functions).
|
|
|
- Опитайте да използвате различни стойности за `timesteps`, за да накарате модела да се върне назад и да направи прогноза.
|
|
|
|
|
|
## [Тест след лекцията](https://ff-quizzes.netlify.app/en/ml/)
|
|
|
|
|
|
## Преглед и самостоятелно обучение
|
|
|
|
|
|
Този урок беше за въвеждане на приложението на SVR за прогнозиране на времеви серии. За повече информация относно SVR можете да се обърнете към [този блог](https://www.analyticsvidhya.com/blog/2020/03/support-vector-regression-tutorial-for-machine-learning/). Тази [документация за scikit-learn](https://scikit-learn.org/stable/modules/svm.html) предоставя по-изчерпателно обяснение за SVM като цяло, [SVRs](https://scikit-learn.org/stable/modules/svm.html#regression) и също така други детайли за имплементация, като различните [функции на kernel](https://scikit-learn.org/stable/modules/svm.html#kernel-functions), които могат да бъдат използвани, и техните параметри.
|
|
|
|
|
|
## Задача
|
|
|
|
|
|
[Нов SVR модел](assignment.md)
|
|
|
|
|
|
## Благодарности
|
|
|
|
|
|
[^1]: Текстът, кодът и резултатите в този раздел са предоставени от [@AnirbanMukherjeeXD](https://github.com/AnirbanMukherjeeXD)
|
|
|
[^2]: Текстът, кодът и резултатите в този раздел са взети от [ARIMA](https://github.com/microsoft/ML-For-Beginners/tree/main/7-TimeSeries/2-ARIMA)
|
|
|
|
|
|
---
|
|
|
|
|
|
**Отказ от отговорност**:
|
|
|
Този документ е преведен с помощта на AI услуга за превод [Co-op Translator](https://github.com/Azure/co-op-translator). Въпреки че се стремим към точност, моля, имайте предвид, че автоматизираните преводи може да съдържат грешки или неточности. Оригиналният документ на неговия роден език трябва да се счита за авторитетен източник. За критична информация се препоръчва професионален човешки превод. Ние не носим отговорност за недоразумения или погрешни интерпретации, произтичащи от използването на този превод. |