Repository navigation
This release deprecates positional treatment and y ahead of the v1.0 switch to fit(X, y, treatment, ...), makes causal trees and forests estimate leaves honestly by default, and moves the uplift trees and forests onto the shared Cython tree kernel, with native missing-value support. It also adds benchmark dataset loaders with ground-truth metrics, new CATE evaluation scores, model save() / load(), and a rebuilt documentation site with an end-to-end tutorial, an estimator guide and an FAQ.
The full notes, with measurements, are in the changelog.
⚠️ Breaking Changes
BaseSLearner.estimate_atealways returns(ate, lb, ub)and no longer acceptsreturn_ci.ate = learner.estimate_ate(...)now binds a tuple, and passingreturn_ciraisesTypeError; unpack instead:ate, lb, ub = learner.estimate_ate(...). By @su-jin1425 in #1031
Deprecations
- Positional
treatmentandyemit aFutureWarning(#854). In v1.0 the positional order becomesfit(X, y, treatment, ...), the scikit-learn convention. Pass both by keyword —learner.fit(X=X, treatment=treatment, y=y)— which is correct before and after the flip. A call left positional will silently train on swapped arguments at v1.0 rather than raise. See the migration guide. By @jeongyoonlee in #975
Behavior Changes
These change fitted models or estimates without any edit to your code.
CausalTreeRegressorandCausalRandomForestRegressordefault tohonesty=True: the tree structure is grown on one half of the sample and leaf values are re-estimated on the other (Athey & Imbens 2016). Passhonesty=Falsefor the previous behavior. By @jeongyoonlee in #1001- The default propensity models produce different scores: log-loss model selection over a wider
Cgrid for the logistic models,max_depth=3(was 8) forGradientBoostedPropensityModel, and a seeded, stratified early-stopping split. By @arpitjain099 in #944, @su-jin1425 in #1033 and @ismailvc1111 in #1051 UpliftTreeClassifierandUpliftRandomForestClassifierrun on the shared tree kernel. Names, arguments and output shapes are kept;X_val/treatment_val/y_valandearly_stopping_eval_diff_scaleare ignored with aUserWarning(useprune_fractioninstead), andDecisionTreeis deprecated. By @jeongyoonlee in #973UpliftRandomForestClassifierdefaults ton_jobs=None(was-1), because peak memory grew with the core count. Predictions are unchanged; passn_jobs=-1to restore. By @jeongyoonlee in #992causalml.features.load_datareturnsnumpy.ndarrayinstead ofnumpy.matrix, and no longer raises when the one-hot encoder produces no columns. By @arpitjain099 in #978 and #979
New Features
- Benchmark dataset loaders (
fetch_lalonde,fetch_ihdp,fetch_twins), ground-truth metrics (pehe,ate_error,policy_risk) and a reproducible leaderboard notebook by @jeongyoonlee in #1015 ccp_alpha="cv"on the causal tree: cost-complexity pruning with the tree size chosen by cross-validation by @jeongyoonlee in #1001pretrain=TrueonCausalTreeRegressor.estimate_ateandBaseDRIVLearner.estimate_ateby @jeongyoonlee in #1024prune_fractiononUpliftTreeClassifierfor validation-based pruning insidefitby @jeongyoonlee in #1004- Add a model serialization API (
save()/load()/load_learner) with version metadata to the meta-learners by @genrichez in #929 - Extend serialization to the causal and uplift trees and forests,
BaseDRIVLearnerandIVRegressorby @genrichez in #932 - Add
dr_score()andplug_in_t_score()for evaluating CATE models without ground truth by @aman-coder03 in #930 - Add
rlearner_score()(R-loss) for CATE model evaluation, matching EconML'sRScorerby @aman-coder03 in #935 - Add bootstrap confidence intervals to
auuc_score()andqini_score()by @ipezygj in #994 - Add
SensitivityMSM: ATE bounds under the Marginal Sensitivity Model by @aman-coder03 in #925 - Improve
SensitivityMSMrobustness and test coverage by @aman-coder03 in #933 - Add
return_componentsto the R-learner'spredict()andfit_predict()by @aman-coder03 in #923 - Add
XGBTClassifierandXGBRClassifiermeta-learners by @jeongyoonlee in #942 - Add a JAX/flax.nnx backend for CEVAE by @xrhd in #957
- Expose matched index pairs as
NearestNeighborMatch.matched_indexes_by @jeongyoonlee in #940 - Add node p-value display to
plot_causal_treeby @genrichez in #976
Tree Unification (#945)
- Kernel-backed uplift criteria (KL/ED/Chi) with legacy parity by @jeongyoonlee in #959
- Add uplift split regularization (
n_reg/min_samples_treatment) to the kernel tree by @jeongyoonlee in #961 - Kernel uplift normalization + CTS and two-class criteria DDP/IT/CIT by @jeongyoonlee in #965
- Add the honest approach and the IDDP criterion to the kernel uplift tree by @jeongyoonlee in #964
- Add validation-based pruning to the kernel uplift tree by @jeongyoonlee in #966
- Add a kernel-backed uplift random forest by @jeongyoonlee in #967
- Make
plot.pywork with the kernel uplift tree by @jeongyoonlee in #968 - Serialization and
BaseEstimatorconformance for the kernel uplift classes by @jeongyoonlee in #971 - Add a kernel-vs-legacy uplift tree parity notebook by @jeongyoonlee in #969
- Native missing-value (NaN) support for the kernel uplift and causal trees by @jeongyoonlee in #972
- Share the tree kernel: hoist the group criterion base and unify the builders by @jeongyoonlee in #974
- Switch the public uplift trees to the kernel backend and delete
uplift.pyxby @jeongyoonlee in #973
Bug Fixes
- Fix
CausalTreeRegressor.estimate_ateunderstating the standard error: nominal 95% intervals covered the true ATE 0% of the time, now 88% by @jeongyoonlee in #1007 - Fix
UpliftTreeClassifier.pruneleaving per-node group counts stale by @jeongyoonlee in #1004 - Fix
uplift_tree_plotfailing with pyparsing 3.3.3 by replacingpydotpluswithpydotby @jeongyoonlee in #1053 - Report an actionable error on macOS without the OpenMP runtime by @su-jin1425 in #1005
- Fix
LRSRegressor.estimate_ateraisingKeyErroron DataFrame input by @su-jin1425 in #1031 - Thread
random_statetoBaseRLearnerbootstraps by @su-jin1425 in #1032 - Accept
RandomStateinstances as the meta-learners'random_stateby @su-jin1425 in #1040 - Supply a default LightGBM outcome learner in the public
cate_scoringfunctions by @su-jin1425 in #1030 - Give
rlearner_scorea default outcome learner, and raiseValueErrorinstead of asserting in the CATE scoring functions by @su-jin1425 in #1039 - Seed and stratify
GradientBoostedPropensityModel's early-stopping validation split by @ismailvc1111 in #1051 - Use a custom
propensity_learneron the R-learner's first fit by @arpitjain099 in #937 - Raise in
mapewhen every target is near zero, and definesmape's 0/0 term as 0 by @arpitjain099 in #1050 - Stop
loglossfrom clipping the caller's prediction array in place by @arpitjain099 in #943 - Fix NaN scores in
FilterSelect's KL filter when a bin has no treated converters by @arpitjain099 in #999 - Take the exact KL limits at
pk = 0andpk = 1instead of clamping by @arpitjain099 in #1000 - Validate a binary outcome in
filter_LR/filter_Dby @jeongyoonlee in #941 - Fix the
ATEcolumn filled with NaN inSensitivitySelectionBias.summaryby @arpitjain099 in #958 - Fix a
NearestNeighborMatchcrash when the control pool runs belowratioby @arpitjain099 in #934 - Preserve the decorated function's name, docstring and signature in
timeitby @jeongyoonlee in #987
Documentation
- Switch the docs theme to pydata-sphinx-theme by @jeongyoonlee in #1014
- Fix broken references and drop internal files from
docs/by @jeongyoonlee in #1016 - Correctness pass over the published pages, and a five-section structure by @jeongyoonlee in #1018
- Take the docs build to zero warnings and fail on new ones by @jeongyoonlee in #1020
- Document honest estimation and pruning in the methodology by @jeongyoonlee in #1021
- Group the example notebooks by topic by @jeongyoonlee in #1022
- Order the validation page as an evaluation workflow by @jeongyoonlee in #1023
- Add the IHDP tutorial, choosing-an-estimator guide, FAQ and uncertainty catalog by @jeongyoonlee in #1025
- Document DragonNet and CEVAE in the methodology by @jeongyoonlee in #998
- Add CatBoost documentation and test coverage for the Explainer by @aman-coder03 in #924
- Add the
fit()argument-order migration guide by @jeongyoonlee in #990 - Publish the release schedule and the #854 deprecation window by @jeongyoonlee in #993
- Record the
load_datareturn-type change in the changelog by @jeongyoonlee in #996
Build / CI
- Run the optional-backend tests on pull requests by @mohsinm-dev in #977
- Fail the suite on causalml's own arg-order
FutureWarningby @jeongyoonlee in #997 - Stop the #854 shim warning on causalml's own internal
fitcalls by @jeongyoonlee in #988 - Migrate tests and docs to keyword
fit/predictcalls by @jeongyoonlee in #989 - Filter caught warnings by category in the serialization tests by @jeongyoonlee in #1002
- Release v0.18.0 by @jeongyoonlee in #1056
New Contributors
- @genrichez made their first contribution in #929
- @ipezygj made their first contribution in #994
- @su-jin1425 made their first contribution in #1005
- @ismailvc1111 made their first contribution in #1051
Full Changelog: v0.17.0...v0.18.0