I am interested in models where the observed data is a discretization of a continuous latent parameter.
As a simple example imagine that you have observations J_i
,
where
J_i = 1 if L_i >= 1
J_i = -1 if L_i < -1
J_i = 0 if -1 <= L_i < 1
where L_i = \mu + \epsilon_i
and we want to infer \mu
How would this be implemented in Stan?
Assuming that L[i]
is normally distributed with mean mu
and standard deviation epsilon[i]
, one approach is to consider that J[i]
is drawn from a categorical distribution of 3 categories (ie, -1, 0, 1), with parameters theta[i]
(each of length 3), where each theta[i][j]
is the area under the normal probability distribution with parameters (mu, epsilon[i])
, at the corresponding interval. An example can be seen below.
So, we can include theta
as a parameter matrix in a transformed parameters
block, without needing to specify L
at all in the Stan model. An example implementation is the following. Note that the categories are here considered as 1, 2, 3
instead of -1, 0, 1
, for convenience in using the categorical
function.
model.stan:
data {
int<lower=0> N; // number of samples
int J[N]; // observed values
}
parameters {
real mu; // mean value to infer
real<lower=0> epsilon[N]; // standard deviations
}
transformed parameters {
matrix[N, 3] theta; // parameters of categorical distributions
for (i in 1:N) {
theta[i, 1] = Phi((-1 - mu) / epsilon[i]); // Area from -Inf to -1
theta[i, 3] = 1 - Phi((1 - mu) / epsilon[i]); // Area from 1 to Inf
theta[i, 2] = 1 - theta[i, 1] - theta[i, 3]; // The rest of the area
}
}
model {
mu ~ normal(0, 10); // prior for mu
for (i in 1:N) {
epsilon[i] ~ lognormal(0, 1); // prior for epsilon[i]
J[i] ~ categorical(to_vector(theta[i]));
}
}
An example usage in R is the following.
main.R:
library(rstan)
set.seed(100)
# simulated data
N <- 20
mu <- -1.2 # This is the value we want to estimate
epsilon <- runif(N, 0.5, 2)
L <- rnorm(N, mu, epsilon)
J <- ifelse(L < -1, 1, ifelse(L >= 1, 3, 2))
mdl <- stan("model.stan", data = list(N = N, J = J))
samples <- extract(mdl, "mu")
mu_estimate <- list(mean = mean(samples$mu), sd = sd(samples$mu))
print(mu_estimate)
# $mean
# [1] -1.177485
#
# $sd
# [1] 0.2540879
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.