【问题标题】:Implementing exponential General Linear Model in Stan/RStan在 Stan/RStan 中实现指数一般线性模型
【发布时间】:2018-06-05 17:37:26
【问题描述】:

我有以下型号:

我想学习如何实现这个模型。

研究与尝试

我以 Poisson GLM 为例:

```{stan output.var="PoissonGLMQR"}
  data{
    int<lower=1> n;     // number of observations
    int<lower=1> p;     // number of predictors
    matrix[n, p] x;     // design matrix
    int<lower=0> y[n];  // responses
  }
  
  transformed data{
    matrix [n, p] Q_ast;
    matrix [p, p] R_ast;
    matrix [p, p] R_ast_inverse;
    Q_ast = qr_Q(x)[,1:p] * sqrt(n - 1.0);
    R_ast = qr_R(x)[1:p,] / sqrt(n - 1.0);
    R_ast_inverse = inverse(R_ast);
  }
  
  parameters{
    vector[p] theta;  // regression coefficients for predictors
  }
  
  transformed parameters{
    vector[p] beta;
    vector[n] mu;
    mu = exp(Q_ast*theta);
    beta = R_ast_inverse * theta;
  }
  
  model{
     y  ~ poisson(mu);
  }
```

我了解此示例使用了 QR 重新参数化(请参阅 Stan 参考手册的第 9.2 节)。然而,由于我是 Stan 的新手,我觉得这很吓人,而且我不确定如何以同样的方式实现指数 GLM。是否需要对指数情况使用 QR 重新参数化?

无论如何,我对指数 GLM 的天真尝试是对 Poisson GLM 代码的以下改编:

```{stan output.var="ExponentialGLM"}
  data{
    int<lower=1> n;     // number of observations
    int<lower=1> p;     // number of predictors
    matrix[n, p] x;     // design matrix
    real<lower=0> y[n];  // responses
  }
  
  transformed data{
    matrix [n, p] Q_ast;
    matrix [p, p] R_ast;
    matrix [p, p] R_ast_inverse;
    Q_ast = qr_Q(x)[,1:p] * sqrt(n - 1.0);
    R_ast = qr_R(x)[1:p,] / sqrt(n - 1.0);
    R_ast_inverse = inverse(R_ast);
  }
  
  parameters{
    vector[p] theta;  // regression coefficients for predictors
  }
  
  transformed parameters{
    vector[p] beta;
    vector[n] mu;
    mu = exp(Q_ast*theta);
    beta = (R_ast_inverse * theta);
  }
  
  model{
     y  ~ exponential(mu);
  }
```

但是,我完全不确定这是否是在 Stan 中编写这样一个模型的正确方法。我所做的只是尝试使 Poisson GLM 示例适应上述指数 GLM。

我正在寻求指数 GLM 的演示,并就我上面的误解进行澄清。

样本数据

    conc  time
 1   6.1   0.8
 2   4.2   3.5
 3   0.5  12.4
 4   8.8   1.1
 5   1.5   8.9
 6   9.2   2.4
 7   8.5   0.1
 8   8.7   0.4
 9   6.7   3.5
10   6.5   8.3
11   6.3   2.6
12   6.7   1.5
13   0.2  16.6
14   8.7   0.1
15   7.5   1.3

【问题讨论】:

  • 你能提供一些示例数据吗?我也对一般模型感到困惑。您是在谈论泊松模型还是指数(即 Gamma)模型?这是两个不同的东西。 glm 等价物是 glm(..., family = poisson)glm(..., family = Gamma)。第一步,您应该将 Stan 模型的输出与 glm 的输出进行比较。点估计值是否一致?
  • @MauritsEvers 感谢您的回复。我说的是指数模型。我发布的泊松模型是一个完全独立的示例,我试图使用它来确定如何进行指数模型。我用一些示例数据编辑了我的帖子。如果还有什么不清楚的,请不要犹豫,问。我完全不确定如何实现此模型,因此非常感谢您的帮助。感谢您的帮助。

标签: r statistics regression stan rstan


【解决方案1】:

这样的事情怎么样?

  1. 我们从读取样本数据开始。

    df <- read.table(text =
        "    conc  time
     1   6.1   0.8
     2   4.2   3.5
     3   0.5  12.4
     4   8.8   1.1
     5   1.5   8.9
     6   9.2   2.4
     7   8.5   0.1
     8   8.7   0.4
     9   6.7   3.5
    10   6.5   8.3
    11   6.3   2.6
    12   6.7   1.5
    13   0.2  16.6
    14   8.7   0.1
    15   7.5   1.3", header = T);
    
  2. 我们将 Stan 模型定义为带有对数链接的简单 Gamma(指数)模型。

    model <- "
    data {
        int N;                                       // Number of observations
        int K;                                       // Number of parameters
        real y[N];                                   // Response
        matrix[N,K] X;                               // Model matrix
    }
    
    parameters {
        vector[K] beta;                              // Model parameters
    }
    
    transformed parameters {
        vector[N] lambda;
        lambda = exp(-X * beta);                     // log-link
    }
    
    model {
        // Priors
        beta[1] ~ cauchy(0, 10);
        for (i in 2:K)
            beta[i] ~ cauchy(0, 2.5);
    
        y ~ exponential(lambda);
    }
    "
    

    在这里,我假设(标准)关于 beta 模型参数的信息量较弱的柯西先验。

  3. 我们现在将模型拟合到数据中。

    library(rstan);
    options(mc.cores = parallel::detectCores());
    rstan_options(auto_write = TRUE);
    
    X <- model.matrix(time ~ conc, data = df);
    model.stan <- stan(
        model_code = model,
        data = list(
            N = nrow(df),
            K = ncol(X),
            y = df$time,
            X = X),
        iter = 4000);
    
  4. 为了比较点估计,我们还使用 glm 将 Gamma GLM 拟合到数据。

    model.glm <- glm(time ~ conc, data = df, family = Gamma(link = "log"));
    
  5. Stan 模型参数估计是

    summary(model.stan, "beta")$summary;
    #              mean     se_mean         sd       2.5%        25%        50%
    #beta[1]  2.9371457 0.016460000 0.62017934  1.8671652  2.5000356  2.8871936
    #beta[2] -0.3099799 0.002420744 0.09252423 -0.5045937 -0.3708111 -0.3046333
    #               75%      97.5%    n_eff     Rhat
    #beta[1]  3.3193334  4.3078478 1419.629 1.002440
    #beta[2] -0.2461567 -0.1412095 1460.876 1.002236        
    

    GLM 模型参数估计为

    summary(model.glm)$coef;
    #              Estimate Std. Error   t value     Pr(>|t|)
    #(Intercept)  2.8211487 0.54432115  5.182875 0.0001762685
    #conc        -0.3013355 0.08137986 -3.702827 0.0026556952
    

    我们看到均值的 Stan 点估计值和 Gamma-GLM 参数估计值之间的一致性很好。

  6. 我们绘制了 Stan 和 glm 模型的参数估计值。

    library(tidyverse);
    as.data.frame(summary(model.stan, "beta")$summary) %>%
        rownames_to_column("Parameter") %>%
        ggplot(aes(x = `50%`, y = Parameter)) +
        geom_point(size = 3) +
        geom_segment(aes(x = `2.5%`, xend = `97.5%`, yend = Parameter), size = 1) +
        geom_segment(aes(x = `25%`, xend = `75%`, yend = Parameter), size = 2) +
        labs(x = "Median (plus/minus 95% and 50% CIs)") +
        geom_point(
            data = data.frame(summary(model.glm)$coef, row.names = c("beta[1]", "beta[2]")) %>%
                rownames_to_column("Parameter"),
            aes(x = Estimate, y = Parameter),
            colour = "red", size = 4, shape = 1)
    

    glm 估计值显示为红色。


更新(使用 QR 重新参数化拟合 Stan 模型)

  1. 具有 QR 重新参数化的 Stan 模型。

    model.QR <- "
    data {
        int N;                                       // Number of observations
        int K;                                       // Number of parameters
        real y[N];                                   // Response
        matrix[N,K] X;                               // Model matrix
    }
    
    transformed data {
        matrix[N, K] Q;
        matrix[K, K] R;
        matrix[K, K] R_inverse;
        Q = qr_Q(X)[, 1:K];
        R = qr_R(X)[1:K, ];
        R_inverse = inverse(R);
    }
    
    parameters {
        vector[K] theta;
    }
    
    transformed parameters {
        vector[N] lambda;
        lambda = exp(-Q * theta);                     // log-link
    }
    
    model {
        y ~ exponential(lambda);
    }
    
    generated quantities {
        vector[K] beta;                              // Model parameters
        beta = R_inverse * theta;
    }
    "
    

    在 QR 分解中,我们有lambda = exp(- X * beta) = exp(- Q * R * beta) = exp(- Q * theta),其中theta = R * beta,因此beta = R^-1 * theta

    请注意,我们没有在 theta 上指定任何先验;在 Stan 中,这默认为平坦(即统一)先验。

  2. 根据数据拟合 Stan 模型。

    library(rstan);
    options(mc.cores = parallel::detectCores());
    rstan_options(auto_write = TRUE);
    
    X <- model.matrix(time ~ conc, data = df);
    model.stan.QR <- stan(
        model_code = model.QR,
        data = list(
            N = nrow(df),
            K = ncol(X),
            y = df$time,
            X = X),
        iter = 4000);
    
  3. 参数估计

    summary(model.stan.QR, "beta")$summary;
    #              mean     se_mean         sd       2.5%        25%        50%
    #beta[1]  2.9637547 0.009129250 0.64383609  1.8396681  2.5174800  2.9194682
    #beta[2] -0.3134252 0.001321584 0.09477156 -0.5126905 -0.3740475 -0.3093937
    #               75%      97.5%    n_eff      Rhat
    #beta[1]  3.3498585  4.3593912 4973.710 0.9998545
    #beta[2] -0.2478029 -0.1395686 5142.408 1.0003236
    

    您可以看到,两个 Stan 模型(有和没有 QR 重新参数化)之间的参数估计非常一致。

    如果您要问我 QR 重新参数化是否会产生(大/任何)差异,我会说“在这种情况下可能不会”; Andrew Gelman 和其他人经常强调,即使使用信息量非常微弱的先验也有助于收敛,应该优先于平坦(统一)先验;我总是会尝试在所有参数上使用弱信息先验,并从没有 QR 重新参数化的模型开始;如果收敛性很差,我会在下一步尝试优化我的模型。

【讨论】:

  • 啊,这很有启发性!再次感谢您的帮助。我有几个问题,你不介意。所以我们不需要对指数 GLM 使用 QR 重新参数化,就像我发布的 Poisson GLM 示例中所做的那样?此外,对于日志链接,您有 lambda = exp(-X * beta)。如果我没记错的话,这个 beta 对应于模型描述中的 beta_1。 beta_0 呢?
  • @ThePointer (1) beta[1]对应偏移量(你的beta_0); Stan 使用基于 1 而不是基于 0 的索引(具有与 R 更一致的良好副作用)。我添加了一个图表,显示了 Stan 和 glm 模型的参数估计值的比较。 (2) 关于 QR 重新参数化。我不是这方面的专家,但据我了解,QR 重新参数化可以帮助加快采样过程。这是一种优化策略,如果您有平坦的先验,则特别有用。 [...]
  • [...] 我从未使用过 QR 重新参数化,因为大多数时候我能够提供信息量较弱的先验,并且解决方案的收敛性很好(您可以查看 Rhat值)。所以很抱歉,我无法在这方面给出更全面的答案。也许 Rstan/Stan 团队的某个人可以提供见解;我知道他们会监控 SO 以解决与 Stan 相关的问题;或者在 Stan Google 论坛上提出单独的问题。
  • 不客气@ThePointer;我喜欢这些 Stan/Rstan 建模问题,因为 (R)stan 是一个很棒的 IMO 框架。您对 95% 可信区间的解释是正确的。关于先验,是的,在 QR 重新参数化模型中,您可以在 theta 参数上提供信息量较弱的先验(例如柯西先验)。但在这种情况下,您不妨使用第一个模型。据我了解,QR 重新参数化是一种优化策略,适用于解决方案不收敛的情况(当您的先验平坦和/或 K 很大时可能会发生这种情况); [...]
  • [...] 在您的情况下,即使第一个模型中的先验平坦,收敛也不是真正的问题。因此,在这种情况下,QR 重新参数化的额外好处似乎很小。但是知道如何实现它仍然很好;我从未使用过 QR 重新参数化,所以我从您的示例中学到了一些新东西;-)
猜你喜欢
  • 2018-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-08
  • 1970-01-01
  • 2013-07-19
相关资源
最近更新 更多