Created
October 7, 2021 02:39
-
-
Save mbjoseph/960c3b259d007c81bebbaf9e5be1e250 to your computer and use it in GitHub Desktop.
Poisson-binomial multinomial distance sampling model in Stan, with half-normal detection function
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
data { | |
int<lower=1> n_site; | |
int<lower=1> n_distance_bins; | |
vector[n_distance_bins + 1] bin_breakpoints; | |
array[n_site, n_distance_bins] int y; | |
array[n_site] int n_obs; | |
} | |
transformed data { | |
real max_distance = max(bin_breakpoints); | |
real log_two = log(2); | |
real log_max_distance_sq = 2 * log(max(bin_breakpoints)); | |
vector[n_distance_bins + 1] bin_breakpoints_sq = bin_breakpoints^2; | |
} | |
parameters { | |
real log_lambda; | |
real log_sigma; | |
} | |
transformed parameters { | |
real log_p; | |
vector[n_distance_bins] log_p_raw; | |
{ | |
real two_sig_sq = 2 * exp(2 * log_sigma); | |
for (i in 1:n_distance_bins) { | |
// p_raw[i] = pr(animal occurs and is detected in bin i) | |
// assuming a half-normal detection fn | |
log_p_raw[i] = log_two + 2 * log_sigma - log_max_distance_sq + | |
log_diff_exp( | |
- bin_breakpoints_sq[i] / two_sig_sq, | |
- bin_breakpoints_sq[i + 1] / two_sig_sq | |
); | |
} | |
log_p = log_sum_exp(log_p_raw); | |
} | |
} | |
model { | |
log_lambda ~ normal(3, 1); | |
log_sigma ~ normal(4, 1); | |
n_obs ~ poisson_log(log_lambda + log_p); | |
for (i in 1:n_site) { | |
y[i, ] ~ multinomial_logit(log_p_raw); | |
} | |
} | |
generated quantities { | |
array[n_site] int n_unobserved; | |
array[n_site] int n; | |
for (i in 1:n_site) { | |
n_unobserved[i] = poisson_rng(exp(log_lambda) * (1 - exp(log_p))); | |
n[i] = n_obs[i] + n_unobserved[i]; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
n_site <- 50 | |
n_distance_bins <- 20 | |
max_distance <- 300 | |
bin_breakpoints <- seq(0, max_distance, length.out = n_distance_bins + 1) | |
sigma <- 100 | |
p <- rep(NA, n_distance_bins) | |
for (b in 1:n_distance_bins) { | |
p[b] <- - 2 * sigma^2 / max_distance^2 * ( | |
exp(- bin_breakpoints[b + 1]^2 / (2 * sigma^2)) - | |
exp(- bin_breakpoints[b]^2 / (2 * sigma^2)) | |
) | |
} | |
p_c <- p / sum(p) | |
plot(bin_breakpoints[-1], p_c) | |
lambda <- 100 | |
n_true <- rpois(n_site, lambda) | |
n_obs <- rbinom(n_site, size = n_true, prob = sum(p)) | |
plot(n_true, n_obs) | |
y <- matrix(NA, nrow = n_site, ncol = n_distance_bins) | |
for (i in 1:n_site) { | |
y[i, ] <- c(rmultinom(1, size = n_obs[i], prob = p_c)) | |
} | |
stan_d <- list( | |
n_site = n_site, | |
n_distance_bins = n_distance_bins, | |
bin_breakpoints = bin_breakpoints, | |
y = y, | |
n_obs = n_obs | |
) | |
model <- cmdstanr::cmdstan_model("distance-sampling.stan") | |
fit <- model$sample(data = stan_d, parallel_chains = 4) | |
bayesplot::mcmc_trace(fit$draws(c("lp__", "log_lambda", "log_sigma", "log_p"))) | |
bayesplot::mcmc_pairs(fit$draws(c("log_lambda", "log_sigma"))) | |
bayesplot::mcmc_intervals(fit$draws('n')) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment