Statsmodels:使用ARIMA实现直接和递归的多步预测策略

5
我目前正在尝试使用statsmodels ARIMA库实现直接和递归多步预测策略,这引发了一些问题。
递归多步预测策略将训练一个单步模型,预测下一个值,将预测值添加到输入到预测方法中的外生值的末尾并重复此操作。 这是我的递归实现:
def arima_forecast_recursive(history, horizon=1, config=None):
    # make list so can add / remove elements
    history = history.tolist()
    model = ARIMA(history, order=config)
    model_fit = model.fit(trend='nc', disp=0)

    for i, x in enumerate(history):
        yhat = model_fit.forecast(steps=1, exog=history[i:])
        yhat.append(history)
    return np.array(yhat)

def walk_forward_validation(dataframe, config=None):
    n_train = 52  # Give a minimum of 2 forecasting periods to capture any seasonality
    n_test = 26  # Test set should be the size of one forecasting horizon
    n_records = len(dataframe)
    tuple_list = []

    for index, i in enumerate(range(n_train, n_records)):
        # create the train-test split
        train, test = dataframe[0:i], dataframe[i:i + n_test]

        # Test set is less than forecasting horizon so stop here.
        if len(test) < n_test:
            break

        yhat = arima_forecast_recursive(train, n_test, config)
        results = smape3(test, yhat)
        tuple_list.append(results)

    return tuple_list

类似地,要执行直接策略,我只需要在可用的训练数据上适配我的模型,并使用该模型一次性预测总多步预测。我不确定如何使用statsmodels库实现这一点。
我的尝试(可以产生结果)如下:
def walk_forward_validation(dataframe, config=None):
    # This currently implements a direct forecasting strategy
    n_train = 52  # Give a minimum of 2 forecasting periods to capture any seasonality
    n_test = 26  # Test set should be the size of one forecasting horizon
    n_records = len(dataframe)
    tuple_list = []

    for index, i in enumerate(range(n_train, n_records)):
        # create the train-test split
        train, test = dataframe[0:i], dataframe[i:i + n_test]

        # Test set is less than forecasting horizon so stop here.
        if len(test) < n_test:
            break

        yhat = arima_forecast_direct(train, n_test, config)
        results = smape3(test, yhat)
        tuple_list.append(results)

    return tuple_list

def arima_forecast_direct(history, horizon=1, config=None):
    model = ARIMA(history, order=config)
    model_fit = model.fit(trend='nc', disp=0)
    return model_fit.forecast(steps=horizon)[0]

我困惑的是模型是应该只拟合一次来进行所有预测,还是为了进行多步预测而多次拟合?从Souhaib Ben Taieb博士论文(第35页第3段)中可以看出,直接模型将会估计H个模型,其中H是预测时间跨度的长度,因此在我的例子中,如果预测时间跨度为26,则需要估计26个模型而不仅仅是一个。如上所示,我目前的实现只拟合了一个模型。
我不理解的是,如果我在相同的训练数据上多次调用ARIMA.fit()方法,那么我将得到一个与预期正常随机变化之外任何不同的拟合吗?
我的最后一个问题与优化有关。使用像前向验证这样的方法给我带来了非常显著的统计结果,但对于许多时间序列来说,它的计算成本非常高。上述两种实现已经使用了joblib并行循环执行功能进行调用,这显著减少了我的笔记本电脑运行时间。然而,我想知道是否有任何方法可以使上述实现更加高效。当针对约2000个单独的时间序列(所有系列总共约500,000个数据点)运行这些方法时,运行时间为10小时。我已经对代码进行了分析,大部分执行时间都花费在statsmodels库中,这很好,但是walk_forward_validation()方法和ARIMA.fit()的运行时间之间存在差异。这是预期的,因为显然walk_forward_validation()方法不仅仅是调用fit方法,但如果其中的任何内容都可以更改以加快执行时间,请告诉我。这段代码的想法是找到每个时间序列的最佳ARIMA顺序,因为逐个调查2000个时间序列是不可行的,因此会对每个时间序列调用27次walk_forward_validation()方法。因此,无论发现该方法内部的任何性能节省有多小,都将产生影响。
1个回答

5
通常情况下,ARIMA 只能进行递归预测,而不能进行直接预测。可能有一些关于 ARIMA 直接预测的变体研究,但它们不会在 Statsmodels 中实现。在 statsmodels(或 R auto.arima())中,当您设置一个大于 1 的值 h 时,它只是执行递归预测以达到该值。
据我所知,目前没有标准的预测库实现了直接预测,您需要自己编写代码。
引用 Souhaib Ben Taieb 博士论文第 35 页第 3 段的说法,直接模型将估计 H 个模型,其中 H 是预测时间跨度的长度,因此在我的例子中,预测时间跨度为 26,应该估计 26 个模型,而不仅仅是一个。

我没有阅读Ben Taieb的论文,但从他的论文“机器学习策略用于时间序列预测”中了解到,对于直接预测,每个H值只有一个模型。因此,当H=26时,只有一个模型。如果您需要预测1到H之间的每个值,将会有H个模型,但对于一个H值,只有一个模型。


感谢您抽出时间回答。您提到标准预测库已经实现了递归预测策略,而不是直接预测策略。这是否意味着在我上面的实现中,直接方法实际上是一种递归策略,而我实际上根本不需要递归实现? - Aesir
1
@Aesir 是的,那是正确的。在 model_fit.forecast 中,.forecast 方法执行递归预测。 - Alex Kinman
那么,forecast模型中'exog'参数的作用是什么? 我的理解是,您可以将先前的结果馈送到其中,以便区分直接或递归。显然这是不正确的,我不怀疑您,只是试图澄清我的误解。如果您还能进一步说明只实现了递归预测,那就更好了。我在statsmodels网站上查找澄清信息,但没有找到。 - Aesir
1
@Aesir,'exog'参数代表着“外生变量”,它用于输入除时间序列本身之外的附加变量。例如,如果您要建模一个每日的时间序列,您可以使用exog添加一个附加指标,告诉模型哪些天是假期,哪些天是正常的工作日。 - Alex Kinman
无论如何,我都会接受你的答案,因为它真的对我有帮助。不过,我觉得你可以通过在评论中提供给我的额外信息来进一步完善它! - Aesir

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接