Generate observed symbol sequences from a discrete hidden
Markov model (HMM). For each sequence a latent state path is drawn from
the Markov chain defined by init (initial distribution) and
trans (state transition matrix); each hidden state then emits an
observed symbol according to the emission matrix. The true latent
paths are returned in $params$hidden_paths for parameter-recovery
testing.
Usage
simulate_hmm(
n_sequences = 50,
seq_length = 30,
n_states = 2,
n_symbols = 3,
trans = NULL,
emission = NULL,
init = NULL,
seed = NULL
)Arguments
- n_sequences
Integer. Number of sequences to simulate. Default: 50.
- seq_length
Integer. Length (number of time points) of each sequence. Default: 30.
- n_states
Integer. Number of hidden states. Default: 2.
- n_symbols
Integer. Number of observable symbols. Default: 3.
- trans
Numeric matrix (
n_states x n_states) or NULL. Row- stochastic state transition matrix. When NULL, a diagonally dominant matrix (states persist) is auto-generated.- emission
Numeric matrix (
n_states x n_symbols) or NULL. Row- stochastic emission matrix. When NULL, an auto-generated matrix where each state favours a distinct symbol is used.- init
Numeric vector (length
n_states) or NULL. Initial state distribution. When NULL, a uniform distribution is used.- seed
Integer or NULL. Random seed.
Value
A saqr_sim object with:
$datalong-format data.frame with columns
sequence_id(integer),time(integer, 1...seq_length), andsymbol(integer observed symbol in 1...n_symbols).$paramslist with
trans,emission,init,n_states,n_symbols, andhidden_paths(ann_sequences x seq_lengthinteger matrix of the TRUE latent state sequences).
Details
The within-sequence latent recursion is inherently sequential and
is implemented with Reduce(..., accumulate = TRUE) over the time
index; the work across sequences is vectorised with Map/vapply.
Examples
r <- simulate_hmm(n_sequences = 100, seq_length = 40, seed = 1)
print(r)
#> saqr_sim [hmm] 4000 x 3 (seed=1)
#> params: trans, emission, init, n_states, n_symbols, hidden_paths
#> cols: sequence_id, time, symbol
r$params$trans
#> [,1] [,2]
#> [1,] 0.8 0.2
#> [2,] 0.2 0.8
r$params$emission
#> [,1] [,2] [,3]
#> [1,] 0.8 0.1 0.1
#> [2,] 0.1 0.8 0.1
head(as.data.frame(r))
#> sequence_id time symbol
#> 1 1 1 2
#> 2 1 2 1
#> 3 1 3 2
#> 4 1 4 2
#> 5 1 5 3
#> 6 1 6 3
# Explicit three-state model
tr <- matrix(c(0.8, 0.1, 0.1,
0.1, 0.8, 0.1,
0.1, 0.1, 0.8), nrow = 3, byrow = TRUE)
em <- matrix(c(0.7, 0.2, 0.1,
0.1, 0.7, 0.2,
0.2, 0.1, 0.7), nrow = 3, byrow = TRUE)
r2 <- simulate_hmm(n_sequences = 80, seq_length = 50, n_states = 3,
n_symbols = 3, trans = tr, emission = em, seed = 42)
summary(r2)
#> Simulation type: hmm
#> Seed: 42
#>
#> --- Data ---
#> sequence_id time symbol
#> Min. : 1.00 Min. : 1.0 Min. :1.000
#> 1st Qu.:20.75 1st Qu.:13.0 1st Qu.:1.000
#> Median :40.50 Median :25.5 Median :2.000
#> Mean :40.50 Mean :25.5 Mean :2.002
#> 3rd Qu.:60.25 3rd Qu.:38.0 3rd Qu.:3.000
#> Max. :80.00 Max. :50.0 Max. :3.000
#>
#> --- Parameters ---
#> List of 6
#> $ trans : num [1:3, 1:3] 0.8 0.1 0.1 0.1 0.8 0.1 0.1 0.1 0.8
#> $ emission : num [1:3, 1:3] 0.7 0.1 0.2 0.2 0.7 0.1 0.1 0.2 0.7
#> $ init : num [1:3] 0.333 0.333 0.333
#> $ n_states : int 3
#> $ n_symbols : int 3
#> $ hidden_paths: int [1:80, 1:50] 1 3 3 1 1 3 3 3 2 3 ...