Реализация экспоненциальной общей линейной модели в Stan / RStan

У меня такая модель:

введите описание изображения здесь

Я хочу узнать, как реализовать эту модель.

Исследование и попытка

В качестве примера я видел следующий пуассоновский 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 (см. Раздел 9.2 справочного руководства Stan). Однако, поскольку я новичок в Стэне, я нахожу это довольно пугающим, и я не уверен, как реализовать экспоненциальный GLM таким же образом. Нужно ли вообще использовать повторную параметризацию QR для экспоненциального случая?

В любом случае, моя наивная попытка экспоненциальной GLM - это следующая адаптация кода Пуассона 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);
  }
```

Но я совершенно не уверен, что это вообще правильный способ кодирования такой модели на Стэне. Все, что я сделал, это просто попытался адаптировать пример пуассоновской 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

person The Pointer    schedule 05.06.2018    source источник
comment
Можете ли вы предоставить образцы данных? Меня также смущает общая модель. Вы говорите о модели Пуассона или экспоненциальной (т.е. гамма) модели? Это разные вещи. glm эквивалентами являются glm(..., family = poisson) и glm(..., family = Gamma). На первом этапе вы должны сравнить выходные данные вашей модели Stan с результатами glm. Согласны ли точечные оценки?   -  person Maurits Evers    schedule 06.06.2018
comment
@MauritsEvers Спасибо за ответ. Я говорю об экспоненциальной модели. Модель Пуассона, которую я опубликовал, была совершенно отдельным примером, который я пытался использовать, чтобы определить, как создать экспоненциальную модель. Я отредактировал свой пост с некоторыми образцами данных. Если что-то еще неясно, не стесняйтесь спрашивать. Я совершенно не знаю, как реализовать эту модель, поэтому очень благодарен за помощь. Спасибо за помощь.   -  person The Pointer    schedule 06.06.2018


Ответы (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 как простую гамма-модель (экспоненциальную) с лог-связью.

    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);
    }
    "
    

    Здесь я предполагаю (стандартные) малоинформативные априоры Коши по параметрам бета-модели.

  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 к данным, используя glm.

    model.glm <- glm(time ~ conc, data = df, family = Gamma(link = "log"));
    
  5. Оценки параметров модели Стэна:

    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
    

    Мы видим хорошее согласие между точечными оценками Стэн для средних и оценками параметров гамма-GLM.

  6. Мы строим оценки параметров как для стандартной, так и для 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 оценок показаны красным.


Обновление (модель Fit Stan с повторной параметризацией QR)

  1. Стандартная модель с QR-параметризацией.

    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.

    Обратите внимание, что мы не указываем никаких априорных значений тета; в Stan это по умолчанию плоские (т.е. унифицированные) априорные значения.

  2. Подгоните модель Стэна к данным.

    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
    

    Вы можете видеть, что оценки параметров двух моделей Стэна (с параметризацией QR и без нее) очень хорошо согласуются.

    Если бы вы спросили меня, имеет ли (большое / какое-либо) значение повторная параметризация QR, я бы сказал: «Вероятно, не в этом случае»; Эндрю Гельман и другие часто подчеркивали, что использование даже очень слабо информативных априорных чисел поможет сходимости и должно быть предпочтительнее плоских (однородных) априорных чисел; Я всегда старался использовать малоинформативные априорные значения по всем параметрам и начинать с модели без QR-репараметризации; если сходимость плохая, я бы попытался оптимизировать свою модель на следующем этапе.

person Maurits Evers    schedule 06.06.2018
comment
Ах, это проясняет! Еще раз спасибо за помощь. У меня есть пара вопросов, вы не против. Значит, нам не нужно использовать репараметризацию QR для экспоненциальной GLM, как это было сделано в примере Poisson GLM, который я опубликовал? Кроме того, для ссылки на журнал у вас есть lambda = exp(-X * beta). Если не ошибаюсь, эта бета соответствует бета_1 в описании модели. А как насчет beta_0? - person The Pointer; 06.06.2018
comment
@ThePointer (1) beta[1] соответствует смещению (ваша beta_0); Стэн использует индексацию на основе 1, а не 0 (с приятным побочным эффектом, заключающимся в большей согласованности с R). Я добавил график, который показывает сравнение оценок параметров для моделей Stan и glm. (2) Относительно репараметризации QR. Я не эксперт в этом, но насколько я понимаю, повторная параметризация QR может помочь ускорить процесс выборки. Это стратегия оптимизации, которая помогает, в частности, если у вас плоские априорные значения. [...] - person Maurits Evers; 06.06.2018
comment
[...] Я никогда не использовал повторную параметризацию QR, потому что в большинстве случаев я могу предоставить малоинформативные априорные решения, и сходимость решений в порядке (вы можете проверить это, посмотрев на значения Rhat). Мне очень жаль, что я не могу дать более исчерпывающий ответ по этому поводу. Возможно, кто-нибудь из команды Rstan / Stan сможет поделиться своим мнением; Я знаю, что они следят за SO по вопросам, связанным со Стэном; или, возможно, задайте отдельный вопрос на форумах Стэна Гугла. - person Maurits Evers; 06.06.2018
comment
@ThePointer Я добавил пример, показывающий, как подогнать модель Стэна с помощью повторной параметризации QR; пожалуйста, посмотрите и дайте мне знать, если что-то неясно. - person Maurits Evers; 06.06.2018
comment
Ух ты!!! Ваш ответ просто великолепен! Большое спасибо за то, что вы нашли время написать такой подробный и информативный ответ. Ваши объяснения ясны, и я думаю, что теперь все понимаю. Итак, используя ваши результаты, 95% достоверные интервалы для beta[1] и beta[2] будут просто интервалом от квантиля 2,5% до квантиля 97,5%? И если бы я хотел поставить информативные априорные точки для beta[1] и beta[2] в репараметризацию QR, я бы просто поставил априорные значения для theta[1] и theta[2]? - person The Pointer; 06.06.2018
comment
Добро пожаловать, @ThePointer; Мне нравятся эти вопросы моделирования Стэна / Рстана, поскольку (R) stan - это фантастическая структура ИМО. Вы правы в интерпретации 95% вероятного интервала. Что касается априорных значений, то да, в модели репараметризации QR вы могли бы предоставить малоинформативные априорные значения (такие как априоры Коши) по тета-параметрам. Но в этом случае вы можете использовать первую модель. Насколько я понимаю, повторная параметризация QR - это стратегия оптимизации, которая подходит, когда решения не сходятся (что может произойти, когда у вас плоские априорные значения и / или K велико); [...] - person Maurits Evers; 06.06.2018
comment
[...] В вашем случае сходимость на самом деле не проблема даже с плоскими априорными значениями в первой модели. Таким образом, дополнительное преимущество повторной параметризации QR в этом случае кажется незначительным. Но все же хорошо знать, как это реализовать; Я никогда не использовал параметризацию QR, поэтому я узнал кое-что новое из вашего примера ;-) - person Maurits Evers; 06.06.2018
comment
Понял. Еще раз спасибо за помощь. Мне немного неловко спросить так скоро после того, как вы ответили на этот вопрос, но есть ли у вас какой-либо опыт иерархического моделирования? Я пытаюсь преобразовать модель нелинейного роста, которую я ранее реализовал в Стэне, в иерархическую модель. Опять же, если это не слишком большая проблема, я был бы очень признателен, если бы вы могли объяснить эту реализацию так же, как вы сделали здесь. stackoverflow.com/questions/50749414/ - person The Pointer; 07.06.2018