Home/Machine Learning/Bayesian Statistics & Methods
Back
🎲

Applied Scientist

Bayesian Statistics & Methods

Bayesian statistics gives you a principled framework for updating beliefs with evidence — critical for sequential decision-making, handling small samples, and incorporating domain knowledge through priors. At companies like Netflix, Spotify, and Airbnb, Bayesian A/B testing has largely replaced frequentist testing because it enables early stopping, communicates uncertainty naturally (probability that A beats B), and avoids the p-value peeking problem. For Research Scientist roles, Gaussian Processes and Bayesian optimization are directly tested. For Applied Scientist roles, Thompson sampling (multi-armed bandits), hierarchical models, and Bayesian A/B testing are high-frequency topics.

Probability theory (Bayes' theorem)Basic statistics (distributions, likelihood)Linear algebra (covariance matrices)Python/NumPyBayes' TheoremMCMCCredible IntervalsBayesian A/B TestingHierarchical ModelsGaussian ProcessesThompson Sampling

Core Theory

  • 1Bayes' theorem and the posterior: P(θ|D) = P(D|θ) P(θ) / P(D). Posterior ∝ Likelihood × Prior. P(θ) is the prior — your belief about θ before seeing data. P(D|θ) is the likelihood — the probability of observing data D given parameter θ. P(θ|D) is the posterior — your updated belief after seeing data. P(D) = ∫ P(D|θ) P(θ) dθ is the marginal likelihood (evidence) — a normalizing constant that makes the posterior a valid distribution. The key Bayesian insight: parameters are random variables with distributions, not fixed unknown constants (the frequentist view). This lets you make direct probability statements: 'P(treatment is better than control | data) = 0.87.'
  • 2Conjugate priors: When the prior and posterior belong to the same distributional family, we say the prior is conjugate to the likelihood — conjugacy gives closed-form posteriors, avoiding numerical integration. Beta-Binomial: If X ~ Binomial(n, p) and prior p ~ Beta(α, β), then posterior p|X ~ Beta(α + X, β + n - X). Perfect for conversion rates, CTR. Gamma-Poisson: If X ~ Poisson(λ) and prior λ ~ Gamma(α, β), then posterior λ|X ~ Gamma(α + ΣX, β + n). Perfect for event counts, arrival rates. Normal-Normal: If X ~ N(μ, σ²) with known σ² and prior μ ~ N(μ₀, τ²), then posterior μ|X ~ N(posterior_mean, posterior_variance) with known closed form. Knowing which prior conjugates to which likelihood is a common interview question.
  • 3Credible intervals vs confidence intervals: A 95% Bayesian credible interval [a, b] means: given the data, there is a 95% probability that the true parameter lies in [a, b]. This is the natural interpretation people mistakenly assign to frequentist CIs. A 95% frequentist confidence interval means: if you repeated the experiment many times and constructed a CI each time, 95% of those intervals would contain the true value. The specific interval you observe either does or does not contain the true value — no probability statement about this specific interval is valid in the frequentist framework. In Bayesian analysis, the HDI (Highest Density Interval) is the shortest interval containing 95% of the posterior mass — preferred over equal-tail intervals when the posterior is skewed.
  • 4MCMC — Metropolis-Hastings: Used when the posterior has no closed form. Algorithm: (1) Start at θ₀. (2) Propose θ* from a proposal distribution q(θ*|θ_t). (3) Compute acceptance ratio r = [P(D|θ*) P(θ*)] / [P(D|θ_t) P(θ_t)] × [q(θ_t|θ*) / q(θ*|θ_t)]. (4) Accept θ* with probability min(1, r); otherwise stay at θ_t. (5) Repeat. Under mild conditions, the chain converges to the target posterior distribution. Convergence diagnostics: R-hat (Gelman-Rubin statistic) < 1.1 indicates convergence across multiple chains. Effective sample size (ESS) should be > 400 for reliable posterior estimates. Trace plots should look like 'fuzzy caterpillars' — mixing well without getting stuck.
  • 5Gibbs sampling: A special case of MCMC where, for a model with multiple parameters θ = (θ₁, θ₂, ..., θ_k), you iteratively sample each parameter from its full conditional distribution P(θ_i | θ_{-i}, D) while holding all other parameters fixed. Requires knowing the full conditionals in closed form. More efficient than Metropolis-Hastings when conditionals are tractable. Used in Bayesian network inference and LDA (Latent Dirichlet Allocation). Hamiltonian Monte Carlo (HMC) uses gradient information to make longer, more efficient proposals — the basis of Stan and PyMC's NUTS sampler, which is now the production standard for Bayesian modeling.
  • 6Variational inference (VI): An alternative to MCMC that frames posterior inference as optimization. Approximate the true posterior P(θ|D) with a simpler distribution q(θ; φ) from a variational family (e.g., mean-field: q(θ) = Πᵢ q(θᵢ)). Minimize the KL divergence KL(q || P) by maximizing the Evidence Lower BOund (ELBO): ELBO = E_q[log P(D|θ)] - KL(q(θ) || P(θ)). Maximizing the ELBO is equivalent to minimizing KL(q || P). VI is faster than MCMC (optimization vs sampling) but approximate — tends to underestimate posterior variance. Scalable VI (stochastic VI, ADVI) enables Bayesian inference on large datasets. Used in production at Uber, Netflix for large-scale latent variable models.
  • 7Bayesian A/B testing — sequential decision making: The core advantage over frequentist testing: you can stop the experiment early at any time without inflating Type I error, because you're computing P(treatment > control | data) directly from the posterior, not a p-value. Setup: model control conversion rate p_A ~ Beta(α₀, β₀), treatment p_B ~ Beta(α₀, β₀) with weak prior. After observing n_A conversions in N_A trials: p_A|data ~ Beta(α₀ + n_A, β₀ + N_A - n_A). P(p_B > p_A | data) = ∫∫ 1[p_B > p_A] P(p_A|data) P(p_B|data) dp_A dp_B — computable analytically for Beta distributions or via Monte Carlo sampling. Expected loss: E[loss of choosing A | data] = E[max(p_B - p_A, 0) | data]. Decision rule: ship treatment when P(p_B > p_A | data) > 0.95 or when expected loss < ε.
  • 8Hierarchical models (partial pooling): Suppose you're modeling conversion rates for 50 different product categories. Complete pooling (estimate one global rate) ignores between-category variation. No pooling (estimate each category independently) ignores information shared across categories — small categories get noisy estimates. Hierarchical model: model each category's rate θ_k ~ Beta(α, β) where (α, β) are drawn from a hyperprior — categories share information through the hyperprior. The result is partial pooling: small categories are shrunk toward the global mean, large categories retain their own estimate. This is empirical Bayes in a full Bayesian formulation. Directly tested at companies running experiments across many product verticals (Airbnb) or regions (Uber).
  • 9Thompson sampling for multi-armed bandits: The exploration-exploitation dilemma: should you exploit the arm with the best observed reward, or explore other arms that might be better? Thompson sampling: at each round, sample θ_k from the posterior P(θ_k | observed rewards for arm k). Pull the arm with the highest sampled θ_k. The uncertainty in the posterior naturally drives exploration (arms with uncertain posteriors are sometimes sampled high) while the posterior mean drives exploitation. For a Bernoulli bandit with Beta-Binomial conjugacy: initialize p_k ~ Beta(1,1). After observing s_k successes and f_k failures for arm k: sample θ_k ~ Beta(1+s_k, 1+f_k) each round. Thompson sampling is asymptotically optimal (achieves Lai-Robbins lower bound on cumulative regret). Used at Netflix for A/B test allocation, at Spotify for playlist ranking.
  • 10Gaussian Processes (GP): A GP is a distribution over functions. Any finite collection of function values f(x₁), ..., f(xₙ) follows a multivariate Gaussian. Specified by: mean function m(x) and covariance (kernel) function k(x, x'). Common kernels: RBF (squared exponential) k(x,x') = σ² exp(-||x-x'||²/(2l²)) — smooth functions; Matérn — controls smoothness via ν parameter; periodic kernel for periodic patterns. GP regression: given observations y = f(X) + ε (ε ~ N(0, σ²_noise)), the posterior predictive for new point x* is also Gaussian with closed-form mean and variance. GP is the non-parametric Bayesian alternative to kernel regression — it quantifies uncertainty in predictions, not just point estimates. Limitation: O(n³) computation for n training points — approximate methods (sparse GPs, inducing points) scale to larger datasets.
  • 11Bayesian optimization: Uses a GP as a surrogate model to optimize expensive black-box functions (e.g., hyperparameter tuning for ML models). Algorithm: (1) Build a GP posterior over the objective function using evaluated points. (2) Maximize an acquisition function that balances exploration and exploitation to select the next point to evaluate. (3) Evaluate the expensive function at that point. (4) Update the GP. (5) Repeat. Acquisition functions: Expected Improvement (EI) = E[max(f(x) - f_best, 0)]; Upper Confidence Bound (UCB) = μ(x) + κ σ(x); Probability of Improvement (PI). Bayesian optimization typically finds good hyperparameters in 50-100 function evaluations vs 1000s for random search. Used in AutoML systems (Google Vizier, Optuna, Spearmint).
  • 12MAP estimation vs MLE: Maximum Likelihood Estimation (MLE) finds θ_MLE = argmax_θ P(D|θ). Maximum A Posteriori (MAP) finds θ_MAP = argmax_θ P(θ|D) = argmax_θ P(D|θ)P(θ). MAP is equivalent to MLE with a regularization term equal to -log P(θ). Connection: L2 regularization (Ridge) = MAP with Gaussian prior. L1 regularization (LASSO) = MAP with Laplace prior. MAP gives a point estimate (not a full posterior) — it does not quantify uncertainty. As n → ∞, MAP and MLE converge because the likelihood dominates the prior. MAP is a computationally tractable Bayesian approximation when full posterior inference is too expensive.

Key Formulas

01Bayes' theorem: P(θD)=P(Dθ)P(θ)P(D)P(\theta | D) = \frac{P(D|\theta) P(\theta)}{P(D)}, posterior \propto likelihood ×\times prior
02Beta-Binomial conjugate: prior pBeta(α,β)p \sim \text{Beta}(\alpha, \beta), posterior pxBeta(α+x,  β+nx)p|x \sim \text{Beta}(\alpha + x,\; \beta + n - x)
03ELBO (variational inference): L(ϕ)=Eqϕ[logP(Dθ)]KL(qϕ(θ)P(θ))\mathcal{L}(\phi) = \mathbb{E}_{q_\phi}[\log P(D|\theta)] - \text{KL}(q_\phi(\theta) \| P(\theta))
04GP posterior mean: μ=k(x,X)[K(X,X)+σ2I]1y\mu_{*} = k(x_*, X)[K(X,X) + \sigma^2 I]^{-1} y
05GP posterior variance: σ2=k(x,x)k(x,X)[K(X,X)+σ2I]1k(X,x)\sigma^2_{*} = k(x_*, x_*) - k(x_*, X)[K(X,X) + \sigma^2 I]^{-1} k(X, x_*)
06Expected Improvement: EI(x)=E[max(f(x)fbest,0)]\text{EI}(x) = \mathbb{E}[\max(f(x) - f_{\text{best}}, 0)]
07Thompson sampling: sample θkP(θkdatak)\theta_k \sim P(\theta_k | \text{data}_k), pull argmaxkθk\arg\max_k \theta_k
08MAP = MLE + prior: θMAP=argmaxθ[logP(Dθ)+logP(θ)]\theta_{\text{MAP}} = \arg\max_\theta [\log P(D|\theta) + \log P(\theta)]
python
1import numpy as np
2import scipy.stats as stats
3import matplotlib.pyplot as plt
4from typing import Tuple
5
6np.random.seed(42)
7
8# ─── 1. Bayesian A/B test with Beta-Binomial conjugate ───────────────────────
9def bayesian_ab_test(
10 n_A: int, conversions_A: int,
11 n_B: int, conversions_B: int,
12 prior_alpha: float = 1.0,
13 prior_beta: float = 1.0,
14 n_samples: int = 100_000
15) -> dict:
16 """
17 Bayesian A/B test for conversion rates using Beta-Binomial conjugacy.
18 Returns: P(B > A), expected lift, credible interval for lift.
19 """
20 # Posterior distributions (closed form via conjugacy)
21 alpha_A = prior_alpha + conversions_A
22 beta_A = prior_beta + n_A - conversions_A
23 alpha_B = prior_alpha + conversions_B
24 beta_B = prior_beta + n_B - conversions_B
25
26 # Monte Carlo integration (faster than analytical formula for multiple metrics)
27 samples_A = np.random.beta(alpha_A, beta_A, n_samples)
28 samples_B = np.random.beta(alpha_B, beta_B, n_samples)
29
30 p_B_wins = (samples_B > samples_A).mean()
31 relative_lift = (samples_B - samples_A) / samples_A
32 lift_mean = relative_lift.mean()
33 lift_ci_95 = np.percentile(relative_lift, [2.5, 97.5])
34
35 # Expected loss: E[max(p_A - p_B, 0) | data] — cost of wrongly choosing B
36 expected_loss_B = np.maximum(samples_A - samples_B, 0).mean()
37
38 return {
39 'p_B_beats_A': p_B_wins,
40 'posterior_mean_A': alpha_A / (alpha_A + beta_A),
41 'posterior_mean_B': alpha_B / (alpha_B + beta_B),
42 'expected_lift': lift_mean,
43 'lift_ci_95': lift_ci_95,
44 'expected_loss_B': expected_loss_B,
45 'posterior_A': (alpha_A, beta_A),
46 'posterior_B': (alpha_B, beta_B),
47 }
48
49# Example: control 3% CVR, treatment 3.4% CVR (true 13% relative lift)
50result = bayesian_ab_test(
51 n_A=10_000, conversions_A=300, # control: 3.0% CVR
52 n_B=10_000, conversions_B=340, # treatment: 3.4% CVR
53)
54print("─── Bayesian A/B Test Results ───")
55print(f"P(B beats A): {result['p_B_beats_A']:.3f}")
56print(f"Posterior mean A: {result['posterior_mean_A']:.4f}")
57print(f"Posterior mean B: {result['posterior_mean_B']:.4f}")
58print(f"Expected relative lift: {result['expected_lift']:.2%}")
59print(f"95% Credible Interval: [{result['lift_ci_95'][0]:.2%}, {result['lift_ci_95'][1]:.2%}]")
60print(f"Expected loss of B: {result['expected_loss_B']:.5f}")
61
62# Sequential monitoring — run this daily, no p-value inflation
63print("\n─── Sequential Bayesian Monitoring ───")
64print(f"{'Day':>4} {'n_A':>6} {'n_B':>6} {'P(B>A)':>8} {'Decision'}")
65print("-" * 50)
66true_p_A, true_p_B = 0.030, 0.034
67for day in range(1, 15):
68 n_per_day = 1500
69 total_n = n_per_day * day
70 conv_A = np.random.binomial(total_n, true_p_A)
71 conv_B = np.random.binomial(total_n, true_p_B)
72 r = bayesian_ab_test(total_n, conv_A, total_n, conv_B)
73 prob = r['p_B_beats_A']
74 decision = "SHIP B" if prob > 0.95 else ("STOP (B losing)" if prob < 0.05 else "continue...")
75 print(f"{day:>4} {total_n:>6} {total_n:>6} {prob:>8.3f} {decision}")
76
77# ─── 2. Thompson Sampling for multi-armed bandit ─────────────────────────────
78print("\n─── Thompson Sampling: Multi-Armed Bandit ───")
79
80class ThompsonSamplingBandit:
81 """Beta-Bernoulli Thompson Sampling with conjugate posterior updates."""
82 def __init__(self, n_arms: int, prior_alpha: float = 1.0, prior_beta: float = 1.0):
83 self.n_arms = n_arms
84 self.alpha = np.full(n_arms, prior_alpha, dtype=float) # successes + prior
85 self.beta_ = np.full(n_arms, prior_beta, dtype=float) # failures + prior
86 self.counts = np.zeros(n_arms, dtype=int)
87 self.rewards = np.zeros(n_arms, dtype=float)
88
89 def select_arm(self) -> int:
90 """Sample from each arm's posterior and pull the best."""
91 samples = np.random.beta(self.alpha, self.beta_)
92 return int(np.argmax(samples))
93
94 def update(self, arm: int, reward: float):
95 """Update posterior with Bernoulli reward (0 or 1)."""
96 self.counts[arm] += 1
97 self.alpha[arm] += reward
98 self.beta_[arm] += (1 - reward)
99 self.rewards[arm] += reward
100
101 def posterior_means(self) -> np.ndarray:
102 return self.alpha / (self.alpha + self.beta_)
103
104# True conversion rates (arm 2 is best with 12%)
105true_rates = [0.05, 0.08, 0.12, 0.07, 0.06]
106n_arms = len(true_rates)
107n_rounds = 5_000
108best_arm = np.argmax(true_rates)
109
110bandit = ThompsonSamplingBandit(n_arms)
111cumulative_regret = []
112total_regret = 0.0
113
114for t in range(n_rounds):
115 arm = bandit.select_arm()
116 reward = int(np.random.rand() < true_rates[arm])
117 bandit.update(arm, reward)
118 regret = true_rates[best_arm] - true_rates[arm]
119 total_regret += regret
120 if (t + 1) % 1000 == 0:
121 cumulative_regret.append(total_regret)
122
123print(f"True rates: {true_rates}")
124print(f"Posterior means: {bandit.posterior_means().round(4).tolist()}")
125print(f"Arm pull counts: {bandit.counts.tolist()}")
126print(f"Cumulative regret after {n_rounds} rounds: {total_regret:.2f}")
127print(f"Best arm correctly identified: {np.argmax(bandit.posterior_means()) == best_arm}")
128
129# ─── 3. Conjugate update: Beta-Binomial posterior as Bayesian learning ────────
130print("\n─── Conjugate Bayesian Learning (Beta-Binomial) ───")
131print("Prior: Beta(1,1) = Uniform (complete uncertainty)")
132print(f"{'n_obs':>6} {'conversions':>12} {'posterior_mean':>15} {'95% HDI'}")
133print("-" * 60)
134
135prior_a, prior_b = 1.0, 1.0
136true_rate = 0.08 # true CTR
137
138for n in [10, 50, 100, 500, 2000]:
139 conversions = np.random.binomial(n, true_rate)
140 post_a = prior_a + conversions
141 post_b = prior_b + n - conversions
142 post_mean = post_a / (post_a + post_b)
143 # 95% HDI via Beta quantiles (symmetric for demonstration)
144 hdi_lo = stats.beta.ppf(0.025, post_a, post_b)
145 hdi_hi = stats.beta.ppf(0.975, post_a, post_b)
146 print(f"{n:>6} {conversions:>12} {post_mean:>15.4f} [{hdi_lo:.4f}, {hdi_hi:.4f}]")
147
148print(f"\nTrue rate: {true_rate:.4f} | Posterior narrows as n increases")
149
150# ─── 4. Hierarchical shrinkage: partial pooling simulation ───────────────────
151print("\n─── Hierarchical Shrinkage: No Pooling vs Partial Pooling ───")
152
153np.random.seed(0)
154# 20 product categories with different true CTRs
155n_categories = 20
156true_ctrs = np.random.beta(2, 20, n_categories) # centered around 9%
157sample_sizes = np.random.choice([30, 100, 500, 2000], n_categories) # small and large
158observed_conversions = np.random.binomial(sample_sizes, true_ctrs)
159
160# No pooling: each category estimated independently
161no_pool_estimates = observed_conversions / sample_sizes
162
163# Partial pooling (empirical Bayes): estimate hyperparameters from data
164# Then shrink each category estimate toward the global mean
165global_mean = observed_conversions.sum() / sample_sizes.sum()
166shrinkage_factor = sample_sizes / (sample_sizes + 50) # effective n / (n + k)
167partial_pool_estimates = shrinkage_factor * no_pool_estimates + (1 - shrinkage_factor) * global_mean
168
169# Compare RMSE
170rmse_no_pool = np.sqrt(np.mean((no_pool_estimates - true_ctrs)**2))
171rmse_partial_pool = np.sqrt(np.mean((partial_pool_estimates - true_ctrs)**2))
172
173print(f"Global mean CTR: {global_mean:.4f}")
174print(f"RMSE (no pooling): {rmse_no_pool:.5f}")
175print(f"RMSE (partial pooling): {rmse_partial_pool:.5f}")
176print(f"Partial pooling improves RMSE by: {(1 - rmse_partial_pool/rmse_no_pool)*100:.1f}%")
177print("(Improvement largest for small-sample categories where no-pooling is noisy)")

Four Bayesian concepts in runnable code: (1) Bayesian A/B test using Beta-Binomial conjugacy — computes P(B beats A), expected lift, credible interval, and expected loss; the sequential monitoring loop shows daily decisions without p-value inflation; (2) Thompson sampling bandit — sample from posterior per arm, take the best, update with the reward, observe how arm pull counts concentrate on the best arm with sub-linear regret; (3) conjugate Bayesian learning showing how the posterior Beta distribution narrows around the true rate as sample size grows; (4) hierarchical shrinkage demonstrating that partial pooling beats no pooling in RMSE by shrinking small-sample estimates toward the global mean.

Worked Interview Problems

3 problems

Problem

A product manager at Netflix asks: 'We've been running frequentist A/B tests. A colleague says we should switch to Bayesian A/B testing. What are the tradeoffs and when would you recommend each approach?'

Solution

1

Frequentist A/B testing strengths: (1) Well-understood by regulators and executives (p-value, though often misinterpreted, is widely expected). (2) Strong theoretical guarantees: if you pre-specify α, β, and sample size, you have guaranteed Type I and Type II error rates. (3) No prior specification required — no risk of prior manipulation. (4) Computationally trivial. Weaknesses: (1) Cannot stop early or peek without inflating Type I error. (2) Communicates 'reject/fail to reject' — hard to convey magnitude of effect. (3) p-value does not answer the question everyone asks: 'what is the probability the treatment is better?'

2

Bayesian A/B testing strengths: (1) Natural sequential decision making — can stop as soon as P(B > A) > 0.95, reducing experiment duration. (2) Communicates uncertainty naturally: 'there is an 87% probability that treatment B is better.' (3) Expected loss gives a business-friendly decision rule. (4) Hierarchical priors can pool information across related experiments. Weaknesses: (1) Requires prior specification — a weak prior (Beta(1,1)) is standard but a strong prior can influence small-sample results. (2) Less familiar to stakeholders. (3) If you choose a prior that matches your hypothesis, it can look like hypothesis confirmation.

3

Recommendation framework: Use Bayesian when: (a) you expect to monitor results continuously (e.g., real-time dashboards), (b) you have prior knowledge from historical experiments worth encoding, (c) you want to stop early when one variant clearly dominates, (d) you're running many related experiments that benefit from hierarchical pooling. Use Frequentist when: (a) regulatory or external reporting requires p-values, (b) you can pre-specify and strictly commit to a fixed sample size, (c) you want exact Type I error control for high-stakes decisions.

4

At Netflix specifically: Bayesian testing is used for personalization experiments where you run thousands of concurrent experiments and want to terminate losing experiments early. The expected loss framework allows a clear 'cost of a wrong decision' interpretation that executives can understand. Frequentist testing is retained for pricing experiments where regulatory requirements or financial audits require formal Type I error guarantees.

Answer

Frequentist: exact Type I error control, no prior needed, familiar to stakeholders — but no peeking, and p-value doesn't answer P(B > A). Bayesian: natural sequential stopping, P(B > A) is directly interpretable, expected loss enables business-cost decision rules, hierarchical pooling across experiments — but requires prior, can be gamed with strong priors. Netflix uses Bayesian for the majority of product experiments (early stopping, intuitive communication) and frequentist for financially audited decisions.

Common Mistakes

!

Misinterpreting a Bayesian credible interval as equivalent to a frequentist confidence interval. A 95% credible interval [a,b] means P(θ ∈ [a,b] | data) = 0.95 — a direct probability statement about θ given this specific dataset. A 95% CI is a procedure property (95% of such intervals cover the true value), not a property of the specific interval computed. In an interview, this distinction is tested directly.

!

Choosing an informative prior and not acknowledging it introduces a strong assumption. A Beta(10, 90) prior encodes the belief that conversion rate is around 10% with moderate confidence. If your prior is based on historical data, state this explicitly. If the posterior is driven by the prior rather than the data (happens with small n), sensitivity analysis (trying different priors) is required. Presenting a Bayesian result without disclosing the prior is incomplete analysis.

!

Confusing MAP estimation with full Bayesian inference. MAP gives a single point estimate (the mode of the posterior) — it does not give a posterior distribution or quantify uncertainty. You cannot compute credible intervals from a MAP estimate alone. If someone asks for 'Bayesian uncertainty quantification,' MAP is not sufficient; you need the full posterior.

!

Ignoring MCMC convergence diagnostics. Reporting results from an MCMC chain that has not converged is a fundamental error. Always check: R-hat < 1.1 for all parameters (Gelman-Rubin across multiple chains), effective sample size ESS > 400 per parameter, and trace plots showing good mixing (no stuck behavior, no trends). In PyMC or Stan, az.summary() computes these automatically.

!

In Thompson sampling, forgetting to reset or decay posteriors when the environment changes. If the true arm reward rates shift (seasonal effects, product changes), an old posterior with thousands of accumulated observations will barely update — the bandit gets stuck exploiting a previously-optimal arm. Solutions: sliding window updates (only use the last N observations), prior decay (multiply α and β by a discount factor each round), or explicit change-point detection to trigger a posterior reset.

Only works in the Electron app

<webview> is an Electron-only tag. Run npm run electron:dev to use this.

25:00Focus
0

25 min focus · 5 min break · long break every 4 sessions

The Ultimate Grind