Metadata-Version: 2.4
Name: py-qte
Version: 0.1.0a2
Summary: Quantile Treatment Effects
Keywords: quantile treatment effects,causal inference,econometrics,quantile regression
Author-Email: Moritz Helm <mohelm84@gmail.com>
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering :: Mathematics
Project-URL: Homepage, https://github.com/mohelm/py-qte
Project-URL: Repository, https://github.com/mohelm/py-qte
Project-URL: Issues, https://github.com/mohelm/py-qte/issues
Requires-Python: >=3.12
Requires-Dist: altair>=6.2.2
Requires-Dist: formulaic>=1.2.2
Requires-Dist: great-tables>=0.23.0
Requires-Dist: numpy>=2.5.1
Requires-Dist: polars>=1.43.2
Requires-Dist: pyarrow>=25.0.0
Requires-Dist: rich>=15.0.0
Requires-Dist: scipy>=1.18.0
Requires-Dist: statsmodels>=0.14.6
Description-Content-Type: text/markdown

# qte — Quantile Treatment Effects in Python

> **Alpha software:** the API may change without notice between releases.

This is a Python implementation of some of the estimators in the `qte` R package by Brantly Callaway
([link](https://github.com/bcallaway11/qte)). See the
[project website](https://mohelm.github.io/py-qte/) for the API reference and benchmarks.

The main **features** are:

- **Cross-sectional quantile treatment effects** estimators (unadjusted, inverse probability
  weighted, outcome regression, doubly robust) and a **nonlinear difference-in-differences**
  estimator (changes-in-changes and quantile difference-in-differences).
- **Fast**: `py-qte` uses more efficient algorithms and parallelizes the bootstrap standard errors
  effectively. On larger datasets it is more than 20× faster than `qte` for the AIPW estimator of
  the quantile treatment effect (see the
  [benchmark timings](https://mohelm.github.io/py-qte/benchmark.html#tbl-aipw-timings)).
- **Beautiful**: Graphs and tables for the console, the web, and LaTeX powered by
  [Altair](https://github.com/vega/altair),
  [Great Tables](https://github.com/posit-dev/great-tables) and
  [Rich](https://github.com/textualize/rich).

---

# Installation

Requires Python 3.12 or newer.

```bash
uv add py-qte # or pip install py-qte
```

On Linux and macOS the Fortran solver for quantile regression should work and be used in the
computations. On Windows a fallback (based on the `statsmodels` library) will be used.

---

# Examples

## Cross-Sectional Data

We can estimate quantile treatment (and average) treatment effects using an augmented inverse
probability weighting (AIPW) estimator.

```python
from qte.cross_sectional import estimate_aipw_effects
from qte.datasets import load_lalonde

ds = load_lalonde()

res = estimate_aipw_effects(
    ds=ds,
    outcome="re78",
    treatment="treat",
    outcome_regression_formula="age + education",
    propensity_score_formula="age + education",
)

res.plot()  # Vega-Altair plot (see below)
res.tabulate()  # Great Tables output (see below)
```

<table width="100%" border="0" cellpadding="0" cellspacing="0">
  <tr>
    <td width="48%" valign="top" align="center">
      <img src="https://raw.githubusercontent.com/mohelm/py-qte/main/assets/aipw_qte_results.svg" width="100%">
    </td>
    <td width="4%"></td>
    <td width="48%" valign="top" align="center">
      <img src="https://raw.githubusercontent.com/mohelm/py-qte/main/assets/aipw_qte_table.png" width="100%">
    </td>
  </tr>
</table>

## Nonlinear Difference-in-Differences

We can estimate quantile treatment (and average) treatment effects with the changes-in-changes
estimator.

```python
from qte.nonlinear_did import (
    CounterfactualModel,
    TrtGroupConfig,
    estimate_nonlinear_did_for_panel,
)
from qte.datasets import load_mpdta

ds = load_mpdta()
res = estimate_nonlinear_did_for_panel(
    ds,
    "lemp",
    TrtGroupConfig("first.treat", 0),  # never-treated group is 0
    "year",
    "countyreal",
    qs=[0.25, 0.5, 0.75],
    counterfactual_model=CounterfactualModel.CIC,
)
```

<table width="100%" border="0" cellpadding="0" cellspacing="0">
  <tr>
    <td width="48%" valign="top" align="center">
      <img src="https://raw.githubusercontent.com/mohelm/py-qte/main/assets/nonlinear_did_results.svg" width="100%">
    </td>
    <td width="4%"></td>
    <td width="48%" valign="top" align="center">
      <img src="https://raw.githubusercontent.com/mohelm/py-qte/main/assets/nonlinear_did_table.png" width="100%">
    </td>
  </tr>
</table>

---

# Development

Development is somewhat complicated due to the inclusion of the Fortran code for solving quantile
regression. A working way to set up the project for development is:

```sh
git clone git@github.com:mohelm/py-qte.git
cd py-qte
uv sync --all-groups --no-install-project && uv sync --all-groups
```

## Website

See [`docs/README.md`](https://github.com/mohelm/py-qte/blob/main/docs/README.md) for how to build
and preview the Quarto website and regenerate the API reference.

## Regenerating the README assets

Regenerate the figures above after changing the estimators or their presentation:

```sh
uv run python -m docs.readme
```

`README_PYPI.md` (what `project.readme` points at) is generated from this file with relative links
made absolute, since PyPI can't resolve repo-relative assets. Regenerate it after editing this file:

```sh
uv run python -m docs.readme --pypi-readme-only
```

## Releasing

See [`RELEASING.md`](https://github.com/mohelm/py-qte/blob/main/RELEASING.md) for how to cut a
release.
