Repository navigation
Release v0.6.0: R MatchIt Parity, Option Warnings, and Balanced CBPS
What's New in v0.6.0
This release aligns pymatchit with R MatchIt (checked against version 4.8.1) and fixes several cases where options were silently ignored. Results change for some methods; see "Changed results" below before upgrading an existing analysis.
New
- Genetic matching supports
exact,antiexact,mahvarsandm_order. - Full matching supports
antiexactand covariate-specific calipers (caliper={"age": 2}). - Cardinality matching supports
exact(each stratum is solved separately),ratioandmahvars:ratio=kselects the largest balanced sample with k controls per treated unit. Leavingratiounset keeps profile matching, where the whole treated group is retained.mahvarspairs the selected units, andmatches()returns the pairs.
- GLM links
cloglogandcauchit, pluslinear.probit.linearis accepted as an alias forlinear.logit. - Optimal matching supports
antiexactandmahvars. estimand="ATC"is implemented for all methods. For nearest, optimal and genetic matching the control group becomes the focal group, andmatches()is keyed by control unit.
Unused options now warn
An option the chosen method cannot use (for example caliper with method="subclass") is ignored with a warning that names the option, as in R. Before, most were ignored silently. This lets you switch method without rewriting the call. To turn these warnings into errors, use warnings.simplefilter("error").
Contradictory requests raise an error: estimand="ATE" with nearest, optimal or genetic matching; an unknown link; m_order="largest" without a propensity score; mahvars with cardinality matching but no ratio.
Changed results
link:logitandprobitnow match on the predicted probability, as in R. Uselink="linear.logit"for the previous behaviour (matching on the linear predictor). Calipers are in standard deviations of this measure, so their width changes too.- User-supplied distances (
distance=an array) are used as-is; they are no longer logit-transformed. - Nearest matching with
ratio > 1assigns matches in rounds: every unit gets a first match before any gets a second. Control weights are 1/k per match, where k is the number of matches the treated unit actually received. - Calipers with
exact=use the full-sample standard deviation, not each stratum's. - Matching order:
m_orderdefaults tolargestwhen a propensity score is available (smallestforATC) and to row order otherwise.mahvarsmatching is ordered by the propensity score. - Genetic matching uses a weighted distance on standardized variables, including the propensity score, and optimizes the matching it actually returns.
- CBPS is the just-identified estimator, which balances the covariates exactly, and follows
estimand. - Cardinality matching is solved exactly as a mixed-integer program.
std_tolsuses the same standardization assummary(). - Full matching seeds subclasses with an optimal 1:1 assignment and enforces calipers and
min/max_controls_per_subclass. - Subclassification bins on the focal group's scores (treated for ATT, control for ATC, everyone for ATE).
- CEM bins numeric covariates with Sturges' rule by default instead of 5 bins.
- KS statistics for the matched sample use the matching weights.
Fixed
- Optimal matching crashed when a caliper excluded pairs.
- Genetic matching with a caliper crashed on non-default indexes and dropped most treated units when matching without replacement.
m_order="random"reseeded NumPy's global random state.matches()returned missing values for string-labelled indexes.
Signature
ratiodefaults toNone(1:1 for pair matching; profile matching for cardinality). It was1.m_orderdefaults toNone. It was"largest".
Development
- Tests run on Python 3.9–3.14 and on the oldest and newest supported pandas. The code is formatted with black.
Thanks to Nick Eubank (@nickeubank) for the bug review and the pull requests behind most of this release, and to @codeteme for the report on control weights.