JuliaActuary
Practical, extensible, and open-source actuarial modeling and analysis.

Poisson approximation to Binomial

This notebook explores using the Poissson approximation to the Binomial. This can be useful for a number of reasons:

  1. The Binomial probability mass formula becomes more unwieldy for large $N$ faster than it does for the Poisson.

  2. In actuarial, and other contexts, $N$ can be a non-integer value (think partial period exposures) and rounding up or down could materially distort the posterior estimate if $N$ is small.

We will look at the approximation across a range of parameters $q$ (the probabilty a binomial event occurs) and $N$ (the number of chances for the event to occur, or "exposures").

Under certain conditions, the Poisson distribution can approximate the Binomial, where the average number of events, $λ=N*q$.

What are those conditions? According to Wikipedia:

According to two rules of thumb, this approximation is good if n ≥ 20 and p ≤ 0.05, or if n ≥ 100 and np ≤ 10.

It's not really that simple, and arguably a bit restrictive as this notebook will show.

Approach

We will use Julia and Turing.jl to simulate the posterior distribution. Our prior for the parameter $q$ will be ${Uniform} = Beta(1,1)$.

We will sample from the posterior using the No-U-Turn (NUTS) sampler, and aggregate the results of the chains over 30 trials of simulated outcomes for the given $q$ and $N$.

This is overkill for a toy problem where we could just model the parameters themselves, but it demonstrates using Bayesian MCMC techniques in a simple, exploratory fashion.

We begin by importing the relevant packages:

begin
    using Turing
    using CairoMakie
    using StatsBase
    using MCMCChains
    using DataFrames
    using ThreadsX
    using Logging
    using Markdown
end

Define the Models

@model function poisson(N,n_events) 
    q ~ Beta(1,1)
    
    n_events ~ Poisson(q*N)
end
poisson (generic function with 2 methods)
@model function binom(N,n_events) 
    q ~ Beta(1,1)
    
    n_events ~ Binomial(N,q)
end
binom (generic function with 2 methods)

Simulation Parameters

trials = 30
30
qs = [0.05,0.25,0.5,0.75,0.95]
5-element Vector{Float64}:
 0.05
 0.25
 0.5
 0.75
 0.95
Ns = [10,25,50,100,250,500,1000,5000]
8-element Vector{Int64}:
   10
   25
   50
  100
  250
  500
 1000
 5000
model_points =  [(;q,N) for q in qs, N in Ns]
5×8 Matrix{NamedTuple{(:q, :N), Tuple{Float64, Int64}}}:
 (q = 0.05, N = 10)  (q = 0.05, N = 25)  (q = 0.05, N = 50)  …  (q = 0.05, N = 5000)
 (q = 0.25, N = 10)  (q = 0.25, N = 25)  (q = 0.25, N = 50)     (q = 0.25, N = 5000)
 (q = 0.5, N = 10)   (q = 0.5, N = 25)   (q = 0.5, N = 50)      (q = 0.5, N = 5000)
 (q = 0.75, N = 10)  (q = 0.75, N = 25)  (q = 0.75, N = 50)     (q = 0.75, N = 5000)
 (q = 0.95, N = 10)  (q = 0.95, N = 25)  (q = 0.95, N = 50)     (q = 0.95, N = 5000)

Sample from the Posterior

Logging.disable_logging(Logging.Warn); #Disable warning logs to improve sampling time

This is a collection of samples (chains) from Markov chains that are sampled in proportion to the posterior density. If this is new to you, I highly recommend the book Statistical Rethinking:

@time bpchains = map(model_points) do mp
    
    ThreadsX.map(1:trials) do i
        claims = sum(rand() < mp.q for _ in 1:mp.N)
        bc = sample(binom(mp.N,claims), NUTS(), 500)
        pc = sample(poisson(mp.N,claims), NUTS(), 500)

        (;bc,pc)
    end
end
5×8 Matrix{Vector{NamedTuple{(:bc, :pc), Tuple{Chains{Float64, AxisArrays.AxisArray{Float64, 3, Array{Float64, 3}, Tuple{AxisArrays.Axis{:iter, StepRange{Int64, Int64}}, AxisArrays.Axis{:var, Vector{Symbol}}, AxisArrays.Axis{:chain, UnitRange{Int64}}}}, Missing, NamedTuple{(:parameters, :internals), Tuple{Vector{Symbol}, Vector{Symbol}}}, NamedTuple{(:start_time, :stop_time), Tuple{Float64, Float64}}}, Chains{Float64, AxisArrays.AxisArray{Float64, 3, Array{Float64, 3}, Tuple{AxisArrays.Axis{:iter, StepRange{Int64, Int64}}, AxisArrays.Axis{:var, Vector{Symbol}}, AxisArrays.Axis{:chain, UnitRange{Int64}}}}, Missing, NamedTuple{(:parameters, :internals), Tuple{Vector{Symbol}, Vector{Symbol}}}, NamedTuple{(:start_time, :stop_time), Tuple{Float64, Float64}}}}}}}:
 [(bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3}))  …  (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3}))]  …  [(bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3}))  …  (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3}))]
 [(bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3}))  …  (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3}))]     [(bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3}))  …  (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3}))]
 [(bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3}))  …  (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3}))]     [(bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3}))  …  (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3}))]
 [(bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3}))  …  (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3}))]     [(bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3}))  …  (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3}))]
 [(bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3}))  …  (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3}))]     [(bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3}))  …  (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3})), (bc = MCMC chain (500×13×1 Array{Float64, 3}), pc = MCMC chain (500×13×1 Array{Float64, 3}))]

Results

The results indicate that the Poisson is a good fit when $q$ is small, where "small" depends on N, but in general it seems to provide a good fit in less restrictive cases than the "rule of thumb" quoted below. E.g. go ahead and use the Poisson approximation when you've got enough expsoures even if $q$ is well above $0.10$. The Poisson approximation also isn't terrible when $N$ is as low as 10 as long as $q$ is very small (e.g. $<0.05$ ).

The fit remains poor when $q >> 0.5$ and when $N$ is small.

Visualization

This visualization shows the aggregated posterior distribution across all of the trials and model points. The darker shaded band indicates the middle 50% of the posterior:

let
    f = Figure(resolution=(1280,960))
    a = Any # outer variable to set as axis for to grab legend
    
    for (i,N) in enumerate(reverse(Ns))
        ax = Axis(f[i+1,1:10],
        xticks=qs,
        ylabel="N=$N"
        )
        a = ax
        xlims!(0,1)
        model_idx = findall(x->x.N == N,model_points)

        for n in model_idx
            c = bpchains[n]
            q = model_points[n].q
            y = model_points[n].N
            bpoints = vcat([x.bc["q"][:] for x in c]...)
            ppoints = vcat([x.pc["q"][:] for x in c]...)
            @show bpoints
            bqtls = quantile(bpoints,[.25,.75])
            pqtls = quantile(ppoints,[.25,.75])
            j = density!(
                bpoints,
                linewidth=10,
                strokewidth = 1, 
                strokecolor = (:grey30,0.6),
                label="Binomial",
            	color=(:red,.25),
            )
            plot_band_under!(ax,j,0,bqtls[1],bqtls[2],"Binomial")
        

            j = density!(
                ppoints, 
                color=(:blue,.25),
                linewidth=10,
                strokewidth = 1, 
                strokecolor = (:grey30,0.6),
                label="Poisson",
            )
            plot_band_under!(ax,j,0,pqtls[1],pqtls[2],"Poisson")

            hideydecorations!(ax,label=false)
        end

        scatter!(
            qs,
            zeros(length(qs)),
            marker = :vline,
            markersize=20,
            color=:grey30,
            label="actual value"
            )
    end

    Legend(f[1,5],a,unique=true,orientation=:horizontal)
    f
end
function plot_band_under!(ax,plot,y,low,high,label="")
    function points(plot)
        pts = plot.plots[2].converted[1][]
        [p[1] for p in pts], [p[2] for p in pts]
    end    
    xs′, ys′ = points(plot)

    filt = findall(x-> (x ≥ low) && (x ≤ high),xs′)
    b = band!(ax,xs′[filt], fill(y,length(filt)), ys′[filt], color=(plot.color, 0.9),transparency=true,shading = false,) # 0.25 alpha
    translate!(b,0,0,5)
end

plot_band_under! (generic function with 2 methods)

Built with Julia 1.8.5 and

CairoMakie 0.8.13
DataFrames 1.3.4
MCMCChains 5.3.1
StatsBase 0.33.21
ThreadsX 0.1.10
Turing 0.21.12

Run this Pluto Notebook

To run this page locally, download this file and open it with Pluto.jl.

The packages in JuliaActuary are open-source and liberally licensed (MIT License) to allow wide private and commercial usage of the packages, like the base Julia language and many other packages in the ecosystem. See terms of this site.