formative-ds 2.2.4__tar.gz → 2.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {formative_ds-2.2.4 → formative_ds-2.3.0}/.github/workflows/ci.yml +1 -1
- {formative_ds-2.2.4 → formative_ds-2.3.0}/CLAUDE.md +3 -3
- {formative_ds-2.2.4 → formative_ds-2.3.0}/Makefile +3 -3
- {formative_ds-2.2.4 → formative_ds-2.3.0}/PKG-INFO +1 -1
- {formative_ds-2.2.4 → formative_ds-2.3.0}/docs/design/policy_learning.md +3 -4
- {formative_ds-2.2.4 → formative_ds-2.3.0}/docs/index.rst +0 -1
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/estimators/_base.py +32 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/estimators/_cate.py +2 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/estimators/did.py +2 -1
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/estimators/iv.py +3 -9
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/estimators/matching.py +4 -20
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/estimators/ols.py +4 -21
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/estimators/policy.py +5 -29
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/estimators/rct.py +2 -1
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/estimators/rdd.py +7 -1
- {formative_ds-2.2.4 → formative_ds-2.3.0}/pyproject.toml +2 -3
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/documentation_options.js +1 -1
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/causal/benchmarks.html +2 -2
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/causal/dag.html +2 -2
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/causal/decisions.html +2 -2
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/causal/estimands.html +2 -2
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/causal/estimators.html +2 -2
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/causal/introduction.html +2 -2
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/causal/motivation.html +2 -2
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/causal/refutations.html +2 -2
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/causal/wizard.html +2 -2
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/game/decision_rules.html +2 -2
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/game/introduction.html +2 -2
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/game/single_player.html +2 -2
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/genindex.html +2 -2
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/index.html +2 -2
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/search.html +2 -2
- formative_ds-2.3.0/tests/test_missing_values.py +86 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/tests/test_policy.py +2 -1
- {formative_ds-2.2.4 → formative_ds-2.3.0}/tests/test_rdd_refutation.py +26 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/uv.lock +98 -1722
- formative_ds-2.2.4/docs/causal/benchmarks.rst +0 -431
- formative_ds-2.2.4/notebooks/card_krueger_benchmark.ipynb +0 -452
- formative_ds-2.2.4/notebooks/lalonde_benchmark.ipynb +0 -538
- {formative_ds-2.2.4 → formative_ds-2.3.0}/.gitattributes +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/.github/workflows/publish.yml +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/.gitignore +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/LICENSE +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/README.md +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/TODO.md +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/docs/_static/version_switcher.css +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/docs/_static/version_switcher.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/docs/causal/dag.rst +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/docs/causal/decisions.rst +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/docs/causal/estimands.rst +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/docs/causal/estimators.rst +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/docs/causal/introduction.rst +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/docs/causal/motivation.rst +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/docs/causal/refutations.rst +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/docs/causal/wizard.rst +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/docs/conf.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/docs/game/decision_rules.rst +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/docs/game/introduction.rst +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/docs/game/single_player.rst +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/examples/decision/01_decision_basic.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/examples/did/01_did_basic.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/examples/iv/01_iv_basic.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/examples/iv/02_iv_vs_ols_bias.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/examples/iv/03_iv_with_observed_confounder.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/examples/iv/04_iv_refutation.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/examples/matching/01_basic_matching.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/examples/matching/02_matching_vs_naive.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/examples/matching/03_matching_refutation.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/examples/ols/01_ols_basic.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/examples/ols/02_ols_unobserved_confounder.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/examples/ols/03_ols_multiple_confounders.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/examples/rct/01_rct_basic.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/examples/rdd/01_rdd_basic.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/examples/rdd/02_rdd_positive_running_var.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/__init__.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/__init__.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/_assumptions.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/_exceptions.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/_explain.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/dag.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/decision.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/estimators/__init__.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/refutations/__init__.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/refutations/_check.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/refutations/cate.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/refutations/did.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/refutations/iv.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/refutations/matching.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/refutations/ols.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/refutations/policy.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/refutations/rct.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/causal/refutations/rdd.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/game/__init__.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/game/expected_value.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/game/hurwicz.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/game/laplace.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/game/maximax.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/game/maximin.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/formative/game/minimax.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/scripts/snapshot_docs.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_sources/causal/benchmarks.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_sources/causal/dag.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_sources/causal/decisions.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_sources/causal/estimands.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_sources/causal/estimators.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_sources/causal/introduction.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_sources/causal/motivation.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_sources/causal/refutations.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_sources/causal/wizard.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_sources/game/decision_rules.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_sources/game/introduction.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_sources/game/single_player.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_sources/index.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/_sphinx_javascript_frameworks_compat.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/base-stemmer.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/basic.css +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/check-solid.svg +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/clipboard.min.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/copy-button.svg +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/copybutton.css +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/copybutton.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/copybutton_funcs.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/css/badge_only.css +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/css/fonts/Roboto-Slab-Bold.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/css/fonts/Roboto-Slab-Bold.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/css/fonts/Roboto-Slab-Regular.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/css/fonts/Roboto-Slab-Regular.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/css/fonts/fontawesome-webfont.eot +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/css/fonts/fontawesome-webfont.svg +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/css/fonts/fontawesome-webfont.ttf +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/css/fonts/fontawesome-webfont.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/css/fonts/fontawesome-webfont.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/css/fonts/lato-bold-italic.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/css/fonts/lato-bold-italic.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/css/fonts/lato-bold.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/css/fonts/lato-bold.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/css/fonts/lato-normal-italic.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/css/fonts/lato-normal-italic.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/css/fonts/lato-normal.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/css/fonts/lato-normal.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/css/theme.css +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/doctools.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/documentation_options.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/english-stemmer.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/file.png +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/Lato/lato-bold.eot +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/Lato/lato-bold.ttf +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/Lato/lato-bold.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/Lato/lato-bold.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/Lato/lato-bolditalic.eot +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/Lato/lato-bolditalic.ttf +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/Lato/lato-bolditalic.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/Lato/lato-bolditalic.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/Lato/lato-italic.eot +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/Lato/lato-italic.ttf +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/Lato/lato-italic.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/Lato/lato-italic.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/Lato/lato-regular.eot +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/Lato/lato-regular.ttf +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/Lato/lato-regular.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/Lato/lato-regular.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/jquery.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/js/badge_only.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/js/theme.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/js/versions.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/language_data.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/minus.png +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/plus.png +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/pygments.css +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/searchtools.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/sphinx_highlight.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/version_switcher.css +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/_static/version_switcher.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/causal/benchmarks.html +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/causal/dag.html +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/causal/decisions.html +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/causal/estimands.html +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/causal/estimators.html +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/causal/introduction.html +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/causal/motivation.html +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/causal/refutations.html +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/causal/wizard.html +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/game/decision_rules.html +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/game/introduction.html +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/game/single_player.html +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/genindex.html +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/index.html +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/objects.inv +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/search.html +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.1/searchindex.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_sources/causal/benchmarks.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_sources/causal/dag.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_sources/causal/decisions.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_sources/causal/estimands.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_sources/causal/estimators.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_sources/causal/introduction.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_sources/causal/motivation.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_sources/causal/refutations.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_sources/causal/wizard.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_sources/game/decision_rules.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_sources/game/introduction.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_sources/game/single_player.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_sources/index.rst.txt +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/_sphinx_javascript_frameworks_compat.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/base-stemmer.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/basic.css +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/check-solid.svg +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/clipboard.min.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/copy-button.svg +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/copybutton.css +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/copybutton.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/copybutton_funcs.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/css/badge_only.css +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/css/fonts/Roboto-Slab-Bold.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/css/fonts/Roboto-Slab-Bold.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/css/fonts/Roboto-Slab-Regular.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/css/fonts/Roboto-Slab-Regular.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/css/fonts/fontawesome-webfont.eot +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/css/fonts/fontawesome-webfont.svg +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/css/fonts/fontawesome-webfont.ttf +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/css/fonts/fontawesome-webfont.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/css/fonts/fontawesome-webfont.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/css/fonts/lato-bold-italic.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/css/fonts/lato-bold-italic.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/css/fonts/lato-bold.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/css/fonts/lato-bold.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/css/fonts/lato-normal-italic.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/css/fonts/lato-normal-italic.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/css/fonts/lato-normal.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/css/fonts/lato-normal.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/css/theme.css +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/doctools.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/english-stemmer.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/file.png +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/Lato/lato-bold.eot +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/Lato/lato-bold.ttf +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/Lato/lato-bold.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/Lato/lato-bold.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/Lato/lato-bolditalic.eot +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/Lato/lato-bolditalic.ttf +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/Lato/lato-bolditalic.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/Lato/lato-bolditalic.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/Lato/lato-italic.eot +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/Lato/lato-italic.ttf +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/Lato/lato-italic.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/Lato/lato-italic.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/Lato/lato-regular.eot +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/Lato/lato-regular.ttf +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/Lato/lato-regular.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/Lato/lato-regular.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/jquery.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/js/badge_only.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/js/theme.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/js/versions.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/language_data.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/minus.png +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/plus.png +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/pygments.css +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/searchtools.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/sphinx_highlight.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/version_switcher.css +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/_static/version_switcher.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/objects.inv +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/2.2/searchindex.js +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/site/versions.json +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/tests/test_cate.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/tests/test_cate_refutation.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/tests/test_dag.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/tests/test_decision.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/tests/test_did.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/tests/test_did_refutation.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/tests/test_game.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/tests/test_iv.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/tests/test_iv_refutation.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/tests/test_matching.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/tests/test_matching_refutation.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/tests/test_ols.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/tests/test_ols_refutation.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/tests/test_policy_refutation.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/tests/test_rct.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/tests/test_rct_refutation.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/tests/test_rdd.py +0 -0
- {formative_ds-2.2.4 → formative_ds-2.3.0}/vercel.json +0 -0
|
@@ -16,7 +16,7 @@ jobs:
|
|
|
16
16
|
run: uv sync --dev --group docs
|
|
17
17
|
|
|
18
18
|
- name: Lint
|
|
19
|
-
run: uv run ruff check
|
|
19
|
+
run: uv run ruff check . && uv run ruff format --check --exclude notebooks .
|
|
20
20
|
|
|
21
21
|
- name: Run tests
|
|
22
22
|
run: uv run pytest --cov=formative --cov-report=term-missing --cov-fail-under=80
|
|
@@ -9,7 +9,7 @@ uv sync --dev # install dependencies
|
|
|
9
9
|
uv run pytest # run all tests
|
|
10
10
|
uv run pytest tests/test_iv.py # run one file
|
|
11
11
|
uv run pytest tests/test_iv.py::TestIV2SLSEstimation::test_iv_recovers_true_effect # run one test
|
|
12
|
-
make lint # ruff check
|
|
12
|
+
make lint # ruff check
|
|
13
13
|
make fmt # ruff format
|
|
14
14
|
make check # lint + format check + tests with coverage (CI requires ≥80%)
|
|
15
15
|
make build-docs # sphinx with -W: warnings are errors in CI
|
|
@@ -66,7 +66,7 @@ Do not change `_RCC_SEED` or `_PLACEBO_SEED` to 42 — the generated noise colli
|
|
|
66
66
|
|
|
67
67
|
**Heterogeneous effects (CATE)** — `OLSObservational` and `RCT` accept `effect_modifier=` (a discrete, pre-treatment column). `fit()` then returns `OLSCATEResult`/`RCTCATEResult` with `effect_by_group`, a homogeneity F-test, and `decide_by_group()`. The headline `effect` is the sample-share-weighted average of group effects (the raw treatment coefficient under interaction coding is only the reference group's effect). Shared machinery lives in `estimators/_cate.py`; DAG validation rejects modifiers that are descendants of the treatment (mediators) or not ancestors of the outcome.
|
|
68
68
|
|
|
69
|
-
**Policy learning** — `RCTResult.learn_policy(df, modifiers=[...], cost=, benefit=, max_depth=1|2)` (design note: `docs/design/policy_learning.md`) does Athey–Wager doubly robust policy learning: cross-fitted AIPW scores, exhaustive shallow-tree search over discrete features, honest (out-of-fold) value reported as the advantage over the best constant policy. Returns `PolicyResult` (`rules`, `value`, `assign()`, `refute()`). Refutation checks test the honest *value*, not tree structure — in-sample search happily splits on noise within its depth budget, so structural checks would be flaky.
|
|
69
|
+
**Policy learning** — `RCTResult.learn_policy(df, modifiers=[...], cost=, benefit=, max_depth=1|2)` (design note: `docs/design/policy_learning.md`) does Athey–Wager doubly robust policy learning: cross-fitted AIPW scores, exhaustive shallow-tree search over discrete features, honest (out-of-fold) value reported as the advantage over the best constant policy. Returns `PolicyResult` (`rules`, `value`, `assign()`, `refute()`). Refutation checks test the honest *value*, not tree structure — in-sample search happily splits on noise within its depth budget, so structural checks would be flaky. The depth-2 search starts from the best depth-1 tree, so a deeper tree must strictly beat it — otherwise equal-value trees with redundant conditions can win on candidate order.
|
|
70
70
|
|
|
71
71
|
**Package layout:**
|
|
72
72
|
- `formative/causal/dag.py` — `DAG`, `_Node`
|
|
@@ -98,7 +98,7 @@ Do not change `_RCC_SEED` or `_PLACEBO_SEED` to 42 — the generated noise colli
|
|
|
98
98
|
|
|
99
99
|
**Bootstrap-heavy tests:** matching tests use `setup_class` (not `setup_method`) so `.fit()` runs once per class. Use N=1_000 — larger N widens bootstrap SE faster than NN noise shrinks, causing refutation checks to fail even on well-specified data.
|
|
100
100
|
|
|
101
|
-
**
|
|
101
|
+
**Examples:** runnable per-estimator example scripts live in `examples/`.
|
|
102
102
|
|
|
103
103
|
**Planned estimators:** the goal is to cover all methods in the causal inference decision tree at https://www.maxpagels.com/prototypes/causal-wizard. Remaining: **Synthetic Control**.
|
|
104
104
|
|
|
@@ -8,13 +8,13 @@ test:
|
|
|
8
8
|
uv run pytest --cov=formative --cov-report=term-missing --cov-fail-under=80
|
|
9
9
|
|
|
10
10
|
lint:
|
|
11
|
-
uv run ruff check
|
|
11
|
+
uv run ruff check .
|
|
12
12
|
|
|
13
13
|
fmt:
|
|
14
|
-
uv run ruff format
|
|
14
|
+
uv run ruff format .
|
|
15
15
|
|
|
16
16
|
check: lint
|
|
17
|
-
uv run ruff format --check
|
|
17
|
+
uv run ruff format --check .
|
|
18
18
|
uv run pytest --cov=formative --cov-report=term-missing --cov-fail-under=80
|
|
19
19
|
|
|
20
20
|
release: # usage: make release BUMP=patch|minor|major
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
**Status:** implemented (see `formative/causal/estimators/policy.py`); deviations from this
|
|
4
4
|
note: refutation checks test the honest value rather than tree structure (in-sample search
|
|
5
|
-
splits on noise within its depth budget, so structural checks are flaky), and
|
|
6
|
-
|
|
5
|
+
splits on noise within its depth budget, so structural checks are flaky), and a deeper tree
|
|
6
|
+
must strictly beat the best shallower one, so equal-value trees with redundant splits never win.
|
|
7
7
|
**Date:** 2026-07-11
|
|
8
8
|
|
|
9
9
|
## Motivation
|
|
@@ -115,8 +115,7 @@ print(policy.summary())
|
|
|
115
115
|
- Narrative rendering in `_explain.py`.
|
|
116
116
|
- Tests in `tests/test_policy.py` + `tests/test_policy_refutation.py`; cross-fitting
|
|
117
117
|
makes fitting expensive, so use `setup_class` like the matching tests.
|
|
118
|
-
- Docs page under `docs/causal/` with a worked example
|
|
119
|
-
once a public dataset with a known-good policy exists.
|
|
118
|
+
- Docs page under `docs/causal/` with a worked example.
|
|
120
119
|
|
|
121
120
|
## Open questions
|
|
122
121
|
|
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from .._assumptions import Assumption
|
|
4
|
+
from .._exceptions import IdentificationError
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _backdoor_confounders(dag, treatment: str, outcome: str) -> set[str]:
|
|
8
|
+
"""
|
|
9
|
+
Confounders under the backdoor criterion: common ancestors of treatment and
|
|
10
|
+
outcome that are not descendants of treatment (mediators or post-treatment
|
|
11
|
+
variables).
|
|
12
|
+
"""
|
|
13
|
+
return (dag.ancestors(treatment) & dag.ancestors(outcome)) - dag.descendants(treatment)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _missing_confounders_error(missing: set[str], treatment: str, outcome: str) -> IdentificationError:
|
|
17
|
+
"""``IdentificationError`` for DAG-declared confounders absent from the dataframe."""
|
|
18
|
+
return IdentificationError(
|
|
19
|
+
f"\nDAG confounders not found in dataframe: {sorted(missing)}\n\n"
|
|
20
|
+
f"Your DAG declares these variables as confounders of '{treatment}' and\n"
|
|
21
|
+
f"'{outcome}', but they are absent from the dataframe and cannot be\n"
|
|
22
|
+
f"controlled for. Note: there may also be confounders not modelled in your\n"
|
|
23
|
+
f"DAG at all — formative cannot detect those.\n\n"
|
|
24
|
+
f"Consider:\n"
|
|
25
|
+
f" - Collecting data on {sorted(missing)} and adding it to the dataframe\n"
|
|
26
|
+
f" - IV estimation if you have a valid instrument for '{treatment}'\n"
|
|
27
|
+
f" - DiD or RD if a natural experiment is available"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _reject_missing(data, columns, action: str = "fitting") -> None:
|
|
32
|
+
"""Raise if any used column has NaNs: statsmodels formulas drop those rows silently, our own code doesn't."""
|
|
33
|
+
with_nan = [c for c in dict.fromkeys(columns) if data[c].isna().any()]
|
|
34
|
+
if with_nan:
|
|
35
|
+
raise ValueError(f"Columns {with_nan} contain missing values — drop or impute them before {action}.")
|
|
4
36
|
|
|
5
37
|
|
|
6
38
|
class _BaseResult:
|
|
@@ -18,6 +18,7 @@ import statsmodels.formula.api as smf
|
|
|
18
18
|
|
|
19
19
|
from .._assumptions import Assumption
|
|
20
20
|
from ..dag import DAG
|
|
21
|
+
from ._base import _reject_missing
|
|
21
22
|
|
|
22
23
|
CATE_ASSUMPTIONS: list[Assumption] = [
|
|
23
24
|
Assumption("Correct specification of effect modification (linear interaction form)", testable=False),
|
|
@@ -86,6 +87,7 @@ def _validate_modifier_data(data: pd.DataFrame, treatment: str, modifier: str) -
|
|
|
86
87
|
"""Data checks on the effect modifier column. Raises ``ValueError`` on violation."""
|
|
87
88
|
if modifier not in data.columns:
|
|
88
89
|
raise ValueError(f"Effect modifier column '{modifier}' not found in dataframe.")
|
|
90
|
+
_reject_missing(data, [modifier])
|
|
89
91
|
levels = data[modifier].dropna().unique()
|
|
90
92
|
if len(levels) < 2:
|
|
91
93
|
raise ValueError(f"Effect modifier '{modifier}' must have at least 2 levels. Found: {list(levels)}")
|
|
@@ -5,7 +5,7 @@ import statsmodels.formula.api as smf
|
|
|
5
5
|
|
|
6
6
|
from .._assumptions import Assumption
|
|
7
7
|
from ..dag import DAG
|
|
8
|
-
from ._base import _StatsmodelsResult
|
|
8
|
+
from ._base import _reject_missing, _StatsmodelsResult
|
|
9
9
|
|
|
10
10
|
DID_ASSUMPTIONS: list[Assumption] = [
|
|
11
11
|
Assumption(
|
|
@@ -227,6 +227,7 @@ class DiD:
|
|
|
227
227
|
]:
|
|
228
228
|
if var not in data.columns:
|
|
229
229
|
raise ValueError(f"{label} column '{var}' not found in dataframe.")
|
|
230
|
+
_reject_missing(data, [self._group, self._time, self._outcome])
|
|
230
231
|
|
|
231
232
|
for label, var in [("Group", self._group), ("Time", self._time)]:
|
|
232
233
|
vals = set(data[var].dropna().unique())
|
|
@@ -7,7 +7,7 @@ from statsmodels.sandbox.regression.gmm import IV2SLS as _IV2SLS
|
|
|
7
7
|
|
|
8
8
|
from .._assumptions import Assumption
|
|
9
9
|
from ..dag import DAG
|
|
10
|
-
from ._base import _StatsmodelsResult
|
|
10
|
+
from ._base import _backdoor_confounders, _reject_missing, _StatsmodelsResult
|
|
11
11
|
|
|
12
12
|
IV_ASSUMPTIONS: list[Assumption] = [
|
|
13
13
|
Assumption("Relevance: the instrument strongly affects treatment", testable=True),
|
|
@@ -228,14 +228,7 @@ class IV2SLS:
|
|
|
228
228
|
Unobserved confounders are handled by the instrument and are not flagged
|
|
229
229
|
as errors — this is the primary use case for IV estimation.
|
|
230
230
|
"""
|
|
231
|
-
|
|
232
|
-
T, Y = self._treatment, self._outcome
|
|
233
|
-
|
|
234
|
-
treatment_ancestors = dag.ancestors(T)
|
|
235
|
-
outcome_ancestors = dag.ancestors(Y)
|
|
236
|
-
treatment_descendants = dag.descendants(T)
|
|
237
|
-
|
|
238
|
-
confounders = (treatment_ancestors & outcome_ancestors) - treatment_descendants
|
|
231
|
+
confounders = _backdoor_confounders(self._dag, self._treatment, self._outcome)
|
|
239
232
|
confounders.discard(self._instrument)
|
|
240
233
|
|
|
241
234
|
return {c for c in confounders if c in data_columns}
|
|
@@ -274,6 +267,7 @@ class IV2SLS:
|
|
|
274
267
|
controls = sorted(adjustment_set)
|
|
275
268
|
|
|
276
269
|
T, Y, Z = self._treatment, self._outcome, self._instrument
|
|
270
|
+
_reject_missing(data, [T, Y, Z, *controls])
|
|
277
271
|
|
|
278
272
|
# Build design matrices for 2SLS:
|
|
279
273
|
# exog: [const, T, controls] — includes endogenous treatment
|
|
@@ -6,9 +6,8 @@ import statsmodels.api as sm
|
|
|
6
6
|
import statsmodels.formula.api as smf
|
|
7
7
|
|
|
8
8
|
from .._assumptions import Assumption
|
|
9
|
-
from .._exceptions import IdentificationError
|
|
10
9
|
from ..dag import DAG
|
|
11
|
-
from ._base import _BaseResult
|
|
10
|
+
from ._base import _backdoor_confounders, _BaseResult, _missing_confounders_error, _reject_missing
|
|
12
11
|
|
|
13
12
|
MATCHING_ASSUMPTIONS: list[Assumption] = [
|
|
14
13
|
Assumption("Conditional independence: no unobserved confounders given matched variables", testable=False),
|
|
@@ -283,14 +282,7 @@ class PropensityScoreMatching:
|
|
|
283
282
|
raise ValueError("Treatment and outcome must be different variables.")
|
|
284
283
|
|
|
285
284
|
def _identify(self, data_columns: set[str]) -> tuple[set[str], set[str]]:
|
|
286
|
-
|
|
287
|
-
T, Y = self._treatment, self._outcome
|
|
288
|
-
|
|
289
|
-
treatment_ancestors = dag.ancestors(T)
|
|
290
|
-
outcome_ancestors = dag.ancestors(Y)
|
|
291
|
-
treatment_descendants = dag.descendants(T)
|
|
292
|
-
|
|
293
|
-
confounders = (treatment_ancestors & outcome_ancestors) - treatment_descendants
|
|
285
|
+
confounders = _backdoor_confounders(self._dag, self._treatment, self._outcome)
|
|
294
286
|
observed = {c for c in confounders if c in data_columns}
|
|
295
287
|
missing = {c for c in confounders if c not in data_columns}
|
|
296
288
|
return observed, missing
|
|
@@ -328,18 +320,10 @@ class PropensityScoreMatching:
|
|
|
328
320
|
adjustment_set, missing = self._identify(data_columns)
|
|
329
321
|
|
|
330
322
|
if missing:
|
|
331
|
-
raise
|
|
332
|
-
f"\nDAG confounders not found in dataframe: {sorted(missing)}\n\n"
|
|
333
|
-
f"Your DAG declares these variables as confounders of "
|
|
334
|
-
f"'{self._treatment}' and '{self._outcome}', but they are "
|
|
335
|
-
f"absent from the dataframe and cannot be controlled for.\n\n"
|
|
336
|
-
f"Consider:\n"
|
|
337
|
-
f" - Collecting data on {sorted(missing)} and adding it to the dataframe\n"
|
|
338
|
-
f" - IV estimation if you have a valid instrument for '{self._treatment}'\n"
|
|
339
|
-
f" - DiD or RD if a natural experiment is available"
|
|
340
|
-
)
|
|
323
|
+
raise _missing_confounders_error(missing, self._treatment, self._outcome)
|
|
341
324
|
|
|
342
325
|
T, Y = self._treatment, self._outcome
|
|
326
|
+
_reject_missing(data, [T, Y, *sorted(adjustment_set)])
|
|
343
327
|
|
|
344
328
|
# Unadjusted estimate: naive mean difference, no matching.
|
|
345
329
|
unadjusted = data.loc[data[T] == 1, Y].mean() - data.loc[data[T] == 0, Y].mean()
|
|
@@ -4,9 +4,8 @@ import pandas as pd
|
|
|
4
4
|
import statsmodels.formula.api as smf
|
|
5
5
|
|
|
6
6
|
from .._assumptions import Assumption
|
|
7
|
-
from .._exceptions import IdentificationError
|
|
8
7
|
from ..dag import DAG
|
|
9
|
-
from ._base import _StatsmodelsResult
|
|
8
|
+
from ._base import _backdoor_confounders, _missing_confounders_error, _reject_missing, _StatsmodelsResult
|
|
10
9
|
from ._cate import (
|
|
11
10
|
CATE_ASSUMPTIONS,
|
|
12
11
|
_CATEResultMixin,
|
|
@@ -282,14 +281,7 @@ class OLSObservational:
|
|
|
282
281
|
absent from the data. There may be additional unobserved confounders
|
|
283
282
|
not represented in the DAG at all.
|
|
284
283
|
"""
|
|
285
|
-
|
|
286
|
-
T, Y = self._treatment, self._outcome
|
|
287
|
-
|
|
288
|
-
treatment_ancestors = dag.ancestors(T)
|
|
289
|
-
outcome_ancestors = dag.ancestors(Y)
|
|
290
|
-
treatment_descendants = dag.descendants(T)
|
|
291
|
-
|
|
292
|
-
confounders = (treatment_ancestors & outcome_ancestors) - treatment_descendants
|
|
284
|
+
confounders = _backdoor_confounders(self._dag, self._treatment, self._outcome)
|
|
293
285
|
|
|
294
286
|
observed_confounders = {c for c in confounders if c in data_columns}
|
|
295
287
|
dag_confounders_not_in_data = {c for c in confounders if c not in data_columns}
|
|
@@ -335,18 +327,9 @@ class OLSObservational:
|
|
|
335
327
|
adjustment_set, dag_confounders_not_in_data = self._identify(data_columns)
|
|
336
328
|
|
|
337
329
|
if dag_confounders_not_in_data:
|
|
338
|
-
raise
|
|
339
|
-
f"\nDAG confounders not found in dataframe: {sorted(dag_confounders_not_in_data)}\n\n"
|
|
340
|
-
f"Your DAG declares these variables as confounders of '{self._treatment}' and\n"
|
|
341
|
-
f"'{self._outcome}', but they are absent from the dataframe and cannot be\n"
|
|
342
|
-
f"controlled for. Note: there may also be confounders not modelled in your\n"
|
|
343
|
-
f"DAG at all — formative cannot detect those.\n\n"
|
|
344
|
-
f"Consider:\n"
|
|
345
|
-
f" - Collecting data on {sorted(dag_confounders_not_in_data)} and adding it to the dataframe\n"
|
|
346
|
-
f" - IV estimation if you have a valid instrument for '{self._treatment}'\n"
|
|
347
|
-
f" - DiD or RD if a natural experiment is available"
|
|
348
|
-
)
|
|
330
|
+
raise _missing_confounders_error(dag_confounders_not_in_data, self._treatment, self._outcome)
|
|
349
331
|
|
|
332
|
+
_reject_missing(data, [self._treatment, self._outcome, *sorted(adjustment_set)])
|
|
350
333
|
unadjusted_result = smf.ols(f"{self._outcome} ~ {self._treatment}", data=data).fit()
|
|
351
334
|
|
|
352
335
|
if self._modifier is not None:
|
|
@@ -23,6 +23,7 @@ import numpy as np
|
|
|
23
23
|
import pandas as pd
|
|
24
24
|
|
|
25
25
|
from .._assumptions import Assumption
|
|
26
|
+
from ._base import _reject_missing
|
|
26
27
|
from ._cate import _validate_modifier_dag
|
|
27
28
|
|
|
28
29
|
_FOLD_SEED = 13579
|
|
@@ -101,30 +102,6 @@ def _rules_lines(tree: PolicyNode | bool) -> list[str]:
|
|
|
101
102
|
return [f"treat if {' and '.join(conds)}" for conds in paths] + ["otherwise don't treat"]
|
|
102
103
|
|
|
103
104
|
|
|
104
|
-
def _simplify_tree(tree: PolicyNode | bool, data: pd.DataFrame) -> PolicyNode | bool:
|
|
105
|
-
"""
|
|
106
|
-
Drop splits that don't change the assignment on *data*.
|
|
107
|
-
|
|
108
|
-
The exhaustive search keeps the first of several equal-value trees, which
|
|
109
|
-
can carry redundant conditions (e.g. a root split whose subtree already
|
|
110
|
-
implies it). Replacing a node by one of its children is safe whenever the
|
|
111
|
-
assignment is identical over the sample — same assignment, same value.
|
|
112
|
-
"""
|
|
113
|
-
if isinstance(tree, bool):
|
|
114
|
-
return tree
|
|
115
|
-
cond = data[tree.feature].to_numpy() == tree.level
|
|
116
|
-
left = _simplify_tree(tree.if_true, data.loc[cond])
|
|
117
|
-
right = _simplify_tree(tree.if_false, data.loc[~cond])
|
|
118
|
-
if isinstance(left, bool) and isinstance(right, bool) and left == right:
|
|
119
|
-
return left
|
|
120
|
-
tree = PolicyNode(tree.feature, tree.level, left, right)
|
|
121
|
-
full = _assign_tree(tree, data)
|
|
122
|
-
for child in (left, right):
|
|
123
|
-
if np.array_equal(_assign_tree(child, data), full):
|
|
124
|
-
return child
|
|
125
|
-
return tree
|
|
126
|
-
|
|
127
|
-
|
|
128
105
|
def _dr_scores(
|
|
129
106
|
W: np.ndarray,
|
|
130
107
|
Y: np.ndarray,
|
|
@@ -188,6 +165,9 @@ def _learn_tree(
|
|
|
188
165
|
best_val = float(vals[i])
|
|
189
166
|
return best_tree, best_val
|
|
190
167
|
|
|
168
|
+
# A deeper tree must strictly beat the best shallower one, or an equal-value
|
|
169
|
+
# tree with redundant splits can win on candidate order.
|
|
170
|
+
best_tree, best_val = _learn_tree(gamma, M, candidates, max_depth - 1)
|
|
191
171
|
for i, (feature, level) in enumerate(candidates):
|
|
192
172
|
mask = M[i].astype(bool)
|
|
193
173
|
left_tree, left_val = _learn_tree(gamma[mask], M[:, mask], candidates, max_depth - 1)
|
|
@@ -260,7 +240,6 @@ def _fit_policy(
|
|
|
260
240
|
value_ci = (value - 1.96 * value_se, value + 1.96 * value_se)
|
|
261
241
|
|
|
262
242
|
tree, _ = _learn_tree(gamma, M, candidates, max_depth)
|
|
263
|
-
tree = _simplify_tree(tree, data)
|
|
264
243
|
coverage = float(_assign_tree(tree, data).mean())
|
|
265
244
|
|
|
266
245
|
return _PolicyFit(tree=tree, value=value, value_se=value_se, value_ci=value_ci, coverage=coverage)
|
|
@@ -458,10 +437,7 @@ def _validate_policy_inputs(
|
|
|
458
437
|
f"Policy trees need discrete features — bin continuous or high-cardinality columns first."
|
|
459
438
|
)
|
|
460
439
|
|
|
461
|
-
|
|
462
|
-
with_nan = [c for c in used if data[c].isna().any()]
|
|
463
|
-
if with_nan:
|
|
464
|
-
raise ValueError(f"Columns {with_nan} contain missing values — drop or impute them before learning a policy.")
|
|
440
|
+
_reject_missing(data, [treatment, outcome, *modifiers], action="learning a policy")
|
|
465
441
|
|
|
466
442
|
w = set(data[treatment].unique())
|
|
467
443
|
if w != {0, 1}:
|
|
@@ -5,7 +5,7 @@ import statsmodels.formula.api as smf
|
|
|
5
5
|
|
|
6
6
|
from .._assumptions import Assumption
|
|
7
7
|
from ..dag import DAG
|
|
8
|
-
from ._base import _StatsmodelsResult
|
|
8
|
+
from ._base import _reject_missing, _StatsmodelsResult
|
|
9
9
|
from ._cate import (
|
|
10
10
|
CATE_ASSUMPTIONS,
|
|
11
11
|
_CATEResultMixin,
|
|
@@ -305,6 +305,7 @@ class RCT:
|
|
|
305
305
|
for label, var in [("Treatment", self._treatment), ("Outcome", self._outcome)]:
|
|
306
306
|
if var not in data.columns:
|
|
307
307
|
raise ValueError(f"{label} column '{var}' not found in dataframe.")
|
|
308
|
+
_reject_missing(data, [self._treatment, self._outcome])
|
|
308
309
|
|
|
309
310
|
if self._modifier is not None:
|
|
310
311
|
_validate_modifier_data(data, self._treatment, self._modifier)
|
|
@@ -5,7 +5,7 @@ import statsmodels.formula.api as smf
|
|
|
5
5
|
|
|
6
6
|
from .._assumptions import Assumption
|
|
7
7
|
from ..dag import DAG
|
|
8
|
-
from ._base import _StatsmodelsResult
|
|
8
|
+
from ._base import _reject_missing, _StatsmodelsResult
|
|
9
9
|
|
|
10
10
|
RDD_ASSUMPTIONS: list[Assumption] = [
|
|
11
11
|
Assumption(
|
|
@@ -131,6 +131,10 @@ class RDDResult(_StatsmodelsResult):
|
|
|
131
131
|
_check_random_common_cause,
|
|
132
132
|
)
|
|
133
133
|
|
|
134
|
+
# Refute on the same rows fit() used, not the whole dataframe.
|
|
135
|
+
if self._bandwidth is not None:
|
|
136
|
+
data = data.loc[(data[self._running_var] - self._cutoff).abs() <= self._bandwidth]
|
|
137
|
+
|
|
134
138
|
checks = [
|
|
135
139
|
_check_placebo_cutoff(
|
|
136
140
|
data,
|
|
@@ -256,6 +260,8 @@ class RDD:
|
|
|
256
260
|
filtered = data.loc[mask]
|
|
257
261
|
else:
|
|
258
262
|
filtered = data
|
|
263
|
+
# Rows outside the bandwidth are never used, so their gaps don't matter.
|
|
264
|
+
_reject_missing(filtered, [self._running_var, self._outcome])
|
|
259
265
|
|
|
260
266
|
# Unadjusted effect: naive mean difference above vs below cutoff
|
|
261
267
|
above = filtered.loc[filtered[self._running_var] >= self._cutoff, self._outcome].mean()
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "formative-ds"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.3.0"
|
|
8
8
|
description = "A Python library for quantitative reasoning."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -37,7 +37,6 @@ Repository = "https://github.com/maxpagels/formative"
|
|
|
37
37
|
|
|
38
38
|
[dependency-groups]
|
|
39
39
|
dev = [
|
|
40
|
-
"jupyter>=1.1.1",
|
|
41
40
|
"pytest>=9,<10",
|
|
42
41
|
"pytest-cov",
|
|
43
42
|
"ruff>=0.9",
|
|
@@ -48,7 +47,7 @@ docs = ["sphinx>=7,<10", "sphinx-rtd-theme>=2,<4", "sphinx-copybutton>=0.5,<0.6"
|
|
|
48
47
|
packages = ["formative"]
|
|
49
48
|
|
|
50
49
|
[tool.bumpversion]
|
|
51
|
-
current_version = "2.
|
|
50
|
+
current_version = "2.3.0"
|
|
52
51
|
commit = true
|
|
53
52
|
tag = true
|
|
54
53
|
tag_name = "v{new_version}"
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
7
|
|
|
8
8
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
9
|
-
<title>Benchmarks — formative 2.2.
|
|
9
|
+
<title>Benchmarks — formative 2.2.5 documentation</title>
|
|
10
10
|
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=b86133f3" />
|
|
11
11
|
<link rel="stylesheet" type="text/css" href="../_static/css/theme.css?v=9edc463e" />
|
|
12
12
|
<link rel="stylesheet" type="text/css" href="../_static/copybutton.css?v=76b2166b" />
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<link rel="canonical" href="https://docs.getformative.dev/causal/benchmarks.html" />
|
|
17
17
|
<script src="../_static/jquery.js?v=5d32c60e"></script>
|
|
18
18
|
<script src="../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
|
19
|
-
<script src="../_static/documentation_options.js?v=
|
|
19
|
+
<script src="../_static/documentation_options.js?v=ea147abf"></script>
|
|
20
20
|
<script src="../_static/doctools.js?v=fd6eb6e6"></script>
|
|
21
21
|
<script src="../_static/sphinx_highlight.js?v=6ffebe34"></script>
|
|
22
22
|
<script src="../_static/clipboard.min.js?v=a7894cd8"></script>
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
7
|
|
|
8
8
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
9
|
-
<title>DAG — formative 2.2.
|
|
9
|
+
<title>DAG — formative 2.2.5 documentation</title>
|
|
10
10
|
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=b86133f3" />
|
|
11
11
|
<link rel="stylesheet" type="text/css" href="../_static/css/theme.css?v=9edc463e" />
|
|
12
12
|
<link rel="stylesheet" type="text/css" href="../_static/copybutton.css?v=76b2166b" />
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<link rel="canonical" href="https://docs.getformative.dev/causal/dag.html" />
|
|
17
17
|
<script src="../_static/jquery.js?v=5d32c60e"></script>
|
|
18
18
|
<script src="../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
|
19
|
-
<script src="../_static/documentation_options.js?v=
|
|
19
|
+
<script src="../_static/documentation_options.js?v=ea147abf"></script>
|
|
20
20
|
<script src="../_static/doctools.js?v=fd6eb6e6"></script>
|
|
21
21
|
<script src="../_static/sphinx_highlight.js?v=6ffebe34"></script>
|
|
22
22
|
<script src="../_static/clipboard.min.js?v=a7894cd8"></script>
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
7
|
|
|
8
8
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
9
|
-
<title>Decisions — formative 2.2.
|
|
9
|
+
<title>Decisions — formative 2.2.5 documentation</title>
|
|
10
10
|
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=b86133f3" />
|
|
11
11
|
<link rel="stylesheet" type="text/css" href="../_static/css/theme.css?v=9edc463e" />
|
|
12
12
|
<link rel="stylesheet" type="text/css" href="../_static/copybutton.css?v=76b2166b" />
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<link rel="canonical" href="https://docs.getformative.dev/causal/decisions.html" />
|
|
17
17
|
<script src="../_static/jquery.js?v=5d32c60e"></script>
|
|
18
18
|
<script src="../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
|
19
|
-
<script src="../_static/documentation_options.js?v=
|
|
19
|
+
<script src="../_static/documentation_options.js?v=ea147abf"></script>
|
|
20
20
|
<script src="../_static/doctools.js?v=fd6eb6e6"></script>
|
|
21
21
|
<script src="../_static/sphinx_highlight.js?v=6ffebe34"></script>
|
|
22
22
|
<script src="../_static/clipboard.min.js?v=a7894cd8"></script>
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
7
|
|
|
8
8
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
9
|
-
<title>Estimands — formative 2.2.
|
|
9
|
+
<title>Estimands — formative 2.2.5 documentation</title>
|
|
10
10
|
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=b86133f3" />
|
|
11
11
|
<link rel="stylesheet" type="text/css" href="../_static/css/theme.css?v=9edc463e" />
|
|
12
12
|
<link rel="stylesheet" type="text/css" href="../_static/copybutton.css?v=76b2166b" />
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<link rel="canonical" href="https://docs.getformative.dev/causal/estimands.html" />
|
|
17
17
|
<script src="../_static/jquery.js?v=5d32c60e"></script>
|
|
18
18
|
<script src="../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
|
19
|
-
<script src="../_static/documentation_options.js?v=
|
|
19
|
+
<script src="../_static/documentation_options.js?v=ea147abf"></script>
|
|
20
20
|
<script src="../_static/doctools.js?v=fd6eb6e6"></script>
|
|
21
21
|
<script src="../_static/sphinx_highlight.js?v=6ffebe34"></script>
|
|
22
22
|
<script src="../_static/clipboard.min.js?v=a7894cd8"></script>
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
7
|
|
|
8
8
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
9
|
-
<title>Estimators — formative 2.2.
|
|
9
|
+
<title>Estimators — formative 2.2.5 documentation</title>
|
|
10
10
|
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=b86133f3" />
|
|
11
11
|
<link rel="stylesheet" type="text/css" href="../_static/css/theme.css?v=9edc463e" />
|
|
12
12
|
<link rel="stylesheet" type="text/css" href="../_static/copybutton.css?v=76b2166b" />
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<link rel="canonical" href="https://docs.getformative.dev/causal/estimators.html" />
|
|
17
17
|
<script src="../_static/jquery.js?v=5d32c60e"></script>
|
|
18
18
|
<script src="../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
|
19
|
-
<script src="../_static/documentation_options.js?v=
|
|
19
|
+
<script src="../_static/documentation_options.js?v=ea147abf"></script>
|
|
20
20
|
<script src="../_static/doctools.js?v=fd6eb6e6"></script>
|
|
21
21
|
<script src="../_static/sphinx_highlight.js?v=6ffebe34"></script>
|
|
22
22
|
<script src="../_static/clipboard.min.js?v=a7894cd8"></script>
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
7
|
|
|
8
8
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
9
|
-
<title>Introduction — formative 2.2.
|
|
9
|
+
<title>Introduction — formative 2.2.5 documentation</title>
|
|
10
10
|
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=b86133f3" />
|
|
11
11
|
<link rel="stylesheet" type="text/css" href="../_static/css/theme.css?v=9edc463e" />
|
|
12
12
|
<link rel="stylesheet" type="text/css" href="../_static/copybutton.css?v=76b2166b" />
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<link rel="canonical" href="https://docs.getformative.dev/causal/introduction.html" />
|
|
17
17
|
<script src="../_static/jquery.js?v=5d32c60e"></script>
|
|
18
18
|
<script src="../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
|
19
|
-
<script src="../_static/documentation_options.js?v=
|
|
19
|
+
<script src="../_static/documentation_options.js?v=ea147abf"></script>
|
|
20
20
|
<script src="../_static/doctools.js?v=fd6eb6e6"></script>
|
|
21
21
|
<script src="../_static/sphinx_highlight.js?v=6ffebe34"></script>
|
|
22
22
|
<script src="../_static/clipboard.min.js?v=a7894cd8"></script>
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
7
|
|
|
8
8
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
9
|
-
<title>Motivation — formative 2.2.
|
|
9
|
+
<title>Motivation — formative 2.2.5 documentation</title>
|
|
10
10
|
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=b86133f3" />
|
|
11
11
|
<link rel="stylesheet" type="text/css" href="../_static/css/theme.css?v=9edc463e" />
|
|
12
12
|
<link rel="stylesheet" type="text/css" href="../_static/copybutton.css?v=76b2166b" />
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<link rel="canonical" href="https://docs.getformative.dev/causal/motivation.html" />
|
|
17
17
|
<script src="../_static/jquery.js?v=5d32c60e"></script>
|
|
18
18
|
<script src="../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
|
19
|
-
<script src="../_static/documentation_options.js?v=
|
|
19
|
+
<script src="../_static/documentation_options.js?v=ea147abf"></script>
|
|
20
20
|
<script src="../_static/doctools.js?v=fd6eb6e6"></script>
|
|
21
21
|
<script src="../_static/sphinx_highlight.js?v=6ffebe34"></script>
|
|
22
22
|
<script src="../_static/clipboard.min.js?v=a7894cd8"></script>
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
7
|
|
|
8
8
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
9
|
-
<title>Refutations — formative 2.2.
|
|
9
|
+
<title>Refutations — formative 2.2.5 documentation</title>
|
|
10
10
|
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=b86133f3" />
|
|
11
11
|
<link rel="stylesheet" type="text/css" href="../_static/css/theme.css?v=9edc463e" />
|
|
12
12
|
<link rel="stylesheet" type="text/css" href="../_static/copybutton.css?v=76b2166b" />
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<link rel="canonical" href="https://docs.getformative.dev/causal/refutations.html" />
|
|
17
17
|
<script src="../_static/jquery.js?v=5d32c60e"></script>
|
|
18
18
|
<script src="../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
|
19
|
-
<script src="../_static/documentation_options.js?v=
|
|
19
|
+
<script src="../_static/documentation_options.js?v=ea147abf"></script>
|
|
20
20
|
<script src="../_static/doctools.js?v=fd6eb6e6"></script>
|
|
21
21
|
<script src="../_static/sphinx_highlight.js?v=6ffebe34"></script>
|
|
22
22
|
<script src="../_static/clipboard.min.js?v=a7894cd8"></script>
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
7
|
|
|
8
8
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
9
|
-
<title>Choosing an estimator — formative 2.2.
|
|
9
|
+
<title>Choosing an estimator — formative 2.2.5 documentation</title>
|
|
10
10
|
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=b86133f3" />
|
|
11
11
|
<link rel="stylesheet" type="text/css" href="../_static/css/theme.css?v=9edc463e" />
|
|
12
12
|
<link rel="stylesheet" type="text/css" href="../_static/copybutton.css?v=76b2166b" />
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<link rel="canonical" href="https://docs.getformative.dev/causal/wizard.html" />
|
|
17
17
|
<script src="../_static/jquery.js?v=5d32c60e"></script>
|
|
18
18
|
<script src="../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
|
19
|
-
<script src="../_static/documentation_options.js?v=
|
|
19
|
+
<script src="../_static/documentation_options.js?v=ea147abf"></script>
|
|
20
20
|
<script src="../_static/doctools.js?v=fd6eb6e6"></script>
|
|
21
21
|
<script src="../_static/sphinx_highlight.js?v=6ffebe34"></script>
|
|
22
22
|
<script src="../_static/clipboard.min.js?v=a7894cd8"></script>
|