Skip to main content

pymc-modeling

Load whenever the user is working on code that imports pymc, pytensor, or arviz, or asks about Bayesian modeling, MCMC, priors, posteriors, sampling, or model diagnostics. Covers PyMC 6+, PyTensor 3+, ArviZ 1.1+ (DataTree API), pymc-bart, pymc-extras, nutpie, and JAX/NumPyro backends. Use for building probabilistic models, specifying priors, running MCMC, diagnosing convergence, or comparing models. Triggers include: Bayesian inference, posterior sampling, hierarchical/multilevel models, GLMs, time series, Gaussian processes, HSGP, BART, mixture models, prior/posterior predictive checks, MCMC diagnostics, LOO-CV, model comparison, causal inference with do/observe, and any PyTensor Op or graph work.

설치로 이동

소스 정보

저장소
pymc-labs/python-analytics-skills
최근 소스 활동
2026년 6월 22일 14:35
감지된 SKILL.md 언어
영어
스타
82
포크
10

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
14 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
pymc-modeling
description
Load whenever the user is working on code that imports pymc, pytensor, or arviz, or asks about Bayesian modeling, MCMC, priors, posteriors, sampling, or model diagnostics. Covers PyMC 6+, PyTensor 3+, ArviZ 1.1+ (DataTree API), pymc-bart, pymc-extras, nutpie, and JAX/NumPyro backends. Use for building probabilistic models, specifying priors, running MCMC, diagnosing convergence, or comparing models. Triggers include: Bayesian inference, posterior sampling, hierarchical/multilevel models, GLMs, time series, Gaussian processes, HSGP, BART, mixture models, prior/posterior predictive checks, MCMC diagnostics, LOO-CV, model comparison, causal inference with do/observe, and any PyTensor Op or graph work.
# PyMC Modeling Modern Bayesian modeling with PyMC 6+ on the ArviZ 1.1 / PyTensor 3 stack. Key defaults: nutpie sampler (2-5x faster; PyMC 6 selects it automatically when installed — no `nuts_sampler` argument needed), non-centered parameterization for hierarchical models, HSGP over exact GPs, coords/dims for readable DataTree output, and save-early workflow to prevent data loss from late crashes. `pm.sample(...)` returns an `xarray.DataTree` — the `idata` name is kept by convention, but it is a DataTree, not the old `InferenceData`. Access groups by bracket: `idata["posterior"]`, `idata["sample_stats"]`, etc. **Modeling strategy**: Build models iteratively — start simple, check prior predictions, fit and diagnose, check posterior predictions, expand one piece at a time. See [references/workflow.md](references/workflow.md) for the full workflow. ## Model Specification ### Basic Structure ```python import pymc as pm import arviz as az with pm.Model(coords=coords) as model: # Data containers (for out-of-sample prediction) x = pm.Data("x", x_obs, dims="obs") # Priors beta = pm.Normal("beta", mu=0, sigma=1, dims="features") sigma = pm.HalfNormal("sigma", sigma=1) # Likelihood mu = pm.math.dot(x, beta) y = pm.Normal("y", mu=mu, sigma=sigma, observed=y_obs, dims="obs") # Inference idata = pm.sample(random_seed=42) # PyMC 6 uses nutpie automatically when installed ``` ### Coords and Dims Use coords/dims for an interpretable DataTree when the model has meaningful structure: ```python coords = { "obs": np.arange(n_obs), "features": ["intercept", "age", "income"], "group": group_labels, } ``` Skip for simple models where overhead exceeds benefit. ### Parameterization Prefer non-centered parameterization for hierarchical models with weak data: ```python # Non-centered (better for divergences) offset = pm.Normal("offset", 0, 1, dims="group") alpha = mu_alpha + sigma_alpha * offset # Centered (better with strong data) alpha = pm.Normal("alpha", mu_alpha, sigma_alpha, dims="group") ``` ## Inference ### Default Sampling (nutpie preferred) In PyMC 6, `pm.sample` uses nutpie automatically whenever it is installed and the model can be compiled — do not pass `nuts_sampler="nutpie"` explicitly: ```python with model: idata = pm.sample( draws=1000, tune=1000, chains=4, random_seed=42, ) idata.to_netcdf("results.nc") # Save immediately after sampling ``` **Important**: For LOO-CV, model comparison, or LOO-PIT checks, ensure the `log_likelihood` group exists. In PyMC 6, do not pass a top-level `compute_log_likelihood=` argument to `pm.sample`. Either request it during conversion with `idata_kwargs={"log_likelihood": True}` or compute it explicitly after sampling: ```python idata = pm.sample(idata_kwargs={"log_likelihood": True}, random_seed=42) # or, after an existing sample: pm.compute_log_likelihood(idata, model=model) ``` This applies to every sampler (nutpie, PyMC NUTS, NumPyro) — not just nutpie. ### When to Use PyMC's Default NUTS Instead nutpie cannot handle discrete parameters or certain transforms (e.g., `ordered` transform with `OrderedLogistic`/`OrderedProbit`). PyMC 6 falls back automatically; to force the PyMC sampler explicitly, pass `nuts_sampler="pymc"`: ```python idata = pm.sample(draws=1000, tune=1000, chains=4, nuts_sampler="pymc", random_seed=42) ``` Never change the model specification to work around sampler limitations. If nutpie is not installed, install it (`pip install nutpie`) or fall back to `nuts_sampler="numpyro"`. ### Alternative MCMC Backends See [references/inference.md](references/inference.md) for: - **NumPyro/JAX**: GPU acceleration, vectorized chains ### Approximate Inference For fast (but inexact) posterior approximations: - **ADVI/DADVI**: Variational inference with Gaussian approximation - **Pathfinder**: Quasi-Newton optimization for initialization or screening ## Diagnostics and ArviZ Workflow **Minimum workflow checklist** — every model script should include: 1. Prior predictive check (`pm.sample_prior_predictive`) 2. Save results immediately after sampling (`idata.to_netcdf(...)`) 3. Divergence count + r_hat + ESS check 4. Posterior predictive check (`pm.sample_posterior_predictive`) Follow this systematic workflow after every sampling run: ### Phase 1: Immediate Checks (Required) ```python # 1. Check for divergences (must be 0 or near 0) # idata is an xarray.DataTree; path-access gets a DataArray n_div = idata["sample_stats"]["diverging"].sum().item() print(f"Divergences: {n_div}") # 2. Summary with convergence diagnostics # Default CI is 0.89 ETI (equal-tailed) — bounds labelled eti89_lb / eti89_ub summary = az.summary(idata, var_names=["~offset"]) # exclude auxiliary print(summary[["mean", "sd", "eti89_lb", "eti89_ub", "ess_bulk", "ess_tail", "r_hat"]]) # 3. Visual convergence check az.plot_trace_dist(idata, compact=True) az.plot_rank(idata, var_names=["beta", "sigma"]) ``` **Pass criteria** (all must pass before proceeding): - Zero divergences (or < 0.1% and randomly scattered) - `r_hat < 1.01` for all parameters - `ess_bulk > 400` and `ess_tail > 400` - Trace plots show good mixing (overlapping densities, fuzzy caterpillar) ### Phase 2: Deep Convergence (If Phase 1 marginal) ```python # ESS evolution (should grow linearly) az.plot_ess_evolution(idata) # Energy diagnostic (HMC health) az.plot_energy(idata) # Autocorrelation (should decay rapidly) az.plot_autocorr(idata, var_names=["beta"]) ``` ### Phase 3: Model Criticism (Required) ```python # Generate posterior predictive with model: idata.update(pm.sample_posterior_predictive(idata)) # Does the model capture the data? az.plot_ppc_dist(idata, kind="ecdf") # Calibration check az.plot_loo_pit(idata, var_names=["y"]) ``` **Critical rule**: Never interpret parameters until Phases 1-3 pass. ### Phase 4: Parameter Interpretation ```python # Posterior summaries az.plot_dist(idata, var_names=["beta"]) # Forest plots for hierarchical parameters az.plot_forest(idata, var_names=["alpha"], combined=True) # Parameter correlations (identify non-identifiability) az.plot_pair(idata, var_names=["alpha", "beta", "sigma"]) ``` See [references/arviz.md](references/arviz.md) for comprehensive ArviZ usage. See [references/diagnostics.md](references/diagnostics.md) for troubleshooting. ## Prior and Posterior Predictive Checks ### Prior Predictive (Before Fitting) Always check prior implications before fitting: ```python with model: prior_pred = pm.sample_prior_predictive(draws=500) az.plot_ppc_dist(prior_pred, group="prior_predictive", kind="ecdf") prior_y = prior_pred["prior_predictive"]["y"].values.flatten() print(f"Prior predictive range: [{prior_y.min():.1f}, {prior_y.max():.1f}]") ``` **Rule**: Run prior predictive checks before `pm.sample()` on any new model. If the range is implausible (negative counts, probabilities > 1), adjust priors before proceeding. ### Posterior Predictive (After Fitting) ```python with model: idata.update(pm.sample_posterior_predictive(idata)) az.plot_ppc_dist(idata, kind="ecdf") az.plot_loo_pit(idata, var_names=["y"]) ``` Observed data (dark line) should fall within posterior predictive distribution. See [references/arviz.md](references/arviz.md) for detailed interpretation. ## Model Debugging Before sampling, validate the model with `model.debug()` and `model.point_logps()`. Use `print(model)` for structure and `pm.model_to_graphviz(model)` for a DAG visualization. ### Common Issues | Symptom | Likely Cause | Fix | |---------|--------------|-----| | `ValueError: Shape mismatch` | Parameter vs observation dimensions | Use index vectors: `alpha[group_idx]` | | `Initial evaluation failed` | Data outside distribution support | Check bounds; use `init="adapt_diag"` | | `Mass matrix contains zeros` | Unscaled predictors or flat priors | Standardize features; use weakly informative priors | | High divergence count | Funnel geometry | Non-centered parameterization | | `NaN` in log-probability | Invalid parameter combinations | Check parameter constraints, add bounds | | `-inf` log-probability | Observations outside likelihood support | Verify data matches distribution domain | | Slow discrete sampling | NUTS incompatible with discrete | Marginalize discrete variables | See [references/troubleshooting.md](references/troubleshooting.md) for comprehensive problem-solution guide. For debugging divergences, use `az.plot_pair(idata, divergences=True)` to locate clusters. See [references/diagnostics.md](references/diagnostics.md) § Divergence Troubleshooting. For profiling slow models, see [references/troubleshooting.md](references/troubleshooting.md) § Performance Issues. ## Model Comparison ### LOO-CV (Preferred) ```python # Compute LOO with pointwise diagnostics loo = az.loo(idata, pointwise=True) print(f"ELPD: {loo.elpd:.1f} ± {loo.se:.1f}") # Check Pareto k values (must be < 0.7 for reliable LOO) print(f"Bad k (>0.7): {(loo.pareto_k > 0.7).sum().item()}") az.plot_khat(loo) ``` ### Comparing Models ```python # PyMC 6 requires an explicit log-likelihood compute before LOO pm.compute_log_likelihood(idata_a, model=model_a) pm.compute_log_likelihood(idata_b, model=model_b) # ArviZ 1.1 — only loo is supported (waic was removed) comparison = az.compare({ "model_a": idata_a, "model_b": idata_b, }) print(comparison[["rank", "elpd", "elpd_diff", "weight"]]) az.plot_compare(comparison) ``` **Decision rule**: If two models have similar stacking weights, they are effectively equivalent. See [references/arviz.md](references/arviz.md) for detailed model comparison workflow. For detailed LOO-CV workflows, model stacking, and calibration diagnostics, see the [model-evaluation skill](../model-evaluation/SKILL.md). ### Iterative Model Building Build complexity incrementally: fit the simplest plausible model first, diagnose it, check posterior predictions, then add ONE piece of complexity at a time. Compare each expansion via LOO. If stacking weights are similar, the models are effectively equivalent. See [references/workflow.md](references/workflow.md) for the full iterative workflow. ## Saving and Loading Results ### DataTree Persistence `pm.sample()` returns an `xarray.DataTree`. Persist with NetCDF; the `idata` name is convention. ```python # Save to NetCDF (recommended format) idata.to_netcdf("results/model_v1.nc") # Load idata = az.from_netcdf("results/model_v1.nc") ``` For compressed storage of large DataTree objects, see [references/workflow.md](references/workflow.md). **Critical**: Save IMMEDIATELY after sampling — late crashes destroy valid results: ```python with model: idata = pm.sample() # nutpie by default in PyMC 6; returns a DataTree idata.to_netcdf("results.nc") # Save before any post-processing! with model: idata.update(pm.sample_posterior_predictive(idata)) # .update() merges the new group in place idata.to_netcdf("results.nc") # Update with posterior predictive ``` **Note**: Use `.update({...})` or direct assignment (`idata["posterior_predictive"] = ppd_ds`) to add groups. ## Prior Selection See [references/priors.md](references/priors.md) for: - Weakly informative defaults by distribution type - Prior predictive checking workflow - Domain-specific recommendations For constrained priors, expert elicitation workflows, and PreliZ integration, see the [prior-elicitation skill](../prior-elicitation/SKILL.md). ## Common Patterns ### Hierarchical/Multilevel ```python with pm.Model(coords={"group": groups, "obs": obs_idx}) as hierarchical: # Hyperpriors mu_alpha = pm.Normal("mu_alpha", 0, 1) sigma_alpha = pm.HalfNormal("sigma_alpha", 1) # Group-level (non-centered) alpha_offset = pm.Normal("alpha_offset", 0, 1, dims="group") alpha = pm.Deterministic("alpha", mu_alpha + sigma_alpha * alpha_offset, dims="group") # Likelihood y = pm.Normal("y", alpha[group_idx], sigma, observed=y_obs, dims="obs") ``` ### GLMs ```python # Logistic regression with pm.Model() as logistic: alpha = pm.Normal("alpha", 0, 2.5) beta = pm.Normal("beta", 0, 2.5, dims="features")
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기