Skip to content

Commit 9f84071

Browse files
committed
fix(tweedie-post): fix CustomDist random arg, add xtensor/pytensor explanation
- Change CustomDist to per Ricardo's review (dist expects a PyTensor expression, not numpy) - Add docstring to tweedie_logp_series explaining why plain PyTensor ops are used (xtensor named axes fail under PyMC 6.0 broadcasting) - Clean up leftover @classmethod dist corruption in code block - Update text references from 'dist' / 'tweedie_dist' to 'random' / 'tweedie_random'
1 parent fa95249 commit 9f84071

1 file changed

Lines changed: 13 additions & 7 deletions

File tree

docs/blog/posts/2026/pearson-phi-broken-tweedie.md

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ import pytensor.tensor as pt
5656

5757

5858
def tweedie_logp_series(value, mu, phi, p, n_terms=20):
59+
"""Tweedie log-pdf via series expansion (Dunn & Smyth 2005).
60+
61+
Uses plain PyTensor ops for PyMC 6.0 compatibility: xtensor's
62+
named axes require dims metadata that PyMC 6.0 strips during
63+
broadcasting. Plain tensor ops handle scalar-vector broadcasting
64+
without dims information.
65+
"""
5966
j = pt.arange(1, n_terms + 1, dtype=pytensor.config.floatX).reshape((-1, 1))
6067
alpha = (2 - p) / (p - 1)
6168

@@ -128,16 +135,15 @@ def tweedie_random(mu, phi, p, rng=None, size=None):
128135
With the log-pdf and random sampler in hand, building the model is straightforward. We place weakly informative priors on the parameters and wrap both functions into a `CustomDist`: the log-pdf for MCMC inference and the random sampler for posterior predictive checks.
129136

130137
```python title="Tweedie CustomDist wrapper"
131-
class Tweedie:
132-
@staticmethod
133-
def tweedie_dist(mu, phi, p, size):
134-
return tweedie_random(mu, phi, p, size=size)
138+
import pymc as pm
139+
from pymc import CustomDist
135140

141+
class Tweedie:
136142
def __new__(cls, name, mu, phi, p, **kwargs):
137143
return CustomDist(
138144
name, mu, phi, p,
139-
dist=cls.tweedie_dist,
140145
logp=tweedie_logp_series,
146+
random=tweedie_random,
141147
class_name="Tweedie",
142148
**kwargs,
143149
)
@@ -245,7 +251,7 @@ The (φ, p) joint distribution reveals no pathological tradeoff:
245251

246252
The 95% credible ellipse is well-centered on the true (MLE) values with moderate positive correlation: higher φ means slightly higher p, but the correlation is weak (≈ 0.3). This is the expected pattern — a larger dispersion naturally pairs with a slightly higher power parameter since both push in the same direction (more variance). The key point is that the posterior is **not** degenerate along the φ-p diagonal, confirming both parameters are separately identifiable from the data.
247253

248-
Posterior predictive checks (PPC) are a critical validation step in Bayesian workflow. Because the `Tweedie` wrapper provides `tweedie_dist` as the `dist` argument to `CustomDist`, PyMC handles posterior predictive sampling automatically:
254+
Posterior predictive checks (PPC) are a critical validation step in Bayesian workflow. Because the `Tweedie` wrapper provides `tweedie_random` as the `random` argument to `CustomDist`, PyMC handles posterior predictive sampling automatically:
249255

250256
```python title="Posterior predictive check — using pm.sample_posterior_predictive"
251257
with model:
@@ -267,7 +273,7 @@ obs_stats = {
267273
}
268274
```
269275

270-
The key point: `tweedie_dist` defined in the `Tweedie` class is what `sample_posterior_predictive` uses under the hood to generate draws — no manual thinning or re-sampling needed.
276+
The key point: `tweedie_random` defined in the `Tweedie` class is what `sample_posterior_predictive` uses under the hood to generate draws — no manual thinning or re-sampling needed.
271277

272278
#### Moment Validation
273279

0 commit comments

Comments
 (0)