Python interface to Stan, a package for Bayesian inference
npx @tessl/cli install tessl/pypi-pystan@3.10.0PyStan provides a Python interface to Stan, a state-of-the-art platform for statistical modeling and high-performance statistical computation. It enables Python developers to build, compile, and sample from Bayesian statistical models using Stan's probabilistic programming language, featuring automatic caching of compiled models and samples, and support for complex hierarchical models used in scientific research across social, biological, and physical sciences.
pip install pystanimport stan
# Version information (when available)
print(stan.__version__) # Package versionimport stan
# Define a simple Bayesian model
program_code = """
parameters {
real mu;
real<lower=0> sigma;
}
model {
mu ~ normal(0, 10);
sigma ~ exponential(1);
}
"""
# Build (compile) the model
model = stan.build(program_code)
# Sample from the posterior
fit = model.sample(num_chains=4, num_samples=1000)
# Access results
print(fit['mu']) # Parameter samples
print(fit.to_frame()) # Pandas DataFrame viewPyStan operates through a client-server architecture where Python manages the high-level interface while delegating computational tasks to httpstan, a Stan HTTP service. The core workflow follows these steps:
This design ensures high performance for computationally intensive Bayesian inference while maintaining Python's ease of use.
Core functionality for building Stan models from program code, including data handling, caching, and compilation management.
def build(program_code: str, data: Data = frozendict(), random_seed: Optional[int] = None) -> Model:
"""
Build (compile) a Stan program.
Args:
program_code: Stan program code describing a Stan model
data: Dictionary providing data for the model (default: frozendict())
random_seed: Random seed for reproducible results
Returns:
Model: Compiled model ready for sampling
"""MCMC sampling methods for drawing from posterior distributions, including HMC-NUTS and fixed parameter sampling.
class Model:
def sample(self, *, num_chains: int = 4, **kwargs) -> Fit: ...
def hmc_nuts_diag_e_adapt(self, *, num_chains: int = 4, **kwargs) -> Fit: ...
def fixed_param(self, *, num_chains: int = 4, **kwargs) -> Fit: ...Advanced functionality for parameter space transformations, log probability calculations, and gradient computations.
class Model:
def constrain_pars(self, unconstrained_parameters: Sequence[float], include_tparams: bool = True, include_gqs: bool = True) -> Sequence[float]: ...
def unconstrain_pars(self, constrained_parameters: Sequence[float]) -> Sequence[float]: ...
def log_prob(self, unconstrained_parameters: Sequence[float], adjust_transform: bool = True) -> float: ...
def grad_log_prob(self, unconstrained_parameters: Sequence[float]) -> Sequence[float]: ...Tools for accessing, analyzing, and transforming MCMC samples into usable formats.
class Fit:
def to_frame(self): ...
def __getitem__(self, param: str): ...
def __contains__(self, key: str) -> bool: ...
def __iter__(self): ...from typing import Dict, Union, Sequence, Optional
# Type alias for model data
Data = Dict[str, Union[int, float, Sequence[Union[int, float]]]]
@dataclass(frozen=True)
class Model:
"""Stores data associated with and proxies calls to a Stan model."""
model_name: str
program_code: str
data: Data
param_names: Tuple[str, ...]
constrained_param_names: Tuple[str, ...]
dims: Tuple[Tuple[int, ...]]
random_seed: Optional[int]
class Fit:
"""Stores draws from one or more chains. Acts like a Python dictionary."""
stan_outputs: Tuple[bytes, ...]
num_chains: int
param_names: Tuple[str, ...]
constrained_param_names: Tuple[str, ...]
dims: Tuple[Tuple[int, ...]]
num_warmup: int
num_samples: int
num_thin: int
save_warmup: bool
sample_and_sampler_param_names: Tuple[str, ...]PyStan provides a plugin system for extending functionality, primarily for post-sampling analysis.
# Plugin development (advanced usage)
import stan.plugins
class PluginBase:
"""Base class for PyStan plugins."""
def on_post_sample(self, fit: Fit) -> Fit:
"""Called with Fit instance when sampling has finished."""
return fit
def get_plugins():
"""Iterate over available plugins."""
...