时间序列 – ARIMA vs. SARIMA vs. LSTM:动手教程
原文:
towardsdatascience.com/time-series-arima-vs-sarima-vs-lstm-hands-on-tutorial-bd5630298da3
.
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/9740fd65d260cffe20a725bc3a1dc5e8.png
图片由 Djim Loic 在 Unsplash 提供
在这篇文章中,我们将深入探讨时间序列预测的世界。预测未来的时间价值对各种企业来说都很有价值。例如,需求预测对在线零售商准备年终销售非常有帮助,以确保有足够的库存来满足即将到来的购物需求。在金融领域,股票交易者依赖复杂的预测模型来决定买卖哪些证券。在更基本的情况下,我们依赖天气预报来决定是否携带雨伞或雨衣出门上班。这些都是时间序列预测在我们的生活中扮演重要角色的系统例子。
在这篇文章中,我们将讨论在这个领域中最常用的三种时间序列预测模型:
自回归积分滑动平均或 ARIMA
季节性自回归积分滑动平均或 SARIMA
长短期记忆或 LSTM。
我们将通过实际操作来了解每个预测模型,通过训练模型并使用每个训练模型生成预测来学习。然后我们将查看常用于评估序列数据(如时间序列)的指标,最后可视化结果。
在深入细节之前,我将包括一个表格,展示这三个方法之间的比较,你可以将其作为未来的参考。如果你现在还认不出这个表格中的术语,请不要担心。在我们通过这篇文章学习之后,你将对时间序列预测术语更加熟练!
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/6339d77b5c7354e0de44db6f1ec008af.png
ARIMA、SARIMA 和 LSTMs 的比较
现在已经介绍完毕,让我们开始吧!
1. 数据集
为了实现我们的示例,我们将使用来自加州大学欧文分校机器学习存储库的开放源代码空气质量数据集,该数据集在CC BY 4.0 许可下可用。该数据集包括一段时间内的每小时空气质量水平,这使得它非常适合进行时间序列预测练习。我们的想法是看看我们根据过去的数据能够多好地预测一些空气质量水平。
让我们从导入必要的库、加载数据和查看前 5 行开始。
# import librariesimportpandasaspdimportnumpyasnp# load the dataset# https://archive.ics.uci.edu/dataset/360/air+qualityair_quality=pd.read_csv("AirQualityUCI.csv",sep=';',decimal=',')air_quality.head()结果
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/05ffe63cbb2d696c39076a1314e618b0.png
数据集概述
现在,让我们通过替换缺失值和删除一些列来清理数据。
# replace missing values and drop unnecessary columnsair_quality.replace(-200,np.nan,inplace=True)air_quality.dropna(axis=1,how='all',inplace=True)air_quality.dropna(inplace=True)# replace periods with colons in the 'Time' columnair_quality['Time']=air_quality['Time'].str.replace('.',':',regex=False)# combine date and time into a single datetime columnair_quality['DateTime']=pd.to_datetime(air_quality['Date']+' '+air_quality['Time'],dayfirst=True)# set 'DateTime' as the indexair_quality.set_index('DateTime',inplace=True)air_quality.sort_index(inplace=True)# select target variable (e.g., 'NOx(GT)')data=air_quality['NOx(GT)']# drop any remaining missing values in the target variabledata.dropna(inplace=True)接下来,在我们开始预测之旅之前,让我们先绘制数据并查看它。
# import librariesimportmatplotlib.pyplotasplt%matplotlib inline# visualizeplt.figure(figsize=(14,7))plt.plot(data.index,data.values)plt.title('Hourly NOx(GT) Levels')plt.xlabel('Date')plt.ylabel('NOx Concentration')plt.show()结果:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/17a4a17c3a501e61459ffe56dee0a535.png
按日期可视化的空气质量数据
最后,我们将数据分为训练集和测试集,就像我们会对任何机器学习任务做的那样。训练数据将被预测模型用来“学习”数据,然后我们将使用未见的测试集来评估训练模型的表现。
# break into train (80%) and testtrain_size=int(len(data)*0.8)train,test=data.iloc[:train_size],data.iloc[train_size:]print(f'Training set size:{len(train)}')print(f'Testing set size:{len(test)}')结果:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/8e51dc311f5f0a21390dce7d8cabfa9b.png
现在我们对数据有了更多的了解,我们可以继续进行预测任务。我们稍后会讨论数据模式,所以现在不必担心这一点。
2. 预测建模
在本节中,我们将开始使用 ARIMA、SARIMA 和 LSTM 进行建模。我们将分别在单独的章节中解释每一个,以便更容易跟随。让我们从 ARIMA 开始!
2.1. ARIMA
自回归积分滑动平均(ARIMA)是一种流行的时序预测方法,归功于统计学领域!它在简单的数据集中非常有帮助,但也可以用于预测非平稳(如下定义)时间序列,这使我们需要定义一些概念。让我们从什么是平稳数据开始。
**平稳性:**均值、方差和自相关等属性不会随时间变化。例如,这意味着时间序列的平均值(或均值)、分布(方差)以及不同时间点的值之间的关系保持不变。例如,在我家里,我将恒温器设定在 70 华氏度。空调会根据房间温度开启和关闭,试图将其保持在 70 度左右,因此我们预计一天中我房间温度的变化会围绕 70 度波动,并保持平均温度在这一点附近。我们有理由假设这个时间序列将是平稳的(我们通过空调强制使其如此)。
**非平稳性:**正如我们根据上面的定义所预期的,对于非平稳时间序列,相同的属性(均值、方差和自相关)会随时间变化。非平稳时间序列中可能有多种模式,所以让我们定义这些模式:
**趋势:**数据在一段时间内可以呈现上升或下降的轨迹(或方向)。想象一下,如果我在一个冬天的一天回家,室内温度是 30 度,然后我将恒温器设置为 70 度。让我们进一步假设房间达到 70 度需要 5 个小时,然后我们观察这 5 个小时的温度。我们会看到温度有一个上升的趋势或方向,从 30 度开始,到大约 70 度结束。让我们可视化这个情况!
# import librariesimportnumpyasnpimportmatplotlib.pyplotaspltfromsklearn.linear_modelimportLinearRegression# Parametersstart_temp=30end_temp=70hours=5time=np.linspace(0,hours,num=100)# 100 time points over 5 hours# Simulate temperature change with a linear upward trendtemperature=np.linspace(start_temp,end_temp,num=100)# add random noise to simulate slight fluctuations in the temperaturenoise=np.random.normal(0,1,temperature.shape)# mean=0, standard deviation=1temperature_with_noise=temperature+noise# add noise to the temperature trend# linear regression for the trend linetime_reshaped=time.reshape(-1,1)model=LinearRegression().fit(time_reshaped,temperature_with_noise)trend_line=model.predict(time_reshaped)# visualizeplt.figure(figsize=(10,6))plt.plot(time,temperature_with_noise,label='Room Temperature with Noise',color='b')plt.plot(time,trend_line,label='Trend Line',color='r',linestyle='--')plt.title("Temperature Trend Over Time")plt.xlabel("Time (hours)")plt.ylabel("Temperature (°F)")plt.grid(True)plt.legend()plt.show()结果:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/a59436503004e991e6d36d01c2eb1fdd.png
随时间温度上升趋势数据
**季节性:**意味着在(几乎)固定间隔内重复出现的模式。例如,假设一个在线零售商在前三个季度的销售额相对稳定,但销售额在第四季度往往会激增。那么这种每年重复出现的激增就代表了数据时间序列中的季节性。
**方差:**正如其名所示,它描述的是数据随时间变化而变化或波动的情形。
如上所述,从解释中可以猜到,预测平稳数据比非平稳数据更容易。非平稳时间序列的潜在模式不断变化,因此我们需要识别它们,然后进一步“转换”它们以提高我们预测模型的性能。将非平稳数据转换为平稳数据的一种方法称为“差分”。差分简单地说,就是我们将前一个数据点(或观察值)从当前数据点中减去,这可能会消除趋势等非平稳成分。为了确定时间序列中是否需要差分,可以使用各种测试,其中之一称为增强迪基-富勒(ADF)测试。出于本文的目的,我们不需要理解其背后的数学,但如果这个测试显示的 p 值大于 5%,则表明数据是非平稳的,因此需要差分。
现在我们对平稳和非平稳数据以及如何将后者转换为前者有了更多的了解,我们可以开始实施:
# import librariesfromstatsmodels.tsa.stattoolsimportadfuller# ADF testresult=adfuller(train)print('ADF Statistic:',result[0])print('p-value:',result[1])# if p-value > 0.05, the series is non-stationary and needs differencingifresult[1]>0.05:print("needs differencing")else:print("time series is stationary")结果:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/c4a438225491e55723e46c535aeb19e6.png
如上图所示,p 值大于 5%,因此数据是非平稳的,正如我们根据之前创建的数据集图表所预期的。我们将使用一阶差分将非平稳数据转换为平稳数据,然后进行验证以确保它是平稳的。
# first-order differencingtrain_diff=train.diff().dropna()# review stationarity againresult_diff=adfuller(train_diff)print('Differenced ADF Statistic:',result_diff[0])print('Differenced p-value:',result_diff[1])# if p-value > 0.05, the series is non-stationary and needs differencingifresult[1]>0.05:print("needs differencing")else:print("time series is stationary")结果:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/f9b9518c6c6e7f474ce4cf8ed35f088c.png
p 值仍然大于 5%,因此我们可以继续进行二阶差分,直到达到平稳状态。我想实现这一点,以便我们可以看到并理解差分是如何工作的,但在现实中,我们可以使用自动实现 ARIMA 并找到最佳参数的库,包括差分的顺序。所以让我定义在 ARIMA 模型中考虑的变量,然后我们将实现自动方法。ARIMA 模型有以下参数:
p代表自回归项的数量(ARIMA 中的“AR”部分)。例如,当 AR=1 时,当前值取决于立即前一个值。
d代表使序列平稳(ARIMA 中的“积分”或“I”部分)所需的不同次数。所以,如果 d=1,则只需要一阶差分。
q代表移动平均项的数量(ARIMA 中的“MA”部分)。如果 MA=1,当前值仅取决于前一步的错误。
这听起来优化起来相当手动,所以让我们将其交给自动优化器:
# import librariesimportpmdarimaaspm# create the optimization model instancemodel=pm.auto_arima(train,start_p=1,start_q=1,max_p=5,max_q=5,m=1,# frequency of series (set to 1 for non-seasonal data)d=None,# let the model determine 'd'seasonal=False,# assuming no seasonalitytest='adf',# use ADF test to find 'd'trace=True,error_action='ignore',suppress_warnings=True,stepwise=True)print(model.summary())结果:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/7c5ded9e35ba8208d57ac8ea7751a30e.png
ARIMA 模型摘要
有趣的是,优化器决定不需要差分就是一个足够好的选项。无论这是否是最佳方法,我们先实现它,然后再将性能与其他方法,如 SARIMA 和 LSTM 进行比较。
# import librariesfromstatsmodels.tsa.arima.modelimportARIMA# fit ARIMA modelarima_order=(2,0,0)arima_model=ARIMA(train,order=arima_order,trend='c')arima_result=arima_model.fit()# forecastarima_forecast=arima_result.forecast(steps=len(test))我们将在最后一起可视化所有结果,所以让我们继续到 SARIMA。
2.2. SARIMA
季节性自回归积分移动平均(Seasonal AutoRegressive Integrated Moving Average,SARIMA)是 ARIMA 的扩展,旨在更好地处理季节性时间序列数据。我们已经熟悉季节性,并且 ARIMA 下定义的大多数概念在这里仍然适用。这里唯一的区别在于,对于实现来说,季节性有新的参数,但这些参数也非常直观。我们定义 ARIMA 参数为“ARIMA(p, d, q)”。同样,我们定义“SARIMA(p, d, q, P, D, Q, m)”,其中 p、d 和 q 与之前相同,代表模型的非平稳部分,而 P、D 和 Q 控制季节性,m 代表完整季节周期的步数——例如,对于月度数据,m=12 将代表年度季节性。
让我们分解数据,看看是否有任何季节性。
# import librariesfromstatsmodels.tsa.seasonalimportseasonal_decompose# decompose the datadecomposition=seasonal_decompose(train,model='additive',period=24)# 24 hours in a daydecomposition.plot()plt.show()结果:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/4daa33d90f5bba2890387b7baf0df83b.png
通过趋势、季节性和残差分解的数据
我们可以看到一些季节性,也许使用 SARIMA 会得到更好的预测。让我们来实现。
fromstatsmodels.tsa.statespace.sarimaximportSARIMAX# fit SARIMA modelsarima_order=(2,0,0)# this is what we had in our ARIMA modelseasonal_order=(1,1,1,24)# daily seasonalitysarima_model=SARIMAX(train,order=sarima_order,seasonal_order=seasonal_order)sarima_result=sarima_model.fit(disp=False)# Forecastsarima_forecast=sarima_result.forecast(steps=len(test))作为下一步,我们将使用 LSTM 进行预测,然后比较整体预测结果。
2.3. LSTM
作为第三种方法,我们将探讨长短期记忆(LSTM)网络,这是一种循环神经网络(RNN)。这些 LSTM 在记住关于数据序列的信息方面非常有趣,这在时间序列中非常有用。由于反向传播中梯度的方式,传统的 RNN 方法无法记住太多关于过去的信息(这被称为梯度消失问题),导致这些网络更容易忘记,但我们不需要深入了解这些细节。我们只需要知道,在时间序列方面,LSTM 可以是非常强大的预测工具。缺点是 LSTM 计算成本更高,这在大型项目中是一个重要的考虑因素,但对我们的小问题来说不是问题。
让我们为我们的示例实现 LSTM(我在代码中添加了注释以使其更容易理解),然后最终查看结果以比较这三种方法。
# import librariesfromsklearn.preprocessingimportMinMaxScaler# scale data to improve performancescaler=MinMaxScaler(feature_range=(0,1))scaled_data=scaler.fit_transform(data.values.reshape(-1,1))# train and testing data splitsscaled_train=scaled_data[:train_size]scaled_test=scaled_data[train_size:]# function to create sequences for lstm (takes in data and returns x and y numpy array sequences)defcreate_sequences(data,seq_length):x=[]y=[]foriinrange(len(data)-seq_length):x.append(data[i:i+seq_length])y.append(data[i+seq_length])returnnp.array(x),np.array(y)seq_length=24# use past 24 hours to predict the next hourX_train,y_train=create_sequences(scaled_train,seq_length)X_test,y_test=create_sequences(scaled_test,seq_length)# import librariesfromtensorflow.keras.modelsimportSequentialfromtensorflow.keras.layersimportLSTM,Dense,Dropout# reshape input data to 3-dimensional that lstm expects (samples, timesteps, features)X_train=X_train.reshape((X_train.shape[0],X_train.shape[1],1))X_test=X_test.reshape((X_test.shape[0],X_test.shape[1],1))# build lstm modelmodel=Sequential()model.add(LSTM(50,activation='relu',input_shape=(seq_length,1)))model.add(Dropout(0.2))model.add(Dense(1))# compile the modelmodel.compile(optimizer='adam',loss='mean_squared_error')# train the modelhistory=model.fit(X_train,y_train,epochs=50,batch_size=32,validation_data=(X_test,y_test))# predictlstm_predictions=model.predict(X_test)lstm_predictions=scaler.inverse_transform(lstm_predictions)# adjust test values to align with predictionsadjusted_test_values=data.values[train_size+seq_length:]3. 性能比较
到目前为止,我们已经准备好了所有预测!无需更多延迟,让我们可视化预测结果并进行讨论。
# visualizeplt.figure(figsize=(14,7))# actualsplt.plot(test.index,test.values,label='Actual',color='black')# ARIMA predictionsplt.plot(test.index,arima_forecast,label='ARIMA Forecast',color='blue')# SARIMA predictionsplt.plot(test.index,sarima_forecast,label='SARIMA Forecast',color='green')# LSTM predictionsplt.plot(test.index[seq_length:],lstm_predictions,label='LSTM Forecast',color='red')plt.title('Actual vs. Predicted')plt.xlabel('Date')plt.ylabel('NOx Concentration')plt.legend()plt.show()结果:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/969d127936be7e04eccd5cd69a6fa4e4.png
预测比较 – ARIMA, SARIMA 和 LSTM 与实际值
我们可以看到“实际值”用黑色表示,因此预测值越接近黑色线条,这些预测就越好。正如我们所见,ARIMA 在这种情况下表现出较差的预测能力,随后 SARIMA 有所改进,而 LSTM 则显示出与实际值最佳拟合。视觉检查这些结果总是好的,但如果我们可以定义一些指标并对其进行定量测量那就更好了。为了做到这一点,我们可以查看以下指标:
- 平均绝对误差 (MAE):衡量预测值与实际值之间误差的平均绝对值,不考虑其方向。由于我们在计算中使用绝对值,因此不考虑方向,较低的值表示更好的模型性能。它可以描述如下:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/e9aad680f060b51644d837a011bff89b.png
- 均方根误差 (RMSE):与 MAE 非常相似,但给予较大误差更高的权重。它计算为实际值与预测值之间平方距离平均值的平方根(在看到公式后更容易理解)。由于实际值与预测值之间的差异是平方的,因此与 MAE 相比,它对异常值更敏感。与 MAE 类似,较低的值更好。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/94eb4ccad7c636106a3ae5a55d1b4281.png
- 平均绝对百分比误差 (MAPE):是预测值与实际值之间平均绝对百分比差异的计算。由于它是以另一种方式衡量实际值与预测值之间距离的方法,因此较低的百分比更好。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/527bdade601d74c8c644782419314e00.png
- 确定系数(R-squared):表示模型通过以下数学表示解释目标变量变异性程度的好坏。简而言之,它计算残差的平方和,这是实际值和预测值之间距离的度量,然后将其除以总平方和,即实际值的总方差。值范围从负无穷大到 1.0。接近 1.0 的值表示拟合度更好。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/28a41197638112d084d958363ace3a49.png
现在我们已经了解了指标,让我们计算我们三个预测模型的这些指标并分析结果。
# import librariesfromsklearn.metricsimportmean_absolute_error,mean_squared_error,r2_score# a function to evaluate our forecast models using mae, rmse, mape and r²defevaluate_model(test,forecast):mae=mean_absolute_error(test,forecast)rmse=np.sqrt(mean_squared_error(test,forecast))mape=np.mean(np.abs((test-forecast)/test))*100r2=r2_score(test,forecast)returnmae,rmse,mape,r2# evaluate our modelsarima_mae,arima_rmse,arima_mape,arima_r2=evaluate_model(test.values,arima_forecast.values)sarima_mae,sarima_rmse,sarima_mape,sarima_r2=evaluate_model(test.values,sarima_forecast.values)lstm_mae,lstm_rmse,lstm_mape,lstm_r2=evaluate_model(adjusted_test_values,lstm_predictions.flatten())# results data frameresults=pd.DataFrame({'Model':['ARIMA','SARIMA','LSTM'],'MAE':[arima_mae,sarima_mae,lstm_mae],'RMSE':[arima_rmse,sarima_rmse,lstm_rmse],'MAPE':[arima_mape,sarima_mape,lstm_mape],'R-squared':[arima_r2,sarima_r2,lstm_r2]})results结果:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/3c58f7292f155ca91b474a19c0fca652.png
预测比较摘要
现在我们可以比较这些模型了。全面来看,正如我们之前从图中看到的那样,与 ARIMA 和 SARIMA 相比,LSTM 做得更好。最后,让我们可视化残差,即实际值和预测数据点在时间序列中的距离。正如其名所示,我们希望残差尽可能接近零,这意味着预测值与实际值更接近。
# calculate residualsarima_residuals=test.values-arima_forecast.values sarima_residuals=test.values-sarima_forecast.values lstm_residuals=adjusted_test_values-lstm_predictions.flatten()# visualizeplt.figure(figsize=(14,7))plt.plot(test.index,arima_residuals,label='ARIMA Residuals',color='blue')plt.plot(test.index,sarima_residuals,label='SARIMA Residuals',color='green')plt.plot(test.index[seq_length:],lstm_residuals,label='LSTM Residuals',color='red')plt.axhline(y=0,color='black',linestyle='--')plt.title('Residuals of the Models')plt.xlabel('Date')plt.ylabel('Residuals')plt.legend()plt.show()结果:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/eec915a70c28807acb09d7ab13c44339.png
预测残差随时间比较 - ARIMA、SARIMA、LSTM 与实际值
4. 结论
在这篇帖子中,我们介绍了使用 ARIMA、SARIMA 和 LSTM 三种流行模型进行时间序列预测。在逐步实现这些模型的过程中,我们讨论了相关的时间序列概念,如趋势、季节性、平稳数据等。然后我们使用这些模型在测试集上进行预测,并使用相关指标和可视化进行比较。
感谢阅读!
如果你觉得这篇帖子有帮助,请在 Medium 上关注我并订阅以接收我的最新帖子!
(除非另有说明,所有图像均由作者提供。)
