时间序列预测(Python):ARIMA、LSTM、 Prophet
本文主要对时间序列数据进行预测。我们将用Python构建三个不同的模型,并检查它们的结果。我们将使用的模型有ARIMA(差分整合移动平均自回归模型)、LSTM(长短期记忆神经网络)和Facebook Prophet。
ARIMA
ARIMA是一个用于预测未来趋势的时间序列数据模型。模型是回归分析的一种形式。
- AR(Autoregression):显示变量变化的模型,该变量在其自身的滞后/先验值上回归。
- I(Integrated):差分时间序列的原始观测数据,使其平稳
- MA(Moving average):观察值与移动平均模型的残差之间的依赖关系
对于ARIMA模型,标准的表示法是带有p、d和q的ARIMA,其中整数值替代参数来表示所使用的ARIMA模型的类型。
- p:自回归阶数
- d:差分次数
- q:移动平均阶数
LSTM神经网络
LSTM代表长短期记忆。它是一种扩展了循环神经网络记忆的模型或体系结构。通常,循环神经网络具有“短期记忆”,因为它们使用在当前神经网络中使用的持久先前信息。实质上,先前的信息用于当前任务。这意味着我们没有可用于神经节点的所有先前信息的列表。LSTM将长期记忆引入循环神经网络。它缓解了梯度消失问题,也就是神经网络停止学习的地方,因为给定神经网络内各种权重的更新变得越来越小。它通过使用一系列“门(Gate)”来实现这一点。它们包含在通过层连接的内存块中,如下所示:
LSTM工作单元内有三种类型的门:Input Gate、Output Gate、Forget Gate。每个门就像一个控制读/写的开关,从而将长期记忆功能整合到模型中。
Prophet
Prophet是一种基于加法模型预测时间序列数据的过程,其中非线性趋势与年、周、日季节性以及假日效应相吻合。它最适用于具有强烈季节效应和几个季节的历史数据的时间序列。Prophet对缺失的数据和趋势的变化是健壮的,通常能很好地处理异常值。
Python实现
读取机器学习数据集
机器学习数据集地址:https://www.kaggle.com/shenba/time-series-datasets
import numpy as np import pandas as pd from statsmodels.tsa.statespace.sarimax import SARIMAX from statsmodels.graphics.tsaplots import plot_acf,plot_pacf from statsmodels.tsa.seasonal import seasonal_decompose from pmdarima import auto_arima from sklearn.metrics import mean_squared_error from statsmodels.tools.eval_measures import rmse import warnings warnings.filterwarnings("ignore") df = pd.read_csv('monthly-beer-production-in-austr.csv') df.head()
df.info()
df.Month = pd.to_datetime(df.Month) df = df.set_index("Month") df.head()
df.index.freq = 'MS' ax = df['Monthly beer production'].plot(figsize = (16,5), title = "Monthly Beer Production") ax.set(xlabel='Dates', ylabel='Total Production');
当我们看情节时,我们可以看到数据存在季节性。这就是为什么我们将使用SARIMA(季节性ARIMA)而不是ARIMA。
SARIMA是ARIMA的扩展,它显式地支持带有季节性成分的单变量时间序列数据。它添加了三个新的超参数来指定序列的季节成分的自回归(AR)、差分(I)和移动平均(MA),以及季节性周期的附加参数。
有四个不属于ARIMA的季节性元素必须配置; 他们是:
- P: 季节性自回归阶数。
- D: 季节性差分次数。
- Q: 季节性移动平均阶数。
- m: 单个季节性时段的时间步长。
a = seasonal_decompose(df["Monthly beer production"], model = "add") a.plot();
import matplotlib.pyplot as plt plt.figure(figsize = (16,7)) a.seasonal.plot();
ARIMA预测
让我们运行aauto_arima()函数来获得最佳的p,d,q,P,D,Q值
auto_arima(df['Monthly beer production'], seasonal=True, m=12,max_p=7, max_d=5,max_q=7, max_P=4, max_D=4,max_Q=4).summary()
我们可以看到auto_arima()选择的最佳arima模型是SARIMAX(2,1,1)x(4,0,3,12)
让我们将机器学习数据集分成训练和测试集
train_data = df[:len(df)-12] test_data = df[len(df)-12:] arima_model = SARIMAX(train_data['Monthly beer production'], order = (2,1,1), seasonal_order = (4,0,3,12)) arima_result = arima_model.fit() arima_result.summary()
arima_pred = arima_result.predict(start = len(train_data), end = len(df)-1, typ="levels").rename("ARIMA Predictions") arima_pred
test_data['Monthly beer production'].plot(figsize = (16,5), legend=True) arima_pred.plot(legend = True);
arima_rmse_error = rmse(test_data['Monthly beer production'], arima_pred) arima_mse_error = arima_rmse_error**2 mean_value = df['Monthly beer production'].mean() print(f'MSE Error: {arima_mse_error} RMSE Error: {arima_rmse_error} Mean: {mean_value}')
test_data['ARIMA_Predictions'] = arima_pred
LSTM预测
首先,我们将使用MinMaxScaler缩放我们的训练和测试数据
from sklearn.preprocessing import MinMaxScaler scaler = MinMaxScaler() scaler.fit(train_data) scaled_train_data = scaler.transform(train_data) scaled_test_data = scaler.transform(test_data)
在创建LSTM模型之前,我们应该创建一个时间序列生成器对象。
from keras.preprocessing.sequence import TimeseriesGenerator n_input = 12 n_features= 1 generator = TimeseriesGenerator(scaled_train_data, scaled_train_data, length=n_input, batch_size=1) from keras.models import Sequential from keras.layers import Dense from keras.layers import LSTM lstm_model = Sequential() lstm_model.add(LSTM(200, activation='relu', input_shape=(n_input, n_features))) lstm_model.add(Dense(1)) lstm_model.compile(optimizer='adam', loss='mse') lstm_model.summary()
lstm_model.fit_generator(generator,epochs=20)
losses_lstm = lstm_model.history.history['loss'] plt.figure(figsize=(12,4)) plt.xlabel("Epochs") plt.ylabel("Loss") plt.xticks(np.arange(0,21,1)) plt.plot(range(len(losses_lstm)),losses_lstm);
lstm_predictions_scaled = list() batch = scaled_train_data[-n_input:] current_batch = batch.reshape((1, n_input, n_features)) for i in range(len(test_data)): lstm_pred = lstm_model.predict(current_batch)[0] lstm_predictions_scaled.append(lstm_pred) current_batch = np.append(current_batch[:,1:,:],[[lstm_pred]],axis=1)
我们对数据进行了缩放,这就是为什么我们要对它进行逆运算才能看到真实的预测。
lstm_predictions_scaled
lstm_predictions = scaler.inverse_transform(lstm_predictions_scaled) lstm_predictions
test_data['LSTM_Predictions'] = lstm_predictions test_data
test_data['Monthly beer production'].plot(figsize = (16,5), legend=True) test_data['LSTM_Predictions'].plot(legend = True);
lstm_rmse_error = rmse(test_data['Monthly beer production'], test_data["LSTM_Predictions"]) lstm_mse_error = lstm_rmse_error**2 mean_value = df['Monthly beer production'].mean() print(f'MSE Error: {lstm_mse_error} RMSE Error: {lstm_rmse_error} Mean: {mean_value}')
Prophet预测
df.info()
df_pr = df.copy() df_pr = df.reset_index() df_pr.columns = ['ds','y'] # To use prophet column names should be like that train_data_pr = df_pr.iloc[:len(df)-12] test_data_pr = df_pr.iloc[len(df)-12:] from fbprophet import Prophet m = Prophet() m.fit(train_data_pr) future = m.make_future_dataframe(periods=12,freq='MS') prophet_pred = m.predict(future) prophet_pred.tail()
prophet_pred = pd.DataFrame({"Date" : prophet_pred[-12:]['ds'], "Pred" : prophet_pred[-12:]["yhat"]}) prophet_pred = prophet_pred.set_index("Date") prophet_pred.index.freq = "MS" prophet_pred
test_data["Prophet_Predictions"] = prophet_pred['Pred'].values import seaborn as sns plt.figure(figsize=(16,5)) ax = sns.lineplot(x= test_data.index, y=test_data["Monthly beer production"]) sns.lineplot(x=test_data.index, y = test_data["Prophet_Predictions"]);
prophet_rmse_error = rmse(test_data['Monthly beer production'], test_data["Prophet_Predictions"]) prophet_mse_error = prophet_rmse_error**2 mean_value = df['Monthly beer production'].mean() print(f'MSE Error: {prophet_mse_error} RMSE Error: {prophet_rmse_error} Mean: {mean_value}')
rmse_errors = [arima_rmse_error, lstm_rmse_error, prophet_rmse_error] mse_errors = [arima_mse_error, lstm_mse_error, prophet_mse_error] errors = pd.DataFrame({"Models" : ["ARIMA", "LSTM", "Prophet"],"RMSE Errors" : rmse_errors, "MSE Errors" : mse_errors}) plt.figure(figsize=(16,9)) plt.plot_date(test_data.index, test_data["Monthly beer production"], linestyle="-") plt.plot_date(test_data.index, test_data["ARIMA_Predictions"], linestyle="-.") plt.plot_date(test_data.index, test_data["LSTM_Predictions"], linestyle="--") plt.plot_date(test_data.index, test_data["Prophet_Predictions"], linestyle=":") plt.legend() plt.show()
print(f"Mean: {test_data['Monthly beer production'].mean()}") errors
test_data
这只是最基本的模型预测,您可以根据您的数据和业务知识通过调整来改进这些模型。