使用 Statsmodels 中的时变回归示例代码预测具有外生变量的样本外 -python

Forecasting out-of-sample with exogenous variables using Time-varying regression example code in Statsmodels -python

我的问题是: 如何使用 Statsmodels state-space class TVRegression 和示例中提供的自定义数据(参见下面的 link)预测样本外的值。 我花了几个小时寻找当回归模型包含外生变量时如何预测样本外值的示例。我想建立一个简单的动态线性模型 class。我在 Statsmodels、TVRegression(见这里)中找到了 class,[https://www.statsmodels.org/dev/examples/notebooks/generated/statespace_custom_models.html][1] 那应该可以解决我的问题。 TVRegression class 将两个外生预测变量和一个响应变量作为参数。 我毫无问题地复制并粘贴了代码和 运行 上面 link 中的示例。但是,即使使用给出的示例数据,我也无法生成简单的样本外预测。 TVRegression class 是 sm.tsa.statespace.MLEModel 的子 class,因此应该继承所有关联的方法。 sm.tsa.statespace.MLEModel 的方法之一是 forecast() 并且根据用户指南我应该能够提供一个简单的步骤参数并脱离样本预测:MLEResults.forecast(steps=1, **kwargs) . 用于生成依赖项 :y 和独立项 (exogs) 的代码 x_t;w_t

def gen_data_for_model1():
    nobs = 1000

    rs = np.random.RandomState(seed=93572)

    d = 5
    var_y = 5
    var_coeff_x = 0.01
    var_coeff_w = 0.5

    x_t = rs.uniform(size=nobs)
    w_t = rs.uniform(size=nobs)
    eps = rs.normal(scale=var_y ** 0.5, size=nobs)


    beta_x = np.cumsum(rs.normal(size=nobs, scale=var_coeff_x ** 0.5))
    beta_w = np.cumsum(rs.normal(size=nobs, scale=var_coeff_w ** 0.5))

    y_t = d + beta_x * x_t + beta_w * w_t + eps
    return y_t, x_t, w_t, beta_x, beta_w

y_t, x_t, w_t, beta_x, beta_w = gen_data_for_model1()

上面提供的 link 的 TVRegression class:

class TVRegression(sm.tsa.statespace.MLEModel):
    def __init__(self, y_t, x_t, w_t):
        exog = np.c_[x_t, w_t]  # shaped nobs x 2

        super(TVRegression, self).__init__(
            endog=y_t, exog=exog, k_states=2, initialization="diffuse"
        )

        # Since the design matrix is time-varying, it must be
        # shaped k_endog x k_states x nobs
        # Notice that exog.T is shaped k_states x nobs, so we
        # just need to add a new first axis with shape 1
        self.ssm["design"] = exog.T[np.newaxis, :, :]  # shaped 1 x 2 x nobs
        self.ssm["selection"] = np.eye(self.k_states)
        self.ssm["transition"] = np.eye(self.k_states)

        # Which parameters need to be positive?
        self.positive_parameters = slice(1, 4)

    @property
    def param_names(self):
        return ["intercept", "var.e", "var.x.coeff", "var.w.coeff"]

    @property
    def start_params(self):
        """
        Defines the starting values for the parameters
        The linear regression gives us reasonable starting values for the constant
        d and the variance of the epsilon error
        """
        exog = sm.add_constant(self.exog)
        res = sm.OLS(self.endog, exog).fit()
        params = np.r_[res.params[0], res.scale, 0.001, 0.001]
        return params

    def transform_params(self, unconstrained):
        """
        We constraint the last three parameters
        ('var.e', 'var.x.coeff', 'var.w.coeff') to be positive,
        because they are variances
        """
        constrained = unconstrained.copy()
        constrained[self.positive_parameters] = (
            constrained[self.positive_parameters] ** 2
        )
        return constrained

    def untransform_params(self, constrained):
        """
        Need to unstransform all the parameters you transformed
        in the `transform_params` function
        """
        unconstrained = constrained.copy()
        unconstrained[self.positive_parameters] = (
            unconstrained[self.positive_parameters] ** 0.5
        )
        return unconstrained

    def update(self, params, **kwargs):
        params = super(TVRegression, self).update(params, **kwargs)

        self["obs_intercept", 0, 0] = params[0]
        self["obs_cov", 0, 0] = params[1]
        self["state_cov"] = np.diag(params[2:4])

使用假生成数据拟合的简单结果:

mod = TVRegression(y_t, x_t, w_t)
res = mod.fit()

print(res.summary())

我想要的是至少无误地完成以下内容:

res.forecast(steps = 5)

理想情况下,我可以获得有关如何构造参数 exog 以接受 x_t 和 w_t 的新值作为此 class.

的 exog 预测变量的帮助

到目前为止我尝试过的:

  1. 我在 class 代码的初始化部分添加了 self.k_exog 以响应第一个错误。

  2. 在我的第二次尝试中,我收到以下值错误:

    ValueError:具有回归分量的模型中的样本外操作需要通过 exog 参数提供额外的外生值。

  3. 我尝试通过连接新值来添加外生变量,以便步长等于数据切片。

解决方法:最简单的方法是:

首先将您的构造函数重新定义为:

def __init__(self, y_t, exog):
    super(TVRegression, self).__init__(
        endog=y_t, exog=exog, k_states=2, initialization="diffuse"
    )
    self.k_exog = self.exog.shape[1]

    # Since the design matrix is time-varying, it must be
    # shaped k_endog x k_states x nobs
    # Notice that exog.T is shaped k_states x nobs, so we
    # just need to add a new first axis with shape 1
    self.ssm["design"] = exog.T[np.newaxis, :, :]  # shaped 1 x 2 x nobs
    self.ssm["selection"] = np.eye(self.k_states)
    self.ssm["transition"] = np.eye(self.k_states)

    # Which parameters need to be positive?
    self.positive_parameters = slice(1, 4)

然后添加一个新的方法

def clone(self, endog, exog=None, **kwargs):
    return self._clone_from_init_kwds(endog, exog=exog, **kwargs)

现在你可以做例如:

exog_t = np.c_[x_t, w_t]
mod = TVRegression(y_t[:-5], exog=exog_t[:-5])
res = mod.fit()
print(res.summary())

res.forecast(steps=5, exog=exog_t[-5:])

讨论:

这里的问题是,当您的模型依赖于这些 exog 变量时,您需要为预测的样本外部分更新 exog 的值(因为 exog 您在构建模型时提供的仅包含样本内值)。

要执行预测,Statsmodels 必须能够使用新的样本外 exog 从本质上创建新的模型表示。这就是 clone 方法的用途 - 它描述了如何创建模型的新副本,但使用不同的数据集。由于此模型很简单,因此我们可以使用现有的通用克隆方法 (_clone_from_init_kwds)。

最后,我们需要使用 exog 参数将样本外 exog 值传递给 forecast 方法。