时间序列预测中的支持向量回归器


文档摘要

时间序列预测中的支持向量回归器 在上一课中,你学习了如何使用ARIMA模型进行时间序列预测。现在,我们将研究一种用于预测连续数据的回归模型——支持向量回归器(SVR)。 课前测验 简介 在本课程中,你将发现如何使用[SVM:Support Vector Machine](https://zh.wikipedia.org/wiki/支持向量机)来构建回归模型,即SVR:支持向量回归器。 SVR 在时间序列中的应用 [^1] 在理解SVR在时间序列预测中的重要性之前,这里有一些你需要了解的重要概念: 回归:监督学习技术,用于根据给定的一组输入预测连续值。其想法是在特征空间中拟合一条曲线(或直线),使其包含尽可能多的数据点。点击此处了解更多。

时间序列预测中的支持向量回归器

在上一课中,你学习了如何使用ARIMA模型进行时间序列预测。现在,我们将研究一种用于预测连续数据的回归模型——支持向量回归器(SVR)。

课前测验

简介

在本课程中,你将发现如何使用[SVMSupport Vector Machine](https://zh.wikipedia.org/wiki/支持向量机)来构建回归模型,即SVR:支持向量回归器。

SVR 在时间序列中的应用 1

在理解SVR在时间序列预测中的重要性之前,这里有一些你需要了解的重要概念:

  • 回归:监督学习技术,用于根据给定的一组输入预测连续值。其想法是在特征空间中拟合一条曲线(或直线),使其包含尽可能多的数据点。点击此处了解更多。
  • 支持向量机(SVM):一种用于分类、回归和异常检测的监督机器学习模型。该模型是一个特征空间中的超平面,在分类任务中充当边界,在回归任务中充当最佳拟合线。在SVM中,通常使用核函数将数据集转换到更高维度的空间,以便它们可以更容易地分离。点击此处了解更多关于SVM的信息。
  • 支持向量回归器(SVR):一种SVM,用于找到包含最多数据点的最佳拟合线(在SVM中是一条超平面)。

为什么选择SVR? 1

在上一课中,你学习了ARIMA,这是一种非常成功的统计线性方法,用于预测时间序列数据。然而,在许多情况下,时间序列数据具有非线性特性,这不能被线性模型映射。在这种情况下,SVM考虑数据中的非线性能力使SVR在时间序列预测中表现出色。

练习 - 构建一个SVR模型

数据准备的第一步与上一课中的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. 运行笔记本并导入必要的库: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
  2. /data/energy.csv文件中的数据加载到Pandas数据框中并查看:2

    energy = load_data('../../data')[['load']]
  3. 绘制从2012年1月到2014年12月的所有可用能源数据: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是必需的。你将在训练集上训练模型。在模型训练完成后,你需要在训练集、测试集以及整个数据集上评估其准确性,以查看整体性能。你需要确保测试集覆盖的时间段晚于训练集,以确保模型不会从未来的时间段获取信息(这种情况称为过拟合)。

  1. 分配一个时间段,即2014年9月1日至2014年10月31日作为训练集。测试集将包括2014年11月1日至2014年12月31日的时间段:2

    train_start_dt = '2014-11-01 00:00:00' test_start_dt = '2014-12-30 00:00:00'
  2. 可视化差异: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。

  1. 过滤原始数据集,仅包括指定时间段的数据,并只包括所需的“负载”列加上日期: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)
  2. 缩放训练数据,使其范围在(0, 1)之间:2

    scaler = MinMaxScaler() train['load'] = scaler.fit_transform(train)
  3. 现在,你将缩放测试数据:2

    test['load'] = scaler.transform(test)

使用时间步长创建数据 1

对于SVR,你将输入数据转换为形式 [batch, timesteps]. So, you reshape the existing train_data and test_data,这样就会有一个新的维度,表示时间步长。

# Converting to numpy arrays train_data = train.values test_data = test.values

在这个例子中,我们取 timesteps = 5。因此,模型的输入是前4个时间步的数据,输出将是第5个时间步的数据。

timesteps=5

使用嵌套列表推导式将训练数据转换为二维张量:

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)

将测试数据转换为二维张量:

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了。要了解更多信息,可以参考此文档。对于我们的实现,我们遵循以下步骤:

  1. 通过调用 `SVR()`` and passing in the model hyperparameters: kernel, gamma, c and epsilon
  2. Prepare the model for the training data by calling the fit() function
  3. Make predictions calling the predict() 函数定义模型

现在我们创建一个SVR模型。在这里,我们使用RBF核,并将超参数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和不同核函数及其参数的解释。

作业

一个新的SVR模型

致谢

声明:
本文件灏天文库团队进行了翻译。尽管我们力求准确,但请注意,翻译可能包含错误或不准确之处。原文档以其原始语言为准。我们不对因使用此翻译而产生的任何误解或误译负责。

  1. 本节中的文本、代码和输出由@AnirbanMukherjeeXD贡献

  2. 本节中的文本、代码和输出来自ARIMA


发布者: 作者: 转发
评论区 (0)
U