集成时间序列模型提高预测精度
Posted deephub
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了集成时间序列模型提高预测精度相关的知识,希望对你有一定的参考价值。
使用Catboost从RNN、ARIMA和Prophet模型中提取信号进行预测
集成各种弱学习器可以提高预测精度,但是如果我们的模型已经很强大了,集成学习往往也能够起到锦上添花的作用。流行的机器学习库scikit-learn提供了一个StackingRegressor,可以用于时间序列任务。但是StackingRegressor有一个局限性;它只接受其他scikit-learn模型类和api。所以像ARIMA这样在scikit-learn中不可用的模型,或者来自深度神经网络的模型都无法使用。在这篇文章中,我将展示如何堆叠我们能见到的模型的预测。
我们将用到下面的包:
pip install --upgrade scalecast
conda install tensorflow
conda install shap
conda install -c conda-forge cmdstanpy
pip install prophet
数据集
数据集每小时一次,分为训练集(700个观测值)和测试集(48个观测值)。下面代码是读取数据并将其存储在Forecaster对象中:
importpandasaspd
importnumpyasnp
fromscalecast.ForecasterimportForecaster
fromscalecast.utilimportmetrics
importmatplotlib.pyplotasplt
importseabornassns
defread_data(idx='H1', cis=True, metrics= ['smape']):
info=pd.read_csv(
'M4-info.csv',
index_col=0,
parse_dates=['StartingDate'],
dayfirst=True,
)
train=pd.read_csv(
f'Hourly-train.csv',
index_col=0,
).loc[idx]
test=pd.read_csv(
f'Hourly-test.csv',
index_col=0,
).loc[idx]
y=train.values
sd=info.loc[idx,'StartingDate']
fcst_horizon=info.loc[idx,'Horizon']
cd=pd.date_range(
start=sd,
freq='H',
periods=len(y),
)
f=Forecaster(
y=y, # observed values
current_dates=cd, # current dates
future_dates=fcst_horizon, # forecast length
test_length=fcst_horizon, # test-set length
cis=cis, # whether to evaluate intervals for each model
metrics=metrics, # what metrics to evaluate
)
returnf, test.values
f, test_set=read_data()
f# display the Forecaster object
结果是这样的:
模型
在我们开始构建模型之前,我们需要从中生成最简单的预测,naive方法就是向前传播最近24个观测值。
f.set_estimator('naive')
f.manual_forecast(seasonal=True)
然后使用ARIMA、LSTM和Prophet作为基准。
ARIMA
Autoregressive Integrated Moving Average 是一种流行而简单的时间序列技术,它利用序列的滞后和误差以线性方式预测其未来。通过EDA,我们确定这个系列是高度季节性的。所以最终选择了应用order (5,1,4) x(1,1,1,24)的季节性ARIMA模型。
f.set_estimator('arima')
f.manual_forecast(
order = (5,1,4),
seasonal_order = (1,1,1,24),
call_me = 'manual_arima',
)
LSTM
如果说ARIMA是时间序列模型中比较简单的一种,那么LSTM就是比较先进的方法之一。它是一种具有许多参数的深度学习技术,其中包括一种在顺序数据中发现长期和短期模式的机制,这在理论上使其成为时间序列的理想选择。这里使用tensorflow建立这个模型
f.set_estimator('rnn')
f.manual_forecast(
lags=48,
layers_struct=[
('LSTM','units':100,'activation':'tanh'),
('LSTM','units':100,'activation':'tanh'),
('LSTM','units':100,'activation':'tanh'),
],
optimizer='Adam',
epochs=15,
plot_loss=True,
validation_split=0.2,
call_me='rnn_tanh_activation',
)
f.manual_forecast(
lags=48,
layers_struct=[
('LSTM','units':100,'activation':'relu'),
('LSTM','units':100,'activation':'relu'),
('LSTM','units':100,'activation':'relu'),
],
optimizer='Adam',
epochs=15,
plot_loss=True,
validation_split=0.2,
call_me='rnn_relu_activation',
)
Prophet
尽管它非常受欢迎,但有人声称它的准确性并不令人印象深刻,主要是因为它对趋势的推断有时候很不切实际,而且它没有通过自回归建模来考虑局部模式。但是它也有自己的特点。1,它会自动将节日效果应用到模型身上,并且还考虑了几种类型的季节性。可以以用户所需的最低需求来完成这一切,所以我喜欢把它用作信号,而不是最终的预测结果。
f.set_estimator('prophet')
f.manual_forecast()
比较结果
现在我们已经为每个模型生成了预测,让我们看看它们在验证集上的表现如何,验证集是我们训练集中的最后48个观察结果。
results=f.export(determine_best_by='TestSetSMAPE')
ms=results['model_summaries']
ms[
[
'ModelNickname',
'TestSetLength',
'TestSetSMAPE',
'InSampleSMAPE',
]
]
每个模型的表现都优于naive方法。ARIMA模型表现最好,百分比误差为4.7%,其次是Prophet模型。让我们看看所有的预测与验证集的关系:
f.plot(order_by="TestSetSMAPE",ci=True)
plt.show()
所有这些模型在这个时间序列上的表现都很合理,它们之间没有很大的偏差。下面让我们把它们堆起来!
堆叠模型
每个堆叠模型都需要一个最终估计器,它将过滤其他模型的各种估计,创建一组新的预测。我们将把之前结果与Catboost估计器叠加在一起。Catboost是一个强大的程序,希望它能从每个已经应用的模型中充实出最好的信号。
f.add_signals(
f.history.keys(), # add signals from all previously evaluated models
)
f.add_ar_terms(48)
f.set_estimator('catboost')
上面的代码将来自每个评估模型的预测添加到Forecaster对象中。它称这些预测为“信号”。 它们的处理方式与存储在同一对象中的任何其他协变量相同。 这里还添加了最后 48 个系列的滞后作为 Catboost 模型可以用来进行预测的附加回归变量。 现在让我们调用三种 Catboost 模型:一种使用所有可用信号和滞后,一种仅使用信号,一种仅使用滞后。
f.manual_forecast(
Xvars='all',
call_me='catboost_all_reg',
verbose=False,
)
f.manual_forecast(
Xvars=[xforxinf.get_regressor_names() ifx.startswith('AR')],
call_me='catboost_lags_only',
verbose=False,
)
f.manual_forecast(
Xvars=[xforxinf.get_regressor_names() ifnotx.startswith('AR')],
call_me='catboost_signals_only',
verbose=False,
)
下面可以比较所有模型的结果。我们将研究两个度量:SMAPE和平均绝对比例误差(MASE)。这是实际M4比赛中使用的两个指标。
test_results=pd.DataFrame(index=f.history.keys(),columns= ['smape','mase'])
fork, vinf.history.items():
test_results.loc[k,['smape','mase']] = [
metrics.smape(test_set,v['Forecast']),
metrics.mase(test_set,v['Forecast'],m=24,obs=f.y),
]
test_results.sort_values('smape')
可以看到,通过组合来自不同类型模型的信号生成了两个优于其他估计器的估计器:使用所有信号训练的Catboost模型和只使用信号的Catboost模型。这两种方法的样本误差都在2.8%左右。下面是对比图:
fig, ax=plt.subplots(figsize=(12,6))
f.plot(
models= ['catboost_all_reg','catboost_signals_only'],
ci=True,
ax=ax
)
sns.lineplot(
x=f.future_dates,
y=test_set,
ax=ax,
label='held out actuals',
color='darkblue',
alpha=.75,
)
plt.show()
哪些信号最重要?
为了完善分析,我们可以使用shapley评分来确定哪些信号是最重要的。Shapley评分被认为是确定给定机器学习模型中输入的预测能力的最先进的方法之一。得分越高,意味着输入在特定模型中越重要。
f.export_feature_importance('catboost_all_reg')
上面的图只显示了前几个最重要的预测因子,但我们可以从中看出,ARIMA信号是最重要的,其次是序列的第一个滞后,然后是Prophet。RNN模型的得分也高于许多滞后模型。如果我们想在未来训练一个更轻量的模型,这可能是一个很好的起点。
总结
在这篇文章中,我展示了在时间序列上下文中集成模型的力量,以及如何使用不同的模型在时间序列上获得更高的精度。这里我们使用scalecast包,这个包的功能还是很强大的,如果你喜欢,可以去它的主页看看:
https://avoid.overfit.cn/post/cd910a41e6b94852b762cd6f2abf8b16
作者:Michael Keith
测试精度比实际输出高。如何提高实际输出精度?
【中文标题】测试精度比实际输出高。如何提高实际输出精度?【英文标题】:Testing Accuracy is high compared actual output. How to increase the actual output accuracy? 【发布时间】:2020-06-01 16:49:33 【问题描述】:我的逻辑预测模型为我提供了 80% 的训练准确度和 79% 的测试准确度。
训练模型准确率:0.8039535210772422 测试模型精度:0.7937496044721021
我的混淆矩阵给了我这些值:
使用超参数调整并打印我的分类报告:
precision recall f1-score support
0 0.87 0.88 0.87 172299
1 0.77 0.70 0.74 17321
micro avg 0.85 0.85 0.85 189620
macro avg 0.77 0.74 0.76 189620
weighted avg 0.85 0.85 0.85 189620
当我将结果与实际数据进行比较时,我仅在 40% 的数据匹配上测试了预测模型。我怎样才能提高我的实际输出。
这是我的代码,任何建议都会很有帮助。
# Create the hyperparameter grid
c_space = np.logspace(-5, 8, 15)
log_param_grid = 'C': c_space, 'penalty': ['l1', 'l2']
# Setup the GridSearchCV object: logReg_cv
logReg=LogisticRegression()
logReg_cv = GridSearchCV(logReg,log_param_grid,cv=5)
y=predict_pi.P_I
X=pd.get_dummies(X)
test=pd.get_dummies(test)
extra_cols_train = [i for i in list(test) if i not in list(X)]
extra_cols_test = [i for i in list(X) if i not in list(test)]
X = X.reindex(columns=X.columns.tolist() + extra_cols_train)
X[extra_cols_train] = 0
test = test.reindex(columns=test.columns.tolist() + extra_cols_test)
test[extra_cols_test] = 0
X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.4,random_state=42)
logReg_cv.fit(X_train,y_train)
pred_pi=logReg_cv.predict(X_test)
test_pi=logReg_cv.predict(X_train)
print("Training Model Accuracy:".format(accuracy_score(y_train,test_pi)))
print("Testing Model Accuracy:".format(accuracy_score(y_test,pred_pi)))
print(confusion_matrix(y_test, pred_pi))
print(classification_report(y_test, pred_pi))
print("Tuned Logistic Regression Parameter: ".format(logReg_cv.best_params_))
print("Tuned Logistic Regression Accuracy: ".format(logReg_cv.best_score_))
【问题讨论】:
【参考方案1】:这可能意味着您的模型过度拟合了您的训练数据。您是否对实际数据进行过 EDA,以查看其行为是否符合您的预期,以及您的训练/测试数据是否真正代表您的实际数据。
您的训练集是实际数据的子集吗?我建议完全根据您的实际数据训练您的模型,使用您拥有的每一点数据进行训练。
当您测试您的模型时,我建议您使用交叉验证。当您确实喜欢对数据进行 5 倍或 10 倍的训练/测试时,您应该有一个不错的模型。
【讨论】:
以上是关于集成时间序列模型提高预测精度的主要内容,如果未能解决你的问题,请参考以下文章
Tensorflow的官方MNIST模型具有较高的训练精度,但预测性能较低
机器学习 Out-of-Fold 折外预测详解 | 使用折外预测 OOF 评估模型的泛化性能和构建集成模型