Full Code of py-why/EconML for AI

main b0404c02be5a cached
270 files
53.0 MB
4.1M tokens
2220 symbols
2 requests
Copy disabled (too large) Download .txt
Showing preview only (16,290K chars total). Download the full file to get everything.
Repository: py-why/EconML
Branch: main
Commit: b0404c02be5a
Files: 270
Total size: 53.0 MB

Directory structure:
gitextract_2llsel0e/

├── .github/
│   └── workflows/
│       ├── ci.yml
│       ├── generate_lkg.py
│       ├── publish-documentation.yml
│       └── publish-package.yml
├── .gitignore
├── .pre-commit-config.yaml
├── LICENSE
├── README.md
├── SECURITY.md
├── doc/
│   ├── conf.py
│   ├── index.rst
│   ├── reference.rst
│   └── spec/
│       ├── api.rst
│       ├── causal_intro.rst
│       ├── community.rst
│       ├── comparison.rst
│       ├── estimation/
│       │   ├── dml.rst
│       │   ├── dr.rst
│       │   ├── dynamic_dml.rst
│       │   ├── forest.rst
│       │   ├── metalearners.rst
│       │   ├── orthoiv.rst
│       │   └── two_sls.rst
│       ├── estimation.rst
│       ├── estimation_dynamic.rst
│       ├── estimation_iv.rst
│       ├── faq.rst
│       ├── federated_learning.rst
│       ├── flowchart.rst
│       ├── inference.rst
│       ├── interpretability.rst
│       ├── model_selection.rst
│       ├── motivation.rst
│       ├── overview.rst
│       ├── references.rst
│       ├── spec.rst
│       └── validation.rst
├── econml/
│   ├── __init__.py
│   ├── _cate_estimator.py
│   ├── _ensemble/
│   │   ├── __init__.py
│   │   ├── _ensemble.py
│   │   └── _utilities.py
│   ├── _ortho_learner.py
│   ├── _shap.py
│   ├── _tree_exporter.py
│   ├── _version.py
│   ├── automated_ml/
│   │   ├── __init__.py
│   │   └── _automated_ml.py
│   ├── cate_interpreter/
│   │   ├── __init__.py
│   │   └── _interpreters.py
│   ├── data/
│   │   ├── __init__.py
│   │   ├── color-edits.sty
│   │   ├── data_doc.bib
│   │   ├── data_doc.tex
│   │   ├── dgps.py
│   │   ├── dynamic_panel_dgp.py
│   │   ├── ihdp/
│   │   │   ├── example.csv
│   │   │   ├── example_full.csv
│   │   │   └── sim.csv
│   │   └── input_dynamicdgp/
│   │       ├── cov_new.jbl
│   │       ├── gm_0.jbl
│   │       ├── gm_1.jbl
│   │       ├── gm_2.jbl
│   │       ├── gm_3.jbl
│   │       ├── gm_4.jbl
│   │       ├── gm_5.jbl
│   │       ├── gm_6.jbl
│   │       ├── lognorm_neg_0.jbl
│   │       ├── lognorm_neg_1.jbl
│   │       ├── lognorm_neg_2.jbl
│   │       ├── lognorm_neg_3.jbl
│   │       ├── lognorm_neg_4.jbl
│   │       ├── lognorm_neg_5.jbl
│   │       ├── lognorm_pos_0.jbl
│   │       ├── lognorm_pos_1.jbl
│   │       ├── lognorm_pos_2.jbl
│   │       ├── lognorm_pos_3.jbl
│   │       ├── lognorm_pos_4.jbl
│   │       ├── lognorm_pos_5.jbl
│   │       ├── lognorm_pos_6.jbl
│   │       ├── n_0.jbl
│   │       ├── n_1.jbl
│   │       ├── n_2.jbl
│   │       ├── n_3.jbl
│   │       ├── n_4.jbl
│   │       ├── n_5.jbl
│   │       └── n_6.jbl
│   ├── dml/
│   │   ├── __init__.py
│   │   ├── _rlearner.py
│   │   ├── causal_forest.py
│   │   └── dml.py
│   ├── dowhy.py
│   ├── dr/
│   │   ├── __init__.py
│   │   └── _drlearner.py
│   ├── federated_learning.py
│   ├── grf/
│   │   ├── __init__.py
│   │   ├── _base_grf.py
│   │   ├── _base_grftree.py
│   │   ├── _criterion.pxd
│   │   ├── _criterion.pyx
│   │   ├── _utils.pxd
│   │   ├── _utils.pyx
│   │   └── classes.py
│   ├── inference/
│   │   ├── __init__.py
│   │   ├── _bootstrap.py
│   │   └── _inference.py
│   ├── iv/
│   │   ├── __init__.py
│   │   ├── dml/
│   │   │   ├── __init__.py
│   │   │   └── _dml.py
│   │   ├── dr/
│   │   │   ├── __init__.py
│   │   │   └── _dr.py
│   │   └── sieve/
│   │       ├── __init__.py
│   │       └── _tsls.py
│   ├── metalearners/
│   │   ├── __init__.py
│   │   └── _metalearners.py
│   ├── orf/
│   │   ├── __init__.py
│   │   ├── _causal_tree.py
│   │   └── _ortho_forest.py
│   ├── panel/
│   │   ├── __init__.py
│   │   ├── dml/
│   │   │   ├── __init__.py
│   │   │   └── _dml.py
│   │   └── utilities.py
│   ├── policy/
│   │   ├── __init__.py
│   │   ├── _base.py
│   │   ├── _drlearner.py
│   │   └── _forest/
│   │       ├── __init__.py
│   │       ├── _criterion.pxd
│   │       ├── _criterion.pyx
│   │       ├── _forest.py
│   │       └── _tree.py
│   ├── score/
│   │   ├── __init__.py
│   │   ├── ensemble_cate.py
│   │   └── rscorer.py
│   ├── sklearn_extensions/
│   │   ├── __init__.py
│   │   ├── linear_model.py
│   │   └── model_selection.py
│   ├── solutions/
│   │   └── causal_analysis/
│   │       ├── __init__.py
│   │       └── _causal_analysis.py
│   ├── tests/
│   │   ├── __init__.py
│   │   ├── dgp.py
│   │   ├── test_ate_inference.py
│   │   ├── test_automated_ml.py
│   │   ├── test_bootstrap.py
│   │   ├── test_cate_interpreter.py
│   │   ├── test_causal_analysis.py
│   │   ├── test_discrete_outcome.py
│   │   ├── test_dml.py
│   │   ├── test_dmliv.py
│   │   ├── test_dominicks.py
│   │   ├── test_dowhy.py
│   │   ├── test_driv.py
│   │   ├── test_drlearner.py
│   │   ├── test_drtester.py
│   │   ├── test_dynamic_dml.py
│   │   ├── test_federated_learning.py
│   │   ├── test_grf_cython.py
│   │   ├── test_grf_python.py
│   │   ├── test_inference.py
│   │   ├── test_integration.py
│   │   ├── test_linear_model.py
│   │   ├── test_metalearners.py
│   │   ├── test_missing_values.py
│   │   ├── test_model_selection.py
│   │   ├── test_montecarlo.py
│   │   ├── test_notebooks.py
│   │   ├── test_orf.py
│   │   ├── test_ortho_learner.py
│   │   ├── test_policy_forest.py
│   │   ├── test_random_state.py
│   │   ├── test_refit.py
│   │   ├── test_rscorer.py
│   │   ├── test_sensitivity_analysis.py
│   │   ├── test_shap.py
│   │   ├── test_statsmodels.py
│   │   ├── test_treatment_featurization.py
│   │   ├── test_tree.py
│   │   ├── test_two_stage_least_squares.py
│   │   ├── test_utilities.py
│   │   └── utilities.py
│   ├── tree/
│   │   ├── __init__.py
│   │   ├── _criterion.pxd
│   │   ├── _criterion.pyx
│   │   ├── _splitter.pxd
│   │   ├── _splitter.pyx
│   │   ├── _tree.pxd
│   │   ├── _tree.pyx
│   │   ├── _tree_classes.py
│   │   ├── _utils.pxd
│   │   └── _utils.pyx
│   ├── utilities.py
│   └── validate/
│       ├── __init__.py
│       ├── drtester.py
│       ├── results.py
│       ├── sensitivity_analysis.py
│       └── utils.py
├── lkg-notebook.txt
├── lkg.txt
├── monte_carlo_tests/
│   ├── monte_carlo_honestforest.py
│   └── monte_carlo_statsmodels.py
├── notebooks/
│   ├── AutomatedML/
│   │   └── Automated Machine Learning For EconML.ipynb
│   ├── CATE validation.ipynb
│   ├── Causal Forest and Orthogonal Random Forest Examples.ipynb
│   ├── Causal Model Selection with the RScorer.ipynb
│   ├── Choosing First Stage Models.ipynb
│   ├── CustomerScenarios/
│   │   ├── Case Study - Customer Segmentation at An Online Media Company - EconML + DoWhy.ipynb
│   │   ├── Case Study - Customer Segmentation at An Online Media Company.ipynb
│   │   ├── Case Study - Long-Term Return-on-Investment via Short-Term Proxies.ipynb
│   │   ├── Case Study - Multi-investment Attribution at A Software Company - EconML + DoWhy.ipynb
│   │   ├── Case Study - Multi-investment Attribution at A Software Company.ipynb
│   │   ├── Case Study - Recommendation AB Testing at An Online Travel Company - EconML + DoWhy.ipynb
│   │   ├── Case Study - Recommendation AB Testing at An Online Travel Company.ipynb
│   │   └── Case Study - Using EconML to evaluate the treatment effect of training program - Lalonde dataset.ipynb
│   ├── Double Machine Learning Examples.ipynb
│   ├── Doubly Robust Learner and Interpretability.ipynb
│   ├── Dynamic Double Machine Learning Examples.ipynb
│   ├── ForestLearners Basic Example.ipynb
│   ├── Generalized Random Forests.ipynb
│   ├── Interpretability with SHAP.ipynb
│   ├── Metalearners Examples.ipynb
│   ├── OrthoIV and DRIV Examples.ipynb
│   ├── Policy Learning with Trees and Forests.ipynb
│   ├── Scaling EconML using Ray.ipynb
│   ├── Solutions/
│   │   ├── Causal Interpretation for Ames Housing Price.ipynb
│   │   └── Causal Interpretation for Employee Attrition Dataset.ipynb
│   ├── Treatment Featurization Examples.ipynb
│   └── Weighted Double Machine Learning Examples.ipynb
├── prototypes/
│   ├── dml_iv/
│   │   ├── NLSYM_GBM.ipynb
│   │   ├── NLSYM_Linear.ipynb
│   │   ├── NLSYM_Semi_Synthetic_GBM.ipynb
│   │   ├── NLSYM_Semi_Synthetic_Linear.ipynb
│   │   ├── README.md
│   │   ├── TA_DGP_analysis.ipynb
│   │   ├── TA_DGP_analysis_Step_CATE.ipynb
│   │   ├── coverage_experiment.py
│   │   ├── data/
│   │   │   ├── NEW7080.dta
│   │   │   ├── card.csv
│   │   │   ├── code_bk.txt
│   │   │   └── readme
│   │   ├── deep_dml_iv.py
│   │   ├── deep_dr_iv.py
│   │   ├── dml_ate_iv.py
│   │   ├── dml_iv.py
│   │   ├── dr_iv.py
│   │   ├── post_processing.ipynb
│   │   ├── utilities.py
│   │   └── xgb_utilities.py
│   ├── dynamic_dml/
│   │   ├── README.md
│   │   ├── all_coverage.sh
│   │   ├── coverage_panel.py
│   │   ├── coverage_panel_hetero.py
│   │   ├── dynamic_panel_dgp.py
│   │   ├── hetero_panel_dynamic_dml.py
│   │   ├── high_dim_state_any_m_panel.ipynb
│   │   ├── high_dim_state_any_m_panel_hetero.ipynb
│   │   ├── panel_dynamic_dml.py
│   │   ├── postprocess_panel.ipynb
│   │   └── postprocess_panel_hetero.ipynb
│   ├── orthogonal_forests/
│   │   ├── GRF_treatment_effects.R
│   │   ├── README.md
│   │   ├── causal_tree.py
│   │   ├── comparison_plots.py
│   │   ├── hetero_dml.py
│   │   ├── monte_carlo.py
│   │   ├── ortho_forest.py
│   │   ├── residualizer.py
│   │   └── seq_map.sh
│   └── sensitivity_analysis/
│       ├── ovb_dml.ipynb
│       └── ovb_dr.ipynb
├── pyproject.toml
└── setup.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/ci.yml
================================================
name: Run all checks

on:
  pull_request:
    branches:
      - main
  workflow_dispatch:
    inputs:
      ref:
        description: 'The git ref to build the package for'
        required: false
        default: ''
        type: string
      use_lkg:
        description: 'Whether to use the last known good versions of dependencies'
        required: false
        default: True
        type: boolean
  # nightly
  schedule:
    - cron: '0 0 * * *'

# Only run once per PR, canceling any previous runs
concurrency:
  group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
  cancel-in-progress: true

# Precompute the ref if the workflow was triggered by a workflow dispatch rather than copying this logic repeatedly
env:
  ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || null }}
  # we want to use the LKG if that is explicitly requested, or if we're in a PR, but not a nightly run
  # the final `|| ''` is because env vars are always converted to strings and the string 'false' is truthy (!!)
  # (see https://github.com/orgs/community/discussions/25645)
  use_lkg: ${{ (github.event_name == 'workflow_dispatch' && inputs.use_lkg) || github.event_name == 'pull_request' || ''}}

jobs:
  eval: 
    name: Evaluate changes
    runs-on: ubuntu-latest
    steps:
    - name: Checkout repository
      uses: actions/checkout@v4
      with:
        ref: ${{ env.ref }}
        fetch-depth: 2

      # We want to enforce the following rules for PRs:
      # * if all modifications are to README.md
      #     no testing is needed
      # * if there are modifications to docs/* or to any code
      #     then docs need to be built to verify consistency
      # * if there are modifications to notebooks/* or to any code
      #     then notebooks need to be run to verify consistency
      # * for any code changes (or changes to metadata files)
      #     linting and testing should be run
      # For a PR build, HEAD will be the merge commit, and we want to diff against the base branch,
      #  which will be the first parent: HEAD^ 
      # (For non-PR changes, we will always perform all CI tasks)
      # Note that GitHub Actions provides path filters, but they operate at the workflow level, not the job level
    - name: Determine type of code change
      run: |
        if ($env:GITHUB_EVENT_NAME -eq 'pull_request') {
          $editedFiles = git diff HEAD^ --name-only
          $editedFiles # echo edited files to enable easier debugging
          $codeChanges = $false
          $docChanges = $false
          $nbChanges = $false
          $changeType = "none"
          foreach ($file in $editedFiles) {
            switch -Wildcard ($file) {
              "README.md" { Continue }
              ".gitignore" { Continue }
              "econml/_version.py" { Continue }
              "prototypes/*" { Continue }
              "images/*" { Continue }
              "doc/*" { $docChanges = $true; Continue }
              "notebooks/*" { $nbChanges = $true; Continue }
              default { $codeChanges = $true; Continue }
            }
          }
        }
        echo "buildDocs=$(($env:GITHUB_EVENT_NAME -ne 'pull_request') -or ($docChanges -or $codeChanges))" >> $env:GITHUB_OUTPUT
        echo "buildNbs=$(($env:GITHUB_EVENT_NAME -ne 'pull_request') -or ($nbChanges -or $codeChanges))" >> $env:GITHUB_OUTPUT
        echo "testCode=$(($env:GITHUB_EVENT_NAME -ne 'pull_request') -or $codeChanges)" >> $env:GITHUB_OUTPUT
      shell: pwsh
      id: eval
    outputs: 
      buildDocs: ${{ steps.eval.outputs.buildDocs }}
      buildNbs: ${{ steps.eval.outputs.buildNbs }}
      testCode: ${{ steps.eval.outputs.testCode }}

  lint:
    name: Lint code
    needs: [eval]
    if: ${{ needs.eval.outputs.testCode == 'True' }}
    runs-on: ubuntu-latest
    steps:
    - name: Checkout repository
      uses: actions/checkout@v4
      with:
        ref: ${{ env.ref }}
    - name: Setup Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.9'
    - name: Ensure latest pip and setuptools
      run: python -m pip install --upgrade pip && pip install --upgrade setuptools
    - name: Run Ruff
      run: 'pip install ruff && ruff check'

  notebooks:
    name: Run notebooks
    needs: [eval]
    if: ${{ needs.eval.outputs.buildNbs == 'True' }}
    runs-on: ubuntu-latest
    strategy:
      matrix:
        kind: [except-customer-scenarios, customer-scenarios]
        include:
        - kind: "except-customer-scenarios"
          extras: "[plt,ray]"
          pattern: "(?!CustomerScenarios)"
          install_graphviz: true
          version: '3.12'
        - kind: "customer-scenarios"
          extras: "[plt,dowhy]"
          pattern: "CustomerScenarios"
          version: '3.12'
          install_graphviz: false
      fail-fast: false
    env:
      id_string: ${{ matrix.kind }}-${{ matrix.version }}
    steps:
    - name: Checkout repository
      uses: actions/checkout@v4
      with:
        ref: ${{ env.ref }}
    - name: Setup Python
      uses: actions/setup-python@v5
      with:
        python-version: ${{ matrix.version }}
    - name: Install uv
      # check if we're running on windows
      run: ${{ runner.os == 'Windows' && 'irm https://astral.sh/uv/install.ps1 | iex' || 'curl -LsSf https://astral.sh/uv/install.sh | sh' }}
    - name: Install graphviz
      run: sudo apt-get -yq install graphviz
      if: ${{ matrix.install_graphviz }}
    # Add verbose flag to pip installation if in debug mode
    - name: Install econml
      run: uv pip install --system -e .${{ matrix.extras }} ${{ fromJSON('["","-v"]')[runner.debug] }} ${{ env.use_lkg && '-r lkg-notebook.txt' }}
    # Install notebook requirements (if not already done as part of lkg)
    - name: Install notebook requirements
      run: uv pip install --system jupyter jupyter-client nbconvert nbformat seaborn xgboost tqdm
      if: ${{ !env.use_lkg }}
    - name: Save installed packages
      run: pip freeze --exclude-editable > notebooks-${{ env.id_string }}-requirements.txt
    - name: Upload installed packages
      uses: actions/upload-artifact@v4
      with:
        name: requirements-${{ env.id_string }}
        path: notebooks-${{ env.id_string }}-requirements.txt
    - name: Install pytest
      run: uv pip install --system pytest pytest-xdist pytest-cov coverage[toml]
    - name: Run notebook tests
      run: python -m pytest
      id: run_tests
      env:
        PYTEST_ADDOPTS: '-m "notebook"'
        NOTEBOOK_DIR_PATTERN: ${{ matrix.pattern }}
        COVERAGE_PROCESS_START: 'pyproject.toml'
    - name: Make coverage filename unique
      run: mv .coverage .coverage.${{ env.id_string }}
      # Run whether or not the tests passed, but only if they ran at all
      if: success() || failure() && contains(fromJSON('["success", "failure"]'), steps.run_tests.outcome)
    - name: Upload coverage report
      uses: actions/upload-artifact@v4
      if: success() || failure() && contains(fromJSON('["success", "failure"]'), steps.run_tests.outcome)
      with:
        name: coverage-${{ env.id_string }}
        path: .coverage.${{ env.id_string }}
        # need to include hidden files since path starts with .
        include-hidden-files: true
    - name: Make test XML filename unique
      run: mv junit/test-results.xml ${{ env.id_string }}-test-results.xml
      # Run whether or not the tests passed, but only if they ran at all
      if: success() || failure() && contains(fromJSON('["success", "failure"]'), steps.run_tests.outcome)
    - name: Upload test XML files
      uses: actions/upload-artifact@v4
      if: success() || failure() && contains(fromJSON('["success", "failure"]'), steps.run_tests.outcome)
      with:
        name: tests-${{ env.id_string }}
        path: ${{ env.id_string }}-test-results.xml
    - name: Upload notebook outputs
      uses: actions/upload-artifact@v4
      if: success() || failure() && contains(fromJSON('["success", "failure"]'), steps.run_tests.outcome)
      with:
        name: notebooks-${{ env.id_string }}
        path: notebooks/output/
  
  tests:
    name: "Run tests"
    needs: [eval]
    if: ${{ needs.eval.outputs.testCode == 'True' }}
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
        kind: [serial, other, dml, main, treatment, ray]
        exclude:
          # Serial tests fail randomly on mac sometimes, so we don't run them there
          - os: macos-latest
            kind: serial
          # Ray tests run out of memory on Windows
          - os: windows-latest
            kind: ray
          # Ray doesn't currently support Python 3.13
          - python-version: '3.13'
            kind: ray
        # Assign the correct package and testing options for each kind of test
        include:
          - kind: serial
            opts: '-m "serial and not ray" -n 1'
            extras: ""
          - kind: other
            opts: '-m "cate_api and not ray" -n auto'
            extras: "[plt]"
          - kind: dml
            opts: '-m "dml and not ray"'
            extras: "[plt]"
          - kind: main
            opts: '-m "not (notebook or automl or dml or serial or cate_api or treatment_featurization or ray)" -n 2'
            extras: "[plt,dowhy]"
          - kind: treatment
            opts: '-m "treatment_featurization and not ray" -n auto'
            extras: "[plt]"
          - kind: ray
            opts: '-m "ray"'
            extras: "[ray]"
      fail-fast: false    
    runs-on: ${{ matrix.os }}
    env:
      id_string: ${{ matrix.os }}-${{ matrix.python-version }}-${{ matrix.kind }}
    steps:
    - name: Checkout repository
      uses: actions/checkout@v4
      with:
        ref: ${{ env.ref }}
    - name: Setup Python
      uses: actions/setup-python@v5
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install libomp
      # lightgbm needs libomp on mac
      run: brew install libomp
      if: matrix.os == 'macos-latest'
    - name: Install graphviz on Ubuntu
      run: sudo apt-get -yq install graphviz
      if: ${{ matrix.os == 'ubuntu-latest' }}
    - name: Install uv
      # check if we're running on windows
      run: ${{ runner.os == 'Windows' && 'irm https://astral.sh/uv/install.ps1 | iex' || 'curl -LsSf https://astral.sh/uv/install.sh | sh' }}
    # Add verbose flag to pip installation if in debug mode
    - name: Install econml
      run: uv pip install --system -e .${{ matrix.extras }} ${{ fromJSON('["","-v"]')[runner.debug] }} ${{ env.use_lkg && '-r lkg.txt' }}
    - name: Save installed packages
      run: pip freeze --exclude-editable > tests-${{ env.id_string }}-requirements.txt
    - name: Upload installed packages
      uses: actions/upload-artifact@v4
      with:
        name: requirements-${{ env.id_string }}
        path: tests-${{ env.id_string }}-requirements.txt
    - name: Install pytest
      run: uv pip install --system pytest pytest-xdist pytest-cov coverage[toml]
    - name: Run tests
      run: python -m pytest
      id: run_tests
      env:
        PYTEST_ADDOPTS: ${{ matrix.opts }}
        COVERAGE_PROCESS_START: 'pyproject.toml'
    - name: Make coverage filename unique
      run: mv .coverage .coverage.${{ env.id_string }}
      # Run whether or not the tests passed, but only if they ran at all
      if: success() || failure() && contains(fromJSON('["success", "failure"]'), steps.run_tests.outcome)
    - name: Upload coverage report
      uses: actions/upload-artifact@v4
      if: success() || failure() && contains(fromJSON('["success", "failure"]'), steps.run_tests.outcome)
      with:
        name: coverage-${{ env.id_string }}
        path: .coverage.${{ env.id_string }}
        # need to include hidden files since path starts with .
        include-hidden-files: true
    - name: Make test XML filename unique
      run: mv junit/test-results.xml ${{ env.id_string }}-test-results.xml
      # Run whether or not the tests passed, but only if they ran at all
      if: success() || failure() && contains(fromJSON('["success", "failure"]'), steps.run_tests.outcome)
    - name: Upload test XML files
      uses: actions/upload-artifact@v4
      if: success() || failure() && contains(fromJSON('["success", "failure"]'), steps.run_tests.outcome)
      with:
        name: tests-${{ env.id_string }}
        path: ${{ env.id_string }}-test-results.xml

  store-reqs-per-env:
    name: Store requirements for LKG updates
    if: (success() || failure()) && (github.event_name == 'workflow_dispatch' && !inputs.use_lkg || github.event_name == 'schedule')
    strategy:
      matrix:
        kind: [tests]
        os: [ubuntu-latest, windows-latest, macos-latest]
        python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
        include:
          # assign extras to all combinations
          - extras: "[plt,dowhy,ray]"
          # overwrite extras for python 3.13 only
          - extras: "[plt,dowhy]"
            python-version: '3.13'
          # explicitly add the two notebook extras
          - kind: notebooks-other
            os: ubuntu-latest
            python-version: '3.12'
            extras: "[plt,ray]"
          - kind: notebooks-customer
            os: ubuntu-latest
            python-version: '3.12'
            extras: "[plt,dowhy]"
      fail-fast: false
    runs-on: ${{ matrix.os }}
    steps:
    - name: Checkout repository
      uses: actions/checkout@v4
      with:
        ref: ${{ env.ref }}
    - name: Setup Python
      uses: actions/setup-python@v5
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install uv
      # check if we're running on windows
      run: ${{ runner.os == 'Windows' && 'irm https://astral.sh/uv/install.ps1 | iex' || 'curl -LsSf https://astral.sh/uv/install.sh | sh' }}
    - name: Install econml
      # add all extras used by any of the individual tests, which is a superset of what's actually used anywhere
      run: uv pip install --system -e .${{ matrix.extras }}
    - name: Install notebook requirements
      run: uv pip install --system jupyter jupyter-client nbconvert nbformat seaborn xgboost tqdm
      if: startswith(matrix.kind, 'notebooks-')
    - name: Save installed packages
      run: pip freeze --exclude-editable > lkg-${{ matrix.kind }}-${{ matrix.os }}-${{ matrix.python-version }}.txt
    - name: Upload installed packages
      uses: actions/upload-artifact@v4
      with:
        name: lkg-${{ matrix.kind }}-${{ matrix.os }}-${{ matrix.python-version }}
        path: lkg-${{ matrix.kind }}-${{ matrix.os }}-${{ matrix.python-version }}.txt

  coverage-report:
    name: "Coverage report"
    needs: [tests, notebooks]
    if: success() || failure()
    runs-on: ubuntu-latest
    steps:
    - name: Checkout repository
      uses: actions/checkout@v4
      with:
        ref: ${{ env.ref }}
    - name: Get coverage reports
      uses: actions/download-artifact@v4
      with:
        pattern: coverage-*
        path: coverage
        merge-multiple: true
    - name: Setup Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.12'
    - name: Install coverage
      run: pip install coverage[toml]
    - name: Combine coverage reports
      run: coverage combine coverage/
    - name: Generate coverage report
      run: coverage report -m --format=markdown > $GITHUB_STEP_SUMMARY
    - name: Generate coverage html --fail-under=86
      run: coverage html
    - name: Upload coverage report
      uses: actions/upload-artifact@v4
      with:
        name: coverage-report
        path: htmlcov
      
  merge-artifacts:
    name: "Merge artifacts"
    needs: [coverage-report, tests, notebooks, store-reqs-per-env]
    if: success() || failure()
    strategy:
      matrix:
        artifact: [requirements, tests, coverage, notebooks, lkg-tests, lkg-notebooks]
    runs-on: ubuntu-latest
    steps:
    - name: "Merge artifacts"
      uses: actions/upload-artifact/merge@v4
      with:
        name: ${{ matrix.artifact }}
        pattern: "${{ matrix.artifact }}-*"
        delete-merged: true
      # if we are re-running a job in a subsequent attempt, some of the other artifacts may not exist in this attempt (e.g. notebooks, if only non-notebook tests failed)
      # Unlike with plain upload-artifact, there's no way to ignore the situation where no files are found when using the v4 merge action
      # (see https://github.com/actions/upload-artifact/issues/520), so just continue on error isntead
      continue-on-error: true

  generate-lkg:
    name: "Generate updated last known good files"
    needs: [merge-artifacts]
    if: (success() || failure()) && (github.event_name == 'workflow_dispatch' && !inputs.use_lkg || github.event_name == 'schedule')
    strategy:
      matrix:
        kind: [tests, notebooks]
        include:
        - kind: tests
          pattern: tests
          output-name: lkg
        - kind: notebooks
          pattern: "notebooks-(?P<subset>[a-z]+)"
          output-name: lkg-notebook
    runs-on: ubuntu-latest
    steps:
    - name: Checkout repository
      uses: actions/checkout@v4
      with:
        ref: ${{ env.ref }}
    - name: Setup Python
      uses: actions/setup-python@v5
    - name: Download files
      uses: actions/download-artifact@v4
      with:
        name: lkg-${{ matrix.kind }}
        path: requirements
    - name: "Generate last known good versions"
      run: python .github/workflows/generate_lkg.py requirements "lkg-${{ matrix.pattern }}-(?P<os>[a-z]+)-(latest|[0-9.]+)-(?P<pyversion>[0-9.]+).txt" ${{ matrix.output-name }}.txt
    - name: "Upload last known good versions"
      uses: actions/upload-artifact@v4
      with:
        name: ${{ matrix.output-name }}
        path: ${{ matrix.output-name }}.txt
        
  merge-lkg:
    name: "Merge last known good versions"
    needs: [generate-lkg]
    if: success() || failure()
    runs-on: ubuntu-latest
    steps:
    - name: "Merge last known good versions"
      uses: actions/upload-artifact/merge@v4
      with:
        # can't use just "lkg" for the name since that artifact already exists and merge won't overwrite it even when delete-merged is true
        name: lkg-files
        pattern: "lkg*"
        delete-merged: true

  build:
    name: Build package
    needs: [eval]
    if: ${{ needs.eval.outputs.testCode == 'True' }}
    uses: ./.github/workflows/publish-package.yml
    with:
      publish: false
      environment: test
      # don't have access to env context here for some reason
      ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || null }}
      # can't use env context here so need to duplicate expression, but these are true boolean values so don't need extra string logic
      use_lkg: ${{ (github.event_name == 'workflow_dispatch' && inputs.use_lkg) || github.event_name == 'pull_request' }}

  docs:
    name: Build documentation
    needs: [eval]
    if: ${{ needs.eval.outputs.buildDocs == 'True' }}
    uses: ./.github/workflows/publish-documentation.yml
    with:
      publish: false
      environment: test
      # don't have access to env context here for some reason
      ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || null }}
      # can't use env context here so need to duplicate expression, but these are true boolean values so don't need extra string logic
      use_lkg: ${{ (github.event_name == 'workflow_dispatch' && inputs.use_lkg) || github.event_name == 'pull_request' }}
      
  verify:
    name: Verify CI checks
    needs: [lint, notebooks, tests, build, docs]
    if: always()
    runs-on: ubuntu-latest
    steps:
    - name: At least one check failed or was cancelled
      run: exit 1
      if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
    - name: All checks passed
      run: exit 0
      if: ${{ !(contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')) }}


================================================
FILE: .github/workflows/generate_lkg.py
================================================
# Copyright (c) PyWhy contributors. All rights reserved.
# Licensed under the MIT License.

import argparse
import re
from collections import defaultdict, namedtuple
from os import listdir, path

import packaging.version
from packaging.version import Version

# We have a list of requirements files, one per python version and OS.
# We want to generate a single requirements file that specifies the requirements
# for each package contained in any of those files, along with the constraints on python version
# and OS that apply to each package.

Combo = namedtuple('Combo', ['os', 'py_version'])

# For each version of a package (say numpy==0.24.1), we'll have a set of os/py_version combos
# where it was installed; the correct constraint will be the union of all these pairs.
# However, for readability we'd like to simplify that when possible to something more readable.
# For example, if numpy==0.24.1 is installed on all versions of python and all OSes, we can just say
# "numpy==0.24.1"; if it's installed on all versions of python on ubuntu, we can say
# "numpy==0.24.1; platform_system=='Linux'".


# We'll precompute a dictionary of simple constraints, mapping from the sets of combos to a string representation
# of the constraint.
# For simplicity, we won't consider all possible constraints, just some easy to generate ones.
# In the most general case we'll OR together constraints grouped by os
def simple_constraint_map(all_combos: frozenset[Combo]) -> tuple[dict[frozenset[Combo], str],
                                                                 dict[tuple[str, frozenset[Version]], str]]:
    """
    Represent simple constraints via dictionaries.

    Parameters
    ----------
    all_combos : frozenset[Combo]
        All of the possible os/py_version pairs

    Returns
    -------
    (d1, d2): tuple[dict[frozenset[Combo], str], dict[tuple[str, frozenset[Version]], str]]
        A tuple of two dictionaries.
        The first dictionary maps from a constrained set of os/py_version pairs to the string representation of the
        constraint.
        The second dictionary maps from a tuple of (os, set of py_versions) to the string representation of the
        constraint.
    """
    all_os = frozenset({combo.os for combo in all_combos})
    all_py_versions = frozenset({combo.py_version for combo in all_combos})

    # constraint_map will map from sets of os/py_version pairs to a string representation of the constraint
    # that would restrict all possible combos to just that set;
    # we'll look up the sets of os/py_version pairs that a package is installed on and use this map to generate
    # the correct constraint for that package.
    constraint_map = {}

    # first generate simple os constraints, like "platform_system=='Linux'" or "platform_system!='Linux'"
    for os in all_os:
        # Get the set of all os/py_version pairs where the os is the given os and the py_version is anything
        filtered_combos = frozenset({combo for combo in all_combos if combo.os == os})
        constraint_map[filtered_combos] = f"; platform_system=='{os}'"
        constraint_map[all_combos - filtered_combos] = f"; platform_system!='{os}'"

    # now generate simple python version constraints,
    # like "python_version=='3.8'"", "python_version!='3.8'"; "python_version<'3.8'", "python_version>'3.8'"
    for i, py_version in enumerate(sorted(all_py_versions)):
        # Get the set of all os/py_version pairs where the py_version is the given py_version and the os is anything
        filtered_combos = frozenset({combo for combo in all_combos if combo.py_version == py_version})
        constraint_map[filtered_combos] = f"; python_version=='{py_version}'"
        constraint_map[all_combos - filtered_combos] = f"; python_version!='{py_version}'"

        if i > 0:
            less_than = frozenset({combo for combo in all_combos if combo.py_version < py_version})
            constraint_map[less_than] = f"; python_version<'{py_version}'"
        # We want to use >= next version instead of > this version
        #       because otherwise we have pairs like
        #           somelib==1.2, python_version<'3.9'
        #           somelib==1.3, python_version>'3.8'
        #       which is correct but looks more confusing than
        #           somelib==1.2, python_version<'3.9'
        #           somelib==1.3, python_version>='3.9'
        if i < len(all_py_versions)-2:
            next_version = sorted(all_py_versions)[i+1]
            greater_than = frozenset({combo for combo in all_combos if combo.py_version >= next_version})
            constraint_map[greater_than] = f"; python_version>='{next_version}'"

    # if every combination is present, we don't need to add any constraint
    constraint_map[all_combos] = ""

    # generate simple per-os python version constraints
    # we include the os in the key because we might not have every combination for every os
    # (e.g. maybe macos doesn't support python 3.8, in which case there won't be a combo for that, but there might
    # be a combo for ubuntu with python 3.8; then if we see all versions of python 3.9 and up on macos, we don't need
    # any python version constraint, whereas if we see all versions of python 3.9 and up on ubuntu,
    # we still do need a constraint since 3.8 is missing")
    os_map = {}
    for os in all_os:
        for i, py_version in enumerate(all_py_versions):
            filtered_combos = frozenset({combo for combo in all_combos
                                         if combo.os == os and combo.py_version == py_version})
            os_map[(os, frozenset({py_version}))] = f"python_version=='{py_version}'"
            if i > 0 and i < len(all_py_versions)-1:
                os_map[(os, all_py_versions - frozenset({py_version}))] = f"python_version!='{py_version}'"

            if i > 0:
                os_map[(os, frozenset({py for py in all_py_versions
                                       if py < py_version}))] = f"python_version<'{py_version}'"
            if i < len(all_py_versions)-1:
                os_map[(os, frozenset({py for py in all_py_versions
                                       if py > py_version}))] = f"python_version>'{py_version}'"

        # if every combination is present, we don't need to add any constraint for that os
        os_map[(os, all_py_versions)] = ""

    return constraint_map, os_map


# Convert between GitHub Actions' platform names and Python's platform.system() names
platform_map = {'macos': 'Darwin', 'ubuntu': 'Linux', 'windows': 'Windows'}


def make_req_file(requirements_directory, regex):
    """
    Make a unified requirements file from a directory of requirements files.

    Parameters
    ----------
    requirements_directory : str
        Directory containing requirements files

    regex : str
        Regex to match requirements file names, must have named groups "os" and "pyversion"
    """
    req_regex = r'^(?P<pkg>.*?)==(?P<version>.*)$'  # parses requirements from pip freeze results
    files = listdir(requirements_directory)

    all_combos = set()

    # We'll store the requirements for each version of each package in a dictionary
    # (e.g. "numpy" -> {0.24.1 -> {Combo1, Combo2, ...}, 0.24.2 -> {Combo3, Combo4, ...}, ...})
    # each entry of the inner dictionary will become a line in the requirements file
    # (e.g. "numpy==0.24.1; platform_system=='Linux' and python_version=='3.8' or ...")
    req_dict = defaultdict(lambda: defaultdict(set))  # package -> package_version -> set of Combos

    for file in files:
        match = re.match(regex, file)
        if not match:
            print(f"Skipping {file} because it doesn't match the regex")
            continue
        os = platform_map[match.group('os')]
        py_version = packaging.version.parse(match.group('pyversion'))
        combo = Combo(os, py_version)
        all_combos.add(combo)

        # read each line of the file
        with open(path.join(requirements_directory, file)) as lines:
            for line in lines:
                match = re.search(req_regex, line)
                pkg_version = packaging.version.parse(match.group('version'))
                req_dict[match.group('pkg')][pkg_version].add(combo)

    constraint_map, os_map = simple_constraint_map(frozenset(all_combos))
    # list of all requirements, sorted by package name and version
    reqs = []
    for pkg, versions in sorted(req_dict.items()):
        for version, combos in sorted(versions.items()):
            combos = frozenset(combos)
            req = f"{pkg}=={version}"

            if combos in constraint_map:
                suffix = constraint_map[combos]

            else:
                # we don't have a simple constraint for this package, so we need to generate a more complex one
                # which will generally be of the form:
                # "(platform_system=='os1' and (python_version=='py1' or python_version=='py2') or ...) or
                #  (platform_system=='os2' and (python_version=='py3' or ...) ..."
                #
                # that is, we will OR together constraints grouped by os
                # for some oses, we might find a nice representation for their python version constraints in the os_map
                # (e.g. "python_version=='3.8'", or "python_version<'3.8'"), in which case we'll use that;
                # for others, we'll have to OR together all of the relevant individual versions
                os_constraints = []

                os_versions = defaultdict(set)  # dictionary from os to set of python versions
                for combo in combos:
                    os_versions[combo.os].add(combo.py_version)

                # for each os, generate the corresponding constraint
                for os in sorted(os_versions.keys()):
                    versions = os_versions[os]
                    os_key = (os, frozenset(os_versions[os]))
                    if os_key in os_map:
                        constraint = os_map[os_key]
                        if constraint == "":
                            os_constraints.append(f"platform_system=='{os}'")
                        else:
                            os_constraints.append(f"platform_system=='{os}' and {constraint}")
                    else:
                        version_constraint = " or ".join([f"python_version=='{py_version}'"
                                                          for py_version in sorted(os_versions[os])])
                        os_constraints.append(f"platform_system=='{os}' and ({version_constraint})")
                if len(os_constraints) == 1:  # just one os with correspondig python versions, can use it directly
                    suffix = f"; {os_constraints[0]}"
                else:  # need to OR them together
                    suffix = f"; ({') or ('.join(os_constraints)})"

            reqs.append(f"{req}{suffix}")

    return '\n'.join(reqs)


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Generate requirements files for CI')
    parser.add_argument('requirements_directory', type=str, help='Directory containing requirements files')
    parser.add_argument('regex', type=str,
                        help='Regex to match requirements file names, must have named groups "os" and "pyversion"')
    parser.add_argument('output_name', type=str, help='File to write requirements to')
    args = parser.parse_args()

    reqs = make_req_file(args.requirements_directory, args.regex)
    with open(args.output_name, 'w') as f:
        f.write(reqs)


================================================
FILE: .github/workflows/publish-documentation.yml
================================================
name: Build and publish the documentation
on:
  workflow_dispatch:
    inputs:
      publish:
        description: 'Whether to publish the documentation (as opposed to just building it)'
        required: false
        default: true
        type: boolean
      environment:
        description: 'Whether to publish to production or test environment'
        required: false
        default: prod
        type: choice
        options: [prod, test]
      ref:
        description: 'The git ref to build the documentation for'
        required: false
        default: ''
        type: string
      use_lkg:
        description: 'Whether to use the last known good versions of dependencies'
        required: false
        default: True
        type: boolean
      run_doctests:
        description: 'Whether to run doctests'
        required: false
        default: True
        type: boolean
  # annoyingly, there does not seem to be a way to share these input definitions between triggers
  workflow_call:
    inputs:
      publish:
        description: 'Whether to publish the documentation (as opposed to just building it)'
        required: false
        default: true
        type: boolean
      # choice type only supported for workflow_dispatch, not workflow_call
      environment:
        description: 'Whether to publish to production or test environment'
        required: false
        default: prod
        type: string
      ref:
        description: 'The git ref to build the documentation for'
        required: false
        default: ''
        type: string
      use_lkg:
        description: 'Whether to use the last known good versions of dependencies'
        required: false
        default: True
        type: boolean
      run_doctests:
        description: 'Whether to run doctests'
        required: false
        default: True
        type: boolean

jobs:
  create_docs:
    name: Create and publish documentation
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          ref: ${{ inputs.ref }}
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: 3.12
      - name: Ensure latest pip and setuptools
        run: python -m pip install --upgrade pip && pip install --upgrade setuptools
      - name: Install econml[all]
        run: pip install -e .[all] ${{ inputs.use_lkg && '-r lkg.txt' || '' }}
      - name: Install graphviz
        run: sudo apt-get -yq install graphviz
      - name: Build documentation
        run: pip install "sphinx~=7.0" "sphinx_rtd_theme~=2.0.0" && sphinx-build ./doc/ ./build/sphinx/html/ -W
      - name: Upload docs as artifact
        uses: actions/upload-artifact@v4
        with:
          name: docs
          path: build/sphinx/html/
      - name: Run doctests
        run: sphinx-build ./doc/ ./build/sphinx/doctest/ -b doctest
        if : ${{ inputs.run_doctests }}
        
  publish-docs:
    name: Publish documentation
    needs: create_docs
    permissions:
      id-token: write # needed to publish to Azure
    environment: ${{ inputs.environment }}
    if: ${{ inputs.publish }}
    runs-on: ubuntu-latest
    steps:
      - name: Download docs artifact
        uses: actions/download-artifact@v4
        with:
          name: docs
          path: html
      - name: Zip docs for publishing
        run: |-
          pushd html
          zip -r docs.zip *
          popd
      - name: Login to Azure
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
      - name: Deploy documentation to Azure web app
        uses: azure/webapps-deploy@v2
        with:
          app-name: ${{ inputs.environment == 'prod' && 'econml' || 'econml-dev' }}
          package: html/docs.zip


================================================
FILE: .github/workflows/publish-package.yml
================================================
name: Build and publish the package to PyPI

on:
  workflow_dispatch:
    inputs:
      publish:
        description: 'Whether to publish the package (as opposed to just building it)'
        required: false
        default: true
        type: boolean
      environment:
        description: 'Whether to publish to production PyPI or test PyPI'
        required: false
        default: prod
        type: choice
        options: [prod, test]
      ref:
        description: 'The git ref to build the package for'
        required: false
        default: ''
        type: string
      use_lkg:
          description: 'Whether to use the last known good versions of dependencies'
          required: false
          default: True
          type: boolean

  # annoyingly, there does not seem to be a way to share these input definitions between triggers
  workflow_call:
    inputs:
      publish:
        description: 'Whether to publish the package (as opposed to just building it)'
        required: false
        default: true
        type: boolean
      # choice type only supported for workflow_dispatch, not workflow_call
      environment:
        description: 'Whether to publish to production PyPI or test PyPI'
        required: false
        default: prod
        type: string
      ref:
        description: 'The git ref to build the package for'
        required: false
        default: ''
        type: string
      use_lkg:
        description: 'Whether to use the last known good versions of dependencies'
        required: false
        default: True
        type: boolean
jobs:
  build_wheels:
    name: Build wheels on ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
      fail-fast: false
    runs-on: ${{ matrix.os }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          ref: ${{ inputs.ref }}
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: 3.11
      - name: Ensure latest pip and setuptools
        run: python -m pip install --upgrade pip && pip install --upgrade setuptools
      - name: Build wheels
        run: pip install 'cibuildwheel < 4' && python -m cibuildwheel --output-dir dist
        env:
          CIBW_BUILD: ${{ inputs.use_lkg && 'cp3{9,10,11,12,13}-*' || 'cp3*' }}
          CIBW_SKIP: "*musl* *win32 *i686"
      - name: Upload wheels as artifact
        uses: actions/upload-artifact@v4
        with:
          name: dist-${{ matrix.os }}
          path: dist/
  build_sdist:
    name: Build sdist
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          ref: ${{ inputs.ref }}
      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: 3.12
      - name: Ensure latest pip and setuptools
        run: python -m pip install --upgrade pip && pip install --upgrade setuptools
      - name: Install econml[all]
        run: pip install -e .[all] ${{ inputs.use_lkg && '-r lkg.txt' || '' }}
      - name: Build sdist
        run: python setup.py sdist
      - name: Upload sdist as artifact
        uses: actions/upload-artifact@v4
        with:
          name: dist-sdist
          path: dist/

  merge:
    name: Merge artifacts
    needs: [build_wheels, build_sdist]
    runs-on: ubuntu-latest
    steps:
      - name: "Merge artifacts"
        uses: actions/upload-artifact/merge@v4
        with:
          name: dist
          pattern: dist-*
          delete-merged: true

  publish:
    name: Publish to PyPI or TestPyPI
    needs: [merge]
    permissions:
      id-token: write
    environment: ${{ inputs.environment }}
    if: ${{ inputs.publish }}
    runs-on: ubuntu-latest
    steps:
      - name: Download wheels and sdist
        uses: actions/download-artifact@v4
        with:
          name: dist
          path: dist/
      - name: Upload wheels and sdist to package index
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          repository-url: ${{ inputs.environment == 'test' && 'https://test.pypi.org/legacy/' || '' }}


================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# Tex
*.aux
*.bbl
*.blg
*.log
*.out
*.synctex.gz

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
test-results.xml

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# dotenv
.env

# virtualenv
.venv
venv/
ENV/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/

# images
double_ml/proto/*.png
double_ml/proto/*.jpg

# sphinx autosummaries 
doc/_autosummary/

# compiled C files
*.c

================================================
FILE: .pre-commit-config.yaml
================================================
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
  # Ruff version.
  rev: v0.12.2
  hooks:
    # Run the linter.
    - id: ruff
      args: [ --fix ]
      types_or: [python, pyi, jupyter]
    # Run the formatter.
    # - id: ruff-format
    #   types_or: [python, pyi, jupyter]

================================================
FILE: LICENSE
================================================
    MIT License

    Copyright (c) PyWhy contributors. All rights reserved.

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all
    copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE


Parts of this software, in particular code contained in the modules econml.tree and
econml.grf contain files that are forks from the scikit-learn git repository, or code
snippets from that repository:
https://github.com/scikit-learn/scikit-learn
published under the following License.

BSD 3-Clause License

Copyright (c) 2007-2020 The scikit-learn developers.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of the copyright holder nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

================================================
FILE: README.md
================================================
[![Build status](https://github.com/py-why/EconML/actions/workflows/ci.yml/badge.svg)](https://github.com/py-why/EconML/actions/workflows/ci.yml)
[![PyPI version](https://img.shields.io/pypi/v/econml.svg)](https://pypi.org/project/econml/)
[![PyPI wheel](https://img.shields.io/pypi/wheel/econml.svg)](https://pypi.org/project/econml/)
[![Supported Python versions](https://img.shields.io/pypi/pyversions/econml.svg)](https://pypi.org/project/econml/)

<h1>
<a href="https://www.pywhy.org/EconML/">
<img src="doc/econml-logo-icon.png" width="80px" align="left" style="margin-right: 10px;", alt="econml-logo"> 
</a> EconML: A Python Package for ML-Based Heterogeneous Treatment Effects Estimation
</h1>

**EconML** is a Python package for estimating heterogeneous treatment effects from observational data via machine learning. This package was designed and built as part of the [ALICE project](https://www.microsoft.com/en-us/research/project/alice/) at Microsoft Research with the goal to combine state-of-the-art machine learning 
techniques with econometrics to bring automation to complex causal inference problems. The promise of EconML:

* Implement recent techniques in the literature at the intersection of econometrics and machine learning
* Maintain flexibility in modeling the effect heterogeneity (via techniques such as random forests, boosting, lasso and neural nets), while preserving the causal interpretation of the learned model and often offering valid confidence intervals
* Use a unified API
* Build on standard Python packages for Machine Learning and Data Analysis

One of the biggest promises of machine learning is to automate decision making in a multitude of domains. At the core of many data-driven personalized decision scenarios is the estimation of heterogeneous treatment effects: what is the causal effect of an intervention on an outcome of interest for a sample with a particular set of features? In a nutshell, this toolkit is designed to measure the causal effect of some treatment variable(s) `T` on an outcome 
variable `Y`, controlling for a set of features `X, W` and how does that effect vary as a function of `X`. The methods implemented are applicable even with observational (non-experimental or historical) datasets. For the estimation results to have a causal interpretation, some methods assume no unobserved confounders (i.e. there is no unobserved variable not included in `X, W` that simultaneously has an effect on both `T` and `Y`), while others assume access to an instrument `Z` (i.e. an observed variable `Z` that has an effect on the treatment `T` but no direct effect on the outcome `Y`). Most methods provide confidence intervals and inference results.

For detailed information about the package, consult the documentation at https://www.pywhy.org/EconML/.

For information on use cases and background material on causal inference and heterogeneous treatment effects see our webpage at https://www.microsoft.com/en-us/research/project/econml/

<details>
<summary><strong><em>Table of Contents</em></strong></summary>

- [News](#news)
- [Getting Started](#getting-started)
  - [Installation](#installation)
  - [Usage Examples](#usage-examples)
    - [Estimation Methods](#estimation-methods)
    - [Interpretability](#interpretability)
    - [Causal Model Selection and Cross-Validation](#causal-model-selection-and-cross-validation)
    - [Inference](#inference)
    - [Policy Learning](#policy-learning)
- [For Developers](#for-developers)
  - [Running the tests](#running-the-tests)
  - [Generating the documentation](#generating-the-documentation)
- [Blogs and Publications](#blogs-and-publications)
- [Citation](#citation)
- [Contributing and Feedback](#contributing-and-feedback)
- [Community](#community)
- [References](#references)

</details>

# News

If you'd like to contribute to this project, see the [Help Wanted](#finding-issues-to-help-with) section below.

**July 10, 2025:** Release v0.16.0, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.16.0)

<details><summary>Previous releases</summary>

**July 3, 2024:** Release v0.15.1, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.15.1)

**February 12, 2024:** Release v0.15.0, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.15.0)

**November 11, 2023:** Release v0.15.0b1, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.15.0b1)

**May 19, 2023:** Release v0.14.1, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.14.1)

**November 16, 2022:** Release v0.14.0, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.14.0)

**June 17, 2022:** Release v0.13.1, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.13.1)

**January 31, 2022:** Release v0.13.0, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.13.0)

**August 13, 2021:** Release v0.12.0, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.12.0)

**August 5, 2021:** Release v0.12.0b6, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.12.0b6)

**August 3, 2021:** Release v0.12.0b5, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.12.0b5)

**July 9, 2021:** Release v0.12.0b4, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.12.0b4)

**June 25, 2021:** Release v0.12.0b3, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.12.0b3)

**June 18, 2021:** Release v0.12.0b2, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.12.0b2)

**June 7, 2021:** Release v0.12.0b1, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.12.0b1)

**May 18, 2021:** Release v0.11.1, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.11.1)

**May 8, 2021:** Release v0.11.0, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.11.0)

**March 22, 2021:** Release v0.10.0, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.10.0)

**March 11, 2021:** Release v0.9.2, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.9.2)

**March 3, 2021:** Release v0.9.1, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.9.1)

**February 20, 2021:** Release v0.9.0, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.9.0)

**January 20, 2021:** Release v0.9.0b1, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.9.0b1)

**November 20, 2020:** Release v0.8.1, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.8.1)

**November 18, 2020:** Release v0.8.0, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.8.0)

**September 4, 2020:** Release v0.8.0b1, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.8.0b1)

**March 6, 2020:** Release v0.7.0, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.7.0)

**February 18, 2020:** Release v0.7.0b1, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.7.0b1)

**January 10, 2020:** Release v0.6.1, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.6.1)

**December 6, 2019:** Release v0.6, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.6)

**November 21, 2019:** Release v0.5, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.5). 

**June 3, 2019:** Release v0.4, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.4). 

**May 3, 2019:** Release v0.3, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.3).

**April 10, 2019:** Release v0.2, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.2).

**March 6, 2019:** Release v0.1, welcome to have a try and provide feedback.

</details>

# Getting Started

## Installation

Install the latest release from [PyPI](https://pypi.org/project/econml/):
```
pip install econml
```
To install from source, see [For Developers](#for-developers) section below.

## Usage Examples
### Estimation Methods

<details>
  <summary>Double Machine Learning (aka RLearner) (click to expand)</summary>

  * Linear final stage

  ```Python
  from econml.dml import LinearDML
  from sklearn.linear_model import LassoCV
  from econml.inference import BootstrapInference

  est = LinearDML(model_y=LassoCV(), model_t=LassoCV())
  ### Estimate with OLS confidence intervals
  est.fit(Y, T, X=X, W=W) # W -> high-dimensional confounders, X -> features
  treatment_effects = est.effect(X_test)
  lb, ub = est.effect_interval(X_test, alpha=0.05) # OLS confidence intervals

  ### Estimate with bootstrap confidence intervals
  est.fit(Y, T, X=X, W=W, inference='bootstrap')  # with default bootstrap parameters
  est.fit(Y, T, X=X, W=W, inference=BootstrapInference(n_bootstrap_samples=100))  # or customized
  lb, ub = est.effect_interval(X_test, alpha=0.05) # Bootstrap confidence intervals
  ```

  * Sparse linear final stage

  ```Python
  from econml.dml import SparseLinearDML
  from sklearn.linear_model import LassoCV

  est = SparseLinearDML(model_y=LassoCV(), model_t=LassoCV())
  est.fit(Y, T, X=X, W=W) # X -> high dimensional features
  treatment_effects = est.effect(X_test)
  lb, ub = est.effect_interval(X_test, alpha=0.05) # Confidence intervals via debiased lasso
  ```

  * Generic Machine Learning last stage
  
  ```Python
  from econml.dml import NonParamDML
  from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier

  est = NonParamDML(model_y=RandomForestRegressor(),
                    model_t=RandomForestClassifier(),
                    model_final=RandomForestRegressor(),
                    discrete_treatment=True)
  est.fit(Y, T, X=X, W=W) 
  treatment_effects = est.effect(X_test)
  ```

</details>

<details>
  <summary>Dynamic Double Machine Learning (click to expand)</summary>

  ```Python
  from econml.panel.dml import DynamicDML
  # Use defaults
  est = DynamicDML()
  # Or specify hyperparameters
  est = DynamicDML(model_y=LassoCV(cv=3), 
                   model_t=LassoCV(cv=3), 
                   cv=3)
  est.fit(Y, T, X=X, W=None, groups=groups, inference="auto")
  # Effects
  treatment_effects = est.effect(X_test)
  # Confidence intervals
  lb, ub = est.effect_interval(X_test, alpha=0.05)
  ```
</details>

<details>
  <summary>Causal Forests (click to expand)</summary>

  ```Python
  from econml.dml import CausalForestDML
  from sklearn.linear_model import LassoCV
  # Use defaults
  est = CausalForestDML()
  # Or specify hyperparameters
  est = CausalForestDML(criterion='het', n_estimators=500,       
                        min_samples_leaf=10, 
                        max_depth=10, max_samples=0.5,
                        discrete_treatment=False,
                        model_t=LassoCV(), model_y=LassoCV())
  est.fit(Y, T, X=X, W=W)
  treatment_effects = est.effect(X_test)
  # Confidence intervals via Bootstrap-of-Little-Bags for forests
  lb, ub = est.effect_interval(X_test, alpha=0.05)
  ```
</details>


<details>
  <summary>Orthogonal Random Forests (click to expand)</summary>

  ```Python
  from econml.orf import DMLOrthoForest, DROrthoForest
  from econml.sklearn_extensions.linear_model import WeightedLasso, WeightedLassoCV
  # Use defaults
  est = DMLOrthoForest()
  est = DROrthoForest()
  # Or specify hyperparameters
  est = DMLOrthoForest(n_trees=500, min_leaf_size=10,
                       max_depth=10, subsample_ratio=0.7,
                       lambda_reg=0.01,
                       discrete_treatment=False,
                       model_T=WeightedLasso(alpha=0.01), model_Y=WeightedLasso(alpha=0.01),
                       model_T_final=WeightedLassoCV(cv=3), model_Y_final=WeightedLassoCV(cv=3))
  est.fit(Y, T, X=X, W=W)
  treatment_effects = est.effect(X_test)
  # Confidence intervals via Bootstrap-of-Little-Bags for forests
  lb, ub = est.effect_interval(X_test, alpha=0.05)
  ```
</details>

<details>

<summary>Meta-Learners (click to expand)</summary>
  
  * XLearner

  ```Python
  from econml.metalearners import XLearner
  from sklearn.ensemble import GradientBoostingClassifier, GradientBoostingRegressor

  est = XLearner(models=GradientBoostingRegressor(),
                propensity_model=GradientBoostingClassifier(),
                cate_models=GradientBoostingRegressor())
  est.fit(Y, T, X=np.hstack([X, W]))
  treatment_effects = est.effect(np.hstack([X_test, W_test]))

  # Fit with bootstrap confidence interval construction enabled
  est.fit(Y, T, X=np.hstack([X, W]), inference='bootstrap')
  treatment_effects = est.effect(np.hstack([X_test, W_test]))
  lb, ub = est.effect_interval(np.hstack([X_test, W_test]), alpha=0.05) # Bootstrap CIs
  ```
  
  * SLearner

  ```Python
  from econml.metalearners import SLearner
  from sklearn.ensemble import GradientBoostingRegressor

  est = SLearner(overall_model=GradientBoostingRegressor())
  est.fit(Y, T, X=np.hstack([X, W]))
  treatment_effects = est.effect(np.hstack([X_test, W_test]))
  ```

  * TLearner

  ```Python
  from econml.metalearners import TLearner
  from sklearn.ensemble import GradientBoostingRegressor

  est = TLearner(models=GradientBoostingRegressor())
  est.fit(Y, T, X=np.hstack([X, W]))
  treatment_effects = est.effect(np.hstack([X_test, W_test]))
  ```
</details>

<details>
<summary>Doubly Robust Learners (click to expand)
</summary>

* Linear final stage

```Python
from econml.dr import LinearDRLearner
from sklearn.ensemble import GradientBoostingRegressor, GradientBoostingClassifier

est = LinearDRLearner(model_propensity=GradientBoostingClassifier(),
                      model_regression=GradientBoostingRegressor())
est.fit(Y, T, X=X, W=W)
treatment_effects = est.effect(X_test)
lb, ub = est.effect_interval(X_test, alpha=0.05)
```

* Sparse linear final stage

```Python
from econml.dr import SparseLinearDRLearner
from sklearn.ensemble import GradientBoostingRegressor, GradientBoostingClassifier

est = SparseLinearDRLearner(model_propensity=GradientBoostingClassifier(),
                            model_regression=GradientBoostingRegressor())
est.fit(Y, T, X=X, W=W)
treatment_effects = est.effect(X_test)
lb, ub = est.effect_interval(X_test, alpha=0.05)
```

* Nonparametric final stage

```Python
from econml.dr import ForestDRLearner
from sklearn.ensemble import GradientBoostingRegressor, GradientBoostingClassifier

est = ForestDRLearner(model_propensity=GradientBoostingClassifier(),
                      model_regression=GradientBoostingRegressor())
est.fit(Y, T, X=X, W=W) 
treatment_effects = est.effect(X_test)
lb, ub = est.effect_interval(X_test, alpha=0.05)
```
</details>

<details>
<summary>Double Machine Learning with Instrumental Variables (click to expand)</summary>

* Orthogonal instrumental variable learner

```Python
from econml.iv.dml import OrthoIV

est = OrthoIV(projection=False, 
              discrete_treatment=True, 
              discrete_instrument=True)
est.fit(Y, T, Z=Z, X=X, W=W)
treatment_effects = est.effect(X_test)
lb, ub = est.effect_interval(X_test, alpha=0.05) # OLS confidence intervals
```
* Nonparametric double machine learning with instrumental variable

```Python
from econml.iv.dml import NonParamDMLIV

est = NonParamDMLIV(discrete_treatment=True, 
                    discrete_instrument=True,
                    model_final=RandomForestRegressor())
est.fit(Y, T, Z=Z, X=X, W=W) # no analytical confidence interval available
treatment_effects = est.effect(X_test)
```
</details>

<details>
<summary>Doubly Robust Machine Learning with Instrumental Variables (click to expand)</summary>

* Linear final stage
```Python
from econml.iv.dr import LinearDRIV

est = LinearDRIV(discrete_instrument=True, discrete_treatment=True)
est.fit(Y, T, Z=Z, X=X, W=W)
treatment_effects = est.effect(X_test)
lb, ub = est.effect_interval(X_test, alpha=0.05) # OLS confidence intervals
```

* Sparse linear final stage

```Python
from econml.iv.dr import SparseLinearDRIV

est = SparseLinearDRIV(discrete_instrument=True, discrete_treatment=True)
est.fit(Y, T, Z=Z, X=X, W=W)
treatment_effects = est.effect(X_test)
lb, ub = est.effect_interval(X_test, alpha=0.05) # Debiased lasso confidence intervals
```

* Nonparametric final stage
```Python
from econml.iv.dr import ForestDRIV

est = ForestDRIV(discrete_instrument=True, discrete_treatment=True)
est.fit(Y, T, Z=Z, X=X, W=W)
treatment_effects = est.effect(X_test)
# Confidence intervals via Bootstrap-of-Little-Bags for forests
lb, ub = est.effect_interval(X_test, alpha=0.05) 
```

* Linear intent-to-treat (discrete instrument, discrete treatment)

```Python
from econml.iv.dr import LinearIntentToTreatDRIV
from sklearn.ensemble import GradientBoostingRegressor, GradientBoostingClassifier

est = LinearIntentToTreatDRIV(model_y_xw=GradientBoostingRegressor(),
                              model_t_xwz=GradientBoostingClassifier(),
                              flexible_model_effect=GradientBoostingRegressor())
est.fit(Y, T, Z=Z, X=X, W=W)
treatment_effects = est.effect(X_test)
lb, ub = est.effect_interval(X_test, alpha=0.05) # OLS confidence intervals
```
</details>

See the <a href="#references">References</a> section for more details.

### Interpretability
<details>
  <summary>Tree Interpreter of the CATE model (click to expand)</summary>
  
  ```Python
  from econml.cate_interpreter import SingleTreeCateInterpreter
  intrp = SingleTreeCateInterpreter(include_model_uncertainty=True, max_depth=2, min_samples_leaf=10)
  # We interpret the CATE model's behavior based on the features used for heterogeneity
  intrp.interpret(est, X)
  # Plot the tree
  plt.figure(figsize=(25, 5))
  intrp.plot(feature_names=['A', 'B', 'C', 'D'], fontsize=12)
  plt.show()
  ```
  ![image](notebooks/images/dr_cate_tree.png)
  
</details>

<details>
  <summary>Policy Interpreter of the CATE model (click to expand)</summary>

  ```Python
  from econml.cate_interpreter import SingleTreePolicyInterpreter
  # We find a tree-based treatment policy based on the CATE model
  intrp = SingleTreePolicyInterpreter(risk_level=0.05, max_depth=2, min_samples_leaf=1,min_impurity_decrease=.001)
  intrp.interpret(est, X, sample_treatment_costs=0.2)
  # Plot the tree
  plt.figure(figsize=(25, 5))
  intrp.plot(feature_names=['A', 'B', 'C', 'D'], fontsize=12)
  plt.show()
  ```
  ![image](notebooks/images/dr_policy_tree.png)

</details>

<details>
  <summary>SHAP values for the CATE model (click to expand)</summary>

  ```Python
  import shap
  from econml.dml import CausalForestDML
  est = CausalForestDML()
  est.fit(Y, T, X=X, W=W)
  shap_values = est.shap_values(X)
  shap.summary_plot(shap_values['Y0']['T0'])
  ```

</details>


### Causal Model Selection and Cross-Validation


<details>
  <summary>Causal model selection with the `RScorer` (click to expand)</summary>

  ```Python
  from econml.score import RScorer

  # split data in train-validation
  X_train, X_val, T_train, T_val, Y_train, Y_val = train_test_split(X, T, y, test_size=.4)

  # define list of CATE estimators to select among
  reg = lambda: RandomForestRegressor(min_samples_leaf=20)
  clf = lambda: RandomForestClassifier(min_samples_leaf=20)
  models = [('ldml', LinearDML(model_y=reg(), model_t=clf(), discrete_treatment=True,
                               cv=3)),
            ('xlearner', XLearner(models=reg(), cate_models=reg(), propensity_model=clf())),
            ('dalearner', DomainAdaptationLearner(models=reg(), final_models=reg(), propensity_model=clf())),
            ('slearner', SLearner(overall_model=reg())),
            ('drlearner', DRLearner(model_propensity=clf(), model_regression=reg(),
                                    model_final=reg(), cv=3)),
            ('rlearner', NonParamDML(model_y=reg(), model_t=clf(), model_final=reg(),
                                     discrete_treatment=True, cv=3)),
            ('dml3dlasso', DML(model_y=reg(), model_t=clf(),
                               model_final=LassoCV(cv=3, fit_intercept=False),
                               discrete_treatment=True,
                               featurizer=PolynomialFeatures(degree=3),
                               cv=3))
  ]

  # fit cate models on train data
  models = [(name, mdl.fit(Y_train, T_train, X=X_train)) for name, mdl in models]

  # score cate models on validation data
  scorer = RScorer(model_y=reg(), model_t=clf(),
                   discrete_treatment=True, cv=3, mc_iters=2, mc_agg='median')
  scorer.fit(Y_val, T_val, X=X_val)
  rscore = [scorer.score(mdl) for _, mdl in models]
  # select the best model
  mdl, _ = scorer.best_model([mdl for _, mdl in models])
  # create weighted ensemble model based on score performance
  mdl, _ = scorer.ensemble([mdl for _, mdl in models])
  ```

</details>

<details>
  <summary>First Stage Model Selection (click to expand)</summary>

EconML's cross-fitting estimators provide built-in functionality for first-stage model selection.  This support can work with existing sklearn model selection classes such as `LassoCV` or `GridSearchCV`, or you can pass a list of models to choose the best from among them when cross-fitting.

```Python
from econml.dml import LinearDML
from sklearn import clone
from sklearn.ensemble import RandomForestRegressor
from sklearn.linear_model import LassoCV
from sklearn.model_selection import GridSearchCV

cv_model = GridSearchCV(
              estimator=RandomForestRegressor(),
              param_grid={
                  "max_depth": [3, None],
                  "n_estimators": (10, 30, 50, 100, 200),
                  "max_features": (2, 4, 6),
              },
              cv=5,
           )

est = LinearDML(model_y=cv_model, # use sklearn's grid search to select the best Y model 
                model_t=[RandomForestRegressor(), LassoCV()]) # use built-in model selection to choose between forest and linear models for T model
```


</details>

### Inference

Whenever inference is enabled, then one can get a more structure `InferenceResults` object with more elaborate inference information, such
as p-values and z-statistics. When the CATE model is linear and parametric, then a `summary()` method is also enabled. For instance:

  ```Python
  from econml.dml import LinearDML
  # Use defaults
  est = LinearDML()
  est.fit(Y, T, X=X, W=W)
  # Get the effect inference summary, which includes the standard error, z test score, p value, and confidence interval given each sample X[i]
  est.effect_inference(X_test).summary_frame(alpha=0.05, value=0, decimals=3)
  # Get the population summary for the entire sample X
  est.effect_inference(X_test).population_summary(alpha=0.1, value=0, decimals=3, tol=0.001)
  #  Get the parameter inference summary for the final model
  est.summary()
  ```
  
  <details><summary>Example Output (click to expand)</summary>
  
  ```Python
  # Get the effect inference summary, which includes the standard error, z test score, p value, and confidence interval given each sample X[i]
  est.effect_inference(X_test).summary_frame(alpha=0.05, value=0, decimals=3)
  ```
  ![image](notebooks/images/summary_frame.png)
  
  ```Python
  # Get the population summary for the entire sample X
  est.effect_inference(X_test).population_summary(alpha=0.1, value=0, decimals=3, tol=0.001)
  ```
  ![image](notebooks/images/population_summary.png)
  
  ```Python
  #  Get the parameter inference summary for the final model
  est.summary()
  ```
  ![image](notebooks/images/summary.png)
  
  </details>
  

### Policy Learning

You can also perform direct policy learning from observational data, using the doubly robust method for offline
policy learning. These methods directly predict a recommended treatment, without internally fitting an explicit
model of the conditional average treatment effect.

<details>
  <summary>Doubly Robust Policy Learning (click to expand)</summary>

```Python
from econml.policy import DRPolicyTree, DRPolicyForest
from sklearn.ensemble import RandomForestRegressor

# fit a single binary decision tree policy
policy = DRPolicyTree(max_depth=1, min_impurity_decrease=0.01, honest=True)
policy.fit(y, T, X=X, W=W)
# predict the recommended treatment
recommended_T = policy.predict(X)
# plot the binary decision tree
plt.figure(figsize=(10,5))
policy.plot()
# get feature importances
importances = policy.feature_importances_

# fit a binary decision forest
policy = DRPolicyForest(max_depth=1, min_impurity_decrease=0.01, honest=True)
policy.fit(y, T, X=X, W=W)
# predict the recommended treatment
recommended_T = policy.predict(X)
# plot the first tree in the ensemble
plt.figure(figsize=(10,5))
policy.plot(0)
# get feature importances
importances = policy.feature_importances_
```


  ![image](images/policy_tree.png)
</details>

To see more complex examples, go to the [notebooks](https://github.com/py-why/EconML/tree/main/notebooks) section of the repository. For a more detailed description of the treatment effect estimation algorithms, see the EconML [documentation](https://www.pywhy.org/EconML/).

# For Developers

You can get started by cloning this repository. We use 
[setuptools](https://setuptools.readthedocs.io/en/latest/index.html) for building and distributing our package.
We rely on some recent features of setuptools, so make sure to upgrade to a recent version with
`pip install setuptools --upgrade`.  Then from your local copy of the repository you can run `pip install -e .` to get started (but depending on what you're doing you might want to install with extras instead, like `pip install -e .[plt]` if you want to use matplotlib integration, or you can use  `pip install -e .[all]` to include all extras).

## Pre-commit hooks

We use the [pre-commit](https://pre-commit.com/) framework to enforce code style and run checks before every commit. To install the pre-commit hooks, make sure you have pre-commit installed (`pip install pre-commit`) and then run `pre-commit install` in the root of the repository. This will install the hooks and run them automatically before every commit. If you want to run the hooks manually, you can run `pre-commit run --all-files`.

## Finding issues to help with

If you're looking to contribute to the project, we have a number of issues tagged with the [`up for grabs`](https://github.com/py-why/EconML/issues?q=is%3Aopen+is%3Aissue+label%3A%22up+for+grabs%22) and [`help wanted`](https://github.com/py-why/EconML/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) labels. "Up for grabs" issues are ones that we think that people without a lot of experience in our codebase may be able to help with, while "Help wanted" issues are valuable improvements to the library that our team currently does not have time to prioritize where we would greatly appreciate community-initiated PRs, but which might be more involved.

## Running the tests

This project uses [pytest](https://docs.pytest.org/) to run tests for continuous integration.  It is also possible to use `pytest` to run tests locally, but this isn't recommended because it will take an extremely long time and some tests are specific to certain environments or scenarios that have additional dependencies.  However, if you'd like to do this anyway, to run all tests locally after installing the package you can use `pip install pytest pytest-xdist pytest-cov coverage[toml]` (as well as `pip install jupyter jupyter-client nbconvert nbformat seaborn xgboost tqdm` for the dependencies to run all of our notebooks as tests) followed by `python -m pytest`.

Because running all tests can be very time-consuming, we recommend running only the relevant subset of tests when developing locally.  The easiest way to do this is to rely on `pytest`'s compatibility with `unittest`, so you can just run `python -m unittest econml.tests.test_module` to run all tests in a given module, or `python -m unittest econml.tests.test_module.TestClass` to run all tests in a given class.  You can also run `python -m unittest econml.tests.test_module.TestClass.test_method` to run a single test method.

## Generating the documentation

This project's documentation is generated via [Sphinx](https://www.sphinx-doc.org/en/main/index.html).  Note that we use [graphviz](https://graphviz.org/)'s 
`dot` application to produce some of the images in our documentation, so you should make sure that `dot` is installed and in your path.

To generate a local copy of the documentation from a clone of this repository, just run `python setup.py build_sphinx -W -E -a`, which will build the documentation and place it under the `build/sphinx/html` path. 

The reStructuredText files that make up the documentation are stored in the [docs directory](https://github.com/py-why/EconML/tree/main/doc); module documentation is automatically generated by the Sphinx build process.

## Release process

We use GitHub Actions to build and publish the package and documentation.  To create a new release, an admin should perform the following steps:

1. Update the version number in `econml/_version.py` and add a mention of the new version in the news section of this file and commit the changes.
2. Manually run the publish_package.yml workflow to build and publish the package to PyPI.
3. Manually run the publish_docs.yml workflow to build and publish the documentation.
4. Under https://github.com/py-why/EconML/releases, create a new release with a corresponding tag, and update the release notes.

# Blogs and Publications

* May 2021: [Be Careful When Interpreting Predictive Models in Search of Causal Insights](https://towardsdatascience.com/be-careful-when-interpreting-predictive-models-in-search-of-causal-insights-e68626e664b6)

* June 2019: [Treatment Effects with Instruments paper](https://arxiv.org/pdf/1905.10176.pdf)

* May 2019: [Open Data Science Conference Workshop](https://odsc.com/speakers/machine-learning-estimation-of-heterogeneous-treatment-effect-the-microsoft-econml-library/) 

* 2018: [Orthogonal Random Forests paper](http://proceedings.mlr.press/v97/oprescu19a.html)

* 2017: [DeepIV paper](http://proceedings.mlr.press/v70/hartford17a/hartford17a.pdf)

# Citation

If you use EconML in your research, please cite us as follows:

   Keith Battocchi, Eleanor Dillon, Maggie Hei, Greg Lewis, Paul Oka, Miruna Oprescu, Vasilis Syrgkanis. **EconML: A Python Package for ML-Based Heterogeneous Treatment Effects Estimation.** https://github.com/py-why/EconML, 2019. Version 0.x.

BibTex:

```
@misc{econml,
  author={Keith Battocchi, Eleanor Dillon, Maggie Hei, Greg Lewis, Paul Oka, Miruna Oprescu, Vasilis Syrgkanis},
  title={{EconML}: {A Python Package for ML-Based Heterogeneous Treatment Effects Estimation}},
  howpublished={https://github.com/py-why/EconML},
  note={Version 0.x},
  year={2019}
}
```

# Contributing and Feedback

This project welcomes contributions and suggestions.  We use the [DCO bot](https://github.com/apps/dco) to enforce a [Developer Certificate of Origin](https://developercertificate.org/) which requires users to sign-off on their commits.  This is a simple way to certify that you wrote or otherwise have the right to submit the code you are contributing to the project.  Git provides a `-s` command line option to include this automatically when you commit via `git commit`.

If you forget to sign one of your commits, the DCO bot will provide specific instructions along with the failed check; alternatively you can use `git commit --amend -s` to add the sign-off to your last commit if you forgot it or `git rebase --signoff` to sign all of the commits in the branch, after which you can force push the changes to your branch with `git push --force-with-lease`.

This project has adopted the [PyWhy Code of Conduct](https://github.com/py-why/governance/blob/main/CODE-OF-CONDUCT.md).

# Community

<a href="https://pywhy.org/">
<img src="doc/spec/img/pywhy-logo.png" width="80px" align="left" style="margin-right: 10px;", alt="pywhy-logo">
</a>

EconML is a part of [PyWhy](https://www.pywhy.org/), an organization with a mission to build an open-source ecosystem for causal machine learning.

PyWhy also has a [Discord](https://discord.gg/cSBGb3vsZb), which serves as a space for like-minded casual machine learning researchers and practitioners of all experience levels to come together to ask and answer questions, discuss new features, and share ideas.

We invite you to join us at regular office hours and community calls in the Discord.

# References

Athey, Susan, and Stefan Wager.
**Policy learning with observational data.**
[*Econometrica 89.1, 133-161*](https://doi.org/10.3982/ECTA15732), 2021.

X Nie, S Wager.
**Quasi-Oracle Estimation of Heterogeneous Treatment Effects.**
[*Biometrika 108.2, 299-319*](https://doi.org/10.1093/biomet/asaa076), 2021.

V. Syrgkanis, V. Lei, M. Oprescu, M. Hei, K. Battocchi, G. Lewis.
**Machine Learning Estimation of Heterogeneous Treatment Effects with Instruments.**
[*Proceedings of the 33rd Conference on Neural Information Processing Systems (NeurIPS)*](https://arxiv.org/abs/1905.10176), 2019.
**(Spotlight Presentation)**

D. Foster, V. Syrgkanis.
**Orthogonal Statistical Learning.**
[*Proceedings of the 32nd Annual Conference on Learning Theory (COLT)*](https://arxiv.org/pdf/1901.09036.pdf), 2019.
**(Best Paper Award)**

M. Oprescu, V. Syrgkanis and Z. S. Wu.
**Orthogonal Random Forest for Causal Inference.**
[*Proceedings of the 36th International Conference on Machine Learning (ICML)*](http://proceedings.mlr.press/v97/oprescu19a.html), 2019.

S. Künzel, J. Sekhon, J. Bickel and B. Yu.
**Metalearners for estimating heterogeneous treatment effects using machine learning.**
[*Proceedings of the national academy of sciences, 116(10), 4156-4165*](https://www.pnas.org/content/116/10/4156), 2019.

S. Athey, J. Tibshirani, S. Wager.
**Generalized random forests.**
[*Annals of Statistics, 47, no. 2, 1148--1178*](https://projecteuclid.org/euclid.aos/1547197251), 2019.

V. Chernozhukov, D. Nekipelov, V. Semenova, V. Syrgkanis.
**Plug-in Regularized Estimation of High-Dimensional Parameters in Nonlinear Semiparametric Models.**
[*Arxiv preprint arxiv:1806.04823*](https://arxiv.org/abs/1806.04823), 2018.

S. Wager, S. Athey.
**Estimation and Inference of Heterogeneous Treatment Effects using Random Forests.**
[*Journal of the American Statistical Association, 113:523, 1228-1242*](https://www.tandfonline.com/doi/citedby/10.1080/01621459.2017.1319839), 2018.

Jason Hartford, Greg Lewis, Kevin Leyton-Brown, and Matt Taddy. **Deep IV: A flexible approach for counterfactual prediction.** [*Proceedings of the 34th International Conference on Machine Learning, ICML'17*](http://proceedings.mlr.press/v70/hartford17a/hartford17a.pdf), 2017.

V. Chernozhukov, D. Chetverikov, M. Demirer, E. Duflo, C. Hansen, and a. W. Newey. **Double Machine Learning for Treatment and Causal Parameters.** [*ArXiv preprint arXiv:1608.00060*](https://arxiv.org/abs/1608.00060), 2016.

Dudik, M., Erhan, D., Langford, J., & Li, L.
**Doubly robust policy evaluation and optimization.**
[*Statistical Science, 29(4), 485-511*](https://projecteuclid.org/journals/statistical-science/volume-29/issue-4/Doubly-Robust-Policy-Evaluation-and-Optimization/10.1214/14-STS500.full), 2014.


================================================
FILE: SECURITY.md
================================================
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.7 BLOCK -->

## Security

Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).

If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.

## Reporting Security Issues

**Please do not report security vulnerabilities through public GitHub issues.**

Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).

If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com).  If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).

You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 

Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:

  * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
  * Full paths of source file(s) related to the manifestation of the issue
  * The location of the affected source code (tag/branch/commit or direct URL)
  * Any special configuration required to reproduce the issue
  * Step-by-step instructions to reproduce the issue
  * Proof-of-concept or exploit code (if possible)
  * Impact of the issue, including how an attacker might exploit the issue

This information will help us triage your report more quickly.

If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.

## Preferred Languages

We prefer all communications to be in English.

## Policy

Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).

<!-- END MICROSOFT SECURITY.MD BLOCK -->


================================================
FILE: doc/conf.py
================================================
# -*- coding: utf-8 -*-
#
# Configuration file for the Sphinx documentation builder.
#
# This file does only contain a selection of the most common options. For a
# full list see the documentation:
# http://www.sphinx-doc.org/en/main/config

# -- Path setup --------------------------------------------------------------

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import sys
import doctest
import econml
sys.path.insert(0, os.path.abspath('econml'))


# -- Project information -----------------------------------------------------

project = 'econml'
copyright = '2023, PyWhy contributors'
author = 'PyWhy contributors'
version = econml.__version__
release = econml.__version__

# -- General configuration ---------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
    'sphinx.ext.autodoc',
    'sphinx.ext.autosummary',
    'sphinx.ext.doctest',
    'sphinx.ext.intersphinx',
    'sphinx.ext.napoleon',
    'sphinx.ext.todo',
    'sphinx.ext.coverage',
    'sphinx.ext.mathjax',
    'sphinx.ext.viewcode',
    'sphinx.ext.inheritance_diagram',
]
inheritance_graph_attrs = dict(rankdir="TB", size='"7.0, 10.0"',
                               fontsize=12, ratio='auto',
                               bgcolor='"#ffffff"', center='true', style='solid')
inheritance_node_attrs = dict(shape='ellipse', fontsize=12,
                              fontname="monspace", height=0.75)

napoleon_use_param = False
# TODO: enable type aliases
# napoleon_preprocess_types = True  # needed for type aliases to work
# napoleon_type_aliases = {
#     "array_like": ":term:`array_like`",
#     "ndarray": "~numpy.ndarray",
#     "RandomState": ":class:`~numpy.random.RandomState`",
#     "DataFrame": ":class:`~pandas.DataFrame`",
#     "Series": ":class:`~pandas.Series`",
# }

autosummary_generate = True
autodoc_default_options = {'members': None,
                           'show-inheritance': None,
                           'inherited-members': None,
                           'member-order': 'groupwise'}

mathjax3_config = {
    'tex': {
        'macros': {
            'vec': [r'{\bf #1}', 1],
            'ldot': [r'\left\langle #1, #2 \right\rangle', 2],
            'E': r'\mathbb{E}',
            'T': r'\mathcal{T}',
            'argmin': r'\mathrm{argmin}',
            'Var': r'\mathrm{Var}'
        }
    }
}

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of strings:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'

# The root toctree document.
root_doc = 'index'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = "en"

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = []

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = None


# -- Options for HTML output -------------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'

# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
#
html_theme_options = {
    'collapse_navigation': False
}

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
# html_static_path = ['_static']
html_extra_path = ['map.svg', 'Causal-Inference-User-Guide-v4-022520.pdf', "spec/img"]

# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# The default sidebars (for documents that don't match any pattern) are
# defined by theme itself.  Builtin themes are using these templates by
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
# 'searchbox.html']``.
#
# html_sidebars = {}

html_logo = 'econml-logo-inverse.png'
html_favicon = 'econml.ico'

# -- Options for HTMLHelp output ---------------------------------------------

# Output file base name for HTML help builder.
htmlhelp_basename = 'econmldoc'


# -- Options for LaTeX output ------------------------------------------------

latex_elements = {
    # The paper size ('letterpaper' or 'a4paper').
    #
    # 'papersize': 'letterpaper',

    # The font size ('10pt', '11pt' or '12pt').
    #
    # 'pointsize': '10pt',

    # Additional stuff for the LaTeX preamble.
    #
    # 'preamble': '',

    # Latex figure (float) alignment
    #
    # 'figure_align': 'htbp',
}

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
#  author, documentclass [howto, manual, or own class]).
latex_documents = [
    (root_doc, 'econml.tex', 'econml Documentation',
     'PyWhy contributors', 'manual'),
]


# -- Options for manual page output ------------------------------------------

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
    (root_doc, 'econml', 'econml Documentation',
     [author], 1)
]


# -- Options for Texinfo output ----------------------------------------------

# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
#  dir menu entry, description, category)
texinfo_documents = [
    (root_doc, 'econml', 'econml Documentation',
     author, 'econml', 'One line description of project.',
     'Miscellaneous'),
]


# -- Options for Epub output -------------------------------------------------

# Bibliographic Dublin Core info.
epub_title = project

# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#
# epub_identifier = ''

# A unique identification for the text.
#
# epub_uid = ''

# A list of files that should not be packed into the epub file.
epub_exclude_files = ['search.html']


# -- Extension configuration -------------------------------------------------

# -- Options for intersphinx extension ---------------------------------------

# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'python': ('https://docs.python.org/3', None),
                       'numpy': ('https://numpy.org/doc/stable/', None),
                       'sklearn': ('https://scikit-learn.org/stable/', None),
                       'matplotlib': ('https://matplotlib.org/stable/', None),
                       'shap': ('https://shap.readthedocs.io/en/stable/', None),
                       'dowhy': ('https://www.pywhy.org/dowhy/main/', None),
                       'statsmodels': ('https://www.statsmodels.org/stable/', None)}


# -- Options for todo extension ----------------------------------------------

# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False

# -- Options for doctest extension -------------------------------------------
doctest_default_flags = (doctest.DONT_ACCEPT_TRUE_FOR_1 |
                         doctest.ELLIPSIS |
                         doctest.IGNORE_EXCEPTION_DETAIL |
                         doctest.NORMALIZE_WHITESPACE)


def exclude_entity(app, what, name, obj, skip, opts):
    # we can document otherwise excluded entities here by returning False
    # or skip otherwise included entities by returning True
    if name in ["_RLearner", "_OrthoLearner", "_crossfit"]:
        return False
    return None


def setup(app):
    app.connect('autodoc-skip-member', exclude_entity)
    ()


================================================
FILE: doc/index.rst
================================================
.. econml documentation root file, created by
   sphinx-quickstart on Fri Feb 15 12:08:35 2019.
   You can adapt this file completely to your liking, but it should at least
   contain the root `toctree` directive.

Welcome to econml's documentation!
==================================

.. toctree::
    spec/spec
    reference

Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

.. todolist::

================================================
FILE: doc/reference.rst
================================================
Public Module Reference
=======================

CATE Estimators
---------------

.. _dml_api:

Double Machine Learning (DML)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. autosummary::
    :toctree: _autosummary

    econml.dml.DML
    econml.dml.LinearDML
    econml.dml.SparseLinearDML
    econml.dml.CausalForestDML
    econml.dml.NonParamDML
    econml.dml.KernelDML

.. _dr_api:

Doubly Robust (DR)
^^^^^^^^^^^^^^^^^^

.. autosummary::
    :toctree: _autosummary

    econml.dr.DRLearner
    econml.dr.LinearDRLearner
    econml.dr.SparseLinearDRLearner
    econml.dr.ForestDRLearner

.. _metalearners_api:

Meta-Learners
^^^^^^^^^^^^^

.. autosummary::
    :toctree: _autosummary

    econml.metalearners.XLearner
    econml.metalearners.TLearner
    econml.metalearners.SLearner
    econml.metalearners.DomainAdaptationLearner

.. _orf_api:

Orthogonal Random Forest (ORF)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. autosummary::
    :toctree: _autosummary

    econml.orf.DMLOrthoForest
    econml.orf.DROrthoForest

Instrumental Variable CATE Estimators
-------------------------------------

.. _dmliv_api:

Double Machine Learning (DML) IV
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. autosummary::
    :toctree: _autosummary

    econml.iv.dml.OrthoIV
    econml.iv.dml.DMLIV
    econml.iv.dml.NonParamDMLIV

.. _driv_api:

Doubly Robust (DR) IV
^^^^^^^^^^^^^^^^^^^^^

.. autosummary::
    :toctree: _autosummary

    econml.iv.dr.DRIV
    econml.iv.dr.LinearDRIV
    econml.iv.dr.SparseLinearDRIV
    econml.iv.dr.ForestDRIV
    econml.iv.dr.IntentToTreatDRIV
    econml.iv.dr.LinearIntentToTreatDRIV

.. _tsls_api:

Sieve Methods
^^^^^^^^^^^^^

.. autosummary::
    :toctree: _autosummary

    econml.iv.sieve.SieveTSLS
    econml.iv.sieve.HermiteFeatures
    econml.iv.sieve.DPolynomialFeatures

.. _panel_api:

Estimators for Panel Data
-------------------------

.. _dynamicdml_api:

Dynamic Double Machine Learning
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. autosummary::
    :toctree: _autosummary

    econml.panel.dml.DynamicDML

.. _policy_api:

Policy Learning
---------------

.. autosummary::
    :toctree: _autosummary

    econml.policy.DRPolicyForest
    econml.policy.DRPolicyTree
    econml.policy.PolicyForest
    econml.policy.PolicyTree

.. _interpreters_api:

CATE Interpreters
-----------------

.. autosummary::
    :toctree: _autosummary

    econml.cate_interpreter.SingleTreeCateInterpreter
    econml.cate_interpreter.SingleTreePolicyInterpreter

.. _validation_api:

CATE Validation
---------------

.. autosummary::
    :toctree: _autosummary

    econml.validate.DRTester
    econml.validate.BLPEvaluationResults
    econml.validate.CalibrationEvaluationResults
    econml.validate.UpliftEvaluationResults
    econml.validate.EvaluationResults

.. _scorers_api:

CATE Scorers
------------

.. autosummary::
    :toctree: _autosummary
    
    econml.score.RScorer
    econml.score.EnsembleCateEstimator


.. _grf_api:

Generalized Random Forests
--------------------------

.. autosummary::
    :toctree: _autosummary

    econml.grf.CausalForest
    econml.grf.CausalIVForest
    econml.grf.RegressionForest
    econml.grf.MultiOutputGRF
    econml.grf.LinearMomentGRFCriterion
    econml.grf.LinearMomentGRFCriterionMSE
    econml.grf._base_grf.BaseGRF
    econml.grf._base_grftree.GRFTree


.. Integration with AzureML AutoML
.. -------------------------------

.. .. autosummary::
..     :toctree: _autosummary

..     econml.automated_ml

Scikit-Learn Extensions
-----------------------

.. _sklearn_linear_api:

Linear Model Extensions
^^^^^^^^^^^^^^^^^^^^^^^

.. autosummary::
    :toctree: _autosummary

    econml.sklearn_extensions.linear_model.DebiasedLasso
    econml.sklearn_extensions.linear_model.MultiOutputDebiasedLasso
    econml.sklearn_extensions.linear_model.SelectiveRegularization
    econml.sklearn_extensions.linear_model.StatsModelsLinearRegression
    econml.sklearn_extensions.linear_model.StatsModelsRLM
    econml.sklearn_extensions.linear_model.WeightedLasso
    econml.sklearn_extensions.linear_model.WeightedLassoCV
    econml.sklearn_extensions.linear_model.WeightedMultiTaskLassoCV
    econml.sklearn_extensions.linear_model.WeightedLassoCVWrapper

.. _sklearn_model_api:

Model Selection Extensions
^^^^^^^^^^^^^^^^^^^^^^^^^^

.. autosummary::
    :toctree: _autosummary

    econml.sklearn_extensions.model_selection.GridSearchCVList
    econml.sklearn_extensions.model_selection.WeightedKFold
    econml.sklearn_extensions.model_selection.WeightedStratifiedKFold


.. _inference_api:

Inference
---------

Inference Results
^^^^^^^^^^^^^^^^^

.. autosummary::
    :toctree: _autosummary

    econml.inference.NormalInferenceResults
    econml.inference.EmpiricalInferenceResults
    econml.inference.PopulationSummaryResults

Inference Methods
^^^^^^^^^^^^^^^^^

.. autosummary::
    :toctree: _autosummary

    econml.inference.BootstrapInference
    econml.inference.GenericModelFinalInference
    econml.inference.GenericSingleTreatmentModelFinalInference
    econml.inference.LinearModelFinalInference
    econml.inference.StatsModelsInference
    econml.inference.GenericModelFinalInferenceDiscrete
    econml.inference.LinearModelFinalInferenceDiscrete
    econml.inference.StatsModelsInferenceDiscrete

.. _federated_api:

Federated Estimation
--------------------

.. autosummary::
    :toctree: _autosummary

    econml.federated_learning.FederatedEstimator

.. _solutions_api:

Solutions
---------

Causal Analysis
^^^^^^^^^^^^^^^

.. autosummary::
    :toctree: _autosummary

    econml.solutions.causal_analysis.CausalAnalysis

.. _dowhy_api:

Integration with DoWhy
----------------------

.. autosummary::
    :toctree: _autosummary
    
    econml.dowhy.DoWhyWrapper


.. _utilities_api:

Utilities
---------

.. autosummary::
    :toctree: _autosummary
    
    econml.utilities

Private Module Reference
========================

.. autosummary::
    :toctree: _autosummary

    econml._ortho_learner
    econml._cate_estimator
    econml.dml._rlearner
    econml.inference._bootstrap


================================================
FILE: doc/spec/api.rst
================================================
Problem Setup and API Design
============================


.. rubric::
    Potential Outcomes Formulation

We begin by formulating the problem in the potential outcomes terminology. Subsequently,
we will also provide a formulation in the structural equations notation for readers more familiar
with that notation.

The methods developed in our library tackle the following general problem: let :math:`Y(\vec{t})` 
denote the random variable that corresponds to the value of the outcome of interest if we were to treat a sample
with treatment :math:`\vec{t} \in \T`.
Given two vectors of treatments :math:`\vec{t}_0, \vec{t}_1 \in \T`, a vector of co-variates :math:`\vec{x}` 
and a random vector of potential outcomes :math:`Y(\vec{t})`, we want to estimate the quantity: 

.. math ::
    \tau(\vec{t}_0, \vec{t}_1, \vec{x}) = \E[Y(\vec{t}_1) - Y(\vec{t}_0) | X=\vec{x}]

We will refer to the latter quantity as the *heterogeneous treatment effect* of going from treatment 
:math:`\vec{t}_0` to treatment :math:`\vec{t}_1` conditional on observables :math:`\vec{x}`.  
If treatments are continuous, then one might also be interested in a local effect around a treatment point. 
The latter translates to estimating a local gradient around a treatment vector conditional on observables:

.. math ::
    \partial\tau(\vec{t}, \vec{x}) = \E\left[\nabla_{\vec{t}} Y(\vec{t}) | X=\vec{x}\right] \tag{marginal CATE}

We will refer to the latter as the *heterogeneous marginal effect*. [1]_ 

We assume we have data that are generated from some collection policy. In particular, we assume that we have data of the form: 
:math:`\{Y_i(T_i), T_i, X_i, W_i, Z_i\}`, where :math:`Y_i(T_i)` is the observed outcome for the chosen treatment, 
:math:`T_i` is the treatment, :math:`X_i` are the co-variates used for heterogeneity, 
:math:`W_i` are other observable co-variates that we believe are affecting the potential outcome :math:`Y_i(T_i)` 
and potentially also the treatment :math:`T_i`; and :math:`Z_i` are variables that affect 
the treatment :math:`T_i` but do not directly affect the potential outcome. 
We will refer to variables :math:`W_i` as *controls* and variables :math:`Z_i` as *instruments*. 
The variables :math:`X_i` can also be thought of as *control* variables, but they are special in the sense that 
they are a subset of the controls with respect to which we want to measure treatment effect heterogeneity. 
We will refer to them as *features*.

Finally, some times we might not only be interested in the effect but also in the actual *counterfactual prediction*, i.e. estimating the quantity: 

.. math ::
    \mu(\vec{t}, \vec{x}) = \E\left[Y(\vec{t}) | X=\vec{x}\right] \tag{counterfactual prediction}

Our package does not offer support for counterfactual prediction. However, for most of our estimators (the ones
assuming a linear-in-treatment model), counterfactual prediction can be easily constructed by combining any baseline predictive model
with our causal effect model, i.e. train any machine learning model :math:`b(\vec{t}, \vec{x})` to solve the regression/classification
problem :math:`\E[Y | T=\vec{t}, X=\vec{x}]`, and then set :math:`\mu(\vec{t}, \vec{x}) = \tau(\vec{t}, T, \vec{x}) + b(T, \vec{x})`,
where :math:`T` is either the observed treatment for that sample under the observational policy or the treatment
that the observational policy would have assigned to that sample. These auxiliary ML models can be trained
with any machine learning package outside of EconML.

.. rubric:: 
    Structural Equation Formulation

We can equivalently describe the data and the quantities of interest via the means of structural equations. In particular, 
suppose that we observe i.i.d. samples :math:`\{Y_i, T_i, X_i, W_i, Z_i\}` from some joint distribution and 
we assume the following structural equation model of the world:

.. math ::
    Y =~& g(T, X, W, \epsilon)

    T =~& f(X, W, Z, \eta)

where :math:`\epsilon` and :math:`\eta` are *noise* random variables that are independent of :math:`X, Z, T, W` but could be potentially correlated with each other. 
The target quantity that we want to estimate can then be expressed as:

.. math ::
    :nowrap:

    \begin{align}
        \tau(\vec{t}_0, \vec{t}_1, \vec{x}) =& \E[g(\vec{t}_1, X, W, \epsilon) - g(\vec{t}_0, X, W, \epsilon) | X=\vec{x}] \tag{CATE} \\
        \partial\tau(\vec{t}, \vec{x}) =& \E[\nabla_{\vec{t}} g(\vec{t}, X, W, \epsilon) | X=\vec{x}] \tag{marginal CATE} \\
    \end{align}

where in these expectations, the random variables :math:`W, \epsilon` are taken from the same distribution as the one that generated the data. 
In other words, there is a one-to-one correspondence between the potential outcomes formulation and the structural equations formulation 
in that the random variable :math:`Y(t)` is equal to the random variable :math:`g(t, X, W, \epsilon)`, where :math:`X, W, \epsilon` 
is drawn from the distribution that generated each sample in the data set.

API of Conditional Average Treatment Effect Package
----------------------------------------------------------

The base class of all the methods in our API has the following signature:

.. code-block:: python3
    :caption: Base CATE Estimator Class

    class BaseCateEstimator
        
        def fit(self, Y, T, X=None, W=None, Z=None, inference=None):
            ''' Estimates the counterfactual model from data, i.e. estimates functions 
            τ(·, ·, ·)}, ∂τ(·, ·) and μ(·, ·)
        
            Parameters:
            Y: (n × d_y) matrix of outcomes for each sample
            T: (n × d_t) matrix of treatments for each sample
            X: (n × d_x) matrix of features for each sample, optional
            W: (n × d_w) matrix of controls for each sample, optional
            Z: (n × d_z) matrix of instruments for each sample, optional
            inference: str or `Inference` instance, optional
                Method for performing inference.  All estimators support 'bootstrap'
                (or an instance of `BootstrapInference`), some support other methods as well.
            '''
        
        def effect(self, X=None, *, T0, T1):
            ''' Calculates the heterogeneous treatment effect τ(·, ·, ·) between two treatment
            points conditional on a vector of features on a set of m test samples {T0_i, T1_i, X_i}
        
            Parameters:
            T0: (m × d_t) matrix of base treatments for each sample
            T1: (m × d_t) matrix of target treatments for each sample
            X:  (m × d_x) matrix of features for each sample, optional
        
            Returns:
            tau: (m × d_y) matrix of heterogeneous treatment effects on each outcome
                for each sample
            '''
        
        def marginal_effect(self, T, X=None):
            ''' Calculates the heterogeneous marginal effect ∂τ(·, ·) around a base treatment
            point conditional on a vector of features on a set of m test samples {T_i, X_i}
        
            Parameters:
            T: (m × d_t) matrix of base treatments for each sample
            X:  (m × d_x) matrix of features for each sample, optional
        
            Returns:
            grad_tau: (m × d_y × d_t) matrix of heterogeneous marginal effects on each outcome
                for each sample
            '''

        def effect_interval(self, X=None, *, T0=0, T1=1, alpha=0.05):
            ''' Confidence intervals for the quantities τ(·, ·, ·) produced by the model. 
            Available only when inference is not None, when calling the fit method.

            Parameters:
            X:  (m, d_x) matrix of features for each sample, optional
            T0: (m, d_t) matrix of base treatments for each sample, optional
            T1: (m, d_t) matrix of target treatments for each sample, optional
            alpha: float in [0, 1] of the (1-alpha) level of confidence, optional

            Returns:
            lower, upper : tuple of the lower and the upper bounds of the confidence interval 
                for each quantity.
            '''
        
        def marginal_effect_interval(self, T, X=None, *, alpha=0.05):
            ''' Confidence intervals for the quantities effect ∂τ(·, ·) produced by the model. 
            Available only when inference is not None, when calling the fit method.

            Parameters:
            T: (m, d_t) matrix of base treatments for each sample
            X: (m, d_x) matrix of features for each sample, optional
            alpha: float in [0, 1] of the (1-alpha) level of confidence, optional

            Returns:
            lower, upper : tuple of the lower and the upper bounds of the confidence interval 
                for each quantity.
            '''

        


Linear in Treatment CATE Estimators
-----------------------------------

.. rubric::
    Constant Marginal Effects

In many settings, we might want to make further structural assumptions on the form of the data generating process.
One particular prevalent assumption is that the outcome :math:`y` is linear in the treatment vector and therefore that the marginal effect is constant across treatments, i.e.:

.. math ::
    Y =~& H(X, W) \cdot T + g(X, W, \epsilon)

    T =~& f(X, W, Z, \eta)

where :math:`\epsilon, \eta` are exogenous noise terms. Under such a linear response assumption we observe that the CATE and marginal CATE take a special form of:

.. math ::

    \tau(\vec{t}_0, \vec{t}_1, \vec{x}) =~& \E[H(X, W) | X=\vec{x}] \cdot (\vec{t}_1 - \vec{t}_0) 

    \partial \tau(\vec{t}, \vec{x}) =~&  \E[H(X, W) | X=\vec{x}]

Hence, the marginal CATE is independent of :math:`\vec{t}`. In these settings, we will denote with :math:`\theta(\vec{x})` the constant marginal CATE, i.e. 

.. math ::
    \theta(\vec{x}) = \E[H(X, W) | X=\vec{x}] \tag{constant marginal CATE}

.. rubric::
    Constant Marginal Effects and Marginal Effects Given Treatment Featurization

Additionally, we may be interested in cases where the outcome depends linearly on a transformation of the treatment vector (via some featurizer :math:`\phi`). 
Some estimators provide support for passing such a featurizer :math:`\phi` directly to the estimator, in which case the outcome would be modeled as follows: 

.. math ::
    
    Y = H(X, W) \cdot \phi(T) + g(X, W, \epsilon)

We can then get constant marginal effects in the featurized treatment space:

.. math ::

    \tau(\phi(\vec{t_0}), \phi(\vec{t_1}), \vec{x}) =~& \E[H(X, W) | X=\vec{x}] \cdot (\phi(\vec{t_1}) - \phi(\vec{t_0}))

    \partial \tau(\phi(\vec{t}), \vec{x}) =~& \E[H(X, W) | X=\vec{x}]

    \theta(\vec{x}) =~& \E[H(X, W) | X=\vec{x}] 
    

Finally, we can recover the marginal effect with respect to the original treatment space by multiplying the constant marginal effect (which is in featurized treatment space) with the jacobian of the treatment featurizer at :math:`\vec{t}`.

.. math ::
    \partial \tau(\vec{t}, \vec{x}) = \theta(\vec{x}) \nabla \phi(\vec{t}) \tag{marginal CATE}

where :math:`\nabla \phi(\vec{t})` is the :math:`d_{ft} \times d_{t}` jacobian matrix, and :math:`d_{ft}` and :math:`d_{t}` are the dimensions of the featurized treatment and the original treatment, respectively.

.. rubric::
    API for Linear in Treatment CATE Estimators

Given the prevalence of linear treatment effect assumptions, we will create a generic LinearCateEstimator, which will support a method that returns the constant marginal CATE 
and constant marginal CATE interval at any target feature vector :math:`\vec{x}`, as well as calculating marginal effects in the original treatment space when a treatment featurizer is provided.

.. code-block:: python3
    :caption: Linear CATE Estimator Class

    class LinearCateEstimator(BaseCateEstimator):
        self.treatment_featurizer = None
        
        def const_marginal_effect(self, X=None):
            ''' Calculates the constant marginal CATE θ(·) conditional on a vector of
            features on a set of m test samples {X_i}
        
            Parameters:
            X: (m × d_x) matrix of features for each sample, optional
        
            Returns:
            theta: (m × d_y × d_f_t) matrix of constant marginal CATE of each treatment on each outcome	
            for each sample, where d_f_t is the dimension of the featurized treatment. 
            If treatment_featurizer is None, d_f_t = d_t
            '''
        
        def const_marginal_effect_interval(self, X=None, *, alpha=0.05):
            ''' Confidence intervals for the quantities θ(·) produced by the model.
            Available only when inference is not None, when calling the fit method.

            Parameters:
            X: (m, d_x) matrix of features for each sample, optional
            alpha: float in [0, 1] of the (1-alpha) level of confidence, optional

            Returns:
            lower, upper : tuple of the lower and the upper bounds of the confidence interval 
                for each quantity.
            '''
        
        def effect(self,  X=None, *, T0, T1,):
            if self.treatment_featurizer:
                return const_marginal_effect(X) * (T1 - T0)
            else:
                dt = self.treatment_featurizer.transform(T1) - self.treatment_featurizer.transform(T0)
                return const_marginal_effect(X) * dt
        
        def marginal_effect(self, T, X=None)
            if self.treatment_featurizer is None:
                return const_marginal_effect(X)
            else:
                # for every observation X_i, T_i, 
                # calculate jacobian at T_i and multiply with const_marginal_effect at X_i
        
        def marginal_effect_interval(self, T, X=None, *, alpha=0.05):
            if self.treatment_featurizer is None:
                return const_marginal_effect_interval(X, alpha=alpha)
            else:
                # perform separate treatment featurization inference logic
        
        


Example Use of API
------------------

Let us walk through a simple example of what one can achieve via the latter API
even irrespective of the actual estimation method that is being used.

Let us consider a hypothetical data generating process (DGP) governed by the 
following equations:

.. math ::
    \begin{align}
        Y(t) =~& \gamma t^2 + \delta X t + \langle \zeta, W \rangle + \epsilon\\
        T =~& \langle \alpha, W \rangle + \langle \beta, Z \rangle + \eta\\
        X, Z, \epsilon, \eta \sim~& N(0, 1), ~~ W \sim N(0, I_{d})
    \end{align}


Suppose that we have :math:`n` samples from this DGP. For instance, we could create these
samples with the following code:

.. code-block:: python3
    :caption: Example Data Generated from Structural Equations

    import numpy as np

    # Instance parameters
    n_controls = 100
    n_instruments = 1
    n_features = 1
    n_treatments = 1
    alpha = np.random.normal(size=(n_controls, 1))
    beta = np.random.normal(size=(n_instruments, 1))
    gamma = np.random.normal(size=(n_treatments, 1))
    delta = np.random.normal(size=(n_treatments, 1))
    zeta = np.random.normal(size=(n_controls, 1))

    n_samples = 1000
    W = np.random.normal(size=(n_samples, n_controls))
    Z = np.random.normal(size=(n_samples, n_instruments))
    X = np.random.normal(size=(n_samples, n_features))
    eta = np.random.normal(size=(n_samples, n_treatments))
    epsilon = np.random.normal(size=(n_samples, 1))
    T = np.dot(W, alpha) + np.dot(Z, beta) + eta
    y = np.dot(T**2, gamma) + np.dot(np.multiply(T, X), delta) + np.dot(W, zeta) + epsilon


We can then fit a counterfactual model to the data. In order to learn confidence interval of our CATE, 
we could pass an additional inference argument to fit, bootstrap interval is supported by all estimators.
We can run the following: 

.. code-block:: python3
    :caption: Example fit of causal model

    # Fit counterfactual model 
    cfest = BaseCateEstimator()
    cfest.fit(y, T, X=X, W=W, Z=Z, inference='bootstrap')

Suppose now that we wanted to estimate the conditional average treatment effect for every point :math:`X_i` 
in the training data and between treatment 1 and treatment 0. 
This should be an estimate of the quantities: :math:`\gamma + \delta X_i`.  We can also get the
confidence interval of the CATE. We can run the following:

.. code-block:: python3
    :caption: Estimating cate for all training features from treatment 0 to 1

    X_test = X
    # Estimate heterogeneous treatment effects from going from treatment 0 to treatment 1
    T0_test = np.zeros((X_test.shape[0], n_treatments))
    T1_test = np.ones((X_test.shape[0], n_treatments))
    hetero_te = cfest.effect(X_test, T0=T0_test, T1=T1_test)
    hetero_te_interval =  cfest.effect_interval(X_test, T0=T0_test, T1=T1_test, alpha=0.1)

Suppose now that we wanted to estimate the conditional marginal effect for every point :math:`X_i` 
at treatment 0.
This should be an estimate of the quantities: :math:`\delta X_i`. We can also get the
confidence interval of the CATE. We can run the following:

.. code-block:: python3
    :caption: Estimating marginal cate for all training features at treatment 0

    # Estimate heterogeneous marginal effects around treatment 0
    T_test = np.zeros((X_test.shape[0], n_treatments))
    hetero_marginal_te = cfest.marginal_effect(T_test, X_test)
    hetero_marginal_te_interval = cfest.marginal_effect_interval(T_test, X_test, alpha=0.1)

Suppose we wanted to create projections of these estimated quantities on sub-populations, i.e.
the average treatment effect or the average treatment effect on the population where :math:`X_i\geq 1/2`.
We could simply achieve this as follows:

.. code-block:: python3
    :caption: Projecting on subpopulations

    # Estimate average treatment effects over a population of z's
    T0_test = np.zeros((X_test.shape[0], n_treatments))
    T1_test = np.ones((X_test.shape[0], n_treatments))

    # average treatment effect
    ate = np.mean(cfest.effect(X_test, T0=T0_test, T1=T1_test)) # returns estimate of γ + δ 𝔼[x]

    # average treatment effect of population with x>1/2
    # returns estimate of γ + δ 𝔼[x | x>1/2]
    cate = np.mean(cfest.effect(X_test[X_test>1/2], T0=T0_test[X_test>1/2], T1=T1_test[X_test>1/2])) 

More importantly, suppose we wanted to understand what would be the overall expected change in response
if we were to follow some treatment policy (e.g. treat everyone with :math:`X_i\geq 0`). This
can also be easily done as follows:

.. code-block:: python3
    :caption: Estimating expected lift of some treatment policy
    
    # Estimate expected lift of treatment policy: π(z) = 𝟙{x > 0} over existing policy
    Pi0_test = T
    Pi1_test = (X_test > 0) * 1.
    # returns estimate of γ/2 + δ/√(2π)
    policy_effect = np.mean(cfest.effect(X_test, T0=Pi0_test, T1=Pi1_test)) 

    # Estimate expected lift of treatment policy: π(x) = 𝟙{x > 0} over baseline of no treatment
    Pi0_test = np.zeros((X_test.shape[0], n_treatments))
    Pi1_test = (X_test > 0) * 1.
    # returns estimate of γ/2 + δ/√(2π)
    policy_effect = np.mean(cfest.effect(X_test, T0=Pi0_test, T1=Pi1_test)) 

.. rubric:: Footnotes

.. [1] One can always approximate the latter with the former and vice versa, 
    i.e. :math:`\partial_i \tau(\vec{t},\vec{x}) \approx \tau(\vec{t}, \vec{t} + \delta \vec{e}_i, \vec{x})/\delta` 
    for some small enough :math:`\delta`, and similarly, 
    :math:`\tau(\vec{t_0}, \vec{t_1}, \vec{x}) = \int_{0}^{1} \partial\tau(\vec{t}_0 + q (\vec{t}_1 - \vec{t}_0), \vec{x}) (\vec{t}_1 - \vec{t_0})dq`. 
    However, in many settings more direct methods that make use of the structure might simplify these generic transformations.



================================================
FILE: doc/spec/causal_intro.rst
================================================
Introduction to Causal Inference
=================================

If you are new to causal inference, it may be helpful to walk through a quick overview of concepts and techniques that we refer to over the course of the documentation. Below we provide a high level introduction to causal inference tailored for EconML:

.. raw:: html

    <iframe src="../Causal-Inference-User-Guide-v4-022520.pdf" width="700" height="388"> </iframe>

The folks at DoWhy also have a broader introduction `here <https://causalinference.gitlab.io/kdd-tutorial/>`__.

================================================
FILE: doc/spec/community.rst
================================================
Community
==========

.. raw:: html
    
    <p></p>
    <a href="https://pywhy.org/">
    <img src="../pywhy-logo.png" width="80px" align="left" style="margin-right: 10px;", alt="pywhy-logo">
    </a>

EconML is a part of `PyWhy <https://www.pywhy.org/>`__, an organization with a mission to build an open-source ecosystem for causal machine learning.

PyWhy also has a `Discord <https://discord.gg/cSBGb3vsZb>`__, which serves as a space for like-minded casual machine learning researchers and practitioners of all experience levels to come together to ask and answer questions, discuss new features, and share ideas.

We invite you to join us at regular office hours and community calls in the Discord.

================================================
FILE: doc/spec/comparison.rst
================================================
=============================
Detailed estimator comparison
=============================


+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+
| Estimator                                   | | Treatment  | | Requires   | | Delivers Conf. | | Linear    | | Linear        | | Multiple | | Multiple   | | High-Dimensional |
|                                             | | Type       | | Instrument | | Intervals      | | Treatment | | Heterogeneity | | Outcomes | | Treatments | | Features         |
+=============================================+==============+==============+==================+=============+=================+============+==============+====================+
| :class:`.SieveTSLS`                         | Any          | Yes          |                  | Yes         | Assumed         | Yes        | Yes          |                    |
+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+
| :class:`.SparseLinearDML`                   | Any          |              | Yes              | Yes         | Assumed         | Yes        | Yes          | Yes                |
+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+
| :class:`.SparseLinearDRLearner`             | Categorical  |              | Yes              |             | Projected       |            | Yes          | Yes                |
+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+
| :class:`.LinearDML`                         | Any          |              | Yes              | Yes         | Assumed         | Yes        | Yes          |                    |
+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+
| :class:`.LinearDRLearner`                   | Categorical  |              | Yes              |             | Projected       |            | Yes          |                    |
+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+
| :class:`.CausalForestDML`                   | Any          |              | Yes              | Yes         |                 | Yes        | Yes          | Yes                |
+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+
| :class:`.ForestDRLearner`                   | Categorical  |              | Yes              |             |                 |            | Yes          | Yes                |
+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+
| :class:`.DMLOrthoForest`                    | Any          |              | Yes              | Yes         |                 |            | Yes          | Yes                |
+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+
| :class:`.DROrthoForest`                     | Categorical  |              | Yes              |             |                 |            | Yes          | Yes                |
+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+
| :ref:`metalearners <metalearners_api>`      | Categorical  |              |                  |             |                 | Yes        | Yes          | Yes                |
+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+
| :class:`.DRLearner`                         | Categorical  |              |                  |             |                 |            | Yes          | Yes                |
+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+
| :class:`.DML`                               | Any          |              |                  | Yes         | Assumed         | Yes        | Yes          | Yes                |
+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+
| :class:`.NonParamDML`                       | 1-d/Binary   |              |                  | Yes         |                 | Yes        |              | Yes                |
+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+
| :class:`.OrthoIV`                           | Any          | Yes          | Yes              | Yes         | Assumed         | Yes        | Yes          |                    |
+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+
| :class:`.DMLIV`                             | Any          | Yes          |                  | Yes         | Assumed         | Yes        | Yes          | Yes                |
+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+
| :class:`.NonParamDMLIV`                     | 1-d/Binary   | Yes          |                  | Yes         |                 | Yes        |              | Yes                |
+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+
| :class:`.DRIV`                              | 1-d/Binary   | Yes          | Yes              | Yes         |                 |            |              | Yes                |
+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+
| :class:`.LinearDRIV`                        | 1-d/Binary   | Yes          | Yes              | Yes         | Projected       |            |              |                    |
+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+
| :class:`.SparseLinearDRIV`                  | 1-d/Binary   | Yes          | Yes              | Yes         | Projected       |            |              | Yes                |
+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+
| :class:`.ForestDRIV`                        | 1-d/Binary   | Yes          | Yes              | Yes         |                 |            |              | Yes                |
+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+
| :class:`.IntentToTreatDRIV`                 | Binary       | Yes          | Ye               | Yes         |                 |            |              | Yes                |
+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+
| :class:`.LinearIntentToTreatDRIV`           | Binary       | Yes          | Yes              | Yes         | Projected       |            |              |                    |
+---------------------------------------------+--------------+--------------+------------------+-------------+-----------------+------------+--------------+--------------------+

Treatment Type
    Some estimators can only estimate effects of particular kinds of treatments. 
    *Discrete* treatments can be described by a finite number of comprehensive categories (for example, 
    group A received a 10% discount on product 1, group B received a 10% discount on product 2, group C 
    received no discounts). *Binary* treatments are a special case of discrete treatments with only two 
    categories. *Continuous* treatments can take on any value along the number line (for example, minutes of 
    exercise per week).  

Requires Instrument
    Some estimators identify the causal effect of a treatment by considering only a subset of the variation in 
    treatment intensity that is conditionally random given other data features. This subset of the variation 
    is driven by an instrument, which is usually some kind of randomization (i.e. an earlier experiment or a 
    lottery). See the Instrumental Variable Regression section for more information on picking a good 
    instrument.  

Delivers Confidence Intervals
    Many estimators can deliver analytic confidence intervals for the final treatment effects. These 
    confidence intervals correctly adjust for the reuse of data across multiple stages of estimation. EconML 
    cannot deliver analytic confidence intervals in cases where this multi-stage estimation is too complex or 
    for estimators such as the MetaLearners that trade honest confidence intervals for model selection and 
    regularization. In these cases it is still possible to get bootstrap confidence intervals, but this 
    process is slow and may not be statistically valid. 

Linear Treatment
    Some estimators impose the assumption that the outcome is a linear function of the treatment. These 
    estimators can also estimate a non-linear relationship between a treatment and the outcome if the 
    structure of the relationship is known and additively separable (for example, the linear function could 
    include both treatment and treatment-squared for continuous treatments). These linear functions can also 
    include specified interactions between treatments. However, these estimators cannot estimate a fully 
    flexible non-parametric relationship between treatments and the outcome (for example, the relationship 
    cannot be modeled by a forest). 

Linear Heterogeneity
    The CATE function determines how the size of a user’s response to the treatment varies by user features. 
    Some estimators impose the *assumption* that effect size is a linear function of user features. A few models 
    estimate a more flexible relationship between effect size and user features and then *project* that flexible
    function onto a linear model. This second approach delivers a better-fitting linear approximation of a 
    non-linear relationship, but is less efficient in cases where you are confident assuming the true 
    relationship is linear. Finally, some estimation models allow a fully flexible relationship between 
    effect size and user features with no linearity structure. 

Multiple Outcomes
    Some estimation models allow joint estimation of the effects of treatment(s) on multiple outcomes. Other 
    models only accommodate a single outcome. 

Multiple Treatments
    Some estimation models allow joint estimation of the effects of multiple treatments on outcome(s). Other 
    models only accommodate a single treatment. 

High-Dimensional Features
    Many estimators only behave well with a small set of specified features, X, that affect the size of a 
    user’s response to the treatment. If you do not already know which few features might reasonably affect 
    the user’s response, use one of our sparse estimators that can handle large feature sets and penalize them 
    to discover the features that are most correlated with treatment effect heterogeneity. 



================================================
FILE: doc/spec/estimation/dml.rst
================================================
.. _dmluserguide:

==================================
Orthogonal/Double Machine Learning
==================================

What is it?
==================================

Double Machine Learning is a method for estimating (heterogeneous) treatment effects when
all potential confounders/controls (factors that simultaneously had a direct effect on the treatment decision in the
collected data and the observed outcome) are observed, but are either too many (high-dimensional) for
classical statistical approaches to be applicable or their effect on 
the treatment and outcome cannot be satisfactorily modeled by parametric functions (non-parametric).
Both of these latter problems can be addressed via machine learning techniques (see e.g. [Chernozhukov2016]_).

The method reduces the problem to first estimating *two predictive tasks*: 
    
    1) predicting the outcome from the controls,
    2) predicting the treatment from the controls;

Then the method combines these two predictive models in a final stage estimation so as to create a
model of the heterogeneous treatment effect. The approach allows for *arbitrary Machine Learning algorithms* to be
used for the two predictive tasks, while maintaining many favorable statistical properties related to the final
model (e.g. small mean squared error, asymptotic normality, construction of confidence intervals).

Our package offers several variants for the final model estimation. Many of these variants also
provide *valid inference* (confidence interval construction) for measuring the uncertainty of the learned model.


What are the relevant estimator classes?
========================================

This section describes the methodology implemented in the classes, :class:`._RLearner`,
:class:`.DML`, :class:`.LinearDML`,
:class:`.SparseLinearDML`, :class:`.KernelDML`, :class:`.NonParamDML`,
:class:`.CausalForestDML`.
Click on each of these links for a detailed module documentation and input parameters of each class.


When should you use it?
==================================

Suppose you have observational (or experimental from an A/B test) historical data, where some treatment(s)/intervention(s)/action(s) 
:math:`T` were chosen and some outcome(s) :math:`Y` were observed and all the variables :math:`W` that could have
potentially gone into the choice of :math:`T`, and simultaneously could have had a direct effect on the outcome :math:`Y` (aka controls or confounders) are also recorded in the dataset.

If your goal is to understand what was the effect of the treatment on the outcome as a function of a set of observable
characteristics :math:`X` of the treated samples, then one can use this method. For instance call:

.. testsetup::

    # DML
    import numpy as np
    X = np.random.choice(6, size=(100,3))
    Y = np.random.normal(size=(100,2))
    y = np.random.normal(size=(100,))
    (T, T0, T1) = (np.random.choice(np.arange(3), size=(100,2)) for _ in range(3))
    (t, t0, t1) = (a[:,0] for a in (T, T0, T1))
    W = np.random.normal(size=(100,2))

.. testcode::

    from econml.dml import LinearDML
    est = LinearDML()
    est.fit(y, T, X=X, W=W)
    est.const_marginal_effect(X)

This way an optimal treatment policy can be learned, by simply inspecting for which :math:`X` the effect was positive.

Most of the methods provided make a parametric form assumption on the heterogeneous treatment effect model (e.g.
linear on some pre-defined; potentially high-dimensional; featurization). These methods include: 
:class:`.DML`, :class:`.LinearDML`,
:class:`.SparseLinearDML`, :class:`.KernelDML`.
For fully non-parametric heterogeneous treatment effect models, check out the :class:`.NonParamDML`
and the :class:`.CausalForestDML`. 
For more options of non-parametric CATE estimators, 
check out the :ref:`Forest Estimators User Guide <orthoforestuserguide>` 
and the :ref:`Meta Learners User Guide <metalearnersuserguide>`.


Overview of Formal Methodology
==================================

The model makes the following structural equation assumptions on the data generating process.

.. math::

    Y =~& \theta(X) \cdot T + g(X, W) + \epsilon ~~~&~~~ \E[\epsilon | X, W] = 0 \\ 
    T =~& f(X, W) + \eta & \E[\eta \mid X, W] = 0 \\
    ~& \E[\eta \cdot \epsilon | X, W] = 0

What is particularly attractive about DML is that it makes no further structural assumptions on :math:`g` and :math:`f` and estimates them 
non-parametrically using arbitrary non-parametric Machine Learning methods. Our goal is to estimate
the constant marginal CATE :math:`\theta(X)`.

The idea to estimate :math:`\theta(X)` is as follows: we can re-write the structural equations as

.. math::

    Y - \E[Y | X, W]
    = \theta(X) \cdot (T - \E[T | X, W]) + \epsilon

Thus if one can estimate the conditional expectation functions (both of which are non-parametric regression tasks):

.. math::

    q(X, W) =~& \E[Y | X, W]\\
    f(X, W) =~& \E[T | X, W]

Then we can compute the residuals:

.. math::

    \tilde{Y} =~& Y - q(X, W)\\
    \tilde{T} =~& T - f(X, W) = \eta

which are subsequently related by the equation:

.. math::

    \tilde{Y} = \theta(X) \cdot \tilde{T} + \epsilon

Subsequently, since :math:`\E[\epsilon \cdot \eta | X]=0`, estimating :math:`\theta(X)` is a final regression problem, regressing :math:`\tilde{Y}` on :math:`X, \tilde{T}` (albeit over models that are linear in :math:`\tilde{T}`), i.e.

.. math::
    :nowrap:

    \begin{equation}
    \hat{\theta} = \arg\min_{\theta \in \Theta} \E_n\left[ (\tilde{Y} - \theta(X)\cdot \tilde{T})^2 \right]
    \end{equation}

This approach has been analyzed in multiple papers in the literature, for different model classes :math:`\Theta`.
[Chernozhukov2016]_ consider the case where :math:`\theta(X)` is a constant (average treatment effect) or a low dimensional
linear function,
[Nie2017]_ consider the case where :math:`\theta(X)` falls in a Reproducing Kernel Hilbert Space (RKHS),
[Chernozhukov2017]_, [Chernozhukov2018]_ consider the case of a high dimensional sparse linear space, where :math:`\theta(X)=\langle \theta, \phi(X)\rangle`
for some known high-dimensional feature mapping and where :math:`\theta_0` has very few non-zero entries (sparse), 
[Athey2019]_ (among other results) consider the case where :math:`\theta(X)` is a non-parametric lipschitz function and 
use random forest models to fit the function, [Foster2019]_ allow for arbitrary models :math:`\theta(X)` and give 
results based on sample complexity measures of the model space (e.g. Rademacher complexity, metric entropy).


The main advantage of DML is that if one makes parametric assumptions on :math:`\theta(X)`, then one achieves fast estimation rates and, 
for many cases of final stage estimators, also asymptotic normality on the second stage estimate :math:`\hat{\theta}`, even if the first stage estimates on :math:`q(X, W)` 
and :math:`f(X, W)` are only :math:`n^{1/4}` consistent, in terms of RMSE. For this theorem to hold, the nuisance
estimates need to be fitted in a cross-fitting manner (see :class:`._OrthoLearner`).
The latter robustness property follows from the fact that the moment equations that correspond to the final 
least squares estimation (i.e. the gradient of the squared loss), satisfy a Neyman orthogonality condition with respect to the
nuisance parameters :math:`q, f`. For a more detailed exposition of how Neyman orthogonality 
leads to robustness we refer the reader to [Chernozhukov2016]_, [Mackey2017]_, [Nie2017]_, [Chernozhukov2017]_,
[Chernozhukov2018]_, [Foster2019]_. 

Class Hierarchy Structure
==================================

In this library we implement variants of several of the approaches mentioned in the last section. The hierarchy
structure of the implemented CATE estimators is as follows.

    .. inheritance-diagram:: econml.dml.LinearDML econml.dml.SparseLinearDML econml.dml.KernelDML econml.dml.NonParamDML econml.dml.CausalForestDML
        :parts: 1
        :private-bases:
        :top-classes: econml._rlearner._RLearner, econml._cate_estimator.StatsModelsCateEstimatorMixin, econml._cate_estimator.DebiasedLassoCateEstimatorMixin

Below we give a brief description of each of these classes:

    * **DML.** The class :class:`.DML` assumes that the effect model for each outcome :math:`i` and treatment :math:`j` is linear, i.e. takes the form :math:`\theta_{ij}(X)=\langle \theta_{ij}, \phi(X)\rangle`, and allows for any arbitrary scikit-learn linear estimator to be defined as the final stage (e.g.    
      :class:`~sklearn.linear_model.ElasticNet`, :class:`~sklearn.linear_model.Lasso`, :class:`~sklearn.linear_model.LinearRegression` and their multi-task variations in the case where we have multiple outcomes, i.e. :math:`Y` is a vector). The final linear model will be fitted on features that are derived by the Kronecker-product
      of the vectors :math:`T` and :math:`\phi(X)`, i.e. :math:`\tilde{T}\otimes \phi(X) = \mathtt{vec}(\tilde{T}\cdot \phi(X)^T)`. This regression will estimate the coefficients :math:`\theta_{ijk}` 
      for each outcome :math:`i`, treatment :math:`j` and feature :math:`k`. The final model is minimizing a regularized empirical square loss of the form:
      
      .. math::

            \hat{\Theta} = \arg\min_{\Theta} \E_n\left[ \left(\tilde{Y} - \Theta \cdot \tilde{T}\otimes \phi(X)\right)^2 \right] + \lambda R(\Theta)

      for some strongly convex regularizer :math:`R`, where :math:`\Theta` is the parameter matrix of dimensions (number of outcomes, number of treatments * number of features). For instance, if :math:`Y` is single dimensional and the lasso is used as model final, i.e.:

      .. testcode::
      
        from econml.dml import DML
        from sklearn.linear_model import LassoCV
        from sklearn.ensemble import GradientBoostingRegressor
        est = DML(model_y=GradientBoostingRegressor(),
                  model_t=GradientBoostingRegressor(),    
                  model_final=LassoCV(fit_intercept=False))

      then :math:`R(\Theta) =\|\Theta\|_1`, 
      if ElasticNet is used as model final, i.e.:

      .. testcode::    

        from econml.dml import DML
        from sklearn.linear_model import ElasticNetCV
        from sklearn.ensemble import GradientBoostingRegressor
        est = DML(model_y=GradientBoostingRegressor(),
                  model_t=GradientBoostingRegressor(),
                  model_final=ElasticNetCV(fit_intercept=False))

      then :math:`R(\Theta)=\kappa \|\Theta\|_2 + (1-\kappa)\|\Theta\|_1`. For multi-dimensional :math:`Y`, 
      one can impose several extensions to the matrix of parameters :math:`\Theta`, such as the one corresponding to the MultiTask Lasso 
      :math:`\sum_{j} \sum_{i} \theta_{ij}^2` or MultiTask ElasticNet or nuclear norm regularization  [Jaggi2010]_, which enforces low-rank 
      constraints on the matrix :math:`\Theta`.
      This essentially implements the techniques analyzed in [Chernozhukov2016]_, [Nie2017]_, [Chernozhukov2017]_, [Chernozhukov2018]_
        
        - **LinearDML.** The child class  :class:`.LinearDML`, uses an unregularized final linear model and  
          essentially works only when the feature vector :math:`\phi(X)` is low dimensional. Given that it is an unregularized
          low dimensional final model, this class also offers confidence intervals via asymptotic normality 
          arguments. This is achieved by essentially using the :class:`.StatsModelsLinearRegression`
          (which is an extension of the scikit-learn LinearRegression estimator, that also supports inference
          functionalities) as a final model. The theoretical foundations of this class essentially follow the arguments in [Chernozhukov2016]_.
          For instance, to get confidence intervals on the effect of going
          from any treatment T0 to any other treatment T1, one can simply call:

          .. testcode::

            est = LinearDML()
            est.fit(y, T, X=X, W=W)
            point = est.effect(X, T0=T0, T1=T1)
            lb, ub = est.effect_interval(X, T0=T0, T1=T1, alpha=0.05)

          One could also construct bootstrap based confidence intervals by setting `inference='bootstrap'`.

        - **SparseLinearDML.** The child class :class:`.SparseLinearDML`, uses an :math:`\ell_1`-regularized final    
          model. In particular, it uses an implementation of the DebiasedLasso algorithm [Buhlmann2011]_ (see :class:`.DebiasedLasso`). Using the asymptotic normality properties
          of the debiased lasso, this class also offers asymptotically normal based confidence intervals.
          The theoretical foundations of this class essentially follow the arguments in [Chernozhukov2017]_, [Chernozhukov2018]_.
          For instance, to get confidence intervals on the effect of going
          from any treatment T0 to any other treatment T1, one can simply call:

          .. testcode::

            from econml.dml import SparseLinearDML
            est = SparseLinearDML()
            est.fit(y, T, X=X, W=W)
            point = est.effect(X, T0=T0, T1=T1)
            lb, ub = est.effect_interval(X, T0=T0, T1=T1, alpha=0.05)

        - **KernelDML.** The child class :class:`.KernelDML` performs a variant of the RKHS approach proposed in 
          [Nie2017]_. It approximates any function in the RKHS by creating random Fourier features. Then runs a ElasticNet
          regularized final model. Thus it approximately implements the results of [Nie2017], via the random fourier feature
          approximate representation of functions in the RKHS. Moreover, given that we use Random Fourier Features this class
          assumes an RBF kernel.
    
    * **NonParamDML.** The class :class:`.NonParamDML` makes no assumption on the effect model for each outcome :math:`i`.
      However, it applies only when the treatment is either binary or single-dimensional continuous. It uses the observation that for a single
      dimensional treatment, the square loss can be re-written as:

      .. math::

        \E_n\left[ \left(\tilde{Y} - \theta(X) \cdot \tilde{T}\right)^2 \right] = \E_n\left[ \tilde{T}^2 \left(\frac{\tilde{Y}}{\tilde{T}} - \theta(X)\right)^2 \right]
    
      The latter corresponds to a weighted regression problem, where the target label is :math:`\tilde{Y}/\tilde{T}`, the features are :math:`X`
      and the weight of each sample is :math:`\tilde{T}^2`. Thus any scikit-learn regressor that accepts sample weights can be used as a final model, e.g.:

      .. testcode::

        from econml.dml import NonParamDML
        from sklearn.ensemble import GradientBoostingRegressor
        est = NonParamDML(model_y=GradientBoostingRegressor(),
                          model_t=GradientBoostingRegressor(),    
                          model_final=GradientBoostingRegressor())
        est.fit(y, t, X=X, W=W)
        point = est.effect(X, T0=t0, T1=t1)    

      Examples include Random Forests (:class:`~sklearn.ensemble.RandomForestRegressor`), Gradient Boosted Forests (:class:`~sklearn.ensemble.GradientBoostingRegressor`) and
      Support Vector Machines (:class:`~sklearn.svm.SVC`). Moreover, we offer a wrapper :class:`.WeightedModelWrapper` that adds sample weight functionality
      to any scikit-learn regressor. Moreover, for particular estimators we offer scikit-learn extensions that are more tailored such as the :class:`.WeightedLasso`.
      Hence, any such model and even cross validated estimators that perform automatic model selection can be used as `model_final`. From that respect this
      estimator is also a *Meta-Learner*, since all steps of the estimation use out-of-the-box ML algorithms. For more information,
      check out :ref:`Meta Learners User Guide <metalearnersuserguide>`.

    * **CausalForestDML.** This is a child of the :class:`._RLearner` that uses a Causal Forest
      as a final model (see [Wager2018]_ and [Athey2019]_). The Causal Forest is implemented in the library as a scikit-learn
      predictor, in the class :class:`.CausalForest`. This estimator
      offers confidence intervals via the Bootstrap-of-Little-Bags as described in [Athey2019]_.
      Using this functionality we can also construct confidence intervals for the CATE:

        .. testcode::
        
            from econml.dml import CausalForestDML
            from sklearn.ensemble import GradientBoostingRegressor
            est = CausalForestDML(model_y=GradientBoostingRegressor(),
                                  model_t=GradientBoostingRegressor())
            est.fit(y, t, X=X, W=W)
            point = est.effect(X, T0=t0, T1=t1)
            lb, ub = est.effect_interval(X, T0=t0, T1=t1, alpha=0.05)

      Check out :ref:`Forest Estimators User Guide <orthoforestuserguide>` for more information on forest based CATE models and other
      alternatives to the :class:`.CausalForestDML`.

    * **_RLearner.** The internal private class :class:`._RLearner` is a parent of the :class:`.DML`
      and allows the user to specify any way of fitting a final model that takes as input the residual :math:`\tilde{T}`,
      the features :math:`X` and predicts the residual :math:`\tilde{Y}`. Moreover, the nuisance models take as input
      :math:`X` and :math:`W` and predict :math:`T` and :math:`Y` respectively. Since these models take non-standard
      input variables, one cannot use out-of-the-box scikit-learn estimators as inputs to this class. Hence, it is
      slightly more cumbersome to use, which is the reason why we designated it as private. However, if one wants to
      fit for instance a neural net model for :math:`\theta(X)`, then this class can be used (see the implementation
      of the :class:`.DML` of how to wrap sklearn estimators and pass them as inputs to the
      :class:`._RLearner`. This private class essentially follows the general arguments and
      terminology of the RLearner presented in [Nie2017]_, and allows for the full flexibility of the final model
      estimation that is presented in [Foster2019]_.



Usage FAQs
==========

- **What if I want confidence intervals?**

    For valid confidence intervals use the :class:`.LinearDML` if the number of features :math:`X`,
    that you want to use for heterogeneity are small compared to the number of samples that you have. If the number of
    features is comparable to the number of samples, then use :class:`.SparseLinearDML`.
    e.g.:

    .. testcode::

        from econml.dml import LinearDML
        est = LinearDML()
        est.fit(y, T, X=X, W=W)
        lb, ub = est.const_marginal_effect_interval(X, alpha=.05)
        lb, ub = est.coef__interval(alpha=.05)
        lb, ub = est.effect_interval(X, T0=T0, T1=T1, alpha=.05)
    
    If you have a single dimensional continuous treatment or a binary treatment, then you can also fit non-linear
    models and have confidence intervals by using the :class:`.CausalForestDML`. This class will also
    perform well with high dimensional features, as long as only few of these features are actually relevant.

- **Why not just run a simple big linear regression with all the treatments, features and controls?**

    If you want to estimate an average treatment effect with accompanied confidence intervals then one
    potential approach one could take is simply run a big linear regression, regressing :math:`Y` on
    :math:`T, X, W` and then looking at the coefficient associated with the :math:`T` variable and
    the corresponding confidence interval (e.g. using statistical packages like
    :class:`~statsmodels.regression.linear_model.OLS`). However, this will not work if:

        1) The number of control variables :math:`X, W` that you have is large and comparable
        to the number of samples. This could for instance arise if one wants to control for
        unit fixed effects, in which case the number of controls is at least the number of units.
        In such high-dimensional settings, ordinary least squares (OLS) is not a reasonable approach.
        Typically, the covariance matrix of the controls, will be ill-posed and the inference
        will be invalid. The DML method bypasses this by using ML approaches to appropriately
        regularize the estimation and provide better models on how the controls affect the outcome,
        given the number of samples that you have.

        2) The effect of the variables :math:`X, W` on the outcome :math:`Y` is not linear.
        In this case, OLS will not provide a consistent model, which could lead to heavily
        biased effect results. The DML approach, when combined with non-linear first stage
        models, like Random Forests or Gradient Boosted Forests, can capture such non-linearities
        and provide unbiased estimates of the effect of :math:`T` on :math:`Y`. Moreover,
        it does so in a manner that is robust to the estimation mistakes that these ML algorithms
        might be making.
    
    Moreover, one may typically want to estimate treatment effect heterogeneity,
    which the above OLS approach wouldn't provide. One potential way of providing such heterogeneity
    is to include product features of the form :math:`X\cdot T` in the OLS model. However, then
    one faces again the same problems as above:

        1) If effect heterogeneity does not have a linear form, then this approach is not valid.
        One might want to then create more complex featurization, in which case the problem could
        become too high-dimensional for OLS. Our :class:`.SparseLinearDML`
        can handle such settings via the use of the debiased Lasso. Our :class:`.CausalForestDML` does not
        even need explicit featurization and learns non-linear forest based CATE models, automatically. Also see the
        :ref:`Forest Estimators User Guide <orthoforestuserguide>` and the :ref:`Meta Learners User Guide <metalearnersuserguide>`,
        if you want even more flexible CATE models.

        2) If the number of features :math:`X` is comparable to the number of samples, then even
        with a linear model, the OLS approach is not feasible or has very small statistical power.


- **What if I have no idea how heterogeneity looks like?**

    Either use a flexible featurizer, e.g. a polynomial featurizer with many degrees and use
    the :class:`.SparseLinearDML`:

    .. testcode::

        from econml.dml import SparseLinearDML
        from sklearn.preprocessing import PolynomialFeatures
        est = SparseLinearDML(featurizer=PolynomialFeatures(degree=4, include_bias=False))
        est.fit(y, T, X=X, W=W)
        lb, ub = est.const_marginal_effect_interval(X, alpha=.05)
    
    Alternatively, you can also use a forest based estimator such as :class:`.CausalForestDML`. This 
    estimator can also handle many features, albeit typically smaller number of features than the sparse linear DML.
    Moreover, this estimator essentially performs automatic featurization and can fit non-linear models.

    .. testcode::

        from econml.dml import CausalForestDML
        from sklearn.ensemble import GradientBoostingRegressor
        est = CausalForestDML(model_y=GradientBoostingRegressor(),
                        model_t=GradientBoostingRegressor())
        est.fit(y, t, X=X, W=W)
        lb, ub = est.const_marginal_effect_interval(X, alpha=.05)
    
    Also the check out the :ref:`Orthogonal Random Forest User Guide <orthoforestuserguide>` or the
    :ref:`Meta Learners User Guide <metalearnersuserguide>`.

- **What if I have too many features that can create heterogeneity?**

    Use the :class:`.SparseLinearDML` or :class:`.CausalForestDML` (see above).

- **What if I have too many features I want to control for?**

    Use first stage models that work well with high dimensional features. For instance, the Lasso or the 
    ElasticNet or gradient boosted forests are all good options (the latter allows for 
    non-linearities in the model but can typically handle fewer features than the former), e.g.:

    .. testcode::

        from econml.dml import SparseLinearDML
        from sklearn.linear_model import LassoCV, ElasticNetCV
        from sklearn.ensemble import GradientBoostingRegressor
        est = SparseLinearDML(model_y=LassoCV(), model_t=LassoCV())
        est = SparseLinearDML(model_y=ElasticNetCV(), model_t=ElasticNetCV())
        est = SparseLinearDML(model_y=GradientBoostingRegressor(),
                              model_t=GradientBoostingRegressor())
    
    The confidence intervals will still be valid, provided that these first stage models achieve small
    mean squared error.

- **What should I use for first stage estimation?**

    See above. The first stage problems are pure predictive tasks, so any ML approach that is relevant for your
    prediction problem is good.

- **How do I select the hyperparameters of the first stage models?**

    You can use cross-validated models that automatically choose the hyperparameters, e.g. the
    :class:`~sklearn.linear_model.LassoCV` instead of the :class:`~sklearn.linear_model.Lasso`. Similarly,
    for forest based estimators you can wrap them with a grid search CV, :class:`~sklearn.model_selection.GridSearchCV`, e.g.:

    .. testcode::

        from econml.dml import SparseLinearDML
        from sklearn.ensemble import RandomForestRegressor
        from sklearn.model_selection import GridSearchCV
        first_stage = lambda: GridSearchCV(
                        estimator=RandomForestRegressor(),
                        param_grid={
                                'max_depth': [3, None],
                                'n_estimators': (10, 30, 50, 100, 200),
                                'max_features': (1,2,3)
                            }, cv=10, n_jobs=-1, scoring='neg_mean_squared_error'
                        )
        est = SparseLinearDML(model_y=first_stage(), model_t=first_stage())

    Alternatively, you can pick the best first stage models outside of the EconML framework and pass in the selected models to EconML. 
    This can save on runtime and computational resources. Furthermore, it is statistically more stable since all data is being used for
    hyper-parameter tuning rather than a single fold inside of the DML algorithm (as long as the number of hyperparameter values
    that you are selecting over is not exponential in the number of samples, this approach is statistically valid). E.g.:

    .. testcode::

        from econml.dml import LinearDML
        from sklearn.ensemble import RandomForestRegressor
        from sklearn.model_selection import GridSearchCV
        first_stage = lambda: GridSearchCV(
                        estimator=RandomForestRegressor(),
                        param_grid={
                                'max_depth': [3, None],
                                'n_estimators': (10, 30, 50, 100, 200),
                                'max_features': (1,2,3)
                            }, cv=10, n_jobs=-1, scoring='neg_mean_squared_error'
                        )
        model_y = first_stage().fit(X, Y).best_estimator_
        model_t = first_stage().fit(X, T).best_estimator_
        est = LinearDML(model_y=model_y, model_t=model_t)


- **How do I select the hyperparameters of the final model (if any)?**

    You can use cross-validated classes for the final model too. Our default debiased lasso performs cross validation
    for hyperparameter selection. For custom final models you can also use CV versions, e.g.:

    .. testcode::

        from econml.dml import DML
        from sklearn.linear_model import ElasticNetCV
        from sklearn.ensemble import GradientBoostingRegressor
        est = DML(model_y=GradientBoostingRegressor(),
                  model_t=GradientBoostingRegressor(),
                  model_final=ElasticNetCV(fit_intercept=False))
        est.fit(y, t, X=X, W=W)
        point = est.const_marginal_effect(X)
        point = est.effect(X, T0=t0, T1=t1)
    
    In the case of :class:`.NonParamDML` you can also use non-linear cross-validated models as model_final:

    .. testcode::

        from econml.dml import NonParamDML
        from sklearn.ensemble import RandomForestRegressor
        from sklearn.model_selection import GridSearchCV
        cv_reg = lambda: GridSearchCV(
                    estimator=RandomForestRegressor(),
                    param_grid={
                            'max_depth': [3, None],
                            'n_estimators': (10, 30, 50, 100, 200, 400, 600, 800, 1000),
                            'max_features': (1,2,3)
                        }, cv=10, n_jobs=-1, scoring='neg_mean_squared_error'
                    )
        est = NonParamDML(model_y=cv_reg(), model_t=cv_reg(), model_final=cv_reg())


- **What if I have many treatments?**

    The method is going to assume that each of these treatments enters linearly into the model. So it cannot capture complementarities or substitutabilities
    of the different treatments. For that you can also create composite treatments that look like the product 
    of two base treatments. Then these product will enter in the model and an effect for that product will be estimated.
    This effect will be the substitute/complement effect of both treatments being present. See below for more examples.

    If you have too many treatments, then you can use the :class:`.SparseLinearDML`. However,
    this method will essentially impose a regularization that only a small subset of your featurized treatments has any effect.

- **What if my treatments are continuous and don't have a linear effect on the outcome?**

    You can impose a particular form of non-linearity by specifying a `treatment_featurizer` to the estimator. 
    For example, one can use the sklearn `PolynomialFeatures` transformer as a `treatment_featurizer` in order to learn 
    higher-order polynomial treatment effects.

    Using the `treatment_featurizer` argument additionally has the benefit of calculating marginal effects with respect to the original treatment dimension, 
    as opposed to featurizing the treatment yourself before passing to the estimator.

    .. testcode::

        from econml.dml import LinearDML
        from sklearn.preprocessing import PolynomialFeatures
        poly = PolynomialFeatures(degree=2, interaction_only=True, include_bias=False)
        est = LinearDML(treatment_featurizer=poly)
        est.fit(y, T, X=X, W=W)
        point = est.const_marginal_effect(X)
        est.effect(X, T0=T0, T1=T1)
        est.marginal_effect(T, X)


    Alternatively, you can still create composite treatments and add them as extra treatment variables:

    .. testcode::

        from econml.dml import LinearDML
        from sklearn.preprocessing import PolynomialFeatures
        poly = PolynomialFeatures(degree=2, interaction_only=True, include_bias=False)
        est = LinearDML()
        T_composite = poly.fit_transform(T)
        est.fit(y, T_composite, X=X, W=W)
        point = est.const_marginal_effect(X)
        est.effect(X, T0=poly.transform(T0), T1=poly.transform(T1)) 

- **What if my treatment is categorical/binary?**

    You can simply set `discrete_treatment=True` in the parameters of the class. Then use any classifier for 
    `model_t`, that has a `predict_proba` method:

    .. testcode::

        from econml.dml import LinearDML
        from sklearn.linear_model import LogisticRegressionCV
        est = LinearDML(model_t=LogisticRegressionCV(), discrete_treatment=True)
        est.fit(y, t, X=X, W=W)
        point = est.const_marginal_effect(X)
        est.effect(X, T0=t0, T1=t1)

- **How can I assess the performance of the CATE model?**

    Each of the DML classes have an attribute `score_` after they are fitted. So one can access that
    attribute and compare the performance across different modeling parameters (lower score is better):

    .. testcode::

        from econml.dml import DML
        from sklearn.linear_model import ElasticNetCV
        from sklearn.ensemble import RandomForestRegressor
        est = DML(model_y=RandomForestRegressor(),
                  model_t=RandomForestRegressor(),
                  model_final=ElasticNetCV(fit_intercept=False), featurizer=PolynomialFeatures(degree=1))
        est.fit(y, T, X=X, W=W)
        est.score_

    This essentially measures the score based on the final stage loss. Moreover, one can assess the out-of-sample score by calling the `score` method on a separate validation sample that was not
    used for training::

        est.score(Y_val, T_val, X_val, W_val)

    Moreover, one can independently check the goodness of fit of the fitted first stage models by
    inspecting the fitted models. You can access the nested list of fitted first stage models (one for each
    fold of the crossfitting structure) via the methods: `models_t` and `models_y`. Then if those models
    also have a score associated attribute, that can be used as an indicator of performance of the first
    stage. For instance in the case of Random Forest first stages as in the above example, if the `oob_score`
    is set to `True`, then the estimator has a post-fit measure of performance::

        [mdl.oob_score_ for mdls in est.models_y for mdl in mdls]

    If one uses cross-validated estimators as first stages, then model selection for the first stage models
    is performed automatically.

- **How should I set the parameter `cv`?**

    This parameter defines the number of data partitions to create in order to fit the first stages in a
    crossfitting manner (see :class:`._OrthoLearner`). The default is 2, which
    is the minimal. However, larger values like 5 or 6 can lead to greater statistical stability of the method,
    especially if the number of samples is small. So we advise that for small datasets, one should raise this
    value. This can increase the computational cost as more first stage models are being fitted.


Usage Examples
==================================

For more extensive examples check out the following notebooks:
`DML Examples Jupyter Notebook <https://github.com/py-why/EconML/blob/main/notebooks/Double%20Machine%20Learning%20Examples.ipynb>`_,
`Forest Learners Jupyter Notebook <https://github.com/py-why/EconML/blob/main/notebooks/ForestLearners%20Basic%20Example.ipynb>`_.

.. rubric:: Single Outcome, Single Treatment

We consider some example use cases of the library when :math:`Y` and :math:`T` are :math:`1`-dimensional.

**Random Forest First Stages.**
A classical non-parametric regressor for the first stage estimates is a Random Forest. Using RandomForests in our API is as simple as:

.. testcode::

    from econml.dml import LinearDML
    from sklearn.ensemble import RandomForestRegressor
    est = LinearDML(model_y=RandomForestRegressor(),
                    model_t=RandomForestRegressor())
    est.fit(y, T, X=X, W=W)
    pnt_effect = est.const_marginal_effect(X)
    lb_effect, ub_effect = est.const_marginal_effect_interval(X, alpha=.05)
    pnt_coef = est.coef_
    lb_coef, ub_coef = est.coef__interval(alpha=.05)


**Polynomial Features for Heterogeneity.**
Suppose that we believe that the treatment effect is a polynomial of :math:`X`, i.e.

.. math::
    
    Y = (\alpha_0 + \alpha_1 X + \alpha_2 X^2 + \ldots) \cdot T + g(X, W, \epsilon)

Then we can estimate the coefficients :math:`\alpha_i` by running:

.. testcode::

    from econml.dml import LinearDML
    from sklearn.ensemble import RandomForestRegressor
    from sklearn.preprocessing import PolynomialFeatures
    est = LinearDML(model_y=RandomForestRegressor(),
                    model_t=RandomForestRegressor(),
                    featurizer=PolynomialFeatures(degree=3, include_bias=False))
    est.fit(y, T, X=X, W=W)

    # To get the coefficients of the polynomial fitted in the final stage we can
    # access the `coef_` attribute of the fitted second stage model. This would 
    # return the coefficients in front of each term in the vector T⊗ϕ(X).
    est.coef_


**Fixed Effects.**
To add fixed effect heterogeneity, we can create one-hot encodings of the id, which is assumed to be part of the input:

.. testcode::

    from econml.dml import LinearDML
    from sklearn.preprocessing import OneHotEncoder
    # removing one id to avoid colinearity, as is standard for fixed effects
    X_oh = OneHotEncoder(sparse_output=False, drop="first").fit_transform(X)

    est = LinearDML(model_y=RandomForestRegressor(),
                                 model_t=RandomForestRegressor())
    est.fit(y, T, X=X_oh, W=W)
    # The latter will fit a model for θ(x) of the form ̂α_0 + ̂α_1 𝟙{id=1} + ̂α_2 𝟙{id=2} + ...
    # The vector of α can be extracted as follows
    est.coef_

**Custom Features.**
One can also define a custom featurizer, as long as it supports the fit\_transform interface of sklearn.

.. testcode::

    from sklearn.ensemble import RandomForestRegressor
    class LogFeatures(object):
        """Augments the features with logarithmic features and returns the augmented structure"""
        def fit(self, X, y=None):
            return self
        def transform(self, X):
            return np.concatenate((X, np.log(1+X)), axis=1)
        def fit_transform(self, X, y=None):
            return self.fit(X).transform(X)

    est = LinearDML(model_y=RandomForestRegressor(),
                    model_t=RandomForestRegressor(),
                    featurizer=LogFeatures())
    est.fit(y, T, X=X, W=W)

We can even create a Pipeline or Union of featurizers that will apply multiply featurizations, e.g. first creating log features and then adding polynomials of them:

.. testcode::

    from econml.dml import LinearDML
    from sklearn.ensemble import RandomForestRegressor
    from sklearn.pipeline import Pipeline
    from sklearn.preprocessing import PolynomialFeatures
    est = LinearDML(model_y=RandomForestRegressor(), 
                    model_t=RandomForestRegressor(),
                    featurizer=Pipeline([('log', LogFeatures()), 
                                         ('poly', PolynomialFeatures(degree=2, include_bias=False))]))
    est.fit(y, T, X=X, W=W)


.. rubric:: Single Outcome, Multiple Treatments

Suppose we want to estimate treatment effects for multiple continuous treatments at the same time. 
Then we can simply concatenate them before passing them to the estimator.

.. testcode::

    import numpy as np
    est = LinearDML()
    est.fit(y, np.concatenate((T0, T1), axis=1), X=X, W=W)


.. rubric:: Multiple Outcome, Multiple Treatments

In settings like demand estimation, we might want to fit the demand of multiple products as a function of the price of each one of them, i.e. fit the matrix of cross price elasticities. The latter can be done, by simply setting :math:`Y` to be the vector of demands and :math:`T` to be the vector of prices. Then we can recover the 
matrix of cross price elasticities as:

.. testcode::

    from sklearn.linear_model import MultiTaskElasticNet
    est = LinearDML(model_y=MultiTaskElasticNet(alpha=0.1),
                    model_t=MultiTaskElasticNet(alpha=0.1))
    est.fit(Y, T, X=None, W=W)

    # a_hat[i,j] contains the elasticity of the demand of product i on the price of product j
    a_hat = est.const_marginal_effect()

If we have too many products then the cross-price elasticity matrix contains many parameters and we need
to regularize. Given that we want to estimate a matrix, it makes sense in this application to consider
the case where this matrix has low rank: all the products can be embedded in some low dimensional feature
space and the cross-price elasticities is a linear function of these low dimensional embeddings. This corresponds
to well-studied latent factor models in pricing. Our framework can easily handle this by using 
a nuclear norm regularized multi-task regression in the final stage. For instance the 
lightning package implements such a class::

    from econml.dml import DML
    from sklearn.preprocessing import PolynomialFeatures
    from lightning.regression import FistaRegressor
    from sklearn.linear_model import MultiTaskElasticNet

    est = DML(model_y=MultiTaskElasticNet(alpha=0.1),
              model_t=MultiTaskElasticNet(alpha=0.1),
              model_final=FistaRegressor(penalty='trace', C=0.0001),
              fit_cate_intercept=False)
    est.fit(Y, T, X=X, W=W)
    te_pred = est.const_marginal_effect(np.median(X, axis=0, keepdims=True))
    print(te_pred)
    print(np.linalg.svd(te_pred[0]))


================================================
FILE: doc/spec/estimation/dr.rst
================================================
.. _druserguide:

======================
Doubly Robust Learning
======================

What is it?
==================================

Doubly Robust Learning, similar to Double Machine Learning, is a method for estimating (heterogeneous) treatment effects when
the treatment is categorical and all potential confounders/controls (factors that simultaneously had a direct effect on the treatment decision in the
collected data and the observed outcome) are observed, but are either too many (high-dimensional) for
classical statistical approaches to be applicable or their effect on 
the treatment and outcome cannot be satisfactorily modeled by parametric functions (non-parametric).
Both of these latter problems can be addressed via machine learning techniques (see e.g. [Chernozhukov2016]_, [Foster2019]_).
The method dates back to the early works of [Robins1994]_, [Bang]_ (see [Tsiatis]_ for more details), which applied
the method primarily for the estimation of average treatment effects. In this library we implement recent modifications
to the doubly robust approach that allow for the estimation of heterogeneous treatment effects (see e.g. [Foster2019]_).
The method has also been recently heavily used in the context of policy learning (see e.g. [Dudik2014]_, [Athey2017]_).

It reduces the problem to first estimating *two predictive tasks*: 

    1) predicting the outcome from the treatment and controls,
    2) predicting the treatment from the controls;

Thus unlike Double Machine Learning the first model predicts the outcome from both the treatment and the controls as
opposed to just the controls. Then the method combines these two predictive models in a final stage estimation so as to create a
model of the heterogeneous treatment effect. The approach allows for *arbitrary Machine Learning algorithms* to be
used for the two predictive tasks, while maintaining many favorable statistical properties related to the final
model (e.g. small mean squared error, asymptotic normality, construction of confidence intervals). The latter
favorable statistical properties hold if either the first or the second of the two predictive tasks achieves small mean
squared error (hence the name doubly robust).

Our package offers several variants for the final model estimation. Many of these variants also
provide *valid inference* (confidence interval construction) for measuring the uncertainty of the learned model.


What are the relevant estimator classes?
========================================

This section describes the methodology implemented in the classes, :class:`.DRLearner`,
:class:`.LinearDRLearner`,
:class:`.SparseLinearDRLearner`, :class:`.ForestDRLearner`.
Click on each of these links for a detailed module documentation and input parameters of each class.


When should you use it?
==================================

Suppose you have observational (or experimental from an A/B test) historical data, where some treatment/intervention/action
:math:`T` from among a finite set of treatments was chosen and some outcome(s) :math:`Y` was observed and all the variables :math:`W` that could have
potentially gone into the choice of :math:`T`, and simultaneously could have had a direct effect on the outcome
:math:`Y` (aka controls or confounders) are also recorded in the dataset.

If your goal is to understand what was the effect of each of the treatments on the outcome as a function of a set of observable
characteristics :math:`X` of the treated samples, then one can use this method. For instance call:

.. testsetup::

    import numpy as np
    X = np.random.choice(np.arange(5), size=(100,3))
    Y = np.random.normal(size=(100,2))
    y = np.random.normal(size=(100,))
    T = np.random.choice(np.arange(2), size=(100,))
    t0 = T0 = np.zeros((100,))
    t1 = T1 = np.ones((100,))
    W = np.random.normal(size=(100,2))

.. testcode::

    from econml.dr import LinearDRLearner
    est = LinearDRLearner()
    est.fit(y, T, X=X, W=W)
    est.effect(X, T0=t0, T1=t1)

This way an optimal treatment policy can be learned, by simply inspecting for which :math:`X` the effect was positive.


Overview of Formal Methodology
==================================

The model's assumptions are better explained in the language of potential outcomes. If we denote with :math:`Y^{(t)}` the potential outcome that
we would have observed had we treated the sample with treatment :math:`T=t`, then the approach assumes that:

.. math::

    Y^{(t)} =~& g_t(X, W) + \epsilon_t ~~~&~~~ \E[\epsilon | X, W] = 0 \\
    \Pr[T = t | X, W] =~& p_t(X, W) & \\
    \{Y^{(t)}\}_{t=1}^{n_t} \perp T | X, W

It makes no further structural assumptions on :math:`g_t` and :math:`p_t` and estimates them 
non-parametrically using arbitrary non-parametric Machine Learning methods. Our goal is to estimate
the CATE associated with each possible treatment :math:`t \in \{1, \ldots, n_t\}`, as compared to some baseline
treatment :math:`t=0`, i.e.: 

.. math::

    \theta_t(X) = \E[Y^{(t)} - Y^{(0)} | X] = \E[g_t(X, W) - g_0(X, W) | X]

One way to estimate :math:`\theta_t(X)` is the *Direct Method* (DM) approach,
where we simply estimate a regression,
regressing :math:`Y` on :math:`T, X, W` to learn a model
of :math:`g_T(X, W) = \E[Y | T, X, W]` and then evaluate :math:`\theta_t(X)` by regressing

.. math::

    Y_{i, t}^{DM} = g_t(X_i, W_i) - g_0(X_i, W_i)

on :math:`X`. The main problem with this approach is that it is heavily dependent
on the model-based extrapolation that is implicitly done via the model that is fitted in the regression. Essentially,
when we evaluate :math:`g_t(X, W)` on a sample with features :math:`X, W` for which we gave some other treatment
:math:`T=t'`, then we are extrapolating from other samples with similar :math:`X, W`, which received the treatment
:math:`T=t`. However, the definition of "similarity" is very model based and in some cases we might even be extrapolating
from very far away points (e.g. if we fit linear regression models).

An alternative approach that does not suffer from the aforementioned problems is the *Inverse Propensity Score* (IPS)
approach. This method starts from the realization that, due to the unconfoundedness assumption, we can create
an unbiased estimate of every potential outcome by re-weighting each sample by the inverse probability of that
sample receiving the treatment we observed (i.e. up-weighting samples that have "surprising" treatment assignments).
More concretely, if we let:

.. math::

    Y_{i, t}^{IPS} = \frac{Y_i 1\{T_i=t\}}{\Pr[T_i=t | X_i, W_i]} = \frac{Y_i 1\{T_i=t\}}{p_t(X_i, W_i)} 

then it holds that:

.. math::

    \E[Y_{i, t}^{IPS} | X, W] =~& \E\left[\frac{Y_i 1\{T_i=t\}}{p_t(X_i, W_i)} | X_i, W_i\right] = \E\left[\frac{Y_i^{(t)} 1\{T_i=t\}}{p_t(X_i, W_i)} | X_i, W_i\right]\\
    =~&  \E\left[\frac{Y_i^{(t)} \E[1\{T_i=t\} | X_i, W_i]}{p_t(X_i, W_i)} | X_i, W_i\right] = \E\left[Y_i^{(t)} | X_i, W_i\right]


Thus we can estimate a :math:`\theta_t(X)` by regressing :math:`Y_{i, t}^{IPS} - Y_{i, 0}^{IPS}` on :math:`X`. This
method has two drawbacks: 1) first, even if we knew the probability of treatment :math:`p_t(X, W)`, the approach has
high variance, because we are dividing the observation by a relatively small number (especially if some regions
of :math:`X, W`, some treatments are quite unlikely), 2) second, in observational data we typically don't know
the probability of treatment and thereby we also need to estimate a model for the probability of treatment.
This corresponds to a multi-class classification task, which when :math:`X, W` are high dimensional or when we
use non-linear models like random forests, could have slow estimation rates. This method will inherit these rates.
Moreover, if we use ML to fit these propensity models, then it is hard to characterize what the limit distribution
of our estimate will be so as to provide valid confidence intervals.

The *Doubly Robust* approach, avoids the above drawbacks by combining the two methods. In particular, it fits 
a direct regression model, but then debiases that model, by applying an Inverse Propensity approach to the
residual of that model, i.e. it constructs the following estimates of the potential outcomes:

.. math::
    Y_{i, t}^{DR} = g_t(X_i, W_i) + \frac{Y_i -g_t(X_i, W_i)}{p_t(X_i, W_i)} \cdot 1\{T_i=t\}

Then we can learn :math:`\theta_t(X)` by regressing :math:`Y_{i, t}^{DR} - Y_{i, 0}^{DR}` on :math:`X_i`.

This yields the overall algorithm: first learn a **regression model** :math:`\hat{g}_t(X, W)`, by running a regression
of :math:`Y` on :math:`T, X, W` and a **propensity model** :math:`\hat{p}_t(X, W)`, by running a classification to predict
:math:`T` from :math:`X, W`. Then construct the doubly robust random variables as described above and regress them on
:math:`X`.

The main advantage of the Doubly Robust method is that the mean squared error of the final estimate :math:`\theta_t(X)`,
is only affected by the product of the mean squared errors of the regression estimate :math:`\hat{g}_t(X, W)` and
the propensity estimate :math:`\hat{p}_t(X, W)`. Thus as long as one of them is accurate then the final model is correct.
For instance, as long as neither of them converges at a rate slower than :math:`n^{-1/4}`, then the final model achieves
parametric rates of :math:`n^{-1/2}`. Moreover, under some further assumption on what estimation algorithm
was used in the final stage, then the final estimate is asymptotically normal and valid confidence intervals can be constructed.
For this theorem to hold, the nuisance
estimates need to be fitted in a cross-fitting manner (see :class:`._OrthoLearner`).
The latter robustness property follows from the fact that the moment equations that correspond to the final 
least squares estimation (i.e. the gradient of the squared loss), satisfy a Neyman orthogonality condition with respect to the
nuisance parameters :math:`q, f`. For a more detailed exposition of how Neyman orthogonality 
leads to robustness we refer the reader to [Chernozhukov2016]_, [Mackey2017]_, [Nie2017]_, [Chernozhukov2017]_,
[Chernozhukov2018]_, [Foster2019]_. In fact, the doubly robust estimator satisfies a slightly stronger property
then Neyman orthogonality, which is why it possess the stronger robustness guarantee that only the product
of the two mean squared errors of the first stage models, matter for the error and the distributional properties
of the final estimator.

The other advantage of the Doubly Robust method compared to the DML method, is that the final regression is meaningful
even if the space of functions over which we minimize the final regression loss does not contain the true CATE function.
In that case, the method will estimate the projection of the CATE function onto the space of models over which
we optimize in the final regression. For instance, this allows one to perform inference on the best linear projection
of the CATE function or to perform inference on the best CATE function on a subset of the features that could potentially be
creating heterogeneity. For instance, one can use the DR method with a non-parametric final model like an Honest
Forest and perform inference of the marginal treatment effect heterogeneity with respect to a single feature, without
making any further assumptions on how that treatment effect heterogeneity looks like.

The downside of the DR method over DML is that it typically has higher variance, especially when there are regions
of the control space, :math:`X, W`, in which some treatment has a small probability of being assigned (typically referred
to as "small overlap" in the literature). In such settings, the DML method could potentially extrapolate better, as it only
requires good overlap "on-average" to achieve good mean squared error.


Class Hierarchy Structure
==================================

In this library we implement several variants of the Doubly Robust method, dependent on what type of estimation algorithm
is chosen for the final stage. The user can choose any regression/classification method for the first stage models
in all these variants. The hierarchy
structure of the implemented CATE estimators is as follows.

    .. inheritance-diagram:: econml.dr.DRLearner econml.dr.LinearDRLearner econml.dr.SparseLinearDRLearner econml.dr.ForestDRLearner
        :parts: 1
        :private-bases:
        :top-classes: econml._ortho_learner._OrthoLearner, econml._cate_estimator.StatsModelsCateEstimatorDiscreteMixin, econml._cate_estimator.DebiasedLassoCateEstimatorDiscreteMixin

Below we give a brief description of each of these classes:

    * **DRLearner.** The class :class:`.DRLearner` makes no assumption on the effect model for each outcome :math:`i`
      and treatment :math:`t`. Any scikit-learn regressor can be used for the final stage estimation. Similarly, any
      scikit-learn regressor can be used for the *regression model* and any scikit-learn classifier can be used
      for the *propensity model*:

      .. testcode::

        from econml.dr import DRLearner
        from sklearn.ensemble import GradientBoostingRegressor, GradientBoostingClassifier
        est = DRLearner(model_regression=GradientBoostingRegressor(),
                        model_propensity=GradientBoostingClassifier(),
                        model_final=GradientBoostingRegressor())
        est.fit(y, T, X=X, W=W)
        point = est.effect(X, T0=T0, T1=T1)

      Examples of models include Random Forests (:class:`~sklearn.ensemble.RandomForestRegressor`),
      Gradient Boosted Forests (:class:`~sklearn.ensemble.GradientBoostingRegressor`) and
      Support Vector Machines (:class:`~sklearn.svm.SVC`). Moreover, one can even use cross validated estimators
      that perform automatic model selection for each of these models:

      .. testcode::

        from econml.dr import DRLearner
        from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
        from sklearn.model_selection import GridSearchCV
        model_reg = lambda: GridSearchCV(
                        estimator=RandomForestRegressor(),
                        param_grid={
                                'max_depth': [3, None],
                                'n_estimators': (10, 50, 100)
                            }, cv=10, n_jobs=-1, scoring='neg_mean_squared_error'
                        )
        model_clf = lambda: GridSearchCV(
                        estimator=RandomForestClassifier(min_samples_leaf=10),
                        param_grid={
                                'max_depth': [3, None],
                                'n_estimators': (10, 50, 100)
                            }, cv=10, n_jobs=-1, scoring='neg_mean_squared_error'
                        )
        est = DRLearner(model_regression=model_reg(), model_propensity=model_clf(),
                        model_final=model_reg(), cv=5)
        est.fit(y, T, X=X, W=W)
        point = est.effect(X, T0=T0, T1=T1)

      From that respect this estimator is also a *Meta-Learner*, since all steps of the estimation use out-of-the-box ML algorithms. For more information,
      check out :ref:`Meta Learners User Guide <metalearnersuserguide>`. This general method was proposed in [Foster2019]_.

        - **LinearDRLearner.** The child class  :class:`.LinearDRLearner`, uses an unregularized final linear model and  
          essentially works only when the feature vector :math:`\phi(X)` is low dimensional. Given that it is an unregularized
          low dimensional final model, this class also offers confidence intervals via asymptotic normality 
          arguments. This is achieved by essentially using the :class:`.StatsModelsLinearRegression`
          (which is an extension of the scikit-learn LinearRegression estimator, that also supports inference
          functionalities) as a final model. The theoretical foundations of this class essentially follow the arguments in [Chernozhukov2016]_.
          For instance, to get confidence intervals on the effect of going
          from the baseline treatment (assumed to be treatment 0) to any other treatment T1, one can simply call:

          .. testcode::

            from econml.dr import LinearDRLearner
            est = LinearDRLearner()
            est.fit(y, T, X=X, W=W)
            point = est.effect(X, T1=t1)
            lb, ub = est.effect_interval(X, T1=t1, alpha=0.05)
            # Get CATE for all treatments
            point = est.const_marginal_effect(X)
            lb, ub = est.const_marginal_effect_interval(X, alpha=0.05)

          One could also construct bootstrap based confidence intervals by setting `inference='bootstrap'`.

        - **SparseLinearDRLearner.** The child class :class:`.SparseLinearDRLearner`, uses an :math:`\ell_1`-regularized final    
          model. In particular, it uses our implementation of the DebiasedLasso algorithm [Buhlmann2011]_ (see :class:`.DebiasedLasso`).
          Using the asymptotic normality properties
          of the debiased lasso, this class also offers asymptotically normal based confidence intervals.
          The theoretical foundations of this class essentially follow the arguments in [Chernozhukov2017]_, [Chernozhukov2018]_.
          For instance, to get confidence intervals on the effect of going
          from any treatment T0 to any other treatment T1, one can simply call:

          .. testcode::

            from econml.dr import SparseLinearDRLearner
            est = SparseLinearDRLearner()
            est.fit(y, T, X=X, W=W)
            point = est.effect(X, T1=T1)
            lb, ub = est.effect_interval(X, T1=T1, alpha=0.05)
            # Get CATE for all treatments
            point = est.const_marginal_effect(X)
            lb, ub = est.const_marginal_effect_interval(X, alpha=0.05)

        - **ForestDRLearner.** The child class :class:`.ForestDRLearner` uses a Subsampled Honest Forest regressor
          as a final model (see [Wager2018]_ and [Athey2019]_). The subsampled honest forest is implemented in our library as a scikit-learn extension
          of the :class:`~sklearn.ensemble.RandomForestRegressor`, in the class :class:`~econml.grf.RegressionForest`. This estimator
          offers confidence intervals via the Bootstrap-of-Little-Bags as described in [Athey2019]_.
          Using this functionality we can also construct confidence intervals for the CATE:

          .. testcode::

            from econml.dr import ForestDRLearner
            from sklearn.ensemble import GradientBoostingRegressor, GradientBoostingClassifier
            est = ForestDRLearner(model_regression=GradientBoostingRegressor(),
                                  model_propensity=GradientBoostingClassifier())
            est.fit(y, T, X=X, W=W)
            point = est.effect(X, T0=T0, T1=T1)
            lb, ub = est.effect_interval(X, T0=T0, T1=T1, alpha=0.05)

          This method is related to the :class:`.DROrthoForest` and you can check [Oprescu2019]_ for more technical details;
          the main difference being how the nuisance models are being constructed for the CATE estimation at some
          target :math:`X=x`. Check out :ref:`Forest Estimators User Guide <orthoforestuserguide>` for more information on forest based CATE models and other
          alternatives to the :class:`.CausalForestDML`.


Usage FAQs
==========

- **What if I want confidence intervals?**

    For valid confidence intervals use the :class:`.LinearDRLearner` if the number of features :math:`X`,
    that you want to use for heterogeneity are small compared to the number of samples that you have,
    e.g.:

    .. testcode::

        from econml.dr import LinearDRLearner
        est = LinearDRLearner()
        est.fit(y, T, X=X, W=W)
        lb, ub = est.const_marginal_effect_interval(X, alpha=.05)
        lb, ub = est.coef__interval(T=1, alpha=.05)
        lb, ub = est.effect_interval(X, T0=T0, T1=T1, alpha=.05)

    If the number of features is comparable or even larger than the number of samples, then use :class:`.SparseLinearDRLearner`,
    with ``inference='debiasedlasso``. If you
    want non-linear models then use :class:`.ForestDRLearner` with ``inference='blb'``.

- **What if I have no idea how heterogeneity looks like?**

    Either use a flexible featurizer, e.g. a polynomial featurizer with many degrees and use
    the :class:`.SparseLinearDRLearner`:

    .. testcode::

        from econml.dr import SparseLinearDRLearner
        from sklearn.preprocessing import PolynomialFeatures
        est = SparseLinearDRLearner(featurizer=PolynomialFeatures(degree=3, include_bias=False))
        est.fit(y, T, X=X, W=W)
        lb, ub = est.const_marginal_effect_interval(X, alpha=.05)
        lb, ub = est.coef__interval(T=1, alpha=.05)
        lb, ub = est.effect_interval(X, T0=T0, T1=T1, alpha=.05)

    Alternatively, you can also use a forest based estimator such as :class:`.ForestDRLearner`. This 
    estimator can also handle many features, albeit typically smaller number of features than the sparse linear DRLearner.
    Moreover, this estimator essentially performs automatic featurization and can fit non-linear models.

    .. testcode::

        from econml.dr import ForestDRLearner
        from sklearn.ensemble import GradientBoostingRegressor, GradientBoostingClassifier
        est = ForestDRLearner(model_regression=GradientBoostingRegressor(),
                              model_propensity=GradientBoostingClassifier())
        est.fit(y, T, X=X, W=W)
        point = est.effect(X, T0=T0, T1=T1)
        lb, ub = est.effect_interval(X, T0=T0, T1=T1, alpha=0.05)
        lb, ub = est.const_marginal_effect_interval(X, alpha=0.05)

    If you care more about mean squared error than confidence intervals and hypothesis testing, then use the
    :class:`.DRLearner` class and choose a cross-validated final model (checkout the 
    `Forest Learners Jupyter notebook <https://github.com/py-why/EconML/blob/main/notebooks/ForestLearners%20Basic%20Example.ipynb>`_ 
    for such an example).
    Also the check out the :ref:`Orthogonal Random Forest User Guide <orthoforestuserguide>` or the
    :ref:`Meta Learners User Guide <metalearnersuserguide>`.

- **What if I have too many features that can create heterogeneity?**

    Use the :class:`.SparseLinearDRLearner` or :class:`.ForestDRLearner` or :class:`.DRLearner`. (see above).

- **What if I have too many features I want to control for?**

    Use first stage models that work well with high dimensional features. For instance, the Lasso or the 
    ElasticNet or gradient boosted forests are all good options (the latter allows for 
    non-linearities in the model but can typically handle fewer features than the former), e.g.:

    .. testcode::

        from econml.dr import SparseLinearDRLearner
        from sklearn.linear_model import LassoCV, LogisticRegressionCV, ElasticNetCV
        from sklearn.ensemble import GradientBoostingRegressor
        est = SparseLinearDRLearner(model_regression=LassoCV(),
                                    model_propensity=LogisticRegressionCV())
        est = SparseLinearDRLearner(model_regression=ElasticNetCV(),
                                    model_propensity=LogisticRegressionCV())
        est = SparseLinearDRLearner(model_regression=GradientBoostingRegressor(),
                                    model_propensity=GradientBoostingClassifier())

    The confidence intervals will still be valid, provided that these first stage models achieve small
    mean squared error.

- **What should I use for first stage estimation?**

    See above. The first stage problems are pure predictive tasks, so any ML approach that is relevant for your
    prediction problem is good.

- **How do I select the hyperparameters of the first stage models or the final model?**

    You can use cross-validated models that automatically choose the hyperparameters, e.g. the
    :class:`~sklearn.linear_model.LassoCV` instead of the :class:`~sklearn.linear_model.Lasso`. Similarly,
    for forest based estimators you can wrap them with a grid search CV, :class:`~sklearn.model_selection.GridSearchCV`, e.g.:

    .. testcode::

        from econml.dr import DRLearner
        from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
        from sklearn.model_selection import GridSearchCV
        model_reg = lambda: GridSearchCV(
                        estimator=RandomForestRegressor(),
                        param_grid={
                                'max_depth': [3, None],
                                'n_estimators': (10, 50, 100)
                            }, cv=5, n_jobs=-1, scoring='neg_mean_squared_error'
                        )
        model_clf = lambda: GridSearchCV(
                        estimator=RandomForestClassifier(min_samples_leaf=10),
                        param_grid={
                                'max_depth': [3, None],
                                'n_estimators': (10, 50, 100)
                            }, cv=5, n_jobs=-1, scoring='neg_mean_squared_error'
                        )
        est = DRLearner(model_regression=model_reg(), model_propensity=model_clf(),
                        model_final=model_reg(), cv=5)
        est.fit(y, T, X=X, W=W)
        point = est.effect(X, T0=T0, T1=T1)

    Alternatively, you can pick the best first stage models outside of the EconML framework and pass in the selected models to EconML. 
    This can save on runtime and computational resources. Furthermore, it is statistically more stable since all data is being used for
    hyper-parameter tuning rather than a single fold inside of the DML algorithm (as long as the number of hyperparameter values
    that you are selecting over is not exponential in the number of samples, this approach is statistically valid). E.g.:

    .. testcode::

        from econml.dr import DRLearner
        from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
        from sklearn.model_selection import GridSearchCV
        model_reg = lambda: GridSearchCV(
                        estimator=RandomForestRegressor(),
                        param_grid={
                                'max_depth': [3, None],
                             
Download .txt
gitextract_2llsel0e/

├── .github/
│   └── workflows/
│       ├── ci.yml
│       ├── generate_lkg.py
│       ├── publish-documentation.yml
│       └── publish-package.yml
├── .gitignore
├── .pre-commit-config.yaml
├── LICENSE
├── README.md
├── SECURITY.md
├── doc/
│   ├── conf.py
│   ├── index.rst
│   ├── reference.rst
│   └── spec/
│       ├── api.rst
│       ├── causal_intro.rst
│       ├── community.rst
│       ├── comparison.rst
│       ├── estimation/
│       │   ├── dml.rst
│       │   ├── dr.rst
│       │   ├── dynamic_dml.rst
│       │   ├── forest.rst
│       │   ├── metalearners.rst
│       │   ├── orthoiv.rst
│       │   └── two_sls.rst
│       ├── estimation.rst
│       ├── estimation_dynamic.rst
│       ├── estimation_iv.rst
│       ├── faq.rst
│       ├── federated_learning.rst
│       ├── flowchart.rst
│       ├── inference.rst
│       ├── interpretability.rst
│       ├── model_selection.rst
│       ├── motivation.rst
│       ├── overview.rst
│       ├── references.rst
│       ├── spec.rst
│       └── validation.rst
├── econml/
│   ├── __init__.py
│   ├── _cate_estimator.py
│   ├── _ensemble/
│   │   ├── __init__.py
│   │   ├── _ensemble.py
│   │   └── _utilities.py
│   ├── _ortho_learner.py
│   ├── _shap.py
│   ├── _tree_exporter.py
│   ├── _version.py
│   ├── automated_ml/
│   │   ├── __init__.py
│   │   └── _automated_ml.py
│   ├── cate_interpreter/
│   │   ├── __init__.py
│   │   └── _interpreters.py
│   ├── data/
│   │   ├── __init__.py
│   │   ├── color-edits.sty
│   │   ├── data_doc.bib
│   │   ├── data_doc.tex
│   │   ├── dgps.py
│   │   ├── dynamic_panel_dgp.py
│   │   ├── ihdp/
│   │   │   ├── example.csv
│   │   │   ├── example_full.csv
│   │   │   └── sim.csv
│   │   └── input_dynamicdgp/
│   │       ├── cov_new.jbl
│   │       ├── gm_0.jbl
│   │       ├── gm_1.jbl
│   │       ├── gm_2.jbl
│   │       ├── gm_3.jbl
│   │       ├── gm_4.jbl
│   │       ├── gm_5.jbl
│   │       ├── gm_6.jbl
│   │       ├── lognorm_neg_0.jbl
│   │       ├── lognorm_neg_1.jbl
│   │       ├── lognorm_neg_2.jbl
│   │       ├── lognorm_neg_3.jbl
│   │       ├── lognorm_neg_4.jbl
│   │       ├── lognorm_neg_5.jbl
│   │       ├── lognorm_pos_0.jbl
│   │       ├── lognorm_pos_1.jbl
│   │       ├── lognorm_pos_2.jbl
│   │       ├── lognorm_pos_3.jbl
│   │       ├── lognorm_pos_4.jbl
│   │       ├── lognorm_pos_5.jbl
│   │       ├── lognorm_pos_6.jbl
│   │       ├── n_0.jbl
│   │       ├── n_1.jbl
│   │       ├── n_2.jbl
│   │       ├── n_3.jbl
│   │       ├── n_4.jbl
│   │       ├── n_5.jbl
│   │       └── n_6.jbl
│   ├── dml/
│   │   ├── __init__.py
│   │   ├── _rlearner.py
│   │   ├── causal_forest.py
│   │   └── dml.py
│   ├── dowhy.py
│   ├── dr/
│   │   ├── __init__.py
│   │   └── _drlearner.py
│   ├── federated_learning.py
│   ├── grf/
│   │   ├── __init__.py
│   │   ├── _base_grf.py
│   │   ├── _base_grftree.py
│   │   ├── _criterion.pxd
│   │   ├── _criterion.pyx
│   │   ├── _utils.pxd
│   │   ├── _utils.pyx
│   │   └── classes.py
│   ├── inference/
│   │   ├── __init__.py
│   │   ├── _bootstrap.py
│   │   └── _inference.py
│   ├── iv/
│   │   ├── __init__.py
│   │   ├── dml/
│   │   │   ├── __init__.py
│   │   │   └── _dml.py
│   │   ├── dr/
│   │   │   ├── __init__.py
│   │   │   └── _dr.py
│   │   └── sieve/
│   │       ├── __init__.py
│   │       └── _tsls.py
│   ├── metalearners/
│   │   ├── __init__.py
│   │   └── _metalearners.py
│   ├── orf/
│   │   ├── __init__.py
│   │   ├── _causal_tree.py
│   │   └── _ortho_forest.py
│   ├── panel/
│   │   ├── __init__.py
│   │   ├── dml/
│   │   │   ├── __init__.py
│   │   │   └── _dml.py
│   │   └── utilities.py
│   ├── policy/
│   │   ├── __init__.py
│   │   ├── _base.py
│   │   ├── _drlearner.py
│   │   └── _forest/
│   │       ├── __init__.py
│   │       ├── _criterion.pxd
│   │       ├── _criterion.pyx
│   │       ├── _forest.py
│   │       └── _tree.py
│   ├── score/
│   │   ├── __init__.py
│   │   ├── ensemble_cate.py
│   │   └── rscorer.py
│   ├── sklearn_extensions/
│   │   ├── __init__.py
│   │   ├── linear_model.py
│   │   └── model_selection.py
│   ├── solutions/
│   │   └── causal_analysis/
│   │       ├── __init__.py
│   │       └── _causal_analysis.py
│   ├── tests/
│   │   ├── __init__.py
│   │   ├── dgp.py
│   │   ├── test_ate_inference.py
│   │   ├── test_automated_ml.py
│   │   ├── test_bootstrap.py
│   │   ├── test_cate_interpreter.py
│   │   ├── test_causal_analysis.py
│   │   ├── test_discrete_outcome.py
│   │   ├── test_dml.py
│   │   ├── test_dmliv.py
│   │   ├── test_dominicks.py
│   │   ├── test_dowhy.py
│   │   ├── test_driv.py
│   │   ├── test_drlearner.py
│   │   ├── test_drtester.py
│   │   ├── test_dynamic_dml.py
│   │   ├── test_federated_learning.py
│   │   ├── test_grf_cython.py
│   │   ├── test_grf_python.py
│   │   ├── test_inference.py
│   │   ├── test_integration.py
│   │   ├── test_linear_model.py
│   │   ├── test_metalearners.py
│   │   ├── test_missing_values.py
│   │   ├── test_model_selection.py
│   │   ├── test_montecarlo.py
│   │   ├── test_notebooks.py
│   │   ├── test_orf.py
│   │   ├── test_ortho_learner.py
│   │   ├── test_policy_forest.py
│   │   ├── test_random_state.py
│   │   ├── test_refit.py
│   │   ├── test_rscorer.py
│   │   ├── test_sensitivity_analysis.py
│   │   ├── test_shap.py
│   │   ├── test_statsmodels.py
│   │   ├── test_treatment_featurization.py
│   │   ├── test_tree.py
│   │   ├── test_two_stage_least_squares.py
│   │   ├── test_utilities.py
│   │   └── utilities.py
│   ├── tree/
│   │   ├── __init__.py
│   │   ├── _criterion.pxd
│   │   ├── _criterion.pyx
│   │   ├── _splitter.pxd
│   │   ├── _splitter.pyx
│   │   ├── _tree.pxd
│   │   ├── _tree.pyx
│   │   ├── _tree_classes.py
│   │   ├── _utils.pxd
│   │   └── _utils.pyx
│   ├── utilities.py
│   └── validate/
│       ├── __init__.py
│       ├── drtester.py
│       ├── results.py
│       ├── sensitivity_analysis.py
│       └── utils.py
├── lkg-notebook.txt
├── lkg.txt
├── monte_carlo_tests/
│   ├── monte_carlo_honestforest.py
│   └── monte_carlo_statsmodels.py
├── notebooks/
│   ├── AutomatedML/
│   │   └── Automated Machine Learning For EconML.ipynb
│   ├── CATE validation.ipynb
│   ├── Causal Forest and Orthogonal Random Forest Examples.ipynb
│   ├── Causal Model Selection with the RScorer.ipynb
│   ├── Choosing First Stage Models.ipynb
│   ├── CustomerScenarios/
│   │   ├── Case Study - Customer Segmentation at An Online Media Company - EconML + DoWhy.ipynb
│   │   ├── Case Study - Customer Segmentation at An Online Media Company.ipynb
│   │   ├── Case Study - Long-Term Return-on-Investment via Short-Term Proxies.ipynb
│   │   ├── Case Study - Multi-investment Attribution at A Software Company - EconML + DoWhy.ipynb
│   │   ├── Case Study - Multi-investment Attribution at A Software Company.ipynb
│   │   ├── Case Study - Recommendation AB Testing at An Online Travel Company - EconML + DoWhy.ipynb
│   │   ├── Case Study - Recommendation AB Testing at An Online Travel Company.ipynb
│   │   └── Case Study - Using EconML to evaluate the treatment effect of training program - Lalonde dataset.ipynb
│   ├── Double Machine Learning Examples.ipynb
│   ├── Doubly Robust Learner and Interpretability.ipynb
│   ├── Dynamic Double Machine Learning Examples.ipynb
│   ├── ForestLearners Basic Example.ipynb
│   ├── Generalized Random Forests.ipynb
│   ├── Interpretability with SHAP.ipynb
│   ├── Metalearners Examples.ipynb
│   ├── OrthoIV and DRIV Examples.ipynb
│   ├── Policy Learning with Trees and Forests.ipynb
│   ├── Scaling EconML using Ray.ipynb
│   ├── Solutions/
│   │   ├── Causal Interpretation for Ames Housing Price.ipynb
│   │   └── Causal Interpretation for Employee Attrition Dataset.ipynb
│   ├── Treatment Featurization Examples.ipynb
│   └── Weighted Double Machine Learning Examples.ipynb
├── prototypes/
│   ├── dml_iv/
│   │   ├── NLSYM_GBM.ipynb
│   │   ├── NLSYM_Linear.ipynb
│   │   ├── NLSYM_Semi_Synthetic_GBM.ipynb
│   │   ├── NLSYM_Semi_Synthetic_Linear.ipynb
│   │   ├── README.md
│   │   ├── TA_DGP_analysis.ipynb
│   │   ├── TA_DGP_analysis_Step_CATE.ipynb
│   │   ├── coverage_experiment.py
│   │   ├── data/
│   │   │   ├── NEW7080.dta
│   │   │   ├── card.csv
│   │   │   ├── code_bk.txt
│   │   │   └── readme
│   │   ├── deep_dml_iv.py
│   │   ├── deep_dr_iv.py
│   │   ├── dml_ate_iv.py
│   │   ├── dml_iv.py
│   │   ├── dr_iv.py
│   │   ├── post_processing.ipynb
│   │   ├── utilities.py
│   │   └── xgb_utilities.py
│   ├── dynamic_dml/
│   │   ├── README.md
│   │   ├── all_coverage.sh
│   │   ├── coverage_panel.py
│   │   ├── coverage_panel_hetero.py
│   │   ├── dynamic_panel_dgp.py
│   │   ├── hetero_panel_dynamic_dml.py
│   │   ├── high_dim_state_any_m_panel.ipynb
│   │   ├── high_dim_state_any_m_panel_hetero.ipynb
│   │   ├── panel_dynamic_dml.py
│   │   ├── postprocess_panel.ipynb
│   │   └── postprocess_panel_hetero.ipynb
│   ├── orthogonal_forests/
│   │   ├── GRF_treatment_effects.R
│   │   ├── README.md
│   │   ├── causal_tree.py
│   │   ├── comparison_plots.py
│   │   ├── hetero_dml.py
│   │   ├── monte_carlo.py
│   │   ├── ortho_forest.py
│   │   ├── residualizer.py
│   │   └── seq_map.sh
│   └── sensitivity_analysis/
│       ├── ovb_dml.ipynb
│       └── ovb_dr.ipynb
├── pyproject.toml
└── setup.py
Download .txt
SYMBOL INDEX (2220 symbols across 107 files)

FILE: .github/workflows/generate_lkg.py
  function simple_constraint_map (line 31) | def simple_constraint_map(all_combos: frozenset[Combo]) -> tuple[dict[fr...
  function make_req_file (line 124) | def make_req_file(requirements_directory, regex):

FILE: doc/conf.py
  function exclude_entity (line 250) | def exclude_entity(app, what, name, obj, skip, opts):
  function setup (line 258) | def setup(app):

FILE: econml/_cate_estimator.py
  class BaseCateEstimator (line 22) | class BaseCateEstimator(metaclass=abc.ABCMeta):
    method _get_inference_options (line 25) | def _get_inference_options(self):
    method _get_inference (line 33) | def _get_inference(self, inference):
    method _set_input_names (line 49) | def _set_input_names(self, Y, T, X, set_flag=False):
    method _strata (line 61) | def _strata(self, Y, T, *args, **kwargs):
    method _prefit (line 78) | def _prefit(self, Y, T, *args, **kwargs):
    method _postfit (line 89) | def _postfit(self, Y, T, *args, **kwargs):
    method fit (line 94) | def fit(self, *args, inference=None, **kwargs):
    method _wrap_fit (line 126) | def _wrap_fit(m):
    method effect (line 144) | def effect(self, X=None, *, T0, T1):
    method marginal_effect (line 170) | def marginal_effect(self, T, X=None):
    method ate (line 194) | def ate(self, X=None, *, T0, T1):
    method cate_feature_names (line 218) | def cate_feature_names(self, feature_names=None):
    method cate_output_names (line 240) | def cate_output_names(self, output_names=None):
    method cate_treatment_names (line 263) | def cate_treatment_names(self, treatment_names=None):
    method marginal_ate (line 286) | def marginal_ate(self, T, X=None):
    method _expand_treatments (line 310) | def _expand_treatments(self, X=None, *Ts):
    method _use_inference_method (line 327) | def _use_inference_method(self, name, *args, **kwargs):
    method _defer_to_inference (line 333) | def _defer_to_inference(m):
    method effect_interval (line 345) | def effect_interval(self, X=None, *, T0=0, T1=1, alpha=0.05):
    method effect_inference (line 372) | def effect_inference(self, X=None, *, T0=0, T1=1):
    method marginal_effect_interval (line 398) | def marginal_effect_interval(self, T, X=None, *, alpha=0.05):
    method marginal_effect_inference (line 424) | def marginal_effect_inference(self, T, X=None):
    method ate_interval (line 448) | def ate_interval(self, X=None, *, T0, T1, alpha=0.05):
    method ate_inference (line 475) | def ate_inference(self, X=None, *, T0, T1):
    method marginal_ate_interval (line 501) | def marginal_ate_interval(self, T, X=None, *, alpha=0.05):
    method marginal_ate_inference (line 527) | def marginal_ate_inference(self, T, X=None):
    method dowhy (line 551) | def dowhy(self):
  class LinearCateEstimator (line 563) | class LinearCateEstimator(BaseCateEstimator):
    method const_marginal_effect (line 569) | def const_marginal_effect(self, X=None):
    method effect (line 592) | def effect(self, X=None, *, T0, T1):
    method marginal_effect (line 633) | def marginal_effect(self, T, X=None):
    method marginal_effect_interval (line 680) | def marginal_effect_interval(self, T, X=None, *, alpha=0.05):
    method marginal_effect_inference (line 691) | def marginal_effect_inference(self, T, X=None):
    method const_marginal_effect_interval (line 703) | def const_marginal_effect_interval(self, X=None, *, alpha=0.05):
    method const_marginal_effect_inference (line 727) | def const_marginal_effect_inference(self, X=None):
    method const_marginal_ate (line 748) | def const_marginal_ate(self, X=None):
    method const_marginal_ate_interval (line 769) | def const_marginal_ate_interval(self, X=None, *, alpha=0.05):
    method const_marginal_ate_inference (line 793) | def const_marginal_ate_inference(self, X=None):
    method marginal_ate (line 813) | def marginal_ate(self, T, X=None):
    method marginal_ate_interval (line 818) | def marginal_ate_interval(self, T, X=None, *, alpha=0.05):
    method marginal_ate_inference (line 823) | def marginal_ate_inference(self, T, X=None):
    method shap_values (line 827) | def shap_values(self, X, *, feature_names=None, treatment_names=None, ...
  class TreatmentExpansionMixin (line 861) | class TreatmentExpansionMixin(BaseCateEstimator):
    method _prefit (line 871) | def _prefit(self, Y, T, *args, **kwargs):
    method _postfit (line 877) | def _postfit(self, Y, T, *args, **kwargs):
    method _expand_treatments (line 882) | def _expand_treatments(self, X=None, *Ts, transform=True):
    method _set_transformed_treatment_names (line 907) | def _set_transformed_treatment_names(self):
    method cate_treatment_names (line 917) | def cate_treatment_names(self, treatment_names=None):
    method effect (line 943) | def effect(self, X=None, *, T0=0, T1=1):
    method ate (line 948) | def ate(self, X=None, *, T0=0, T1=1):
    method ate_interval (line 952) | def ate_interval(self, X=None, *, T0=0, T1=1, alpha=0.05):
    method ate_inference (line 956) | def ate_inference(self, X=None, *, T0=0, T1=1):
  class LinearModelFinalCateEstimatorMixin (line 961) | class LinearModelFinalCateEstimatorMixin(BaseCateEstimator):
    method _get_inference_options (line 980) | def _get_inference_options(self):
    method bias_part_of_coef (line 986) | def bias_part_of_coef(self):
    method coef_ (line 990) | def coef_(self):
    method intercept_ (line 1009) | def intercept_(self):
    method coef__interval (line 1028) | def coef__interval(self, *, alpha=0.05):
    method coef__inference (line 1046) | def coef__inference(self):
    method intercept__interval (line 1058) | def intercept__interval(self, *, alpha=0.05):
    method intercept__inference (line 1076) | def intercept__inference(self):
    method summary (line 1087) | def summary(self, alpha=0.05, value=0, decimals=3, feature_names=None,...
    method shap_values (line 1180) | def shap_values(self, X, *, feature_names=None, treatment_names=None, ...
  class StatsModelsCateEstimatorMixin (line 1194) | class StatsModelsCateEstimatorMixin(LinearModelFinalCateEstimatorMixin):
    method _get_inference_options (line 1205) | def _get_inference_options(self):
  class DebiasedLassoCateEstimatorMixin (line 1213) | class DebiasedLassoCateEstimatorMixin(LinearModelFinalCateEstimatorMixin):
    method _get_inference_options (line 1216) | def _get_inference_options(self):
  class ForestModelFinalCateEstimatorMixin (line 1224) | class ForestModelFinalCateEstimatorMixin(BaseCateEstimator):
    method _get_inference_options (line 1226) | def _get_inference_options(self):
    method feature_importances_ (line 1234) | def feature_importances_(self):
  class LinearModelFinalCateEstimatorDiscreteMixin (line 1238) | class LinearModelFinalCateEstimatorDiscreteMixin(BaseCateEstimator):
    method _get_inference_options (line 1247) | def _get_inference_options(self):
    method coef_ (line 1252) | def coef_(self, T):
    method intercept_ (line 1273) | def intercept_(self, T):
    method coef__interval (line 1294) | def coef__interval(self, T, *, alpha=0.05):
    method coef__inference (line 1314) | def coef__inference(self, T):
    method intercept__interval (line 1331) | def intercept__interval(self, T, *, alpha=0.05):
    method intercept__inference (line 1351) | def intercept__inference(self, T):
    method summary (line 1368) | def summary(self, T, *, alpha=0.05, value=0, decimals=3,
  class StatsModelsCateEstimatorDiscreteMixin (line 1440) | class StatsModelsCateEstimatorDiscreteMixin(LinearModelFinalCateEstimato...
    method _get_inference_options (line 1450) | def _get_inference_options(self):
  class DebiasedLassoCateEstimatorDiscreteMixin (line 1458) | class DebiasedLassoCateEstimatorDiscreteMixin(LinearModelFinalCateEstima...
    method _get_inference_options (line 1461) | def _get_inference_options(self):
  class ForestModelFinalCateEstimatorDiscreteMixin (line 1469) | class ForestModelFinalCateEstimatorDiscreteMixin(BaseCateEstimator):
    method _get_inference_options (line 1471) | def _get_inference_options(self):
    method feature_importances_ (line 1478) | def feature_importances_(self, T):

FILE: econml/_ensemble/_ensemble.py
  function _fit_single_estimator (line 25) | def _fit_single_estimator(estimator, X, y, sample_weight=None,
  function _set_random_states (line 45) | def _set_random_states(estimator, random_state):
  class BaseEnsemble (line 79) | class BaseEnsemble(BaseEstimator, metaclass=ABCMeta):
    method __init__ (line 105) | def __init__(self, base_estimator, *, n_estimators=10,
    method _validate_estimator (line 116) | def _validate_estimator(self, default=None):
    method _make_estimator (line 138) | def _make_estimator(self, append=True, random_state=None):
    method __len__ (line 157) | def __len__(self):
    method __getitem__ (line 161) | def __getitem__(self, index):
    method __iter__ (line 165) | def __iter__(self):
  function _partition_estimators (line 170) | def _partition_estimators(n_estimators, n_jobs):

FILE: econml/_ensemble/_utilities.py
  function _get_n_samples_subsample (line 8) | def _get_n_samples_subsample(n_samples, max_samples):
  function _accumulate_prediction (line 47) | def _accumulate_prediction(predict, X, out, lock, *args, **kwargs):
  function _accumulate_prediction_var (line 64) | def _accumulate_prediction_var(predict, X, out, lock, *args, **kwargs):
  function _accumulate_prediction_and_var (line 91) | def _accumulate_prediction_and_var(predict, X, out, out_var, lock, *args...
  function _accumulate_oob_preds (line 118) | def _accumulate_oob_preds(tree, X, subsample_inds, alpha_hat, jac_hat, c...

FILE: econml/_ortho_learner.py
  function _fit_fold (line 54) | def _fit_fold(model, train_idxs, test_idxs, calculate_scores, args, kwar...
  function _crossfit (line 112) | def _crossfit(models: Union[ModelSelector, List[ModelSelector]], folds, ...
  class _OrthoLearner (line 312) | class _OrthoLearner(TreatmentExpansionMixin, LinearCateEstimator):
    method __init__ (line 559) | def __init__(self, *,
    method _gen_allowed_missing_vars (line 586) | def _gen_allowed_missing_vars(self):
    method _gen_ortho_learner_model_nuisance (line 590) | def _gen_ortho_learner_model_nuisance(self):
    method _gen_ortho_learner_model_final (line 616) | def _gen_ortho_learner_model_final(self):
    method _check_input_dims (line 638) | def _check_input_dims(self, Y, T, X=None, W=None, Z=None, *other_arrays):
    method _check_fitted_dims (line 646) | def _check_fitted_dims(self, X):
    method _check_fitted_dims_w_z (line 652) | def _check_fitted_dims_w_z(self, W, Z):
    method _subinds_check_none (line 663) | def _subinds_check_none(self, var, inds):
    method _strata (line 666) | def _strata(self, Y, T, X=None, W=None, Z=None,
    method _prefit (line 679) | def _prefit(self, Y, T, *args, only_final=False, **kwargs):
    method fit (line 690) | def fit(self, Y, T, *, X=None, W=None, Z=None, sample_weight=None, fre...
    method _illegal_refit_inference_methods (line 888) | def _illegal_refit_inference_methods(self):
    method refit_final (line 891) | def refit_final(self, inference=None):
    method _fit_nuisances (line 924) | def _fit_nuisances(self, Y, T, X=None, W=None, Z=None, sample_weight=N...
    method _fit_final (line 977) | def _fit_final(self, Y, T, X=None, W=None, Z=None, nuisances=None, sam...
    method const_marginal_effect (line 992) | def const_marginal_effect(self, X=None):
    method const_marginal_effect_interval (line 1006) | def const_marginal_effect_interval(self, X=None, *, alpha=0.05):
    method const_marginal_effect_inference (line 1017) | def const_marginal_effect_inference(self, X=None):
    method effect_interval (line 1028) | def effect_interval(self, X=None, *, T0=0, T1=1, alpha=0.05):
    method effect_inference (line 1040) | def effect_inference(self, X=None, *, T0=0, T1=1):
    method score (line 1052) | def score(self, Y, T, X=None, W=None, Z=None, sample_weight=None, grou...
    method ortho_learner_model_final_ (line 1161) | def ortho_learner_model_final_(self):
    method models_nuisance_ (line 1167) | def models_nuisance_(self):

FILE: econml/_shap.py
  function _shap_explain_cme (line 22) | def _shap_explain_cme(cme_model, X, d_t, d_y,
  function _shap_explain_model_cate (line 90) | def _shap_explain_model_cate(cme_model, models, X, d_t, d_y, featurizer=...
  function _shap_explain_joint_linear_model_cate (line 187) | def _shap_explain_joint_linear_model_cate(model_final, X, d_t, d_y, fit_...
  function _shap_explain_multitask_model_cate (line 269) | def _shap_explain_multitask_model_cate(cme_model, multitask_model_cate, ...
  function _define_names (line 366) | def _define_names(d_t, d_y, treatment_names, output_names, feature_names...

FILE: econml/_tree_exporter.py
  function _color_brew (line 48) | def _color_brew(n):
  class _TreeExporter (line 90) | class _TreeExporter(_BaseTreeExporter):
    method node_replacement_text (line 93) | def node_replacement_text(self, tree, node_id, criterion):
    method node_to_str (line 96) | def node_to_str(self, tree, node_id, criterion):
  class _MPLExporter (line 110) | class _MPLExporter(_MPLTreeExporter):
    method __init__ (line 113) | def __init__(self, *args, title=None, **kwargs):
    method export (line 117) | def export(self, decision_tree, node_dict=None, ax=None):
  class _DOTExporter (line 127) | class _DOTExporter(_DOTTreeExporter):
    method __init__ (line 130) | def __init__(self, *args, title=None, **kwargs):
    method export (line 134) | def export(self, decision_tree, node_dict=None):
    method tail (line 138) | def tail(self):
  class _CateTreeMixin (line 145) | class _CateTreeMixin(_TreeExporter):
    method __init__ (line 148) | def __init__(self, include_uncertainty=False, uncertainty_level=0.1,
    method get_fill_color (line 155) | def get_fill_color(self, tree, node_id):
    method node_replacement_text (line 177) | def node_replacement_text(self, tree, node_id, criterion):
  class _PolicyTreeMixin (line 241) | class _PolicyTreeMixin(_TreeExporter):
    method __init__ (line 251) | def __init__(self, *args, treatment_names=None, **kwargs):
    method get_fill_color (line 255) | def get_fill_color(self, tree, node_id):
    method node_replacement_text (line 267) | def node_replacement_text(self, tree, node_id, criterion):
    method _node_replacement_text_with_dict (line 287) | def _node_replacement_text_with_dict(self, tree, node_id, criterion):
  class _PolicyTreeMPLExporter (line 333) | class _PolicyTreeMPLExporter(_PolicyTreeMixin, _MPLExporter):
    method __init__ (line 368) | def __init__(self, treatment_names=None, title=None, feature_names=None,
  class _CateTreeMPLExporter (line 380) | class _CateTreeMPLExporter(_CateTreeMixin, _MPLExporter):
    method __init__ (line 421) | def __init__(self, include_uncertainty, uncertainty_level, title=None,
  class _PolicyTreeDOTExporter (line 435) | class _PolicyTreeDOTExporter(_PolicyTreeMixin, _DOTExporter):
    method __init__ (line 481) | def __init__(self, out_file=None, title=None, treatment_names=None, fe...
  class _CateTreeDOTExporter (line 492) | class _CateTreeDOTExporter(_CateTreeMixin, _DOTExporter):
    method __init__ (line 544) | def __init__(self, include_uncertainty, uncertainty_level, out_file=No...
  class _SingleTreeExporterMixin (line 557) | class _SingleTreeExporterMixin(metaclass=abc.ABCMeta):
    method _make_dot_exporter (line 563) | def _make_dot_exporter(self, *, out_file, feature_names, treatment_nam...
    method _make_mpl_exporter (line 611) | def _make_mpl_exporter(self, *, title=None, feature_names=None, treatm...
    method export_graphviz (line 648) | def export_graphviz(self, out_file=None, feature_names=None, treatment...
    method render (line 718) | def render(self, out_file, format='pdf', view=True, feature_names=None,
    method plot (line 777) | def plot(self, ax=None, title=None, feature_names=None, treatment_name...

FILE: econml/automated_ml/_automated_ml.py
  function setAutomatedMLWorkspace (line 48) | def setAutomatedMLWorkspace(create_workspace=False,
  function addAutomatedML (line 114) | def addAutomatedML(baseClass):
  class AutomatedMLModel (line 141) | class AutomatedMLModel():
    method __init__ (line 142) | def __init__(self, automl_config, workspace, experiment_name_prefix="a...
    method fit (line 170) | def fit(self, X, y, sample_weight=None):
    method predict (line 204) | def predict(self, X):
    method predict_proba (line 213) | def predict_proba(self, X):
  class _InnerAutomatedMLModel (line 223) | class _InnerAutomatedMLModel():
    method __init__ (line 225) | def __init__(self, automl_config, workspace,
    method get_params (line 232) | def get_params(self, deep=True):
    method fit (line 241) | def fit(self, X, y, sample_weight=None):
    method predict (line 259) | def predict(self, X):
    method predict_proba (line 262) | def predict_proba(self, X):
  class AutomatedMLMixin (line 266) | class AutomatedMLMixin():
    method __init__ (line 267) | def __init__(self, *args, **kwargs):
    method _get_automated_ml_model (line 307) | def _get_automated_ml_model(self, automl_config, prefix):
  class EconAutoMLConfig (line 320) | class EconAutoMLConfig(AutoMLConfig):
    method __init__ (line 322) | def __init__(self, sample_weights_required=False, linear_model_require...

FILE: econml/cate_interpreter/_interpreters.py
  class _SingleTreeInterpreter (line 15) | class _SingleTreeInterpreter(_SingleTreeExporterMixin, metaclass=abc.ABC...
    method interpret (line 18) | def interpret(self, cate_estimator, X):
  class SingleTreeCateInterpreter (line 35) | class SingleTreeCateInterpreter(_SingleTreeInterpreter):
    method __init__ (line 136) | def __init__(self, *,
    method interpret (line 163) | def interpret(self, cate_estimator, X):
    method _make_dot_exporter (line 212) | def _make_dot_exporter(self, *, out_file, feature_names, treatment_nam...
    method _make_mpl_exporter (line 223) | def _make_mpl_exporter(self, *, title, feature_names, treatment_names,...
  class SingleTreePolicyInterpreter (line 235) | class SingleTreePolicyInterpreter(_SingleTreeInterpreter):
    method __init__ (line 355) | def __init__(self, *,
    method interpret (line 383) | def interpret(self, cate_estimator, X, sample_treatment_costs=None):
    method treat (line 479) | def treat(self, X):
    method _make_dot_exporter (line 498) | def _make_dot_exporter(self, *, out_file, feature_names, treatment_nam...
    method _make_mpl_exporter (line 512) | def _make_mpl_exporter(self, *, title, feature_names, treatment_names,...

FILE: econml/data/dgps.py
  function ihdp_surface_A (line 11) | def ihdp_surface_A(random_state=None):
  function ihdp_surface_B (line 45) | def ihdp_surface_B(random_state=None):
  function _process_ihdp_sim_data (line 80) | def _process_ihdp_sim_data():

FILE: econml/data/dynamic_panel_dgp.py
  function new_cov_matrix (line 18) | def new_cov_matrix(cov):
  function linear_approximation (line 45) | def linear_approximation(start, end, e_val):
  function generate_coefs (line 54) | def generate_coefs(index, columns):
  function simulate_residuals (line 112) | def simulate_residuals(ind):
  function simulate_residuals_all (line 137) | def simulate_residuals_all(res_df):
  function get_prediction (line 148) | def get_prediction(df, coef_matrix, residuals, thetas, n, intervention, ...
  function generate_dgp (line 168) | def generate_dgp(
  class AbstracDynamicPanelDGP (line 211) | class AbstracDynamicPanelDGP:
    method __init__ (line 213) | def __init__(self, n_periods, n_treatments, n_x):
    method create_instance (line 219) | def create_instance(self, *args, **kwargs):
    method _gen_data_with_policy (line 222) | def _gen_data_with_policy(self, n_units, policy_gen, random_seed=123):
    method static_policy_data (line 225) | def static_policy_data(self, n_units, tau, random_seed=123):
    method adaptive_policy_data (line 230) | def adaptive_policy_data(self, n_units, policy_gen, random_seed=123):
    method static_policy_effect (line 233) | def static_policy_effect(self, tau, mc_samples=1000):
    method adaptive_policy_effect (line 241) | def adaptive_policy_effect(self, policy_gen, mc_samples=1000):
  class DynamicPanelDGP (line 250) | class DynamicPanelDGP(AbstracDynamicPanelDGP):
    method __init__ (line 252) | def __init__(self, n_periods, n_treatments, n_x):
    method create_instance (line 255) | def create_instance(self, s_x, sigma_x, sigma_y, conf_str, epsilon, Al...
    method hetero_effect_fn (line 320) | def hetero_effect_fn(self, t, x):
    method _gen_data_with_policy (line 328) | def _gen_data_with_policy(self, n_units, policy_gen, random_seed=123):
    method observational_data (line 351) | def observational_data(self, n_units, gamma, s_t, sigma_t, random_seed...
  class SemiSynthetic (line 371) | class SemiSynthetic:
    method create_instance (line 373) | def create_instance(self):
    method gen_data (line 391) | def gen_data(self, n, n_periods, thetas, random_seed):
    method plot_coefs (line 445) | def plot_coefs(self):
    method plot_cov (line 458) | def plot_cov(self):

FILE: econml/dml/_rlearner.py
  class _ModelNuisance (line 40) | class _ModelNuisance(ModelSelector):
    method __init__ (line 49) | def __init__(self, model_y: ModelSelector, model_t: ModelSelector):
    method train (line 53) | def train(self, is_selecting, folds, Y, T, X=None, W=None, Z=None, sam...
    method score (line 61) | def score(self, Y, T, X=None, W=None, Z=None, sample_weight=None, grou...
    method predict (line 70) | def predict(self, Y, T, X=None, W=None, Z=None, sample_weight=None, gr...
  class _ModelFinal (line 81) | class _ModelFinal:
    method __init__ (line 95) | def __init__(self, model_final):
    method fit (line 98) | def fit(self, Y, T, X=None, W=None, Z=None, nuisances=None,
    method predict (line 105) | def predict(self, X=None):
    method score (line 108) | def score(self, Y, T, X=None, W=None, Z=None, nuisances=None, sample_w...
    method _wrap_scoring (line 139) | def _wrap_scoring(scoring:Union[str, Callable], Y_true, Y_pred, sample...
    method wrap_scoring (line 179) | def wrap_scoring(scoring, Y_true, Y_pred, sample_weight=None, score_by...
  class _RLearner (line 196) | class _RLearner(_OrthoLearner):
    method __init__ (line 378) | def __init__(self,
    method _gen_model_y (line 405) | def _gen_model_y(self):
    method _gen_model_t (line 422) | def _gen_model_t(self):
    method _gen_rlearner_model_final (line 439) | def _gen_rlearner_model_final(self):
    method _gen_ortho_learner_model_nuisance (line 456) | def _gen_ortho_learner_model_nuisance(self):
    method _gen_ortho_learner_model_final (line 459) | def _gen_ortho_learner_model_final(self):
    method fit (line 462) | def fit(self, Y, T, *, X=None, W=None, sample_weight=None, freq_weight...
    method score (line 506) | def score(self, Y, T, X=None, W=None, sample_weight=None, scoring=None):
    method rlearner_model_final_ (line 540) | def rlearner_model_final_(self):
    method models_y (line 546) | def models_y(self):
    method models_t (line 550) | def models_t(self):
    method nuisance_scores_y (line 554) | def nuisance_scores_y(self):
    method nuisance_scores_t (line 558) | def nuisance_scores_t(self):
    method residuals_ (line 562) | def residuals_(self):
    method scoring_name (line 579) | def scoring_name(scoring: Union[str,Callable,None])->str:
    method score_nuisances (line 590) | def score_nuisances(self, Y, T, X=None, W=None, Z=None, sample_weight=...

FILE: econml/dml/causal_forest.py
  class _CausalForestFinalWrapper (line 24) | class _CausalForestFinalWrapper:
    method __init__ (line 26) | def __init__(self, model_final, featurizer, discrete_treatment, drate):
    method _combine (line 33) | def _combine(self, X, fitting=True):
    method _ate_and_stderr (line 44) | def _ate_and_stderr(self, drpreds, mask=None):
    method fit (line 52) | def fit(self, X, T, T_res, Y_res, sample_weight=None, freq_weight=None...
    method predict (line 95) | def predict(self, X):
    method ate_ (line 99) | def ate_(self):
    method ate_ (line 109) | def ate_(self, value):
    method ate_stderr_ (line 113) | def ate_stderr_(self):
    method ate_stderr_ (line 123) | def ate_stderr_(self, value):
    method att_ (line 127) | def att_(self):
    method att_ (line 137) | def att_(self, value):
    method att_stderr_ (line 141) | def att_stderr_(self):
    method att_stderr_ (line 151) | def att_stderr_(self, value):
  class _GenericSingleOutcomeModelFinalWithCovInference (line 155) | class _GenericSingleOutcomeModelFinalWithCovInference(Inference):
    method prefit (line 157) | def prefit(self, estimator, *args, **kwargs):
    method fit (line 161) | def fit(self, estimator, *args, **kwargs):
    method const_marginal_effect_interval (line 170) | def const_marginal_effect_interval(self, X, *, alpha=0.05):
    method const_marginal_effect_inference (line 173) | def const_marginal_effect_inference(self, X):
    method effect_interval (line 184) | def effect_interval(self, X, *, T0, T1, alpha=0.05):
    method effect_inference (line 187) | def effect_inference(self, X, *, T0, T1):
    method marginal_effect_interval (line 202) | def marginal_effect_interval(self, T, X, alpha=0.05):
    method marginal_effect_inference (line 205) | def marginal_effect_inference(self, T, X):
  class CausalForestDML (line 258) | class CausalForestDML(_BaseDML):
    method __init__ (line 596) | def __init__(self, *,
    method _gen_allowed_missing_vars (line 670) | def _gen_allowed_missing_vars(self):
    method _get_inference_options (line 673) | def _get_inference_options(self):
    method _gen_featurizer (line 679) | def _gen_featurizer(self):
    method _gen_model_y (line 682) | def _gen_model_y(self):
    method _gen_model_t (line 685) | def _gen_model_t(self):
    method _gen_model_final (line 688) | def _gen_model_final(self):
    method _gen_rlearner_model_final (line 710) | def _gen_rlearner_model_final(self):
    method tunable_params (line 715) | def tunable_params(self):
    method tune (line 721) | def tune(self, Y, T, *, X=None, W=None,
    method sensitivity_summary (line 822) | def sensitivity_summary(self, null_hypothesis=0, alpha=0.05, c_y=0.05,...
    method sensitivity_interval (line 851) | def sensitivity_interval(self, alpha=0.05, c_y=0.05, c_t=0.05, rho=1.,...
    method robustness_value (line 888) | def robustness_value(self, null_hypothesis=0, alpha=0.05, interval_typ...
    method fit (line 930) | def fit(self, Y, T, *, X=None, W=None, sample_weight=None, groups=None,
    method refit_final (line 969) | def refit_final(self, *, inference='auto'):
    method feature_importances (line 973) | def feature_importances(self, max_depth=4, depth_decay_exponent=2.0):
    method summary (line 977) | def summary(self, alpha=0.05, value=0, decimals=3, feature_names=None,...
    method shap_values (line 1057) | def shap_values(self, X, *, feature_names=None, treatment_names=None, ...
    method ate__inference (line 1067) | def ate__inference(self):
    method ate_ (line 1090) | def ate_(self):
    method ate_stderr_ (line 1094) | def ate_stderr_(self):
    method att__inference (line 1097) | def att__inference(self, *, T):
    method att_ (line 1125) | def att_(self, *, T):
    method att_stderr_ (line 1144) | def att_stderr_(self, *, T):
    method feature_importances_ (line 1162) | def feature_importances_(self):
    method model_final (line 1166) | def model_final(self):
    method model_final (line 1170) | def model_final(self, model):
    method __len__ (line 1174) | def __len__(self):
    method __getitem__ (line 1178) | def __getitem__(self, index):
    method __iter__ (line 1182) | def __iter__(self):

FILE: econml/dml/dml.py
  function _combine (line 33) | def _combine(X, W, n_samples):
  class _FirstStageWrapper (line 40) | class _FirstStageWrapper:
    method __init__ (line 41) | def __init__(self, model, discrete_target):
    method predict (line 45) | def predict(self, X, W):
    method score (line 58) | def score(self, X, W, Target, sample_weight=None, scoring=None, score_...
    method _wrap_scoring (line 90) | def _wrap_scoring(scoring, Y_true, X, est, sample_weight=None, score_b...
  class _FirstStageSelector (line 95) | class _FirstStageSelector(SingleModelSelector):
    method __init__ (line 96) | def __init__(self, model: SingleModelSelector, discrete_target):
    method train (line 100) | def train(self, is_selecting, folds, X, W, Target, sample_weight=None,...
    method best_model (line 115) | def best_model(self):
    method best_score (line 119) | def best_score(self):
  function _make_first_stage_selector (line 123) | def _make_first_stage_selector(model, is_discrete, random_state):
  class _FinalWrapper (line 132) | class _FinalWrapper:
    method __init__ (line 133) | def __init__(self, model_final, fit_cate_intercept, featurizer,
    method _combine (line 156) | def _combine(self, X, T, fitting=True):
    method fit (line 172) | def fit(self, X, T, T_res, Y_res, sample_weight=None, freq_weight=None...
    method predict (line 221) | def predict(self, X):
  class _BaseDML (line 233) | class _BaseDML(_RLearner):
    method original_featurizer (line 238) | def original_featurizer(self):
    method featurizer_ (line 244) | def featurizer_(self):
    method model_final_ (line 250) | def model_final_(self):
    method model_cate (line 256) | def model_cate(self):
    method models_y (line 269) | def models_y(self):
    method models_t (line 283) | def models_t(self):
    method cate_feature_names (line 296) | def cate_feature_names(self, feature_names=None):
  class DML (line 324) | class DML(LinearModelFinalCateEstimatorMixin, _BaseDML):
    method __init__ (line 518) | def __init__(self, *,
    method _gen_allowed_missing_vars (line 557) | def _gen_allowed_missing_vars(self):
    method _gen_featurizer (line 560) | def _gen_featurizer(self):
    method _gen_model_y (line 563) | def _gen_model_y(self):
    method _gen_model_t (line 566) | def _gen_model_t(self):
    method _gen_model_final (line 569) | def _gen_model_final(self):
    method _gen_rlearner_model_final (line 572) | def _gen_rlearner_model_final(self):
    method fit (line 577) | def fit(self, Y, T, *, X=None, W=None, sample_weight=None, freq_weight...
    method refit_final (line 621) | def refit_final(self, *, inference='auto'):
    method bias_part_of_coef (line 626) | def bias_part_of_coef(self):
    method fit_cate_intercept_ (line 630) | def fit_cate_intercept_(self):
    method sensitivity_summary (line 633) | def sensitivity_summary(self, null_hypothesis=0, alpha=0.05, c_y=0.05,...
    method sensitivity_interval (line 663) | def sensitivity_interval(self, alpha=0.05, c_y=0.05, c_t=0.05, rho=1.,...
    method robustness_value (line 700) | def robustness_value(self, null_hypothesis=0, alpha=0.05, interval_typ...
  class LinearDML (line 742) | class LinearDML(StatsModelsCateEstimatorMixin, DML):
    method __init__ (line 872) | def __init__(self, *,
    method _gen_allowed_missing_vars (line 910) | def _gen_allowed_missing_vars(self):
    method _gen_model_final (line 913) | def _gen_model_final(self):
    method fit (line 917) | def fit(self, Y, T, *, X=None, W=None, sample_weight=None, freq_weight...
    method model_final (line 962) | def model_final(self):
    method model_final (line 966) | def model_final(self, model):
  class SparseLinearDML (line 971) | class SparseLinearDML(DebiasedLassoCateEstimatorMixin, DML):
    method __init__ (line 1133) | def __init__(self, *,
    method _gen_allowed_missing_vars (line 1182) | def _gen_allowed_missing_vars(self):
    method _gen_model_final (line 1185) | def _gen_model_final(self):
    method fit (line 1196) | def fit(self, Y, T, *, X=None, W=None, sample_weight=None, groups=None,
    method model_final (line 1238) | def model_final(self):
    method model_final (line 1242) | def model_final(self, model):
  class _RandomFeatures (line 1247) | class _RandomFeatures(TransformerMixin):
    method __init__ (line 1248) | def __init__(self, *, dim, bw, random_state):
    method fit (line 1253) | def fit(self, X):
    method transform (line 1260) | def transform(self, X):
  class KernelDML (line 1264) | class KernelDML(DML):
    method __init__ (line 1379) | def __init__(self, model_y='auto', model_t='auto',
    method _gen_allowed_missing_vars (line 1413) | def _gen_allowed_missing_vars(self):
    method _gen_model_final (line 1416) | def _gen_model_final(self):
    method _gen_featurizer (line 1419) | def _gen_featurizer(self):
    method fit (line 1422) | def fit(self, Y, T, X=None, W=None, *, sample_weight=None, groups=None,
    method featurizer (line 1459) | def featurizer(self):
    method featurizer (line 1463) | def featurizer(self, value):
    method model_final (line 1468) | def model_final(self):
    method model_final (line 1472) | def model_final(self, model):
  class NonParamDML (line 1477) | class NonParamDML(_BaseDML):
    method __init__ (line 1603) | def __init__(self, *,
    method _gen_allowed_missing_vars (line 1636) | def _gen_allowed_missing_vars(self):
    method _get_inference_options (line 1639) | def _get_inference_options(self):
    method _gen_featurizer (line 1645) | def _gen_featurizer(self):
    method _gen_model_y (line 1648) | def _gen_model_y(self):
    method _gen_model_t (line 1652) | def _gen_model_t(self):
    method _gen_model_final (line 1656) | def _gen_model_final(self):
    method _gen_rlearner_model_final (line 1659) | def _gen_rlearner_model_final(self):
    method fit (line 1664) | def fit(self, Y, T, *, X=None, W=None, sample_weight=None, freq_weight...
    method refit_final (line 1708) | def refit_final(self, *, inference='auto'):
    method shap_values (line 1712) | def shap_values(self, X, *, feature_names=None, treatment_names=None, ...

FILE: econml/dowhy.py
  class DoWhyWrapper (line 27) | class DoWhyWrapper:
    method __init__ (line 37) | def __init__(self, cate_estimator):
    method _get_params (line 43) | def _get_params(self):
    method fit (line 62) | def fit(self, Y, T, X=None, W=None, Z=None, *, outcome_names=None, tre...
    method refute_estimate (line 191) | def refute_estimate(self, *, method_name, **kwargs):
    method refit_final (line 226) | def refit_final(self, inference=None):
    method __getattr__ (line 230) | def __getattr__(self, attr):
    method __setattr__ (line 255) | def __setattr__(self, attr, value):

FILE: econml/dr/_drlearner.py
  function _calculate_crump_threshold (line 59) | def _calculate_crump_threshold(propensities):
  class _ModelNuisance (line 109) | class _ModelNuisance(ModelSelector):
    method __init__ (line 110) | def __init__(self,
    method _combine (line 120) | def _combine(self, X, W):
    method train (line 123) | def train(self, is_selecting, folds, Y, T, X=None, W=None, *, sample_w...
    method score (line 139) | def score(self, Y, T, X=None, W=None, *, sample_weight=None, groups=No...
    method predict (line 148) | def predict(self, Y, T, X=None, W=None, *, sample_weight=None, groups=...
  function _make_first_stage_selector (line 192) | def _make_first_stage_selector(model, is_discrete, random_state):
  class _ModelFinal (line 198) | class _ModelFinal:
    method __init__ (line 204) | def __init__(self, model_final, featurizer, multitask_model_final, tri...
    method _compute_trim_mask (line 211) | def _compute_trim_mask(self, T_pred):
    method fit (line 246) | def fit(self, Y, T, X=None, W=None, *, nuisances,
    method predict (line 300) | def predict(self, X=None):
    method score (line 312) | def score(self, Y, T, X=None, W=None, *, nuisances, sample_weight=None...
  class DRLearner (line 344) | class DRLearner(_OrthoLearner):
    method __init__ (line 587) | def __init__(self, *,
    method _gen_allowed_missing_vars (line 626) | def _gen_allowed_missing_vars(self):
    method const_marginal_effect (line 630) | def const_marginal_effect(self, X=None):
    method const_marginal_ate (line 653) | def const_marginal_ate(self, X=None):
    method _get_inference_options (line 672) | def _get_inference_options(self):
    method _gen_ortho_learner_model_nuisance (line 680) | def _gen_ortho_learner_model_nuisance(self):
    method _gen_featurizer (line 686) | def _gen_featurizer(self):
    method _gen_model_final (line 689) | def _gen_model_final(self):
    method _gen_ortho_learner_model_final (line 692) | def _gen_ortho_learner_model_final(self):
    method fit (line 696) | def fit(self, Y, T, *, X=None, W=None, sample_weight=None, freq_weight...
    method refit_final (line 751) | def refit_final(self, *, inference='auto'):
    method score (line 755) | def score(self, Y, T, X=None, W=None, sample_weight=None):
    method multitask_model_cate (line 788) | def multitask_model_cate(self):
    method model_cate (line 803) | def model_cate(self, T=1):
    method models_propensity (line 826) | def models_propensity(self):
    method models_regression (line 840) | def models_regression(self):
    method nuisance_scores_propensity (line 854) | def nuisance_scores_propensity(self):
    method nuisance_scores_regression (line 859) | def nuisance_scores_regression(self):
    method n_samples_trimmed_ (line 864) | def n_samples_trimmed_(self):
    method n_samples_used_ (line 880) | def n_samples_used_(self):
    method featurizer_ (line 896) | def featurizer_(self):
    method cate_feature_names (line 908) | def cate_feature_names(self, feature_names=None):
    method model_final_ (line 936) | def model_final_(self):
    method fitted_models_final (line 940) | def fitted_models_final(self):
    method shap_values (line 943) | def shap_values(self, X, *, feature_names=None, treatment_names=None, ...
    method sensitivity_summary (line 964) | def sensitivity_summary(self, T, null_hypothesis=0, alpha=0.05, c_y=0....
    method sensitivity_interval (line 997) | def sensitivity_interval(self, T, alpha=0.05, c_y=0.05, c_t=0.05, rho=...
    method robustness_value (line 1040) | def robustness_value(self, T, null_hypothesis=0, alpha=0.05, interval_...
  class LinearDRLearner (line 1086) | class LinearDRLearner(StatsModelsCateEstimatorDiscreteMixin, DRLearner):
    method __init__ (line 1276) | def __init__(self, *,
    method _gen_allowed_missing_vars (line 1314) | def _gen_allowed_missing_vars(self):
    method _gen_model_final (line 1317) | def _gen_model_final(self):
    method _gen_ortho_learner_model_final (line 1321) | def _gen_ortho_learner_model_final(self):
    method fit (line 1324) | def fit(self, Y, T, *, X=None, W=None, sample_weight=None, freq_weight...
    method fit_cate_intercept_ (line 1369) | def fit_cate_intercept_(self):
    method multitask_model_cate (line 1373) | def multitask_model_cate(self):
    method multitask_model_final (line 1379) | def multitask_model_final(self):
    method multitask_model_final (line 1383) | def multitask_model_final(self, value):
    method model_final (line 1388) | def model_final(self):
    method model_final (line 1392) | def model_final(self, model):
  class SparseLinearDRLearner (line 1397) | class SparseLinearDRLearner(DebiasedLassoCateEstimatorDiscreteMixin, DRL...
    method __init__ (line 1611) | def __init__(self, *,
    method _gen_allowed_missing_vars (line 1660) | def _gen_allowed_missing_vars(self):
    method _gen_model_final (line 1663) | def _gen_model_final(self):
    method _gen_ortho_learner_model_final (line 1674) | def _gen_ortho_learner_model_final(self):
    method fit (line 1677) | def fit(self, Y, T, *, X=None, W=None, sample_weight=None, groups=None,
    method fit_cate_intercept_ (line 1720) | def fit_cate_intercept_(self):
    method multitask_model_final (line 1724) | def multitask_model_final(self):
    method multitask_model_final (line 1728) | def multitask_model_final(self, value):
    method model_final (line 1733) | def model_final(self):
    method model_final (line 1737) | def model_final(self, model):
  class ForestDRLearner (line 1742) | class ForestDRLearner(ForestModelFinalCateEstimatorDiscreteMixin, DRLear...
    method __init__ (line 1952) | def __init__(self, *,
    method _gen_allowed_missing_vars (line 2010) | def _gen_allowed_missing_vars(self):
    method _gen_model_final (line 2013) | def _gen_model_final(self):
    method _gen_ortho_learner_model_final (line 2031) | def _gen_ortho_learner_model_final(self):
    method fit (line 2034) | def fit(self, Y, T, *, X=None, W=None, sample_weight=None, groups=None,
    method multitask_model_cate (line 2073) | def multitask_model_cate(self):
    method multitask_model_final (line 2078) | def multitask_model_final(self):
    method multitask_model_final (line 2082) | def multitask_model_final(self, value):
    method model_final (line 2087) | def model_final(self):
    method model_final (line 2091) | def model_final(self, model):

FILE: econml/federated_learning.py
  class FederatedEstimator (line 19) | class FederatedEstimator(TreatmentExpansionMixin, LinearCateEstimator):
    method __init__ (line 30) | def __init__(self, estimators: List[LinearDML]):
    method _gen_allowed_missing_vars (line 75) | def _gen_allowed_missing_vars(self):
    method const_marginal_effect (line 81) | def const_marginal_effect(self, X=None):
    method fit (line 85) | def fit(self, *args, **kwargs):
    method bias_part_of_coef (line 90) | def bias_part_of_coef(self):

FILE: econml/grf/_base_grf.py
  class BaseGRF (line 40) | class BaseGRF(BaseEnsemble, metaclass=ABCMeta):
    method __init__ (line 56) | def __init__(self,
    method _get_alpha_and_pointJ (line 108) | def _get_alpha_and_pointJ(self, X, T, y, **kwargs):
    method _get_n_outputs_decomposition (line 127) | def _get_n_outputs_decomposition(self, X, T, y, **kwargs):
    method apply (line 145) | def apply(self, X):
    method decision_path (line 168) | def decision_path(self, X):
    method fit (line 199) | def fit(self, X, T, y, *, sample_weight=None, **kwargs):
    method get_subsample_inds (line 409) | def get_subsample_inds(self,):
    method feature_importances (line 424) | def feature_importances(self, max_depth=4, depth_decay_exponent=2.0):
    method feature_importances_ (line 465) | def feature_importances_(self):
    method _validate_X_predict (line 468) | def _validate_X_predict(self, X):
    method predict_tree_average_full (line 474) | def predict_tree_average_full(self, X):
    method predict_tree_average (line 513) | def predict_tree_average(self, X):
    method predict_moment_and_var (line 537) | def predict_moment_and_var(self, X, parameter, slice=None, parallel=Tr...
    method predict_alpha_and_jac (line 607) | def predict_alpha_and_jac(self, X, slice=None, parallel=True):
    method _predict_point_and_var (line 665) | def _predict_point_and_var(self, X, full=False, point=True, var=False,...
    method predict_full (line 791) | def predict_full(self, X, interval=False, alpha=0.05):
    method predict (line 827) | def predict(self, X, interval=False, alpha=0.05):
    method predict_interval (line 862) | def predict_interval(self, X, alpha=0.05):
    method predict_and_var (line 884) | def predict_and_var(self, X):
    method predict_var (line 903) | def predict_var(self, X):
    method prediction_stderr (line 920) | def prediction_stderr(self, X):
    method _check_projector (line 937) | def _check_projector(self, X, projector):
    method predict_projection_and_var (line 947) | def predict_projection_and_var(self, X, projector):
    method predict_projection (line 976) | def predict_projection(self, X, projector):
    method predict_projection_var (line 1001) | def predict_projection_var(self, X, projector):
    method oob_predict (line 1026) | def oob_predict(self, Xtrain):

FILE: econml/grf/_base_grftree.py
  class GRFTree (line 31) | class GRFTree(BaseTree):
    method __init__ (line 288) | def __init__(self, *,
    method _get_valid_criteria (line 316) | def _get_valid_criteria(self):
    method _get_valid_min_var_leaf_criteria (line 319) | def _get_valid_min_var_leaf_criteria(self):
    method _get_store_jac (line 322) | def _get_store_jac(self):
    method init (line 325) | def init(self,):
    method fit (line 340) | def fit(self, X, y, n_y, n_outputs, n_relevant_outputs, sample_weight=...
    method predict (line 372) | def predict(self, X, check_input=True):
    method predict_full (line 394) | def predict_full(self, X, check_input=True):
    method predict_alpha_and_jac (line 416) | def predict_alpha_and_jac(self, X, check_input=True):
    method predict_moment (line 440) | def predict_moment(self, X, parameter, check_input=True):
    method feature_importances (line 467) | def feature_importances(self, max_depth=4, depth_decay_exponent=2.0):
    method feature_importances_ (line 498) | def feature_importances_(self):

FILE: econml/grf/classes.py
  class MultiOutputGRF (line 21) | class MultiOutputGRF(BaseEstimator):
    method __init__ (line 28) | def __init__(self, estimator):
    method fit (line 31) | def fit(self, X, T, y, *, sample_weight=None, **kwargs):
    method predict (line 41) | def predict(self, X, interval=False, alpha=0.05):
    method predict_and_var (line 50) | def predict_and_var(self, X):
    method predict_projection_and_var (line 54) | def predict_projection_and_var(self, X, projector):
    method oob_predict (line 58) | def oob_predict(self, Xtrain):
    method feature_importances (line 62) | def feature_importances(self, max_depth=4, depth_decay_exponent=2.0):
    method feature_importances_ (line 68) | def feature_importances_(self):
    method __len__ (line 71) | def __len__(self):
    method __getitem__ (line 75) | def __getitem__(self, index):
    method __iter__ (line 79) | def __iter__(self):
  class CausalForest (line 88) | class CausalForest(BaseGRF):
    method __init__ (line 342) | def __init__(self,
    method fit (line 373) | def fit(self, X, T, y, *, sample_weight=None):
    method _get_alpha_and_pointJ (line 397) | def _get_alpha_and_pointJ(self, X, T, y):
    method _get_n_outputs_decomposition (line 404) | def _get_n_outputs_decomposition(self, X, T, y):
  class CausalIVForest (line 412) | class CausalIVForest(BaseGRF):
    method __init__ (line 675) | def __init__(self,
    method fit (line 706) | def fit(self, X, T, y, *, Z, sample_weight=None):
    method _get_alpha_and_pointJ (line 735) | def _get_alpha_and_pointJ(self, X, T, y, *, Z):
    method _get_n_outputs_decomposition (line 754) | def _get_n_outputs_decomposition(self, X, T, y, *, Z):
  class RegressionForest (line 762) | class RegressionForest(BaseGRF):
    method __init__ (line 978) | def __init__(self,
    method fit (line 1005) | def fit(self, X, y, *, sample_weight=None):
    method _get_alpha_and_pointJ (line 1027) | def _get_alpha_and_pointJ(self, X, y, T):
    method _get_n_outputs_decomposition (line 1031) | def _get_n_outputs_decomposition(self, X, y, T):

FILE: econml/inference/_bootstrap.py
  class BootstrapEstimator (line 11) | class BootstrapEstimator:
    method __init__ (line 54) | def __init__(self, wrapped,
    method __stratified_indices (line 71) | def __stratified_indices(arr):
    method fit (line 80) | def fit(self, *args, **named_args):
    method __getattr__ (line 127) | def __getattr__(self, name):

FILE: econml/inference/_inference.py
  class Inference (line 22) | class Inference(metaclass=abc.ABCMeta):
    method prefit (line 23) | def prefit(self, estimator, *args, **kwargs):
    method fit (line 28) | def fit(self, estimator, *args, **kwargs):
    method ate_interval (line 36) | def ate_interval(self, X=None, *, T0=0, T1=1, alpha=0.05):
    method ate_inference (line 39) | def ate_inference(self, X=None, *, T0=0, T1=1):
    method marginal_ate_interval (line 42) | def marginal_ate_interval(self, T, X=None, *, alpha=0.05):
    method marginal_ate_inference (line 45) | def marginal_ate_inference(self, T, X=None):
    method const_marginal_ate_interval (line 48) | def const_marginal_ate_interval(self, X=None, *, alpha=0.05):
    method const_marginal_ate_inference (line 51) | def const_marginal_ate_inference(self, X=None):
  class BootstrapInference (line 55) | class BootstrapInference(Inference):
    method __init__ (line 80) | def __init__(self, n_bootstrap_samples=100, n_jobs=-1, bootstrap_type=...
    method fit (line 86) | def fit(self, estimator, *args, **kwargs):
    method __getattr__ (line 97) | def __getattr__(self, name):
  class GenericModelFinalInference (line 110) | class GenericModelFinalInference(Inference):
    method prefit (line 120) | def prefit(self, estimator, *args, **kwargs):
    method fit (line 124) | def fit(self, estimator, *args, **kwargs):
    method const_marginal_effect_interval (line 133) | def const_marginal_effect_interval(self, X, *, alpha=0.05):
    method const_marginal_effect_inference (line 136) | def const_marginal_effect_inference(self, X):
    method _predict (line 156) | def _predict(self, X):
    method _prediction_stderr (line 159) | def _prediction_stderr(self, X):
  class GenericSingleTreatmentModelFinalInference (line 167) | class GenericSingleTreatmentModelFinalInference(GenericModelFinalInferen...
    method fit (line 176) | def fit(self, estimator, *args, **kwargs):
    method effect_interval (line 182) | def effect_interval(self, X, *, T0, T1, alpha=0.05):
    method effect_inference (line 185) | def effect_inference(self, X, *, T0, T1):
    method marginal_effect_inference (line 206) | def marginal_effect_inference(self, T, X):
    method marginal_effect_interval (line 238) | def marginal_effect_interval(self, T, X, *, alpha=0.05):
  class LinearModelFinalInference (line 242) | class LinearModelFinalInference(GenericModelFinalInference):
    method fit (line 252) | def fit(self, estimator, *args, **kwargs):
    method _predict (line 261) | def _predict(self, X):
    method effect_interval (line 273) | def effect_interval(self, X, *, T0, T1, alpha=0.05):
    method effect_inference (line 276) | def effect_inference(self, X, *, T0, T1):
    method const_marginal_effect_inference (line 299) | def const_marginal_effect_inference(self, X):
    method marginal_effect_inference (line 316) | def marginal_effect_inference(self, T, X):
    method marginal_effect_interval (line 374) | def marginal_effect_interval(self, T, X, *, alpha=0.05):
    method coef__interval (line 377) | def coef__interval(self, *, alpha=0.05):
    method coef__inference (line 388) | def coef__inference(self):
    method intercept__interval (line 419) | def intercept__interval(self, *, alpha=0.05):
    method intercept__inference (line 432) | def intercept__inference(self):
  class StatsModelsInference (line 459) | class StatsModelsInference(LinearModelFinalInference):
    method __init__ (line 471) | def __init__(self, cov_type='HC1'):
    method prefit (line 479) | def prefit(self, estimator, *args, **kwargs):
  class GenericModelFinalInferenceDiscrete (line 486) | class GenericModelFinalInferenceDiscrete(Inference):
    method prefit (line 493) | def prefit(self, estimator, *args, **kwargs):
    method fit (line 497) | def fit(self, estimator, *args, **kwargs):
    method const_marginal_effect_interval (line 509) | def const_marginal_effect_interval(self, X, *, alpha=0.05):
    method const_marginal_effect_inference (line 512) | def const_marginal_effect_inference(self, X):
    method effect_interval (line 533) | def effect_interval(self, X, *, T0, T1, alpha=0.05):
    method effect_inference (line 536) | def effect_inference(self, X, *, T0, T1):
  class LinearModelFinalInferenceDiscrete (line 561) | class LinearModelFinalInferenceDiscrete(GenericModelFinalInferenceDiscre...
    method const_marginal_effect_inference (line 569) | def const_marginal_effect_inference(self, X):
    method effect_inference (line 584) | def effect_inference(self, X, *, T0, T1):
    method coef__interval (line 596) | def coef__interval(self, T, *, alpha=0.05):
    method coef__inference (line 602) | def coef__inference(self, T):
    method intercept__interval (line 627) | def intercept__interval(self, T, *, alpha=0.05):
    method intercept__inference (line 635) | def intercept__inference(self, T):
  class StatsModelsInferenceDiscrete (line 655) | class StatsModelsInferenceDiscrete(LinearModelFinalInferenceDiscrete):
    method __init__ (line 666) | def __init__(self, cov_type='HC1'):
    method prefit (line 674) | def prefit(self, estimator, *args, **kwargs):
  class InferenceResults (line 680) | class InferenceResults(metaclass=abc.ABCMeta):
    method __init__ (line 702) | def __init__(self, d_t, d_y, pred, inf_type, fname_transformer=None,
    method point_estimate (line 716) | def point_estimate(self):
    method stderr (line 732) | def stderr(self):
    method var (line 747) | def var(self):
    method conf_int (line 764) | def conf_int(self, alpha=0.05):
    method pvalue (line 785) | def pvalue(self, value=0):
    method zstat (line 804) | def zstat(self, value=0):
    method summary_frame (line 825) | def summary_frame(self, alpha=0.05, value=0, decimals=3,
    method population_summary (line 908) | def population_summary(self, alpha=0.05, value=0, decimals=3, tol=0.00...
    method _reshape_array (line 945) | def _reshape_array(self, arr):
    method _expand_outputs (line 954) | def _expand_outputs(self, n_rows):
    method translate (line 973) | def translate(self, offset):
    method scale (line 987) | def scale(self, factor):
  class NormalInferenceResults (line 1001) | class NormalInferenceResults(InferenceResults):
    method __init__ (line 1032) | def __init__(self, d_t, d_y, pred, pred_stderr, mean_pred_stderr, inf_...
    method stderr (line 1040) | def stderr(self):
    method conf_int (line 1054) | def conf_int(self, alpha=0.05):
    method pvalue (line 1078) | def pvalue(self, value=0):
    method population_summary (line 1097) | def population_summary(self, alpha=0.05, value=0, decimals=3, tol=0.00...
    method _expand_outputs (line 1104) | def _expand_outputs(self, n_rows):
    method scale (line 1114) | def scale(self, factor):
  class EmpiricalInferenceResults (line 1127) | class EmpiricalInferenceResults(InferenceResults):
    method __init__ (line 1150) | def __init__(self, d_t, d_y, pred, pred_dist, inf_type, fname_transfor...
    method stderr (line 1156) | def stderr(self):
    method conf_int (line 1170) | def conf_int(self, alpha=0.05):
    method pvalue (line 1192) | def pvalue(self, value=0):
    method _expand_outputs (line 1214) | def _expand_outputs(self, n_rows):
    method translate (line 1221) | def translate(self, other):
    method scale (line 1230) | def scale(self, factor):
  class PopulationSummaryResults (line 1240) | class PopulationSummaryResults:
    method __init__ (line 1280) | def __init__(self, pred, pred_stderr, mean_pred_stderr, d_t, d_y, alph...
    method __str__ (line 1296) | def __str__(self):
    method _repr_html_ (line 1299) | def _repr_html_(self):
    method mean_point (line 1304) | def mean_point(self):
    method stderr_mean (line 1319) | def stderr_mean(self):
    method zstat (line 1339) | def zstat(self, *, value=None):
    method pvalue (line 1360) | def pvalue(self, *, value=None):
    method conf_int_mean (line 1381) | def conf_int_mean(self, *, alpha=None):
    method std_point (line 1406) | def std_point(self):
    method percentile_point (line 1420) | def percentile_point(self, *, alpha=None):
    method conf_int_point (line 1443) | def conf_int_point(self, *, alpha=None, tol=None):
    method stderr_point (line 1472) | def stderr_point(self):
    method summary (line 1486) | def summary(self, alpha=None, value=None, decimals=None, tol=None, out...
    method _print (line 1515) | def _print(self, *, alpha=None, value=None, decimals=None, tol=None, o...
    method _mixture_ppf (line 1577) | def _mixture_ppf(self, alpha, mean, stderr, tol):
    method _format_res (line 1604) | def _format_res(self, res, decimals):
    method _get_stub_names (line 1609) | def _get_stub_names(self, d_y, d_t, treatment_names, output_names):

FILE: econml/iv/dml/_dml.py
  function _combine (line 34) | def _combine(W, Z, n_samples):
  class _OrthoIVNuisanceSelector (line 41) | class _OrthoIVNuisanceSelector(ModelSelector):
    method __init__ (line 43) | def __init__(self,
    method train (line 56) | def train(self, is_selecting, folds, Y, T, X=None, W=None, Z=None, sam...
    method score (line 68) | def score(self, Y, T, X=None, W=None, Z=None, sample_weight=None, grou...
    method predict (line 93) | def predict(self, Y, T, X=None, W=None, Z=None, sample_weight=None, gr...
  class _OrthoIVModelFinal (line 120) | class _OrthoIVModelFinal:
    method __init__ (line 121) | def __init__(self, model_final, featurizer, fit_cate_intercept):
    method _combine (line 137) | def _combine(self, X, T, fitting=True):
    method fit (line 149) | def fit(self, Y, T, X=None, W=None, Z=None, nuisances=None,
    method predict (line 166) | def predict(self, X=None):
    method score (line 174) | def score(self, Y, T, X=None, W=None, Z=None, nuisances=None, sample_w...
  class OrthoIV (line 189) | class OrthoIV(LinearModelFinalCateEstimatorMixin, _OrthoLearner):
    method __init__ (line 362) | def __init__(self, *,
    method _gen_allowed_missing_vars (line 399) | def _gen_allowed_missing_vars(self):
    method _gen_featurizer (line 402) | def _gen_featurizer(self):
    method _gen_model_final (line 405) | def _gen_model_final(self):
    method _gen_ortho_learner_model_final (line 408) | def _gen_ortho_learner_model_final(self):
    method _gen_ortho_learner_model_nuisance (line 411) | def _gen_ortho_learner_model_nuisance(self):
    method fit (line 436) | def fit(self, Y, T, *, Z, X=None, W=None, sample_weight=None, freq_wei...
    method refit_final (line 488) | def refit_final(self, *, inference='auto'):
    method score (line 492) | def score(self, Y, T, Z, X=None, W=None, sample_weight=None):
    method featurizer_ (line 528) | def featurizer_(self):
    method original_featurizer (line 541) | def original_featurizer(self):
    method cate_feature_names (line 546) | def cate_feature_names(self, feature_names=None):
    method model_final_ (line 574) | def model_final_(self):
    method model_cate (line 579) | def model_cate(self):
    method models_y_xw (line 592) | def models_y_xw(self):
    method models_t_xw (line 606) | def models_t_xw(self):
    method models_z_xw (line 620) | def models_z_xw(self):
    method models_t_xwz (line 636) | def models_t_xwz(self):
    method nuisance_scores_y_xw (line 652) | def nuisance_scores_y_xw(self):
    method nuisance_scores_t_xw (line 657) | def nuisance_scores_t_xw(self):
    method nuisance_scores_z_xw (line 662) | def nuisance_scores_z_xw(self):
    method nuisance_scores_t_xwz (line 669) | def nuisance_scores_t_xwz(self):
    method fit_cate_intercept_ (line 676) | def fit_cate_intercept_(self):
    method bias_part_of_coef (line 680) | def bias_part_of_coef(self):
    method model_final (line 684) | def model_final(self):
    method model_final (line 688) | def model_final(self, model):
    method residuals_ (line 693) | def residuals_(self):
  class _BaseDMLIVNuisanceSelector (line 710) | class _BaseDMLIVNuisanceSelector(ModelSelector):
    method __init__ (line 718) | def __init__(self, model_y_xw: ModelSelector, model_t_xw: ModelSelecto...
    method train (line 723) | def train(self, is_selecting, folds, Y, T, X=None, W=None, Z=None, sam...
    method score (line 734) | def score(self, Y, T, X=None, W=None, Z=None, sample_weight=None, grou...
    method predict (line 752) | def predict(self, Y, T, X=None, W=None, Z=None, sample_weight=None, gr...
  class _BaseDMLIVModelFinal (line 767) | class _BaseDMLIVModelFinal(_ModelFinal):
  class _BaseDMLIV (line 784) | class _BaseDMLIV(_OrthoLearner):
    method fit (line 788) | def fit(self, Y, T, *, Z, X=None, W=None, sample_weight=None, freq_wei...
    method score (line 832) | def score(self, Y, T, Z, X=None, W=None, sample_weight=None):
    method original_featurizer (line 867) | def original_featurizer(self):
    method featurizer_ (line 871) | def featurizer_(self):
    method model_final_ (line 877) | def model_final_(self):
    method model_cate (line 882) | def model_cate(self):
    method models_y_xw (line 895) | def models_y_xw(self):
    method models_t_xw (line 909) | def models_t_xw(self):
    method models_t_xwz (line 923) | def models_t_xwz(self):
    method nuisance_scores_y_xw (line 937) | def nuisance_scores_y_xw(self):
    method nuisance_scores_t_xw (line 942) | def nuisance_scores_t_xw(self):
    method nuisance_scores_t_xwz (line 947) | def nuisance_scores_t_xwz(self):
    method residuals_ (line 952) | def residuals_(self):
    method cate_feature_names (line 968) | def cate_feature_names(self, feature_names=None):
  class DMLIV (line 996) | class DMLIV(_BaseDMLIV):
    method __init__ (line 1154) | def __init__(self, *,
    method _gen_featurizer (line 1188) | def _gen_featurizer(self):
    method _gen_model_y_xw (line 1191) | def _gen_model_y_xw(self):
    method _gen_model_t_xw (line 1194) | def _gen_model_t_xw(self):
    method _gen_model_t_xwz (line 1197) | def _gen_model_t_xwz(self):
    method _gen_model_final (line 1200) | def _gen_model_final(self):
    method _gen_ortho_learner_model_nuisance (line 1203) | def _gen_ortho_learner_model_nuisance(self):
    method _gen_ortho_learner_model_final (line 1206) | def _gen_ortho_learner_model_final(self):
    method bias_part_of_coef (line 1213) | def bias_part_of_coef(self):
    method fit_cate_intercept_ (line 1217) | def fit_cate_intercept_(self):
    method shap_values (line 1220) | def shap_values(self, X, *, feature_names=None, treatment_names=None, ...
    method coef_ (line 1234) | def coef_(self):
    method intercept_ (line 1253) | def intercept_(self):
    method summary (line 1271) | def summary(self, decimals=3, feature_names=None, treatment_names=None...
  class NonParamDMLIV (line 1378) | class NonParamDMLIV(_BaseDMLIV):
    method __init__ (line 1543) | def __init__(self, *,
    method _gen_featurizer (line 1575) | def _gen_featurizer(self):
    method _gen_model_y_xw (line 1578) | def _gen_model_y_xw(self):
    method _gen_model_t_xw (line 1581) | def _gen_model_t_xw(self):
    method _gen_model_t_xwz (line 1584) | def _gen_model_t_xwz(self):
    method _gen_model_final (line 1587) | def _gen_model_final(self):
    method _gen_ortho_learner_model_nuisance (line 1590) | def _gen_ortho_learner_model_nuisance(self):
    method _gen_ortho_learner_model_final (line 1593) | def _gen_ortho_learner_model_final(self):
    method shap_values (line 1599) | def shap_values(self, X, *, feature_names=None, treatment_names=None, ...

FILE: econml/iv/dr/_dr.py
  function _combine (line 37) | def _combine(W, Z, n_samples):
  class _BaseDRIVNuisanceSelector (line 44) | class _BaseDRIVNuisanceSelector(ModelSelector):
    method __init__ (line 45) | def __init__(self, *, prel_model_effect, model_y_xw, model_t_xw, model_z,
    method train (line 59) | def train(self, is_selecting, folds, Y, T, X=None, W=None, Z=None, sam...
    method score (line 83) | def score(self, Y, T, X=None, W=None, Z=None, sample_weight=None, grou...
    method predict (line 124) | def predict(self, Y, T, X=None, W=None, Z=None, sample_weight=None, gr...
  class _BaseDRIVNuisanceCovarianceSelector (line 165) | class _BaseDRIVNuisanceCovarianceSelector(ModelSelector):
    method __init__ (line 166) | def __init__(self, *, model_tz_xw,
    method _get_target (line 175) | def _get_target(self, T_res, Z_res, T, Z):
    method train (line 216) | def train(self, is_selecting, folds,
    method score (line 226) | def score(self, prel_theta, Y_res, T_res, Z_res, Y, T, X=None, W=None,...
    method predict (line 236) | def predict(self, prel_theta, Y_res, T_res, Z_res, Y, T, X=None, W=Non...
  class _BaseDRIVModelFinal (line 271) | class _BaseDRIVModelFinal:
    method __init__ (line 272) | def __init__(self, model_final, featurizer, fit_cate_intercept, cov_cl...
    method _effect_estimate (line 290) | def _effect_estimate(self, nuisances):
    method _transform_X (line 305) | def _transform_X(self, X, n=1, fitting=True):
    method fit (line 317) | def fit(self, Y, T, X=None, W=None, Z=None, nuisances=None,
    method predict (line 333) | def predict(self, X=None):
    method score (line 337) | def score(self, Y, T, X=None, W=None, Z=None, nuisances=None, sample_w...
  class _BaseDRIV (line 351) | class _BaseDRIV(_OrthoLearner):
    method __init__ (line 354) | def __init__(self, *,
    method _gen_allowed_missing_vars (line 390) | def _gen_allowed_missing_vars(self):
    method _get_inference_options (line 394) | def _get_inference_options(self):
    method _gen_featurizer (line 399) | def _gen_featurizer(self):
    method _gen_model_final (line 402) | def _gen_model_final(self):
    method _gen_ortho_learner_model_final (line 405) | def _gen_ortho_learner_model_final(self):
    method _check_inputs (line 409) | def _check_inputs(self, Y, T, Z, X, W):
    method fit (line 427) | def fit(self, Y, T, *, Z, X=None, W=None, sample_weight=None, freq_wei...
    method refit_final (line 474) | def refit_final(self, *, inference='auto'):
    method score (line 478) | def score(self, Y, T, Z, X=None, W=None, sample_weight=None):
    method featurizer_ (line 514) | def featurizer_(self):
    method original_featurizer (line 527) | def original_featurizer(self):
    method cate_feature_names (line 532) | def cate_feature_names(self, feature_names=None):
    method model_final_ (line 560) | def model_final_(self):
    method model_cate (line 565) | def model_cate(self):
    method shap_values (line 577) | def shap_values(self, X, *, feature_names=None, treatment_names=None, ...
    method residuals_ (line 588) | def residuals_(self):
  class _DRIV (line 606) | class _DRIV(_BaseDRIV):
    method __init__ (line 609) | def __init__(self, *,
    method _gen_prel_model_effect (line 662) | def _gen_prel_model_effect(self):
    method _gen_ortho_learner_model_nuisance (line 665) | def _gen_ortho_learner_model_nuisance(self):
  class DRIV (line 705) | class DRIV(_DRIV):
    method __init__ (line 907) | def __init__(self, *,
    method _gen_model_final (line 970) | def _gen_model_final(self):
    method _gen_prel_model_effect (line 975) | def _gen_prel_model_effect(self):
    method fit (line 1019) | def fit(self, Y, T, *, Z, X=None, W=None, sample_weight=None, freq_wei...
    method models_y_xw (line 1072) | def models_y_xw(self):
    method models_t_xw (line 1086) | def models_t_xw(self):
    method models_z_xw (line 1100) | def models_z_xw(self):
    method models_t_xwz (line 1116) | def models_t_xwz(self):
    method models_tz_xw (line 1132) | def models_tz_xw(self):
    method models_prel_model_effect (line 1146) | def models_prel_model_effect(self):
    method nuisance_scores_y_xw (line 1160) | def nuisance_scores_y_xw(self):
    method nuisance_scores_t_xw (line 1165) | def nuisance_scores_t_xw(self):
    method nuisance_scores_z_xw (line 1170) | def nuisance_scores_z_xw(self):
    method nuisance_scores_t_xwz (line 1177) | def nuisance_scores_t_xwz(self):
    method nuisance_scores_prel_model_effect (line 1184) | def nuisance_scores_prel_model_effect(self):
    method nuisance_scores_tz_xw (line 1189) | def nuisance_scores_tz_xw(self):
  class LinearDRIV (line 1194) | class LinearDRIV(StatsModelsCateEstimatorMixin, DRIV):
    method __init__ (line 1408) | def __init__(self, *,
    method _gen_model_final (line 1466) | def _gen_model_final(self):
    method fit (line 1469) | def fit(self, Y, T, *, Z, X=None, W=None, sample_weight=None, freq_wei...
    method fit_cate_intercept_ (line 1516) | def fit_cate_intercept_(self):
    method bias_part_of_coef (line 1520) | def bias_part_of_coef(self):
    method model_final (line 1524) | def model_final(self):
    method model_final (line 1528) | def model_final(self, model):
  class SparseLinearDRIV (line 1533) | class SparseLinearDRIV(DebiasedLassoCateEstimatorMixin, DRIV):
    method __init__ (line 1777) | def __init__(self, *,
    method _gen_model_final (line 1849) | def _gen_model_final(self):
    method fit (line 1860) | def fit(self, Y, T, *, Z, X=None, W=None, sample_weight=None, groups=N...
    method fit_cate_intercept_ (line 1905) | def fit_cate_intercept_(self):
    method bias_part_of_coef (line 1909) | def bias_part_of_coef(self):
    method model_final (line 1913) | def model_final(self):
    method model_final (line 1917) | def model_final(self, model):
  class ForestDRIV (line 1922) | class ForestDRIV(ForestModelFinalCateEstimatorMixin, DRIV):
    method __init__ (line 2226) | def __init__(self, *,
    method _gen_model_final (line 2308) | def _gen_model_final(self):
    method fit (line 2326) | def fit(self, Y, T, *, Z, X=None, W=None, sample_weight=None, groups=N...
    method model_final (line 2369) | def model_final(self):
    method model_final (line 2373) | def model_final(self, model):
  class _IntentToTreatDRIVNuisanceSelector (line 2378) | class _IntentToTreatDRIVNuisanceSelector(ModelSelector):
    method __init__ (line 2379) | def __init__(self,
    method train (line 2389) | def train(self, is_selecting, folds, Y, T, X=None, W=None, Z=None, sam...
    method score (line 2401) | def score(self, Y, T, X=None, W=None, Z=None, sample_weight=None, grou...
    method predict (line 2422) | def predict(self, Y, T, X=None, W=None, Z=None, sample_weight=None, gr...
  class _DummyClassifier (line 2451) | class _DummyClassifier:
    method __init__ (line 2461) | def __init__(self, *, ratio):
    method fit (line 2464) | def fit(self, X, y, **kwargs):
    method predict_proba (line 2467) | def predict_proba(self, X):
  class _IntentToTreatDRIV (line 2472) | class _IntentToTreatDRIV(_BaseDRIV):
    method __init__ (line 2475) | def __init__(self, *,
    method _gen_prel_model_effect (line 2516) | def _gen_prel_model_effect(self):
    method _gen_ortho_learner_model_nuisance (line 2519) | def _gen_ortho_learner_model_nuisance(self):
  class _DummyCATE (line 2537) | class _DummyCATE:
    method __init__ (line 2540) | def __init__(self):
    method fit (line 2543) | def fit(self, y, T, *, Z, X=None, W=None, sample_weight=None, groups=N...
    method effect (line 2546) | def effect(self, X):
  class IntentToTreatDRIV (line 2552) | class IntentToTreatDRIV(_IntentToTreatDRIV):
    method __init__ (line 2707) | def __init__(self, *,
    method _gen_model_final (line 2757) | def _gen_model_final(self):
    method _gen_prel_model_effect (line 2762) | def _gen_prel_model_effect(self):
    method models_y_xw (line 2796) | def models_y_xw(self):
    method models_t_xwz (line 2810) | def models_t_xwz(self):
    method models_prel_model_effect (line 2824) | def models_prel_model_effect(self):
    method nuisance_scores_y_xw (line 2838) | def nuisance_scores_y_xw(self):
    method nuisance_scores_t_xwz (line 2843) | def nuisance_scores_t_xwz(self):
    method nuisance_scores_prel_model_effect (line 2848) | def nuisance_scores_prel_model_effect(self):
  class LinearIntentToTreatDRIV (line 2853) | class LinearIntentToTreatDRIV(StatsModelsCateEstimatorMixin, IntentToTre...
    method __init__ (line 3021) | def __init__(self, *,
    method _gen_model_final (line 3066) | def _gen_model_final(self):
    method fit (line 3070) | def fit(self, Y, T, *, Z, X=None, W=None, sample_weight=None, freq_wei...
    method fit_cate_intercept_ (line 3117) | def fit_cate_intercept_(self):
    method bias_part_of_coef (line 3121) | def bias_part_of_coef(self):
    method model_final (line 3125) | def model_final(self):
    method model_final (line 3129) | def model_final(self, value):

FILE: econml/iv/sieve/_tsls.py
  class HermiteFeatures (line 18) | class HermiteFeatures(TransformerMixin):
    method __init__ (line 30) | def __init__(self, degree, shift=0, joint=False):
    method _column_feats (line 35) | def _column_feats(self, X, shift):
    method fit (line 48) | def fit(self, X):
    method transform (line 52) | def transform(self, X):
  class DPolynomialFeatures (line 89) | class DPolynomialFeatures(TransformerMixin):
    method __init__ (line 113) | def __init__(self, degree=2, interaction_only=False, include_bias=True):
    method fit (line 116) | def fit(self, X, y=None):
    method transform (line 133) | def transform(self, X):
  function _add_ones (line 160) | def _add_ones(arr):
  function _add_zeros (line 165) | def _add_zeros(arr):
  class SieveTSLS (line 170) | class SieveTSLS(BaseCateEstimator):
    method __init__ (line 195) | def __init__(self, *,
    method fit (line 211) | def fit(self, Y, T, *, Z, X=None, W=None, inference=None):
    method effect (line 269) | def effect(self, X=None, T0=0, T1=1):
    method marginal_effect (line 314) | def marginal_effect(self, T, X=None):

FILE: econml/metalearners/_metalearners.py
  class TLearner (line 22) | class TLearner(TreatmentExpansionMixin, LinearCateEstimator):
    method __init__ (line 68) | def __init__(self, *,
    method _gen_allowed_missing_vars (line 77) | def _gen_allowed_missing_vars(self):
    method fit (line 81) | def fit(self, Y, T, *, X, inference=None):
    method const_marginal_effect (line 120) | def const_marginal_effect(self, X):
  class SLearner (line 150) | class SLearner(TreatmentExpansionMixin, LinearCateEstimator):
    method __init__ (line 195) | def __init__(self, *,
    method _gen_allowed_missing_vars (line 204) | def _gen_allowed_missing_vars(self):
    method fit (line 208) | def fit(self, Y, T, *, X=None, inference=None):
    method const_marginal_effect (line 249) | def const_marginal_effect(self, X=None):
  class XLearner (line 284) | class XLearner(TreatmentExpansionMixin, LinearCateEstimator):
    method __init__ (line 342) | def __init__(self, *,
    method _gen_allowed_missing_vars (line 355) | def _gen_allowed_missing_vars(self):
    method fit (line 359) | def fit(self, Y, T, *, X, inference=None):
    method const_marginal_effect (line 418) | def const_marginal_effect(self, X):
  class DomainAdaptationLearner (line 451) | class DomainAdaptationLearner(TreatmentExpansionMixin, LinearCateEstimat...
    method __init__ (line 510) | def __init__(self, *,
    method _gen_allowed_missing_vars (line 523) | def _gen_allowed_missing_vars(self):
    method fit (line 527) | def fit(self, Y, T, *, X, inference=None):
    method const_marginal_effect (line 590) | def const_marginal_effect(self, X):
    method _fit_weighted_pipeline (line 618) | def _fit_weighted_pipeline(self, model_instance, X, y, sample_weight):
    method shap_values (line 625) | def shap_values(self, X, *, feature_names=None, treatment_names=None, ...

FILE: econml/orf/_causal_tree.py
  class Node (line 14) | class Node:
    method __init__ (line 27) | def __init__(self, sample_inds, estimate_inds):
    method find_tree_node (line 35) | def find_tree_node(self, value):
  class CausalTree (line 52) | class CausalTree:
    method __init__ (line 94) | def __init__(self,
    method create_splits (line 109) | def create_splits(self, Y, T, X, W,
    method print_tree_rec (line 259) | def print_tree_rec(self, node):
    method print_tree (line 268) | def print_tree(self):
    method find_split (line 271) | def find_split(self, value):

FILE: econml/orf/_ortho_forest.py
  function _build_tree_in_parallel (line 46) | def _build_tree_in_parallel(tree, Y, T, X, W,
  function _fit_weighted_pipeline (line 53) | def _fit_weighted_pipeline(model_instance, X, y, sample_weight):
  function _cross_fit (line 79) | def _cross_fit(model_instance, X, y, split_indices, sample_weight=None, ...
  function _group_predict (line 100) | def _group_predict(X, n_groups, predict_func):
  function _group_cross_fit (line 127) | def _group_cross_fit(model_instance, X, y, t, split_indices, sample_weig...
  function _pointwise_effect (line 152) | def _pointwise_effect(X_single, Y, T, X, W, w_nonzero, split_inds, slice...
  class BaseOrthoForest (line 199) | class BaseOrthoForest(TreatmentExpansionMixin, LinearCateEstimator):
    method __init__ (line 202) | def __init__(self,
    method _gen_allowed_missing_vars (line 254) | def _gen_allowed_missing_vars(self):
    method fit (line 258) | def fit(self, Y, T, *, X, W=None, inference='auto'):
    method const_marginal_effect (line 310) | def const_marginal_effect(self, X):
    method _predict (line 327) | def _predict(self, X, stderr=False):
    method _pw_effect_inputs (line 340) | def _pw_effect_inputs(self, X_single, stderr=False):
    method _get_inference_options (line 366) | def _get_inference_options(self):
    method _fit_forest (line 374) | def _fit_forest(self, Y, T, X, W=None):
    method _get_weights (line 390) | def _get_weights(self, X_single, tree_slice=None):
    method _get_blb_indices (line 425) | def _get_blb_indices(self, X):
  class DMLOrthoForest (line 447) | class DMLOrthoForest(BaseOrthoForest):
    method __init__ (line 545) | def __init__(self, *,
    method _combine (line 632) | def _combine(self, X, W):
    method fit (line 641) | def fit(self, Y, T, *, X, W=None, inference='auto'):
    method const_marginal_effect (line 701) | def const_marginal_effect(self, X):
  class _DMLOrthoForest_nuisance_estimator_generator (line 709) | class _DMLOrthoForest_nuisance_estimator_generator:
    method __init__ (line 712) | def __init__(self, model_T, model_Y, random_state=None, second_stage=T...
    method __call__ (line 721) | def __call__(self, Y, T, X, W, sample_weight=None, split_indices=None):
  function _DMLOrthoForest_parameter_estimator_func (line 767) | def _DMLOrthoForest_parameter_estimator_func(Y, T, X,
  class _DMLOrthoForest_second_stage_parameter_estimator_gen (line 781) | class _DMLOrthoForest_second_stage_parameter_estimator_gen:
    method __init__ (line 789) | def __init__(self, lambda_reg):
    method __call__ (line 792) | def __call__(self, Y, T, X,
  function _DMLOrthoForest_moment_and_mean_gradient_estimator_func (line 824) | def _DMLOrthoForest_moment_and_mean_gradient_estimator_func(Y, T, X, W,
  function _DMLOrthoForest_get_conforming_residuals (line 839) | def _DMLOrthoForest_get_conforming_residuals(Y, T, nuisance_estimates):
  class DROrthoForest (line 849) | class DROrthoForest(BaseOrthoForest):
    method __init__ (line 933) | def __init__(self, *,
    method fit (line 993) | def fit(self, Y, T, *, X, W=None, inference='auto'):
    method const_marginal_effect (line 1045) | def const_marginal_effect(self, X):
    method const_marginal_ate (line 1064) | def const_marginal_ate(self, X=None):
    method nuisance_estimator_generator (line 1084) | def nuisance_estimator_generator(propensity_model, model_Y, random_sta...
    method parameter_estimator_func (line 1131) | def parameter_estimator_func(Y, T, X,
    method second_stage_parameter_estimator_gen (line 1142) | def second_stage_parameter_estimator_gen(lambda_reg):
    method moment_and_mean_gradient_estimator_func (line 1183) | def moment_and_mean_gradient_estimator_func(Y, T, X, W,
    method _partial_moments (line 1199) | def _partial_moments(Y, T, nuisance_estimates):
    method _check_treatment (line 1212) | def _check_treatment(self, T):
  class BLBInference (line 1226) | class BLBInference(Inference):
    method fit (line 1238) | def fit(self, estimator, *args, **kwargs):
    method const_marginal_effect_interval (line 1255) | def const_marginal_effect_interval(self, X=None, *, alpha=0.05):
    method const_marginal_effect_inference (line 1290) | def const_marginal_effect_inference(self, X=None):
    method _effect_inference_helper (line 1321) | def _effect_inference_helper(self, X, T0, T1):
    method effect_interval (line 1332) | def effect_interval(self, X=None, *, T0=0, T1=1, alpha=0.05):
    method effect_inference (line 1363) | def effect_inference(self, X=None, *, T0=0, T1=1):
    method _marginal_effect_inference_helper (line 1395) | def _marginal_effect_inference_helper(self, T, X):
    method marginal_effect_inference (line 1452) | def marginal_effect_inference(self, T, X):
    method marginal_effect_interval (line 1466) | def marginal_effect_interval(self, T, X, *, alpha=0.05):
    method _predict_wrapper (line 1469) | def _predict_wrapper(self, X=None):

FILE: econml/panel/dml/_dml.py
  function _get_groups_period_filter (line 18) | def _get_groups_period_filter(groups, n_periods):
  class _DynamicModelNuisanceSelector (line 29) | class _DynamicModelNuisanceSelector(ModelSelector):
    method __init__ (line 38) | def __init__(self, model_y, model_t, n_periods):
    method train (line 43) | def train(self, is_selecting, folds, Y, T, X=None, W=None, sample_weig...
    method predict (line 99) | def predict(self, Y, T, X=None, W=None, sample_weight=None, groups=None):
    method score (line 137) | def score(self, Y, T, X=None, W=None, sample_weight=None, groups=None):
    method _get_shape_formatter (line 162) | def _get_shape_formatter(self, X, W):
    method _index_or_None (line 167) | def _index_or_None(self, X, filter_idx):
  class _DynamicModelFinal (line 171) | class _DynamicModelFinal:
    method __init__ (line 188) | def __init__(self, model_final, n_periods):
    method fit (line 193) | def fit(self, Y, T, X=None, W=None, Z=None, nuisances=None, sample_wei...
    method predict (line 212) | def predict(self, X=None):
    method score (line 229) | def score(self, Y, T, X=None, W=None, Z=None, nuisances=None, sample_w...
  class _LinearDynamicModelFinal (line 253) | class _LinearDynamicModelFinal(_DynamicModelFinal):
    method __init__ (line 260) | def __init__(self, model_final, n_periods):
    method fit (line 264) | def fit(self, Y, T, X=None, W=None, Z=None, nuisances=None, sample_wei...
    method _get_coef_ (line 274) | def _get_coef_(self):
    method _get_cov (line 283) | def _get_cov(self, nuisances, X, groups):
    method _fit_single_output_cov (line 291) | def _fit_single_output_cov(self, nuisances, X, y_index, groups):
  class _DynamicFinalWrapper (line 349) | class _DynamicFinalWrapper(_FinalWrapper):
    method predict_with_res (line 351) | def predict_with_res(self, X, T_res):
  class DynamicDML (line 359) | class DynamicDML(LinearModelFinalCateEstimatorMixin, _OrthoLearner):
    method __init__ (line 496) | def __init__(self, *,
    method _gen_allowed_missing_vars (line 527) | def _gen_allowed_missing_vars(self):
    method const_marginal_effect (line 531) | def const_marginal_effect(self, X=None):
    method const_marginal_ate (line 554) | def const_marginal_ate(self, X=None):
    method _gen_featurizer (line 573) | def _gen_featurizer(self):
    method _gen_model_y (line 576) | def _gen_model_y(self):
    method _gen_model_t (line 581) | def _gen_model_t(self):
    method _gen_model_final (line 586) | def _gen_model_final(self):
    method _gen_ortho_learner_model_nuisance (line 589) | def _gen_ortho_learner_model_nuisance(self):
    method _gen_ortho_learner_model_final (line 595) | def _gen_ortho_learner_model_final(self):
    method _prefit (line 603) | def _prefit(self, Y, T, *args, groups=None, only_final=False, **kwargs):
    method _postfit (line 613) | def _postfit(self, Y, T, *args, **kwargs):
    method _strata (line 618) | def _strata(self, Y, T, X=None, W=None, Z=None,
    method fit (line 624) | def fit(self, Y, T, *, X=None, W=None, sample_weight=None, sample_var=...
    method score (line 684) | def score(self, Y, T, X=None, W=None, sample_weight=None, *, groups):
    method cate_treatment_names (line 742) | def cate_treatment_names(self, treatment_names=None):
    method cate_feature_names (line 765) | def cate_feature_names(self, feature_names=None):
    method _expand_treatments (line 792) | def _expand_treatments(self, X, *Ts, transform=True):
    method bias_part_of_coef (line 813) | def bias_part_of_coef(self):
    method fit_cate_intercept_ (line 817) | def fit_cate_intercept_(self):
    method original_featurizer (line 821) | def original_featurizer(self):
    method featurizer_ (line 827) | def featurizer_(self):
    method model_final_ (line 833) | def model_final_(self):
    method model_final (line 839) | def model_final(self):
    method model_final (line 843) | def model_final(self, model):
    method models_y (line 848) | def models_y(self):
    method models_t (line 852) | def models_t(self):
    method nuisance_scores_y (line 856) | def nuisance_scores_y(self):
    method nuisance_scores_t (line 860) | def nuisance_scores_t(self):
    method residuals_ (line 864) | def residuals_(self):

FILE: econml/panel/utilities.py
  function long (line 5) | def long(x):
  function wide (line 27) | def wide(x):

FILE: econml/policy/_base.py
  class PolicyLearner (line 9) | class PolicyLearner(metaclass=abc.ABCMeta):
    method fit (line 11) | def fit(self, Y, T, *, X=None, **kwargs):
    method predict_value (line 14) | def predict_value(self, X):
    method predict (line 17) | def predict(self, X):

FILE: econml/policy/_drlearner.py
  class _PolicyModelFinal (line 14) | class _PolicyModelFinal(_ModelFinal):
    method fit (line 16) | def fit(self, Y, T, X=None, W=None, *, nuisances,
    method predict (line 34) | def predict(self, X=None):
    method score (line 42) | def score(self, Y, T, X=None, W=None, *, nuisances, sample_weight=None...
  class _DRLearnerWrapper (line 46) | class _DRLearnerWrapper(DRLearner):
    method _gen_ortho_learner_model_final (line 48) | def _gen_ortho_learner_model_final(self):
  class _BaseDRPolicyLearner (line 52) | class _BaseDRPolicyLearner(PolicyLearner):
    method _gen_drpolicy_learner (line 54) | def _gen_drpolicy_learner(self):
    method fit (line 57) | def fit(self, Y, T, *, X=None, W=None, sample_weight=None, groups=None):
    method predict_value (line 86) | def predict_value(self, X):
    method predict_proba (line 102) | def predict_proba(self, X):
    method predict (line 120) | def predict(self, X):
    method policy_feature_names (line 139) | def policy_feature_names(self, *, feature_names=None):
    method policy_treatment_names (line 156) | def policy_treatment_names(self, *, treatment_names=None):
    method feature_importances (line 179) | def feature_importances(self, max_depth=4, depth_decay_exponent=2.0):
    method feature_importances_ (line 201) | def feature_importances_(self):
    method policy_model_ (line 205) | def policy_model_(self):
  class DRPolicyTree (line 210) | class DRPolicyTree(_BaseDRPolicyLearner):
    method __init__ (line 384) | def __init__(self, *,
    method _gen_drpolicy_learner (line 420) | def _gen_drpolicy_learner(self):
    method plot (line 441) | def plot(self, *, feature_names=None, treatment_names=None, ax=None, t...
    method export_graphviz (line 489) | def export_graphviz(self, *, out_file=None,
    method render (line 546) | def render(self, out_file, *, format='pdf', view=True, feature_names=N...
  class DRPolicyForest (line 609) | class DRPolicyForest(_BaseDRPolicyLearner):
    method __init__ (line 804) | def __init__(self, *,
    method _gen_drpolicy_learner (line 848) | def _gen_drpolicy_learner(self):
    method plot (line 873) | def plot(self, tree_id, *, feature_names=None, treatment_names=None,
    method export_graphviz (line 927) | def export_graphviz(self, tree_id, *, out_file=None, feature_names=Non...
    method render (line 989) | def render(self, tree_id, out_file, *, format='pdf', view=True,

FILE: econml/policy/_forest/_forest.py
  class PolicyForest (line 34) | class PolicyForest(BaseEnsemble, metaclass=ABCMeta):
    method __init__ (line 161) | def __init__(self,
    method apply (line 201) | def apply(self, X):
    method decision_path (line 224) | def decision_path(self, X):
    method fit (line 255) | def fit(self, X, y, *, sample_weight=None, **kwargs):
    method get_subsample_inds (line 374) | def get_subsample_inds(self,):
    method feature_importances (line 381) | def feature_importances(self, max_depth=4, depth_decay_exponent=2.0):
    method feature_importances_ (line 414) | def feature_importances_(self):
    method _validate_X_predict (line 417) | def _validate_X_predict(self, X):
    method predict_value (line 423) | def predict_value(self, X):
    method predict_proba (line 457) | def predict_proba(self, X):
    method predict (line 495) | def predict(self, X):

FILE: econml/policy/_forest/_tree.py
  class PolicyTree (line 31) | class PolicyTree(_SingleTreeExporterMixin, BaseTree):
    method __init__ (line 163) | def __init__(self, *,
    method _get_valid_criteria (line 187) | def _get_valid_criteria(self):
    method _get_store_jac (line 190) | def _get_store_jac(self):
    method init (line 193) | def init(self,):
    method fit (line 196) | def fit(self, X, y, *, sample_weight=None, check_input=True):
    method predict (line 233) | def predict(self, X, check_input=True):
    method predict_proba (line 255) | def predict_proba(self, X, check_input=True):
    method predict_value (line 279) | def predict_value(self, X, check_input=True):
    method feature_importances (line 301) | def feature_importances(self, max_depth=4, depth_decay_exponent=2.0):
    method feature_importances_ (line 323) | def feature_importances_(self):
    method _make_dot_exporter (line 326) | def _make_dot_exporter(self, *, out_file, feature_names, treatment_nam...
    method _make_mpl_exporter (line 339) | def _make_mpl_exporter(self, *, title, feature_names, treatment_names,...

FILE: econml/score/ensemble_cate.py
  class EnsembleCateEstimator (line 9) | class EnsembleCateEstimator:
    method __init__ (line 28) | def __init__(self, *, cate_models, weights):
    method effect (line 32) | def effect(self, X=None, *, T0=0, T1=1):
    method marginal_effect (line 37) | def marginal_effect(self, T, X=None):
    method const_marginal_effect (line 42) | def const_marginal_effect(self, X=None):
    method cate_models (line 51) | def cate_models(self):
    method cate_models (line 55) | def cate_models(self, value):
    method weights (line 61) | def weights(self):
    method weights (line 65) | def weights(self, value):

FILE: econml/score/rscorer.py
  class RScorer (line 11) | class RScorer:
    method __init__ (line 106) | def __init__(self, *,
    method fit (line 126) | def fit(self, y, T, X=None, W=None, sample_weight=None, groups=None):
    method score (line 169) | def score(self, cate_model):
    method best_model (line 196) | def best_model(self, cate_models, return_scores=False):
    method ensemble (line 222) | def ensemble(self, cate_models, eta=1000.0, return_scores=False):

FILE: econml/sklearn_extensions/linear_model.py
  class _WeightedCVIterableWrapper (line 42) | class _WeightedCVIterableWrapper(_CVIterableWrapper):
    method __init__ (line 43) | def __init__(self, cv):
    method get_n_splits (line 46) | def get_n_splits(self, X=None, y=None, groups=None, sample_weight=None):
    method split (line 51) | def split(self, X=None, y=None, groups=None, sample_weight=None):
  function _weighted_check_cv (line 57) | def _weighted_check_cv(cv=5, y=None, classifier=False, random_state=None):
  class WeightedModelMixin (line 78) | class WeightedModelMixin:
    method _fit_weighted_linear_model (line 84) | def _fit_weighted_linear_model(self, X, y, sample_weight, check_input=...
  class WeightedLasso (line 137) | class WeightedLasso(WeightedModelMixin, Lasso):
    method __init__ (line 208) | def __init__(self, alpha=1.0, fit_intercept=True,
    method fit (line 219) | def fit(self, X, y, sample_weight=None, check_input=True):
  class WeightedMultiTaskLasso (line 242) | class WeightedMultiTaskLasso(WeightedModelMixin, MultiTaskLasso):
    method __init__ (line 304) | def __init__(self, alpha=1.0, fit_intercept=True,
    method fit (line 312) | def fit(self, X, y, sample_weight=None):
  class WeightedLassoCV (line 331) | class WeightedLassoCV(WeightedModelMixin, LassoCV):
    method __init__ (line 413) | def __init__(self, eps=1e-3, n_alphas=100, alphas=None, fit_intercept=...
    method fit (line 425) | def fit(self, X, y, sample_weight=None):
  class WeightedMultiTaskLassoCV (line 449) | class WeightedMultiTaskLassoCV(WeightedModelMixin, MultiTaskLassoCV):
    method __init__ (line 524) | def __init__(self, eps=1e-3, n_alphas=100, alphas=None, fit_intercept=...
    method fit (line 536) | def fit(self, X, y, sample_weight=None):
  function _get_theta_coefs_and_tau_sq (line 560) | def _get_theta_coefs_and_tau_sq(i, X, sample_weight, alpha_cov, n_alphas...
  class DebiasedLasso (line 588) | class DebiasedLasso(WeightedLasso):
    method __init__ (line 689) | def __init__(self, alpha='auto', n_alphas=100, alpha_cov='auto', n_alp...
    method fit (line 704) | def fit(self, X, y, sample_weight=None, check_input=True):
    method prediction_stderr (line 777) | def prediction_stderr(self, X):
    method predict_interval (line 800) | def predict_interval(self, X, alpha=0.05):
    method coef__interval (line 830) | def coef__interval(self, alpha=0.05):
    method intercept__interval (line 849) | def intercept__interval(self, alpha=0.05):
    method _get_coef_correction (line 871) | def _get_coef_correction(self, X, y, y_pred, sample_weight, theta_hat):
    method _get_optimal_alpha (line 884) | def _get_optimal_alpha(self, X, y, sample_weight):
    method _get_theta_hat (line 895) | def _get_theta_hat(self, X, sample_weight):
    method _get_unscaled_coef_var (line 922) | def _get_unscaled_coef_var(self, X, theta_hat, sample_weight):
  class MultiOutputDebiasedLasso (line 933) | class MultiOutputDebiasedLasso(MultiOutputRegressor):
    method __init__ (line 1025) | def __init__(self, alpha='auto', n_alphas=100, alpha_cov='auto', n_alp...
    method fit (line 1038) | def fit(self, X, y, sample_weight=None):
    method predict (line 1075) | def predict(self, X):
    method prediction_stderr (line 1094) | def prediction_stderr(self, X):
    method predict_interval (line 1116) | def predict_interval(self, X, alpha=0.05):
    method coef__interval (line 1144) | def coef__interval(self, alpha=0.05):
    method intercept__interval (line 1168) | def intercept__interval(self, alpha=0.05):
    method get_params (line 1188) | def get_params(self, deep=True):
    method set_params (line 1192) | def set_params(self, **params):
    method _set_attribute (line 1196) | def _set_attribute(self, attribute_name, condition=True, default=None):
  class _PairedEstimatorWrapper (line 1207) | class _PairedEstimatorWrapper:
    method __init__ (line 1219) | def __init__(self, *args, **kwargs):
    method fit (line 1225) | def fit(self, X, y, sample_weight=None):
    method predict (line 1242) | def predict(self, X):
    method score (line 1246) | def score(self, X, y, sample_weight=None):
    method __getattr__ (line 1249) | def __getattr__(self, key):
    method __setattr__ (line 1255) | def __setattr__(self, key, value):
    method get_params (line 1261) | def get_params(self, deep=True):
    method set_params (line 1265) | def set_params(self, **params):
  class WeightedLassoCVWrapper (line 1270) | class WeightedLassoCVWrapper(_PairedEstimatorWrapper):
  class WeightedLassoWrapper (line 1285) | class WeightedLassoWrapper(_PairedEstimatorWrapper):
  class SelectiveRegularization (line 1295) | class SelectiveRegularization:
    method __init__ (line 1353) | def __init__(self, unpenalized_inds, penalized_model, fit_intercept=Tr...
    method fit (line 1358) | def fit(self, X, y, sample_weight=None):
    method predict (line 1420) | def predict(self, X):
    method score (line 1439) | def score(self, X, y):
    method __getattr__ (line 1462) | def __getattr__(self, key):
    method __setattr__ (line 1477) | def __setattr__(self, key, value):
  class _StatsModelsWrapper (line 1484) | class _StatsModelsWrapper(BaseEstimator):
    method predict (line 1501) | def predict(self, X):
    method coef_ (line 1522) | def coef_(self):
    method intercept_ (line 1545) | def intercept_(self):
    method _param_stderr (line 1558) | def _param_stderr(self):
    method coef_stderr_ (line 1573) | def coef_stderr_(self):
    method intercept_stderr_ (line 1585) | def intercept_stderr_(self):
    method prediction_stderr (line 1596) | def prediction_stderr(self, X):
    method coef__interval (line 1620) | def coef__interval(self, alpha=0.05):
    method intercept__interval (line 1638) | def intercept__interval(self, alpha=0.05):
    method predict_interval (line 1660) | def predict_interval(self, X, alpha=0.05):
  class StatsModelsLinearRegression (line 1684) | class StatsModelsLinearRegression(_StatsModelsWrapper):
    method __init__ (line 1702) | def __init__(self, fit_intercept=True, cov_type="HC0", *, enable_feder...
    method _check_input (line 1707) | def _check_input(self, X, y, sample_weight, freq_weight, sample_var):
    method fit (line 1772) | def fit(self, X, y, sample_weight=None, freq_weight=None, sample_var=N...
    method aggregate (line 1882) | def aggregate(models: List[StatsModelsLinearRegression]):
  class StatsModelsRLM (line 1958) | class StatsModelsRLM(_StatsModelsWrapper):
    method __init__ (line 1977) | def __init__(self, t=1.345,
    method _check_input (line 1989) | def _check_input(self, X, y):
    method fit (line 1998) | def fit(self, X, y):
  class StatsModels2SLS (line 2037) | class StatsModels2SLS(_StatsModelsWrapper):
    method __init__ (line 2047) | def __init__(self, cov_type="HC0"):
    method _check_input (line 2052) | def _check_input(self, Z, T, y, sample_weight):
    method fit (line 2078) | def fit(self, Z, T, y, sample_weight=None, freq_weight=None, sample_va...

FILE: econml/sklearn_extensions/model_selection.py
  function _split_weighted_sample (line 37) | def _split_weighted_sample(self, X, y, sample_weight, is_stratified=False):
  class WeightedKFold (line 101) | class WeightedKFold:
    method __init__ (line 130) | def __init__(self, n_splits=3, n_trials=10, shuffle=False, random_stat...
    method split (line 136) | def split(self, X, y, sample_weight=None):
    method get_n_splits (line 153) | def get_n_splits(self, X, y, groups=None):
    method _get_folds_from_splits (line 174) | def _get_folds_from_splits(self, splits, sample_size):
    method _get_splits_from_weight_stratification (line 181) | def _get_splits_from_weight_stratification(self, sample_weight):
  class WeightedStratifiedKFold (line 204) | class WeightedStratifiedKFold(WeightedKFold):
    method split (line 233) | def split(self, X, y, sample_weight=None):
    method get_n_splits (line 250) | def get_n_splits(self, X, y, groups=None):
  class ModelSelector (line 272) | class ModelSelector(metaclass=abc.ABCMeta):
    method train (line 281) | def train(self, is_selecting: bool, folds: Optional[List], *args, **kw...
    method predict (line 289) | def predict(self, *args, **kwargs):
    method score (line 298) | def score(self, *args, **kwargs):
  class SingleModelSelector (line 308) | class SingleModelSelector(ModelSelector):
    method best_model (line 317) | def best_model(self):
    method best_score (line 322) | def best_score(self):
    method predict (line 325) | def predict(self, *args, **kwargs):
    method __getattr__ (line 330) | def __getattr__(self, name):
    method score (line 336) | def score(self, *args, **kwargs):
  function _fit_with_groups (line 343) | def _fit_with_groups(model, X, y, *, sub_model=None, groups, **kwargs):
  class FixedModelSelector (line 381) | class FixedModelSelector(SingleModelSelector):
    method __init__ (line 384) | def __init__(self, model, score_during_selection):
    method train (line 388) | def train(self, is_selecting, folds: Optional[List], X, y, groups=None...
    method best_model (line 410) | def best_model(self):
    method best_score (line 414) | def best_score(self):
  function _copy_to (line 421) | def _copy_to(m1, m2, attrs, insert_underscore=False):
  function _convert_linear_model (line 426) | def _convert_linear_model(model, new_cls):
  function _to_logisticRegression (line 435) | def _to_logisticRegression(model: LogisticRegressionCV):
  function _convert_linear_regression (line 457) | def _convert_linear_regression(model, new_cls, extra_attrs=["positive"]):
  function _to_elasticNet (line 463) | def _to_elasticNet(model: ElasticNetCV, args, kwargs, is_lasso=False, cl...
  function _to_ridge (line 480) | def _to_ridge(model, cls=Ridge, extra_attrs=["positive"]):
  class SklearnCVSelector (line 486) | class SklearnCVSelector(SingleModelSelector):
    method __init__ (line 489) | def __init__(self, searcher):
    method convertible_types (line 493) | def convertible_types():
    method can_wrap (line 497) | def can_wrap(model):
    method _model_mapping (line 503) | def _model_mapping():
    method _convert_model (line 522) | def _convert_model(model, args, kwargs):
    method train (line 536) | def train(self, is_selecting: bool, folds: Optional[List], *args, grou...
    method best_model (line 562) | def best_model(self):
    method best_score (line 566) | def best_score(self):
  class ListSelector (line 570) | class ListSelector(SingleModelSelector):
    method __init__ (line 582) | def __init__(self, models, unwrap=True):
    method train (line 586) | def train(self, is_selecting, folds: Optional[List], *args, **kwargs):
    method best_model (line 601) | def best_model(self):
    method best_score (line 611) | def best_score(self):
  function get_selector (line 615) | def get_selector(input, is_discrete, *, random_state=None, cv=None, wrap...
  class GridSearchCVList (line 655) | class GridSearchCVList(BaseEstimator):
    method __init__ (line 681) | def __init__(self, estimator_list, param_grid_list, scoring=None,
    method fit (line 696) | def fit(self, X, y=None, **fit_params):
    method predict (line 708) | def predict(self, X):
    method predict_proba (line 711) | def predict_proba(self, X):
  function _cross_val_predict (line 715) | def _cross_val_predict(estimator, X, y=None, *, groups=None, cv=None,

FILE: econml/solutions/causal_analysis/_causal_analysis.py
  class _CausalInsightsConstants (line 40) | class _CausalInsightsConstants:
  function _get_default_shared_insights_output (line 76) | def _get_default_shared_insights_output():
  function _get_default_specific_insights (line 96) | def _get_default_specific_insights(view):
  function _get_metadata_causal_insights_keys (line 109) | def _get_metadata_causal_insights_keys():
  function _get_column_causal_insights_keys (line 116) | def _get_column_causal_insights_keys():
  function _get_data_causal_insights_keys (line 123) | def _get_data_causal_insights_keys():
  function _first_stage_reg (line 132) | def _first_stage_reg(X, y, *, automl=True, random_state=None, verbose=0):
  function _first_stage_clf (line 155) | def _first_stage_clf(X, y, *, make_regressor=False, automl=True, min_cou...
  function _final_stage (line 187) | def _final_stage(*, random_state=None, verbose=0):
  class _ColumnTransformer (line 200) | class _ColumnTransformer(TransformerMixin):
    method __init__ (line 201) | def __init__(self, categorical, passthrough):
    method fit (line 205) | def fit(self, X):
    method transform (line 216) | def transform(self, X):
    method get_feature_names (line 227) | def get_feature_names(self, names=None):
    method get_feature_names_out (line 230) | def get_feature_names_out(self, names=None):
  class _Wrapper (line 242) | class _Wrapper:
    method __init__ (line 243) | def __init__(self, item):
  class _FrozenTransformer (line 247) | class _FrozenTransformer(TransformerMixin, BaseEstimator):
    method __init__ (line 248) | def __init__(self, wrapper):
    method fit (line 251) | def fit(self, X, y):
    method transform (line 254) | def transform(self, X):
  function _freeze (line 258) | def _freeze(transformer):
  function _sanitize (line 263) | def _sanitize(obj):
  function _tree_interpreter_to_dict (line 276) | def _tree_interpreter_to_dict(interp, features, leaf_data=lambda t, n: {}):
  class _PolicyOutput (line 291) | class _PolicyOutput:
    method __init__ (line 307) | def __init__(self, tree_dictionary, policy_value, always_treat, contro...
  function _process_feature (line 321) | def _process_feature(name, feat_ind, verbose, categorical_inds, categori...
  class CausalAnalysis (line 512) | class CausalAnalysis:
    method __init__ (line 611) | def __init__(self, feature_inds, categorical, heterogeneity_inds=None,...
    method fit (line 631) | def fit(self, X, y, warm_start=False):
    method _format_col (line 908) | def _format_col(self, ind):
    method _point_props (line 916) | def _point_props(alpha):
    method _summary_props (line 926) | def _summary_props(alpha):
    method _make_accessor (line 937) | def _make_accessor(attr):
    method _summarize (line 952) | def _summarize(self, *, summary, get_inference, props, expand_arr, dro...
    method _pandas_summary (line 988) | def _pandas_summary(self, get_inference, *, props, n,
    method _dict_summary (line 1042) | def _dict_summary(self, get_inference, *, n, props, kind, drop_sample=...
    method global_causal_effect (line 1102) | def global_causal_effect(self, *, alpha=0.05, keep_all_levels=False):
    method _global_causal_effect_dict (line 1132) | def _global_causal_effect_dict(self, *, alpha=0.05, row_wise=False):
    method _cohort_effect_inference (line 1143) | def _cohort_effect_inference(self, Xtest):
    method cohort_causal_effect (line 1157) | def cohort_causal_effect(self, Xtest, *, alpha=0.05, keep_all_levels=F...
    method _cohort_causal_effect_dict (line 1189) | def _cohort_causal_effect_dict(self, Xtest, *, alpha=0.05, row_wise=Fa...
    method _local_effect_inference (line 1200) | def _local_effect_inference(self, Xtest):
    method local_causal_effect (line 1218) | def local_causal_effect(self, Xtest, *, alpha=0.05, keep_all_levels=Fa...
    method _local_causal_effect_dict (line 1252) | def _local_causal_effect_dict(self, Xtest, *, alpha=0.05, row_wise=Fal...
    method _safe_result_index (line 1263) | def _safe_result_index(self, X, feature_index):
    method _whatif_inference (line 1298) | def _whatif_inference(self, X, Xnew, feature_index, y):
    method whatif (line 1321) | def whatif(self, X, Xnew, feature_index, y, *, alpha=0.05):
    method _whatif_dict (line 1349) | def _whatif_dict(self, X, Xnew, feature_index, y, *, alpha=0.05, row_w...
    method _tree (line 1398) | def _tree(self, is_policy, Xtest, feature_index, *, treatment_costs=0,
    method plot_policy_tree (line 1456) | def plot_policy_tree(self, Xtest, feature_index, *, treatment_costs=0,
    method _policy_tree_output (line 1493) | def _policy_tree_output(self, Xtest, feature_index, *, treatment_costs=0,
    method plot_heterogeneity_tree (line 1547) | def plot_heterogeneity_tree(self, Xtest, feature_index, *,
    method _heterogeneity_tree_output (line 1582) | def _heterogeneity_tree_output(self, Xtest, feature_index, *,
    method individualized_policy (line 1622) | def individualized_policy(self, Xtest, feature_index, *, n_rows=None, ...
    method _individualized_policy_dict (line 1751) | def _individualized_policy_dict(self, Xtest, feature_index, *, n_rows=...
    method typical_treatment_value (line 1779) | def typical_treatment_value(self, feature_index):

FILE: econml/tests/dgp.py
  class _BaseDynamicPanelDGP (line 19) | class _BaseDynamicPanelDGP:
    method __init__ (line 21) | def __init__(self, n_periods, n_treatments, n_x):
    method create_instance (line 28) | def create_instance(self, *args, **kwargs):
    method _gen_data_with_policy (line 32) | def _gen_data_with_policy(self, n_units, policy_gen, random_seed=123):
    method static_policy_data (line 35) | def static_policy_data(self, n_units, tau, random_seed=123):
    method adaptive_policy_data (line 40) | def adaptive_policy_data(self, n_units, policy_gen, random_seed=123):
    method static_policy_effect (line 43) | def static_policy_effect(self, tau, mc_samples=1000):
    method adaptive_policy_effect (line 51) | def adaptive_policy_effect(self, policy_gen, mc_samples=1000):
  class DynamicPanelDGP (line 60) | class DynamicPanelDGP(_BaseDynamicPanelDGP):
    method __init__ (line 62) | def __init__(self, n_periods, n_treatments, n_x):
    method create_instance (line 65) | def create_instance(self, s_x, sigma_x=.8, sigma_y=.1, conf_str=5, het...
    method hetero_effect_fn (line 125) | def hetero_effect_fn(self, t, x):
    method _gen_data_with_policy (line 133) | def _gen_data_with_policy(self, n_units, policy_gen, random_seed=123):
    method observational_data (line 160) | def observational_data(self, n_units, gamma=0, s_t=1, sigma_t=0.5, ran...
  function add_vlines (line 181) | def add_vlines(n_periods, n_treatments, hetero_inds):

FILE: econml/tests/test_ate_inference.py
  class TestATEInference (line 12) | class TestATEInference(unittest.TestCase):
    method setUpClass (line 15) | def setUpClass(cls):
    method test_ate_inference (line 27) | def test_ate_inference(self):

FILE: econml/tests/test_automated_ml.py
  function automl_model_reg (line 80) | def automl_model_reg():
  function automl_model_clf (line 83) | def automl_model_clf():
  function automl_model_linear_reg (line 88) | def automl_model_linear_reg():
  function automl_model_sample_weight_reg (line 93) | def automl_model_sample_weight_reg():
  class TestAutomatedML (line 103) | class TestAutomatedML(unittest.TestCase):
    method setUpClass (line 106) | def setUpClass(cls):
    method test_nonparam (line 117) | def test_nonparam(self):
    method test_param (line 126) | def test_param(self):
    method test_forest_dml (line 135) | def test_forest_dml(self):
    method test_TLearner (line 148) | def test_TLearner(self):
    method test_SLearner (line 159) | def test_SLearner(self):
    method test_DALearner (line 171) | def test_DALearner(self):
    method test_positional (line 181) | def test_positional(self):

FILE: econml/tests/test_bootstrap.py
  class TestBootstrap (line 16) | class TestBootstrap(unittest.TestCase):
    method test_with_sklearn (line 18) | def test_with_sklearn(self):
    method test_with_econml (line 77) | def test_with_econml(self):
    method test_backends (line 131) | def test_backends(self):
    method test_internal (line 191) | def test_internal(self):
    method test_internal_options (line 228) | def test_internal_options(self):
    method test_stratify (line 271) | def test_stratify(self):
    method test_stratify_orthoiv (line 287) | def test_stratify_orthoiv(self):
    method test_all_kinds (line 299) | def test_all_kinds(self):

FILE: econml/tests/test_cate_interpreter.py
  class TestCateInterpreter (line 23) | class TestCateInterpreter(unittest.TestCase):
    method test_can_use_interpreters (line 26) | def test_can_use_interpreters(self):
    method coinflip (line 46) | def coinflip(p_true=0.5):
    method test_cate_uncertainty_needs_inference (line 49) | def test_cate_uncertainty_needs_inference(self):
    method test_can_assign_treatment (line 70) | def test_can_assign_treatment(self):
    method test_random_cate_settings (line 93) | def test_random_cate_settings(self):

FILE: econml/tests/test_causal_analysis.py
  function assert_less_close (line 16) | def assert_less_close(arr1, arr2):
  class TestCausalAnalysis (line 21) | class TestCausalAnalysis(unittest.TestCase):
    method test_basic_array (line 23) | def test_basic_array(self):
    method test_basic_pandas (line 130) | def test_basic_pandas(self):
    method test_automl_first_stage (line 248) | def test_automl_first_stage(self):
    method test_one_feature (line 349) | def test_one_feature(self):
    method test_final_models (line 410) | def test_final_models(self):
    method test_forest_with_pandas (line 467) | def test_forest_with_pandas(self):
    method test_warm_start (line 544) | def test_warm_start(self):
    method test_empty_hinds (line 569) | def test_empty_hinds(self):
    method test_can_serialize (line 592) | def test_can_serialize(self):
    method test_over_cat_limit (line 609) | def test_over_cat_limit(self):
    method test_individualized_policy (line 649) | def test_individualized_policy(self):
    method test_random_state (line 680) | def test_random_state(self):
    method test_can_set_categories (line 708) | def test_can_set_categories(self):
    method test_policy_with_index (line 727) | def test_policy_with_index(self):
    method test_invalid_inds (line 737) | def test_invalid_inds(self):
    method test_scaling_transforms (line 807) | def test_scaling_transforms(self):

FILE: econml/tests/test_discrete_outcome.py
  class TestDiscreteOutcome (line 17) | class TestDiscreteOutcome(unittest.TestCase):
    method test_accuracy (line 19) | def test_accuracy(self):
    method test_accuracy_iv (line 64) | def test_accuracy_iv(self):
    method test_string_outcome (line 99) | def test_string_outcome(self):
    method test_basic_functionality (line 109) | def test_basic_functionality(self):
    method test_constraints (line 196) | def test_constraints(self):

FILE: econml/tests/test_dml.py
  function rand_sol (line 38) | def rand_sol(A, b):
  class TestDML (line 47) | class TestDML(unittest.TestCase):
    method test_cate_api_without_ray (line 49) | def test_cate_api_without_ray(self):
    method test_cate_api_with_ray (line 54) | def test_cate_api_with_ray(self):
    method _test_cate_api (line 62) | def _test_cate_api(self, treatment_featurizations, use_ray=False):
    method test_cate_api_nonparam_without_ray (line 409) | def test_cate_api_nonparam_without_ray(self):
    method test_cate_api_nonparam_with_ray (line 413) | def test_cate_api_nonparam_with_ray(self):
    method _test_cate_api_nonparam (line 420) | def _test_cate_api_nonparam(self, use_ray=False):
    method test_bad_splits_discrete (line 597) | def test_bad_splits_discrete(self):
    method test_bad_treatment_nonparam (line 612) | def test_bad_treatment_nonparam(self):
    method test_access_to_internal_models (line 631) | def test_access_to_internal_models(self):
    method test_forest_dml_perf (line 668) | def test_forest_dml_perf(self):
    method test_forest_dml_score_fns (line 747) | def test_forest_dml_score_fns(self):
    method test_aaforest_pandas (line 822) | def test_aaforest_pandas(self):
    method test_cfdml_ate_inference (line 838) | def test_cfdml_ate_inference(self):
    method test_can_use_vectors (line 926) | def test_can_use_vectors(self):
    method test_can_use_sample_weights (line 938) | def test_can_use_sample_weights(self):
    method test_discrete_treatments (line 949) | def test_discrete_treatments(self):
    method _test_can_custom_splitter (line 976) | def _test_can_custom_splitter(self, use_ray=False):
    method test_can_use_custom_splitter_with_ray (line 990) | def test_can_use_custom_splitter_with_ray(self):
    method test_can_use_custom_splitter_without_ray (line 997) | def test_can_use_custom_splitter_without_ray(self):
    method test_can_use_featurizer (line 1000) | def test_can_use_featurizer(self):
    method test_can_use_statsmodel_inference (line 1029) | def test_can_use_statsmodel_inference(self):
    method test_ignores_final_intercept (line 1075) | def test_ignores_final_intercept(self):
    method test_sparse (line 1108) | def test_sparse(self):
    method test_linear_sparse (line 1118) | def test_linear_sparse(self):
    method _generate_recoverable_errors (line 1168) | def _generate_recoverable_errors(a_X, X, a_W=None, W=None, featurizer=...
    method _test_sparse (line 1194) | def _test_sparse(n_p, d_w, n_r):
    method _test_nuisance_scores (line 1234) | def _test_nuisance_scores(self, use_ray=False):
    method test_nuisance_scores_with_ray (line 1248) | def test_nuisance_scores_with_ray(self):
    method test_nuisance_scores_without_ray (line 1255) | def test_nuisance_scores_without_ray(self):
    method test_compare_nuisance_with_ray_vs_without_ray (line 1259) | def test_compare_nuisance_with_ray_vs_without_ray(self):
    method test_categories (line 1282) | def test_categories(self):
    method test_groups (line 1327) | def test_groups(self):
    method test_treatment_names (line 1350) | def test_treatment_names(self):
    method test_causal_forest_tune_with_discrete_outcome_and_treatment (line 1385) | def test_causal_forest_tune_with_discrete_outcome_and_treatment(self):

FILE: econml/tests/test_dmliv.py
  class TestDMLIV (line 20) | class TestDMLIV(unittest.TestCase):
    method test_cate_api (line 21) | def test_cate_api(self):
    method test_accuracy (line 159) | def test_accuracy(self):
    method test_groups (line 205) | def test_groups(self):

FILE: econml/tests/test_dominicks.py
  function test_dominicks (line 17) | def test_dominicks():

FILE: econml/tests/test_dowhy.py
  class TestDowhy (line 17) | class TestDowhy(unittest.TestCase):
    method _get_data (line 19) | def _get_data(self):
    method test_dowhy (line 26) | def test_dowhy(self):
    method test_store_dataframe_name (line 83) | def test_store_dataframe_name(self):
    method test_dowhy_without_fit (line 99) | def test_dowhy_without_fit(self):

FILE: econml/tests/test_driv.py
  class TestDRIV (line 27) | class TestDRIV(unittest.TestCase):
    method _test_cate_api (line 28) | def _test_cate_api(self, use_ray=False):
    method test_cate_api_with_ray (line 226) | def test_cate_api_with_ray(self):
    method test_cate_api_without_ray (line 233) | def test_cate_api_without_ray(self):
    method _test_accuracy (line 236) | def _test_accuracy(self, use_ray=False):
    method test_accuracy_with_ray (line 299) | def test_accuracy_with_ray(self):
    method test_accuracy_without_ray (line 306) | def test_accuracy_without_ray(self):
    method test_fit_cov_directly (line 309) | def test_fit_cov_directly(self):
    method test_groups (line 346) | def test_groups(self):

FILE: econml/tests/test_drlearner.py
  class TestDRLearner (line 34) | class TestDRLearner(unittest.TestCase):
    method setUpClass (line 37) | def setUpClass(cls):
    method _test_cate_api (line 63) | def _test_cate_api(self, use_ray=False):
    method test_test_cate_api_with_ray (line 307) | def test_test_cate_api_with_ray(self):
    method test_test_cate_api_without_ray (line 314) | def test_test_cate_api_without_ray(self):
    method test_can_use_vectors (line 318) | def test_can_use_vectors(self):
    method test_can_use_sample_weights (line 330) | def test_can_use_sample_weights(self):
    method test_discrete_treatments (line 341) | def test_discrete_treatments(self):
    method test_can_custom_splitter (line 365) | def test_can_custom_splitter(self):
    method test_can_use_statsmodel_inference (line 387) | def test_can_use_statsmodel_inference(self):
    method test_drlearner_all_attributes (line 431) | def test_drlearner_all_attributes(self):
    method _test_drlearner_with_inference_all_attributes (line 554) | def _test_drlearner_with_inference_all_attributes(self, use_ray):
    method test_drlearner_with_inference_all_attributes_with_ray (line 764) | def test_drlearner_with_inference_all_attributes_with_ray(self):
    method test_drlearner_with_inference_all_attributes_without_ray (line 771) | def test_drlearner_with_inference_all_attributes_without_ray(self):
    method _check_with_interval (line 775) | def _check_with_interval(truth, point, lower, upper):
    method test_DRLearner (line 780) | def test_DRLearner(self):
    method test_sparse (line 798) | def test_sparse(self):
    method test_groups (line 842) | def test_groups(self):
    method test_score (line 867) | def test_score(self):
    method test_multitask_model_final (line 898) | def test_multitask_model_final(self):
    method _test_te (line 916) | def _test_te(self, learner_instance, tol, te_type="const"):
    method _test_with_W (line 934) | def _test_with_W(self, learner_instance, tol):
    method _test_inputs (line 950) | def _test_inputs(self, learner_instance):
    method _untreated_outcome (line 969) | def _untreated_outcome(cls, x):
    method _const_te (line 973) | def _const_te(cls, x):
    method _heterogeneous_te (line 977) | def _heterogeneous_te(cls, x):
    method _generate_data (line 981) | def _generate_data(cls, n, d, untreated_outcome, treatment_effect, pro...
  class TestSampleTrimming (line 1005) | class TestSampleTrimming(unittest.TestCase):
    method setUpClass (line 1009) | def setUpClass(cls):
    method test_trimming_disabled_by_default (line 1022) | def test_trimming_disabled_by_default(self):
    method test_trimming_with_fixed_threshold (line 1034) | def test_trimming_with_fixed_threshold(self):
    method test_trimming_with_auto_threshold (line 1048) | def test_trimming_with_auto_threshold(self):
    method test_higher_threshold_trims_more (line 1062) | def test_higher_threshold_trims_more(self):
    method test_trimming_uses_raw_propensities (line 1082) | def test_trimming_uses_raw_propensities(self):
    method test_trimming_warning_when_threshold_less_than_min_propensity (line 1107) | def test_trimming_warning_when_threshold_less_than_min_propensity(self):
    method test_no_warning_when_threshold_greater_than_min_propensity (line 1130) | def test_no_warning_when_threshold_greater_than_min_propensity(self):
    method test_trimming_with_linear_drlearner (line 1153) | def test_trimming_with_linear_drlearner(self):
    method test_trimming_with_sparse_linear_drlearner (line 1170) | def test_trimming_with_sparse_linear_drlearner(self):
    method test_trimming_with_forest_drlearner (line 1183) | def test_trimming_with_forest_drlearner(self):
    method test_score_respects_trimming (line 1197) | def test_score_respects_trimming(self):
    method test_trimming_with_sample_weights (line 1211) | def test_trimming_with_sample_weights(self):
    method test_trimming_preserves_effect_estimation (line 1227) | def test_trimming_preserves_effect_estimation(self):
    method test_multitreatment_trimming_warns (line 1250) | def test_multitreatment_trimming_warns(self):
    method test_auto_trimming_uniform_propensity_full_range (line 1276) | def test_auto_trimming_uniform_propensity_full_range(self):
    method test_auto_trimming_uniform_propensity_narrow_range (line 1316) | def test_auto_trimming_uniform_propensity_narrow_range(self):

FILE: econml/tests/test_drtester.py
  class TestDRTester (line 12) | class TestDRTester(unittest.TestCase):
    method _get_data (line 15) | def _get_data(num_treatments=1):
    method test_multi (line 58) | def test_multi(self):
    method test_binary (line 111) | def test_binary(self):
    method test_nuisance_val_fit (line 159) | def test_nuisance_val_fit(self):
    method test_exceptions (line 200) | def test_exceptions(self):

FILE: econml/tests/test_dynamic_dml.py
  class TestDynamicDML (line 19) | class TestDynamicDML(unittest.TestCase):
    method test_cate_api (line 21) | def test_cate_api(self):
    method test_perf (line 254) | def test_perf(self):

FILE: econml/tests/test_federated_learning.py
  class FunctionRegressor (line 13) | class FunctionRegressor:
    method __init__ (line 16) | def __init__(self, func):
    method fit (line 19) | def fit(self, X, y, sample_weight=None):
    method predict (line 22) | def predict(self, X):
  class FunctionClassifier (line 26) | class FunctionClassifier(FunctionRegressor):
    method __init__ (line 29) | def __init__(self, func):
    method predict_proba (line 32) | def predict_proba(self, X):
  class TestFederatedLearning (line 36) | class TestFederatedLearning(unittest.TestCase):
    method test_lineardrlearner (line 52) | def test_lineardrlearner(self):
    method test_splitting_works (line 132) | def test_splitting_works(self):

FILE: econml/tests/test_grf_cython.py
  class TestGRFCython (line 12) | class TestGRFCython(unittest.TestCase):
    method _get_base_config (line 14) | def _get_base_config(self, n_features=2, n_t=2, n_samples_train=1000):
    method _get_base_honest_config (line 40) | def _get_base_honest_config(self, n_features=2, n_t=2, n_samples_train...
    method _get_cython_objects (line 66) | def _get_cython_objects(self, *, criterion, n_features, n_y, n_outputs...
    method _get_continuous_data (line 91) | def _get_continuous_data(self, config):
    method _train_tree (line 104) | def _train_tree(self, config, X, y):
    method _get_true_quantities (line 112) | def _get_true_quantities(self, config, X, y, mask, criterion):
    method _get_node_quantities (line 129) | def _get_node_quantities(self, tree, node_id):
    method _test_tree_quantities (line 133) | def _test_tree_quantities(self, base_config_gen, criterion):
    method test_dishonest_tree (line 197) | def test_dishonest_tree(self):
    method test_honest_tree (line 201) | def test_honest_tree(self):
    method test_honest_dishonest_equivalency (line 205) | def test_honest_dishonest_equivalency(self):
    method test_min_var_leaf (line 234) | def test_min_var_leaf(self):
    method test_fast_eigv (line 256) | def test_fast_eigv(self):
    method test_linalg (line 269) | def test_linalg(self):

FILE: econml/tests/test_grf_python.py
  class TestGRFPython (line 15) | class TestGRFPython(unittest.TestCase):
    method _get_base_config (line 17) | def _get_base_config(self):
    method _get_regression_data (line 23) | def _get_regression_data(self, n, n_features, random_state):
    method test_regression_tree_internals (line 32) | def test_regression_tree_internals(self):
    method _get_causal_data (line 161) | def _get_causal_data(self, n, n_features, n_treatments, random_state):
    method _get_true_quantities (line 171) | def _get_true_quantities(self, X, T, y, mask, criterion, fit_intercept...
    method _get_node_quantities (line 207) | def _get_node_quantities(self, tree, node_id):
    method _train_causal_forest (line 211) | def _train_causal_forest(self, X, T, y, config, sample_weight=None):
    method _train_iv_forest (line 214) | def _train_iv_forest(self, X, T, y, config, sample_weight=None):
    method _test_causal_tree_internals (line 217) | def _test_causal_tree_internals(self, trainer):
    method _test_causal_honesty (line 243) | def _test_causal_honesty(self, trainer):
    method test_causal_tree (line 312) | def test_causal_tree(self,):
    method test_iv_tree (line 316) | def test_iv_tree(self,):
    method test_min_var_leaf (line 320) | def test_min_var_leaf(self,):
    method test_subsampling (line 358) | def test_subsampling(self,):
    method _get_step_regression_data (line 406) | def _get_step_regression_data(self, n, n_features, random_state):
    method test_var (line 412) | def test_var(self,):
    method test_projection (line 471) | def test_projection(self,):
    method test_feature_importances (line 503) | def test_feature_importances(self,):
    method test_non_standard_input (line 571) | def test_non_standard_input(self,):
    method test_raise_exceptions (line 590) | def test_raise_exceptions(self,):
    method test_warm_start (line 630) | def test_warm_start(self,):
    method test_multioutput (line 656) | def test_multioutput(self,):
    method test_pickling (line 693) | def test_pickling(self,):

FILE: econml/tests/test_inference.py
  class TestInference (line 20) | class TestInference(unittest.TestCase):
    method setUpClass (line 23) | def setUpClass(cls):
    method test_summary (line 35) | def test_summary(self):
    method test_summary_discrete (line 131) | def test_summary_discrete(self):
    method test_degenerate_cases (line 232) | def test_degenerate_cases(self):
    method test_can_summarize (line 278) | def test_can_summarize(self):
    method test_alpha (line 295) | def test_alpha(self):
    method test_inference_with_none_stderr (line 307) | def test_inference_with_none_stderr(self):
    method test_auto_inference (line 343) | def test_auto_inference(self):
    method test_pickle_inferenceresult (line 392) | def test_pickle_inferenceresult(self):
    method test_mean_pred_stderr (line 403) | def test_mean_pred_stderr(self):
    method test_isolate_inferenceresult_from_estimator (line 424) | def test_isolate_inferenceresult_from_estimator(self):
    method test_translate (line 433) | def test_translate(self):
    method test_scale (line 446) | def test_scale(self):
    class _NoFeatNamesEst (line 459) | class _NoFeatNamesEst:
      method __init__ (line 460) | def __init__(self, cate_est):
      method __getattr__ (line 463) | def __getattr__(self, name):

FILE: econml/tests/test_integration.py
  class TestPandasIntegration (line 22) | class TestPandasIntegration(unittest.TestCase):
    method setUpClass (line 25) | def setUpClass(cls):
    method test_dml (line 54) | def test_dml(self):
    method test_orf (line 120) | def test_orf(self):
    method test_metalearners (line 141) | def test_metalearners(self):
    method test_drlearners (line 162) | def test_drlearners(self):
    method test_orthoiv (line 191) | def test_orthoiv(self):
    method test_cat_treatments (line 206) | def test_cat_treatments(self):
    method _check_input_names (line 229) | def _check_input_names(self, summary_table,
    method _check_popsum_names (line 258) | def _check_popsum_names(self, popsum, Y_multi=False):

FILE: econml/tests/test_linear_model.py
  class TestLassoExtensions (line 16) | class TestLassoExtensions(unittest.TestCase):
    method setUpClass (line 20) | def setUpClass(cls):
    method test_can_clone (line 51) | def test_can_clone(self):
    method test_one_DGP (line 59) | def test_one_DGP(self):
    method test_mixed_DGP (line 99) | def test_mixed_DGP(self):
    method test_multiple_outputs (line 118) | def test_multiple_outputs(self):
    method test_no_weights_cv (line 131) | def test_no_weights_cv(self):
    method test_weighted_KFold (line 150) | def test_weighted_KFold(self):
    method test_balanced_weights_cv (line 165) | def test_balanced_weights_cv(self):
    method test_multiple_outputs_no_weights_cv (line 214) | def test_multiple_outputs_no_weights_cv(self):
    method test_multiple_outputs_balanced_weights_cv (line 234) | def test_multiple_outputs_balanced_weights_cv(self):
    method test_wrapper_attributes (line 276) | def test_wrapper_attributes(self):
    method test_debiased_lasso_one_DGP (line 303) | def test_debiased_lasso_one_DGP(self):
    method test_debiased_lasso_mixed_DGP (line 340) | def test_debiased_lasso_mixed_DGP(self):
    method test_multi_output_debiased_lasso (line 352) | def test_multi_output_debiased_lasso(self):
    method _check_debiased_CI (line 404) | def _check_debiased_CI(self,
    method _check_debiased_CI_2D (line 425) | def _check_debiased_CI_2D(self,
    method _check_debiased_coefs (line 447) | def _check_debiased_coefs(self, X, y, sample_weight, expected_coefs, e...
    method _compare_with_lasso (line 464) | def _compare_with_lasso(self, lasso_X, lasso_y, wlasso_X, wlasso_y, sa...
    method _compare_with_lasso_cv (line 482) | def _compare_with_lasso_cv(self, lasso_X, lasso_y, wlasso_X, wlasso_y,
    method _map_splitter (line 507) | def _map_splitter(self, weighted_splits, n_expanded, index_mapper):
  class TestSelectiveRegularization (line 520) | class TestSelectiveRegularization(unittest.TestCase):
    method test_against_ridge_ground_truth (line 524) | def test_against_ridge_ground_truth(self):
    method test_intercept (line 545) | def test_intercept(self):
    method test_vectors_and_arrays (line 567) | def test_vectors_and_arrays(self):
    method test_can_use_sample_weights (line 576) | def test_can_use_sample_weights(self):
    method test_can_slice (line 596) | def test_can_slice(self):
    method test_can_use_index_lambda (line 613) | def test_can_use_index_lambda(self):
    method test_can_pass_through_attributes (line 631) | def test_can_pass_through_attributes(self):
    method test_can_clone_selective_regularization (line 654) | def test_can_clone_selective_regularization(self):

FILE: econml/tests/test_metalearners.py
  class TestMetalearners (line 13) | class TestMetalearners(unittest.TestCase):
    method setUpClass (line 16) | def setUpClass(cls):
    method test_TLearner (line 47) | def test_TLearner(self):
    method test_SLearner (line 59) | def test_SLearner(self):
    method test_XLearner (line 77) | def test_XLearner(self):
    method test_DALearner (line 88) | def test_DALearner(self):
    method _test_te (line 100) | def _test_te(self, learner_instance, T0, T1, tol, te_type="const", mul...
    method _test_inputs (line 133) | def _test_inputs(self, learner_instance, T0, T1):
    method _const_te (line 147) | def _const_te(cls, x):
    method _heterogeneous_te (line 151) | def _heterogeneous_te(cls, x):
    method _generate_data (line 155) | def _generate_data(cls, n, d, beta, treatment_effect, multi_y):

FILE: econml/tests/test_missing_values.py
  class ModelNuisance (line 24) | class ModelNuisance:
    method __init__ (line 25) | def __init__(self, model_t, model_y):
    method train (line 29) | def train(self, is_selecting, folds, Y, T, W=None):
    method predict (line 34) | def predict(self, Y, T, W=None):
  class ModelFinal (line 38) | class ModelFinal:
    method __init__ (line 40) | def __init__(self):
    method fit (line 43) | def fit(self, Y, T, W=None, nuisances=None):
    method predict (line 48) | def predict(self):
    method score (line 52) | def score(self, Y, T, W=None, nuisances=None):
  class ParametricModelFinalForMissing (line 57) | class ParametricModelFinalForMissing:
    method __init__ (line 58) | def __init__(self, model_final):
    method fit (line 61) | def fit(self, *args, **kwargs):
    method predict (line 70) | def predict(self, *args, **kwargs):
    method prediction_stderr (line 74) | def prediction_stderr(self, *args, **kwargs):
  class NonParamModelFinal (line 78) | class NonParamModelFinal:
    method __init__ (line 79) | def __init__(self, pipeline):
    method fit (line 82) | def fit(self, *args, **kwargs):
    method predict (line 88) | def predict(self, *args, **kwargs):
    method predict_proba (line 91) | def predict_proba(self, *args, **kwargs):
  function create_data_dict (line 95) | def create_data_dict(Y, T, X, X_missing, W, W_missing, Z, X_has_missing=...
  class OrthoLearner (line 103) | class OrthoLearner(_OrthoLearner):
    method _gen_ortho_learner_model_nuisance (line 104) | def _gen_ortho_learner_model_nuisance(self):
    method _gen_ortho_learner_model_final (line 110) | def _gen_ortho_learner_model_final(self):
  class TestMissing (line 114) | class TestMissing(unittest.TestCase):
    method test_missing (line 116) | def test_missing(self):
    method test_missing2 (line 143) | def test_missing2(self):

FILE: econml/tests/test_model_selection.py
  class TestModelSelection (line 19) | class TestModelSelection(unittest.TestCase):
    method _simple_dgp (line 21) | def _simple_dgp(self, n, d_x, d_w, discrete_treatment):
    method test_poly (line 37) | def test_poly(self):
    method test_all_strings (line 76) | def test_all_strings(self):
    method test_list_selection (line 94) | def test_list_selection(self):
    method test_sklearn_model_selection (line 120) | def test_sklearn_model_selection(self):
    method test_fixed_model_scoring (line 139) | def test_fixed_model_scoring(self):

FILE: econml/tests/test_montecarlo.py
  class TestMonteCarlo (line 14) | class TestMonteCarlo(unittest.TestCase):
    method test_montecarlo (line 16) | def test_montecarlo(self):
    method test_discrete_treatment (line 32) | def test_discrete_treatment(self):
    method test_parameter_passing (line 51) | def test_parameter_passing(self):

FILE: econml/tests/test_notebooks.py
  function test_notebook (line 28) | def test_notebook(file):

FILE: econml/tests/test_orf.py
  class TestOrthoForest (line 14) | class TestOrthoForest(unittest.TestCase):
    method setUpClass (line 17) | def setUpClass(cls):
    method test_continuous_treatments (line 40) | def test_continuous_treatments(self):
    method test_binary_treatments (line 85) | def test_binary_treatments(self):
    method test_multiple_treatments (line 138) | def test_multiple_treatments(self):
    method test_effect_shape (line 164) | def test_effect_shape(self):
    method test_nuisance_model_has_weights (line 284) | def test_nuisance_model_has_weights(self):
    method _test_te (line 318) | def _test_te(self, learner_instance, expected_te, tol, treatment_type=...
    method _test_ci (line 334) | def _test_ci(self, learner_instance, expected_te, tol, treatment_type=...
    method _const_te (line 359) | def _const_te(cls, x):
    method _exp_te (line 363) | def _exp_te(cls, x):

FILE: econml/tests/test_ortho_learner.py
  class TestOrthoLearner (line 20) | class TestOrthoLearner(unittest.TestCase):
    method _test_crossfit (line 22) | def _test_crossfit(self, use_ray):
    method test_crossfit_with_ray (line 158) | def test_crossfit_with_ray(self):
    method test_crossfit_without_ray (line 165) | def test_crossfit_without_ray(self):
    method test_crossfit_comparison (line 169) | def test_crossfit_comparison(self):
    method _test_ol (line 212) | def _test_ol(self, use_ray):
    method test_ol_with_ray (line 321) | def test_ol_with_ray(self):
    method test_ol_without_ray (line 324) | def test_ol_without_ray(self):
    method test_ol_no_score_final (line 327) | def test_ol_no_score_final(self):
    method test_ol_nuisance_scores (line 375) | def test_ol_nuisance_scores(self):
    method test_ol_discrete_treatment (line 432) | def test_ol_discrete_treatment(self):

FILE: econml/tests/test_policy_forest.py
  class TestPolicyForest (line 26) | class TestPolicyForest(unittest.TestCase):
    method _get_base_config (line 28) | def _get_base_config(self):
    method _get_policy_data (line 34) | def _get_policy_data(self, n, n_features, random_state, n_outcomes=2):
    method _get_true_quantities (line 43) | def _get_true_quantities(self, X, y, mask, sample_weight=None):
    method _get_node_quantities (line 51) | def _get_node_quantities(self, tree, node_id):
    method _train_policy_forest (line 54) | def _train_policy_forest(self, X, y, config, sample_weight=None):
    method _train_dr_policy_forest (line 57) | def _train_dr_policy_forest(self, X, y, config, sample_weight=None):
    method _train_dr_policy_tree (line 75) | def _train_dr_policy_tree(self, X, y, config, sample_weight=None):
    method _test_policy_tree_internals (line 95) | def _test_policy_tree_internals(self, trainer):
    method _test_policy_honesty (line 113) | def _test_policy_honesty(self, trainer, dr=False):
    method test_policy_tree (line 159) | def test_policy_tree(self,):
    method test_drpolicy_tree (line 163) | def test_drpolicy_tree(self,):
    method test_drpolicy_forest (line 166) | def test_drpolicy_forest(self,):
    method test_subsampling (line 170) | def test_subsampling(self,):
    method test_feature_importances (line 215) | def test_feature_importances(self,):
    method test_non_standard_input (line 278) | def test_non_standard_input(self,):
    method test_raise_exceptions (line 337) | def test_raise_exceptions(self,):
    method test_warm_start (line 364) | def test_warm_start(self,):
    method test_plotting (line 393) | def test_plotting(self):
    method test_pickling (line 428) | def test_pickling(self,):

FILE: econml/tests/test_random_state.py
  class TestRandomState (line 13) | class TestRandomState(unittest.TestCase):
    method _make_data (line 16) | def _make_data(n, p):
    method _test_random_state (line 37) | def _test_random_state(est, X_test, Y, T, **kwargs):
    method test_dml_random_state (line 47) | def test_dml_random_state(self):
    method test_dr_random_state (line 66) | def test_dr_random_state(self):
    method test_orthoiv_random_state (line 81) | def test_orthoiv_random_state(self):

FILE: econml/tests/test_refit.py
  class TestRefit (line 17) | class TestRefit(unittest.TestCase):
    method _get_data (line 19) | def _get_data(self):
    method test_dml (line 26) | def test_dml(self):
    method test_nonparam_dml (line 109) | def test_nonparam_dml(self):
    method test_drlearner (line 141) | def test_drlearner(self):
    method test_orthoiv (line 172) | def test_orthoiv(self):
    method test_can_set_discrete_treatment (line 249) | def test_can_set_discrete_treatment(self):
    method test_refit_final_inference (line 264) | def test_refit_final_inference(self):
    method test_rlearner_residuals (line 280) | def test_rlearner_residuals(self):

FILE: econml/tests/test_rscorer.py
  function _fit_model (line 17) | def _fit_model(name, model, Y, T, X):
  class TestRScorer (line 21) | class TestRScorer(unittest.TestCase):
    method _get_data (line 23) | def _get_data(self, discrete_outcome=False):
    method test_comparison (line 41) | def test_comparison(self):

FILE: econml/tests/test_sensitivity_analysis.py
  class TestSensitivityAnalysis (line 15) | class TestSensitivityAnalysis(unittest.TestCase):
    method test_params (line 17) | def test_params(self):
    method test_invalid_params (line 101) | def test_invalid_params(self):

FILE: econml/tests/test_shap.py
  class TestShap (line 16) | class TestShap(unittest.TestCase):
    method test_continuous_t (line 17) | def test_continuous_t(self):
    method test_discrete_t (line 66) | def test_discrete_t(self):
    method test_identical_output (line 126) | def test_identical_output(self):

FILE: econml/tests/test_statsmodels.py
  class StatsModelsOLS (line 28) | class StatsModelsOLS:
    method __init__ (line 46) | def __init__(self, fit_intercept=True, fit_args={}):
    method fit (line 50) | def fit(self, X, y, sample_weight=None):
    method predict (line 78) | def predict(self, X):
    method predict_interval (line 96) | def predict_interval(self, X, alpha=.05):
    method coef_ (line 121) | def coef_(self):
    method coef__interval (line 127) | def coef__interval(self, alpha):
    method intercept_ (line 134) | def intercept_(self):
    method intercept__interval (line 140) | def intercept__interval(self, alpha):
  function _compare_classes (line 147) | def _compare_classes(est, lr, X_test, alpha=.05, tol=1e-12):
  function _summarize (line 163) | def _summarize(X, y, w=None):
  function _compare_dml_classes (line 244) | def _compare_dml_classes(est, lr, X_test, alpha=.05, tol=1e-10):
  function _compare_dr_classes (line 256) | def _compare_dr_classes(est, lr, X_test, alpha=.05, tol=1e-10):
  class TestStatsModels (line 269) | class TestStatsModels(unittest.TestCase):
    method test_comp_with_lr (line 271) | def test_comp_with_lr(self):
    method test_o_dtype (line 330) | def test_o_dtype(self):
    method test_inference (line 349) | def test_inference(self):
    method test_comp_with_statsmodels (line 453) | def test_comp_with_statsmodels(self):
    method test_sum_vs_original (line 580) | def test_sum_vs_original(self):
    method test_dml_sum_vs_original (line 676) | def test_dml_sum_vs_original(self):
    method test_nonparamdml_sum_vs_original (line 760) | def test_nonparamdml_sum_vs_original(self):
    method test_dr_sum_vs_original (line 843) | def test_dr_sum_vs_original(self):
    method test_lineardriv_sum_vs_original (line 927) | def test_lineardriv_sum_vs_original(self):
    method test_dmliv_sum_vs_original (line 1023) | def test_dmliv_sum_vs_original(self):
    method test_dml_multi_dim_treatment_outcome (line 1117) | def test_dml_multi_dim_treatment_outcome(self):
  class TestStatsModels2SLS (line 1245) | class TestStatsModels2SLS(unittest.TestCase):
    method test_comp_with_IV2SLS (line 1246) | def test_comp_with_IV2SLS(self):

FILE: econml/tests/test_treatment_featurization.py
  class DGP (line 22) | class DGP():
    method __init__ (line 23) | def __init__(self,
    method gen_Y (line 59) | def gen_Y(self):
    method gen_X (line 64) | def gen_X(self):
    method gen_T (line 68) | def gen_T(self):
    method gen_Z (line 74) | def gen_Z(self):
    method gen_data (line 84) | def gen_data(self):
  function actual_effect (line 107) | def actual_effect(y_of_t, T0, T1):
  function nuisance_T (line 111) | def nuisance_T(X):
  function nuisance_Y (line 115) | def nuisance_Y(X):
  function identity_y_of_t (line 120) | def identity_y_of_t(T):
  function identity_actual_marginal (line 124) | def identity_actual_marginal(T):
  function identity_actual_cme (line 128) | def identity_actual_cme():
  function poly_y_of_t (line 136) | def poly_y_of_t(T):
  function poly_actual_marginal (line 140) | def poly_actual_marginal(t):
  function poly_actual_cme (line 144) | def poly_actual_cme():
  function poly_func_transform (line 148) | def poly_func_transform(x):
  function poly_1d_actual_cme (line 157) | def poly_1d_actual_cme():
  function poly_1d_func_transform (line 161) | def poly_1d_func_transform(x):
  function sum_y_of_t (line 170) | def sum_y_of_t(T):
  function sum_actual_cme (line 174) | def sum_actual_cme():
  function sum_actual_marginal (line 178) | def sum_actual_marginal(t):
  function sum_func_transform (line 182) | def sum_func_transform(x):
  function sum_squeeze_func_transform (line 190) | def sum_squeeze_func_transform(x):
  class TestTreatmentFeaturization (line 198) | class TestTreatmentFeaturization(unittest.TestCase):
    method test_featurization (line 200) | def test_featurization(self):
    method test_jac (line 486) | def test_jac(self):
    method test_fail_discrete_treatment_and_treatment_featurizer (line 513) | def test_fail_discrete_treatment_and_treatment_featurizer(self):
    method test_cate_treatment_names_edge_cases (line 553) | def test_cate_treatment_names_edge_cases(self):
    method test_alpha_passthrough (line 577) | def test_alpha_passthrough(self):
    method test_identity_feat_with_cate_api (line 598) | def test_identity_feat_with_cate_api(self):

FILE: econml/tests/test_tree.py
  class TestTree (line 13) | class TestTree(unittest.TestCase):
    method _get_base_config (line 15) | def _get_base_config(self):
    method _get_base_honest_config (line 42) | def _get_base_honest_config(self):
    method _get_cython_objects (line 69) | def _get_cython_objects(self, *, n_features, n_y, n_outputs, n_relevan...
    method _get_continuous_data (line 88) | def _get_continuous_data(self, config):
    method _get_binary_data (line 99) | def _get_binary_data(self, config):
    method _train_tree (line 110) | def _train_tree(self, config, X, y):
    method _test_tree_continuous (line 118) | def _test_tree_continuous(self, base_config_gen):
    method test_dishonest_tree (line 238) | def test_dishonest_tree(self):
    method test_honest_tree (line 241) | def test_honest_tree(self):
    method test_multivariable_split (line 244) | def test_multivariable_split(self):
    method test_honest_values (line 251) | def test_honest_values(self):
    method test_noisy_instance (line 260) | def test_noisy_instance(self):

FILE: econml/tests/test_two_stage_least_squares.py
  class Test2SLS (line 16) | class Test2SLS(unittest.TestCase):
    method test_hermite_shape (line 18) | def test_hermite_shape(self):
    method test_hermite_results (line 27) | def test_hermite_results(self):
    method test_hermite_approx (line 42) | def test_hermite_approx(self):
    method test_2sls_shape (line 60) | def test_2sls_shape(self):
    method test_marg_eff (line 94) | def test_marg_eff(self):
    method test_2sls (line 125) | def test_2sls(self):

FILE: econml/tests/test_utilities.py
  class TestUtilities (line 17) | class TestUtilities(unittest.TestCase):
    method test_check_high_dimensional (line 18) | def test_check_high_dimensional(self):
    method test_cross_product (line 28) | def test_cross_product(self):
    method test_einsum_errors (line 46) | def test_einsum_errors(self):
    method test_einsum_basic (line 77) | def test_einsum_basic(self):
    method test_transpose_compatible (line 95) | def test_transpose_compatible(self):
    method test_inverse_onehot (line 108) | def test_inverse_onehot(self):
    method test_einsum_random (line 116) | def test_einsum_random(self):
    method test_transpose_dictionary (line 139) | def test_transpose_dictionary(self):
    method test_deprecated (line 145) | def test_deprecated(self):
    method test_deprecate_positional (line 172) | def test_deprecate_positional(self):
    method test_single_strata_from_discrete_array (line 191) | def test_single_strata_from_discrete_array(self):

FILE: econml/tests/utilities.py
  class GroupingModel (line 8) | class GroupingModel:
    method __init__ (line 20) | def __init__(self, model, total, limits, n_copies):
    method validate (line 26) | def validate(self, y, skip_group_counts=False):
    method fit (line 40) | def fit(self, X, y):
    method predict (line 45) | def predict(self, X):
  class NestedModel (line 49) | class NestedModel(GroupingModel):
    method cv (line 59) | def cv(self):
    method cv (line 63) | def cv(self, value):
    method fit (line 66) | def fit(self, X, y):

FILE: econml/tree/_tree_classes.py
  class BaseTree (line 22) | class BaseTree(BaseEstimator):
    method __init__ (line 24) | def __init__(self, *,
    method _get_valid_criteria (line 52) | def _get_valid_criteria(self):
    method _get_valid_min_var_leaf_criteria (line 55) | def _get_valid_min_var_leaf_criteria(self):
    method _get_store_jac (line 58) | def _get_store_jac(self):
    method get_depth (line 61) | def get_depth(self):
    method get_n_leaves (line 76) | def get_n_leaves(self):
    method fit (line 87) | def fit(self, X, y, n_y, n_outputs, n_relevant_outputs, sample_weight=...
    method _validate_X_predict (line 281) | def _validate_X_predict(self, X, check_input):
    method get_train_test_split_inds (line 295) | def get_train_test_split_inds(self,):
    method apply (line 313) | def apply(self, X, check_input=True):
    method decision_path (line 337) | def decision_path(self, X, check_input=True):
    method n_features_ (line 361) | def n_features_(self):

FILE: econml/utilities.py
  class IdentityFeatures (line 31) | class IdentityFeatures(TransformerMixin):
    method fit (line 34) | def fit(self, X):
    method transform (line 38) | def transform(self, X):
  function parse_final_model_params (line 43) | def parse_final_model_params(coef, intercept, d_y, d_t, d_t_in, bias_par...
  function check_high_dimensional (line 61) | def check_high_dimensional(X, T, *, threshold, featurizer=None, discrete...
  function inverse_onehot (line 78) | def inverse_onehot(T):
  function issparse (line 99) | def issparse(X):
  function iscoo (line 119) | def iscoo(X):
  function tocoo (line 136) | def tocoo(X):
  function todense (line 152) | def todense(X):
  function size (line 168) | def size(X):
  function shape (line 184) | def shape(X):
  function ndim (line 189) | def ndim(X):
  function reshape (line 194) | def reshape(X, shape):
  function _apply (line 222) | def _apply(op, *XS):
  function tensordot (line 240) | def tensordot(X1, X2, axes):
  function cross_product (line 262) | def cross_product(*XS):
  function stack (line 296) | def stack(XS, axis=0):
  function concatenate (line 322) | def concatenate(XS, axis=0):
  function hstack (line 346) | def hstack(XS):
  function vstack (line 367) | def vstack(XS):
  function transpose (line 389) | def transpose(X, axes=None):
  function add_intercept (line 414) | def add_intercept(X):
  function reshape_Y_T (line 431) | def reshape_Y_T(Y, T):
  function _get_ensure_finite_arg (line 461) | def _get_ensure_finite_arg(ensure_all_finite: Union[str, bool]) -> dict[...
  function check_inputs (line 469) | def check_inputs(Y, T, X, W=None, multi_output_T=True, multi_output_Y=True,
  function check_input_arrays (line 546) | def check_input_arrays(*args, validate_len=True, force_all_finite=True, ...
  function get_input_columns (line 608) | def get_input_columns(X, prefix="X"):
  function get_feature_names_or_default (line 652) | def get_feature_names_or_default(featurizer, feature_names, prefix="feat...
  function check_models (line 705) | def check_models(models, n):
  function broadcast_unit_treatments (line 736) | def broadcast_unit_treatments(X, d_t):
  function reshape_treatmentwise_effects (line 761) | def reshape_treatmentwise_effects(A, d_t, d_y):
  function reshape_outcomewise_effects (line 786) | def reshape_outcomewise_effects(A, d_y):
  function einsum_sparse (line 809) | def einsum_sparse(subscripts, *arrs):
  function filter_none_kwargs (line 948) | def filter_none_kwargs(**kwargs):
  class WeightedModelWrapper (line 968) | class WeightedModelWrapper:
    method __init__ (line 984) | def __init__(self, model_instance, sample_type="weighted"):
    method fit (line 993) | def fit(self, X, y, sample_weight=None):
    method predict (line 1012) | def predict(self, X):
    method _weighted_inputs (line 1027) | def _weighted_inputs(self, X, y, sample_weight):
    method _sampled_inputs (line 1035) | def _sampled_inputs(self, X, y, sample_weight):
  class MultiModelWrapper (line 1043) | class MultiModelWrapper:
    method __init__ (line 1052) | def __init__(self, model_list=[]):
    method fit (line 1056) | def fit(self, Xt, y, sample_weight=None):
    method predict (line 1083) | def predict(self, Xt):
  function _safe_norm_ppf (line 1102) | def _safe_norm_ppf(q, loc=0, scale=1):
  class Summary (line 1114) | class Summary:
    method __init__ (line 1132) | def __init__(self):
    method __str__ (line 1136) | def __str__(self):
    method __repr__ (line 1139) | def __repr__(self):
    method _repr_html_ (line 1142) | def _repr_html_(self):
    method add_table (line 1146) | def add_table(self, res, header, index, title):
    method add_extra_txt (line 1150) | def add_extra_txt(self, etext):
    method as_text (line 1161) | def as_text(self):
    method as_latex (line 1175) | def as_latex(self):
    method as_csv (line 1195) | def as_csv(self):
    method as_html (line 1209) | def as_html(self):
  class SeparateModel (line 1224) | class SeparateModel:
    method __init__ (line 1231) | def __init__(self, *models):
    method fit (line 1234) | def fit(self, XZ, T):
    method predict (line 1240) | def predict(self, XZ):
    method coef_ (line 1249) | def coef_(self):
  function deprecated (line 1253) | def deprecated(message, category=FutureWarning):
  function _deprecate_positional (line 1288) | def _deprecate_positional(message, bad_args, category=FutureWarning):
  class MissingModule (line 1319) | class MissingModule:
    method __init__ (line 1331) | def __init__(self, msg, exn):
    method __getattr__ (line 1336) | def __getattr__(self, _):
    method __call__ (line 1340) | def __call__(self, *args, **kwargs):
  function transpose_dictionary (line 1344) | def transpose_dictionary(d):
  function reshape_arrays_2dim (line 1368) | def reshape_arrays_2dim(length, *args):
  class _RegressionWrapper (line 1397) | class _RegressionWrapper:
    method __init__ (line 1410) | def __init__(self, clf):
    method fit (line 1413) | def fit(self, X, y, **kwargs):
    method predict (line 1427) | def predict(self, X):
  class _TransformerWrapper (line 1438) | class _TransformerWrapper:
    method __init__ (line 1441) | def __init__(self, featurizer):
    method fit (line 1444) | def fit(self, X):
    method transform (line 1447) | def transform(self, X):
    method fit_transform (line 1450) | def fit_transform(self, X):
    method get_feature_names_out (line 1453) | def get_feature_names_out(self, feature_names):
    method jac (line 1456) | def jac(self, X, epsilon=0.001):
  function jacify_featurizer (line 1515) | def jacify_featurizer(featurizer):
  function strata_from_discrete_arrays (line 1520) | def strata_from_discrete_arrays(arrs):
  function one_hot_encoder (line 1546) | def one_hot_encoder(sparse=False, **kwargs):

FILE: econml/validate/drtester.py
  class DRTester (line 17) | class DRTester:
    method __init__ (line 122) | def __init__(
    method get_cv_splitter (line 135) | def get_cv_splitter(self, random_state: int = 123):
    method get_cv_splits (line 157) | def get_cv_splits(self, vars: np.array, T: np.array):
    method fit_nuisance (line 182) | def fit_nuisance(
    method fit_nuisance_train (line 253) | def fit_nuisance_train(
    method fit_nuisance_cv (line 296) | def fit_nuisance_cv(
    method get_cate_preds (line 336) | def get_cate_preds(
    method evaluate_cal (line 369) | def evaluate_cal(
    method evaluate_blp (line 448) | def evaluate_blp(
    method evaluate_uplift (line 505) | def evaluate_uplift(
    method evaluate_all (line 593) | def evaluate_all(
  class DRtester (line 642) | class DRtester(DRTester):

FILE: econml/validate/results.py
  class CalibrationEvaluationResults (line 7) | class CalibrationEvaluationResults:
    method __init__ (line 24) | def __init__(
    method summary (line 34) | def summary(self) -> pd.DataFrame:
    method plot_cal (line 52) | def plot_cal(self, tmt: Any):
  class BLPEvaluationResults (line 84) | class BLPEvaluationResults:
    method __init__ (line 103) | def __init__(
    method summary (line 115) | def summary(self):
  class UpliftEvaluationResults (line 136) | class UpliftEvaluationResults:
    method __init__ (line 159) | def __init__(
    method summary (line 173) | def summary(self):
    method plot_uplift (line 193) | def plot_uplift(self, tmt: Any, err_type: str = None):
  class EvaluationResults (line 250) | class EvaluationResults:
    method __init__ (line 269) | def __init__(
    method summary (line 281) | def summary(self):
    method plot_cal (line 305) | def plot_cal(self, tmt: int):
    method plot_qini (line 320) | def plot_qini(self, tmt: int, err_type: str = None):
    method plot_toc (line 339) | def plot_toc(self, tmt: int, err_type: str = None):

FILE: econml/validate/sensitivity_analysis.py
  function sensitivity_summary (line 10) | def sensitivity_summary(theta, sigma, nu, cov, null_hypothesis=0, alpha=...
  function sensitivity_interval (line 38) | def sensitivity_interval(theta, sigma, nu, cov, alpha, c_y, c_t, rho, in...
  function RV (line 77) | def RV(theta, sigma, nu, cov, alpha, null_hypothesis=0, interval_type='c...
  function dml_sensitivity_values (line 138) | def dml_sensitivity_values(t_res, y_res):
  function dr_sensitivity_values (line 168) | def dr_sensitivity_values(Y, T, y_pred, t_pred):

FILE: econml/validate/utils.py
  function calculate_dr_outcomes (line 7) | def calculate_dr_outcomes(
  function calc_uplift (line 50) | def calc_uplift(

FILE: monte_carlo_tests/monte_carlo_honestforest.py
  function monte_carlo (line 11) | def monte_carlo():

FILE: monte_carlo_tests/monte_carlo_statsmodels.py
  class GridSearchCVList (line 20) | class GridSearchCVList:
    method __init__ (line 22) | def __init__(self, estimator_list, param_grid_list, scoring=None,
    method fit (line 32) | def fit(self, X, y, **fit_params):
    method predict (line 39) | def predict(self, X):
  function _coverage_profile (line 43) | def _coverage_profile(est, X_test, alpha, true_coef, true_effect):
  function _append_coverage (line 78) | def _append_coverage(key, coverage, est, X_test, alpha, true_coef, true_...
  function _agg_coverage (line 89) | def _agg_coverage(coverage, qs=np.array([.005, .025, .1, .9, .975, .995])):
  function plot_coverage (line 104) | def plot_coverage(coverage, cov_key, n, n_exp, hetero_coef_list, d_list,...
  function print_aggregate (line 133) | def print_aggregate(mean_coverage, std_coverage, q_coverage, file_gen=la...
  function run_all_mc (line 213) | def run_all_mc(first_stage, folder, n_list, n_exp, hetero_coef_list, d_l...
  function monte_carlo (line 367) | def monte_carlo(first_stage=lambda: LinearRegression(), folder='lr'):
  function monte_carlo_lasso (line 381) | def monte_carlo_lasso(first_stage=lambda: WeightedLasso(alpha=0.01,
  function monte_carlo_rf (line 397) | def monte_carlo_rf(first_stage=lambda: RandomForestRegressor(n_estimator...
  function monte_carlo_gcv (line 412) | def monte_carlo_gcv(folder='gcv'):

FILE: prototypes/dml_iv/coverage_experiment.py
  class StatsModelLinearRegression (line 33) | class StatsModelLinearRegression:
    method __init__ (line 34) | def __init__(self):
    method fit (line 36) | def fit(self, X, y):
    method predict (line 39) | def predict(self, X):
    method summary (line 41) | def summary(self):
    method coef_ (line 44) | def coef_(self):
    method intercept_ (line 47) | def intercept_(self):
  class SeparateModel (line 54) | class SeparateModel:
    method __init__ (line 55) | def __init__(self, model0, model1):
    method fit (line 59) | def fit(self, XZ, T):
    method predict (line 65) | def predict(self, XZ):
    method coef_ (line 76) | def coef_(self):
  function gen_data (line 102) | def gen_data(data_type, n):
  function dgp_binary (line 117) | def dgp_binary(X, n, true_fn):
  function exp (line 128) | def exp(n):

FILE: prototypes/dml_iv/deep_dml_iv.py
  class DeepDMLIV (line 10) | class DeepDMLIV(_BaseDMLIV):
    method __init__ (line 16) | def __init__(self, model_Y_X, model_T_X, model_T_XZ, h,

FILE: prototypes/dml_iv/deep_dr_iv.py
  class _KerasModel (line 9) | class _KerasModel:
    method __init__ (line 19) | def __init__(self, h,
    method fit (line 30) | def fit(self, X, Y, sample_weight=None):
    method predict (line 36) | def predict(self, X):
    method __deepcopy__ (line 39) | def __deepcopy__(self, memo):
  class DeepDRIV (line 44) | class DeepDRIV(DRIV):
    method __init__ (line 49) | def __init__(self, model_Y_X, model_T_X, model_Z_X,
  class DeepProjectedDRIV (line 96) | class DeepProjectedDRIV(ProjectedDRIV):
    method __init__ (line 101) | def __init__(self, model_Y_X, model_T_X, model_T_XZ,
  class DeepIntentToTreatDRIV (line 148) | class DeepIntentToTreatDRIV(IntentToTreatDRIV):
    method __init__ (line 153) | def __init__(self, model_Y_X, model_T_XZ,

FILE: prototypes/dml_iv/dml_ate_iv.py
  class DMLATEIV (line 16) | class DMLATEIV:
    method __init__ (line 30) | def __init__(self, model_Y_X, model_T_X, model_Z_X, n_splits=2,
    method fit (line 50) | def fit(self, y, T, X, Z):
    method effect (line 99) | def effect(self, X=None):
    method normal_effect_interval (line 110) | def normal_effect_interval(self, lower=5, upper=95):
    method std (line 114) | def std(self):
    method fitted_nuisances (line 118) | def fitted_nuisances(self):
  class ProjectedDMLATEIV (line 124) | class ProjectedDMLATEIV:
    method __init__ (line 139) | def __init__(self, model_Y_X, model_T_X, model_T_XZ, n_splits=2,
    method fit (line 158) | def fit(self, y, T, X, Z):
    method effect (line 211) | def effect(self, X=None):
    method normal_effect_interval (line 222) | def normal_effect_interval(self, lower=5, upper=95):
    method std (line 227) | def std(self):
    method fitted_nuisances (line 231) | def fitted_nuisances(self):
  class SimpleATEIV (line 236) | class SimpleATEIV:
    method __init__ (line 243) | def __init__(self, model_T_XZ, model_final):
    method fit (line 253) | def fit(self, y, T, X, Z):
    method effect (line 276) | def effect(self, X, T0=0, T1=1):
    method coef_ (line 292) | def coef_(self):

FILE: prototypes/dml_iv/dml_iv.py
  class _BaseDMLIV (line 22) | class _BaseDMLIV:
    method __init__ (line 38) | def __init__(self, model_Y_X, model_T_X, model_T_XZ, model_effect,
    method fit (line 65) | def fit(self, y, T, X, Z, store_final=False):
    method effect (line 129) | def effect(self, X):
    method coef_ (line 138) | def coef_(self):
    method intercept_ (line 142) | def intercept_(self):
    method effect_model (line 146) | def effect_model(self):
    method fitted_nuisances (line 150) | def fitted_nuisances(self):
  class DMLIV (line 156) | class DMLIV(_BaseDMLIV):
    method __init__ (line 169) | def __init__(self, model_Y_X, model_T_X, model_T_XZ, model_effect, fea...
    method refit_final (line 228) | def refit_final(self, model_effect, featurizer):
    method effect_model (line 244) | def effect_model(self):
  class GenericDMLIV (line 250) | class GenericDMLIV(_BaseDMLIV):
    method __init__ (line 266) | def __init__(self, model_Y_X, model_T_X, model_T_XZ, model_effect,
    method refit_final (line 327) | def refit_final(self, model_effect):
    method effect_model (line 342) | def effect_model(self):

FILE: prototypes/dml_iv/dr_iv.py
  class _BaseDRIV (line 24) | class _BaseDRIV:
    method __init__ (line 31) | def __init__(self, nuisance_models,
    method _check_inputs (line 66) | def _check_inputs(self, y, T, X, Z):
    method _nuisance_estimates (line 71) | def _nuisance_estimates(self, y, T, X, Z):
    method _get_split_enum (line 77) | def _get_split_enum(self, y, T, X, Z):
    method fit (line 95) | def fit(self, y, T, X, Z, store_final=False):
    method refit_final (line 135) | def refit_final(self, model_effect, opt_reweighted=None):
    method effect (line 156) | def effect(self, X):
    method effect_model (line 165) | def effect_model(self):
    method fitted_nuisances (line 169) | def fitted_nuisances(self):
    method coef_ (line 176) | def coef_(self):
    method intercept_ (line 182) | def intercept_(self):
  class DRIV (line 188) | class DRIV(_BaseDRIV):
    method __init__ (line 193) | def __init__(self, model_Y_X, model_T_X, model_Z_X,
    method _check_inputs (line 235) | def _check_inputs(self, y, T, X, Z):
    method _nuisance_estimates (line 249) | def _nuisance_estimates(self, y, T, X, Z):
  class ProjectedDRIV (line 281) | class ProjectedDRIV(_BaseDRIV):
    method __init__ (line 288) | def __init__(self, model_Y_X, model_T_X, model_T_XZ,
    method _check_inputs (line 330) | def _check_inputs(self, y, T, X, Z):
    method _nuisance_estimates (line 347) | def _nuisance_estimates(self, y, T, X, Z):
  class _IntentToTreatDRIV (line 399) | class _IntentToTreatDRIV(_BaseDRIV):
    method __init__ (line 404) | def __init__(self, model_Y_X, model_T_XZ,
    method _check_inputs (line 422) | def _check_inputs(self, y, T, X, Z):
    method _nuisance_estimates (line 436) | def _nuisance_estimates(self, y, T, X, Z):
  class _DummyCATE (line 464) | class _DummyCATE:
    method __init__ (line 469) | def __init__(self):
    method fit (line 472) | def fit(self, y, T, X, Z):
    method effect (line 475) | def effect(self, X):
  class IntentToTreatDRIV (line 479) | class IntentToTreatDRIV(_IntentToTreatDRIV):
    method __init__ (line 484) | def __init__(self, model_Y_X, model_T_XZ,

FILE: prototypes/dml_iv/utilities.py
  class StatsModelLinearRegression (line 23) | class StatsModelLinearRegression:
    method __init__ (line 25) | def __init__(self, fit_intercept=True, cov_type='nonrobust'):
    method fit (line 30) | def fit(self, X, y, sample_weight=None):
    method predict (line 39) | def predict(self, X):
    method summary (line 44) | def summary(self, *args, **kwargs):
    method coef_ (line 48) | def coef_(self):
    method intercept_ (line 54) | def intercept_(self):
  class ConstantModel (line 61) | class ConstantModel:
    method __init__ (line 63) | def __init__(self):
    method fit (line 67) | def fit(self, X, y, sample_weight=None):
    method predict (line 71) | def predict(self, X):
    method summary (line 74) | def summary(self, *args, **kwargs):
    method coef_ (line 78) | def coef_(self):
    method intercept_ (line 82) | def intercept_(self):
  class SeparateModel (line 85) | class SeparateModel:
    method __init__ (line 91) | def __init__(self, model0, model1):
    method fit (line 96) | def fit(self, XZ, T):
    method predict (line 103) | def predict(self, XZ):
    method coef_ (line 114) | def coef_(self):
  class RegWrapper (line 117) | class RegWrapper:
    method __init__ (line 125) | def __init__(self, clf):
    method fit (line 133) | def fit(self, X, y):
    method predict (line 143) | def predict(self, X):
    method __getattr__ (line 151) | def __getattr__(self, name):
    method __deepcopy__ (line 156) | def __deepcopy__(self, memo):
  class SubsetWrapper (line 159) | class SubsetWrapper:
    method __init__ (line 165) | def __init__(self, model, inds):
    method fit (line 175) | def fit(self, X, y, **kwargs):
    method predict (line 185) | def predict(self, X):
    method __getattr__ (line 193) | def __getattr__(self, name):
    method __deepcopy__ (line 198) | def __deepcopy__(self, memo):
  class WeightWrapper (line 201) | class WeightWrapper:
    method __init__ (line 211) | def __init__(self, model):
    method fit (line 222) | def fit(self, X, y, sample_weight=None):
    method predict (line 236) | def predict(self, X):
    method coef_ (line 245) | def coef_(self):
    method intercept_ (line 251) | def intercept_(self):
    method __getattr__ (line 256) | def __getattr__(self, name):
    method __deepcopy__ (line 261) | def __deepcopy__(self, memo):
  class SelectiveLasso (line 266) | class SelectiveLasso:
    method __init__ (line 268) | def __init__(self, inds, lasso_model):
    method fit (line 276) | def fit(self, X, y):
    method predict (line 290) | def predict(self, X):
    method model (line 298) | def model(self):
    method coef_ (line 302) | def coef_(self):
    method intercept_ (line 313) | def intercept_(self):
  class HonestForest (line 317) | class HonestForest(RandomForestRegressor):
    method __init__ (line 324) | def __init__(self, forest, local_linear=False, alpha=0.1):
    method fit (line 337) | def fit(self, X, y, sample_weight=None):
    method predict (line 375) | def predict(self, X):
    method predict_interval (line 390) | def predict_interval(self, X, lower=2.5, upper=97.5, little_bags=False):
    method __getattr__ (line 409) | def __getattr__(self, name):
    method __deepcopy__ (line 414) | def __deepcopy__(self, memo):

FILE: prototypes/dml_iv/xgb_utilities.py
  class XGBWrapper (line 4) | class XGBWrapper:
    method __init__ (line 6) | def __init__(self, XGBoost, early_stopping_rounds, eval_metric, val_fr...
    method fit (line 14) | def fit(self, X, y, sample_weight=None):
    method predict_proba (line 26) | def predict_proba(self, X):
    method predict (line 29) | def predict(self, X):
    method __getattr__ (line 32) | def __getattr__(self, name):
    method __deepcopy__ (line 37) | def __deepcopy__(self, memo):

FILE: prototypes/dynamic_dml/coverage_panel.py
  function exp (line 13) | def exp(exp_id, dgp, n_units, gamma, s_t, sigma_t):
  function add_vlines (line 45) | def add_vlines(n_periods, n_treatments, hetero_inds=[]):
  function run_mc (line 75) | def run_mc(n_exps, n_units, n_x, s_x, n_periods, n_treatments, s_t, sigm...

FILE: prototypes/dynamic_dml/coverage_panel_hetero.py
  function exp (line 13) | def exp(exp_id, dgp, n_units, gamma, s_t, sigma_t, hetero_inds, test_pol...
  function add_vlines (line 56) | def add_vlines(n_periods, n_treatments, hetero_inds):
  function run_mc (line 97) | def run_mc(n_exps, n_units, n_x, s_x, n_periods, n_treatments, s_t, sigm...

FILE: prototypes/dynamic_dml/dynamic_panel_dgp.py
  class AbstracDynamicPanelDGP (line 6) | class AbstracDynamicPanelDGP:
    method __init__ (line 8) | def __init__(self, n_periods, n_treatments, n_x):
    method create_instance (line 14) | def create_instance(self, *args, **kwargs):
    method _gen_data_with_policy (line 17) | def _gen_data_with_policy(self, n_units, policy_gen, random_seed=123):
    method static_policy_data (line 20) | def static_policy_data(self, n_units, tau, random_seed=123):
    method adaptive_policy_data (line 25) | def adaptive_policy_data(self, n_units, policy_gen, random_seed=123):
    method static_policy_effect (line 28) | def static_policy_effect(self, tau, mc_samples=1000):
    method adaptive_policy_effect (line 36) | def adaptive_policy_effect(self, policy_gen, mc_samples=1000):
  class DynamicPanelDGP (line 45) | class DynamicPanelDGP(AbstracDynamicPanelDGP):
    method __init__ (line 47) | def __init__(self, n_periods, n_treatments, n_x):
    method create_instance (line 50) | def create_instance(self, s_x, sigma_x, sigma_y, conf_str, hetero_stre...
    method hetero_effect_fn (line 106) | def hetero_effect_fn(self, t, x):
    method _gen_data_with_policy (line 114) | def _gen_data_with_policy(self, n_units, policy_gen, random_seed=123):
    method observational_data (line 137) | def observational_data(self, n_units, gamma, s_t, sigma_t, random_seed...
  class LongRangeDynamicPanelDGP (line 156) | class LongRangeDynamicPanelDGP(DynamicPanelDGP):
    method __init__ (line 158) | def __init__(self, n_periods, n_treatments, n_x):
    method create_instance (line 161) | def create_instance(self, s_x, sigma_x, sigma_y, conf_str, hetero_stre...
  class EndogenousDynamicPanelDGP (line 209) | class EndogenousDynamicPanelDGP(DynamicPanelDGP):
    method __init__ (line 211) | def __init__(self, n_periods, n_treatments, n_x):
    method create_instance (line 214) | def create_instance(self, s_x, sigma_x, sigma_y, conf_str, hetero_stre...
  class PastTreatmentHeteroDynamicPanelDGP (line 260) | class PastTreatmentHeteroDynamicPanelDGP(DynamicPanelDGP):
    method __init__ (line 262) | def __init__(self, n_periods, n_treatments, n_x):
    method create_instance (line 265) | def create_instance(self, s_x, sigma_x, sigma_y, conf_str, hetero_stre...

FILE: prototypes/dynamic_dml/hetero_panel_dynamic_dml.py
  class HeteroDynamicPanelDML (line 10) | class HeteroDynamicPanelDML:
    method __init__ (line 12) | def __init__(self, model_t=LassoCV(cv=3),
    method fit_nuisances (line 25) | def fit_nuisances(self, Y, T, X, groups, n_periods):
    method _fit_cov_matrix (line 50) | def _fit_cov_matrix(self, resT, resY, models):
    method fit_final (line 85) | def fit_final(self, Y, T, X, groups, resT, resY, n_periods, hetero_inds):
    method fit (line 111) | def fit(self, Y, T, X, groups, hetero_inds=np.empty(shape=(0,))):
    method param (line 126) | def param(self):
    method param_cov (line 130) | def param_cov(self):
    method param_stderr (line 134) | def param_stderr(self):
    method param_interval (line 137) | def param_interval(self, alpha=.05):
    method _policy_effect_var (line 142) | def _policy_effect_var(self, tau):
    method _policy_effect_stderr (line 145) | def _policy_effect_stderr(self, tau):
    method policy_effect (line 148) | def policy_effect(self, tau, subX, groups, alpha=0.05):
    method adaptive_policy_effect (line 167) | def adaptive_policy_effect(self, X, groups, policy_gen, alpha=.05):

FILE: prototypes/dynamic_dml/panel_dynamic_dml.py
  class DynamicPanelDML (line 9) | class DynamicPanelDML:
    method __init__ (line 11) | def __init__(self, model_t=LassoCV(cv=3),
    method fit_nuisances (line 21) | def fit_nuisances(self, Y, T, X, groups, n_periods):
    method _fit_cov_matrix (line 46) | def _fit_cov_matrix(self, resT, resY, models):
    method fit_final (line 81) | def fit_final(self, Y, T, X, groups, resT, resY, n_periods):
    method fit (line 99) | def fit(self, Y, T, X, groups):
    method param (line 112) | def param(self):
    method param_cov (line 116) | def param_cov(self):
    method param_stderr (line 120) | def param_stderr(self):
    method param_interval (line 123) | def param_interval(self, alpha=.05):
    method policy_effect (line 128) | def policy_effect(self, tau):
    method policy_effect_var (line 131) | def policy_effect_var(self, tau):
    method policy_effect_stderr (line 134) | def policy_effect_stderr(self, tau):
    method policy_effect_interval (line 137) | def policy_effect_interval(self, tau, alpha=0.05):
    method adaptive_policy_effect (line 145) | def adaptive_policy_effect(self, X, groups, policy_gen, alpha=.05):

FILE: prototypes/orthogonal_forests/causal_tree.py
  class Node (line 11) | class Node:
    method __init__ (line 13) | def __init__(self, sample_inds, estimate_inds):
  class CausalTree (line 25) | class CausalTree:
    method __init__ (line 27) | def __init__(self, W, x, T, Y, model_T, model_Y, min_leaf_size=20, max...
    method recursive_split (line 44) | def recursive_split(self, node, split_acc):
    method create_splits (line 132) | def create_splits(self):
    method estimate_leafs (line 138) | def estimate_leafs(self, node):
    method estimate (line 150) | def estimate(self):
    method print_tree_rec (line 153) | def print_tree_rec(self, node):
    method print_tree (line 162) | def print_tree(self):
    method find_tree_node (line 165) | def find_tree_node(self, node, value):
    method find_split (line 173) | def find_split(self, value):

FILE: prototypes/orthogonal_forests/comparison_plots.py
  function has_plot_controls (line 32) | def has_plot_controls(fname, control_combination):
  function get_file_key (line 38) | def get_file_key(fname):
  function sort_fnames (line 44) | def sort_fnames(file_names):
  function get_file_groups (line 56) | def get_file_groups(agg_fnames, plot_controls):
  function merge_results (line 73) | def merge_results(sf, input_dir, output_dir, split_files_seeds):
  function get_results (line 87) | def get_results(fname, dir_name):
  function save_plots (line 91) | def save_plots(fig, fname, lgd=None):
  function get_r2 (line 113) | def get_r2(df):
  function get_metrics (line 117) | def get_metrics(dfs):
  function generic_joint_plots (line 142) | def generic_joint_plots(file_key, dfs, labels, file_name_prefix):
  function metrics_subfig (line 174) | def metrics_subfig(dfs, ax, metric, c_scheme=0):
  function metrics_plots (line 240) | def metrics_plots(file_key, dfs, labels, c_scheme, file_name_prefix):
  function support_plots (line 254) | def support_plots(all_metrics, labels, file_name_prefix):

FILE: prototypes/orthogonal_forests/hetero_dml.py
  function cross_product (line 11) | def cross_product(X1, X2):
  class HeteroDML (line 28) | class HeteroDML(object):
    method __init__ (line 30) | def __init__(self, poly_degree=3,
    method fit (line 38) | def fit(self, W, x, T, Y):
    method predict (line 63) | def predict(self, x):
  class ForestHeteroDML (line 68) | class ForestHeteroDML(object):
    method __init__ (line 70) | def __init__(self):
    method fit (line 75) | def fit(self, W, x, T, Y):
    method predict (line 99) | def predict(self, x):

FILE: prototypes/orthogonal_forests/monte_carlo.py
  function piecewise_linear_te (line 21) | def piecewise_linear_te(x):
  function step_te (line 29) | def step_te(x):
  function polynomial_te (line 37) | def polynomial_te(x):
  function doublez_te (line 45) | def doublez_te(x):

FILE: prototypes/orthogonal_forests/ortho_forest.py
  function _build_tree_in_parallel (line 40) | def _build_tree_in_parallel(W, x, T, Y, min_leaf_size, max_splits, resid...
  class OrthoTree (line 47) | class OrthoTree(object):
    method __init__ (line 74) | def __init__(self, min_leaf_size=20, max_splits=10, residualizer=dml,
    method fit (line 83) | def fit(self, W, x, T, Y):
    method predict (line 109) | def predict(self, x):
  class BaseOrthoForest (line 127) | class BaseOrthoForest(object):
    method __init__ (line 158) | def __init__(self, n_trees=10, min_leaf_size=20, max_splits=10,
    method fit_forest (line 173) | def fit_forest(self, W, x, T, Y):
    method fit (line 192) | def fit(self, W, x, T, Y):
    method predict (line 211) | def predict(self, x):
    method predict_interval (line 224) | def predict_interval(self, x, lower=5, upper=95):
  class DishonestOrthoForest (line 245) | class DishonestOrthoForest(BaseOrthoForest):
    method __init__ (line 294) | def __init__(self, n_trees=10, min_leaf_size=20, max_splits=10,
    method fit (line 315) | def fit(self, W, x, T, Y):
    method predict (line 337) | def predict(self, x):
    method predict_with_weights (line 347) | def predict_with_weights(self, x):
    method _predict (line 358) | def _predict(self, x, weights=False):
    method _point_predict (line 369) | def _point_predict(self, x_out, weights=False):
    method _get_weights (line 387) | def _get_weights(self, x_out):
    method _get_weighted_model (line 406) | def _get_weighted_model(self, model_instance):
    method _get_weighted_pipeline (line 416) | def _get_weighted_pipeline(self, model_instance):
    method _fit_weighted_pipeline (line 424) | def _fit_weighted_pipeline(self, model_instance, x, y, weights):
  class OrthoForest (line 431) | class OrthoForest(DishonestOrthoForest):
    method __init__ (line 480) | def __init__(self, n_trees=10, min_leaf_size=20, max_splits=10,
    method fit (line 497) | def fit(self, W, x, T, Y):
    method _predict (line 528) | def _predict(self, x, weights=False):
    method _point_predict (line 539) | def _point_predict(self, x_out, weights=False):
    method _get_weights (line 557) | def _get_weights(self, x_out):
  class ModelWrapper (line 579) | class ModelWrapper(object):
    method __init__ (line 595) | def __init__(self, model_instance, sample_type="weighted"):
    method __getattr__ (line 604) | def __getattr__(self, name):
    method _fit (line 611) | def _fit(self, func):
    method _weighted_inputs (line 619) | def _weighted_inputs(self, X, y, sample_weight):
    method _sampled_inputs (line 624) | def _sampled_inputs(self, X, y, sample_weight):

FILE: prototypes/orthogonal_forests/residualizer.py
  function dml (line 8) | def dml(W, T, Y, model_T=LassoCV(alphas=[0.01, 0.05, 0.1, 0.3, 0.5, 0.9,...
  function second_order_dml (line 35) | def second_order_dml(W, T, Y, model_T=LassoCV(alphas=[0.01, 0.05, 0.1, 0...
Copy disabled (too large) Download .json
Condensed preview — 270 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (16,571K chars).
[
  {
    "path": ".github/workflows/ci.yml",
    "chars": 20027,
    "preview": "name: Run all checks\n\non:\n  pull_request:\n    branches:\n      - main\n  workflow_dispatch:\n    inputs:\n      ref:\n       "
  },
  {
    "path": ".github/workflows/generate_lkg.py",
    "chars": 11595,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nimport argparse\nimport re\nfr"
  },
  {
    "path": ".github/workflows/publish-documentation.yml",
    "chars": 3930,
    "preview": "name: Build and publish the documentation\non:\n  workflow_dispatch:\n    inputs:\n      publish:\n        description: 'Whet"
  },
  {
    "path": ".github/workflows/publish-package.yml",
    "chars": 4182,
    "preview": "name: Build and publish the package to PyPI\n\non:\n  workflow_dispatch:\n    inputs:\n      publish:\n        description: 'W"
  },
  {
    "path": ".gitignore",
    "chars": 1344,
    "preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# Tex\n*.aux\n*.bbl\n*.blg\n*.log\n*.out\n*.synctex"
  },
  {
    "path": ".pre-commit-config.yaml",
    "chars": 289,
    "preview": "repos:\n- repo: https://github.com/astral-sh/ruff-pre-commit\n  # Ruff version.\n  rev: v0.12.2\n  hooks:\n    # Run the lint"
  },
  {
    "path": "LICENSE",
    "chars": 2978,
    "preview": "    MIT License\n\n    Copyright (c) PyWhy contributors. All rights reserved.\n\n    Permission is hereby granted, free of c"
  },
  {
    "path": "README.md",
    "chars": 35383,
    "preview": "[![Build status](https://github.com/py-why/EconML/actions/workflows/ci.yml/badge.svg)](https://github.com/py-why/EconML/"
  },
  {
    "path": "SECURITY.md",
    "chars": 2757,
    "preview": "<!-- BEGIN MICROSOFT SECURITY.MD V0.0.7 BLOCK -->\n\n## Security\n\nMicrosoft takes the security of our software products an"
  },
  {
    "path": "doc/conf.py",
    "chars": 8449,
    "preview": "# -*- coding: utf-8 -*-\n#\n# Configuration file for the Sphinx documentation builder.\n#\n# This file does only contain a s"
  },
  {
    "path": "doc/index.rst",
    "chars": 433,
    "preview": ".. econml documentation root file, created by\n   sphinx-quickstart on Fri Feb 15 12:08:35 2019.\n   You can adapt this fi"
  },
  {
    "path": "doc/reference.rst",
    "chars": 6049,
    "preview": "Public Module Reference\n=======================\n\nCATE Estimators\n---------------\n\n.. _dml_api:\n\nDouble Machine Learning "
  },
  {
    "path": "doc/spec/api.rst",
    "chars": 19704,
    "preview": "Problem Setup and API Design\n============================\n\n\n.. rubric::\n    Potential Outcomes Formulation\n\nWe begin by "
  },
  {
    "path": "doc/spec/causal_intro.rst",
    "chars": 548,
    "preview": "Introduction to Causal Inference\n=================================\n\nIf you are new to causal inference, it may be helpfu"
  },
  {
    "path": "doc/spec/community.rst",
    "chars": 705,
    "preview": "Community\n==========\n\n.. raw:: html\n    \n    <p></p>\n    <a href=\"https://pywhy.org/\">\n    <img src=\"../pywhy-logo.png\" "
  },
  {
    "path": "doc/spec/comparison.rst",
    "chars": 12522,
    "preview": "=============================\nDetailed estimator comparison\n=============================\n\n\n+---------------------------"
  },
  {
    "path": "doc/spec/estimation/dml.rst",
    "chars": 40526,
    "preview": ".. _dmluserguide:\n\n==================================\nOrthogonal/Double Machine Learning\n==============================="
  },
  {
    "path": "doc/spec/estimation/dr.rst",
    "chars": 30062,
    "preview": ".. _druserguide:\n\n======================\nDoubly Robust Learning\n======================\n\nWhat is it?\n===================="
  },
  {
    "path": "doc/spec/estimation/dynamic_dml.rst",
    "chars": 4183,
    "preview": ".. _dynamicdmluserguide:\n\n===============================\nDynamic Double Machine Learning\n=============================="
  },
  {
    "path": "doc/spec/estimation/forest.rst",
    "chars": 21778,
    "preview": ".. _orthoforestuserguide:\n\n=======================\nForest Based Estimators\n=======================\n\n\nWhat is it?\n======="
  },
  {
    "path": "doc/spec/estimation/metalearners.rst",
    "chars": 7476,
    "preview": ".. _metalearnersuserguide:\n\n==============\nMeta-Learners\n==============\n\n\nWhat is it?\n=================================="
  },
  {
    "path": "doc/spec/estimation/orthoiv.rst",
    "chars": 4357,
    "preview": ".. _orthoivuserguide:\n\n=================================\nOrthogonal instrumental variables\n============================="
  },
  {
    "path": "doc/spec/estimation/two_sls.rst",
    "chars": 1989,
    "preview": "\nSieve 2SLS Instrumental Variable Estimation\n===========================================\n\nThe sieve based instrumental v"
  },
  {
    "path": "doc/spec/estimation.rst",
    "chars": 521,
    "preview": "Estimation Methods under Unconfoundedness\n=========================================\n\nThis section contains methods for e"
  },
  {
    "path": "doc/spec/estimation_dynamic.rst",
    "chars": 425,
    "preview": "Estimation Methods for Dynamic Treatment Regimes\n================================================\n\nThis section contains"
  },
  {
    "path": "doc/spec/estimation_iv.rst",
    "chars": 814,
    "preview": "Estimation Methods with Instruments\n===================================\n\nThis section contains methods for estimating (h"
  },
  {
    "path": "doc/spec/faq.rst",
    "chars": 4030,
    "preview": "Frequently Asked Questions (FAQ)\n====================================================================\n\nWhen should I use"
  },
  {
    "path": "doc/spec/federated_learning.rst",
    "chars": 8638,
    "preview": "Federated Learning in EconML\r\n============================\r\n.. contents::\r\n    :local:\r\n    :depth: 2\r\n\r\nOverview\r\n-----"
  },
  {
    "path": "doc/spec/flowchart.rst",
    "chars": 5372,
    "preview": "==================\nLibrary Flow Chart\n==================\n\n\n.. raw:: html\n\n    <object data=\"../map.svg\" type=\"image/svg+"
  },
  {
    "path": "doc/spec/inference.rst",
    "chars": 7480,
    "preview": "=================\nInference\n=================\n\n\\ \n\nBootstrap Inference\n====================\n\nEvery estimator can provide"
  },
  {
    "path": "doc/spec/interpretability.rst",
    "chars": 4890,
    "preview": "Interpretability\n================\n\nOur package offers multiple interpretability tools to better understand the final mod"
  },
  {
    "path": "doc/spec/model_selection.rst",
    "chars": 2044,
    "preview": ".. _model_selection:\n\n=================\nModel Selection\n=================\n\nEstimators that derive from :class:`._OrthoLe"
  },
  {
    "path": "doc/spec/motivation.rst",
    "chars": 6107,
    "preview": "Machine Learning Based Estimation of Heterogeneous Treatment Effects\n==================================================="
  },
  {
    "path": "doc/spec/overview.rst",
    "chars": 3669,
    "preview": "Overview\n=========\n\nEconML is a Python package that applies the power of machine learning techniques to estimate individ"
  },
  {
    "path": "doc/spec/references.rst",
    "chars": 4969,
    "preview": "References\n==========\n\n.. [Chernozhukov2016]\n    V. Chernozhukov, D. Chetverikov, M. Demirer, E. Duflo, C. Hansen, and\n "
  },
  {
    "path": "doc/spec/spec.rst",
    "chars": 366,
    "preview": "EconML User Guide\n=================\n\n.. toctree::\n    overview\n    motivation\n    causal_intro\n    api\n    flowchart\n   "
  },
  {
    "path": "doc/spec/validation.rst",
    "chars": 3202,
    "preview": "Validation\n======================\n\nValidating causal estimates is inherently challenging, as the true counterfactual out"
  },
  {
    "path": "econml/__init__.py",
    "chars": 659,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\n__all__ = ['automated_ml'"
  },
  {
    "path": "econml/_cate_estimator.py",
    "chars": 61742,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\n\"\"\"Base classes for all CAT"
  },
  {
    "path": "econml/_ensemble/__init__.py",
    "chars": 610,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nfrom ._ensemble import Ba"
  },
  {
    "path": "econml/_ensemble/_ensemble.py",
    "chars": 6556,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n#\r\n# This code is a fork fr"
  },
  {
    "path": "econml/_ensemble/_utilities.py",
    "chars": 5035,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nimport numbers\r\nimport nu"
  },
  {
    "path": "econml/_ortho_learner.py",
    "chars": 57107,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\n\"\"\"\nGeneric implementation o"
  },
  {
    "path": "econml/_shap.py",
    "chars": 20800,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\n\"\"\"Helper functions to get s"
  },
  {
    "path": "econml/_tree_exporter.py",
    "chars": 32056,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n#\n# This code contains some s"
  },
  {
    "path": "econml/_version.py",
    "chars": 115,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\n__version__ = '0.16.0'\n"
  },
  {
    "path": "econml/automated_ml/__init__.py",
    "chars": 415,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nfrom ._automated_ml impor"
  },
  {
    "path": "econml/automated_ml/_automated_ml.py",
    "chars": 14812,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\n\"\"\"\nAutomated Machine Learni"
  },
  {
    "path": "econml/cate_interpreter/__init__.py",
    "chars": 264,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nfrom ._interpreters impor"
  },
  {
    "path": "econml/cate_interpreter/_interpreters.py",
    "chars": 26039,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nimport abc\r\nimport number"
  },
  {
    "path": "econml/data/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "econml/data/color-edits.sty",
    "chars": 3055,
    "preview": "\\ProvidesPackage{color-edits}\n\n\\def\\@SuppressEdits{no}\n\\DeclareOption{suppress}{%\n\\def\\@SuppressEdits{yes}\n}\n\n\\def\\@Show"
  },
  {
    "path": "econml/data/data_doc.bib",
    "chars": 274,
    "preview": "@article{hill2011bayesian,\n\ttitle={Bayesian nonparametric modeling for causal inference},\n\tauthor={Hill, Jennifer L},\n\tj"
  },
  {
    "path": "econml/data/data_doc.tex",
    "chars": 10024,
    "preview": "\\documentclass[10pt,letterpaper]{article}\n\n\\usepackage[margin=1in]{geometry}\n\\setlength{\\itemsep}{2pt}\n\\setlength{\\topse"
  },
  {
    "path": "econml/data/dgps.py",
    "chars": 3956,
    "preview": "import os\nimport numpy as np\nimport pandas as pd\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.utils imp"
  },
  {
    "path": "econml/data/dynamic_panel_dgp.py",
    "chars": 19044,
    "preview": "import numpy as np\nfrom econml.utilities import cross_product\nfrom statsmodels.tools.tools import add_constant\nimport pa"
  },
  {
    "path": "econml/data/ihdp/example.csv",
    "chars": 85525,
    "preview": "iqsb.36,ncdctt,dose400,treat,bw,momage,nnhealth,birth.o,parity,moreprem,cigs,alcohol,ppvt.imp,bwg,sex,mlt.birt,b.marr,li"
  },
  {
    "path": "econml/data/ihdp/example_full.csv",
    "chars": 311324,
    "preview": "\"row.names\",\"id\",\"tg\",\"bw\",\"bwg\",\"pag\",\"site\",\"b.length\",\"b.head\",\"momage\",\"momed\",\"kidrace\",\"sex\",\"nnhealth\",\"momrace\","
  },
  {
    "path": "econml/data/ihdp/sim.csv",
    "chars": 66191,
    "preview": "treat,bw,b.head,preterm,birth.o,nnhealth,momage,sex,twin,b.marr,mom.lths,mom.hs,mom.scoll,cig,first,booze,drugs,work.dur"
  },
  {
    "path": "econml/dml/__init__.py",
    "chars": 1972,
    "preview": "\r\n# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\n\"\"\"\r\nDouble Machine Lea"
  },
  {
    "path": "econml/dml/_rlearner.py",
    "chars": 28447,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\n\"\"\"\nThe R Learner plus assoc"
  },
  {
    "path": "econml/dml/causal_forest.py",
    "chars": 56035,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nfrom warnings import warn\n\ni"
  },
  {
    "path": "econml/dml/dml.py",
    "chars": 76884,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nfrom warnings import warn\n\ni"
  },
  {
    "path": "econml/dowhy.py",
    "chars": 12544,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\n\n\"\"\"Helper class to allow ot"
  },
  {
    "path": "econml/dr/__init__.py",
    "chars": 315,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nfrom ._drlearner import ("
  },
  {
    "path": "econml/dr/_drlearner.py",
    "chars": 97863,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\n\"\"\"\nDoubly Robust Learner.\n\n"
  },
  {
    "path": "econml/federated_learning.py",
    "chars": 4590,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nfrom sklearn import clone"
  },
  {
    "path": "econml/grf/__init__.py",
    "chars": 793,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\n\"\"\"\r\nAn efficient Cython "
  },
  {
    "path": "econml/grf/_base_grf.py",
    "chars": 50092,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n#\r\n# This code contains sni"
  },
  {
    "path": "econml/grf/_base_grftree.py",
    "chars": 23791,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n#\r\n# This code contains sni"
  },
  {
    "path": "econml/grf/_criterion.pxd",
    "chars": 5178,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n# published under the follo"
  },
  {
    "path": "econml/grf/_criterion.pyx",
    "chars": 56689,
    "preview": "# cython: cdivision=True\r\n# cython: boundscheck=False\r\n# cython: wraparound=False\r\n\r\n# Copyright (c) PyWhy contributors."
  },
  {
    "path": "econml/grf/_utils.pxd",
    "chars": 1399,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nimport numpy as np\r\ncimpo"
  },
  {
    "path": "econml/grf/_utils.pyx",
    "chars": 9865,
    "preview": "# cython: cdivision=True\r\n# cython: boundscheck=False\r\n# cython: wraparound=False\r\n\r\n# Copyright (c) PyWhy contributors."
  },
  {
    "path": "econml/grf/classes.py",
    "chars": 53329,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nimport numpy as np\r\nfrom "
  },
  {
    "path": "econml/inference/__init__.py",
    "chars": 1017,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nfrom ._inference import ("
  },
  {
    "path": "econml/inference/_bootstrap.py",
    "chars": 13663,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\n\"\"\"Bootstrap sampling.\"\"\""
  },
  {
    "path": "econml/inference/_inference.py",
    "chars": 75613,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nimport abc\nfrom collections "
  },
  {
    "path": "econml/iv/__init__.py",
    "chars": 129,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\n__all__ = [\"dml\", \"dr\", \""
  },
  {
    "path": "econml/iv/dml/__init__.py",
    "chars": 698,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\n\"\"\"Orthogonal IV for Hete"
  },
  {
    "path": "econml/iv/dml/_dml.py",
    "chars": 70791,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\n\"\"\"Orthogonal IV for Heterog"
  },
  {
    "path": "econml/iv/dr/__init__.py",
    "chars": 861,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\n\"\"\"Orthogonal IV for Hete"
  },
  {
    "path": "econml/iv/dr/_dr.py",
    "chars": 144581,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\n\"\"\"Doubly Robust IV for Hete"
  },
  {
    "path": "econml/iv/sieve/__init__.py",
    "chars": 256,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nfrom ._tsls import Hermit"
  },
  {
    "path": "econml/iv/sieve/_tsls.py",
    "chars": 14521,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\n\"\"\"Provides a non-parametric"
  },
  {
    "path": "econml/metalearners/__init__.py",
    "chars": 292,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nfrom ._metalearners impor"
  },
  {
    "path": "econml/metalearners/_metalearners.py",
    "chars": 26158,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\n\"\"\"\nMetalearners for heterog"
  },
  {
    "path": "econml/orf/__init__.py",
    "chars": 583,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\n\"\"\"\r\nAn implementation of"
  },
  {
    "path": "econml/orf/_causal_tree.py",
    "chars": 12797,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\n\"\"\"Basic tree utilities and "
  },
  {
    "path": "econml/orf/_ortho_forest.py",
    "chars": 68457,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\n\"\"\"Orthogonal Random Forest."
  },
  {
    "path": "econml/panel/__init__.py",
    "chars": 110,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\n__all__ = [\"dml\"]\n"
  },
  {
    "path": "econml/panel/dml/__init__.py",
    "chars": 598,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\n\"\"\"Double Machine Learning f"
  },
  {
    "path": "econml/panel/dml/_dml.py",
    "chars": 39739,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nimport numpy as np\nfrom warn"
  },
  {
    "path": "econml/panel/utilities.py",
    "chars": 1092,
    "preview": "\nimport numpy as np\n\n\ndef long(x):\n    \"\"\"\n    Reshape panel data to long format, i.e. (n_units * n_periods, d_x) or (n_"
  },
  {
    "path": "econml/policy/__init__.py",
    "chars": 310,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nfrom ._forest import Poli"
  },
  {
    "path": "econml/policy/_base.py",
    "chars": 360,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\n\"\"\"Base classes for all P"
  },
  {
    "path": "econml/policy/_drlearner.py",
    "chars": 50709,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nfrom warnings import warn"
  },
  {
    "path": "econml/policy/_forest/__init__.py",
    "chars": 217,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nfrom ._tree import Policy"
  },
  {
    "path": "econml/policy/_forest/_criterion.pxd",
    "chars": 798,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n# published under the follo"
  },
  {
    "path": "econml/policy/_forest/_criterion.pyx",
    "chars": 1751,
    "preview": "# cython: cdivision=True\r\n# cython: boundscheck=False\r\n# cython: wraparound=False\r\n\r\n# Copyright (c) PyWhy contributors."
  },
  {
    "path": "econml/policy/_forest/_forest.py",
    "chars": 22392,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n#\r\n# This code contains sni"
  },
  {
    "path": "econml/policy/_forest/_tree.py",
    "chars": 16008,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n#\r\n# This code contains sni"
  },
  {
    "path": "econml/score/__init__.py",
    "chars": 347,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\n\"\"\"A suite of scoring met"
  },
  {
    "path": "econml/score/ensemble_cate.py",
    "chars": 3157,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nimport numpy as np\r\nfrom "
  },
  {
    "path": "econml/score/rscorer.py",
    "chars": 10509,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nfrom ..dml import LinearD"
  },
  {
    "path": "econml/sklearn_extensions/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "econml/sklearn_extensions/linear_model.py",
    "chars": 90510,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\n\"\"\"Collection of scikit-lear"
  },
  {
    "path": "econml/sklearn_extensions/model_selection.py",
    "chars": 38112,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\"\"\"Collection of scikit-learn"
  },
  {
    "path": "econml/solutions/causal_analysis/__init__.py",
    "chars": 167,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nfrom ._causal_analysis impor"
  },
  {
    "path": "econml/solutions/causal_analysis/_causal_analysis.py",
    "chars": 92552,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\n\"\"\"Module for assessing caus"
  },
  {
    "path": "econml/tests/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "econml/tests/dgp.py",
    "chars": 10995,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\nimport abc\nimport numpy as np"
  },
  {
    "path": "econml/tests/test_ate_inference.py",
    "chars": 3636,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nimport numpy as np\r\nimpor"
  },
  {
    "path": "econml/tests/test_automated_ml.py",
    "chars": 8017,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nimport unittest\nimport pytes"
  },
  {
    "path": "econml/tests/test_bootstrap.py",
    "chars": 15415,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nfrom econml.inference._boots"
  },
  {
    "path": "econml/tests/test_cate_interpreter.py",
    "chars": 9074,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nimport numpy as np\nimport un"
  },
  {
    "path": "econml/tests/test_causal_analysis.py",
    "chars": 43060,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nimport unittest\n\nfrom contex"
  },
  {
    "path": "econml/tests/test_discrete_outcome.py",
    "chars": 10014,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\nimport pytest\nimport unittest"
  },
  {
    "path": "econml/tests/test_dml.py",
    "chars": 83060,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nimport unittest\nimport pytes"
  },
  {
    "path": "econml/tests/test_dmliv.py",
    "chars": 12627,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nimport pickle\nimport unittes"
  },
  {
    "path": "econml/tests/test_dominicks.py",
    "chars": 6013,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nimport os.path\nimport pandas"
  },
  {
    "path": "econml/tests/test_dowhy.py",
    "chars": 5378,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nimport numpy as np\nimport pa"
  },
  {
    "path": "econml/tests/test_driv.py",
    "chars": 18057,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nfrom econml.iv.dr import (DR"
  },
  {
    "path": "econml/tests/test_drlearner.py",
    "chars": 75606,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nfrom contextlib import ExitS"
  },
  {
    "path": "econml/tests/test_drtester.py",
    "chars": 10909,
    "preview": "import unittest\n\nimport numpy as np\nimport pandas as pd\nimport scipy.stats as st\nfrom sklearn.ensemble import RandomFore"
  },
  {
    "path": "econml/tests/test_dynamic_dml.py",
    "chars": 20106,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\nimport unittest\nimport pytest"
  },
  {
    "path": "econml/tests/test_federated_learning.py",
    "chars": 11971,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nimport numpy as np\nimport un"
  },
  {
    "path": "econml/tests/test_grf_cython.py",
    "chars": 16241,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nimport unittest\r\nimport n"
  },
  {
    "path": "econml/tests/test_grf_python.py",
    "chars": 40184,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nimport unittest\r\nimport n"
  },
  {
    "path": "econml/tests/test_inference.py",
    "chars": 23770,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nimport numpy as np\nimport pa"
  },
  {
    "path": "econml/tests/test_integration.py",
    "chars": 13734,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nfrom econml.utilities import"
  },
  {
    "path": "econml/tests/test_linear_model.py",
    "chars": 35533,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\n\"\"\"Tests for linear_model ex"
  },
  {
    "path": "econml/tests/test_metalearners.py",
    "chars": 8867,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nimport numpy as np\nimport un"
  },
  {
    "path": "econml/tests/test_missing_values.py",
    "chars": 15915,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\nimport unittest\nimport numpy "
  },
  {
    "path": "econml/tests/test_model_selection.py",
    "chars": 7574,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nimport unittest\nimport numpy"
  },
  {
    "path": "econml/tests/test_montecarlo.py",
    "chars": 5294,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\n\r\nimport unittest\r\nfrom s"
  },
  {
    "path": "econml/tests/test_notebooks.py",
    "chars": 1953,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nimport re\nimport pytest\nimpo"
  },
  {
    "path": "econml/tests/test_orf.py",
    "chars": 22891,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nimport numpy as np\nimport un"
  },
  {
    "path": "econml/tests/test_ortho_learner.py",
    "chars": 23584,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nfrom sklearn.datasets import"
  },
  {
    "path": "econml/tests/test_policy_forest.py",
    "chars": 23155,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nimport unittest\r\nimport n"
  },
  {
    "path": "econml/tests/test_random_state.py",
    "chars": 7110,
    "preview": "import unittest\r\nfrom sklearn.linear_model import LinearRegression\r\nfrom econml.dml import LinearDML, SparseLinearDML, K"
  },
  {
    "path": "econml/tests/test_refit.py",
    "chars": 14589,
    "preview": "import unittest\r\nimport pytest\r\nimport numpy as np\r\nfrom sklearn.linear_model import LinearRegression, LogisticRegressio"
  },
  {
    "path": "econml/tests/test_rscorer.py",
    "chars": 7270,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nimport unittest\r\nimport n"
  },
  {
    "path": "econml/tests/test_sensitivity_analysis.py",
    "chars": 4897,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nimport unittest\nimport pytes"
  },
  {
    "path": "econml/tests/test_shap.py",
    "chars": 11412,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nimport numpy as np\nimport un"
  },
  {
    "path": "econml/tests/test_statsmodels.py",
    "chars": 71221,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nimport unittest\n\nimport nump"
  },
  {
    "path": "econml/tests/test_treatment_featurization.py",
    "chars": 22711,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\nimport pytest\nimport unittest"
  },
  {
    "path": "econml/tests/test_tree.py",
    "chars": 15704,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nimport unittest\r\n\r\nimport"
  },
  {
    "path": "econml/tests/test_two_stage_least_squares.py",
    "chars": 7198,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\n\"\"\"Tests for two stage least"
  },
  {
    "path": "econml/tests/test_utilities.py",
    "chars": 8509,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nimport unittest\nimport time\n"
  },
  {
    "path": "econml/tests/utilities.py",
    "chars": 2556,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nimport numpy as np\nfrom skle"
  },
  {
    "path": "econml/tree/__init__.py",
    "chars": 521,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n\r\nfrom ._criterion import C"
  },
  {
    "path": "econml/tree/_criterion.pxd",
    "chars": 5190,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n#\r\n# This code is a fork fr"
  },
  {
    "path": "econml/tree/_criterion.pyx",
    "chars": 20594,
    "preview": "# cython: cdivision=True\r\n# cython: boundscheck=False\r\n# cython: wraparound=False\r\n\r\n# Copyright (c) PyWhy contributors."
  },
  {
    "path": "econml/tree/_splitter.pxd",
    "chars": 7129,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n#\r\n# This code is a fork fr"
  },
  {
    "path": "econml/tree/_splitter.pyx",
    "chars": 33916,
    "preview": "# cython: cdivision=True\r\n# cython: boundscheck=False\r\n# cython: wraparound=False\r\n\r\n# Copyright (c) PyWhy contributors."
  },
  {
    "path": "econml/tree/_tree.pxd",
    "chars": 6159,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n#\r\n# This code is a fork fr"
  },
  {
    "path": "econml/tree/_tree.pyx",
    "chars": 44672,
    "preview": "# cython: cdivision=True\r\n# cython: boundscheck=False\r\n# cython: wraparound=False\r\n\r\n# Copyright (c) PyWhy contributors."
  },
  {
    "path": "econml/tree/_tree_classes.py",
    "chars": 16093,
    "preview": "import numbers\r\nfrom math import ceil\r\nimport numpy as np\r\nfrom sklearn.base import BaseEstimator\r\nfrom sklearn.utils.va"
  },
  {
    "path": "econml/tree/_utils.pxd",
    "chars": 2838,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\r\n# Licensed under the MIT License.\r\n#\r\n# This code is a fork fr"
  },
  {
    "path": "econml/tree/_utils.pyx",
    "chars": 6046,
    "preview": "# cython: cdivision=True\r\n# cython: boundscheck=False\r\n# cython: wraparound=False\r\n\r\n# Copyright (c) PyWhy contributors."
  },
  {
    "path": "econml/utilities.py",
    "chars": 50035,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\n\"\"\"Utility methods.\"\"\"\n\nfrom"
  },
  {
    "path": "econml/validate/__init__.py",
    "chars": 432,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\n\"\"\"A suite of validation met"
  },
  {
    "path": "econml/validate/drtester.py",
    "chars": 26744,
    "preview": "from typing import Tuple, Union, List\n\nimport numpy as np\nimport pandas as pd\nimport scipy.stats as st\nfrom sklearn.mode"
  },
  {
    "path": "econml/validate/results.py",
    "chars": 9995,
    "preview": "import numpy as np\nimport pandas as pd\n\nfrom typing import List, Dict, Any\n\n\nclass CalibrationEvaluationResults:\n    \"\"\""
  },
  {
    "path": "econml/validate/sensitivity_analysis.py",
    "chars": 7986,
    "preview": "# Copyright (c) PyWhy contributors. All rights reserved.\n# Licensed under the MIT License.\n\nimport numpy as np\nfrom econ"
  },
  {
    "path": "econml/validate/utils.py",
    "chars": 5201,
    "preview": "from typing import Tuple\n\nimport numpy as np\nimport pandas as pd\n\n\ndef calculate_dr_outcomes(\n    D: np.array,\n    y: np"
  },
  {
    "path": "lkg-notebook.txt",
    "chars": 2584,
    "preview": "Cython==0.29.37\nJinja2==3.1.6\nMarkupSafe==3.0.2\nPyYAML==6.0.2\nPygments==2.19.2\nSend2Trash==1.8.3\nanyio==4.10.0\nargon2-cf"
  },
  {
    "path": "lkg.txt",
    "chars": 3015,
    "preview": "Cython==0.29.37\nJinja2==3.1.6\nMarkupSafe==3.0.2\nPyYAML==6.0.2; python_version<'3.13'\nargcomplete==3.6.2; platform_system"
  },
  {
    "path": "monte_carlo_tests/monte_carlo_honestforest.py",
    "chars": 1751,
    "preview": "import numpy as np\r\nimport matplotlib.pyplot as plt\r\nimport os\r\nimport time\r\nimport argparse\r\nimport warnings\r\nimport jo"
  },
  {
    "path": "monte_carlo_tests/monte_carlo_statsmodels.py",
    "chars": 27100,
    "preview": "import numpy as np\r\nfrom econml.dml import LinearDML\r\nfrom sklearn.linear_model import LinearRegression, MultiTaskLassoC"
  },
  {
    "path": "notebooks/AutomatedML/Automated Machine Learning For EconML.ipynb",
    "chars": 309110,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"Copyright (c) PyWhy contributors. A"
  },
  {
    "path": "notebooks/CATE validation.ipynb",
    "chars": 438193,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 1,\n   \"metadata\": {\n    \"collapsed\": false,\n    \"jupyter"
  },
  {
    "path": "notebooks/Causal Forest and Orthogonal Random Forest Examples.ipynb",
    "chars": 320385,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"<table border=\\\"0\\\">\\n\",\n    \"    <"
  },
  {
    "path": "notebooks/Causal Model Selection with the RScorer.ipynb",
    "chars": 298725,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"<table border=\\\"0\\\">\\n\",\n    \"    <"
  },
  {
    "path": "notebooks/Choosing First Stage Models.ipynb",
    "chars": 88296,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"<table border=\\\"0\\\">\\n\",\n    \"    <"
  },
  {
    "path": "notebooks/CustomerScenarios/Case Study - Customer Segmentation at An Online Media Company - EconML + DoWhy.ipynb",
    "chars": 385785,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"<img src=\\\"https://www.microsoft.co"
  },
  {
    "path": "notebooks/CustomerScenarios/Case Study - Customer Segmentation at An Online Media Company.ipynb",
    "chars": 237393,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"<img src=\\\"https://www.microsoft.co"
  },
  {
    "path": "notebooks/CustomerScenarios/Case Study - Long-Term Return-on-Investment via Short-Term Proxies.ipynb",
    "chars": 179805,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"# Long-Term Return-on-Investment vi"
  },
  {
    "path": "notebooks/CustomerScenarios/Case Study - Multi-investment Attribution at A Software Company - EconML + DoWhy.ipynb",
    "chars": 194295,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"<img src=\\\"https://www.microsoft.co"
  },
  {
    "path": "notebooks/CustomerScenarios/Case Study - Multi-investment Attribution at A Software Company.ipynb",
    "chars": 294461,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"<img src=\\\"https://www.microsoft.co"
  },
  {
    "path": "notebooks/CustomerScenarios/Case Study - Recommendation AB Testing at An Online Travel Company - EconML + DoWhy.ipynb",
    "chars": 307568,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {\n    \"slideshow\": {\n     \"slide_type\": \"slide\"\n    }\n   },"
  },
  {
    "path": "notebooks/CustomerScenarios/Case Study - Recommendation AB Testing at An Online Travel Company.ipynb",
    "chars": 203540,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {\n    \"slideshow\": {\n     \"slide_type\": \"slide\"\n    }\n   },"
  },
  {
    "path": "notebooks/CustomerScenarios/Case Study - Using EconML to evaluate the treatment effect of training program - Lalonde dataset.ipynb",
    "chars": 301790,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"<table border=\\\"0\\\">\\n\",\n    \"    <"
  },
  {
    "path": "notebooks/Double Machine Learning Examples.ipynb",
    "chars": 858653,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"<table border=\\\"0\\\">\\n\",\n    \"    <"
  },
  {
    "path": "notebooks/Doubly Robust Learner and Interpretability.ipynb",
    "chars": 285586,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"<table border=\\\"0\\\">\\n\",\n    \"    <"
  },
  {
    "path": "notebooks/Dynamic Double Machine Learning Examples.ipynb",
    "chars": 62469,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"<table border=\\\"0\\\">\\n\",\n    \"    <"
  },
  {
    "path": "notebooks/ForestLearners Basic Example.ipynb",
    "chars": 374253,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"<table border=\\\"0\\\">\\n\",\n    \"    <"
  },
  {
    "path": "notebooks/Generalized Random Forests.ipynb",
    "chars": 1306437,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"<table border=\\\"0\\\">\\n\",\n    \"    <"
  },
  {
    "path": "notebooks/Interpretability with SHAP.ipynb",
    "chars": 387752,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"<table border=\\\"0\\\">\\n\",\n    \"    <"
  },
  {
    "path": "notebooks/Metalearners Examples.ipynb",
    "chars": 104462,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"<table border=\\\"0\\\">\\n\",\n    \"    <"
  },
  {
    "path": "notebooks/OrthoIV and DRIV Examples.ipynb",
    "chars": 186418,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"<table border=\\\"0\\\">\\n\",\n    \"    <"
  },
  {
    "path": "notebooks/Policy Learning with Trees and Forests.ipynb",
    "chars": 313480,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 1,\n   \"id\": \"designed-drain\",\n   \"metadata\": {},\n   \"out"
  },
  {
    "path": "notebooks/Scaling EconML using Ray.ipynb",
    "chars": 66317,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"99b19cd3-a348-4194-9bd0-dd0830b5268c\",\n   \"metadata\": {},\n   \"so"
  },
  {
    "path": "notebooks/Solutions/Causal Interpretation for Ames Housing Price.ipynb",
    "chars": 464900,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {\n    \"tags\": []\n   },\n   \"source\": [\n    \"# Causal Interpr"
  },
  {
    "path": "notebooks/Solutions/Causal Interpretation for Employee Attrition Dataset.ipynb",
    "chars": 265006,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"# Causal Interpretation for Employe"
  },
  {
    "path": "notebooks/Treatment Featurization Examples.ipynb",
    "chars": 355448,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"9fd851ab-e30e-4586-95d1-9494d427f374\",\n   \"metadata\": {},\n   \"so"
  },
  {
    "path": "notebooks/Weighted Double Machine Learning Examples.ipynb",
    "chars": 193915,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"<table border=\\\"0\\\">\\n\",\n    \"    <"
  },
  {
    "path": "prototypes/dml_iv/NLSYM_GBM.ipynb",
    "chars": 217023,
    "preview": "{\n    \"cells\": [\n        {\n            \"cell_type\": \"code\",\n            \"execution_count\": 37,\n            \"metadata\": {"
  },
  {
    "path": "prototypes/dml_iv/NLSYM_Linear.ipynb",
    "chars": 417027,
    "preview": "{\n    \"cells\": [\n        {\n            \"cell_type\": \"code\",\n            \"execution_count\": 110,\n            \"metadata\": "
  }
]

// ... and 70 more files (download for full content)

About this extraction

This page contains the full source code of the py-why/EconML GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 270 files (53.0 MB), approximately 4.1M tokens, and a symbol index with 2220 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!