BinomialPolya
Overview
BinomialPolya is a binomial regression through the logistic: y successes out of n trials, with success probability σ(xᵀβ) for the covariates x and the weights β. With n = 1 it is logistic regression. y, x and n are observed; the node learns β, whose message is normal by the Pólya-Gamma augmentation.
Definition
\[p(y \mid x, n, \beta) = \binom{n}{y} \sigma(x^\top \beta)^{y} \big(1 - \sigma(x^\top \beta)\big)^{n - y}, \qquad \sigma(\psi) = \frac{1}{1 + e^{-\psi}}\]
The binomial coefficient counts the orders in which y successes can occur. The logistic function σ maps the linear predictor xᵀβ to a probability.
Interfaces
using PolyaMessagePassingRules, MessagePassingRulesBase, BayesBase, ExponentialFamily
MessagePassingRulesBase.nodespec(BinomialPolya)| interface | aliases | |
|---|---|---|
y | ||
x | ||
n | ||
β |
| default algorithm | BinomialPolyaApproximation{Nothing}(nothing, 32) |
|---|---|
| static inputs | none |
| defined | src/binomial_polya.jl:101 |
The node has four interfaces. The table lists the marginals and messages the rules read on each.
| name | meaning | messages and marginals the rules take |
|---|---|---|
y | the number of successes | PointMass marginal |
x | the covariates, a vector, or a number for a scalar β | PointMass marginal |
n | the number of trials | PointMass marginal (any marginal with a mean, towards y) |
β | the weights | normal message on β towards β; normal marginal towards y and for the energy |
The rule towards β sends a normal in weighted-mean and precision form, MvNormal for a vector x; the rule towards y sends a Binomial. There is no rule towards x or n.
Algorithm
PolyaMessagePassingRules.BinomialPolyaApproximation — Type
BinomialPolyaApproximation(; samples = nothing, points = 32)The algorithm of BinomialPolya, and its default: a model names it only to sample or to change points.
Keywords
samples:nothingor a number of draws. Defaultnothing. Withnothing, the rules use means: the Pólya-Gamma mean atxᵀtimes the mean ofβ, andσ(xᵀβ)at the mean ofβ. With a numberk, they average overkdraws ofβ, the rule towardsβover one Pólya-Gamma draw for each, from the rule context's generator,ctx.rng. An engine supplies it; a call by hand passesctx = MessagePassingRulesBase.RuleContext(rng = …).points: the number of Gauss–Hermite points with which the average energy computes⟨softplus(ψ)⟩. Default32. The messages do not depend on it.
The average energy does not sample under either: xᵀβ is normal under a normal q(β), so its expectation is computed by Gauss–Hermite cubature.
Examples
julia> BinomialPolyaApproximation().samples === nothing
true
julia> BinomialPolyaApproximation(samples = 100).samples
100
julia> BinomialPolyaApproximation(points = 64).points
64BinomialPolyaApproximation() is the node's default algorithm, so a model names it only to sample, as BinomialPolyaApproximation(samples = 100). Sampling draws from the rule context's generator, a service the engine supplies.
The node declares its dependencies, the inputs each target's rule takes, for both variants of the algorithm:
MessagePassingRulesBase.dependencies_spec(BinomialPolya, BinomialPolyaApproximation())| free-energy partition | from the factorisation |
|---|
Every target takes the inputs of the default scheme. The rule towards β also reads the message on β, the current estimate at which it takes the Pólya-Gamma mean.
Supported rules
MessagePassingRulesBase.rule_coverage(BinomialPolya)| BinomialPolyaApproximation{Nothing} | BinomialPolyaApproximation{Int64} | BinomialPolyaApproximation{<:Union{Nothing, Int64}} | |
|---|---|---|---|
| → y | ✓ | ✓ | |
| → x | |||
| → n | |||
| → β | ✓ | ✓ | |
| average energy | ✓ |
The three columns are the algorithm's variants:
BinomialPolyaApproximation{Nothing}, the means, the default;BinomialPolyaApproximation{Int}, sampling;- the type itself, under which the average energy serves both.
The rules read marginals of the observed interfaces and, towards β, the message on β. They fit a mean-field factorisation, in which y, x and n are data. With the average energy, the Bethe free energy is available.
Example
The message towards β for one observation, at a message on β centred on zero, where the Pólya-Gamma mean is n / 4:
@call_message_update_rule(
node = BinomialPolya, target = :β,
q = (y = PointMass(3), x = PointMass([0.1, 0.2]), n = PointMass(5)),
m = (β = MvNormalWeightedMeanPrecision(zeros(2), [1.0 0.0; 0.0 1.0]),),
)Result
| value | MvNormalWeightedMeanPrecision( xi: [0.05, 0.1] Λ: [0.0125 0.025; 0.025 0.05] ) |
|---|---|
| type | ExponentialFamily.MvNormalWeightedMeanPrecision{Float64, Vector{Float64}, Matrix{Float64}} |
| log scale | undefined: the message rule for BinomialPolya towards :β under BinomialPolyaApproximation{Nothing} declares no `logscale` |
Inputs
| edge | value | |
|---|---|---|
| y | q | PointMass{Int64}(3) |
| x | q | PointMass{Vector{Float64}}([0.1, 0.2]) |
| n | q | PointMass{Int64}(5) |
Rule
| declared inputs | q[:y]::BayesBase.PointMass, q[:x]::BayesBase.PointMass, q[:n]::BayesBase.PointMass, m[:β]::Union{ExponentialFamily.NormalDistributionsFamily{T}, ExponentialFamily.GaussianDistributionsFamily{T}} where T |
|---|---|
| algorithm | BinomialPolyaApproximation{Nothing}(nothing, 32) |
| log scale | none |
| defined | src/binomial_polya.jl:125 |
| body | args->begin
ω = mean(PolyaGammaHybridSampler(mean(args.q[:n]), dot(mean(args.q[:x]), mean(args.m[:β]))))
binomial_polya_towards_β(ω, args.q[:y], args.q[:x], args.q[:n], args.m[:β])
end |
Other rules for this target (1)
src/binomial_polya.jl:134| ✗ | algorithm BinomialPolyaApproximation{Int64} |
| ✓ | q[:y]::BayesBase.PointMass got BayesBase.PointMass{Int64} |
| ✓ | q[:x]::BayesBase.PointMass got BayesBase.PointMass{Vector{Float64}} |
| ✓ | q[:n]::BayesBase.PointMass got BayesBase.PointMass{Int64} |
| ✓ | m[:β]::Union{ExponentialFamily.NormalDistributionsFamily{T}, ExponentialFamily.GaussianDistributionsFamily{T}} where T got ExponentialFamily.MvNormalWeightedMeanPrecision{Float64, Vector{Float64}, Matrix{Float64}} |
@call_message_update_rule runs the rule and draws its inputs: the three observed marginals and the message on β, the target's own edge. The weighted mean is (y - n/2) x and the precision (n/4) x xᵀ, which getresult confirms:
julia> using PolyaMessagePassingRules, MessagePassingRulesBase, BayesBase, ExponentialFamily
julia> result = @call_message_update_rule(
node = BinomialPolya, target = :β,
q = (y = PointMass(3), x = PointMass([0.1, 0.2]), n = PointMass(5)),
m = (β = MvNormalWeightedMeanPrecision(zeros(2), [1.0 0.0; 0.0 1.0]),),
);
julia> weightedmean(getresult(result)) ≈ (3 - 5 / 2) * [0.1, 0.2]
true
julia> precision(getresult(result)) ≈ (5 / 4) * [0.1, 0.2] * [0.1, 0.2]'
trueLimitations
- The rule towards
βneeds an initial message onβ. y,xandnmust be observed: there are no rules towardsxorn, and the average energy takesPointMassmarginals of all three.- The average energy computes
⟨softplus(ψ)⟩by Gauss–Hermite cubature withBinomialPolyaApproximation(points = …)points, 32 by default. It is exact to rounding whileψ = xᵀβis narrow, a variance up to about 1, and loses accuracy asψbroadens, since softplus bends sharply on the cubature's scale: about1e-4relative at a variance of 25 and1e-2at 400, and more points help slowly. The free energy of a model with broad priors is approximate in its first iterations; the messages do not use the cubature.
API
The node:
PolyaMessagePassingRules.BinomialPolya — Type
BinomialPolyaThe stochastic node of a binomial regression through the logistic,
\[p(y \mid x, n, \beta) = \binom{n}{y} \sigma(x^\top \beta)^{y} \big(1 - \sigma(x^\top \beta)\big)^{n - y}, \qquad \sigma(\psi) = \frac{1}{1 + e^{-\psi}},\]
with its weights β Pólya-Gamma augmented so that their message is normal. With n = 1 it is logistic regression.
Interfaces
y: the number of successes, observed, aPointMass;x: the covariates, observed, aPointMassholding a vector (or a number, for a scalarβ);n: the number of trials, observed, aPointMass;β: the weights, with a normal message and marginal,MvNormalfor a vectorx.
Augmentation
For a count y out of b trials with log-odds ψ, the Pólya-Gamma identity
\[\frac{(e^{\psi})^{y}}{(1 + e^{\psi})^{b}} = 2^{-b} e^{\kappa \psi} \int_0^\infty e^{-\omega \psi^2 / 2} \, \mathrm{PG}(\omega \mid b, 0) \, d\omega, \qquad \kappa = y - b / 2,\]
makes the likelihood Gaussian in ψ given the auxiliary ω ~ PG(b, ψ): proportional to exp(κψ - ωψ²/2). The rules replace ω by its expectation, E[ω] = b / (2c) · tanh(c / 2) for PG(b, c), at the current estimate c of ψ, so the message towards the weights is a normal in weighted-mean and precision form.
With ψ = xᵀβ and b = n, the message towards β has the weighted mean (y - n/2) x and the precision ω x xᵀ, where ω is the Pólya-Gamma mean at xᵀ times the mean of the message on β. The message towards y is Binomial(n, σ(xᵀ mᵦ)), mᵦ the mean of q(β). Both rules average over draws of β instead when BinomialPolyaApproximation is given a number of samples.
The average energy is that of the binomial likelihood itself, not of the augmented one: -log C(n, y) - y ⟨ψ⟩ + n ⟨softplus(ψ)⟩, with ⟨softplus(ψ)⟩ under the normal ψ = xᵀβ by Gauss–Hermite cubature with the algorithm's points.
Limitations
- The rule towards
βreads the message onβitself, besides the marginals its factorisation gives it, so a model must initialise that message. y,xandnmust be observed: their rules and the average energy takePointMassmarginals only, and there is no rule towardsxorn.- The Gauss–Hermite cubature of
⟨softplus(ψ)⟩is exact to rounding whileψis narrow, a variance up to about 1, and loses accuracy asψbroadens, since softplus bends sharply on the cubature's scale: about1e-4relative at a variance of 25 and1e-2at 400 with 32 points. Morepointshelp slowly. The free energy of a model with broad priors is therefore approximate in its first iterations; the messages do not use the cubature.
Examples
julia> result = @call_message_update_rule(
node = BinomialPolya, target = :y,
q = (x = PointMass([1.0, 2.0]), n = PointMass(10), β = MvNormalMeanCovariance([0.0, 0.0], [1.0 0.0; 0.0 1.0])),
);
julia> mean(getresult(result)) ≈ 5.0
trueAt β = 0 the success probability is σ(0) = 1/2, so the message is Binomial(10, 1/2).
See also BinomialPolyaApproximation, MultinomialPolya.