Thanks for sharing. It's the same kind of thing
we'd have to do for binomial missing data. Was there
an application driving this?
I would think this would all be more arithmetically
stable on the log scale (less chance of underflow).
So my knee-jerk reaction is to convert the linear scale
formulation
> {
> real tmp_vec[K];
> for(k in y:N)
> {
> real tmp_factorial; #some terms are redundant, but I leave it for those who how I derive this
> tmp_factorial <- (tgamma(N+1.0) /tgamma(k+1.0) / tgamma(N-k+1.0)) * (tgamma(k+1.0)/ tgamma(y+1.0) / tgamma(k-y+1.0));
> tmp_vec[k-y+1] <- tmp_factorial * pow(theta1,k) *pow(1.0-theta1,(N-k)) * pow(theta2,y) * pow(1.0-theta2,(k-y));
> }
> increment_log_prob(log(sum(tmp_vec)));
> }
into the following log-scale version (which won't underflow or overflow
like the tgamma andprod are prone to do with large k or N, especially
wen multiplied together):
{
real log_tmp_vec[K];
for (k in y:N)
log_tmp_vec[k - y + 1]
<- lgamma(N + 1)
- lgamma(k + 1)
- lgamma(N - k + 1)
+ lgamma(k + 1)
- lgamma(y + 1)
- lgamma(k - y + 1)
+ k * log(theta1)
+ (N - k) * log1m(theta1)
+ y * log(theta2)
+ (k - y) * logm(theta2);
increment_log_prob(log_sum_exp(log_tmp_vec));
}
But now I see the structure is just two binomials,
so I'm pretty sure everything reduces to this:
{
real tmp[K];
for (k in y:N)
tmp[k - y + 1]
<- binomial_log(k, N, theta1)
+ binomial_log(y, k, theta2);
increment_log_prob(log_sum_exp(tmp));
}
At least I think that'll give you the same model. It makes
sense given the original BUGS formulation, too.
And speaking of arithmetic, it's usually better to just work
on the int scale (both faster and more accurate) rather than forcing
early double conversion. That is, (k + 1) will evaluate the addition as
integers, then convert to double as the argument to lgamma. But doing
(k + 1.0) will first cast k to a double, then do the addition.
- Bob
On Jul 15, 2014, at 1:25 AM, Soga Shota <
soga....@gmail.com> wrote:
> Hi all,
>
> I just wrote a binomial-binomial model using stan via brute-force marginalization. I think this would be a good example for those who want to marginalize discrete variables, so I post it here.
>
> In BUGS notation, the following stan code is equivalent to
>
> model
> {
> theta1 ~ dunif(0,1)
> theta2 ~ dunif(0,1)
> x ~ dbin(theta1,50)
> y ~ dbin(theta2,x)
> }
> DATA
> list(
> y = 5
> )
>
> transformed data
> {
> int y;
> int N;
> int K;
> y <- 5;
> N <- 50;
> K <- N-y+1;
> }
> parameters
> {
> real<lower=0,upper=1> theta1;
> real<lower=0,upper=1> theta2;
> }
> model
> {
>
> {
> real tmp_vec[K];
> for(k in y:N)
> {
> real tmp_factorial; #some terms are redundant, but I leave it for those who how I derive this
> tmp_factorial <- (tgamma(N+1.0) /tgamma(k+1.0) / tgamma(N-k+1.0)) * (tgamma(k+1.0)/ tgamma(y+1.0) / tgamma(k-y+1.0));
> tmp_vec[k-y+1] <- tmp_factorial * pow(theta1,k) *pow(1.0-theta1,(N-k)) * pow(theta2,y) * pow(1.0-theta2,(k-y));
> }
> increment_log_prob(log(sum(tmp_vec)));
> }
> }
>
> Enjoy!
>
> --
> You received this message because you are subscribed to the Google Groups "Stan users mailing list" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to
stan-users+...@googlegroups.com.
> For more options, visit
https://groups.google.com/d/optout.