越秀网站建设公司全国建设部网站官网
越秀网站建设公司,全国建设部网站官网,e2ee网站开发框架2.23先行版,开发工具idea原文#xff1a;towardsdatascience.com/neural-networks-for-flexible-multivariate-forecasting-82194d6cca0f 预测多个时间序列可以迅速变得复杂#xff1b;传统方法要么需要每个序列一个单独的模型#xff08;即 SARIMA#xff09;#xff0c;要么所有序列都相关…原文towardsdatascience.com/neural-networks-for-flexible-multivariate-forecasting-82194d6cca0f预测多个时间序列可以迅速变得复杂传统方法要么需要每个序列一个单独的模型即 SARIMA要么所有序列都相关即 VARMA。神经网络提供了一种灵活的方法无论序列相关性如何都可以使用单个模型进行多序列预测。此外这种方法允许轻松地纳入外生变量并可以预测未来的多个时间步从而产生一个强大的通用解决方案在各种情况下表现良好。在这篇文章中我们将展示如何执行数据窗口操作将我们的数据从时间序列转换为监督学习格式适用于单变量和多变量时间序列。一旦我们的数据被转换我们将展示如何训练深度神经网络和 LSTM 进行多变量预测。检查我们的数据我们将使用一个数据集该数据集捕捉了 2013 年至 2016 年间德里印度的每日平均温度和湿度。这些数据可在 Kaggle 上找到并许可在CC0公共领域下使用这使得它非常适合我们的项目。以表格格式显示数据我们看到我们有 3 列其中 1 列包含测量日期时间每列分别对应‘meantemp’和‘humidity’。平均温度和湿度将形成我们想要预测的两个时间序列。https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/fa6bf2daf8adeeb87ff4f6393471fa8d.png图 1基础数据集我们可以绘制这些数据如图 2 所示并看到两个数据集的尺度相当一致并且似乎存在某种反向相关性即较高的平均温度与较低的湿度相关。# Create tracesfiggo.Figure()forfactor_levelinids:# Adding plot of original_dffig.add_trace(go.Scatter(xformatted_df[Date],yformatted_df[factor_level],modelines,namefactor_level))fig.update_layout(titleTemp and Humidity over Time, Delhi India)https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/eaf68f9fa8434c65f7fbd1dedd3d90f5.png图 2随时间变化的温度和湿度数据窗口现在是这种方法中最困难的部分确保使用窗口方法我们的数据处于正确的格式。我们面临的问题是我们需要将单变量时间序列 Y 转换为两个变量 X1 和 Y1其中 X1 中的每一行都包含 Y1 中相应行之前的 n 个时间步。在这个例子中n 是我们的窗口大小数据转换可以在图 1 中看到。如果我们的初始 Y 数据集有 10 个点我们将窗口大小 n 设置为 2那么我们的输出 X1 和 Y1 的维度将分别为(8 x 2)和(8 x 1)。有了这两个新变量我们可以拟合一个普通回归模型将每个 Y1 的值作为前两个值的函数来建模。例如在图 3 中我们可以看到窗口大小为 2 时我们的第一个 Y 值将是初始 Y 序列中的第 3 个索引并且它将依赖于 Y 中的索引 1 和 2 的值。https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/530f1fe328c353801596d822b492c3fc.png图 3一元窗口转换如果我们感兴趣的不是单一的时间序列而是预测多个时间序列我们可以执行完全相同的过程并将每个数据集按图 2 所示连接起来。在下面的图中我们可以看到有两个初始时间序列 Y1 和 Y2它们的长度相同我们再次选择窗口大小为 2 来进行转换。一旦每个序列像一元示例中那样被转换我们只需将它们连接起来就得到了 X*T 为(t-2 x 2n)和 Y_T 为(t-n x 2)。https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/dd41a26c4b278a0bdc271cd1dc5f93a2.png图 4多元窗口转换如果我们只有一个想要预测的时间序列和一个外生序列我们可以在图 2 中进行相同的转换但我们的 Y_T 将只有一列而不是两列。例如如果我们想预测空气质量作为响应变量并且有一个与响应变量相关的外生变量如通勤里程但我们不感兴趣进行预测。应用数据转换现在我们将数据窗口化过程应用到我们的数据集上。在这种情况下我们的基础数据集有 2 列我们想要预测的标签为‘meantemp’和‘humidity’以及一个日期列如图 1 所示。我们首先将应用 Min-Max 缩放器以确保每一列都在相同的尺度上并提高模型性能。与传统的 ARIMA 过程不同神经网络不需要数据集是平稳的来进行预测然而标准化和归一化已被证明可以显著提高性能[3]。# creating scalarscalerMinMaxScaler(feature_range(0,1))# normalizing target columnsforcolinids:formatted_df[col]scaler.fit_transform(formatted_df[[col]])formatted_df.head(10)https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/bab2933472190375f66803358a81d1c6.png图 5缩放数据集接下来我们将我们的数据集分为测试集和训练集我们的数据已经按日期升序排序因此我们可以将数据集的前部分作为我们的训练集后部分作为测试集。注意当处理时间序列数据时确保数据按时间排序并分割是至关重要的这样我们就不会有未来数据泄露到过去。# setting test/train ratiototal_observationslen(formatted_df)train_ratio0.7# performing time based test/train splittrain_dfformatted_df[:int(total_observations*train_ratio)]test_dfformatted_df[int(total_observations*train_ratio):]print(len(train_df),len(test_df))最后我们需要将我们的数据从标准时间序列格式转换为窗口格式如图 3 和图 4 所示。为此我们定义了 2 个辅助函数convert_to_supervised它将一维时间序列转换为窗口格式以及 rename_dataframe_supervised它更新列名为 T-1T-2…T-n。defconvert_to_supervised(data,window_size1,forecast_size1,dropnanTrue):Converts a 1d time series dataset into a 2d supervised learning formatdfpd.DataFrame(data)colslist()# Training sequence: t-window_size, ..., t-1foriinrange(window_size,0,-1):cols.append(df.shift(i))# Forecast sequence: (t, t1, ... tforecast_size)foriinrange(0,forecast_size):cols.append(df.shift(-i))# Concatenating columns togetheraggpd.concat(cols,axis1)# drop rows with NaN valuesifdropnan:agg.dropna(inplaceTrue)returnagg.valuesdefrename_dataframe_supervised(data_df,state_name):Takes a dataframe with column names 1-x, relables them as t through t - x and returns. Used to illustrate how the timeseries to supervised conversion works# Renaming columns in dataframemax_colmax(data_df.columns.astype(int))forcolindata_df.columns:ifint(col)max_col:data_df.rename(columns{col:t},inplaceTrue)else:data_df.rename(columns{col:{state}t - {val}.format(statestate_name,valmax_col-col)},inplaceTrue)returndata_df在定义了辅助函数之后我们现在可以通过迭代每个序列在这种情况下是‘meantemp’和‘humidity’来转换我们的数据将序列转换为监督格式重命名它然后将它连接到一个 numpy 数组。timesteps6featureslen(ids)count0# Storing resultstrain_x_all,test_x_allnp.array([]),np.array([])train_y_all,test_y_allnp.array([]),np.array([])# Iterating through each series of interestforvalinids:train_vals,test_valstrain_df[val].values,test_df[val].values# Transforming to time seriestrain_data,test_dataconvert_to_supervised(train_vals,window_sizetimesteps),convert_to_supervised(test_vals,window_sizetimesteps)# Converting to dataframetrain_df_sup,test_df_suprename_dataframe_supervised(pd.DataFrame(train_data)),rename_dataframe_supervised(pd.DataFrame(test_data))# Separating x and ytrain_y,train_xtrain_df_sup[t].to_numpy(),train_df_sup.drop(columns[t]).to_numpy()test_y,test_xtest_df_sup[t].to_numpy(),test_df_sup.drop(columns[t]).to_numpy()ifcount0:train_x_alltrain_x train_y_alltrain_y test_x_alltest_x test_y_alltest_yelse:train_x_allnp.concatenate((train_x_all,train_x),axis1)train_y_allnp.stack((train_y_all,train_y),axis0)test_x_allnp.concatenate((test_x_all,test_x),axis1)test_y_allnp.stack((test_y_all,test_y),axis0)count1train_y_alltrain_y_all.T test_y_alltest_y_all.Tprint(Y-Train Shape: ,train_y_all.shape)print(X-Train Shape: ,train_x_all.shape)在执行上述转换后我们想要通过检查 X/Y 训练集来验证我们的数据是否处于正确的格式。我们的原始数据集有 1462 个观测值使用其中的 70%作为训练集我们预计会有 1023 个训练观测值但由于我们的窗口大小我们会丢失 6 个。因此我们的新训练集应该有 1017 行Y 集和 X 集各有 2 和 12 列。这正是我们在图 4 中看到的内容因此我们可以继续。https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/e77f40a5037ed241705bff02d0c2ad6f.png图 6输出数据维度在我们继续进行模型训练之前我们需要进行最后一次数据转换。我们一直在以二维形式重塑我们的数据然而我们的神经网络期望 X 是一个三维数组其中第三个维度是预测到未来的时间步数。在这种情况下我们只对预测一个时间步到未来感兴趣因此我们可以将我们的数据框重塑如下(1017 x 12) - (1017 x 1 x 12)。我们的最终 X 格式将是一个三维 numpy 数组维度为[行观测值x 时间步 x 列特征]。现在复杂的部分已经完成我们准备进入建模阶段# need data formatted as [rows x timesteps into future x columns]train_x_allnp.reshape(train_x_all,(train_x_all.shape[0],1,train_x_all.shape[1]))test_x_allnp.reshape(test_x_all,(test_x_all.shape[0],1,test_x_all.shape[1]))# checking shapeprint(Train X shape:,train_x_all.shape)print(Test X shape:,test_x_all.shape)https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/6919d319f36b1028d87926921bb57cf3.png图 7最终数据形状开发我们的第一个模型深度神经网络现在我们已经将数据转换成所需的窗口格式我们准备定义和训练我们的第一个模型。首先我们将使用一个基本的深度神经网络具有两个隐藏层。与假设线性关系的传统方法如 ARIMA/SARIMA不同深度神经网络可以模拟非线性时间序列这可以根据数据集具有显著的优势[1]。因为我们将比较多种模型类型所以我们的第一步是定义一个 train_and_predict 函数如下所示这个函数接受一个模型编译并拟合它然后进行预测并返回结果。要使用这个模型与深度神经网络我们定义我们的模型在每个密集隐藏层中使用 16 个神经元并指定 relu 激活函数。然后我们将模型传递给我们的训练和预测函数该函数返回结果。由于我们的神经网络较小我们可以在图 8 的插图中展示它。因为我们选择了窗口大小为 6并且有两个序列所以我们将有总共 12 个输入由输入层的 12 个神经元表示然后我们有我们的 2 个密集隐藏层最后是我们的两个输出每个序列一个。这个网络的一个重要特征是每个输入神经元都与第一隐藏层中的每个神经元相连这意味着我们的模型实际上正在使用 Series B 的数据来帮助预测 Series A反之亦然。这是使用统一模型而不是单独模型的一个显著优势如果两个序列之间存在关系我们可以捕捉到这一点并利用它来提高我们的整体预测性能。https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/e5394b69bb7677148598a662e231e362.png图 8DNN 示例定义我们的模型# defining DNN modelunits64model_dnnSequential()model_dnn.add(Dense(unitsunits,activationrelu))model_dnn.add(Dense(unitsunits,activationrelu))model_dnn.add(Dense(features))epochs100# training model and returning predictionstrainPredict_dnn,testPredict_dnn,trainY,testYtrain_and_predict(model_dnn,train_x_all,test_x_all,train_y_all,test_y_all,epochs)定义我们的训练和预测函数我们将模型传递给它们deftrain_and_predict(model,train_x_all,test_x_all,train_y_all,test_y_all,epochs):# compiling and fitting modelmodel.compile(lossmean_absolute_error,optimizeradam)model.fit(train_x_all,train_y_all,epochsepochs,batch_size1,verbose3)# make predictionstrainPredictmodel.predict(train_x_all).reshape(train_y_all.shape[0],features)testPredictmodel.predict(test_x_all).reshape(test_y_all.shape[0],features)# inverting predictions back to initial scaletrainPredictscaler.inverse_transform(trainPredict)trainYscaler.inverse_transform(train_y_all)testPredictscaler.inverse_transform(testPredict)testYscaler.inverse_transform(test_y_all)returntrainPredict,testPredict,trainY,testY现在我们已经成功训练了我们的深度神经网络并使用它进行预测但我们需要一个方法来评估其性能。为此我们定义了一个 plot_comparison 函数它接受我们的预测和真实标签然后绘制每个预测值与实际序列的对比图并计算每个序列的均方根误差MAPE。defplot_comparison(train_pred,test_pred,train_y,test_y,dates,model_type):factor_levelstrain_pred.shape[1]figmake_subplots(rowsfactor_levels,cols1,subplot_titles(Plot 1,Plot 2))mapes[]# iterating through factor levelsforlevelinrange(factor_levels):fig.layout.annotations[level].update(textUpdated Plot 1)# defining dates for x axistrain_datesdates[:train_pred.shape[0]]test_datesdates[-test_pred.shape[0]:]fig.append_trace(go.Scatter(xtrain_dates,ytrain_y[:,level],modelines,nameActual-Train),rowlevel1,col1)# test setfig.append_trace(go.Scatter(xtest_dates,ytest_y[:,level],modelines,nameActual-Test),rowlevel1,col1)# train predfig.append_trace(go.Scatter(xtrain_dates,ytrain_pred[:,level],modemarkers,namePred-Train),rowlevel1,col1)# test predfig.append_trace(go.Scatter(xtest_dates,ytest_pred[:,level],modemarkers,namePred-Test),rowlevel1,col1)# calculating mape on test set and updating titlemaperound(mean_absolute_percentage_error(test_y[:,level],test_pred[:,level]),4)fig.layout.annotations[level].update(textSeries {series}, Test MAPE, {mape}.format(mapemape,serieslevel1))mapes.append(mape)fig.update_layout(height600,width600,title_text{model_type}, Forecast By Series, Avg MAPE {mape}.format(model_typemodel_type,maperound(sum(mapes)/len(mapes),4)))fig.show()现在我们可以调用我们的 plot_comparison 函数来评估深度神经网络的表现。# graphing datadatesformatted_df[Date].sort_values(ascendingTrue).drop_duplicates().to_list()model_typeDNNplot_comparison(trainPredict_dnn,testPredict_dnn,trainY,testY,dates,model_type)在图 9 中我们可以看到这次评估的结果显示了每个序列‘meantemp’和‘humidity’的测试集和训练集的预测值与实际值。我们可以看到我们模型的预测值是实际值的合理近似两个序列的整体平均绝对百分比误差MAPE为 0.0847。恭喜我们现在已经训练并评估了我们的第一个神经网络预测器https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/961026ceed4a1f847509b58d658ca7b0.png图 9DNN 预测性能RNN 和 LSTM 以及概述现在我们已经训练并评估了我们的第一个模型但想看看我们是否可以改进进入 LSTM。首先是一些快速背景什么是 LSTM长短期记忆以及为什么它可能优于基本的前馈神经网络LSTM 是一种递归神经网络RNN一种将信息反馈到自身的网络这使得它具有一种“记忆”形式这在数据顺序重要的问题中可能很有用如时间序列预测、自然语言处理、文本翻译等。基本结构如图 10 所示如果我们展开这个结构我们得到右侧的结构其中时间 0 的输入被馈送到时间 1然后被修改并发送到时间 2以此类推。更多信息可以在这里找到www.ibm.com/topics/recurrent-neural-networks。https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/dbfb3dbf9a30b0ce623b8584bf5f27fe.png图 10递归神经网络RNN结构作者fdeloche – 自有作品CC BY-SA 4.0虽然这听起来很棒但我们想训练一个 LSTM 而不是 RNN因为 RNN 可能会因为图 10 中显示的反馈循环而遭受梯度消失/爆炸问题。想象一下有一些初始输入 X0这个输入将在每个递归步骤中被某个权重 W 缩放。这将导致时间 t 的输出值等于图 11 中显示的公式。例如如果我们有 10 个递归步骤我们的权重是 2那么第 10 个神经元的输入将是 X0 * 2¹⁰或 1024 * X0这将压倒任何 Xt 值。或者如果权重小于 1梯度可能会消失因为小于 1 的值的大幂几乎等于 0。重要的是梯度消失和梯度爆炸问题可能会导致过去的事件在我们的模型中没有权重或者超过任何当前信号。https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/119032a8b56827e59e567fdecb006955.png图 11RNN 梯度函数LSTM 通过拥有两个记忆路径来设计以克服这个问题一个用于短期一个用于长期。这使得 LSTM 比基本的 RNN 更适合时间序列预测然而不幸的是这也使得基本的 LSTM 单元比 RNN 的单元复杂得多。在非常高的层面上LSTM 单元可以在图 12 中看到顶部路径输出的 Ct 代表长期记忆。你会注意到长期记忆项有一个乘法元素和一个加法元素来修改值但是没有权重来避免我们与基本 RNN 看到的梯度消失/爆炸问题。图 12 底部路径输出的 Ht 代表我们的短期记忆与我们的长期记忆不同它确实有可以修改它的权重。然而因为这个路径仅用于短期并且不会多次复合所以我们不应该看到梯度爆炸或消失。短期和长期记忆之间还有更多组件和交互作用这些超出了本文的范围。如果感兴趣我最喜欢的 LSTM 结构解释来自 StatQuestwww.youtube.com/watch?vYCzL96nL7j0。对我们来说重要的是要知道LSTM 被设计来克服 RNN 的不足并且在许多应用中已被证明优于传统的 ARIMA 方法和深度神经网络 [2]。…/Images/6f98687fab04d389a2ab69c2cf81b5ae.png图 12LSTM 单元结构由 Guillaume Chevalier 绘制授权于 Creative Commons [4]。训练 LSTM现在我们已经简要概述了 LSTM 背后的理论我们可以继续实施一个 LSTM幸运的是由于 tensorflow 的魔力这要容易得多。我们下面定义了一个简单的顺序模型并添加了一个 LSTM 层和一个 Dense 层来提供输出。在这种情况下我们将我们的时间步长定义为 1因为我们只对进行 1 个时间步长的预测感兴趣并将特征定义为 2因为我们对预测的两个序列感兴趣。最后我们将我们的模型传递给与 DNN 使用的相同的 train_and_predict 函数。# defining lstm modelunits8model_lstmSequential()model_lstm.add(LSTM(units,input_shape(1,int(timesteps*features))))model_lstm.add(Dense(features))epochs100# training model and returning predictionstrainPredict_lstm,testPredict_lstm,trainY,testYtrain_and_predict(model_lstm,train_x_all,test_x_all,train_y_all,test_y_all,epochs)在做出我们的预测之后我们想要检查结果并看看我们的 LSTM 相对于 DNN 的表现如何。为此可以简单地调用之前使用的相同 plot_comparison 方法。这些结果如图 13 所示与我们的深度神经网络类似LSTM 预测紧密地反映了我们的实际值我们可以看到我们的平均 MAPE 甚至更低 0.0812 比 0.0847。我们的长短期记忆网络LSTM优于我们的深度神经网络DNN。# graphing datadatesformatted_df[Date].sort_values(ascendingTrue).drop_duplicates().to_list()model_typeLSTMplot_comparison(trainPredict_lstm,testPredict_lstm,trainY,testY,dates,model_type)https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/a3cff4a9deb22ce5a54a7e7dbbf0c683.png图 13LSTM 预测性能总结多变量时间序列预测可能很容易变成一项复杂的任务因为不同的时间序列需要不同的模型并且需要跟踪和维护这些模型。正如本文所示神经网络可以提供一个简单的多输出解决方案使得可以同时预测多个序列。这减少了我们需要训练的模型数量并允许我们的模型在两个序列之间存在相关性时使用一个序列来帮助预测另一个序列。最终没有灵丹妙药你应该使用最适合你用例的模型但神经网络可以是非常有用的工具对于时间序列预测应该在任何工具箱中。引用Casolaro, A.Capone, V.Iannuzzo, G. Camastra, F. (2023)。深度学习在时间序列预测中的应用进展与开放问题。信息14(11)598。doi.org/10.3390/info14110598S. Siami-NaminiN. Tavakoli 和 A. Siami Namin“ARIMA 和 LSTM 在时间序列预测中的比较”2018 年第 17 届 IEEE 国际机器学习与应用会议ICMLA佛罗里达州奥兰多2018 年第 1394–1401 页doi10.1109/ICMLA.2018.00227。关键词{时间序列分析预测预测模型自回归过程经济学深度学习数据模型深度学习长短期记忆LSTM自回归积分移动平均ARIMA预测时间序列数据}Tawakuli, A.Havers, B.Gulisano, V.Kaiser, D. Engel, T. (2024)。调查时间序列数据预处理调查和实证分析。工程研究杂志。doi.org/10.1016/j.jer.2024.02.018长短期记忆。 (2024 年 10 月 17 日)。在维基百科。en.wikipedia.org/wiki/Long_short-term_memory循环神经网络。 (2024, 10 月 24 日)。在维基百科。en.wikipedia.org/wiki/Recurrent_neural_network资源数据来源www.kaggle.com/datasets/sumanthvrao/daily-climate-time-series-data本文的代码在 Github 上github.com/pinstripezebra/forecasting/blob/main/Neural%20Network%20Forecast%20-%20Simple.ipynbKeras 中的 LSTM 实现keras.io/api/layers/recurrent_layers/lstm/LSTM 的简要说明colah.github.io/posts/2015-08-Understanding-LSTMs/涵盖 LSTM 架构的 YouTube 视频www.youtube.com/watch?vYCzL96nL7j0***图表和图形*除非另有说明所有图像均由作者提供。