到目前为止,我们的建模工作仅限于单个时间序列。 RNN 自然非常适合多变量时间序列,并且也是我们在时间序列模型中介绍的向量自回归 (VAR) 模型的非线性替代方案。
导入各类包
import warnings
warnings.filterwarnings('ignore')
%matplotlib inline
from pathlib import Path
import numpy as np
import pandas as pd
import pandas_datareader.data as web
from sklearn.metrics import mean_absolute_error
from sklearn.preprocessing import minmax_scale
import tensorflow as tf
from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping
from tensorflow.keras.models import Sequential, Model
from tensorflow.keras.layers import Dense, LSTM
import tensorflow.keras.backend as K
import matplotlib.pyplot as plt
import seaborn as sns
gpu_devices = tf.config.experimental.list_physical_devices('GPU')
if gpu_devices:
print('Using GPU')
tf.config.experimental.set_memory_growth(gpu_devices[0], True)
else:
print('Using CPU')
sns.set_style('whitegrid')
np.random.seed(42)
results_path = Path('results', 'multivariate_time_series')
if not results_path.exists():
results_path.mkdir(parents=True)
加载数据
为了进行比较,使用我们用于 VAR 示例的相同数据集、消费者情绪的月度数据以及来自美联储 FRED 服务的工业生产。
df = web.DataReader(['UMCSENT', 'IPGMFN'], 'fred', '1980', '2019-12').dropna()
df.columns = ['sentiment', 'ip']#两列分别是sentiment和ip
df.info()
df.head()#导出第8章的数据。
准备数据
平稳性:我们使用先验对数变换来实现我们在第 8 章时间序列模型中使用的平稳性要求:
df_transformed = (pd.DataFrame({'ip': np.log(df.ip).diff(12),#对数变换
'sentiment': df.sentiment.diff(12)})
.dropna())#删除缺失值
缩放:然后我们将转换后的数据缩放到 [0,1] 区间:
df_transformed = df_transformed.apply(minmax_scale)
绘制原始序列和转换后序列的图
fig, axes = plt.subplots(ncols=2, figsize=(14,4))
columns={'ip': 'Industrial Production', 'sentiment': 'Sentiment'}
df.rename(columns=columns).plot(ax=axes[0], title='Original Series')
df_transformed.rename(columns=columns).plot(ax=axes[1], title='Tansformed Series')
sns.despine()
fig.tight_layout()
fig.savefig(results_path / 'multi_rnn', dpi=300)
原始数据序列和转换后数据序列如下图:
将数据重塑为 RNN 格式
我们可以直接重塑以获得不重叠的序列,即把每年的数据作为一个样本(仅当样本数可被窗口大小整除时才有效):
df.values.reshape(-1, 12, 2).shape#reshape在这里指的是可以直接转化成两列
但是,我们想要动态而不是非重叠的滞后值。 create_multivariate_rnn_data 函数将多个时间序列的数据集转换为 Keras RNN 层所需的大小,即 n_samples x window_size x n_series。
def create_multivariate_rnn_data(data, window_size):
y = data[window_size:]
n = data.shape[0]
X = np.stack([data[i: j]
for i, j in enumerate(range(window_size, n))], axis=0)
return X, y
我们将使用 24 个月的 window_size 并为我们的 RNN 模型获取所需的输入。
window_size = 18
X, y = create_multivariate_rnn_data(df_transformed, window_size=window_size)
X.shape, y.shape#x,y都是经过RNN转化后的数据。输出x,y的大小
((450, 18, 2), (450, 2))
最后ÿ