当前位置:   article > 正文

Python数据分析案例26——时间序列的多阶段预测(GRU+RVM)_python 时间序列建模预测案例

python 时间序列建模预测案例

 本篇案例适合理工科硕士。


承接上两篇硬核案例:Python数据分析案例25——海上风力发电预测(多变量循环神经网络)

 之前都是直接预测,即用前面的数据——之前的X和之前的y直接预测未来的y。

本章介绍一个多阶段的预测方法,即先先使用机器学习的方法将X和y的映射关系找到。然后使用循环神经网络用之前的X预测未来的X,得到未来的X之后再用前面训练好的机器学习模型预测未来的y。称为多阶段的预测方法。

数据来源,同样使用上一篇的海上风电数据集,可以对比效果。

机器学习模型采用RVM,相关向量机,同样也是学术界很喜欢的方法,回归问题上表现还不错。

需要这代码演示数据的同学可以参考:数据


代码准备

导入包和定义RVM类:

  1. import os
  2. import math
  3. import time
  4. import datetime
  5. import random as rn
  6. import numpy as np
  7. import pandas as pd
  8. import matplotlib.pyplot as plt
  9. %matplotlib inline
  10. plt.rcParams ['font.sans-serif'] ='SimHei' #显示中文
  11. plt.rcParams ['axes.unicode_minus']=False #显示负号
  12. from sklearn.model_selection import train_test_split
  13. from sklearn.preprocessing import MinMaxScaler,StandardScaler
  14. from sklearn.metrics import mean_absolute_error
  15. from sklearn.metrics import mean_squared_error,r2_score
  16. import tensorflow as tf
  17. import keras
  18. from keras.models import Model, Sequential
  19. from keras.layers import GRU, Dense,Conv1D, MaxPooling1D,GlobalMaxPooling1D,Embedding,Dropout,Flatten,SimpleRNN,LSTM
  20. from keras.callbacks import EarlyStopping
  21. #from tensorflow.keras import regularizers
  22. #from keras.utils.np_utils import to_categorical
  23. from tensorflow.keras import optimizers

RVM

  1. """Relevance Vector Machine classes for regression and classification."""
  2. from scipy.optimize import minimize
  3. from scipy.special import expit
  4. from sklearn.base import BaseEstimator, RegressorMixin, ClassifierMixin
  5. from sklearn.metrics.pairwise import (
  6. linear_kernel,
  7. rbf_kernel,
  8. polynomial_kernel
  9. )
  10. from sklearn.multiclass import OneVsOneClassifier
  11. from sklearn.utils.validation import check_X_y
  12. class BaseRVM(BaseEstimator):
  13. """Base Relevance Vector Machine class.
  14. Implementation of Mike Tipping's Relevance Vector Machine using the
  15. scikit-learn API. Add a posterior over weights method and a predict
  16. in subclass to use for classification or regression.
  17. """
  18. def __init__(
  19. self,
  20. kernel='rbf',
  21. degree=3,
  22. coef1=None,
  23. coef0=0.0,
  24. n_iter=3000,
  25. tol=1e-3,
  26. alpha=1e-6,
  27. threshold_alpha=1e9,
  28. beta=1.e-6,
  29. beta_fixed=False,
  30. bias_used=True,
  31. verbose=False
  32. ):
  33. """Copy params to object properties, no validation."""
  34. self.kernel = kernel
  35. self.degree = degree
  36. self.coef1 = coef1
  37. self.coef0 = coef0
  38. self.n_iter = n_iter
  39. self.tol = tol
  40. self.alpha = alpha
  41. self.threshold_alpha = threshold_alpha
  42. self.beta = beta
  43. self.beta_fixed = beta_fixed
  44. self.bias_used = bias_used
  45. self.verbose = verbose
  46. def get_params(self, deep=True):
  47. """Return parameters as a dictionary."""
  48. params = {
  49. 'kernel': self.kernel,
  50. 'degree': self.degree,
  51. 'coef1': self.coef1,
  52. 'coef0': self.coef0,
  53. 'n_iter': self.n_iter,
  54. 'tol': self.tol,
  55. 'alpha': self.alpha,
  56. 'threshold_alpha': self.threshold_alpha,
  57. 'beta': self.beta,
  58. 'beta_fixed': self.beta_fixed,
  59. 'bias_used': self.bias_used,
  60. 'verbose': self.verbose
  61. }
  62. return params
  63. def set_params(self, **parameters):
  64. """Set parameters using kwargs."""
  65. for parameter, value in parameters.items():
  66. setattr(self, parameter, value)
  67. return self
  68. def _apply_kernel(self, x, y):
  69. """Apply the selected kernel function to the data."""
  70. if self.kernel == 'linear':
  71. phi = linear_kernel(x, y)
  72. elif self.kernel == 'rbf':
  73. phi = rbf_kernel(x, y, self.coef1)
  74. elif self.kernel == 'poly':
  75. phi = polynomial_kernel(x, y, self.degree, self.coef1, self.coef0)
  76. elif callable(self.kernel):
  77. phi = self.kernel(x, y)
  78. if len(phi.shape) != 2:
  79. raise ValueError(
  80. "Custom kernel function did not return 2D matrix"
  81. )
  82. if phi.shape[0] != x.shape[0]:
  83. raise ValueError(
  84. "Custom kernel function did not return matrix with rows"
  85. " equal to number of data points."""
  86. )
  87. else:
  88. raise ValueError("Kernel selection is invalid.")
  89. if self.bias_used:
  90. phi = np.append(phi, np.ones((phi.shape[0], 1)), axis=1)
  91. return phi
  92. def _prune(self):
  93. """Remove basis functions based on alpha values."""
  94. keep_alpha = self.alpha_ < self.threshold_alpha
  95. if not np.any(keep_alpha):
  96. keep_alpha[0] = True
  97. if self.bias_used:
  98. keep_alpha[-1] = True
  99. if self.bias_used:
  100. if not keep_alpha[-1]:
  101. self.bias_used = False
  102. self.relevance_ = self.relevance_[keep_alpha[:-1]]
  103. else:
  104. self.relevance_ = self.relevance_[keep_alpha]
  105. self.alpha_ = self.alpha_[keep_alpha]
  106. self.alpha_old = self.alpha_old[keep_alpha]
  107. self.gamma = self.gamma[keep_alpha]
  108. self.phi = self.phi[:, keep_alpha]
  109. self.sigma_ = self.sigma_[np.ix_(keep_alpha, keep_alpha)]
  110. self.m_ = self.m_[keep_alpha]
  111. def fit(self, X, y):
  112. """Fit the RVR to the training data."""
  113. X, y = check_X_y(X, y)
  114. n_samples, n_features = X.shape
  115. self.phi = self._apply_kernel(X, X)
  116. n_basis_functions = self.phi.shape[1]
  117. self.relevance_ = X
  118. self.y = y
  119. self.alpha_ = self.alpha * np.ones(n_basis_functions)
  120. self.beta_ = self.beta
  121. self.m_ = np.zeros(n_basis_functions)
  122. self.alpha_old = self.alpha_
  123. for i in range(self.n_iter):
  124. self._posterior()
  125. self.gamma = 1 - self.alpha_*np.diag(self.sigma_)
  126. self.alpha_ = self.gamma/(self.m_ ** 2)
  127. if not self.beta_fixed:
  128. self.beta_ = (n_samples - np.sum(self.gamma))/(
  129. np.sum((y - np.dot(self.phi, self.m_)) ** 2))
  130. self._prune()
  131. if self.verbose:
  132. print("Iteration: {}".format(i))
  133. print("Alpha: {}".format(self.alpha_))
  134. print("Beta: {}".format(self.beta_))
  135. print("Gamma: {}".format(self.gamma))
  136. print("m: {}".format(self.m_))
  137. print("Relevance Vectors: {}".format(self.relevance_.shape[0]))
  138. print()
  139. delta = np.amax(np.absolute(self.alpha_ - self.alpha_old))
  140. if delta < self.tol and i > 1:
  141. break
  142. self.alpha_old = self.alpha_
  143. if self.bias_used:
  144. self.bias = self.m_[-1]
  145. else:
  146. self.bias = None
  147. return self
  148. class RVR(BaseRVM, RegressorMixin):
  149. """Relevance Vector Machine Regression.
  150. Implementation of Mike Tipping's Relevance Vector Machine for regression
  151. using the scikit-learn API.
  152. """
  153. def _posterior(self):
  154. """Compute the posterior distriubtion over weights."""
  155. i_s = np.diag(self.alpha_) + self.beta_ * np.dot(self.phi.T, self.phi)
  156. self.sigma_ = np.linalg.inv(i_s)
  157. self.m_ = self.beta_ * np.dot(self.sigma_, np.dot(self.phi.T, self.y))
  158. def predict(self, X, eval_MSE=False):
  159. """Evaluate the RVR model at x."""
  160. phi = self._apply_kernel(X, self.relevance_)
  161. y = np.dot(phi, self.m_)
  162. if eval_MSE:
  163. MSE = (1/self.beta_) + np.dot(phi, np.dot(self.sigma_, phi.T))
  164. return y, MSE[:, 0]
  165. else:
  166. return y


准备数据

读取数据

  1. data0=pd.read_excel('5.xlsx').iloc[:1000,:].set_index('Sequence No.').rename(columns={'y (% relative to rated power)':'y'})
  2. data0.head()

取出X和y,标准化:

  1. X=data0.iloc[:,:-1] ; y=data0.iloc[:,-1]
  2. scaler_s = StandardScaler()
  3. scaler_s.fit(X)
  4. X_s = scaler_s.transform(X)

 拟合RVM模型,下面使用了三种不同核函数的RVM。

  1. #构建RVM模型
  2. rvm_model_linear = RVR(kernel="linear")
  3. rvm_model_linear.fit(X_s, y)
  4. print(rvm_model_linear.score(X_s, y))
  5. rvm_model_rbf = RVR(kernel="rbf")
  6. rvm_model_rbf.fit(X_s, y)
  7. print(rvm_model_rbf.score(X_s, y))
  8. rvm_model_poly = RVR(kernel="poly")
  9. rvm_model_poly.fit(X_s, y)
  10. print(rvm_model_poly.score(X_s, y))

可以看到RBF核表现效果最好,后面默认使用RBF核的RVM。


深度学习准备 

定义一些函数,固定随机数种子,回归问题评价指标函数

  1. def set_my_seed():
  2. os.environ['PYTHONHASHSEED'] = '0'
  3. np.random.seed(1)
  4. rn.seed(12345)
  5. tf.random.set_seed(123)
  6. def evaluation(y_test, y_predict):
  7. mae = mean_absolute_error(y_test, y_predict)
  8. mse = mean_squared_error(y_test, y_predict)
  9. rmse = np.sqrt(mean_squared_error(y_test, y_predict))
  10. mape=(abs(y_predict -y_test)/ y_test).mean()
  11. r_2=r2_score(y_test, y_predict)
  12. return mae, rmse, mape,r_2 #mse

定义构建训练集和测试集的数据函数:

  1. def build_sequences(text, window_size=24):
  2. #text:list of capacity
  3. x, y = [],[]
  4. for i in range(len(text) - window_size):
  5. sequence = text[i:i+window_size]
  6. target = text[i+window_size]
  7. x.append(sequence)
  8. y.append(target)
  9. return np.array(x), np.array(y)
  10. def get_traintest(data,train_size=len(data0),window_size=24):
  11. train=data[:train_size]
  12. test=data[train_size-window_size:]
  13. X_train,y_train=build_sequences(train,window_size=window_size)
  14. X_test,y_test=build_sequences(test,window_size=window_size)
  15. return X_train,y_train,X_test,y_test

定义模型函数(5种神经网络模型),还有画损失图和拟合图对比的函数。

  1. def build_model(X_train,mode='LSTM',hidden_dim=[32,16]):
  2. set_my_seed()
  3. model = Sequential()
  4. if mode=='RNN':
  5. #RNN
  6. model.add(SimpleRNN(hidden_dim[0],return_sequences=True, input_shape=(X_train.shape[-2],X_train.shape[-1])))
  7. model.add(SimpleRNN(hidden_dim[1]))
  8. elif mode=='MLP':
  9. model.add(Dense(hidden_dim[0],activation='relu',input_shape=(X_train.shape[-1],)))
  10. model.add(Dense(hidden_dim[1],activation='relu'))
  11. elif mode=='LSTM':
  12. # LSTM
  13. model.add(LSTM(hidden_dim[0],return_sequences=True, input_shape=(X_train.shape[-2],X_train.shape[-1])))
  14. model.add(LSTM(hidden_dim[1]))
  15. elif mode=='GRU':
  16. #GRU
  17. model.add(GRU(hidden_dim[0],return_sequences=True, input_shape=(X_train.shape[-2],X_train.shape[-1])))
  18. model.add(GRU(hidden_dim[1]))
  19. elif mode=='CNN':
  20. #一维卷积
  21. model.add(Conv1D(hidden_dim[0], kernel_size=3, padding='causal', strides=1, activation='relu', dilation_rate=1, input_shape=(X_train.shape[-2],X_train.shape[-1])))
  22. #model.add(MaxPooling1D())
  23. model.add(Conv1D(hidden_dim[0], kernel_size=3, padding='causal', strides=1, activation='relu', dilation_rate=2))
  24. #model.add(MaxPooling1D())
  25. model.add(Conv1D(hidden_dim[0], kernel_size=3, padding='causal', strides=1, activation='relu', dilation_rate=4))
  26. #GlobalMaxPooling1D()
  27. model.add(Flatten())
  28. model.add(Dense(1))
  29. model.compile(optimizer='Adam', loss='mse',metrics=[tf.keras.metrics.RootMeanSquaredError(),"mape","mae"])
  30. return model
  31. def plot_loss(hist,imfname):
  32. plt.subplots(1,4,figsize=(16,2))
  33. for i,key in enumerate(hist.history.keys()):
  34. n=int(str('14')+str(i+1))
  35. plt.subplot(n)
  36. plt.plot(hist.history[key], 'k', label=f'Training {key}')
  37. plt.title(f'{imfname} Training {key}')
  38. plt.xlabel('Epochs')
  39. plt.ylabel(key)
  40. plt.legend()
  41. plt.tight_layout()
  42. plt.show()
  43. def plot_fit(y_test, y_pred,name):
  44. plt.figure(figsize=(4,2))
  45. plt.plot(y_test, color="red", label="actual")
  46. plt.plot(y_pred, color="blue", label="predict")
  47. plt.title(f"{name}拟合值和真实值对比")
  48. plt.xlabel("Time")
  49. plt.ylabel(name)
  50. plt.legend()
  51. plt.show()

定义训练函数:

  1. df_eval_all=pd.DataFrame(columns=['MAE','RMSE','MAPE','R2'])
  2. df_preds_all=pd.DataFrame()
  3. def train_fuc(mode='LSTM',window_size=64,batch_size=32,epochs=50,hidden_dim=[32,16],train_ratio=0.8,kernel="rbf",show_loss=True,show_fit=True):
  4. df_preds=pd.DataFrame()
  5. #预测每一列
  6. for i,col_name in enumerate(data0.columns):
  7. print(f'正在处理变量:{col_name}')
  8. #准备数据
  9. data=data0[col_name]
  10. train_size=int(len(data)*train_ratio)
  11. X_train,y_train,X_test,y_test=get_traintest(data.values,window_size=window_size,train_size=train_size)
  12. #print(X_train.shape,y_train.shape,X_test.shape,y_test.shape)
  13. #归一化
  14. scaler = MinMaxScaler()
  15. scaler = scaler.fit(X_train)
  16. X_train=scaler.transform(X_train) ; X_test=scaler.transform(X_test)
  17. y_train_orage=y_train.copy() ; y_scaler = MinMaxScaler()
  18. y_scaler = y_scaler.fit(y_train.reshape(-1,1))
  19. y_train=y_scaler.transform(y_train.reshape(-1,1))
  20. if mode!='MLP':
  21. X_train = X_train.reshape((X_train.shape[0], X_train.shape[1], 1))
  22. #构建模型
  23. s = time.time()
  24. set_my_seed()
  25. model=build_model(X_train=X_train,mode=mode,hidden_dim=hidden_dim)
  26. earlystop = EarlyStopping(monitor='loss', min_delta=0, patience=5)
  27. hist=model.fit(X_train, y_train,batch_size=batch_size,epochs=epochs,callbacks=[earlystop],verbose=0)
  28. if show_loss:
  29. plot_loss(hist,col_name)
  30. #预测
  31. y_pred = model.predict(X_test)
  32. y_pred = y_scaler.inverse_transform(y_pred)
  33. #print(f'真实y的形状:{y_test.shape},预测y的形状:{y_pred.shape}')
  34. if show_fit:
  35. plot_fit(y_test, y_pred,name=col_name)
  36. e=time.time()
  37. print(f"运行时间为{round(e-s,3)}")
  38. df_preds[col_name]=y_pred.reshape(-1,)
  39. s=list(evaluation(y_test, y_pred))
  40. s=[round(i,3) for i in s]
  41. print(f'{col_name}变量的预测效果为:MAE:{s[0]},RMSE:{s[1]},MAPE:{s[2]},R2:{s[3]}')
  42. print("=================================================================================")
  43. X_pred=df_preds.iloc[:,:-1]
  44. X_pred_s = scaler_s.transform(X_pred)
  45. y_direct=df_preds.iloc[:,-1]
  46. if kernel=="rbf":
  47. y_nodirect=rvm_model_rbf.predict(X_pred_s)
  48. if kernel=="linear":
  49. y_nodirect=rvm_model_linear.predict(X_pred_s)
  50. if kernel=="ploy":
  51. y_nodirect=rvm_model_ploy.predict(X_pred_s)
  52. score1=list(evaluation(y_test, y_direct))
  53. score2=list(evaluation(y_test, y_nodirect))
  54. df_preds_all[mode]=y_direct
  55. df_preds_all[f'{mode}+RVM']=y_nodirect
  56. df_eval_all.loc[f'{mode}',:]=score1
  57. df_eval_all.loc[f'{mode}+RVM',:]=score2
  58. print(score2)


开始训练

初始化超参数

  1. window_size=64
  2. batch_size=32
  3. epochs=50
  4. hidden_dim=[32,16]
  5. train_ratio=0.8
  6. kernel="rbf"
  7. show_fit=True
  8. show_loss=True
  9. mode='LSTM' #RNN,GRU,CNN

LSTM预测

  1. mode='LSTM'
  2. set_my_seed()
  3. train_fuc(mode=mode,window_size=window_size,batch_size=batch_size,epochs=epochs,hidden_dim=hidden_dim)

  结果有点长,因为是每个X都是要经过一次循环神经网络预测的,最后再使用RVM结合一起预测y。可以看到最后的预测效果是0.95%。还行,但是直接用y自己预测自己拟合优度有97.5%。说明这种多阶段的方法不如直接预测。


RNN

不同的模型改mode参数就行

  1. mode='RNN'
  2. set_my_seed()
  3. train_fuc(mode=mode,window_size=window_size,batch_size=32,epochs=epochs,hidden_dim=hidden_dim)

RNN太慢了我这里就没运行。 


GRU

  1. mode='GRU'
  2. set_my_seed()
  3. train_fuc(mode=mode,window_size=window_size,batch_size=batch_size,epochs=epochs,hidden_dim=hidden_dim)

就不截那么长的图了,看最后的结果图

直接预测98%,多阶段96.6%。


CNN 

  1. mode='CNN'
  2. set_my_seed()
  3. train_fuc(mode=mode,window_size=window_size,batch_size=batch_size,epochs=epochs,hidden_dim=hidden_dim)


MLP

  1. mode='MLP'
  2. set_my_seed()
  3. train_fuc(mode=mode,window_size=window_size,batch_size=batch_size,epochs=60,hidden_dim=hidden_dim)


结论

查看所有模型的对比:

df_eval_all

可以看到,加了RVM的多阶段预测基本表现都没直接预测的好, GRU和LSTM模型表现还是最好的。加了RVM准确率都下降了,这也是自然,你非要多塞一个方法进去,你的X就不是真实的X,X就有误差了,预测的y的误差自然就大一些。

也不知道为什么那么多论文为什么说这样多阶段的预测效果好,说自己做的多阶段模型比直接预测效果好。。。为了缝合模型显得有创新,然后都在乱编预测结果。。。其实很多时候都是一顿操作猛如虎,模型一顿缝合,论文看起来很有创新性,但是效果是越搞越差.....但是为了表现自己模型效果好就狂调参。。。学术界这个现象得管管了。


创作不易,看官觉得写得还不错的话点个关注和赞吧,本人会持续更新python数据分析领域的代码文章~(需要定制代码可私信)

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号