Skip to main content

finite-selection

PyPI CI Docs

finite-selection assigns units to treatment groups at random while keeping the groups alike on their covariates. It implements the Finite Selection Model (FSM) that Carl Morris built for the RAND Health Insurance Experiment, in Python, with allocation results checked against the R package FSM. It works with NumPy arrays and pandas data frames and includes balance diagnostics and randomization tests. The contribution is a tested Python implementation, documented corrections, and reproducible examples; the method is due to the authors cited below.

How it works

The groups take turns choosing units, like captains picking teams. A random draw fixes the order of turns, under a rule that never lets one group get far ahead of its share. On its turn a group takes the remaining unit that most improves its own design: by default, the unit that most increases the determinant of its X'X matrix (D-optimality). Every group chases the same goal, so the groups come out balanced. The turn order is random, so randomization-based inference still applies.

Installation

Requires Python 3.12 or newer.

pip install finite-selection
pip install "finite-selection[data,plot]"   # example data and love plots

Example

This splits the 445 men of the National Supported Work data into groups of 222 and 223, once with the FSM and once by complete randomization. The table reports TASMD for the first group: the distance between its covariate means and the full-sample means, in standard deviations.

import numpy as np
import finite_selection as fs

x = fs.lalonde()
rng = np.random.default_rng(2026)

order = fs.som([222, 223], method="scomars", rng=rng)  # who chooses when
fsm_z = fs.fsm(x, order, rng=rng).assignment  # who goes where
crd_z = fs.crd([222, 223], rng=rng)  # complete randomization

print(fs.tasmd_rand(x, {"CRD": crd_z, "FSM": fsm_z}).round(3))
             CRD    FSM
Age        0.066  0.002
Education  0.004  0.004
Black      0.023  0.011
Hispanic   0.055  0.007
Married    0.043  0.007
Nodegree   0.018  0.004
Re74       0.016  0.006
Re75       0.006  0.002

The FSM group sits within 0.011 standard deviations of the full sample on every covariate. The randomized group is off by up to 0.066, on age. That is one draw of each. Over 200 draws, the average TASMD per covariate is 0.034 to 0.041 under complete randomization and 0.004 to 0.008 under the FSM. tasmd_rand reports these averages when given a matrix of assignments.

The package also allocates units that arrive in batches (fsm_batch), offers ten other selection functions, and covers the analysis side: Fisher randomization tests (perm_test), effective sample sizes for comparing designs (ess_rand, ess_model), squares and interactions of the covariates (make_sq_inter), and love plots (love_plot). The user guide runs a full experiment with them.

What it assumes

The FSM needs every unit and its covariates before assignment starts, so it suits experiments that enroll a known list, not ones that recruit as they go. It balances the columns you give it. Balance on squares or interactions requires passing them in, through make_sq_inter for example. Against outcome components it cannot see, it can increase variance relative to complete randomization. Covariate balance alone does not guarantee more precise estimates for every outcome. The JRSS-A discussion examines this robustness concern. Run time grows with the square of the sample: about 0.1 seconds for 445 units and 7 seconds for 5,000.

Agreement with R

The script tests/fixtures/make_r_fixtures.R runs R's exported functions on a grid of cases and saves their inputs and outputs. The test suite checks the Python functions against those records:

  • Given the same turn order, fsm reproduces R's allocation and selection sequence in all 67 cases, which span the 11 selection functions, two to four groups, and the options (intercept, scaling, ridge size, Q_initial, collinear data). fsm_batch does the same in 3 cases.
  • Random draws (som, crd) match R in distribution over 10,000 draws. R and numpy use different random number generators, so individual draws differ.
  • In several places R 1.0.0 departs from its own documentation, and Python follows the documentation. For example, R's ess_rand reads only the first N assignments, and its perm_test ignores a nonzero null effect. Fixes are proposed upstream, and Behaviour and parity with R lists each departure with its test.

perm_test imputes the two-group sharp null for every supported contrast, including when tau=0. Sampled reference assignments use the Monte Carlo correction (b + 1) / (B + 1); exact=True is for a complete, equally weighted reference distribution. Rank tests and tests with more than two groups support only the sharp no-effect null.

Credits

Carl N. Morris introduced the FSM (1979, Journal of Econometrics 11, 43-61). Ambarish Chattopadhyay, Carl N. Morris and José R. Zubizarreta recast it in the potential-outcomes framework and wrote the R package FSM, described in "Randomized and balanced allocation of units into treatment groups using the finite selection model for R" (arXiv:2105.02393) and "Balanced and robust randomized treatment assignments: the finite selection model for the Health Insurance Experiment and beyond" (JRSS-A 189(4), 2026; arXiv:2205.09736). This package is an independent implementation checked against theirs. The bundled data is Dehejia and Wahba's subset of the National Supported Work demonstration (LaLonde 1986), from NBER.

Cite the papers when you use the method, and this package (CITATION.cff) when you use the software.

Metadata

Release files for finite-selection 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for finite-selection 0.1.0
File Size Uploaded
finite_selection-0.1.0.tar.gz 24.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for finite-selection 0.1.0
File Interpreter ABI Platform
finite_selection-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 49.6 kB

Release files / finite_selection-0.1.0.tar.gz

Download URL finite_selection-0.1.0.tar.gz
Size 24.2 kB
Tags Source
SHA-256 checksum
How to use checksums
d348b97b00b3266b1ed583ad436d77f47557fd62ac8a06c55df3632f65e12bcf
BLAKE2b-256 checksum
How to use checksums
2a6d1ad71b3f3eb788313b39965d2ead957507c91569bde56ea96e79a3ee5287
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release files / finite_selection-0.1.0-py3-none-any.whl

Download URL finite_selection-0.1.0-py3-none-any.whl
Size 25.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1adbc52c9bf9e997a89c616fd2ed298663048a016daf9163702ec5e0be941077
BLAKE2b-256 checksum
How to use checksums
4e5cb2df55ac1813c7b29626296a3c182f2f0a224b558da7c5e12aad1d75c72a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page