Skip to content

trrad/pytyche

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

459 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Pytyche

Faster, calibrated heterogeneous-treatment-effect (HTE) discovery in a sequential / adaptive targeting loop — built for real-world online experiments where most users don't convert and the conversion signal is noisy.

Pytyche fits a Bayesian Causal Forest (BCF) over hurdle-distributed outcomes (revenue, conversion, click-through, churn), recalibrates its posterior intervals against simulation-based ground truth, and feeds the calibrated posterior into a sequential allocator that drives the next round of a multi-round experiment. The end-to-end loop runs on a single GPU. The same primitives also work for a single-shot RCT or observational analysis, but the API is shaped for multi-round growth experiments where you narrow allocation toward responder segments over time while keeping controls in every segment so measurement stays honest.

Documentation: https://tradcliffe2.gitlab.io/tyche/ · First fit: tutorial · Overview: concept doc · Status: alpha (0.1.0.dev) — MIT


What's inside

Why this is here
GPU joint hurdle BCF on top of bartz Roughly 5× to 60× faster than the StochTree CPU backend at production scales on real workloads — the canonical joint hurdle fit lands 4.5–8.6× at n=750k (the heaviest case: two coupled forests with shared topology), while the single-channel continuous and binary paths hit 17–63× from n=250k through n=2M. Full grid in the bench publication snapshot. What used to be a CPU-week of simulation-based calibration (SBC) sweeps now runs overnight.
Shared-tree topology with dual leaves A single tree structure jointly fits both channels of a hurdle outcome (probit conversion + log-severity), instead of training two independent forests — following Linero et al.'s shared Bayesian forests. The structural prior carries information across channels and stabilizes per-segment group-average treatment effect (GATE) estimates at low conversion rates — exactly the regime online experiments live in.
Perturb + rotation MCMC proposals (research / alpha) Augments bartz's grow/prune chain with structural tree moves following Pratola et al., adapted to the GPU kernels. Aimed at reducing autocorrelation in deep-tree posteriors.
Programmatic DGP generators built for tailored SBC recalibration A small typed grammar (pytyche.generators.scenarios) parameterizes the data-generating process (DGP); sweeps over it produce the SBC tables that recalibrate the posterior at your operating regime. Agentic DGP generation is in development.
Sequential targeting as a first-class API citizen The sequential experiment loop (pt.sequential_experiment) runs Thompson allocation with controls retention; built-in power simulations sweep over the same DGP classes used for calibration. See sequential-targeting.
Honest-uncertainty contracts pytyche.contracts separates observed data from ground truth at the type level, so analysis code structurally cannot peek at what it shouldn't see. See statistical-honesty.
Interpretable policy segmentations alongside the posterior Each round of sequential targeting compresses the BCF CATE posterior into a shallow policy tree (cf. Hitsch / Misra / Zhang 2024) — a stakeholder-facing decision surface, not just a model object, that drives the next round's allocation and gives reviewers an auditable handle on the model's segment-level decisions. First-class public API + custom-criterion + robustness layer on the roadmap.

Why it exists

BCF posteriors at production scale are structurally miscalibrated — the regularization prior of Bayesian Additive Regression Trees (BART, the model family BCF builds on) narrows credible intervals for better point estimation at the cost of honest uncertainty. The standard fixes (more chains, better sampler) don't help. The actual fix is empirical: SBC across realistic DGPs, then isotonic recalibration. That requires hundreds of full posterior fits, which on CPU is a multi-week research project per design surface.

GPU BCF makes that loop cheap enough to run routinely. Speed isn't the contribution — speed is what unlocks the contribution. With the loop cheap, calibration becomes something you do per-deployment instead of per-publication; with calibrated posteriors, sequential targeting becomes safe enough to actually deploy.

Install

# Recommended — GPU JAX (CUDA 12)
uv add 'pytyche[gpu]'

# CPU-only (fully functional; the first fit warns once when no CUDA device is found)
uv add pytyche

Verify the runtime with python -c "import pytyche as pt; pt.check_setup()".

For a development checkout (editable, all extras, bartz fork as a submodule):

git clone --recurse-submodules https://gitlab.com/tradcliffe2/tyche
cd tyche
uv sync --all-extras

Quick start

Fit the canonical model on an 800-visitor synthetic dataset in ~20 seconds on JAX-CPU:

import os; os.environ["JAX_PLATFORMS"] = "cpu"  # omit for GPU
import pytyche as pt

bundle = pt.generate(n_visitors=800, segments={
    "responders":     {"pct": 0.4, "base_conv": 0.08, "treatment_effect": 0.10,
                       "aov_mu": 3.5, "aov_sigma": 0.5, "treatment_aov_mu_shift": 0.15},
    "non_responders": {"pct": 0.6, "base_conv": 0.06, "treatment_effect": 0.0,
                       "aov_mu": 3.3, "aov_sigma": 0.5, "treatment_aov_mu_shift": 0.0},
}, metric="revenue_per_visitor", seed=0)

result = pt.fit(bundle.observed, num_burnin=40, num_mcmc=80, num_trees_mu=30,
                num_trees_tau=15, max_depth=4, num_gfr_sweeps=2,
                diagnostic_interval=20, seed=0)
result.analyze()  # comparisons, discovered segments, recommendation
# result.rpv_cate_samples → (n_visitors, 80) posterior draws of the per-visitor CATE

The full product is the adaptive loop on top of that fit — pt.sequential_experiment(...) runs a realistically-sized multi-round experiment (350,000 visitors) in about fifteen minutes on a consumer GPU; the adaptive-experiment tutorial walks it end to end. For the single-fit on-ramp (posterior interpretation at segment level, ground-truth comparison) see the first-fit tutorial.

What pytyche is and isn't

Pytyche is a designed-experiment library for round-based online experiments with a handful of treatments: assignment rules are explicit, propensities are recorded exactly, and the loop pauses between rounds. Out of scope: marketplaces and anything else with cross-visitor interference (SUTVA violations), regulated decision contexts needing preregistration-grade governance, large-catalog per-item recommendation, real-time/streaming adaptation, and heavily-confounded observational inference (use econml / DoubleML). Extremely heavy-tailed revenue and calibration applied far from the scale it was fitted at both warrant a domain-specific re-check. The full enumeration lives in the overview's scope section.

Documentation

The published site follows the Diátaxis information architecture:

Build locally:

uv sync --all-extras
uv run sphinx-build -W -b html docs/ docs/_build/html

Documentation coverage

Public-API docstring coverage: 98% (72/73 symbols on the curated public surface — baseline in docs/coverage-baseline.json).

CI enforces stable-or-increasing coverage on every MR via tests/test_docs/test_public_api_coverage.py. When an MR raises coverage, bump the baseline in the same MR so the new floor sticks. The doc-health dashboard renders the current polish-state breakdown (drafting / reviewed / polished) and the drift list — docs whose declared depends-on source files have moved since the doc's last-human-review. Polished-tier drift fails CI; lower-tier drift is reported but doesn't block.

Development

See CLAUDE.md for project principles (development discipline, the SDLC-citizen contract for docs, the OpenSpec workflow), CLAUDE-AGENT.md for the implementation-subagent guide, and docs/concepts/testing-philosophy.md for the rationale behind pytyche's testing practices. Spec-driven changes live under openspec/.

License

MIT — see LICENSE. Built on bartz (MIT) by Giacomo Petrillo; the GPU BART kernels pytyche fits on top of are bartz's. Hurdle / shared-tree extensions and the calibration / targeting / generator stack are pytyche's.

Source: https://gitlab.com/tradcliffe2/tyche (PyPI package name: pytyche; GitLab repo name: tyche for URL brevity).

Citation

Methodology paper in preparation. Cite as pytyche, v0.1.0.dev (alpha), https://gitlab.com/tradcliffe2/tyche until a citable DOI is up.

About

a GPU-native, JAX implementation of Bayesian Causal Forests for hurdle outcomes with shared tree structure, user-friendly APIs for sequential, batched experimentation design, analysis and calibration. Solving the problem of stable segmentation and heterogeneous effect discovery in real-world, noisy data.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages