【问题标题】:Forecasting out-of-sample with exogenous variables using Time-varying regression example code in Statsmodels -python使用 Statsmodels -python 中的时变回归示例代码预测具有外生变量的样本外
【发布时间】:2021-12-28 23:32:16
【问题描述】:

我的问题是: 如何使用 Statsmodels 状态空间类 TVRegression 和示例中提供的自定义数据预测具有外生预测变量的样本值(参见下面的链接)。 我花了几个小时寻找当回归模型包含外生变量时如何预测样本外值的示例。我想构建一个简单的动态线性模型类。我在 Statsmodels 中找到了一个类,TVRegression(参见此处),[https://www.statsmodels.org/dev/examples/notebooks/generated/statespace_custom_models.html][1] 那应该可以解决我的问题。 TVRegression 类将两个外生预测变量和一个响应变量作为参数。 我复制并粘贴了代码并运行了上面链接中的示例,没有任何问题。但是,即使使用给出的示例数据,我也无法生成简单的样本外预测。 TVRegression 类是 sm.tsa.statespace.MLEModel 的子类,因此应该继承所有相关的方法。 sm.tsa.statespace.MLEModel 的方法之一是 forecast() ,根据用户指南,我应该能够提供一个简单的 step 参数并摆脱样本预测: 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()

上面提供的链接中的 TVRegression 类:

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 的新值作为此类 exog 预测器的帮助。

到目前为止我所尝试的:

  1. 我在类代码的 init 部分添加了 self.k_exog 以响应第一个错误。

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

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

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

  • 例如res.forecast(steps = 5, np.c_(w_t[:5],x_t[:5])

【问题讨论】:

    标签: python statsmodels forecasting


    【解决方案1】:

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

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

    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 方法。

    【讨论】:

    • 这真的很有帮助!对克隆方法的直觉终于清晰起来。
    猜你喜欢
    • 2015-03-05
    • 2020-08-29
    • 2017-10-20
    • 2020-08-06
    • 2013-09-08
    • 1970-01-01
    • 2018-06-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多