EmpiricalBayesGammaRegressor#
Tunes the Gamma prior parameters via the Negative Binomial marginal likelihood, using Minka’s EM algorithm [1] with stabilized forgetting to prevent prior collapse under exponential decay.
Builds on the posterior update from Intercept-Only Models, which is inherited unchanged. Read that page first.
Symbols#
Symbol |
Meaning |
|---|---|
\(\alpha\) |
Gamma shape parameter (prior) |
\(\beta\) |
Gamma rate parameter (prior) |
\(\lambda_g\) |
Latent rate for group \(g\) |
\(c_g\) |
Effective count in group \(g\): \(c_g = \alpha_g^{\text{post}} - \alpha\) |
\(n_g\) |
Effective exposure in group \(g\): \(n_g = \beta_g^{\text{post}} - \beta\) |
\(G\) |
Number of groups (unique values of the first feature) |
\(\psi\) |
Digamma function |
\(\psi'\) |
Trigamma function |
Negative Binomial marginal likelihood#
The Gamma-Poisson marginal for \(G\) groups with effective counts \(c_g\) and exposures \(n_g\) under a shared prior \(\text{Gamma}(\alpha, \beta)\):
EM derivation (Minka 2002, section 2.1)#
The marginal likelihood is maximized via EM, treating the per-group rate \(\lambda_g\) as a latent variable [1].
E-step#
Compute posterior moments of \(\lambda_g\) under \(\text{Gamma}(\alpha + c_g,\, \beta + n_g)\):
M-step#
Solve the Gamma MLE on expected sufficient statistics.
Rate update (closed-form given \(\alpha\)):
where \(\bar{\mathbb{E}}[\lambda] = \frac{1}{G} \sum_g \mathbb{E}[\lambda_g]\).
Shape update (generalized Newton [1], section 1). The fixed-point equation is:
solved by the iteration:
Counts and exposure extraction#
The effective counts and exposures are derived from the difference between posterior and prior parameters:
With stabilized forgetting (see below), this gives the decayed counts and exposures exactly.
Stabilized forgetting#
The problem. Uniform decay \((\alpha_g, \beta_g) \leftarrow \gamma\,(\alpha_g, \beta_g)\) drives all parameters to zero.
The solution. Every decay (both explicit via decay() and
implicit via learning_rate in partial_fit) re-injects the
EB-tuned prior:
where \(\mathbf{p}_g = (\alpha_g, \beta_g)\) and \(n\) is the number of observations. This maintains the invariant:
so effective counts and exposures are correctly decayed and the prior contribution never vanishes.
fit vs. partial_fit#
fit iterates the EM step to convergence on fixed data (up to
n_eb_iter times, checking
\(|\Delta \log p| < \texttt{eb\_tol}\)), then refits the
posterior with the converged prior. partial_fit runs one EM
step per call, correcting all group posteriors by the prior change
\(\mathbf{p}^{\text{new}} - \mathbf{p}^{\text{old}}\).
Hyperparameter semantics#
Parameter |
Controls |
Practical guidance |
|---|---|---|
|
Initial Gamma shape. EB tunes this. |
Start at 1.0. |
|
Initial Gamma rate. EB tunes this. |
Start at 1.0. |
|
Maximum EM iterations during |
10 (default). Set to 0 to disable EB during |
|
Convergence tolerance on log evidence change. |
1e-4 (default). |
|
Decay factor \(\gamma\). See Choosing and Tuning a Decay Rate. |
1.0 (default) for stationary environments. |
Robustness to misspecified priors#
The EB prior mean \(\alpha/\beta\) converges to the average group rate regardless of initialization. The prior strength (concentration) converges more slowly but is less critical for predictions.
import numpy as np
from bayesianbandits import EmpiricalBayesGammaRegressor
rng = np.random.default_rng(42)
true_alpha, true_beta = 3.0, 1.0 # true mean rate = 3.0
# Wrong initial prior: mean rate = 0.1
model = EmpiricalBayesGammaRegressor(
alpha=1.0, beta=10.0, random_state=0
)
for g in range(200):
rate = rng.gamma(true_alpha, 1.0 / true_beta)
obs = rng.poisson(rate, size=rng.poisson(10) + 1)
model.partial_fit(np.full((len(obs), 1), g), obs)
# Recovered prior mean: alpha/beta ~ 3.0
print(f"Prior mean rate: {model.alpha / model.beta:.2f}")