Chapter 8 Major Earthquake Analysis
We apply the concepts in the previous chapters to the series of annual counts of major earthquakes (i.e. magnitude 7 and above) from the textbook.
The data can be read into R
<- read.table("http://www.hmms-for-time-series.de/second/data/earthquakes.txt") eq_dat
We use the following packages for the analysis
# Load packages
library(kableExtra)
library(tidyverse)
library(gridExtra)
library(momentuHMM)
library(rstan)

Figure 8.1: Number of major earthquakes worldwide from 1900-2006.

Figure 8.2: Histogram of major earthquakes overlaid with a Poisson density of mean equal to the observed counts.
mean | variance |
---|---|
19.36 | 51.57 |
Fitting a Poisson Mixture Distribution
Note: See Preliminaries
We may consider fitting a Poisson mixture distribution since earthquake counts are unbounded and there appears to be overdispersion as evident by the multimodal peaks in Figure 8.2 and sample variance \(s^2 \approx 52 > 19 \approx \bar{x}\) in Table 8.1.
Suppose \(m=3\) and the three components are Poisson-distributed with means \(\lambda_1, \lambda_2\), and \(\lambda_3\). Let \(\delta_1\), \(\delta_2\), and \(\delta_3\) be the respective mixing parameters. The mixture distribution \(p\) is given by
\[p(x) = \delta_1 \frac{\lambda_1^x e^{-\lambda_1}}{x!} + \delta_2 \frac{\lambda_2^x e^{-\lambda_2}}{x!} + \delta_3 \frac{\lambda_3^x e^{-\lambda_3}}{x!}\]
The likelihood is given by
\[L(\lambda_1, \lambda_2, \lambda_3, \delta_1, \delta_2|x_1, \dots, x_n) = \prod_{i=1}^n \left( \delta_1 \frac{\lambda_1^{x_i} e^{-\lambda_1}}{x_i!} + \delta_2 \frac{\lambda_2^{x_i} e^{-\lambda_2}}{x_i!} + (1 - \delta_1 - \delta_2) \frac{\lambda_3^{x_i} e^{-\lambda_3}}{x_i!} \right)\]
The log-likelihood can be maximized using the unconstrained optimizer nlm
on reparameterized parameters by the following:
Step 1: Reparameterize the “natural parameters” \(\boldsymbol{\delta}\) and \(\boldsymbol{\lambda}\) into “working parameters” \(\eta_i = \log \lambda_i \qquad{(i = 1, \dots, m)}\) and \(\tau_i = \log \left(\frac{\delta_i}{1 - \sum_{j=2}^m \delta_j}\right) (i = 2, \dots, m)\)
<- function(lambda, delta)log(c(lambda, delta[-1]/(1-sum(delta[-1])))) n2w
Step 2: Compute the negative log-likelihood using the working parameters
<- function(wpar, x){
mllk <- w2n(wpar)
zzz -sum(log(outer(x, zzz$lambda, dpois)%*%zzz$delta))}
Step 3: Transform the parameters back into natural parameters
<- function(wpar){
w2n <- (length(wpar)+1)/2
m <- exp(wpar[1:m])
lambda <- exp(c(0, wpar[(m+1):(2*m-1)]))
delta return(list(lambda=lambda, delta=delta/sum(delta)))}
Hence, for a Poisson mixture distribution with means \(\lambda_1, = 10, \lambda_2 = 20, \lambda_3 = 25\) and probabilities \(\delta_1 = \delta_2 = \delta_3 = \frac{1}{3}\),
<- n2w(c(10, 20, 25), c(1,1,1)/3) wpar
w2n(nlm(mllk, wpar, eq_dat$Count)$estimate)
we obtain the following parameter estimates
lambda | delta |
---|---|
12.73573 | 0.2775329 |
19.78515 | 0.5928037 |
31.62940 | 0.1296634 |
and the negative log likelihood
nlm(mllk, wpar, eq_dat$Count)$minimum
## [1] 356.8489
Note: See Table 1.2 and Figure 1.4 of the textbook for a comparison of fitted mixture models with varying number of components.
Fitting a Poisson-HMM by Numerical Maximization
Note: See Introduction to Hidden Markov Models and Appendix A of the textbook.

Figure 8.3: Autocorrelation plot for major earthquakes.
Instead of fitting an (independent) Poisson mixture distribution, we may consider fitting a Poisson-HMM to account for the strong, positive serial dependence as evident in Figure 8.3.
Step 1: Reparameterize the “natural parameters” \(\boldsymbol{\Gamma}, \boldsymbol{\lambda}\), and \(\boldsymbol{\delta}\) to the “working parameters”.
Set \[\eta_i = \log \lambda_i \qquad{(i = 1, \dots, m)}\]
\[\nu_{ij} = \begin{cases} 1 & \qquad{\text{for } i = j} \\ \log(\gamma_{ij}) & \qquad{\text{for } i \neq j} \end{cases}\]
\[\delta_i = \begin{cases} \log \left(\frac{(\delta_2, \dots, \delta_m)}{\delta_1}\right) & \qquad{\text{if not stationary}}\\ \text{NULL} & \qquad{\text{otherwise}} \end{cases}\]
See Reparameterization to Avoid Constraints.
<- function(m,lambda,gamma,delta=NULL,stationary=TRUE){
pois.HMM.pn2pw
# eta = log(lambda)
<- log(lambda)
tlambda if(m==1) return(tlambda)
# For i = j, nu_ii = 1
<- log(gamma/diag(gamma))
foo
# For i != j, nu_ij = log(gamma_ij)
<- as.vector(foo[!diag(m)])
tgamma
# If stationary, set to pi = null
if(stationary) {tdelta <- NULL}
# Otherwise, pi = log((delta_2, ..., delta_m)/delta_1)
else {tdelta <- log(delta[-1]/delta[1])}
<- c(tlambda,tgamma,tdelta)
parvect return(parvect)
}
Note: pois.HMM.pn2pw
takes in arguments m
number of states (numeric), lambda
Poisson means (vector), delta
initial probabilities, and stationary
(TRUE/FALSE
). By default, the MC is assumed to be stationary with the initial distribution equal to the stationary distribution. The function returns a vector containing the working parameters.
Step 2: Compute the log-likelihood by the forward algorithm using the scaling strategy.
The general algorithm is:
\(w_1 \leftarrow \boldsymbol{\delta P} (x_1) \boldsymbol{1'};\) \(\boldsymbol{\phi}_1 \leftarrow \boldsymbol{\delta P} (x_1);\) \(l \leftarrow \log w_1\)
for \(t=2, 3, \dots, T\)
\[\begin{align} \boldsymbol{v} &\leftarrow \boldsymbol{\phi}_{t-1} \boldsymbol{\Gamma P} (x_t)\\ u & \leftarrow \boldsymbol{v 1'}\\ l &\leftarrow l + \log u\\ \boldsymbol{\phi}_t & \leftarrow \frac{\boldsymbol{v}}{u} \end{align}\]
See Scaling the Likelihood Computation and Note (4).
<- function(x,mod){
pois.HMM.lforward
<- length(x)
n <- matrix(NA,mod$m,n)
lalpha
# At time t=1
<- mod$delta*dpois(x[1],mod$lambda)
foo <- sum(foo)
sumfoo <- log(sumfoo)
lscale <- foo/sumfoo
foo
1] <- lscale+log(foo)
lalpha[,
# For t > 1
for (i in 2:n){
<- foo%*%mod$gamma*dpois(x[i],mod$lambda)
foo <- sum(foo)
sumfoo <- lscale+log(sumfoo)
lscale <- foo/sumfoo
foo <- log(foo)+lscale
lalpha[,i]
}return(lalpha)
}
Note: pois.HMM.lforward
takes in arguments x
data and mod
list consisting of m
states, lambda
means for the Poisson state-dependent distribution, and delta
initial probabilities.
Step 3: Maximize the log-likelihood/Minimize the negative log-likelihood
The function nlm
in R performs the minimization of any function using a Newton-type algorithm. In order to minimize the negative log-likelihood, we first write a function that compute the negative log-likelihood from the working parameters. The same forward algorithm scheme applies.
<- function(parvect,x,m,stationary=TRUE,...)
pois.HMM.mllk
{if(m==1) return(-sum(dpois(x,exp(parvect),log=TRUE)))
<- length(x)
n <- pois.HMM.pw2pn(m,parvect,stationary=stationary)
pn <- pn$delta*dpois(x[1],pn$lambda)
foo <- sum(foo)
sumfoo <- log(sumfoo)
lscale <- foo/sumfoo
foo for (i in 2:n)
{if(!is.na(x[i])){P<-dpois(x[i],pn$lambda)}
else {P<-rep(1,m)}
<- foo %*% pn$gamma*P
foo <- sum(foo)
sumfoo <- lscale+log(sumfoo)
lscale <- foo/sumfoo
foo
}<- -lscale
mllk return(mllk)
}
Step 4: Transform the parameters back into natural parameters.
Set
\[\hat{\lambda_i} = \exp(\hat{\eta_i}) \qquad{(i = 1, \dots, m)}\]
\[\hat{\gamma}_{ij} = \frac{\exp(\hat{\nu_{ik}})}{\sum_{k=1, k \neq i}^m\exp(\hat{\nu_ik})} \qquad{\text{for } (i, j = 1, \dots, m)}\]
\[\hat{\boldsymbol{\delta}} = \begin{cases} \boldsymbol{1} (\boldsymbol{I} - \hat{\boldsymbol{\Gamma}} + \boldsymbol{U})^{-1}& \qquad{\text{if stationary}}\\ \frac{(1, \exp(\hat{\delta_2}), \dots, \exp(\hat{\delta}_m))}{1 + \exp(\hat{\delta_2}) + \dots + \exp(\hat{\delta}_m)} & \qquad{\text{otherwise}} \end{cases}\]
<- function(m,parvect,stationary=TRUE){
pois.HMM.pw2pn <- exp(parvect[1:m])
lambda <- diag(m)
gamma if (m==1) return(list(lambda=lambda,gamma=gamma,delta=1))
!gamma] <- exp(parvect[(m+1):(m*m)])
gamma[<- gamma/apply(gamma,1,sum)
gamma if(stationary){delta<-solve(t(diag(m)-gamma+1),rep(1,m))}
else {foo<-c(1,exp(parvect[(m*m+1):(m*m+m-1)]))
<-foo/sum(foo)}
deltareturn(list(lambda=lambda,gamma=gamma,delta=delta))
}
Note: pois.HMM.pw2pn
takes in arguments m
number of states, parvect
working parameters (vector), and stationary
(TRUE/FALSE
). By default, the MC is assumed to be stationary with the initial distribution equal to the stationary distribution. The function returns a list containing the natural parameters.
We can combine the parts above into the pois.HMM.mle
function.
<- function(x,m,lambda0,gamma0,delta0=NULL,stationary=TRUE,...){
pois.HMM.mle <- pois.HMM.pn2pw(m,lambda0,gamma0,delta0,stationary=stationary)
parvect0 <- nlm(pois.HMM.mllk,parvect0,x=x,m=m,stationary=stationary)
mod <- pois.HMM.pw2pn(m=m,mod$estimate,stationary=stationary)
pn <- mod$minimum
mllk <- length(parvect0)
np <- 2*(mllk+np)
AIC <- sum(!is.na(x))
n <- 2*mllk+np*log(n)
BIC list(m=m,lambda=pn$lambda,gamma=pn$gamma,delta=pn$delta,code=mod$code,mllk=mllk,AIC=AIC,BIC=BIC)
}
Hence, for a three-state Poisson-HMM with the following parameters
\[\boldsymbol{\lambda} = (10, 20, 25)\]
\[\boldsymbol{\Gamma} = \begin{pmatrix} 0.8 & 0.1 & 0.1\\ 0.1 & 0.8 & 0.1\\ 0.1 & 0.1 & 0.8 \end{pmatrix}\]
= 3
m = c(10, 20, 25)
lambda = matrix(c(0.8,0.1,0.1,0.1,0.8,0.1,0.1,0.1,0.8),3,3,byrow=TRUE) gamma
if we assume that the MC is stationary
<- list(m=m,
eq_init_s lambda=lambda,
gamma = gamma)
<-pois.HMM.mle(eq_dat$Count, eq_init_s$m,eq_init_s$lambda,eq_init_s$gamma,stationary=TRUE)) (mod3s
## $m
## [1] 3
##
## $lambda
## [1] 13.14573 19.72101 29.71437
##
## $gamma
## [,1] [,2] [,3]
## [1,] 9.546243e-01 0.0244426 0.02093313
## [2,] 4.976679e-02 0.8993673 0.05086592
## [3,] 1.504495e-09 0.1966420 0.80335799
##
## $delta
## [1] 0.4436420 0.4044983 0.1518597
##
## $code
## [1] 1
##
## $mllk
## [1] 329.4603
##
## $AIC
## [1] 676.9206
##
## $BIC
## [1] 700.976
and if we do not assume stationary and that \(\boldsymbol{\delta} = (\frac{1}{3}, \frac{1}{3}, \frac{1}{3})\) and that the initial distribution is \(\boldsymbol{\delta} = (\frac{1}{3}, \frac{1}{3}, \frac{1}{3})\)
<- list(m=m,
eq_init_ns lambda=lambda,
gamma = gamma,
delta = rep(1, m)/m)
<- pois.HMM.mle(eq_dat$Count,eq_init_ns$m,eq_init_ns$lambda,eq_init_ns$gamma,delta=eq_init_ns$delta,stationary=FALSE)) (mod3h
## $m
## [1] 3
##
## $lambda
## [1] 13.13374 19.71312 29.70964
##
## $gamma
## [,1] [,2] [,3]
## [1,] 9.392937e-01 0.03209754 0.02860881
## [2,] 4.040106e-02 0.90643731 0.05316163
## [3,] 9.052023e-12 0.19025401 0.80974599
##
## $delta
## [1] 9.999998e-01 8.700482e-08 8.281945e-08
##
## $code
## [1] 1
##
## $mllk
## [1] 328.5275
##
## $AIC
## [1] 679.055
##
## $BIC
## [1] 708.4561
Parametric Bootstrapping for Confidence Intervals
We can also perform parameteric bootstrapping to obtain confidence intervals of the above estimates.
Note: See Obtaining Standard Errors and Confidence Intervals.
Step 1: Fit the model
<- pois.HMM.mle(eq_dat$Count,eq_init_ns$m,eq_init_ns$lambda,eq_init_ns$gamma,delta=eq_init_ns$delta,stationary=FALSE) eq_mle
Step 2: Generate a bootstrap sample from the fitted model.
The following function generates a sample from a Poisson-HMM of length ny
from starting values m
number of states, lambda
means for the Poisson state-dependent distribution, and delta
initial probabilities which are stored as mod
(list).
<- function(ny,mod){
pois.HMM.generate_sample <- 1:mod$m
mvect <- numeric(ny)
state 1] <- sample(mvect,1,prob=mod$delta)
state[for (i in 2:ny) state[i] <- sample(mvect,1,prob=mod$gamma[state[i-1],])
<- rpois(ny,lambda=mod$lambda[state])
x return(x)
}
<- pois.HMM.generate_sample(length(eq_dat$Count), eq_mle) boot_sample
Step 3: Estimate parameters using the bootstrap sample.
<- pois.HMM.mle(boot_sample, eq_mle$m, eq_mle$lambda, eq_mle$gamma) boot_mle
## Warning in nlm(pois.HMM.mllk, parvect0, x = x, m = m, stationary = stationary):
## NA/Inf replaced by maximum positive value
Step 4: Repeat (for a large) B times.
We can combine the parts above into the pois.HMM.boot
function.
<- function(B, x, m, lambda0, gamma0, delta0=NULL, stationary=TRUE){
pois.HMM.boot
# Fit the model
<- pois.HMM.mle(x, m, lambda0, gamma0, stationary=stationary)
mod
# Initialize
<- list()
bs_sample <- list()
bs_mod
# Generate B bootstrap samples
for(i in 1:B){
= TRUE
a while(a){
tryCatch({
set.seed(i)
<- pois.HMM.generate_sample(length(x), mod)
bs_sample[[i]] <- pois.HMM.mle(bs_sample[[i]], m, mod$lambda, mod$gamma, mod$delta)
bs_mod[[i]] = FALSE
a
},error=function(w){
= TRUE
a
})
}
}return(bs_mod)
}
Note: Some errors would occasionally arise from solving the stationary distribution of bootstrap samples that may not have had a unique stationary distribution. To overcome this, the tryCatch
function was used to throw out these problematic samples and regenerate a new sample. As there were at most two samples that resulted in the error, the generated bootstrap samples should still be representative of the dataset.
Hence, for the three-state Poisson-HMM with parameters
\[\boldsymbol{\lambda} = (10, 20, 25)\]
\[\boldsymbol{\Gamma} = \begin{pmatrix} 0.8 & 0.1 & 0.1\\ 0.1 & 0.8 & 0.1\\ 0.1 & 0.1 & 0.8 \end{pmatrix}\]
\[\boldsymbol{\delta} = (\frac{1}{3}, \frac{1}{3}, \frac{1}{3})\]
<- pois.HMM.boot(500, eq_dat$Count, eq_init_ns$m, eq_init_ns$lambda, eq_init_ns$gamma, delta=eq_init_ns$delta) eq_boot
and the \(90\%\) confidence interval using the “percentile method”
# Create dataframe for parameters from bootstrap samples
<- sapply(eq_boot, "[[", 2)
eq_lambda_boot <- t(eq_lambda_boot)
eq_lambda_boot <- as.data.frame(eq_lambda_boot)
eq_lambda_boot
<- sapply(eq_boot, "[[", 3)
eq_gamma_boot <- t(eq_gamma_boot)
eq_gamma_boot <- as.data.frame(eq_gamma_boot)
eq_gamma_boot
<- sapply(eq_boot, "[[", 4)
eq_delta_boot <- t(eq_delta_boot)
eq_delta_boot <- as.data.frame(eq_delta_boot)
eq_delta_boot
# Obtain the 90% confidence interval
<- t(cbind(sapply(eq_lambda_boot, quantile, probs=c(0.05, 0.95)),
eq_boot_df sapply(eq_gamma_boot, quantile, probs=c(0.05, 0.95)),
sapply(eq_delta_boot, quantile, probs=c(0.05, 0.95)))) %>%
as.data.frame()
rownames(eq_boot_df)[1:3] <- paste0("lambda", 1:3)
rownames(eq_boot_df)[4:6] <- paste0("gamma", 1, 1:3)
rownames(eq_boot_df)[7:9] <- paste0("gamma", 2, 1:3)
rownames(eq_boot_df)[10:12] <- paste0("gamma", 3, 1:3)
rownames(eq_boot_df)[13:15] <- paste0("delta", 1:3)
%>%
eq_boot_df round(4) %>%
kbl(caption="Bootstrap 90% Confidence Intervals for the parameters of the three-state HMM.") %>%
kable_minimal(full_width=T)
5% | 95% | |
---|---|---|
lambda1 | 11.8405 | 14.6116 |
lambda2 | 16.9308 | 22.0249 |
lambda3 | 19.4806 | 33.0097 |
gamma11 | 0.8232 | 0.9880 |
gamma12 | 0.0137 | 0.2132 |
gamma13 | 0.0000 | 0.0000 |
gamma21 | 0.0000 | 0.1162 |
gamma22 | 0.6603 | 0.9637 |
gamma23 | 0.0515 | 0.5534 |
gamma31 | 0.0000 | 0.1108 |
gamma32 | 0.0000 | 0.1908 |
gamma33 | 0.4466 | 0.9485 |
delta1 | 0.1370 | 0.7485 |
delta2 | 0.1114 | 0.6606 |
delta3 | 0.0404 | 0.3770 |

Figure 8.4: 500 Bootstrap samples for the state-dependent parameters of the fitted three-state Poisson-HMM. The area within the red dotted lines correspond to the 90% confidence interval.

Figure 8.5: 500 Bootstrap samples for the initial probabilities of the fitted three-state Poisson-HMM. The area within the red dotted lines correspond to the 90% confidence interval.

Figure 8.6: 500 Bootstrap samples for the transition probabilities of the fitted three-state Poisson-HMM. The area within the red dotted lines correspond to the 90% confidence interval.
Using momentuHMM
We can also fit the three-state Poisson-HMM from the above using momentuHMM
, which is a popular package for the maximum likelihood analysis of animal movement behaviour using multivariate Hidden Markov Models. McClintock and Michelot (2018)
First, convert the data into the prepData
object and set the names of the states. Since
# prepData
<- prepData(eq_dat,
eq_prepped coordNames = NULL,
covNames = c("Count"))
# Name the states
<- c("state1", "state2", "state3") stateNames
Next, specify the state-dependent model. In our case, we fit the intercept only model.
# Fit intercept only model
= ~ 1 formula
Now, fit the model using fitHMM
<- fitHMM(eq_prepped,
mod3h_momentuHMM nbStates=3,
dist=list(Count="pois"),
Par0 = list(Count = eq_init_ns$lambda, delta=eq_init_ns$delta),
formula = formula,
stateNames = stateNames,
stationary = FALSE)
The resulting MLEs are very similar to that obtained from running the functions from above.
mod3h_momentuHMM
## Value of the maximum log-likelihood: -328.5884
##
##
## Count parameters:
## -----------------
## state1 state2 state3
## lambda 13.13513 19.70822 29.70794
##
## Regression coeffs for the transition probabilities:
## ---------------------------------------------------
## 1 -> 2 1 -> 3 2 -> 1 2 -> 3 3 -> 1 3 -> 2
## (Intercept) -3.42222 -3.520977 -3.119039 -2.83615 -28.60659 -1.448253
##
## Transition probability matrix:
## ------------------------------
## state1 state2 state3
## state1 9.414330e-01 0.03072828 0.02783867
## state2 4.007763e-02 0.90674107 0.05318130
## state3 3.052488e-13 0.19027062 0.80972938
##
## Initial distribution:
## ---------------------
## state1 state2 state3
## 1.000000e+00 1.833456e-08 1.427794e-08
The corresponding \(95 \%\) confidence intervals are
CIreal(mod3h_momentuHMM)
## $Count
## $Count$est
## state1 state2 state3
## lambda 13.13513 19.70822 29.70794
##
## $Count$se
## state1 state2 state3
## lambda 0.6600995 0.8708107 1.679509
##
## $Count$lower
## state1 state2 state3
## lambda 11.84136 18.00146 26.41616
##
## $Count$upper
## state1 state2 state3
## lambda 14.4289 21.41497 32.99972
##
##
## $gamma
## $gamma$est
## state1 state2 state3
## state1 9.414330e-01 0.03072828 0.02783867
## state2 4.007763e-02 0.90674107 0.05318130
## state3 3.052488e-13 0.19027062 0.80972938
##
## $gamma$se
## state1 state2 state3
## state1 4.445528e-02 0.04082282 0.03293175
## state2 3.190339e-02 0.05399426 0.04414623
## state3 4.291928e-14 0.11385140 0.11385140
##
## $gamma$lower
## state1 state2 state3
## state1 7.679853e-01 0.002155143 0.002630290
## state2 8.151374e-03 0.735557101 0.009973817
## state3 2.317242e-13 0.052321545 0.499974591
##
## $gamma$upper
## state1 state2 state3
## state1 9.873516e-01 0.3175655 0.2371871
## state2 1.749874e-01 0.9714172 0.2384795
## state3 4.021022e-13 0.5000254 0.9476785
##
##
## $delta
## $delta$est
## state1 state2 state3
## ID:Animal1 1 1.833456e-08 1.427794e-08
##
## $delta$se
## state1 state2 state3
## ID:Animal1 1.046115e-13 1.046128e-13 1.493643e-21
##
## $delta$lower
## state1 state2 state3
## ID:Animal1 1 1.833436e-08 1.427794e-08
##
## $delta$upper
## state1 state2 state3
## ID:Animal1 1 1.833477e-08 1.427794e-08
Fitting a Poisson-HMM by the EM Algorithm
Note: See EM Algorithm (Baum-Welch)
Alternatively, we may obtain MLEs of the three-state Poisson HMM by the EM algorithm.
E-Step Replace all quantities \(v_jk (t)\), \(u_j (t)\) by their conditional expectations given the observations \(\boldsymbol{x}^{(T)}\) and current parameter estimates:
\[\hat{u}_j = \Pr (C_t = j|\boldsymbol{x}^{(T)}) = \frac{\alpha_t (j) \beta_t (j)}{L_T}\]
\[{\hat{v}}_{jk} (t) = \Pr (C_{t-1} = j, C_t = k| \boldsymbol{x}^{(T)}) \frac{\alpha_{t-1} (j) \gamma_{jk} p_k (x_t) \beta_t (k)}{L_T}\]
This can be broken down into
Step 1: Compute the forward and backward probabilities.
We can use the same forward algorithm from the above and apply the backward algorithm pois.HMM.lbackward
.
The general algorithm is:
\[\begin{align} \boldsymbol{\phi}_T \leftarrow \frac{\boldsymbol{1}}{w_T}$; $l \leftarrow \log w_T\\ \text{for } t = T-1, \dots, 1\\ \boldsymbol{v} &\leftarrow \boldsymbol{\Gamma P} (x_{t+1}) \boldsymbol{\phi_{t+1}}\\ l &\leftarrow l + \log \boldsymbol{v}\\ u &\leftarrow \boldsymbol{v 1'}\\ \boldsymbol{\phi}_t &\leftarrow \frac{\boldsymbol{v}}{u}\\ l & \leftarrow l + \log u \end{align}\]
<-function(x,mod){
pois.HMM.lbackward<- length(x)
n <- mod$m
m <- matrix(NA,m,n)
lbeta <- rep(0,m)
lbeta[,n]
# For t = T
<- rep(1/m,m)
foo <- log(m)
lscale
# For t = (T-1),..., 1
for (i in (n-1):1){
<- mod$gamma%*%(dpois(x[i+1],mod$lambda)*foo)
foo <- log(foo)+lscale
lbeta[,i] <- sum(foo)
sumfoo <- foo/sumfoo
foo <- lscale+log(sumfoo)
lscale
}return(lbeta)
}
Note: pois.HMM.lbackward
takes in the same arguments as the pois.HMM.lforward
.
Step 2: Replace \(u_j(t)\) by \(\hat{u}_j (t)\) and \(v_{jk}(t)\) by \(\hat{v}_{jk} (t)\).
<- function(x, mod){
uhat <- length(x)
n <- mod$m
m
# Forward probabilities
<- pois.HMM.lforward(x, mod)
la
# Backward probabilities
<- pois.HMM.lbackward(x, mod)
lb
<- max(la[,n])
c
# L_T (with some constant amount)
<- c + log(sum(exp(la[,n] - c)))
llk
# Initialize
<- matrix(NA, ncol=n, nrow=m)
stateprobs
## (a_t(j) b_t (j))/L_T
for(i in 1:n){
<- exp(la[, i] + lb[, i] - llk)
stateprobs[,i]
}return(stateprobs)
}
<- function(x, mod){
vhat <- length(x)
n <- mod$m
m
# Forward probabilities
<- pois.HMM.lforward(x, mod)
la
# Backward probabilities
<- pois.HMM.lbackward(x, mod)
lb
# tpm
<- log(mod$gamma)
lgamma <- max(la[, n])
c
# L_T (with some constant amount)
<- c + log(sum(exp(la[, n] - c)))
llk <- array(0, dim=c(m, m, n))
v <- matrix(NA, nrow=mod$m, ncol=n)
px
for(i in 1:n){
<- dpois(x[i], mod$lambda)
px[, i]
}<- log(px)
lpx
for(i in 2:n){
for(j in 1:mod$m){
for(k in 1:mod$m){
<- exp(la[j, i-1] + lgamma[j, k] + lpx[k, i] + lb[k, i] - llk)
v[j, k, i]
}
}
}return(v)
}
Note: The term c
in the code is a constant added to the log-forward and log-backward probabilities to prevent numerical underflow.
M-Step Maximize the complete data log-likelihood with respect to the parameter estimates, with functions of the missing data replaced by their conditional expectations.
That is, maximize
\[\begin{align} \log \left(\Pr(\boldsymbol{x}^{(T)}, \boldsymbol{c}^{(T)}) \right) &= \sum_{j=1}^m \hat{u}_j (1) + \log \delta_j + \sum_{j=1}^m \sum_{k=1}^m \left(\sum_{t=2}^T \hat{v}_{jk} (t)\right) \log \gamma_{jk} + \sum_{j=1}^m \sum_{t=1}^T \hat{u}_j (t) \log p_j (x_t) \end{align}\]
with respect to \(\boldsymbol{\theta} = (\boldsymbol{\delta}, \boldsymbol{\Gamma}, \boldsymbol{\lambda})\).
The maximizations of the parameters are given by
<- function(uhat){
E_delta <- uhat[, 1]
d return(d)
}
<- function(vhat, mod){
E_gamma <- apply(vhat, MARGIN=c(1, 2), FUN=sum)
num <- rowSums(num)
denom <- num/denom
g return(g)
}
<- function(x,mod,uhat){
E_pois_lambda <- length(x)
n <- mod$m
m <- matrix(rep(x, m), nrow=m, ncol=n, byrow=TRUE)
xx <- rowSums(uhat*xx)/rowSums(uhat)
lambda_hat return(lambda_hat)
}
We can combine the parts above into the BaumWelch
function. BaumWelch
performs the EM algorithm by taking initial model parameters as inputs, then repeatedly fitting until convergence or the maximum number of iterations is reached (by default maxit=50
).
<- function(x, m, lambda0, gamma0, delta0, maxit = 50){
BaumWelch # Initial parameters
<- list(m = m, lambda = lambda0, gamma = gamma0, delta = delta0)
mod_old <- 1
iter while(iter < maxit){
# E-step
<- uhat(x, mod_old)
u_hat <- vhat(x, mod_old)
v_hat
# M-step
<- E_delta(u_hat)
delta_new <- E_gamma(v_hat, mod_old)
gamma_new <- E_pois_lambda(x, mod_old, u_hat)
lambda_new
<- list(m=m, lambda=lambda_new, gamma=gamma_new, delta=delta_new)
mod_old = iter + 1
iter
}<- list(m=m, lambda=lambda_new, gamma=gamma_new, delta=delta_new)
mod return(mod)
}
Hence, for the three-state Poisson-HMM with parameters
\[\boldsymbol{\lambda} = (10, 20, 25)\]
\[\boldsymbol{\Gamma} = \begin{pmatrix} 0.8 & 0.1 & 0.1\\ 0.1 & 0.8 & 0.1\\ 0.1 & 0.1 & 0.8 \end{pmatrix}\]
\[\boldsymbol{\delta} = (\frac{1}{3}, \frac{1}{3}, \frac{1}{3})\]
# Fitting a three-state HMM
BaumWelch(eq_dat$Count, eq_init_ns$m, eq_init_ns$lambda, eq_init_ns$gamma, delta = eq_init_ns$delta)
## $m
## [1] 3
##
## $lambda
## [1] 13.13376 19.71316 29.70972
##
## $gamma
## [,1] [,2] [,3]
## [1,] 9.392939e-01 0.03209847 0.02860765
## [2,] 4.040172e-02 0.90643612 0.05316216
## [3,] 2.113508e-32 0.19025585 0.80974415
##
## $delta
## [1] 1.000000e+00 3.977303e-84 2.817232e-235
Forecasting, Decoding, and State Prediction
Note: See Forecasting, Decoding, and State Prediction and Appendix A of the textbook.
Forecasting
The forecast probabilities \(\Pr(X_{T+h} = x|\boldsymbol{X}^{(T)} = \boldsymbol{x}^{(T)})\) can be computed by
<- function(xf,h=1,x,mod)
pois.HMM.forecast
{<- length(x)
n <- length(xf)
nxf <- matrix(0,nrow=h,ncol=nxf)
dxf <- mod$delta*dpois(x[1],mod$lambda)
foo <- sum(foo)
sumfoo <- log(sumfoo)
lscale <- foo/sumfoo
foo for (i in 2:n)
{<- foo%*%mod$gamma*dpois(x[i],mod$lambda)
foo <- sum(foo)
sumfoo <- lscale+log(sumfoo)
lscale <- foo/sumfoo
foo
}for (i in 1:h)
{<- foo%*%mod$gamma
foo for (j in 1:mod$m) dxf[i,] <- dxf[i,] + foo[j]*dpois(xf,mod$lambda[j])
}return(dxf)
}
Note: pois.HMM.forecast
takes in arguments xf
the range of \(x\)-values for the forecast probabilities, h
the forecast horizon, x
data, and mod
list consisting of m
states, lambda
means for the Poisson state-dependent distribution, and delta
initial probabilities.
For example, the forecast distributions for 1 to 4 years ahead with possible values up to 45 earthquakes for the three-state Poisson-HMM (non-stationary) is

Figure 8.7: Forecast probabilities for the fitted three-state Poisson-HMM (non-stationary) for 1 to 4 years ahead.
The function from above can be modified to compute the bivariate forecast distribution.
<- function(xf1, xf2, x, mod){
pois.HMM.forecast_bivariate <- length(x)
n <- length(xf1)
nxf1 <- length(xf2)
nxf2 <- matrix(0, nrow=nxf1, ncol=nxf2)
dxf <- mod$delta*dpois(x[1], mod$lambda)
foo <- sum(foo)
sumfoo <- log(sumfoo)
lscale <- foo/sumfoo
foo
for(t in 2:n){
<- foo%*%mod$gamma*dpois(x[t], mod$lambda)
foo <- sum(foo)
sumfoo <- lscale + log(sumfoo)
lscale <- foo/sumfoo
foo
}
for (i in 1:nxf1){
for(j in 1:nxf2){
for(s in 1:mod$m){
<- dxf[i, j] + foo[s]*dpois(xf1[i], mod$lambda[s]) + foo[s]*dpois(xf2[j], mod$lambda[s])
dxf[i, j]
}
}
}
return(foo)
}
For example, \(\Pr(X_{T+1} \leq 10, X_{T+2} \leq 10|\boldsymbol{X}^{(T)})\) is
<- data.frame(pois.HMM.forecast_bivariate(1:10, 1:10,eq_dat$Count, eq_init_ns))
eq_forecast
%>%
eq_forecast kbl(caption="Bivariate Forecast Distribution of $X_{T+1}$ (rows) and $X_{T+2}$ (columns).") %>%
kable_minimal(full_width=T) %>%
kable_styling()
X1 | X2 | X3 |
---|---|---|
0.961864 | 0.0370039 | 0.0011321 |
Decoding
Local decoding can be computed using the forward and backward algorithms from above. Similar to computing \(\hat{u}\) in the E step of the EM algorithm, the pois.HMM.state_probs
computes the state probabilities then pois.HMM.local_decoding
determines the most likely state at each time.
<- function(x,mod)
pois.HMM.state_probs
{<- length(x)
n <- pois.HMM.lforward(x,mod)
la <- pois.HMM.lbackward(x,mod)
lb <- max(la[,n])
c <- c+log(sum(exp(la[,n]-c)))
llk <- matrix(NA,ncol=n,nrow=mod$m)
stateprobs for (i in 1:n) stateprobs[,i]<-exp(la[,i]+lb[,i]-llk)
return(stateprobs)
}
<- function(x,mod)
pois.HMM.local_decoding
{<- length(x)
n <- pois.HMM.state_probs(x,mod)
stateprobs <- rep(NA,n)
ild for (i in 1:n) ild[i]<-which.max(stateprobs[,i])
ild }
For example, local decoding for the three state Poisson-HMM (non-stationary) is
# Local decoding
<- pois.HMM.local_decoding(eq_dat$Count, eq_init_ns)) (earthquake_local
## [1] 1 1 1 1 1 3 3 3 3 3 3 3 3 3 3 2 2 2 2 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2
## [38] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2 2 2 3 1 2 2 2 2 2 2 2 2 2 3 3 3 3 2 2
## [75] 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 2 2 1 1 1 2 2 2 2 2 2 2 2 2 1 1 1

Figure 8.8: Local decoding for the three-state Poisson-HMM (non-stationary). The horizontal lines indicate the state-dependent means and the points indicate the decoded state at the given time.
We can also perform local decoding using momentuHMM
# Local decoding
## Compute state probabilities for each time step
<- stateProbs(mod3h_momentuHMM)
state_probs
## Select state that maximizes probability
<- rep(NA,length(eq_dat$Count))
local_vec for(i in 1:length(eq_dat$Count)) local_vec[i] <- which.max(state_probs[i,])
local_vec
## [1] 1 1 1 1 1 3 3 3 3 3 3 3 2 2 2 2 2 2 2 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2
## [38] 2 2 2 2 3 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 2 2 2
## [75] 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

Figure 8.9: Local decoding for the three-state Poisson-HMM (non-stationary). The horizontal lines indicate the state-dependent means and the points indicate the decoded state at the given time using pois.HMM.local_decoding (purple) and momentuHMM (orange).
Global decoding can be computed using the Viterbi algorithm
<-function(x,mod)
pois.HMM.viterbi
{<- length(x)
n <- matrix(0,n,mod$m)
xi <- mod$delta*dpois(x[1],mod$lambda)
foo 1,] <- foo/sum(foo)
xi[for (i in 2:n)
{<-apply(xi[i-1,]*mod$gamma,2,max)*dpois(x[i],mod$lambda)
foo<- foo/sum(foo)
xi[i,]
}<-numeric(n)
iv<-which.max(xi[n,])
iv[n] for (i in (n-1):1)
<- which.max(mod$gamma[,iv[i+1]]*xi[i,])
iv[i] return(iv)
}
For example, global decoding for the three state Poisson-HMM (non-stationary) is
<- pois.HMM.viterbi(eq_dat$Count, eq_init_ns)) (earthquake_global
## [1] 1 1 1 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2
## [38] 2 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 2 2
## [75] 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 1 1

Figure 8.10: Global decoding for the three-state Poisson-HMM (non-stationary).

Figure 8.11: Global (green) and local (brown) decoding for the three-state Poisson-HMM (non-stationary).
The result of local and global decoding are very similar but not identical.
Similarly, we can perform global decoding using momentuHMM
<- viterbi(mod3h_momentuHMM)) (global_vec
## [1] 1 1 1 1 1 3 3 3 3 3 3 2 2 2 2 2 2 2 2 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2
## [38] 2 2 2 2 2 3 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 2 2 2
## [75] 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
plotStates(mod3h_momentuHMM)
## Decoding state sequence... DONE
## Computing state probabilities... DONE

Figure 8.12: Global decoding for the three-state Poisson-HMM using pois.HMM.gocal_decoding (purple) and momentuHMM (orange).
There appears to be some differences between the results obtained from our function and from momentuHMM
.
State Predictions
The state prediction for \(h\) steps ahead can be computed by
<- function(h=1,x,mod)
pois.HMM.state_prediction
{<- length(x)
n <- pois.HMM.lforward(x,mod)
la <- max(la[,n])
c <- c+log(sum(exp(la[,n]-c)))
llk <- matrix(NA,ncol=h,nrow=mod$m)
statepreds <- exp(la[,n]-llk)
foo for (i in 1:h){
<-foo%*%mod$gamma
foo<-foo
statepreds[,i]
}return(statepreds)
}
For example, the state predictions for \(h=1, \dots, 5\) for the three-state Poisson-HMM (non-stationary)
pois.HMM.state_prediction(h=5, eq_dat$Count, eq_init_ns)
## [,1] [,2] [,3] [,4] [,5]
## [1,] 0.7733048 0.6413134 0.5489194 0.4842436 0.4389705
## [2,] 0.1259027 0.1881319 0.2316923 0.2621846 0.2835292
## [3,] 0.1007924 0.1705547 0.2193883 0.2535718 0.2775003
The stationary distribution is
# Compute stationary distribution
solve(t(diag(m)-gamma+1),rep(1,m))
## [1] 0.3333333 0.3333333 0.3333333
Notice that as \(h \rightarrow \infty\), the state distribution approaches the stationary distribution.
Fitting a Poisson-HMM using STAN
Note: See Bayesian Inference for HMMs, Leos-Barajas and Michelot (2018), and Damiano, Peterson, and Weylandt (2017).
We can perform Bayesian inference for the three-state Poisson-HMM using STAN Stan Development Team (2023).
In STAN, the main building blocks are the:
data block
: used to define the input data for the model to fit in STAN. Declare the data types, their dimensions, any restrictions, and their names of the data to model.
Here, we specify the length of the sequence of the earthquake series, the number of states, and the vector of observed earthquake counts.
'data{
int<lower=0> m; // number of states
int<lower=1> T; // length of sequence
int<lower=0> x[T]; // observations
}
'
parameters block
: used to define the parameters of the model that will be estimated. Declare the data types, their dimensions, any restrictions, and their names of the parameters to model.
Here, we specify the state-dependent means, transition probability matrix, and the initial distribution (assuming non-stationarity).
'parameters{
simplex[m] Gamma[m]; // transition probability matrix
positive_ordered[m] lambda; // state-dependent means (ordered to prevent label switching)
}
transformed parameters block
: used to define any derived parameters that are not directly estimated but are derived from the parameters defined in the previous block. Declare the data types, their dimensions, any restrictions, their names, and the operation of the parameters to transform.
If we assume that the Markov Chain is stationary, then we can compute the stationary distribution from the tpm.
'transformed parameters{
matrix[m, m] ta; // tpm used to compute stationary distribution
simplex[m] statdist; // stationary distribution
for(j in 1:m){
for(i in 1:m){
ta[i, j] = Gamma[i, j];
}
}
//compute stationary distribution
statdist = to_vector((to_row_vector(rep_vector(1.0, m))/
(diag_matrix(rep_vector(1.0, m)) - ta + rep_matrix(1, m, m))));
}
'
Note: The tpm is transposed so that each row corresponds to the probabilities of transitioning into a state, rather than out of a state.
model block
: used to define the prior distribution, likelihood, and any other necessary variables.
Here, we use the following prior specifications:
\[\boldsymbol{\lambda} \sim Gamma(\alpha=1, \beta=0.01)\]
\[\boldsymbol{\Gamma} \sim Unif(-\infty, \infty)\]
\[\boldsymbol{\delta} \sim Unif(-\infty, \infty)\] The forward algorithm can be used to obtain the posterior distribution of the hidden states at a given time \(t\) based on all the information available up to that time \(\Pr(C_t|\boldsymbol{X}^{(t)})\).
\[\begin{align} \log (\alpha_t, j) &= \log \left(\sum_{i=1}^m \gamma_{ij} \alpha_{t-1, i} \right)\\ &= \log \left(\sum_{i=1}^m \exp (\log (\gamma_{ij}) + \log (\alpha_{t-1, i}))\right) \end{align}\]
'model{
vector[m] log_Gamma_tr[m];
vector[m] lp;
vector[m] lp_p1;
// priors
lambda ~ gamma(1, 0.01);
// transpose tpm and take log of entries
for(i in 1:m)
for(j in 1:m)
log_Gamma_tr[j, i] = log(Gamma[i, j]);
// forward algorithm
// for t = 1
for(i in 1:m)
lp[i] = log(statdist[i]) + poisson_lpmf(x[1]|lambda[i]);
// for t > 1
for(t in 2:T){
for (i in 1:m)
lp_p1[i] = log_sum_exp(log_Gamma_tr[i] + lp) + poisson_lpmf(x[t]|lambda[i]);
lp = lp_p1;
}
target += log_sum_exp(lp);
}
'
## [1] "model{\n vector[m] log_Gamma_tr[m];\n vector[m] lp;\n vector[m] lp_p1;\n\n // priors\n lambda ~ gamma(1, 0.01);\n\n // transpose tpm and take log of entries\n for(i in 1:m)\n for(j in 1:m)\n log_Gamma_tr[j, i] = log(Gamma[i, j]);\n \n // forward algorithm\n // for t = 1\n for(i in 1:m)\n lp[i] = log(statdist[i]) + poisson_lpmf(x[1]|lambda[i]);\n \n // for t > 1\n for(t in 2:T){\n for (i in 1:m)\n lp_p1[i] = log_sum_exp(log_Gamma_tr[i] + lp) + poisson_lpmf(x[t]|lambda[i]);\n \n lp = lp_p1;\n }\n target += log_sum_exp(lp);\n }\n"
All together,
<-
pois.HMM.stan 'data{
int<lower=0> m; // number of states
int<lower=1> T; // length of sequence
int<lower=0> x[T]; // observations
}
parameters{
simplex[m] Gamma[m]; // tpm
positive_ordered[m] lambda; // ordered mean of state-dependent (prevent label switching)
}
transformed parameters{
matrix[m, m] ta; // tpm used to compute stationary distribution
simplex[m] statdist; // stationary distribution
for(j in 1:m){
for(i in 1:m){
ta[i, j] = Gamma[i, j];
}
}
//compute stationary distribution
statdist = to_vector((to_row_vector(rep_vector(1.0, m))/
(diag_matrix(rep_vector(1.0, m)) - ta + rep_matrix(1, m, m))));
}
model{
// initialise
vector[m] log_Gamma_tr[m];
vector[m] lp;
vector[m] lp_p1;
// priors
lambda ~ gamma(1, 0.01);
// transpose tpm and take log of entries
for(i in 1:m)
for(j in 1:m)
log_Gamma_tr[j, i] = log(Gamma[i, j]);
// forward algorithm
// for t = 1
for(i in 1:m)
lp[i] = log(statdist[i]) + poisson_lpmf(x[1]|lambda[i]);
// loop over observations
for(t in 2:T){
// loop over states
for (i in 1:m)
lp_p1[i] = log_sum_exp(log_Gamma_tr[i] + lp) + poisson_lpmf(x[t]|lambda[i]);
lp = lp_p1;
}
target += log_sum_exp(lp);
}
'
Then for the three state-Poisson HMM,
# Format data into list for STAN
<- list(T=dim(eq_dat)[1], m=3, x=eq_dat$Count) stan_data
Running 2000 iterations for each of the 4 chains, with the first 1000 draws drawn during the warm-up phase,
<- stan(model_code = pois.HMM.stan, data = stan_data, refresh=2000) pois.HMM.stanfit
## Trying to compile a simple C file
## Running /Library/Frameworks/R.framework/Resources/bin/R CMD SHLIB foo.c
## clang -arch arm64 -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG -I"/Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library/Rcpp/include/" -I"/Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library/RcppEigen/include/" -I"/Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library/RcppEigen/include/unsupported" -I"/Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library/BH/include" -I"/Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library/StanHeaders/include/src/" -I"/Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library/StanHeaders/include/" -I"/Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library/RcppParallel/include/" -I"/Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library/rstan/include" -DEIGEN_NO_DEBUG -DBOOST_DISABLE_ASSERTS -DBOOST_PENDING_INTEGER_LOG2_HPP -DSTAN_THREADS -DBOOST_NO_AUTO_PTR -include '/Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library/StanHeaders/include/stan/math/prim/mat/fun/Eigen.hpp' -D_REENTRANT -DRCPP_PARALLEL_USE_TBB=1 -I/opt/R/arm64/include -fPIC -falign-functions=64 -Wall -g -O2 -c foo.c -o foo.o
## In file included from <built-in>:1:
## In file included from /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library/StanHeaders/include/stan/math/prim/mat/fun/Eigen.hpp:13:
## In file included from /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library/RcppEigen/include/Eigen/Dense:1:
## In file included from /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library/RcppEigen/include/Eigen/Core:88:
## /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library/RcppEigen/include/Eigen/src/Core/util/Macros.h:628:1: error: unknown type name 'namespace'
## namespace Eigen {
## ^
## /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library/RcppEigen/include/Eigen/src/Core/util/Macros.h:628:16: error: expected ';' after top level declarator
## namespace Eigen {
## ^
## ;
## In file included from <built-in>:1:
## In file included from /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library/StanHeaders/include/stan/math/prim/mat/fun/Eigen.hpp:13:
## In file included from /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library/RcppEigen/include/Eigen/Dense:1:
## /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library/RcppEigen/include/Eigen/Core:96:10: fatal error: 'complex' file not found
## #include <complex>
## ^~~~~~~~~
## 3 errors generated.
## make: *** [foo.o] Error 1
##
## SAMPLING FOR MODEL '9875485ac4343cdf02f82dbe9761d256' NOW (CHAIN 1).
## Chain 1:
## Chain 1: Gradient evaluation took 0.000123 seconds
## Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 1.23 seconds.
## Chain 1: Adjust your expectations accordingly!
## Chain 1:
## Chain 1:
## Chain 1: Iteration: 1 / 2000 [ 0%] (Warmup)
## Chain 1: Iteration: 1001 / 2000 [ 50%] (Sampling)
## Chain 1: Iteration: 2000 / 2000 [100%] (Sampling)
## Chain 1:
## Chain 1: Elapsed Time: 0.820039 seconds (Warm-up)
## Chain 1: 0.450072 seconds (Sampling)
## Chain 1: 1.27011 seconds (Total)
## Chain 1:
##
## SAMPLING FOR MODEL '9875485ac4343cdf02f82dbe9761d256' NOW (CHAIN 2).
## Chain 2:
## Chain 2: Gradient evaluation took 5e-05 seconds
## Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 0.5 seconds.
## Chain 2: Adjust your expectations accordingly!
## Chain 2:
## Chain 2:
## Chain 2: Iteration: 1 / 2000 [ 0%] (Warmup)
## Chain 2: Iteration: 1001 / 2000 [ 50%] (Sampling)
## Chain 2: Iteration: 2000 / 2000 [100%] (Sampling)
## Chain 2:
## Chain 2: Elapsed Time: 0.823041 seconds (Warm-up)
## Chain 2: 0.527402 seconds (Sampling)
## Chain 2: 1.35044 seconds (Total)
## Chain 2:
##
## SAMPLING FOR MODEL '9875485ac4343cdf02f82dbe9761d256' NOW (CHAIN 3).
## Chain 3:
## Chain 3: Gradient evaluation took 4.9e-05 seconds
## Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 0.49 seconds.
## Chain 3: Adjust your expectations accordingly!
## Chain 3:
## Chain 3:
## Chain 3: Iteration: 1 / 2000 [ 0%] (Warmup)
## Chain 3: Iteration: 1001 / 2000 [ 50%] (Sampling)
## Chain 3: Iteration: 2000 / 2000 [100%] (Sampling)
## Chain 3:
## Chain 3: Elapsed Time: 0.812108 seconds (Warm-up)
## Chain 3: 0.457366 seconds (Sampling)
## Chain 3: 1.26947 seconds (Total)
## Chain 3:
##
## SAMPLING FOR MODEL '9875485ac4343cdf02f82dbe9761d256' NOW (CHAIN 4).
## Chain 4:
## Chain 4: Gradient evaluation took 4.9e-05 seconds
## Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 0.49 seconds.
## Chain 4: Adjust your expectations accordingly!
## Chain 4:
## Chain 4:
## Chain 4: Iteration: 1 / 2000 [ 0%] (Warmup)
## Chain 4: Iteration: 1001 / 2000 [ 50%] (Sampling)
## Chain 4: Iteration: 2000 / 2000 [100%] (Sampling)
## Chain 4:
## Chain 4: Elapsed Time: 0.76585 seconds (Warm-up)
## Chain 4: 0.455552 seconds (Sampling)
## Chain 4: 1.2214 seconds (Total)
## Chain 4:
we obtain the following posterior estimates
print(pois.HMM.stanfit,digits_summary = 3)
## Inference for Stan model: 9875485ac4343cdf02f82dbe9761d256.
## 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%
## Gamma[1,1] 0.862 0.002 0.085 0.669 0.825 0.879 0.919 0.966
## Gamma[1,2] 0.091 0.002 0.076 0.006 0.039 0.073 0.122 0.274
## Gamma[1,3] 0.047 0.001 0.042 0.002 0.017 0.036 0.066 0.152
## Gamma[2,1] 0.090 0.002 0.065 0.014 0.048 0.077 0.115 0.237
## Gamma[2,2] 0.817 0.002 0.085 0.626 0.778 0.831 0.874 0.935
## Gamma[2,3] 0.093 0.001 0.058 0.015 0.051 0.083 0.120 0.237
## Gamma[3,1] 0.077 0.001 0.069 0.002 0.025 0.059 0.110 0.249
## Gamma[3,2] 0.231 0.002 0.115 0.055 0.148 0.214 0.300 0.493
## Gamma[3,3] 0.691 0.002 0.124 0.423 0.609 0.706 0.783 0.891
## lambda[1] 13.198 0.019 0.857 11.423 12.686 13.221 13.729 14.875
## lambda[2] 19.828 0.026 1.069 17.689 19.181 19.836 20.478 21.929
## lambda[3] 29.905 0.036 1.905 26.419 28.600 29.855 31.105 33.882
## ta[1,1] 0.862 0.002 0.085 0.669 0.825 0.879 0.919 0.966
## ta[1,2] 0.091 0.002 0.076 0.006 0.039 0.073 0.122 0.274
## ta[1,3] 0.047 0.001 0.042 0.002 0.017 0.036 0.066 0.152
## ta[2,1] 0.090 0.002 0.065 0.014 0.048 0.077 0.115 0.237
## ta[2,2] 0.817 0.002 0.085 0.626 0.778 0.831 0.874 0.935
## ta[2,3] 0.093 0.001 0.058 0.015 0.051 0.083 0.120 0.237
## ta[3,1] 0.077 0.001 0.069 0.002 0.025 0.059 0.110 0.249
## ta[3,2] 0.231 0.002 0.115 0.055 0.148 0.214 0.300 0.493
## ta[3,3] 0.691 0.002 0.124 0.423 0.609 0.706 0.783 0.891
## statdist[1] 0.391 0.002 0.142 0.143 0.286 0.380 0.485 0.688
## statdist[2] 0.418 0.002 0.130 0.172 0.326 0.416 0.509 0.679
## statdist[3] 0.191 0.001 0.092 0.056 0.124 0.177 0.240 0.414
## lp__ -345.917 0.079 2.515 -351.814 -347.287 -345.502 -344.077 -342.235
## n_eff Rhat
## Gamma[1,1] 2066 1.000
## Gamma[1,2] 1987 1.000
## Gamma[1,3] 4086 1.001
## Gamma[2,1] 1333 1.002
## Gamma[2,2] 1526 1.002
## Gamma[2,3] 3405 1.000
## Gamma[3,1] 3718 1.001
## Gamma[3,2] 4353 1.000
## Gamma[3,3] 3762 1.001
## lambda[1] 1953 1.002
## lambda[2] 1658 1.000
## lambda[3] 2877 1.001
## ta[1,1] 2066 1.000
## ta[1,2] 1987 1.000
## ta[1,3] 4086 1.001
## ta[2,1] 1333 1.002
## ta[2,2] 1526 1.002
## ta[2,3] 3405 1.000
## ta[3,1] 3718 1.001
## ta[3,2] 4353 1.000
## ta[3,3] 3762 1.001
## statdist[1] 5011 1.000
## statdist[2] 3710 1.001
## statdist[3] 4474 1.001
## lp__ 1025 1.004
##
## Samples were drawn using NUTS(diag_e) at Fri Jun 16 13:19:35 2023.
## For each parameter, n_eff is a crude measure of effective sample size,
## and Rhat is the potential scale reduction factor on split chains (at
## convergence, Rhat=1).

Figure 8.13: Posterior distribution for the state-dependent means of the three-state Poisson-HMM.

Figure 8.14: Posterior distribution for the state-dependent means of the three-state Poisson-HMM.

Figure 8.15: Posterior distribution for the state-dependent means of the three-state Poisson-HMM.

Figure 8.16: Posterior distribution for the transition probabilities of the three-state Poisson-HMM.

Figure 8.17: Posterior distribution for the transition probabilities of the three-state Poisson-HMM.

Figure 8.18: Posterior distribution for the transition probabilities of the three-state Poisson-HMM.

Figure 8.19: Posterior distribution for the transition probabilities of the three-state Poisson-HMM.

Figure 8.20: Posterior distribution for the transition probabilities of the three-state Poisson-HMM.

Figure 8.21: Posterior distribution for the transition probabilities of the three-state Poisson-HMM.

Figure 8.22: Posterior distribution for the transition probabilities of the three-state Poisson-HMM.

Figure 8.23: Posterior distribution for the transition probabilities of the three-state Poisson-HMM.

Figure 8.24: Posterior distribution for the transition probabilities of the three-state Poisson-HMM.

Figure 8.25: Posterior distribution for the initial distribution of the three-state Poisson-HMM.

Figure 8.26: Posterior distribution for the initial distribution of the three-state Poisson-HMM.

Figure 8.27: Posterior distribution for the initial distribution of the three-state Poisson-HMM.