• 时间序列预测步骤I am a strong believer in “learning by doing” philosophy. 我坚信“做中学”哲学。 Data science is an applied field, so you need to get your feet wet to learn something. One can ...
时间序列预测步骤I am a strong believer in “learning by doing” philosophy. 我坚信“做中学”的哲学。
Data science is an applied field, so you need to get your feet wet to learn something. One can read all the “how to” tutorials on swimming, but at some point, they do have to test the water. 数据科学是一个应用领域，因此您需要专心学习。 人们可以阅读所有有关游泳的“入门指南”，但是在某些时候，他们确实必须测试水。
Beginners in data science often get caught into the impression that they have to learn everything under the sun before they can do a project. Wrong! I believe people can learn faster not by reading stuff but by doing small bits and pieces of projects. 数据科学的初学者常常会陷入一种印象，即他们必须在阳光下学习一切，然后才能进行项目。 错误！   我相信人们可以通过阅读一些零碎的项目而不是阅读东西来更快地学习。
In this article I want you to learn how to fit a time series forecasting model ARIMA — which, for many, is an intimidating algorithm. In this article, you will learn it in just 5 easy steps and make real forecasts. You are not going to build a Ferrari, but I’m sure you will learn to build a car that you can take to the streets. 在本文中，我希望您学习如何拟合时间序列预测模型ARIMA-对许多人来说，这是一个令人生畏的算法。 在本文中，您将仅需5个简单的步骤就可以学习它并做出真实的预测。 您不会制造法拉利，但是我敢肯定，您将学到制造可以上街的汽车。
Let’s roll the sleeves. 让我们卷起袖子。
步骤1：资料准备 (Step 1: Data preparation)
For this demo, we are going to use a forecasting package calledfpp2 in R programming environment. Let’s load that package. 对于此演示，我们将在R编程环境中使用称为fpp2的预测包。 让我们加载该程序包。
# Required packageslibrary(fpp2)I’ve got some data that I extracted from an actual time series. The following are the values, let’s copy them in the R script as well. 我有一些从实际时间序列中提取的数据。 以下是值，我们也将它们复制到R脚本中。
# your datavalues = c(92.1,  92.6,  89.5,  80.9,  95.6,  72.5,  71.2,  78.8,  73.8,  83.5,  97.9, 93.4,  98.0,  90.2,  96.7, 100.0, 103.6,  74.6,  78.9,  92.0,  83.4,  98.1, 109.9, 102.2, 102.1,  96.2, 106.9,  95.1, 113.4,  84.0,  88.6,  94.9,  94.7, 105.7, 108.6, 101.9,  113.9, 100.9, 100.2,  91.9,  99.6,  87.2,  92.1, 104.9, 103.4, 103.3, 103.9, 108.5)Like every other modeling software, this package has a specific data formatting requirement. The ts() function takes care of it by converting data into a time series object. 与其他所有建模软件一样，此软件包也有特定的数据格式要求。 ts()函数通过将数据转换为时间序列对象来进行处理。
In this function we specify the starting year (2015) and 12-month frequency. 在此函数中，我们指定开始年份(2015)和12个月的频率。
# your time seriestime_series = ts(values, start = 2015, frequency =12) 步骤2：时间序列分解 (Step 2: Time series decomposition)
Decomposition basically means deconstructing and visualizing the series into its component parts. 分解基本上意味着将系列分解和可视化为其组成部分。
# time series decompositionautoplot(decompose(time_series)) + theme(plot.title = element_text(size=8))This figure below displays 4 pieces of information: your data (top one), overall trend and seasonality. The final piece is called the remainder or the random part. 下图显示了4条信息：您的数据(第一数据)，总体趋势和季节性。 最后的部分称为余数或随机部分。
Time series decomposition 时间序列分解  步骤3：建模 (Step 3: Modeling)
The actual model building is a simple 2-lines code using auto.arima() function. auto.arima will take care of the optimum parameter values, you just need to specify a few boolean parameters. 实际的模型构建是使用auto.arima()函数的简单两行代码。 auto.arima将照顾最佳参数值，您只需要指定一些布尔参数即可。
model = auto.arima(time_series, seasonal = TRUE, stepwise = FALSE, approximation = FALSE) 步骤4：预测 (Step 4: Forecasting)
Making an actual forecast is the simplest of all the steps above, just half of a line length code— can you believe? We are using forecast() function and passing the model above and specifying the number of time steps into the future you want to forecast (I specified 30 months ahead) 进行实际的预测是上述所有步骤中最简单的，只是行长代码的一半-您可以相信吗？ 我们正在使用forecast()函数并在上面传递模型，并指定了您要预测的未来时间步长(我指定了30个月)
# making forecastforecast_arima = forecast(model, h=30)You are practically done with forecasting. You can print the forecast values with the print(forecast_arima) function. 预测实际上已经完成。 您可以使用print(forecast_arima)函数打印预测值。
Forecast values 预测值 Or, you may want to visualize the forecast values, the input series and confidence intervals altogether. 或者，您可能希望完全可视化预测值，输入序列和置信区间。
# visualizing forecastautoplot(time_series, series = " Data") +  autolayer(forecast_arima, series = "Forecast") +  ggtitle(" Forecasting with ARIMA") +  theme(plot.title = element_text(size=8))Forecasting with ARIMA 用ARIMA进行预测  步骤5：模型评估 (Step 5: Model evaluation)
This is an extra step for model evaluation and accuracy tests. First, let’s check out model description: 这是模型评估和准确性测试的额外步骤。 首先，让我们检查一下模型描述：
# model descriptionmodel['model']I highlighted few things that you might be interested in: the description of the model (ARIMA(0,1,2(0,1,1)[12]) and AIC values. AIC is often used to compare the performance of two or more models. 我重点介绍了您可能感兴趣的几件事：模型的描述(ARIMA(0,1,2(0,1,1)[12])和AIC值。AIC通常用于比较两个或两个的性能更多型号。
In most machine learning models accuracy is determined based on RMSE or MAE values. Let’s print them as well. 在大多数机器学习模型中，准确性是基于RMSE或MAE值确定的。 让我们也打印它们。
# accuracyaccuracy(model)That is all! 就这些！
下一步 (Next steps)
You have just built and implemented a forecasting model using 5 simple steps. Does that mean you became a master of forecasting? No, but you know the overall structure of the model from beginning to end and able to play with it with different datasets, different parameter values etc. 您刚刚使用5个简单的步骤构建并实施了预测模型。 这是否意味着您成为预测大师？ 不，但是您从头到尾都知道模型的整体结构，并且能够与不同的数据集，不同的参数值等一起使用。
Just like I said in the beginning, you haven’t built a Ferrari but you’ve built a car that you can take to the grocery store! 就像我在开始时说的那样，您还没有制造法拉利，但是您已经制造了可以带到杂货店的汽车！
翻译自: https://towardsdatascience.com/5-simples-steps-to-build-your-time-series-forecasting-model-62356336bc35时间序列预测步骤
展开全文
• ## 时间序列的7种预测模型

万次阅读 多人点赞 2018-12-23 20:02:00
时间序列问题比较常见，比如股市，工业生产指标等。 1 朴素估计 使用最后一个时间点值估测后面一段时间段值。 2 简单平均 4 滑动窗平均 使用之前一定大小时间段平均值作为这个时间点值。 ...
背景
时间序列问题比较常见，比如股市，工业生产指标等。
导入必要的Python包：
from statsmodels.tsa.api import ExponentialSmoothing, \
SimpleExpSmoothing, Holt

import statsmodels.api as sm

1. 朴素估计
$\hat{y}_{\mathrm{t}+1}=\mathrm{y}_{\mathrm{t}}$
使用最后一个时间点的值估测后面一段时间段的值。
dd= np.asarray(train.Count)
y_hat = test.copy()
y_hat['naive'] = dd[len(dd)-1]


2. 简单平均
把历史时刻变量所有值的平均值作为预测值：

y_hat_avg = test.copy()
y_hat_avg['avg_forecast'] = train['Count'].mean()


4. 滑动窗平均
使用之前一定大小时间段的平均值作为这个时间点的值。

或者使用加权的滑动窗平均：
加权的权重可以根据时间来设定，比如越是近的时刻的权重越大。

y_hat_avg = test.copy()
y_hat_avg['moving_avg_forecast'] = train['Count'].rolling(60).mean().iloc[-1]


5. 简单指数平滑
当前时刻的值由历史时刻的值确定，但是根据时刻进行了指数衰减。

where 0≤ α ≤1 是平滑参数.
如果时间序列很长，可以看作：

from statsmodels.tsa.api import ExponentialSmoothing, \
SimpleExpSmoothing, Holt
y_hat_avg = test.copy()
fit2 = SimpleExpSmoothing(np.asarray(train['Count'])).fit(
smoothing_level=0.6,optimized=False)
y_hat_avg['SES'] = fit2.forecast(len(test))

5 Holt’s线性趋势方法

主要考虑趋势。
import statsmodels.api as sm
sm.tsa.seasonal_decompose(train.Count).plot()

7 Holt-winters 方法

这种思想比较简单有效，假设数据服从两点，
1.数据是呈递增、递减趋势的；
2.数据服从一个周期变化。
然后，对残差，再进行其他方式的拟合，比如三次样条曲线。
y_hat_avg = test.copy()
fit1 = ExponentialSmoothing(np.asarray(train['Count']) ,
y_hat_avg['Holt_Winter'] = fit1.forecast(len(test))

8 Arima方法
ARIMA模型（Autoregressive Integrated Moving Average model）整合移动平均自回归模型。
ARIMA（p，d，q）模型：

ARIMA(p, d, q) 由三个部分组成：

AR§：AR是autoregressive的缩写，表示自回归模型，含义是当前时间点的值等于过去若干个时间点的值的回归——因为不依赖于别的解释变量，只依赖于自己过去的历史值，故称为自回归；如果依赖过去最近的p个历史值，称阶数为p，记为AR(p)模型。
I(d)：I是integrated的缩写，含义是模型对时间序列进行了差分；因为时间序列分析要求平稳性，不平稳的序列需要通过一定手段转化为平稳序列，一般采用的手段是差分；d表示差分的阶数，t时刻的值减去t-1时刻的值，得到新的时间序列称为1阶差分序列；1阶差分序列的1阶差分序列称为2阶差分序列，以此类推；另外，还有一种特殊的差分是季节性差分S，即一些时间序列反应出一定的周期T，让t时刻的值减去t-T时刻的值得到季节性差分序列。
MA(q)：MA是moving average的缩写，表示移动平均模型，含义是当前时间点的值等于过去若干个时间点的预测误差的回归；预测误差=模型预测值-真实值；如果序列依赖过去最近的q个历史预测误差值，称阶数为q，记为MA(q)模型。

y_hat_avg = test.copy()
fit1 = sm.tsa.statespace.SARIMAX(train.Count, order=(2, 1,
4),seasonal_order=(0,1,1,7)).fit()
y_hat_avg['SARIMA'] = fit1.predict(start="2013-11-1",
end="2013-12-31", dynamic=True)

9. PROPHET 方法
时间序列的分解（Decomposition of Time Series），它把时间序列 分成几个部分，分别是季节项 ，趋势项 ，剩余项，与Holt-winters方法类似 。
fbprophet的安装依赖Pystan.

最近开通了个公众号，主要分享python原理与应用，推荐系统，风控等算法相关的内容，感兴趣的伙伴可以关注下。

公众号相关的学习资料会上传到QQ群596506387，欢迎关注。

reference：

analytics : Time-series forecast；
知乎 arima详解；
Wiki Arima;
ARIMA模型详解;
Fbprophet 使用官网;


展开全文
• 时间序列预测模型的一般表达式是： xt+1=f(xi),i≤tx_{t+1}=f(x_i),i\le txt+1​=f(xi​),i≤t 本篇内容 移动平均预测 简单移动平均 加权移动平均 指数加权移动平均 ARMA模型预测 AR模型 自回归模型 MA模型 ...
根据上一篇博客中所述，只有时间序列是平稳的，且不是白噪声序列，才有预测的价值
时间序列预测模型的一般表达式是：
$x_{t+1}=f(x_i),i\le t$
本篇内容

移动平均预测

简单移动平均
加权移动平均
指数加权移动平均

ARMA模型预测

AR模型 自回归模型
MA模型 移动平均模型
ARMA 自回归移动平均模型

移动平均预测
最简单的预测方式是以过去数据的平均值进行预测，可以消除一些极端值的干扰，起到平滑的效果。移动平均预测分为：简单移动平均，加权移动平均，指数加权移动平均
简单移动平均
$\hat{x}_{t+1}=\frac{x_t+x_{t-1}+x_{t-2}+...+x_{t-n+1}}{n}$
加权移动平均
$\hat{x}_{t+1}=w_0x_t+w_1x_{t-1}+...+w_nx_{t-n+1}$
指数加权移动平均
$\hat{x}_{t+1}=\alpha x_t+\alpha(1-\alpha)x_{t-1}+\alpha(1-\alpha)^2 x_{t-2}+...$
$\hat{x}_{t}=\alpha x_{t-1}+\alpha(1-\alpha)x_{t-2}+\alpha(1-\alpha)^2 x_{t-3}+...$
结合上面两个公式，可以得到：
$\hat{x}_{t+1}=\alpha x_t+(1-\alpha)\hat{x_t}$
从公式可以得出结论，新一期的指数加权移动平均数是本期实际观察之与前一期指数加权移动平均数的加权平均$\hat{x}_t$
ARMA模型预测
AR模型 自回归模型
自回归模型，认为第t期的实现值是过去期的线性组合
p阶自回归模型（Auto Regressive Model）AR§ 的一般表达式为：
$x_t=\phi_0+ \phi_1x_{t-1}+\phi _2x_{t-2}+...+\phi_px_{t-p}+\epsilon_t$
其中$\{ \epsilon_t \}$是一个白噪声序列，即满足：
$\mathbb E(\epsilon_t)=0; Var(\epsilon_t)=\sigma_\epsilon^2; \mathbb E(\epsilon_t\epsilon_s)=0, \forall s \ne t$
如果时间序列是平稳的，所有$\mathbb E(x_t)$都是相等的，则可得：
$\mu = \frac{\phi_0}{1-\phi_1-\phi_2-...-\phi_p}$
将上式两边同时减去均值$\mu$，可得：
$x_t-\mu=\phi_1(x_{t-1}-\mu)+\phi_2(x_{t-2}-\mu)+...+\phi_p(x_{t-p}-\mu)+\epsilon_t$
将上式左右两边分别乘以$(x_t-\mu),(x_{t-1}-\mu),...$，并除以方差$\gamma_0$可得：
$1=\phi_1\rho_1+\phi_2\rho_2+..+\phi_p\rho_p$
$\rho_1=\phi_1+\phi_2\rho_1+\phi_3\rho_2+...+\phi_p\rho_{p-1}$
$\rho_2=\phi_1\rho_1+\phi_2+\phi_3\rho_1+...+\phi_p+\rho_{p-2}$
…
$\rho_p=\phi_1\rho_{p-1}+\phi_2\rho_{p-2}+\phi_3\rho_{p-3}+...+\phi_p$
通过上面的线性方程组可以解得$\rho_1,\rho_2,...,\rho_p$，对于大于p阶的自相关系数也有：
$\rho_k=\phi_1\rho_{k-1}+\phi_2\rho_{k-2}+...+\phi_p\rho_{k-p}$
所以符合AR（p）的平稳时间序列，其自相关性系数在p阶之后仍可能不为0
MA模型 移动平均模型
移动平均模型认为第t期的实现值是当期与过去期的随机冲击项的加权平均
MA(q)可以用数学表达为：
$x_t=\mu+\epsilon_t+\theta_1 \epsilon_{t-1}+\theta_2\epsilon_{t-2}+...+\theta_1\epsilon_{t-q}$
其中$\{ \epsilon_t \}$是一个白噪声序列，即满足：
$\mathbb E(\epsilon_t)=0; Var(\epsilon_t)=\sigma_\epsilon^2; \mathbb E(\epsilon_t\epsilon_s)=0, \forall s \ne t$
由于MA(q)仅仅是白噪声过程的线性组合，因此有：
$\mathbb E(x_t)=\mu\\ Var(x_t)=\gamma_0=(1+\theta_1^2+\theta_2^2+...+\theta_1^2)\sigma_\epsilon^2\\ \rho_l=\begin{cases} 1 & l=0\\ \frac{(\theta_l+\theta_{l+1}\theta_1)+\theta_{l+2}\theta_2+...+\theta_q\theta{q-l}}{(1+\theta_1^2+\theta_2^2+...+\theta_1^2)} & \forall l=1,2,..,q\\ 0 & \forall l>q \end{cases}$
ARMA 自回归移动平均模型
ARMA模型是混合量AR模型和MA模型之后的模型，ARMA(p,q)的模型表达式为：
$x_t=\phi_0+ \phi_1x_{t-1}+\phi _2x_{t-2}+...+\phi_px_{t-p}+\epsilon_t+\theta_1 \epsilon_{t-1}+\theta_2\epsilon_{t-2}+...+\theta_1\epsilon_{t-q}$
其中$\{ \epsilon_t \}$是一个白噪声序列，即满足：
$\mathbb E(\epsilon_t)=0; Var(\epsilon_t)=\sigma_\epsilon^2; \mathbb E(\epsilon_t\epsilon_s)=0, \forall s \ne t$


展开全文
• 接上文，本文介绍自相关模型（ARIMA）实现单变量多步输出时间序列预测任务。 自相关模型非常简单，能够实现快速、有效地对用电量进行一步或多步预测。本文主要内容如下： 如何创建和分析单变量时间序列数据自相关...
• 因为本文示例仅使用简单的人为构造数据来进行演示，因此并没有超参数调整部分，本文更多目的是提供解决时间序列预测问题思路方法和模型的模板，具体细节可以根据自己业务需求进行扩展开发。
本文介绍了如何在以TF2.1为后端的Keras中搭建一系列不同的多层感知器模型来实现序列预测任务。模型包括一元感知器模型，多元感知器模型，多时间步感知器模型，多变量多时间步感知器模型。因为本文示例仅使用简单的人为构造的数据来进行演示，因此并没有超参数调整部分，本文更多的目的是提供解决时间序列预测问题的思路方法和模型的模板，具体的细节可以根据自己的业务需求进行扩展开发。
多层感知器，简称MLPs，可用于时间序列预测。使用MLPs进行时间序列预测的难点在于数据的准备。具体来说，先前的时间步的值在输入时必须展平为特征向量。在深度学习方法应用于时间序列预测的任务中，最热的研究是使用CNN，LSTM和混合模型。这些会在之后的文章中介绍。

【时间序列预测/分类】 全系列45篇由浅入深的博文汇总：传送门

文章目录【时间序列预测/分类】 全系列45篇由浅入深的博文汇总：[传送门](https://blog.csdn.net/weixin_39653948/article/details/105571760)思维导图1. 数据准备2. 单变量MLP模型3. 多变量MLP模型3.1 多输入序列（Multiple Input Series）3.1.1 MLP 模型3.1.2 Multi-headed MLP 模型3.2 多并行序列（Multiple Parallel Series）3.2.1 Vector-Output MLP Model3.2.2 Multi-output MLP Model4. 多步MLP模型（Multi-step MLP Models）4.1 数据准备4.2 Vector Output Model5 多元多步MLP模型（Multivariate Multi-step MLP Models）5.1  多输入多步输出5.2 多并行输入多步输出

思维导图
本文内容较多，大概21000字（包含代码），如果之前没有相关基础，比较容易混淆。不同模型中的有些代码是重复，但需要格外注意不同的数据构建方式，实现序列数据划分为样本的 split_sequence() 的代码中滑动窗口截取数据的部分以及将重塑样本shape的代码有差别，在阅读和测试的过程中，注意这些地方。如果看着比较费劲，可以先看看思维导图，理清本文的行文思路，方便理解。本文结构也大致如下：

1. 数据准备
在对单变量序列进行建模之前，必须先进行准备。 MLP模型将学习将过去的观测序列作为输入映射到输出观测的函数。因此，必须将观察序列转换成可以从中学习模型的多个样本。假设有如下单变量序列：
[10, 20, 30, 40, 50, 60, 70, 80, 90]

我们可以将序列分为多个称为样本的输入/输出模式，其中三个时间步长用作输入，一个时间步长用作输出，用于单步预测。
X,  		 y
10, 20, 30,  40
20, 30, 40,  50
30, 40, 50,  60
...

下面的 split_sequence() 函数实现了此功能，将给定的单变量序列拆分为多个样本，其中每个样本具有指定数量的时间步长，而输出为单个时间步长。
import numpy as np

def split_sequence(sequence, sliding_window_width):
X, y = [], []
for i in range(len(sequence)):
# 找到最后一次滑动所截取数据中最后一个元素的索引，
# 如果这个索引超过原序列中元素的索引则不截取；
end_element_index = i + sliding_window_width
if end_element_index > len(sequence) - 1: # 序列中最后一个元素的索引
break
sequence_x, sequence_y = sequence[i:end_element_index], sequence[end_element_index] # 取最后一个元素作为预测值y
X.append(sequence_x)
y.append(sequence_y)

#return X,y
return np.array(X), np.array(y)

if __name__ == '__main__':
seq_test = [10,20,30,40,50,60,70,80,90]
sw_width = 3
seq_test_x, seq_test_y = split_sequence(seq_test, sw_width)
print(seq_test_x.shape,seq_test_y.shape)
for i in zip(seq_test_x,seq_test_y):
print(i)
for i in range(len(seq_test_x)):
print(seq_test_x[i], seq_test_y[i])

输出：
(6, 3) (6,)
(array([10, 20, 30]), 40)
(array([20, 30, 40]), 50)
(array([30, 40, 50]), 60)
(array([40, 50, 60]), 70)
(array([50, 60, 70]), 80)
(array([60, 70, 80]), 90)
[10 20 30] 40
[20 30 40] 50
[30 40 50] 60
[40 50 60] 70
[50 60 70] 80
[60 70 80] 90


2. 单变量MLP模型
一个简单的MLP模型具有单个隐藏的节点层和一个用于进行预测的输出层。我们可以如下定义用于单变量时间序列预测的MLP。
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense
model = Sequential()

每个样本的输入维度在第一个隐藏层定义的 input dim 参数中指定。从技术上讲，模型将把每个时间步看作一个单独的特征，而不是单独的时间步。
我们几乎总是有多个样本，因此，模型期望训练数据的输入部分具有维度或形状：[样本，特征]。上一节中的 split_sequence() 函数输出X的形状 [样本，特征] 可用于建模。该模型利用高效的随机梯度下降算法 Adam 进行拟合，使用均方误差（mse）损失函数进行优化。定义了模型之后就可以进行训练。
model.fit(seq_test_x, seq_test_y, epochs=2000, verbose=0)

在模型拟合后，我们可以利用它进行预测。我们可以通过输入[70，80，90]来预测序列中的下一个值。并期望模型预测输出能接近100。该模型期望输入形状是二维的，具有 [samples，features]，因此，在进行预测之前，必须重塑单个输入样本，例如，可以将1个样本和3个时间步作为输入特征，重塑为[1，3]的二维数组。
x_input = np.array([70, 80, 90])
x_input = x_input.reshape((1, sw_width))
yhat = model.predict(x_input, verbose=0)
print(yhat)

输出：
[[101.17381]]


3. 多变量MLP模型
多元时间序列数据是指每一时间步有多个观测值的数据，即有多个特征。对于多变量时间序列数据，常用的有两种主要模型：

多输入序列；
多个平行系列；

3.1 多输入序列（Multiple Input Series）
一个问题可能有两个或多个并行输入时间序列和一个依赖于输入时间序列的输出时间序列。输入时间序列是平行的，因为每个序列在同一时间步上都有一个观测值。我们可以通过两个并行输入时间序列的简单示例来演示这一点，其中输出序列是输入序列的简单相加。
in_seq1 = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90])
in_seq2 = np.array([15, 25, 35, 45, 55, 65, 75, 85, 95])
out_seq = np.array([in_seq1[i]+in_seq2[i] for i in range(len(in_seq1))])

我们可以将这三个数组重塑为单个数据集，其中每一行是一个时间步，每一列是一个单独的时间序列。这是在CSV文件中存储并行时间序列的标准方法。
# 每一个数组先转换成9×1的二维数组
in_seq1 = in_seq1.reshape((len(in_seq1), 1))
in_seq2 = in_seq2.reshape((len(in_seq2), 1))
out_seq = out_seq.reshape((len(out_seq), 1))
# 使用numpy的hstack方法，沿水平方向堆叠数组，对于二维数组就是沿第二个维度（列）堆叠
dataset = np.hstack((in_seq1, in_seq2, out_seq))

我们看一下dataset：
array([[ 10,  15,  25],
[ 20,  25,  45],
[ 30,  35,  65],
[ 40,  45,  85],
[ 50,  55, 105],
[ 60,  65, 125],
[ 70,  75, 145],
[ 80,  85, 165],
[ 90,  95, 185]])

与单变量时间序列一样，我们必须将这些数据构造成具有输入和输出样本的样本。我们需要将数据分成样本，保持两个输入序列的观测顺序。如果我们选择三个输入时间步骤，那么第一个示例将如下所示：
输入：
10, 15
20, 25
30, 35

输出：
65

也就是说，将每个并行序列的前三个时间步作为输入提供给模型，并且在第三个时间步，在本例中为65，模型将其与输出序列中的值相关联。我们可以看到，在将时间序列转换为输入/输出样本以训练模型时，我们将不得不放弃输出时间序列中的一些值，因为在先前的时间步，我们在输入时间序列中没有值。反过来，输入时间步数大小的选择将对训练数据的使用量产生重要影响。我们可以定义一个名为 split_sequences() 的函数来实现数据集划分。
def split_sequences(sequences, sliding_window_width):
X, y = [], []
for i in range(len(sequences)):
# 找到最后一次滑动所截取数据中最后一个元素的索引，
# 如果这个索引超过原序列中元素的索引则不截取；
end_element_index = i + sliding_window_width
if end_element_index > len(sequences) : # 序列中最后一个元素的索引
break

# 使用二维数组切片来截取输入数据X和标签y；:-1 表示截取第1,2列数据（共3列）；-1表示截取最后一列数据；
sequence_x, sequence_y = sequences[i:end_element_index ,:-1], sequences[end_element_index-1, -1] # 取最后一个元素作为预测值y
X.append(sequence_x)
y.append(sequence_y)

#return X,y
return np.array(X), np.array(y)

if __name__ == '__main__':
sw_width = 3
X, y = split_sequences(dataset, sw_width)
print(X.shape, y.shape)
for i in range(len(X)):
print(X[i], y[i])

输出：
(7, 3, 2) (7,)
[[10 15]
[20 25]
[30 35]] 65
[[20 25]
[30 35]
[40 45]] 85
[[30 35]
[40 45]
[50 55]] 105
[[40 45]
[50 55]
[60 65]] 125
[[50 55]
[60 65]
[70 75]] 145
[[60 65]
[70 75]
[80 85]] 165
[[70 75]
[80 85]
[90 95]] 185

在拟合MLP之前，必须将输入样本的形状变平。MLP要求每个样本的输入部分的形状是一个向量。对于多变量输入，有多个向量，每个时间步一个向量。我们可以展平每个输入样本：
[[10 15]
[20 25]
[30 35]]

展平输入为：
[10, 15, 20, 25, 30, 35]

我们可以计算每个输入向量的长度，即时间步数乘以特征数或时间序列数。然后我们可以使用这个向量大小来重塑输入。
n_input = X.shape[1] * X.shape[2]
X = X.reshape((X.shape[0], n_input))

我们看一下X：
array([[10, 15, 20, 25, 30, 35],
[20, 25, 30, 35, 40, 45],
[30, 35, 40, 45, 50, 55],
[40, 45, 50, 55, 60, 65],
[50, 55, 60, 65, 70, 75],
[60, 65, 70, 75, 80, 85],
[70, 75, 80, 85, 90, 95]])

3.1.1 MLP 模型
现在可以为多元输入定义一个MLP模型，其中向量长度用于输入维参数。
model = Sequential()

model.fit(X, y, epochs=2000, verbose=0)

输入数据做预测：
x_input = np.array([[80, 85], [90, 95], [100, 105]])
x_input = x_input.reshape((1, n_input))
yhat = model.predict(x_input, verbose=0)
print(yhat)

输出：
[[206.24257]]


    visible1 = Input(shape=(sliding_window_width,))
dense1 = Dense(100, activation='relu')(visible1)
visible2 = Input(shape=(sliding_window_width,))
dense2 = Dense(100, activation='relu')(visible2)

定义了两个输入子模型之后，可以将每个模型的输出合并为一个长向量，在对输出序列进行预测之前可以对其进行解释。
    merge = concatenate([dense1, dense2])
output = Dense(1)(merge)

model = Model(inputs=[visible1, visible2], outputs=output)

下图提供了该模型的外观示意图，包括每个层的输入和输出的形状。绘图方法请看下文完整代码。

此模型要求将输入作为有两个元素组成的列表提供，其中列表中的每个元素都包含其中一个子模型的数据。为了达到这个目的，我们可以将3D输入数据分割成两个独立的输入数据数组：即从一个形状为[7，3，2]的三维数组转化为两个形状为[7，3]的二维数组。
X1 = X[:, :, 0]
X2 = X[:, :, 1]

转换完成后，可以进行编译，然后训练：
model.compile(optimizer='adam', loss='mse')
model.fit([X1, X2], y, epochs=2000, verbose=0)

同样，在进行一步预测时，我们必须将单个样本的数据准备为两个独立的二维数组。
x_input = array([[80, 85], [90, 95], [100, 105]])
x1 = x_input[:, 0].reshape((1, sw_width))
x2 = x_input[:, 1].reshape((1, sw_width)

进行预测：
yhat = model.predict([x1, x2], verbose=0)
print(yhat)

完整代码：
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input,Dense,concatenate
from tensorflow.keras.utils import plot_model
import numpy as np

def split_sequences(sequences, sliding_window_width):
X, y = [], []
for i in range(len(sequences)):
# 找到最后一次滑动所截取数据中最后一个元素的索引，
# 如果这个索引超过原序列中元素的索引则不截取；
end_element_index = i + sliding_window_width
if end_element_index > len(sequences) : # 序列中最后一个元素的索引
break

# 使用二维数组切片来截取输入数据X和标签y；:-1 表示截取第1,2列数据（共3列）；-1表示截取最后一列数据；
sequence_x, sequence_y = sequences[i:end_element_index ,:-1], sequences[end_element_index-1, -1] # 取最后一个元素作为预测值y
X.append(sequence_x)
y.append(sequence_y)

#return X,y
return np.array(X), np.array(y)

def multiple_input_series(X_1, X_2, y, sliding_window_width, epochs_num):
visible1 = Input(shape=(sliding_window_width,))
dense1 = Dense(100, activation='relu')(visible1)

visible2 = Input(shape=(sliding_window_width,))
dense2 = Dense(100, activation='relu')(visible2)

merge = concatenate([dense1, dense2])
output = Dense(1)(merge)
print('output:', output)
# 构建多输入多输出模型Model
model = Model(inputs=[visible1, visible2], outputs=output)
# 编译模型
# 保存模型结构图
plot_model(model, to_file='mis_model.png', show_shapes=True, show_layer_names=True, rankdir='TB', dpi=200)
# 训练模型
model.fit([X_1, X_2], y, epochs=epochs_num, verbose=0)

return model

if __name__ == '__main__':
sw_width = 3
epochs_num = 2000

# 训练数据
in_seq1 = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90]) # shape=(1, 9)
in_seq2 = np.array([15, 25, 35, 45, 55, 65, 75, 85, 95]) # shape=(1, 9)
out_seq = np.array([in_seq1[i]+in_seq2[i] for i in range(len(in_seq1))]) # shape=(1, 9)

in_seq1 = in_seq1.reshape((len(in_seq1), 1)) # shape=(9, 1)
in_seq2 = in_seq2.reshape((len(in_seq2), 1)) # shape=(9, 1)
out_seq = out_seq.reshape((len(out_seq), 1)) # shape=(9, 1)

dataset = np.hstack((in_seq1, in_seq2, out_seq)) # shape=(9, 3)

# 训练数据和标签划分; X.shape = (7, 3, 2)
X, y = split_sequences(dataset, sw_width)

print(X.shape, y.shape)
#     for i in range(len(X)):
#         print(X[i], y[i])

X1 = X[:, :, 0] # shape=(7, 3)
X2 = X[:, :, 1] # shape=(7, 3)

# 训练模型
model = multiple_input_series(X1, X2, y, sw_width, epochs_num)

# 构造测试数据
x_test = np.array([[80, 85], [90, 95], [100, 105]]) # shape=(3, 2)
# 将测试数据重塑为二维数组
x1 = x_test[:, 0].reshape((1, sw_width)) # shape=(1, 3)
x2 = x_test[:, 1].reshape((1, sw_width)) # shape=(1, 3)
# 模型预测
yhat = model.predict([x1, x2], verbose=0)
print(yhat)

输出：
(7, 3, 2) (7,)
output: Tensor("dense_14/Identity:0", shape=(None, 1), dtype=float32)
[[206.31477]]


3.2 多并行序列（Multiple Parallel Series）
另一个时间序列问题是存在多个并行时间序列并且必须为每个时间序列预测值的情况。例如，给定上一节中的数据：
[[ 10 15 25]
[ 20 25 45]
[ 30 35 65]
[ 40 45 85]
[ 50 55 105]
[ 60 65 125]
[ 70 75 145]
[ 80 85 165]
[ 90 95 185]]

我们可能希望为下一个时间步预测三个时间序列中每个时间序列的值。这可能称为多元预测。同样，必须将数据分为输入/输出样本以训练模型。该数据集的第一个样本为：
输入：
10, 15, 25
20, 25, 45
30, 35, 65

输出：
40, 45, 85

下面的 split sequence() 函数会将多个并行时间序列（行以时间步长）和每列一个序列划分为所需的输入/输出形状。完整实例：
def split_sequences(sequence, sliding_window_width):
X, y = [], []
for i in range(len(sequence)):
# 找到最后一次滑动所截取数据中最后一个元素的索引，
# 如果这个索引超过原序列中元素的索引则不截取；
end_element_index = i + sliding_window_width
if end_element_index > len(sequence) - 1: # 序列中最后一个元素的索引
break

sequence_x, sequence_y = sequence[i:end_element_index], sequence[end_element_index, :] # 取最后一列元素作为预测值y
X.append(sequence_x)
y.append(sequence_y)

#return X,y
return np.array(X), np.array(y)

if __name__ == '__main__':
sw_width = 3

# 训练数据
in_seq1 = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90])
in_seq2 = np.array([15, 25, 35, 45, 55, 65, 75, 85, 95])
out_seq = np.array([in_seq1[i]+in_seq2[i] for i in range(len(in_seq1))])

in_seq1 = in_seq1.reshape((len(in_seq1), 1))
in_seq2 = in_seq2.reshape((len(in_seq2), 1))
out_seq = out_seq.reshape((len(out_seq), 1))

dataset = np.hstack((in_seq1, in_seq2, out_seq))

# 训练数据和标签划分
X, y = split_sequences(dataset, sw_width)

print(X.shape, y.shape)
for i in range(len(X)):
print(X[i], y[i])

输出：
(6, 3, 3) (6, 3)
[[10 15 25]
[20 25 45]
[30 35 65]] [40 45 85]
[[20 25 45]
[30 35 65]
[40 45 85]] [ 50  55 105]
[[ 30  35  65]
[ 40  45  85]
[ 50  55 105]] [ 60  65 125]
[[ 40  45  85]
[ 50  55 105]
[ 60  65 125]] [ 70  75 145]
[[ 50  55 105]
[ 60  65 125]
[ 70  75 145]] [ 80  85 165]
[[ 60  65 125]
[ 70  75 145]
[ 80  85 165]] [ 90  95 185]


3.2.1 Vector-Output MLP Model
现在，我们准备在此数据上拟合MLP模型。与前面的多元输入情况一样，我们必须将输入数据样本的三维结构展平为[样本，特征]的二维结构。
n_input = X.shape[1] * X.shape[2]
X = X.reshape((X.shape[0], n_input))

模型输出将是一个向量，三个不同的时间序列各有一个元素作为预测输出。
n_output = y.shape[1]

现在，我们可以定义我们的模型，在进行预测时，使用输入层的展平向量长度和时间序列的数量作为向量长度。
model = Sequential()

通过为每个序列提供三个时间步的输入，我们可以预测三个并行序列中每个序列的下一个值。
70, 75, 145
80, 85, 165
90, 95, 185

用于进行单个预测的输入形状必须是1个样本、3个时间步和3个特征，或[1,3,3]。再一次，我们可以将其扁平化为[1，6]以满足模型的输入要求。我们预计输出为：
[100, 105, 205]

预测：
x_input = array([[70,75,145], [80,85,165], [90,95,185]])
x_input = x_input.reshape((1, n_input))
yhat = model.predict(x_input, verbose=0)

完整代码：
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
import numpy as np

def split_sequences(sequence, sliding_window_width):
X, y = [], []
for i in range(len(sequence)):
# 找到最后一次滑动所截取数据中最后一个元素的索引，
# 如果这个索引超过原序列中元素的索引则不截取；
end_element_index = i + sliding_window_width
if end_element_index > len(sequence) - 1: # 序列中最后一个元素的索引
break

sequence_x, sequence_y = sequence[i:end_element_index], sequence[end_element_index, :] # 取最后一列元素作为预测值y
X.append(sequence_x)
y.append(sequence_y)

#return X,y
return np.array(X), np.array(y)

def vector_output_model(n_input, n_output, epochs_num):
model = Sequential()

model.fit(X, y, epochs=epochs_num, verbose=0)

return model

if __name__ == '__main__':
sw_width = 3
epochs_num = 2000

# 训练数据
in_seq1 = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90])
in_seq2 = np.array([15, 25, 35, 45, 55, 65, 75, 85, 95])
out_seq = np.array([in_seq1[i]+in_seq2[i] for i in range(len(in_seq1))])

in_seq1 = in_seq1.reshape((len(in_seq1), 1))
in_seq2 = in_seq2.reshape((len(in_seq2), 1))
out_seq = out_seq.reshape((len(out_seq), 1))

dataset = np.hstack((in_seq1, in_seq2, out_seq))

# 训练数据和标签划分
X, y = split_sequences(dataset, sw_width)

print(X.shape, y.shape)
#     for i in range(len(X)):
#         print(X[i], y[i])

n_input = X.shape[1] * X.shape[2]
X = X.reshape((X.shape[0], n_input))
n_output = y.shape[1]

x_input = np.array([[70,75,145], [80,85,165], [90,95,185]])
x_input = x_input.reshape((1, n_input))

model = vector_output_model(n_input, n_output, epochs_num)

yhat = model.predict(x_input, verbose=0)
print(yhat)

输出：
(6, 3, 3) (6, 3)
[[101.39276  105.340294 207.98416 ]]


3.2.2 Multi-output MLP Model
与多个输入序列一样，还有另一种更精细的方法来建模问题。每个输出序列可以由单独的输出MLP模型处理。我们可以称之为多输出MLP模型。它可能提供更多的灵活性或更好的性能，这取决于业务需求的具体情况。首先，我们可以将输入模型定义为一个MLP，该MLP的输入为展平的特征向量。
visible = Input(shape=(n_input,))
dense = Dense(100, activation='relu')(visible)

然后，我们可以为希望预测的三个序列中的每一个定义一个输出层，其中每个输出子模型将预测一个时间步。
model = Model(inputs=visible, outputs=[output1, output2, output3])

下图显示了模型的三个独立输出层以及每个层的输入和输出形状。

在训练模型时，每个样本需要三个独立的输出数组。我们可以通过将具有形状[7，3]的输出训练数据转换为具有形状[7，1]的三个数组来实现：
# separate output
y1 = y[:, 0].reshape((y.shape[0], 1))
y2 = y[:, 1].reshape((y.shape[0], 1))
y3 = y[:, 2].reshape((y.shape[0], 1))

训练模型：
model.fit(X, [y1,y2,y3], epochs=2000, verbose=0)

完整代码：
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Dense
from tensorflow.keras.utils import plot_model
import numpy as np

def split_sequences(sequence, sliding_window_width):
X, y = [], []
for i in range(len(sequence)):
# 找到最后一次滑动所截取数据中最后一个元素的索引，
# 如果这个索引超过原序列中元素的索引则不截取；
end_element_index = i + sliding_window_width
if end_element_index > len(sequence) - 1: # 序列中最后一个元素的索引
break

sequence_x, sequence_y = sequence[i:end_element_index, :], sequence[end_element_index, :] # 取最后一列元素作为预测值y
X.append(sequence_x)
y.append(sequence_y)

#return X,y
return np.array(X), np.array(y)

def multi_output_model(n_input, y, epochs_num):
visible = Input(shape=(n_input,))
dense = Dense(100, activation='relu')(visible)

output1 = Dense(1)(dense)
output2 = Dense(1)(dense)
output3 = Dense(1)(dense)

model = Model(inputs=visible, outputs=[output1, output2, output3])

plot_model(model, to_file='multi_output_model.png', show_shapes=True, show_layer_names=True, rankdir='TB', dpi=200)

model.fit(X, y, epochs=2000, verbose=0)

return model

if __name__ == '__main__':
sw_width = 3
epochs_num = 2000

# 训练数据
in_seq1 = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90])
in_seq2 = np.array([15, 25, 35, 45, 55, 65, 75, 85, 95])
out_seq = np.array([in_seq1[i]+in_seq2[i] for i in range(len(in_seq1))])

in_seq1 = in_seq1.reshape((len(in_seq1), 1))
in_seq2 = in_seq2.reshape((len(in_seq2), 1))
out_seq = out_seq.reshape((len(out_seq), 1))

dataset = np.hstack((in_seq1, in_seq2, out_seq))

# 训练数据和标签划分
X, y = split_sequences(dataset, sw_width)

print(X.shape, y.shape)
#     for i in range(len(X)):
#         print(X[i], y[i])

n_input = X.shape[1] * X.shape[2]
X = X.reshape((X.shape[0], n_input))

y1 = y[:, 0].reshape((y.shape[0], 1))
y2 = y[:, 1].reshape((y.shape[0], 1))
y3 = y[:, 2].reshape((y.shape[0], 1))
y_list = [y1,y2,y3]

model = multi_output_model(n_input, y_list, epochs_num)

x_input = np.array([[70,75,145], [80,85,165], [90,95,185]])
x_input = x_input.reshape((1, n_input))
yhat = model.predict(x_input, verbose=0)
print(yhat)

输出：
(6, 3, 3) (6, 3)
[array([[100.50821]], dtype=float32), array([[105.74859]], dtype=float32), array([[206.86055]], dtype=float32)]


4. 多步MLP模型（Multi-step MLP Models）
实际上，MLP模型在预测表示不同输出变量的向量输出（如前一示例中所示）或表示一个变量的多个时间步的向量输出方面几乎没有差别。然而，在训练数据的准备方式上存在着微妙而重要的差异。
4.1 数据准备
与一步预测一样，用于多步时间序列预测的时间序列必须分成具有输入和输出分量的样本。输入和输出分量将由多个时间步组成，并且可能具有或可能不具有相同的步数。例如，给定一元时间序列：
[10, 20, 30, 40, 50, 60, 70, 80, 90]

我们可以使用三个时间步骤作为输入，并预测下两个时间步骤。第一个样本如下：
输入：
[10, 20, 30]

输出：
[40, 50]

数据划分结果：
[10 20 30] [40 50]
[20 30 40] [50 60]
[30 40 50] [60 70]
[40 50 60] [70 80]
[50 60 70] [80 90]

4.2 Vector Output Model
MLP可以直接输出一个可以解释为多步预测的向量。该方法在前一节中看到，每个输出时间序列的一个时间步长被预测为一个向量。在n步输入和n步输出变量中指定输入和输出步数，就可以定义一个多步时间序列预测模型。
完整代码：
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
import numpy as np

def split_sequence(sequence, m_steps_in, n_steps_out):
X, y = [], []
for i in range(len(sequence)):

end_element_index = i + n_steps_in
out_end_index = end_element_index + n_steps_out
if out_end_index > len(sequence):
break

sequence_x, sequence_y = sequence[i:end_element_index], sequence[end_element_index:out_end_index]
X.append(sequence_x)
y.append(sequence_y)

return np.array(X), np.array(y)

def vector_output_model(n_steps_in, n_steps_out, X, y, epochs_num):
model = Sequential()

model.fit(X, y, epochs=2000, verbose=0)
return model

if __name__ == '__main__':
epochs_num = 2000
n_steps_in, n_steps_out = 3, 2

raw_seq = [10, 20, 30, 40, 50, 60, 70, 80, 90]
X, y = split_sequence(raw_seq, n_steps_in, n_steps_out)

print(X.shape, y.shape)
for i in range(len(X)):
print(X[i], y[i])

model = vector_output_model(n_steps_in, n_steps_out, X, y, epochs_num)

x_input = np.array([70, 80, 90])
x_input = x_input.reshape((1, n_steps_in))
yhat = model.predict(x_input, verbose=0)
print(yhat)

输出：
(5, 3) (5, 2)
[10 20 30] [40 50]
[20 30 40] [50 60]
[30 40 50] [60 70]
[40 50 60] [70 80]
[50 60 70] [80 90]
[[100.4229  111.65523]]


5 多元多步MLP模型（Multivariate Multi-step MLP Models）
在前面的章节中，我们讨论了单变量、多变量和多步时间序列预测。对于不同的问题，组合不同类型的MLP模型可能解决不同的问题。这也适用于涉及多变量和多步预测的时间序列预测问题，但这可能更具挑战性，特别是在准备数据和定义模型的输入和输出形状方面。
5.1  多输入多步输出
在多变量时间序列预测问题中，输出序列是独立的，但依赖于输入序列，输出序列需要多个时间步。例如，考虑前面一节中的多元时间序列：
[[ 10 15 25]
[ 20 25 45]
[ 30 35 65]
[ 40 45 85]
[ 50 55 105]
[ 60 65 125]
[ 70 75 145]
[ 80 85 165]
[ 90 95 185]]


我们可以使用两个输入时间序列中每一个的三个先验时间步来预测输出时间序列的两个时间步。
输入：
10, 15
20, 25
30, 35

输出：
65
85

完整代码：
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
import numpy as np

def split_sequences(sequences, n_steps_in, n_steps_out):
X, y = [], []
for i in range(len(sequences)):

end_element_index = i + n_steps_in
out_end_index = end_element_index + n_steps_out - 1

if out_end_index > len(sequences):
break

sequence_x, sequence_y = sequences[i:end_element_index,:-1], sequences[end_element_index-1:out_end_index,-1]
X.append(sequence_x)
y.append(sequence_y)

return np.array(X), np.array(y)

def multi_step_output_model(n_input, n_steps_out, X, y, epochs_num):
model = Sequential()

model.fit(X, y, epochs=epochs_num, verbose=0)
return model

if __name__ == '__main__':
epochs_num = 2000

in_seq1 = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90])
in_seq2 = np.array([15, 25, 35, 45, 55, 65, 75, 85, 95])
out_seq = np.array([in_seq1[i]+in_seq2[i] for i in range(len(in_seq1))])

in_seq1 = in_seq1.reshape((len(in_seq1), 1))
in_seq2 = in_seq2.reshape((len(in_seq2), 1))
out_seq = out_seq.reshape((len(out_seq), 1))

dataset = np.hstack((in_seq1, in_seq2, out_seq))

n_steps_in, n_steps_out = 3, 2

X, y = split_sequences(dataset, n_steps_in, n_steps_out)

n_input = X.shape[1] * X.shape[2]
X = X.reshape((X.shape[0], n_input))

print(X.shape, y.shape)
for i in range(len(X)):
print(X[i], y[i])

model = multi_step_output_model(n_input, n_steps_out, X, y, epochs_num)

x_input = np.array([[70, 75], [80, 85], [90, 95]])
x_input = x_input.reshape((1, n_input))
yhat = model.predict(x_input, verbose=0)
print(yhat)

输出：
(6, 6) (6, 2)
[10 15 20 25 30 35] [65 85]
[20 25 30 35 40 45] [ 85 105]
[30 35 40 45 50 55] [105 125]
[40 45 50 55 60 65] [125 145]
[50 55 60 65 70 75] [145 165]
[60 65 70 75 80 85] [165 185]
[[186.31998 206.29776]]


5.2 多并行输入多步输出
具有并行时间序列的问题可能需要预测每个时间序列的多个时间步。例如，考虑前面一节中的多元时间序列：
[[ 10 15 25]
[ 20 25 45]
[ 30 35 65]
[ 40 45 85]
[ 50 55 105]
[ 60 65 125]
[ 70 75 145]
[ 80 85 165]
[ 90 95 185]]

我们可以使用三个时间序列中每个时间序列的三个时间步作为模型的输入，并预测三个时间序列中每个时间步的下一个时间步作为输出。训练数据集中的第一个示例如下：
输入：
10, 15, 25
20, 25, 45
30, 35, 65

输出：
40, 45, 85
50, 55, 105

我们可以看到数据集的输入(X)和输出(Y)元素对于样本数量、时间步长和变量或并行时间序列来说都是三维的。
我们现在可以开发一个多变量多步预测的MLP模型。除了像前面的例子中那样使输入数据的形状扁平化外，我们还必须使输出数据的三维结构扁平化。这是因为MLP模型只能接受向量输入和输出。
# flatten input
n_input = X.shape[1] * X.shape[2]
X = X.reshape((X.shape[0], n_input))
# flatten output
n_output = y.shape[1] * y.shape[2]
y = y.reshape((y.shape[0], n_output))

完整代码：
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
import numpy as np

def split_sequences(sequences, n_steps_in, n_steps_out):
X, y = [], []
for i in range(len(sequences)):

end_element_index = i + n_steps_in
out_end_index = end_element_index + n_steps_out

if out_end_index > len(sequences):
break

sequence_x, sequence_y = sequences[i:end_element_index,:], sequences[end_element_index:out_end_index,:]
X.append(sequence_x)
y.append(sequence_y)

return np.array(X), np.array(y)

def multi_parallel_output_model(n_input, n_output, X, y, epochs_num):
model = Sequential()

model.fit(X, y, epochs=epochs_num, verbose=0)
return model

if __name__ == '__main__':
epochs_num = 2000

in_seq1 = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90])
in_seq2 = np.array([15, 25, 35, 45, 55, 65, 75, 85, 95])
out_seq = np.array([in_seq1[i]+in_seq2[i] for i in range(len(in_seq1))])

in_seq1 = in_seq1.reshape((len(in_seq1), 1))
in_seq2 = in_seq2.reshape((len(in_seq2), 1))
out_seq = out_seq.reshape((len(out_seq), 1))
# 沿列堆叠数组，相当于列数增加
dataset = np.hstack((in_seq1, in_seq2, out_seq))
# 时间步长
n_steps_in, n_steps_out = 3, 2
# 将输入数据分为训练数据和训练标签
X, y = split_sequences(dataset, n_steps_in, n_steps_out)
# 展平输入数据
n_input = X.shape[1] * X.shape[2]
X = X.reshape((X.shape[0], n_input))
# 展平输出数据
n_output = y.shape[1] * y.shape[2]
y = y.reshape((y.shape[0], n_output))

print(X.shape, y.shape)
for i in range(len(X)):
print(X[i], y[i])

model = multi_parallel_output_model(n_input, n_output, X, y, epochs_num)

x_input = np.array([[60, 65, 125], [70, 75, 145], [80, 85, 165]])
x_input = x_input.reshape((1, n_input))
yhat = model.predict(x_input, verbose=0)
print(yhat)

输出：
(5, 9) (5, 6)
[10 15 25 20 25 45 30 35 65] [ 40  45  85  50  55 105]
[20 25 45 30 35 65 40 45 85] [ 50  55 105  60  65 125]
[ 30  35  65  40  45  85  50  55 105] [ 60  65 125  70  75 145]
[ 40  45  85  50  55 105  60  65 125] [ 70  75 145  80  85 165]
[ 50  55 105  60  65 125  70  75 145] [ 80  85 165  90  95 185]
[[ 92.22672   96.749825 188.34888  102.91172  108.4422   209.61449 ]]


总结一下，本文介绍了：

如何开发用于单变量时间序列预测的MLP模型。
如何开发用于多元时间序列预测的MLP模型。
如何开发用于多步时间序列预测的MLP模型。

再看一下思维导图就一目了然了。

关于CNN、LSTM、CNN-LSTM、Conv-LSTM、LSTM-FCN、MV-LSTM-FCN等等一系列用于时间序列预测建模的模型的内容，请看以后的文章。

参考：
https://machinelearningmastery.com/how-to-develop-multilayer-perceptron-models-for-time-series-forecasting/


展开全文
• 用Python进行时间序列预测的自回归模型 自回归是一个时间序列模型，它使用以前时间步的观察值作为回归方程的输入，以预测下一个时间步的值。 这是一个非常简单的想法，可以对一系列时间序列问题进行准确的预测。 ...
• 时间序列预测之–ARIMA模型 什么是 ARIMA模型 ARIMA模型的全称叫做自回归移动平均模型，全称是(ARIMA, Autoregressive Integrated Moving Average Model)。也记作ARIMA(p,d,q)，是统计模型(statistic model)中最常见...
• 建立时间序列预测的卷积神经网络模型 一维时间序列建立卷积神经网络模型 简单来说一维CNN只在一个维度上进行卷积操作 # 定义模型 这里定义的是一个一维的CNN模型 model = Sequential() model.add(Conv1D(filters=64,...
• 针对传统时间序列线性预测算法对时间序列线性程度要求高，而非线性方法一般建模复杂且计算量大，提出了一种基于趋势点状态模型的时间序列预测算法。该算法无须考虑时间序列是否具有显著线性特征，通过序列间耦合...
• 这玩意使用起来还是较为简单的, 所以选用这个作为预测算法 参考这几篇: https://blog.csdn.net/anshuai_aw1/article/details/83412058 https://blog.csdn.net/qq_23860475/article/details/81354467 ...
• 基于深度神经网络模型DNN时序数据预测模型相对于LSTM网络结构而言更为简单，今天不做说明，本文主要是结合LSTM网络模型来构建时序数据预测模型，实践一下时间序列预测。 这里首先...
• 深度学习多变量时间序列预测：GRU算法构建时间序列多变量模型预测交通流量+代码实战 GRU是LSTM网络一种效果很好变体，它较LSTM网络结构更加简单，而且效果也很好，因此也是当前非常流形一种网络。GRU既然...
• 时间序列预测（二）—— AR模型 文章链接 （一）数据预处理 （二）AR模型（自回归模型） （三）Xgboost模型 （四）LSTM模型 （五）Prophet模型（自回归模型模型原理   AR（auto-regressive）模型，亦即是自...
• 基于时间序列AR模型的PHM预测 由于时间序列分析方法是一个小样本理论，应用起来方便简单，符合实际工程中样本数量较小情况需求。 在工程领域，自回归（AR）模型比滑动平均（MA）模型和自回归滑动平均（ARMA）...
• AR是线性时间序列分析模型中最简单的模型。通过自身前面部分数据与后面部分数据之间相关关系（自相关）来建立回归方程，从而可以进行预测或者分析。下图中展示了一个时间如果可以表示成如下结构，那么就说明它...
• 基于fbprophet的时间序列预测基于fbprophet的时间序列预测Prophet模型常用参数说明趋势相关周期相关假日相关简单入门误差评估与调参使用训练出来参数进行最终预测 基于fbprophet的时间序列预测 由于业务需求，...
• 对于较为简单的时间序列预测问题，可以使用Exponential Smoothing和ARIMA等传统模型非常方便地求解。然而，对于复杂的时间序列预测问题，LSTM不失为一种很好选择。因此，本文旨在探讨如何利用LSTM神经网络求解时间...
• 提供一种适用于初中级学者的时间序列预测模型 并且十分有效好用 数据介绍 该数据集是一个污染数据集，我们需要用该多维时间序列去预测pollution这个维度，采用80%作为训练集，20%作为测试集。 模型实现 模型使用...
• 第1部分_时间序列分析的概念与时间序列分解模型 时间序列 时间序列的基本概念 区分时期和时点序列 时期序列适用于灰色预测模型 时间序列分解 长期变动趋势 T 季节趋势 S 第2部分_SPSS中七种指数平滑方法的简单...
• 本节简单回归一下时间序列任务几种方向以及有哪些比较优秀开源算法。1 时序预测时序预测从不同角度看有不同分类。从实现原理角度，可以分为传统统计学、机器学习（又分非深度学习和深度学习）...
• 问题：韩国、日本、伊朗和意大利...方法：采用R语言forecast包auto.arima函数进行预测。 1 数据采集 利用腾讯微信提供数据。仅收集2月28日至今数据，具体如下： > df1 # A tibble: 13 x 5 date no.kor no....
• 为此，人们研究了许多时间序列预测模型。然而，大部分的时间序列模型都因为预测的问题过于复杂而效果不理想。这是因为时间序列预测不光需要大量的统计知识，更重要的是它需要将问题的背景知识融入其中。为此，...
• 通过机器学习（machine learning）做价格预测。希望能提供一些最基础建议１）首先尽量简化数据，让每一个输入都有很规范格式。每一个输入源必须是mean 0，variance 1。假如说不能直接用价格；要用价格差距。...
• 也记作ARIMA(p,d,q)，是统计模型(statistic model)中最常见的一种用来进行时间序列 预测的模型。 1. ARIMA的优缺点 优点： 模型十分简单，只需要内生变量而不需要借助其他外生变量。 缺点： 1.要求时序...

...