vignettes/normal-nig-noise.Rmd
normal-nig-noise.Rmd
library(ngme2)
#> This is ngme2 of version 0.7.0
#> - See our homepage: https://davidbolin.github.io/ngme2 for more details.
set.seed(123) # For reproducibility
This vignette introduces a special feature of the ngme2
package: the ability to model latent processes driven by a combination
of both Gaussian and Normal Inverse Gaussian (NIG) noise. This mixed
noise model provides greater flexibility in capturing complex
distributional patterns in your data that may exhibit both heavy tails
and Gaussian components.
In many real-world applications, the observed data may result from
processes affected by multiple sources of randomness with different
distributional characteristics. The normal_nig
noise model
in ngme2
provides a powerful way to account for this by
combining:
The NIG distribution is a flexible four-parameter continuous probability distribution that can handle asymmetry and heavy tails. By combining it with normal noise, we can model complex stochastic behaviors more accurately.
The combined Normal-NIG noise model can be represented as:
where:
The NIG component itself is often constructed as:
where: - (for identifiability) - follows an inverse Gaussian distribution with parameters related to - is standard normal
Let’s simulate a dataset that exhibits both Gaussian and NIG noise components. We’ll create an AR(1) process driven by this mixed noise:
# Set parameters
n_obs <- 1000
sigma_eps <- 0.5 # Measurement noise (observation error)
alpha <- 0.5 # AR(1) coefficient
mu <- 2 # NIG parameter mu
delta <- -mu # NIG parameter delta (typically set to -mu)
sigma_nig <- 3 # NIG noise scale
nu <- 1 # NIG shape parameter
sigma_normal <- 2 # Normal noise standard deviation
# First we generate V. V_i follows inverse Gaussian distribution
trueV <- ngme2::rig(n_obs, nu, nu, seed = 10)
# Generate the NIG noise component
nig_noise <- delta + mu*trueV + sigma_nig * sqrt(trueV) * rnorm(n_obs)
# Add normal noise component
mixed_noise <- nig_noise + rnorm(n_obs, mean=0, sd=sigma_normal)
# Generate the AR(1) process
trueW <- Reduce(function(x,y){y + alpha*x}, mixed_noise, accumulate = TRUE)
# Add measurement noise to get observations
Y <- trueW + rnorm(n_obs, mean=0, sd=sigma_eps)
# Add some fixed effects
x1 <- runif(n_obs)
x2 <- rexp(n_obs)
beta <- c(-3, -1, 2)
X <- model.matrix(~x1 + x2) # design matrix
Y <- as.numeric(Y + X %*% beta)
# Plot the simulated data
par(mfrow=c(2,1), mar=c(4,4,2,1))
plot(Y, type="l", main="Simulated observations with Normal-NIG noise",
xlab="Time", ylab="Value")
plot(mixed_noise, type="l", main="Underlying Normal-NIG noise",
xlab="Time", ylab="Value")
The ngme2
package provides the
noise_normal_nig()
function to specify a combined
Normal-NIG noise model. Let’s fit our simulated data:
# Fit model with Normal-NIG noise
ngme_out <- ngme(
Y ~ x1 + x2 + f(
1:n_obs,
name = "my_ar",
model = "ar1",
# noise = noise_normal_nig() # This specifies the combined noise model
noise = list(noise_nig(mu=2, sigma_nig=3, nu=1), noise_normal(sigma_normal=1))
),
data = data.frame(x1=x1, x2=x2, Y=Y),
control_opt = control_opt(
burnin = 100,
iterations = 5000,
std_lim = 0.4,
n_parallel_chain = 4,
seed = 3
)
)
#> Starting estimation...
#>
#> Starting posterior sampling...
#> Posterior sampling done!
#> Note:
#> 1. Use ngme_post_samples(..) to access the posterior samples.
#> 2. Use ngme_result(..) to access different latent models.
# Show model summary
summary(ngme_out)
#> *** Ngme object ***
#>
#> Fixed effects:
#> (Intercept) x1 x2
#> -2.62 -1.50 1.91
#>
#> Models:
#> $my_ar
#> Model type: AR(1)
#> rho = 0.479
#> Noise type: NORMAL_NIG
#> Noise parameters:
#> mu = 2.15
#> sigma_nig = 3.46
#> nu = 1.73
#> sigma_normal = 0.916
#>
#> Measurement noise:
#> Noise type: NORMAL
#> Noise parameters:
#> sigma = 0.781
#>
#>
#> Number of replicates is 1
#> Last estimates:
#> $sigma
#> [1] 0.7936722
#>
#> $`fixed effect 1`
#> [1] -2.621681
#>
#> $`fixed effect 2`
#> [1] -1.497698
#>
#> $`fixed effect 3`
#> [1] 1.909849
traceplot(ngme_out, "my_ar", hline=c(alpha, mu, sigma_nig, sigma_normal, nu))
#> Last estimates:
#> $rho
#> [1] 0.476164
#>
#> $`theta_mu 1`
#> [1] 2.163596
#>
#> $sigma_nig
#> [1] 3.4401
#>
#> $sigma_normal
#> [1] 1.111303
#>
#> $nu
#> [1] 1.736965
We can use the traceplot()
function to see the estimated
parameters trajectories:
The noise_normal_nig()
function provides several
customization options:
# Specifying initial values for parameters
custom_noise <- noise_normal_nig(
mu = 2, # Initial value for mu
sigma_nig = 3, # Initial value for NIG sigma
nu = 1, # Initial value for nu
sigma_normal = 0.8 # Initial value for normal sigma
)
The combined Normal-NIG noise model is particularly useful in:
The noise_normal_nig()
function in ngme2
provides a powerful way to model complex random processes that exhibit
both heavy-tailed and normal characteristics. By combining Normal and
NIG noise components, you can create more flexible and realistic models
for your data.
When your data shows signs of both heavy tails and Gaussian
components, consider using this mixed noise model rather than
restricting yourself to a single noise distribution. The examples in
this vignette demonstrate how to simulate, fit, and analyze such models,
helping you make better use of the ngme2
package’s advanced
features. ****