ZIP - скрытая марковская модель р Стэн

Я пытаюсь настроить модель Маркова с нулевым надувом и скрытым пуассоном с помощью Стэна. Для Пуассона-HMM на прошлом форуме этот параметр был показан. см ссылку

Хотя для настройки ZIP с классической теорией хорошо документированы код и модель.


ziphsmm
library(ziphsmm)
set.seed(123)
prior_init <- c(0.5,0.5)
emit_init <- c(20,6)
zero_init <- c(0.5,0)
tpm <- matrix(c(0.9, 0.1, 0.2, 0.8),2,2,byrow=TRUE)
result <- hmmsim(n=100,M=2,prior=prior_init, tpm_parm=tpm,emit_parm=emit_init,zeroprop=zero_init)
y <- result$series
serie <- data.frame(y = result$series, m = result$state)

fit1 <-  fasthmmfit(y,x=NULL,ntimes=NULL,M=2,prior_init,tpm,
                    emit_init,0.5, hessian=FALSE,method="BFGS", 
                    control=list(trace=1))
fit1
$prior
            [,1]
[1,] 0.997497445
[2,] 0.002502555

$tpm
          [,1]       [,2]
[1,] 0.9264945 0.07350553
[2,] 0.3303533 0.66964673

$zeroprop
[1] 0.6342182

$emit
          [,1]
[1,] 20.384688
[2,]  7.365498

$working_parm
[1] -5.9879373 -2.5340475  0.7065877  0.5503559  3.0147840  1.9968067

$negloglik
[1] 208.823
Стан
library(rstan)

ZIPHMM <- 'data {
    int<lower=0> N;
    int<lower=0> y[N];
    int<lower=1> m;
  }

parameters {
    real<lower=0, upper=1> theta; //
    positive_ordered[m] lambda; //
    simplex[m] Gamma[m]; // tpm
  }

model {
  vector[m] log_Gamma_tr[m];
  vector[m] lp;
  vector[m] lp_p1;

  // priors
  lambda ~ gamma(0.1,0.01);
  theta ~ beta(0.05, 0.05);

  // transposing tpm and taking the log of each entry
  for(i in 1:m)
    for(j in 1:m)
      log_Gamma_tr[j, i] = log(Gamma[i, j]);

  lp = rep_vector(-log(m), m); // 

    for(n in 1:N) {
      for(j in 1:m){
        if (y[n] == 0)
          lp_p1[j] = log_sum_exp(log_Gamma_tr[j] + lp) +
                     log_sum_exp(bernoulli_lpmf(1 | theta),
                     bernoulli_lpmf(0 | theta) + poisson_lpmf(y[n] | lambda[j]));
        else
          lp_p1[j] = log_sum_exp(log_Gamma_tr[j] + lp) + 
                     bernoulli_lpmf(0 | theta) + 
                     poisson_lpmf(y[n] | lambda[j]);
                   }
      lp = lp_p1;
                  }
    target += log_sum_exp(lp);
}'
mod_ZIP <- stan(model_code = ZIPHMM, data=list(N=length(y), y=y, m=2), iter=1000, chains=1)
print(mod_ZIP,digits_summary = 3)
               mean se_mean    sd     2.5%      25%      50%      75%    97.5% n_eff  Rhat
theta         0.518   0.002 0.052    0.417    0.484    0.518    0.554    0.621   568 0.998
lambda[1]     7.620   0.039 0.787    6.190    7.038    7.619    8.194    9.132   404 1.005
lambda[2]    20.544   0.039 0.957   18.861   19.891   20.500   21.189   22.611   614 1.005
Gamma[1,1]    0.664   0.004 0.094    0.473    0.604    0.669    0.730    0.841   541 0.998
Gamma[1,2]    0.336   0.004 0.094    0.159    0.270    0.331    0.396    0.527   541 0.998
Gamma[2,1]    0.163   0.003 0.066    0.057    0.114    0.159    0.201    0.312   522 0.999
Gamma[2,2]    0.837   0.003 0.066    0.688    0.799    0.841    0.886    0.943   522 0.999
lp__       -222.870   0.133 1.683 -227.154 -223.760 -222.469 -221.691 -220.689   161 0.999
Истинные ценности
real = list(tpm = tpm, 
     zeroprop = nrow(serie[serie$m == 1 & serie$y == 0, ]) / nrow(serie[serie$m == 1,]),
     emit = t(t(tapply(serie$y[serie$y != 0],serie$m[serie$y != 0], mean))))
real
$tpm
     [,1] [,2]
[1,]  0.9  0.1
[2,]  0.2  0.8

$zeroprop
[1] 0.6341463

$emit
       [,1]
1 20.433333
2  7.277778

Оценки дают довольно странно, чтобы кто-то мог помочь мне узнать, что я делаю неправильно. Как мы видим, оценки stan zeroprop = 0,518, в то время как действительное значение составляет 0,634, с другой стороны, значения tpm в stan довольно отдаленные, а средние значения lambda1 = 7,62 и lambda2 = 20,54, хотя они достаточно приблизительные, дают в другом порядке. к реальным 20,43 и 7,27. Я думаю, что я делаю некоторую ошибку в определении модели в Стэне, но я не знаю, какая

1 ответ

Решение

Хотя я не знаю, как работает алгоритм подгонки ZIP-HMM, есть некоторые очевидные различия в том, что вы реализовали в модели Стэна, и как описывает алгоритм оптимизации ZIP-HMM. Решение этих проблем представляется достаточным для получения аналогичных результатов.

Различия между моделями

Вероятность начального состояния

Значения, которые оценивает ZIP-HMM, в частности fit1$prior, указать, что он включает в себя способность узнать вероятность для начального состояния. Однако в модели Стэна это установлено на 1:1.

lp = rep_vector(-log(m), m);

Это следует изменить, чтобы позволить модели оценить начальное состояние.

Приоры по параметрам (необязательно)

Модель Стэна имеет неплоские lambda а также theta, но предположительно ZIP-HMM не взвешивает конкретные значения, которые он получает. Если кто-то хочет более реалистично имитировать ZIP-HMM, то плоские приоры были бы лучше. Тем не менее, возможность иметь неплоские приоры в Stan - это действительно возможность разработать более хорошо настроенную модель, чем это возможно с помощью стандартных алгоритмов вывода HMM.

Ноль-инфляция на государство 1

Из документации fasthmmfit метод

Алгоритм быстрого градиентного спуска / стохастического градиентного спуска для изучения параметров в специализированной скрытой марковской модели с нулевым раздувом, где нулевая инфляция происходит только в состоянии 1. [выделение добавлено]

Модель Стэна предполагает нулевую инфляцию во всех штатах. Вероятно, поэтому, по оценкам, theta значение дефлируется относительно оценки MAP ZIP-HMM.

Государственный заказ

При оценке дискретных скрытых состояний или кластеров в Stan можно использовать упорядоченный вектор в качестве хитрости, чтобы смягчить проблему переключения меток. Это эффективно достигается здесь с

positive_ordered[m] lambda;

Однако, поскольку ZIP-HMM имеет нулевую инфляцию только в первом состоянии, для правильной реализации этого поведения в Stan требуется предварительное знание того, каков ранг lambda для "первого" состояния. Это кажется очень проблематичным для обобщения этого кода. А пока давайте просто двигаться вперед, предполагая, что мы всегда можем каким-то образом восстановить эту информацию. В этом конкретном случае мы будем предполагать, что состояние 1 в НММ имеет более высокое lambda значение, и, следовательно, будет состояние 2 в модели Стэна.

Обновленная модель Стэна

Включение вышеуказанных изменений в модель должно быть чем-то вроде

Стэн Модель

data {
  int<lower=0> N;    // length of chain
  int<lower=0> y[N]; // emissions
  int<lower=1> m;    // num states
}

parameters {
  simplex[m] start_pos;         // initial pos probs
  real<lower=0, upper=1> theta; // zero-inflation parameter
  positive_ordered[m] lambda;   // emission poisson params
  simplex[m] Gamma[m];          // transition prob matrix
}

model {
  vector[m] log_Gamma_tr[m];
  vector[m] lp;
  vector[m] lp_p1;

  // transposing tpm and taking the log of each entry
  for (i in 1:m) {
    for (j in 1:m) { 
      log_Gamma_tr[j, i] = log(Gamma[i, j]);
    }
  }

  // initial position log-lik
  lp = log(start_pos);

  for (n in 1:N) {
    for (j in 1:m) {
      // log-lik for state
      lp_p1[j] = log_sum_exp(log_Gamma_tr[j] + lp);

      // log-lik for emission
      if (j == 2) { // assuming only state 2 has zero-inflation
        if (y[n] == 0) {
          lp_p1[j] += log_mix(theta, 0, poisson_lpmf(0 | lambda[j]));
        } else {
          lp_p1[j] += log1m(theta) + poisson_lpmf(y[n] | lambda[j]);
        }
      } else {
        lp_p1[j] += poisson_lpmf(y[n] | lambda[j]);
      }
    }
    lp = lp_p1; // log-lik for next position
  }
  target += log_sum_exp(lp);
}

MAP Estimate

Загрузка вышеупомянутого как строковая переменная code.ZIPHMM Сначала мы скомпилируем его и запустим оценку MAP (поскольку оценка MAP будет вести себя как алгоритм подгонки HMM):

model.ZIPHMM <- stan_model(model_code=code.ZIPHMM)

// note the use of some initialization on the params,
// otherwise it can occasionally converge to strange extrema
map.ZIPHMM <- optimizing(model.ZIPHMM, algorithm="BFGS",
                         data=list(N=length(y), y=y, m=2),
                         init=list(theta=0.5, lambda=c(5,10)))

Изучение оценочных параметров

> map.ZIPHMM$par
start_pos[1] start_pos[2]        
9.872279e-07 9.999990e-01 

theta    
6.342449e-01 

lambda[1]    lambda[2]   
7.370525e+00 2.038363e+01 

Gamma[1,1]   Gamma[2,1]   Gamma[1,2]   Gamma[2,2] 
6.700871e-01 7.253215e-02 3.299129e-01 9.274678e-01

показывает, что они близко отражают ценности, которые fasthmmfit Вывод, за исключением того, что государственные заказы переключаются.

Выборка задних

Эта модель также может работать с MCMC, чтобы сделать вывод

samples.ZIPHMM <- stan(model_code = code.ZIPHMM, 
                       data=list(N=length(y), y=y, m=2), 
                       iter=2000, chains=4)

который выбирает хорошо и дает аналогичные результаты (и без каких-либо инициализаций параметров)

> samples.ZIPHMM
Inference for Stan model: b29a2b7e93b53c78767aa4b0c11b62a0.
4 chains, each with iter=2000; warmup=1000; thin=1; 
post-warmup draws per chain=1000, total post-warmup draws=4000.

                mean se_mean   sd    2.5%     25%     50%     75%   97.5% n_eff Rhat
start_pos[1]    0.45    0.00 0.29    0.02    0.20    0.43    0.69    0.97  6072    1
start_pos[2]    0.55    0.00 0.29    0.03    0.31    0.57    0.80    0.98  6072    1
theta           0.63    0.00 0.05    0.53    0.60    0.63    0.67    0.73  5710    1
lambda[1]       7.53    0.01 0.72    6.23    7.02    7.49    8.00    9.08  4036    1
lambda[2]      20.47    0.01 0.87   18.83   19.87   20.45   21.03   22.24  5964    1
Gamma[1,1]      0.65    0.00 0.11    0.43    0.57    0.65    0.72    0.84  5664    1
Gamma[1,2]      0.35    0.00 0.11    0.16    0.28    0.35    0.43    0.57  5664    1
Gamma[2,1]      0.08    0.00 0.03    0.03    0.06    0.08    0.10    0.16  5605    1
Gamma[2,2]      0.92    0.00 0.03    0.84    0.90    0.92    0.94    0.97  5605    1
lp__         -214.76    0.04 1.83 -219.21 -215.70 -214.43 -213.43 -212.25  1863    1
Другие вопросы по тегам