Probability & Bayesian Thinking for ML Interviews
The probability questions that separate candidates: base rates, why MLE is just cross-entropy in disguise, MAP as regularisation, and the distribution choices baked into every loss function.
Covers: Bayes theorem, conditional probability, distributions, expectation & variance, MLE vs MAP, sampling
Probability shows up in ML interviews in two disguises. The obvious one is a brainteaser about base rates or a coin. The subtle one — and the one that decides your level — is when the interviewer asks why you used cross-entropy loss, or what your model's 0.9 output actually means.
Every loss function is a likelihood in disguise. Once you see that, cross-entropy, MSE and L1 stop being arbitrary choices and become statements about your noise model. This lesson makes that link explicit.
30-second answer
About 1%. Even a 99%-accurate test produces ~100 false positives for every true positive when the base rate is 1 in 10,000. This is exactly why a fraud or rare-disease model with 99.9% accuracy can be useless, and why you report precision/recall at a realistic prevalence rather than accuracy.
Plugging in , , :
prevalence, sens, spec, N = 1e-4, 0.99, 0.99, 1_000_000
sick = N * prevalence
healthy = N - sick
tp = sick * sens
fn = sick - tp
fp = healthy * (1 - spec)
tn = healthy - fp
precision = tp / (tp + fp)
recall = tp / (tp + fn)
accuracy = (tp + tn) / N
print(f"TP={tp:.0f} FP={fp:.0f} FN={fn:.0f} TN={tn:.0f}")
print(f"precision={precision:.4f} recall={recall:.2f} accuracy={accuracy:.4f}")
# TP=99 FP=9999 FN=1 TN=989901
# precision=0.0098 recall=0.99 accuracy=0.9900
# The 'always predict healthy' baseline:
print(f"trivial baseline accuracy = {(N - sick)/N:.4f}") # 0.9999 <- beats the model!That last line is the punchline for an ML interview. A model with 99% accuracy loses to a constant predictor. This generalises to every rare-event problem you will build: fraud, churn-to-cancel, ad clicks, manufacturing defects, safety incidents.
What you actually do about it
- Report PR-AUC, not ROC-AUC. ROC-AUC uses the true-negative count, which is enormous and drowns out changes in false positives. PR curves are dominated by the positive class.
- Pick the threshold from the cost matrix, not from 0.5. If a missed fraud costs 2 of review time, the optimal threshold is where marginal costs balance.
- Two-stage funnels. A cheap high-recall model narrows a million cases to a thousand; an expensive high-precision model (or a human) decides those. This fixes the base rate for stage two.
- Report at deployment prevalence. A model validated on a 50/50 rebalanced set will look dramatically better than it performs live.
Say these points
- P(D|+) ≈ 1% — recite it with natural frequencies, not formulas.
- Base rate dominates: rare positives make precision collapse regardless of sensitivity.
- Accuracy is meaningless under imbalance; use PR-AUC and cost-based thresholds.
- Resampling breaks probability calibration — recalibrate before using scores as probabilities.
Avoid these mistakes
- Confusing P(+|D) with P(D|+) — the prosecutor's fallacy.
- Quoting ROC-AUC on a 1:10,000 problem.
- Reporting metrics on a rebalanced test set without saying so.
Expect these follow-ups
- Your fraud model has 0.94 ROC-AUC and 0.11 PR-AUC. What does that tell you?
- Derive the optimal decision threshold given a cost matrix.
- How would you correct predicted probabilities after training on undersampled negatives?
30-second answer
MLE picks parameters maximising P(data|θ). MAP maximises P(θ|data) ∝ P(data|θ)P(θ), so it adds a prior. Taking the negative log turns MLE into a loss: a Gaussian noise assumption gives MSE, a Bernoulli/categorical assumption gives cross-entropy. A Gaussian prior on θ under MAP is exactly L2 regularisation; a Laplace prior is L1.
Because logs are monotonic and products of many small probabilities underflow, we always work with the negative log-likelihood — and that object is your loss function.
Gaussian noise ⟹ MSE
Assume with . Then
The second term does not depend on . Drop it, absorb into the learning rate, and you have mean squared error. So every time you use MSE you are asserting that your residuals are Gaussian with constant variance. If they are heavy-tailed, a Laplace likelihood (⟹ L1/MAE loss) or Huber is the principled fix — not an ad-hoc one.
Bernoulli / categorical ⟹ cross-entropy
For binary labels with , each observation is Bernoulli:
That is binary cross-entropy, exactly. The multi-class version with a softmax gives categorical cross-entropy. Cross-entropy is not a heuristic — it is the negative log-likelihood of a categorical model.
MAP ⟹ regularisation
| Prior on θ | −log prior | Equivalent penalty |
|---|---|---|
| L2 / ridge / weight decay | ||
| Laplace | L1 / Lasso | |
| Uniform (improper) | constant | No regularisation → MAP = MLE |
import numpy as np
from scipy.optimize import minimize
rng = np.random.default_rng(0)
X = rng.normal(size=(200, 5)); true_w = np.array([2., -1., 0.5, 0., 3.])
y = X @ true_w + rng.normal(scale=0.5, size=200)
sigma, tau = 0.5, 1.0 # noise std, prior std
def neg_log_posterior(w):
nll = ((y - X @ w) ** 2).sum() / (2 * sigma ** 2) # Gaussian likelihood
nlp = (w ** 2).sum() / (2 * tau ** 2) # Gaussian prior
return nll + nlp
w_map = minimize(neg_log_posterior, np.zeros(5)).x
# Closed-form ridge with lambda = sigma^2 / tau^2
lam = sigma ** 2 / tau ** 2
w_ridge = np.linalg.solve(X.T @ X + lam * np.eye(5), X.T @ y)
print(np.round(w_map, 4)) # [ 1.9862 -0.9975 0.4959 -0.0106 3.0067]
print(np.round(w_ridge, 4)) # [ 1.9862 -0.9975 0.4959 -0.0106 3.0067]
print(np.allclose(w_map, w_ridge, atol=1e-4)) # TrueOne more distinction worth knowing: MAP still returns a point estimate. Full Bayesian inference integrates over the posterior to produce predictive distributions. As data grows the prior washes out and MAP → MLE, which is why regularisation matters most in the small-data regime.
Say these points
- Loss = negative log-likelihood; the likelihood encodes your noise assumption.
- Gaussian noise → MSE; Bernoulli/categorical → cross-entropy; Laplace → MAE.
- MAP = MLE + prior; Gaussian prior → L2, Laplace prior → L1.
- λ = σ²/τ² makes the ridge/prior correspondence exact.
- MAP is still a point estimate; full Bayes gives predictive uncertainty.
Avoid these mistakes
- Calling cross-entropy 'the standard classification loss' with no derivation.
- Using MSE on heavy-tailed targets and then blaming outliers rather than the likelihood.
- Claiming MAP gives uncertainty estimates. It does not — it gives a mode.
Expect these follow-ups
- Why is MSE a bad loss for classification even though it is differentiable?
- How would you get calibrated uncertainty out of a deep network?
- Derive the MLE for the parameter of an exponential distribution.
30-second answer
Bernoulli/categorical for classification outputs, Gaussian for continuous noise and initialisation, Poisson for counts, Exponential for waiting times, Beta as the conjugate prior for rates (Thompson sampling), and the long-tailed Zipf/power-law for user and token frequency. Knowing which one your data follows tells you which loss and which sampling strategy to use.
| Distribution | Models | Shows up in |
|---|---|---|
| Bernoulli / Categorical | A single binary or k-way outcome | Classification heads, token sampling, click prediction |
| Gaussian | Additive symmetric noise; sums of many effects (CLT) | MSE loss, weight init, VAE latents, diffusion noise |
| Poisson | Counts in a fixed window with constant rate | Requests/sec, defects per batch, Poisson regression |
| Exponential | Time until the next event (memoryless) | Session gaps, survival/churn analysis, retry backoff |
| Beta | A probability that is itself uncertain | Conjugate prior for CTR, Thompson sampling in bandits |
| Log-normal | Multiplicative effects; strictly positive, right-skewed | Latency, revenue, file sizes — log-transform before modelling |
| Zipf / power law | Extreme long tails | Word and token frequency, item popularity, cold start |
The three that actually get interviewed on
Gaussian, because of the Central Limit Theorem: the mean of enough i.i.d. samples is approximately normal regardless of the underlying distribution. That is what licenses confidence intervals in A/B tests. It is a statement about sample means, not about your raw data — a distinction people get wrong constantly.
Poisson, because it is the right model whenever you count events, and because it forces you to notice overdispersion: Poisson mandates variance = mean. Real traffic is burstier than that, so you reach for a negative binomial instead. Spotting that in an interview is a strong signal.
Beta, because it is the cleanest example of conjugacy and the engine behind Thompson sampling. Starting from and observing successes in trials gives a posterior of — pure counting, no integration.
import numpy as np
rng = np.random.default_rng(7)
true_ctr = [0.02, 0.05, 0.03] # unknown to the algorithm
alpha = np.ones(3); beta = np.ones(3) # Beta(1,1) = uniform prior
pulls = np.zeros(3, dtype=int)
for _ in range(20_000):
theta = rng.beta(alpha, beta) # sample a plausible CTR per arm
arm = int(np.argmax(theta)) # play the arm that looks best *this draw*
reward = rng.random() < true_ctr[arm]
alpha[arm] += reward # conjugate update: just counting
beta[arm] += 1 - reward
pulls[arm] += 1
print("pull share :", np.round(pulls / pulls.sum(), 3)) # [0.021 0.949 0.03 ]
print("posterior :", np.round(alpha / (alpha + beta), 4))# [0.0208 0.0503 0.0301]The bandit converges on arm 2 while still occasionally exploring — exploration falls out of posterior uncertainty rather than an epsilon hyperparameter. This is the standard answer to “how would you roll out a new ranking model without a fixed-split A/B test?”
Say these points
- Every classification head is a categorical distribution; every MSE is a Gaussian assumption.
- CLT is about sample means, not raw data.
- Poisson forces variance = mean; real count data is usually overdispersed → negative binomial.
- Beta–Bernoulli conjugacy makes Thompson sampling a counting exercise.
- Latency and revenue are log-normal — model in log space and report percentiles.
Avoid these mistakes
- Saying 'the CLT means my data is normal'.
- Using a Poisson model on bursty traffic without checking dispersion.
- Reporting mean latency instead of p95/p99.
Expect these follow-ups
- How would you detect overdispersion in count data?
- Compare Thompson sampling with UCB and epsilon-greedy.
- Why do token frequencies follow Zipf, and how does that affect tokenizer design?
30-second answer
Expected squared error at a point decomposes into irreducible noise σ², squared bias (how far the average model is from truth), and variance (how much the model moves across training sets). You derive it by adding and subtracting the expected prediction E[f̂(x)] and showing the cross term vanishes.
The derivation, in three moves
Split off the noise
Write with , . Since is independent of , the cross term dies and you get .Add and subtract the mean prediction
Let (averaged over training sets). Then . Square it.Kill the cross term
The cross term is , and by definition of . What remains is bias² + variance.
import numpy as np
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import BaggingRegressor
from sklearn.linear_model import LinearRegression
rng = np.random.default_rng(0)
f = lambda x: np.sin(2 * np.pi * x)
x_test = np.linspace(0, 1, 200).reshape(-1, 1)
truth = f(x_test).ravel()
def bias_variance(make_model, n_sets=200, n=60, noise=0.25):
preds = np.empty((n_sets, len(x_test)))
for i in range(n_sets):
x = rng.random((n, 1))
y = f(x).ravel() + rng.normal(scale=noise, size=n)
preds[i] = make_model().fit(x, y).predict(x_test)
mean_pred = preds.mean(axis=0)
bias2 = ((mean_pred - truth) ** 2).mean()
var = preds.var(axis=0).mean()
return bias2, var
for name, mk in [
("linear (underfit)", lambda: LinearRegression()),
("deep tree (overfit)",lambda: DecisionTreeRegressor(max_depth=None)),
("bagged trees", lambda: BaggingRegressor(DecisionTreeRegressor(), n_estimators=50)),
]:
b2, v = bias_variance(mk)
print(f"{name:22s} bias^2={b2:.4f} variance={v:.4f} sum={b2+v:.4f}")
# linear (underfit) bias^2=0.4831 variance=0.0179 sum=0.5010
# deep tree (overfit) bias^2=0.0143 variance=0.1074 sum=0.1217
# bagged trees bias^2=0.0138 variance=0.0221 sum=0.0359That table is the whole lesson: bagging keeps the low bias of deep trees while collapsing their variance by ~5×. It is also exactly the argument for random forests over a single tree.
Diagnosing which one you have
| Symptom | Diagnosis | Fix |
|---|---|---|
| Train error high, val ≈ train | High bias (underfitting) | Bigger model, better features, train longer, less regularisation |
| Train error low, val ≫ train | High variance (overfitting) | More data, augmentation, regularisation, early stopping, ensembling |
| Both high and a big gap | Both | Fix bias first — you cannot regularise your way to signal you never learned |
| Train ≈ val but both plateau near noise floor | Irreducible error | Only new features/data sources help; more modelling will not |
Say these points
- Error = σ² + bias² + variance; the expectation is over training-set resamples.
- The cross term vanishes because E[f̄ − f̂] = 0.
- Bagging attacks variance, boosting attacks bias.
- Fix bias before variance — regularisation cannot create signal.
- Double descent means the classic U-curve is an approximation, not a law.
Avoid these mistakes
- Interpreting 'variance' as spread over test points rather than over training sets.
- Forgetting the irreducible term, then chasing an unreachable error target.
- Adding regularisation to a model that is already underfitting.
Expect these follow-ups
- Why does boosting reduce bias while bagging reduces variance?
- How do learning curves let you tell 'need more data' from 'need a better model'?
- Explain double descent and where the interpolation threshold sits.
30-second answer
Importance sampling estimates an expectation under distribution p while only being able to sample from q, by reweighting each sample by p(x)/q(x). It appears in off-policy RL and PPO's ratio term, in off-policy evaluation of recommenders and bandits, in negative sampling for embeddings, and in speculative decoding for LLMs.
The estimator is unbiased provided everywhere . But its variance can be unbounded when has thinner tails than : a few samples land in a region where is enormous and dominate the estimate. Practitioners therefore clip or truncate the weights, accepting a little bias for a lot of stability.
Where you will actually meet it
PPO / RLHF
The policy that generated the rollouts is stale by the time you take several gradient steps. PPO corrects with the ratio — an importance weight — and clips it to precisely to bound the variance described above.Off-policy evaluation of a recommender
You logged traffic under the old ranker but want to estimate the new one's CTR without shipping it. Inverse propensity scoring reweights logged rewards by . It only works if the logging policy was stochastic and you stored the propensities — a data-collection decision you must make before you need it.Negative sampling
word2vec and modern two-tower retrieval models cannot afford a softmax over millions of items, so they sample negatives from a tractable proposal (often popularity^0.75) and correct the bias with a logQ / sampled-softmax adjustment.Speculative decoding
A small draft model proposes k tokens, the large model verifies them in one forward pass, and a modified rejection-sampling rule accepts or resamples so that the output distribution is exactly the large model's. Same reweighting idea, 2–3× decode speedup.
import numpy as np
rng = np.random.default_rng(0)
# Target: N(0,1). Estimate E[f(x)] for a tail-sensitive f.
f = lambda x: (x > 2.5).astype(float) # true value = 1 - Phi(2.5) = 0.00621
def naive(n): # sample directly from the target
return f(rng.normal(size=n)).mean()
def importance(n, shift=2.5): # proposal N(shift, 1) -> lands in the tail
x = rng.normal(loc=shift, size=n)
w = np.exp(-0.5*x**2) / np.exp(-0.5*(x-shift)**2) # p(x)/q(x)
return (w * f(x)).mean()
for n in (1_000, 100_000):
est_n = [naive(n) for _ in range(50)]
est_i = [importance(n) for _ in range(50)]
print(f"n={n:>7} naive {np.mean(est_n):.5f} ± {np.std(est_n):.5f}"
f" IS {np.mean(est_i):.5f} ± {np.std(est_i):.5f}")
# n= 1000 naive 0.00640 ± 0.00248 IS 0.00622 ± 0.00016
# n= 100000 naive 0.00621 ± 0.00025 IS 0.00621 ± 0.00002
# -> a good proposal cuts the standard error by ~15x for the same budget.For interviews, the crisp framing is: importance sampling is how you answer counterfactual questions from logged data. Every 'how would the new model have performed last week?' question is an importance-sampling question, and the honest answer includes its variance caveat.
Say these points
- Reweight by p/q to estimate under p while sampling from q; unbiased if q covers p's support.
- Variance explodes when q has thinner tails than p — clip weights or fix the proposal.
- PPO's clipped ratio is a variance-bounded importance weight.
- Off-policy evaluation needs logged propensities from a stochastic policy.
- Report ESS = (Σw)²/Σw² to show whether the estimate is trustworthy.
Avoid these mistakes
- Claiming unbiasedness while ignoring that the variance may be infinite.
- Attempting off-policy evaluation on deterministically logged traffic (no propensities, no support).
- Forgetting the logQ correction with sampled softmax, which biases toward popular items.
Expect these follow-ups
- Derive why PPO clips the ratio instead of using a KL penalty directly.
- How do you build an off-policy evaluation pipeline for a ranking system?
- Explain how speculative decoding preserves the target distribution exactly.
Showing 5 of 5 questions for probability-for-ml-interviews.
Check your understanding
5 questions · no sign-up, nothing stored
Hands-on challenge
Build it — this is what you talk about in a deep-dive round.
Build a calibrated rare-event classifier
Take a 1:2000 imbalanced dataset and show, with numbers, why accuracy misleads and how to fix both the metric and the calibration.
Requirements
- Train a baseline and report accuracy, ROC-AUC and PR-AUC side by side with a constant-predictor baseline.
- Train a second model on undersampled negatives; show that its predicted probabilities are miscalibrated at true prevalence.
- Apply prior correction and/or isotonic calibration; plot reliability curves before and after.
- Derive the cost-optimal threshold for FN:FP = 250:1 and report the expected cost at that threshold.
Stretch goals
- Implement a two-stage funnel and quantify the precision improvement at fixed recall.
- Estimate the counterfactual precision of a different threshold using importance weights from logged scores.