Hi all,
I would like to work with data that are distributed on an hypersphere of arbitrary dimension. As a first step towards that, I’m starting to familiarise with syntetic data on a simple 3D sphere.
While distributions like the von Mises one have generalisations to higher dimensions, the normalising constant is a pain, so I was looking into using a gaussian copula to account for dependence along the dimensions.
I’ts the first time I approach a copula model, and I have been following this example. I generate a sample of 100 or 1000 observations on the sphere, the angles look fine, the data are constrained to the correct interval etc.
The parameters I am setting right now look like this:
\mu = [0.6\pi, 0.3\pi]
\kappa = [18,23]
\rho = -0.5
The issue is, no matter what I do, I always get wildly incorrect posteriors with massive convergence issues (high R-hat, low ESS, E-BFMI non existent, max-treedepth, but basically no divergent transitions). I already switched from the pdf to the log-pdf of the von Mises and standard normal distributions and that somewhat reduced the amount of warnings I get during sampling, but I still get values out of the [0,1] interval occasionally.
I have tried to use more informative priors on the location and scale parameters, or even to fix either of the two to the true value, to no avail. I also tried the trick of switching to a normal distribution for \kappa > 100, but it didn’t make a difference. I suspect that the issue could be arising from numerical errors more than from the model specification per se, but I might be wrong.
If anyone has any tip on this I would be grateful!
Here is the model:
functions {
real gauss_copula_cholesky_lpdf(matrix u, matrix L) {
array[rows(u)] row_vector[cols(u)] q;
for (n in 1:rows(u)) {
q[n] = std_normal_log_qf(u[n]);
}
return multi_normal_cholesky_lpdf(q | rep_row_vector(0, cols(L)), L)
- std_normal_lpdf(to_vector(to_matrix(q)));
}
}
data {
int<lower=0> N;
int<lower=0> K;
matrix[N, K] Y;
}
parameters {
vector<lower=0>[K] kappa;
vector<lower=-pi(), upper=pi()>[K] mu;
cholesky_factor_corr[K] rho_chol;
}
model {
rho_chol ~ lkj_corr_cholesky(2.0);
kappa ~ exponential(0.05);
mu ~ von_mises(0.0, 0.0);
matrix[N, K] u;
for (n in 1:N) {
for (k in 1:K){
u[n, k] = von_mises_lcdf(Y[n, k] | mu[k], kappa[k]);
}
}
for (k in 1:K){
Y[,k] ~ von_mises(mu[k], kappa[k]);
}
u ~ gauss_copula_cholesky(rho_chol);
}
generated quantities {
matrix[K,K] rho = multiply_lower_tri_self_transpose(rho_chol);
}