Question about modelling copulas in nimble

43 views
Skip to first unread message

­soom

unread,
Jul 30, 2025, 4:12:16 AMJul 30
to nimble-users
Hello,
I'm a graduate student who is new to using Nimble and currently trying to implement a spatio-temporal Bayesian model combining a Gaussian copula with GEV marginals. However, I'm facing a problem where the copula-related parameters are not converging at all, and I would deeply appreciate any insights or advice.

Here's the structure of model:
For each time point t=1,..,N, I have M spatial observations Y_(i,t) with GEV marginals (GEV(mu_st, sigma_s, xi)).
The dependence across variable is modeled using a Gaussian copula, with the correlation matrix C defined based on a spatial distance matrix d_(i,j), 
    like {C}_(i,j) = c_0 * exp(- d_(i,j) / c_1) + (1 - c_0) * exp(- d_(i,j) / c_2).
Then I compute the log-copula density at each time point using:
    log.cop[t] <- log_dmnorm(u[1:M, t], zero_vec[1:M], C[1:M, 1:M]) -
             sum(dnorm(u[1:M, t], log = TRUE)) +
             dGEV_vec(Y[1:M, t], mu_st[1:M, t], sigma[1:M], xi, log = TRUE)
    cop <- sum(log.cop[1:N])
where log_dmnorm and dGEV_vec is constructed using nimble Function, and each denoting 

The problem is: although I compute this log-copula, it doesn't seem to be incorporated into the posterior. As a result, the copula parameters (c_0, c_1, c_2) do not update at all during MCMC sampling - they simply float around their priors.
Since Nimble doesn't allow direct 'target +=' statements like r::stan does, I've been unsure how to correctly incorporate the computed log.cop into the model so that it actually influences the posterior.
As someone quite new to Nimble, I'm really not confident about whether I'm structuring things correctly. I would be extremely grateful for any insight or suggestions on how to properly include custom log-copula expression in the posterior and whether my approach is even going in the right direction (plus, if there's a more reliable or idiomatic way to handle this in Nimble).

Thank you very much in advance - I'd really appreciate any guidance from those more experienced.

Chris Paciorek

unread,
Jul 31, 2025, 8:00:19 PMJul 31
to ­soom, nimble-users
hi Soom,

Right, NIMBLE does not accumulate log-probability values in an imperative coding fashion. Instead, we query the graph structure from the declarative definition of the model and accumulate log-probability values of stochastic nodes that are relevant for a given MCMC sampler.

I think you have a couple options:

1. Write a user-defined distribution that includes all the log-probability contributions from the marginals and from the copula. This could make use of nimble's standard densities for the component pieces.

2. Define the nimble model in terms of the marginals and then include a "dummy" stochastic node representing the joint information, which follows a user-defined copula distribution. For a simple case using normals instead of GEV, I think it would look something like this:
```
## Define density for the data based on marginals
for(i in 1:n)
  y[i] ~ dnorm(mu, sd = sigma)
## Add in the joint part using the "trick" of a dummy node in the model
copula_dummy ~ dcopula(y[1:n], mu, sigma, copula_param1, copula_param2)
```
and set `copula_dummy` as some arbitrary value via `data` in nimbleModel().

`dcopula` would need to compute the copula density for the transformed y's (i.e., you'd need to apply the marginal transformations to get the standard normal random variables from the y's). If you're using a Gaussian copula, that presumably means you could use `dmnorm` internally. Note that the first argument to `dcopula` would be the dummy value, which would be ignored, with all computation done based on the remaining arguments.

The important thing here is that you can't define the transformed y's via a deterministic calculation in the model code and then also define a distribution for the vector of transformed y's, because nimble only allows you to declare something on the left-hand side of a declaration once. Hence the need for `copula_dummy`.

There might be another way that I'm not thinking of.

-chris



--
You received this message because you are subscribed to the Google Groups "nimble-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to nimble-users...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/nimble-users/177c021c-758b-49d7-80fa-9d9f5d4fda3bn%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages