diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..1d20eb815 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,319 @@ +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 }} + 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: + - uses: actions/checkout@v3 + name: Checkout repository + 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 + - 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 + name: Determine type of code change + 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: + - uses: actions/checkout@v3 + name: Checkout repository + with: + ref: ${{ env.ref }} + - uses: actions/setup-python@v4 + name: Setup Python + with: + python-version: '3.9' + - run: python -m pip install --upgrade pip && pip install --upgrade setuptools + name: Ensure latest pip and setuptools + - run: 'pip install pycodestyle && pycodestyle econml' + + 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: "[tf,plt]" + pattern: "(?!CustomerScenarios)" + install_graphviz: true + version: '3.8' # no supported version of tensorflow for 3.9 + - kind: "customer-scenarios" + extras: "[plt,dowhy]" + pattern: "CustomerScenarios" + version: '3.9' + install_graphviz: false + fail-fast: false + steps: + - uses: actions/checkout@v3 + name: Checkout repository + with: + ref: ${{ env.ref }} + - uses: actions/setup-python@v4 + name: Setup Python + with: + python-version: ${{ matrix.version }} + - run: python -m pip install --upgrade pip && pip install --upgrade setuptools + name: Ensure latest pip and setuptools + - run: sudo apt-get -yq install graphviz + name: Install graphviz + if: ${{ matrix.install_graphviz }} + # Add verbose flag to pip installation if in debug mode + - run: pip install -e .${{ matrix.extras }} ${{ fromJSON('["","-v"]')[runner.debug] }} ${{ env.use_lkg && '-r lkg-notebook.txt' }} + name: Install econml + # Install notebook requirements (if not already done as part of lkg) + - run: pip install jupyter jupyter-client nbconvert nbformat seaborn xgboost tqdm + name: Install notebook requirements + if: ${{ !env.use_lkg }} + - run: pip freeze --exclude-editable > notebooks-${{ matrix.version }}-${{ matrix.kind }}-requirements.txt + name: Save installed packages + - uses: actions/upload-artifact@v3 + name: Upload installed packages + with: + name: requirements + path: notebooks-${{ matrix.version }}-${{ matrix.kind }}-requirements.txt + - run: pip install pytest pytest-runner coverage + name: Install pytest + + - run: python setup.py pytest + name: Run notebook tests + id: run_tests + env: + PYTEST_ADDOPTS: '-m "notebook"' + NOTEBOOK_DIR_PATTERN: ${{ matrix.pattern }} + COVERAGE_PROCESS_START: 'setup.cfg' + - run: mv .coverage .coverage.${{ matrix.kind }} + # 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: Make coverage filename unique + - uses: actions/upload-artifact@v3 + name: Upload coverage report + if: success() || failure() && contains(fromJSON('["success", "failure"]'), steps.run_tests.outcome) + with: + name: coverage + path: .coverage.${{ matrix.kind }} + + tests: + name: "Run tests" + needs: [eval] + if: ${{ needs.eval.outputs.testCode == 'True' }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + python-version: ['3.7', '3.8', '3.9', '3.10'] + kind: [serial, other, dml, main, treatment] + exclude: + # Serial tests fail randomly on mac sometimes, so we don't run them there + - os: macos-latest + kind: serial + # Python 3.7 is broken on the mac runner image, see https://github.com/actions/runner-images/issues/7764 + - os: macos-latest + python-version: '3.7' + # Assign the correct package and testing options for each kind of test + include: + - kind: serial + opts: '-m "serial" -n 1' + extras: "[tf,plt]" + - kind: other + opts: '-m "cate_api" -n auto' + extras: "[tf,plt]" + - kind: dml + opts: '-m "dml"' + extras: "[tf,plt]" + - kind: main + opts: '-m "not (notebook or automl or dml or serial or cate_api or treatment_featurization)" -n 2' + extras: "[tf,plt,dowhy]" + - kind: treatment + opts: '-m "treatment_featurization" -n auto' + extras: "[tf,plt]" + fail-fast: false + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + name: Checkout repository + with: + ref: ${{ env.ref }} + - uses: actions/setup-python@v4 + name: Setup Python + with: + python-version: ${{ matrix.python-version }} + - run: python -m pip install --upgrade pip && pip install --upgrade setuptools + name: Ensure latest pip and setuptools + # Add verbose flag to pip installation if in debug mode + - run: pip install -e .${{ matrix.extras }} ${{ fromJSON('["","-v"]')[runner.debug] }} ${{ env.use_lkg && '-r lkg.txt' }} + name: Install econml + - run: pip freeze --exclude-editable > tests-${{ matrix.os }}-${{ matrix.python-version }}-${{ matrix.kind }}-requirements.txt + name: Save installed packages + - uses: actions/upload-artifact@v3 + name: Upload installed packages + with: + name: requirements + path: tests-${{ matrix.os }}-${{ matrix.python-version }}-${{ matrix.kind }}-requirements.txt + - run: pip install pytest pytest-runner coverage + name: Install pytest + - run: python setup.py pytest + name: Run tests + id: run_tests + env: + PYTEST_ADDOPTS: ${{ matrix.opts }} + COVERAGE_PROCESS_START: 'setup.cfg' + - run: mv .coverage .coverage.${{ matrix.os }}-${{ matrix.python-version }}-${{ matrix.kind }} + # 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: Make coverage filename unique + - uses: actions/upload-artifact@v3 + name: Upload coverage report + if: success() || failure() && contains(fromJSON('["success", "failure"]'), steps.run_tests.outcome) + with: + name: coverage + path: .coverage.${{ matrix.os }}-${{ matrix.python-version }}-${{ matrix.kind }} + + coverage-report: + name: "Coverage report" + needs: [tests, notebooks] + if: success() || failure() + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + name: Checkout repository + with: + ref: ${{ env.ref }} + - uses: actions/download-artifact@v3 + name: Get coverage reports + with: + name: coverage + path: coverage + - uses: actions/setup-python@v4 + name: Setup Python + with: + python-version: '3.8' + - run: pip install coverage + name: Install coverage + - run: coverage combine coverage/ + name: Combine coverage reports + - run: coverage report -m --format=markdown > $GITHUB_STEP_SUMMARY + name: Generate coverage report + - run: coverage html + name: Generate coverage html --fail-under=86 + - uses: actions/upload-artifact@v3 + name: Upload coverage report + with: + name: coverage + path: htmlcov + + build: + name: Build package + needs: [eval] + if: ${{ needs.eval.outputs.testCode == 'True' }} + uses: ./.github/workflows/publish-package.yml + with: + publish: false + repository: testpypi + # don't have access to env context here for some reason + ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || null }} + 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 }} + 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: + - run: exit 1 + name: At least one check failed or was cancelled + if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }} + - run: exit 0 + name: All checks passed + if: ${{ !(contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')) }} diff --git a/.github/workflows/publish-documentation.yml b/.github/workflows/publish-documentation.yml new file mode 100644 index 000000000..c7efad85f --- /dev/null +++ b/.github/workflows/publish-documentation.yml @@ -0,0 +1,93 @@ +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 + # 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 + +jobs: + create_docs: + name: Create and publish documentation + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + name: Checkout repository + with: + ref: ${{ inputs.ref }} + - uses: actions/setup-python@v4 + name: Setup Python + with: + python-version: 3.8 # because of our supported TensorFlow versions, must build on 3.6-3.8 + - run: python -m pip install --upgrade pip && pip install --upgrade setuptools + name: Ensure latest pip and setuptools + - run: pip install -e .[all] ${{ inputs.use_lkg && '-r lkg.txt' }} + name: Install econml[all] + - run: sudo apt-get -yq install graphviz + name: Install graphviz + - run: pip install "sphinx~=4.4.0" "sphinx_rtd_theme~=1.0.0" && python setup.py build_sphinx -W + name: Build documentation + - uses: actions/upload-artifact@v3 + name: Upload docs as artifact + with: + name: docs + path: build/sphinx/html/ + - run: |- + pushd build/sphinx/html + zip -r docs.zip * + popd + name: Zip docs for publishing + if : ${{ inputs.publish }} + - uses: azure/login@v1 + name: Login to Azure + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + if : ${{ inputs.publish }} + - uses: azure/webapps-deploy@v2 + name: Deploy documentation to Azure web app + with: + app-name: ${{ inputs.environment == 'prod' && 'econml' || 'econml-dev' }} + package: build/sphinx/html/docs.zip + if: ${{ inputs.publish }} \ No newline at end of file diff --git a/.github/workflows/publish-package.yml b/.github/workflows/publish-package.yml new file mode 100644 index 000000000..65db3c813 --- /dev/null +++ b/.github/workflows/publish-package.yml @@ -0,0 +1,127 @@ +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 + repository: + description: 'Whether to publish to production PyPI or test PyPI' + required: false + default: pypi + type: choice + options: [pypi, testpypi] + 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 + repository: + description: 'Whether to publish to production PyPI or test PyPI' + required: false + default: pypi + 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] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + name: Checkout repository + with: + ref: ${{ inputs.ref }} + - uses: actions/setup-python@v4 + name: Setup Python + with: + python-version: 3.9 + - run: python -m pip install --upgrade pip && pip install --upgrade setuptools + name: Ensure latest pip and setuptools + - run: pip install cibuildwheel && python -m cibuildwheel --output-dir dist + name: Build wheels + env: + CIBW_BUILD: cp3{7,8,9,10}-* + CIBW_SKIP: "*musl* *win32 *i686" + - uses: actions/upload-artifact@v3 + name: Upload wheels as artifact + with: + name: dist + path: dist/ + build_sdist: + name: Build sdist + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + name: Checkout repository + with: + ref: ${{ inputs.ref }} + - uses: actions/setup-python@v4 + name: Setup Python + with: + python-version: 3.8 # because of our supported TensorFlow versions, must build on 3.6-3.8 + - run: python -m pip install --upgrade pip && pip install --upgrade setuptools + name: Ensure latest pip and setuptools + - run: pip install -e .[all] ${{ inputs.use_lkg && '-r lkg.txt' }} + name: Install econml[all] + - run: python setup.py sdist + name: Build sdist + - uses: actions/upload-artifact@v3 + name: Upload sdist as artifact + with: + name: dist + path: dist/ + publish: + name: Publish to PyPI or TestPyPI + needs: [build_wheels, build_sdist] + runs-on: ubuntu-latest + steps: + - uses: actions/setup-python@v4 + name: Setup Python + with: + python-version: 3.9 + - run: python -m pip install --upgrade pip && pip install --upgrade setuptools + name: Ensure latest pip and setuptools + - run: pip install twine + name: Install twine + - uses: actions/download-artifact@v3 + name: Download wheels and sdist + with: + name: dist + path: dist/ + - run: twine upload dist/* + name: Upload wheels and sdist to package index + env: + TWINE_USERNAME: __token__ + TWINE_REPOSITORY: ${{ inputs.repository }} + TWINE_PASSWORD: ${{ inputs.repository == 'pypi' && secrets.PYPI_UPLOAD_TOKEN || secrets.TEST_PYPI_UPLOAD_TOKEN }} + if: ${{ inputs.publish }} \ No newline at end of file diff --git a/LICENSE b/LICENSE index 8a3dfbf66..f55033a55 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License - Copyright (c) Microsoft Corporation. All rights reserved. + 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 diff --git a/README.md b/README.md index 134c30122..70d16eb19 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,15 @@ -[![Build Status](https://dev.azure.com/ms/EconML/_apis/build/status/Microsoft.EconML?branchName=main)](https://dev.azure.com/ms/EconML/_build/latest?definitionId=49&branchName=main) +[![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/) -

EconML: A Python Package for ML-Based Heterogeneous Treatment Effects Estimation

+

+ +econml-logo + EconML: A Python Package for ML-Based Heterogeneous Treatment Effects Estimation +

**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: @@ -40,69 +44,72 @@ For information on use cases and background material on causal inference and het - [Blogs and Publications](#blogs-and-publications) - [Citation](#citation) - [Contributing and Feedback](#contributing-and-feedback) +- [Community](#community) - [References](#references) # News -**November 16, 2022:** Release v0.14.0, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.14.0) +**May 19, 2023:** Release v0.14.1, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.14.1)
Previous releases -**June 17, 2022:** Release v0.13.1, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.13.1) +**November 16, 2022:** Release v0.14.0, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.14.0) -**January 31, 2022:** Release v0.13.0, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.13.0) +**June 17, 2022:** Release v0.13.1, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.13.1) -**August 13, 2021:** Release v0.12.0, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.12.0) +**January 31, 2022:** Release v0.13.0, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.13.0) -**August 5, 2021:** Release v0.12.0b6, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.12.0b6) +**August 13, 2021:** Release v0.12.0, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.12.0) -**August 3, 2021:** Release v0.12.0b5, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.12.0b5) +**August 5, 2021:** Release v0.12.0b6, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.12.0b6) -**July 9, 2021:** Release v0.12.0b4, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.12.0b4) +**August 3, 2021:** Release v0.12.0b5, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.12.0b5) -**June 25, 2021:** Release v0.12.0b3, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.12.0b3) +**July 9, 2021:** Release v0.12.0b4, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.12.0b4) -**June 18, 2021:** Release v0.12.0b2, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.12.0b2) +**June 25, 2021:** Release v0.12.0b3, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.12.0b3) -**June 7, 2021:** Release v0.12.0b1, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.12.0b1) +**June 18, 2021:** Release v0.12.0b2, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.12.0b2) -**May 18, 2021:** Release v0.11.1, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.11.1) +**June 7, 2021:** Release v0.12.0b1, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.12.0b1) -**May 8, 2021:** Release v0.11.0, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.11.0) +**May 18, 2021:** Release v0.11.1, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.11.1) -**March 22, 2021:** Release v0.10.0, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.10.0) +**May 8, 2021:** Release v0.11.0, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.11.0) -**March 11, 2021:** Release v0.9.2, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.9.2) +**March 22, 2021:** Release v0.10.0, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.10.0) -**March 3, 2021:** Release v0.9.1, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.9.1) +**March 11, 2021:** Release v0.9.2, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.9.2) -**February 20, 2021:** Release v0.9.0, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.9.0) +**March 3, 2021:** Release v0.9.1, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.9.1) -**January 20, 2021:** Release v0.9.0b1, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.9.0b1) +**February 20, 2021:** Release v0.9.0, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.9.0) -**November 20, 2020:** Release v0.8.1, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.8.1) +**January 20, 2021:** Release v0.9.0b1, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.9.0b1) -**November 18, 2020:** Release v0.8.0, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.8.0) +**November 20, 2020:** Release v0.8.1, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.8.1) -**September 4, 2020:** Release v0.8.0b1, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.8.0b1) +**November 18, 2020:** Release v0.8.0, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.8.0) -**March 6, 2020:** Release v0.7.0, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.7.0) +**September 4, 2020:** Release v0.8.0b1, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.8.0b1) -**February 18, 2020:** Release v0.7.0b1, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.7.0b1) +**March 6, 2020:** Release v0.7.0, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.7.0) -**January 10, 2020:** Release v0.6.1, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.6.1) +**February 18, 2020:** Release v0.7.0b1, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.7.0b1) -**December 6, 2019:** Release v0.6, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.6) +**January 10, 2020:** Release v0.6.1, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.6.1) -**November 21, 2019:** Release v0.5, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.5). +**December 6, 2019:** Release v0.6, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.6) -**June 3, 2019:** Release v0.4, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.4). +**November 21, 2019:** Release v0.5, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.5). -**May 3, 2019:** Release v0.3, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.3). +**June 3, 2019:** Release v0.4, see release notes [here](https://github.com/py-why/EconML/releases/tag/v0.4). -**April 10, 2019:** Release v0.2, see release notes [here](https://github.com/Microsoft/EconML/releases/tag/v0.2). +**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. @@ -645,7 +652,7 @@ importances = policy.feature_importances_ ![image](images/policy_tree.png)
-To see more complex examples, go to the [notebooks](https://github.com/Microsoft/EconML/tree/main/notebooks) section of the repository. For a more detailed description of the treatment effect estimation algorithms, see the EconML [documentation](https://econml.azurewebsites.net/). +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://econml.azurewebsites.net/). # For Developers @@ -667,7 +674,16 @@ This project's documentation is generated via [Sphinx](https://www.sphinx-doc.or 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/Microsoft/EconML/tree/main/doc); module documentation is automatically generated by the Sphinx build process. +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 @@ -683,7 +699,7 @@ The reStructuredText files that make up the documentation are stored in the [doc 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/microsoft/EconML, 2019. Version 0.x. + 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: @@ -691,7 +707,7 @@ 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/microsoft/EconML}, + howpublished={https://github.com/py-why/EconML}, note={Version 0.x}, year={2019} } @@ -699,17 +715,25 @@ BibTex: # Contributing and Feedback -This project welcomes contributions and suggestions. Most contributions require you to agree to a -Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us -the rights to use your contribution. For details, visit https://cla.microsoft.com. +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`. When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). -For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or -contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. +This project has adopted the [PyWhy Code of Conduct](https://github.com/py-why/governance/blob/main/CODE-OF-CONDUCT.md). + +# Community + + +pywhy-logo + + +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 diff --git a/azure-pipelines-steps.yml b/azure-pipelines-steps.yml deleted file mode 100644 index 12f88fa69..000000000 --- a/azure-pipelines-steps.yml +++ /dev/null @@ -1,65 +0,0 @@ -# Python package -# Create and test a Python package on multiple Python versions. -# Add steps that analyze code, save the dist with the build record, publish to a PyPI-compatible index, and more: -# https://docs.microsoft.com/azure/devops/pipelines/languages/python - -parameters: - package: '-e .' - images: ['ubuntu-20.04', 'macOS-12', 'windows-2019'] - versions: ['3.7', '3.8', '3.9', '3.10'] - job: - job: Job - -jobs: -- job: ${{ parameters.job.job }} - variables: - ${{ if ge(length(parameters.images), 2) }}: - imgPart: ", {0}" - ${{ if lt(length(parameters.images), 2) }}: - imgPart: "" - ${{ if ge(length(parameters.versions), 2) }}: - verPart: ", Python {1}" - ${{ if lt(length(parameters.versions), 2) }}: - verPart: "" - - strategy: - matrix: - ${{ each image in parameters.images }}: - ${{ each version in parameters.versions }}: - ${{ format(format('{0}{1} ', variables.imgPart, variables.verPart), image, version) }}: - imageName: ${{ image }} - python.version: ${{ version }} - - pool: - vmImage: $(imageName) - - ${{ each pair in parameters.job }}: # Insert all properties other than "strategy", "pool", "steps", "variables", "job" - ${{ if notIn(pair.key, 'strategy', 'pool', 'steps', 'variables', 'job') }}: - ${{ pair.key }}: ${{ pair.value }} - - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python $(python.version)' - inputs: - versionSpec: '$(python.version)' - - # Enable long path support on Windows so that all packages can be installed correctly - - script: 'reg add HKLM\SYSTEM\CurrentControlSet\Control\FileSystem /v LongPathsEnabled /t REG_DWORD /d 1 /f' - displayName: 'Enable long paths on Windows' - condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) - - # Install graphviz programmatically on Linux - - script: 'sudo apt-get -yq install graphviz' - displayName: 'Install graphviz on Linux' - condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux')) - - # Install OpenMP on Mac to support lightgbm - - script: 'brew install libomp' - displayName: 'Install OpenMP on Mac' - condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin')) - - # Install the package - - script: 'python -m pip install --upgrade pip && pip install --upgrade setuptools wheel Cython && pip install ${{ parameters.package }} && pip freeze --exclude-editable' - displayName: 'Install dependencies' - - - ${{ parameters.job.steps }} diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index 772c405d0..000000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,333 +0,0 @@ -# Python package -# Create and test a Python package on multiple Python versions. -# Add steps that analyze code, save the dist with the build record, publish to a PyPI-compatible index, and more: -# https://docs.microsoft.com/azure/devops/pipelines/languages/python - -trigger: -- main - -jobs: -- job: 'EvalChanges' - displayName: 'Analyze changed files to determine which job to run' - pool: - vmImage: 'macos-12' - steps: - # 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) - - powershell: | - if ($env:BUILD_REASON -eq 'PullRequest') { - $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 } - } - } - } - Write-Host "##vso[task.setvariable variable=buildDocs;isOutput=true]$(($env:BUILD_REASON -ne 'PullRequest') -or ($docChanges -or $codeChanges))" - Write-Host "##vso[task.setvariable variable=buildNbs;isOutput=true]$(($env:BUILD_REASON -ne 'PullRequest') -or ($nbChanges -or $codeChanges))" - Write-Host "##vso[task.setvariable variable=testCode;isOutput=true]$(($env:BUILD_REASON -ne 'PullRequest') -or $codeChanges)" - name: output - displayName: 'Determine type of code change' - -- template: azure-pipelines-steps.yml - parameters: - versions: ['3.8'] - images: ['ubuntu-20.04'] - package: '-e .[all]' - job: - job: 'Docs' - displayName: 'Build documentation' - dependsOn: 'EvalChanges' - condition: eq(dependencies.EvalChanges.outputs['output.buildDocs'], 'True') - steps: - - script: 'sudo apt-get -yq install graphviz' - displayName: 'Install graphviz' - - - script: 'pip install sklearn-contrib-lightning' - displayName: 'Install lightning' - - - script: 'pip install git+https://github.com/slundberg/shap.git@d1d2700acc0259f211934373826d5ff71ad514de' - displayName: 'Install specific version of shap' - - - script: 'pip install sphinx!=5.1.0 sphinx_rtd_theme' - displayName: 'Install sphinx' - - - script: 'python setup.py build_sphinx -W' - displayName: 'Build documentation' - - - publish: 'build/sphinx/html' - condition: 'succeededOrFailed()' - artifact: 'Documentation' - displayName: 'Publish documentation as artifact' - - - script: 'python setup.py build_sphinx -b doctest' - displayName: 'Run doctests' - - -- template: azure-pipelines-steps.yml - parameters: - versions: ['3.8'] - images: ['ubuntu-20.04'] - package: '-e .[tf,plt,dowhy]' - job: - job: 'Notebooks_cust' - dependsOn: 'EvalChanges' - condition: eq(dependencies.EvalChanges.outputs['output.buildNbs'], 'True') - displayName: 'Notebooks (Customer Solutions)' - steps: - # Work around https://github.com/pypa/pip/issues/9542 - - script: 'pip install -U numpy~=1.21.0' - displayName: 'Upgrade numpy' - - - script: 'pip install pytest pytest-runner jupyter jupyter-client nbconvert nbformat seaborn xgboost tqdm py && pip list && python setup.py pytest' - displayName: 'Unit tests' - env: - PYTEST_ADDOPTS: '-m "notebook"' - NOTEBOOK_DIR_PATTERN: 'CustomerScenarios' - - - task: PublishTestResults@2 - displayName: 'Publish Test Results **/test-results.xml' - inputs: - testResultsFiles: '**/test-results.xml' - testRunTitle: 'Notebooks' - condition: succeededOrFailed() - -- template: azure-pipelines-steps.yml - parameters: - versions: ['3.8'] - images: ['ubuntu-20.04'] - package: '-e .[tf,plt]' - job: - job: 'Notebooks_noncust' - dependsOn: 'EvalChanges' - condition: eq(dependencies.EvalChanges.outputs['output.buildNbs'], 'True') - displayName: 'Notebooks (except Customer Solutions)' - steps: - # Work around https://github.com/pypa/pip/issues/9542 - - script: 'pip install -U numpy~=1.21.0' - displayName: 'Upgrade numpy' - - - script: 'pip install pytest pytest-runner jupyter jupyter-client nbconvert nbformat seaborn xgboost tqdm py && python setup.py pytest' - displayName: 'Unit tests' - env: - PYTEST_ADDOPTS: '-m "notebook"' - NOTEBOOK_DIR_PATTERN: '(?!CustomerScenarios)' - - - task: PublishTestResults@2 - displayName: 'Publish Test Results **/test-results.xml' - inputs: - testResultsFiles: '**/test-results.xml' - testRunTitle: 'Notebooks' - condition: succeededOrFailed() - - -# - job: 'AutoML' -# dependsOn: 'EvalChanges' -# condition: eq(dependencies.EvalChanges.outputs['output.testCode'], 'True') -# variables: -# python.version: '3.6' -# pool: -# vmImage: 'ubuntu-20.04' -# steps: -# - template: azure-pipelines-steps.yml -# parameters: -# body: -# - task: AzureCLI@2 -# displayName: 'AutoML tests' -# inputs: -# azureSubscription: 'automl' -# scriptLocation: 'inlineScript' -# scriptType: 'pscore' -# powerShellIgnoreLASTEXITCODE: '' # string for now due to https://github.com/microsoft/azure-pipelines-tasks/issues/12266 -# inlineScript: | -# $env:SUBSCRIPTION_ID = az account show --query id -o tsv -# python setup.py pytest -# env: -# WORKSPACE_NAME: 'testWorkspace' -# RESOURCE_GROUP: 'testingAutoMLEconML' -# PYTEST_ADDOPTS: '-m "automl" -n 0' -# COVERAGE_PROCESS_START: 'setup.cfg' - -# - task: PublishTestResults@2 -# displayName: 'Publish Test Results **/test-results.xml' -# inputs: -# testResultsFiles: '**/test-results.xml' -# testRunTitle: 'AutoML' -# condition: succeededOrFailed() -# package: '.[automl]' - -- template: azure-pipelines-steps.yml - parameters: - versions: ['3.8'] - images: ['macos-12'] - job: - job: 'Linting' - dependsOn: 'EvalChanges' - condition: eq(dependencies.EvalChanges.outputs['output.testCode'], 'True') - steps: - - script: 'pip install pycodestyle && pycodestyle econml' - failOnStderr: true - displayName: Linting - -- template: azure-pipelines-steps.yml - parameters: - package: '-e .[tf,plt,dowhy]' - job: - job: Tests_main - dependsOn: 'EvalChanges' - condition: eq(dependencies.EvalChanges.outputs['output.testCode'], 'True') - displayName: 'Run tests (main)' - steps: - - script: 'pip install pytest pytest-runner "coverage<6.4.1;python_version==''3.6''" "coverage;python_version>''3.6''" py && python setup.py pytest' - displayName: 'Unit tests' - env: - PYTEST_ADDOPTS: '-m "not (notebook or automl or dml or serial or cate_api or treatment_featurization)" -n 2' - COVERAGE_PROCESS_START: 'setup.cfg' - - task: PublishTestResults@2 - displayName: 'Publish Test Results **/test-results.xml' - inputs: - testResultsFiles: '**/test-results.xml' - testRunTitle: 'Python $(python.version), image $(imageName)' - condition: succeededOrFailed() - - - task: PublishCodeCoverageResults@1 - displayName: 'Publish Code Coverage Results' - inputs: - codeCoverageTool: Cobertura - summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/coverage.xml' - -- template: azure-pipelines-steps.yml - parameters: - package: '-e .[tf,plt]' - job: - job: Tests_dml - dependsOn: 'EvalChanges' - condition: eq(dependencies.EvalChanges.outputs['output.testCode'], 'True') - displayName: 'Run tests (DML)' - steps: - - script: 'pip install pytest pytest-runner "coverage<6.4.1;python_version==''3.6''" "coverage;python_version>''3.6''" py && python setup.py pytest' - displayName: 'Unit tests' - env: - PYTEST_ADDOPTS: '-m "dml"' - COVERAGE_PROCESS_START: 'setup.cfg' - - task: PublishTestResults@2 - displayName: 'Publish Test Results **/test-results.xml' - inputs: - testResultsFiles: '**/test-results.xml' - testRunTitle: 'Python $(python.version), image $(imageName)' - condition: succeededOrFailed() - - - task: PublishCodeCoverageResults@1 - displayName: 'Publish Code Coverage Results' - inputs: - codeCoverageTool: Cobertura - summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/coverage.xml' - -- template: azure-pipelines-steps.yml - parameters: - # exclude macOS since these tests frequently break there - images: ['ubuntu-20.04', 'windows-2019'] - package: '-e .[tf,plt]' - job: - job: Tests_serial - dependsOn: 'EvalChanges' - condition: eq(dependencies.EvalChanges.outputs['output.testCode'], 'True') - displayName: 'Run tests (Serial)' - steps: - - script: 'pip install pytest pytest-runner "coverage<6.4.1;python_version==''3.6''" "coverage;python_version>''3.6''" py && python setup.py pytest' - displayName: 'Unit tests' - env: - PYTEST_ADDOPTS: '-m "serial" -n 1' - COVERAGE_PROCESS_START: 'setup.cfg' - - task: PublishTestResults@2 - displayName: 'Publish Test Results **/test-results.xml' - inputs: - testResultsFiles: '**/test-results.xml' - testRunTitle: 'Python $(python.version), image $(imageName)' - condition: succeededOrFailed() - - - task: PublishCodeCoverageResults@1 - displayName: 'Publish Code Coverage Results' - inputs: - codeCoverageTool: Cobertura - summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/coverage.xml' - -- template: azure-pipelines-steps.yml - parameters: - package: '-e .[tf,plt]' - job: - job: Tests_CATE_API - dependsOn: 'EvalChanges' - condition: eq(dependencies.EvalChanges.outputs['output.testCode'], 'True') - displayName: 'Run tests (Other)' - steps: - - script: 'pip install pytest pytest-runner "coverage<6.4.1;python_version==''3.6''" "coverage;python_version>''3.6''" py' - displayName: 'Install pytest' - - script: 'python setup.py pytest' - displayName: 'CATE Unit tests' - env: - PYTEST_ADDOPTS: '-m "cate_api" -n auto' - COVERAGE_PROCESS_START: 'setup.cfg' - - task: PublishTestResults@2 - displayName: 'Publish Test Results **/test-results.xml' - inputs: - testResultsFiles: '**/test-results.xml' - testRunTitle: 'Python $(python.version), image $(imageName)' - condition: succeededOrFailed() - - - task: PublishCodeCoverageResults@1 - displayName: 'Publish Code Coverage Results' - inputs: - codeCoverageTool: Cobertura - summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/coverage.xml' - -- template: azure-pipelines-steps.yml - parameters: - package: '-e .[tf,plt]' - job: - job: Tests_treatment_featurization - dependsOn: 'EvalChanges' - condition: eq(dependencies.EvalChanges.outputs['output.testCode'], 'True') - displayName: 'Run tests (Treatment Featurization)' - steps: - - script: 'pip install pytest pytest-runner "coverage<6.4.1;python_version==''3.6''" "coverage;python_version>''3.6''" py' - displayName: 'Install pytest' - - script: 'python setup.py pytest' - displayName: 'Treatment Featurization Unit tests' - env: - PYTEST_ADDOPTS: '-m "treatment_featurization" -n auto' - COVERAGE_PROCESS_START: 'setup.cfg' - - task: PublishTestResults@2 - displayName: 'Publish Test Results **/test-results.xml' - inputs: - testResultsFiles: '**/test-results.xml' - testRunTitle: 'Python $(python.version), image $(imageName)' - condition: succeededOrFailed() - - - task: PublishCodeCoverageResults@1 - displayName: 'Publish Code Coverage Results' - inputs: - codeCoverageTool: Cobertura - summaryFileLocation: '$(System.DefaultWorkingDirectory)/**/coverage.xml' \ No newline at end of file diff --git a/doc/conf.py b/doc/conf.py index 411db502f..353aac7ae 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -21,8 +21,8 @@ # -- Project information ----------------------------------------------------- project = 'econml' -copyright = '2022, Microsoft Research' -author = 'Microsoft Research' +copyright = '2023, PyWhy contributors' +author = 'PyWhy contributors' version = econml.__version__ release = econml.__version__ @@ -176,7 +176,7 @@ # author, documentclass [howto, manual, or own class]). latex_documents = [ (root_doc, 'econml.tex', 'econml Documentation', - 'Microsoft Research', 'manual'), + 'PyWhy contributors', 'manual'), ] diff --git a/doc/spec/community.rst b/doc/spec/community.rst new file mode 100644 index 000000000..2302bfd10 --- /dev/null +++ b/doc/spec/community.rst @@ -0,0 +1,15 @@ +Community +========== + +.. raw:: html + +

+ + pywhy-logo + + +EconML is a part of `PyWhy `__, an organization with a mission to build an open-source ecosystem for causal machine learning. + +PyWhy also has a `Discord `__, 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. \ No newline at end of file diff --git a/doc/spec/estimation/dml.rst b/doc/spec/estimation/dml.rst index 4aac2f1e6..416a26c85 100644 --- a/doc/spec/estimation/dml.rst +++ b/doc/spec/estimation/dml.rst @@ -607,8 +607,8 @@ Usage Examples ================================== For more extensive examples check out the following notebooks: -`DML Examples Jupyter Notebook `_, -`Forest Learners Jupyter Notebook `_. +`DML Examples Jupyter Notebook `_, +`Forest Learners Jupyter Notebook `_. .. rubric:: Single Outcome, Single Treatment diff --git a/doc/spec/estimation/dr.rst b/doc/spec/estimation/dr.rst index 2849e83c4..663c568a4 100644 --- a/doc/spec/estimation/dr.rst +++ b/doc/spec/estimation/dr.rst @@ -366,7 +366,7 @@ Usage FAQs 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 `_ + `Forest Learners Jupyter notebook `_ for such an example). Also the check out the :ref:`Orthogonal Random Forest User Guide ` or the :ref:`Meta Learners User Guide `. @@ -516,7 +516,7 @@ Usage Examples Check out the following Jupyter notebooks: -* `Meta Learners Jupyter Notebook `_ -* `Forest Learners Jupyter Notebook `_ +* `Meta Learners Jupyter Notebook `_ +* `Forest Learners Jupyter Notebook `_ diff --git a/doc/spec/estimation/forest.rst b/doc/spec/estimation/forest.rst index cac213909..3a8db34ae 100644 --- a/doc/spec/estimation/forest.rst +++ b/doc/spec/estimation/forest.rst @@ -315,8 +315,8 @@ Usage Examples Here is a simple example of how to call :class:`.DMLOrthoForest` and what the returned values correspond to in a simple data generating process. For more examples check out our -`OrthoForest Jupyter notebook `_ -and the `ForestLearners Jupyter notebook `_ . +`OrthoForest Jupyter notebook `_ +and the `ForestLearners Jupyter notebook `_ . .. testcode:: diff --git a/doc/spec/estimation/metalearners.rst b/doc/spec/estimation/metalearners.rst index 2bd83cd85..ddf42acc5 100644 --- a/doc/spec/estimation/metalearners.rst +++ b/doc/spec/estimation/metalearners.rst @@ -17,7 +17,7 @@ These methods fall into the meta-learner category because they simply combine ML so as to get a final stage estimate and do not introduce new estimation components. For examples of how to use our implemented metelearners check out this -`Metalearners Jupyter notebook `_. The examples +`Metalearners Jupyter notebook `_. The examples and documents here are only based on binary treatment setting, but all of these estimators are applicable to multiple treatment settings as well. @@ -146,9 +146,9 @@ Usage Examples Check out the following notebooks: - * `Metalearners Jupyter notebook `_. - * `DML Examples Jupyter Notebook `_, - * `Forest Learners Jupyter Notebook `_. + * `Metalearners Jupyter notebook `_. + * `DML Examples Jupyter Notebook `_, + * `Forest Learners Jupyter Notebook `_. .. todo:: diff --git a/doc/spec/estimation/orthoiv.rst b/doc/spec/estimation/orthoiv.rst index 3ceed068f..d01ebe932 100644 --- a/doc/spec/estimation/orthoiv.rst +++ b/doc/spec/estimation/orthoiv.rst @@ -77,4 +77,4 @@ Usage Examples ================================== For more extensive examples check out the following notebooks: -`OrthoIV and DRIV Examples Jupyter Notebook `_. \ No newline at end of file +`OrthoIV and DRIV Examples Jupyter Notebook `_. \ No newline at end of file diff --git a/doc/spec/faq.rst b/doc/spec/faq.rst index 7e8b7ab41..e6d63dff3 100644 --- a/doc/spec/faq.rst +++ b/doc/spec/faq.rst @@ -56,22 +56,10 @@ which is a good diagnostic as to the quality of your model. How do I give feedback? ------------------------------------ -This project welcomes contributions and suggestions. Most contributions require you to agree to -a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, -grant us the rights to use your contribution. For details, visit https://cla.microsoft.com. - - -When you submit a pull request, a CLA-bot will automatically determine whether you need to provide -a CLA and decorate the PR appropriately (e.g., label, comment). -Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. - - -This project has adopted the Microsoft Open Source Code of Conduct. -For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments. - - - - - +This project welcomes contributions and suggestions. We use the `DCO bot `_ to enforce a +`Developer Certificate of Origin ` 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 :code:`-s` command line option to include this automatically when you commit via :code:`git commit`. +This project has adopted the `PyWhy Code of Conduct `_. diff --git a/doc/spec/img/pywhy-logo.png b/doc/spec/img/pywhy-logo.png new file mode 100644 index 000000000..86e935903 Binary files /dev/null and b/doc/spec/img/pywhy-logo.png differ diff --git a/doc/spec/motivation.rst b/doc/spec/motivation.rst index 1e59ecb6d..9bc532fb0 100644 --- a/doc/spec/motivation.rst +++ b/doc/spec/motivation.rst @@ -55,7 +55,7 @@ The DRIV model adjusts for the fact that not every customer who was offered the became a member and returns the effect of membership rather than the effect of receiving the quick sign-up. Link to jupyter notebook: -`Recommendation A/B Testing `__ +`Recommendation A/B Testing `__ More details: `Trip Advisor Case Study `__ @@ -82,7 +82,7 @@ The tree interpreter provides a presentation-ready summary of the key features that explain the biggest differences in responsiveness to a discount. Link to jupyter notebook: -`Customer Segmentation `__. +`Customer Segmentation `__. Multi-investment Attribution ----------------------------- @@ -103,4 +103,4 @@ The model uses flexible functions of observed customer features to filter out co in existing data and deliver the causal effect of each effort on revenue. Link to jupyter notebook: -`Multi-investment Attribution `__. \ No newline at end of file +`Multi-investment Attribution `__. \ No newline at end of file diff --git a/doc/spec/spec.rst b/doc/spec/spec.rst index ad10428bb..beb11f4f1 100644 --- a/doc/spec/spec.rst +++ b/doc/spec/spec.rst @@ -15,6 +15,7 @@ EconML User Guide interpretability references faq + community .. todo:: benchmark diff --git a/econml/__init__.py b/econml/__init__.py index 71168f3e7..7d106f509 100644 --- a/econml/__init__.py +++ b/econml/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. __all__ = ['automated_ml', diff --git a/econml/_cate_estimator.py b/econml/_cate_estimator.py index a8dce4dea..3c453b291 100644 --- a/econml/_cate_estimator.py +++ b/econml/_cate_estimator.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Base classes for all CATE estimators.""" @@ -117,7 +117,7 @@ def fit(self, *args, inference=None, **kwargs): self """ - pass + raise NotImplementedError("Abstract method") def _wrap_fit(m): @wraps(m) @@ -160,7 +160,7 @@ def effect(self, X=None, *, T0, T1): Note that when Y is a vector rather than a 2-dimensional array, the corresponding singleton dimension will be collapsed (so this method will return a vector) """ - pass + raise NotImplementedError("Abstract method") @abc.abstractmethod def marginal_effect(self, T, X=None): @@ -185,7 +185,7 @@ def marginal_effect(self, T, X=None): the corresponding singleton dimensions in the output will be collapsed (e.g. if both are vectors, then the output of this method will also be a vector) """ - pass + raise NotImplementedError("Abstract method") def ate(self, X=None, *, T0, T1): """ @@ -355,7 +355,7 @@ def effect_interval(self, X=None, *, T0=0, T1=1, alpha=0.05): lower, upper : tuple(type of :meth:`effect(X, T0, T1)`, type of :meth:`effect(X, T0, T1))` ) The lower and the upper bounds of the confidence interval for each quantity. """ - pass + raise NotImplementedError("Defer to inference") @_defer_to_inference def effect_inference(self, X=None, *, T0=0, T1=1): @@ -379,7 +379,7 @@ def effect_inference(self, X=None, *, T0=0, T1=1): can on demand calculate confidence interval, z statistic and p value. It can also output a dataframe summary of these inference results. """ - pass + raise NotImplementedError("Defer to inference") @_defer_to_inference def marginal_effect_interval(self, T, X=None, *, alpha=0.05): @@ -403,7 +403,7 @@ def marginal_effect_interval(self, T, X=None, *, alpha=0.05): type of :meth:`marginal_effect(T, X)` ) The lower and the upper bounds of the confidence interval for each quantity. """ - pass + raise NotImplementedError("Defer to inference") @_defer_to_inference def marginal_effect_inference(self, T, X=None): @@ -425,7 +425,7 @@ def marginal_effect_inference(self, T, X=None): can on demand calculate confidence interval, z statistic and p value. It can also output a dataframe summary of these inference results. """ - pass + raise NotImplementedError("Defer to inference") @_defer_to_inference def ate_interval(self, X=None, *, T0, T1, alpha=0.05): @@ -450,7 +450,7 @@ def ate_interval(self, X=None, *, T0, T1, alpha=0.05): lower, upper : tuple(type of :meth:`ate(X, T0, T1)`, type of :meth:`ate(X, T0, T1))` ) The lower and the upper bounds of the confidence interval for each quantity. """ - pass + raise NotImplementedError("Defer to inference") @_defer_to_inference def ate_inference(self, X=None, *, T0, T1): @@ -474,7 +474,7 @@ def ate_inference(self, X=None, *, T0, T1): can on demand calculate confidence interval, z statistic and p value. It can also output a dataframe summary of these inference results. """ - pass + raise NotImplementedError("Defer to inference") @_defer_to_inference def marginal_ate_interval(self, T, X=None, *, alpha=0.05): @@ -498,7 +498,7 @@ def marginal_ate_interval(self, T, X=None, *, alpha=0.05): type of :meth:`marginal_ate(T, X)` ) The lower and the upper bounds of the confidence interval for each quantity. """ - pass + raise NotImplementedError("Defer to inference") @_defer_to_inference def marginal_ate_inference(self, T, X=None): @@ -520,7 +520,7 @@ def marginal_ate_inference(self, T, X=None): can on demand calculate confidence interval, z statistic and p value. It can also output a dataframe summary of these inference results. """ - pass + raise NotImplementedError("Defer to inference") @property def dowhy(self): @@ -564,7 +564,7 @@ def const_marginal_effect(self, X=None): rather than a 2-dimensional array, the corresponding singleton dimensions in the output will be collapsed (e.g. if both are vectors, then the output of this method will also be a vector) """ - pass + raise NotImplementedError("Abstract method") def effect(self, X=None, *, T0, T1): """ @@ -697,7 +697,7 @@ def const_marginal_effect_interval(self, X=None, *, alpha=0.05): type of :meth:`const_marginal_effect(X)` ) The lower and the upper bounds of the confidence interval for each quantity. """ - pass + raise NotImplementedError("Defer to inference") @BaseCateEstimator._defer_to_inference def const_marginal_effect_inference(self, X=None): @@ -717,7 +717,7 @@ def const_marginal_effect_inference(self, X=None): can on demand calculate confidence interval, z statistic and p value. It can also output a dataframe summary of these inference results. """ - pass + raise NotImplementedError("Defer to inference") def const_marginal_ate(self, X=None): """ @@ -759,7 +759,7 @@ def const_marginal_ate_interval(self, X=None, *, alpha=0.05): type of :meth:`const_marginal_ate(X)` ) The lower and the upper bounds of the confidence interval for each quantity. """ - pass + raise NotImplementedError("Defer to inference") @BaseCateEstimator._defer_to_inference def const_marginal_ate_inference(self, X=None): @@ -779,7 +779,6 @@ def const_marginal_ate_inference(self, X=None): can on demand calculate confidence interval, z statistic and p value. It can also output a dataframe summary of these inference results. """ - pass def marginal_ate(self, T, X=None): return np.mean(self.marginal_effect(T, X=X), axis=0) @@ -787,12 +786,12 @@ def marginal_ate(self, T, X=None): @BaseCateEstimator._defer_to_inference def marginal_ate_interval(self, T, X=None, *, alpha=0.05): - pass + raise NotImplementedError("Defer to inference") marginal_ate_interval.__doc__ = BaseCateEstimator.marginal_ate_interval.__doc__ @BaseCateEstimator._defer_to_inference def marginal_ate_inference(self, T, X=None): - pass + raise NotImplementedError("Defer to inference") marginal_ate_inference.__doc__ = BaseCateEstimator.marginal_ate_inference.__doc__ def shap_values(self, X, *, feature_names=None, treatment_names=None, output_names=None, background_samples=100): @@ -1003,7 +1002,7 @@ def coef__interval(self, *, alpha=0.05): lb, ub: tuple(type of :meth:`coef_()`, type of :meth:`coef_()`) The lower and upper bounds of the confidence interval for each quantity. """ - pass + raise NotImplementedError("Defer to inference") @BaseCateEstimator._defer_to_inference def coef__inference(self): @@ -1015,7 +1014,7 @@ def coef__inference(self): InferenceResults: object The inference of the coefficients in the final linear model """ - pass + raise NotImplementedError("Defer to inference") @BaseCateEstimator._defer_to_inference def intercept__interval(self, *, alpha=0.05): @@ -1033,7 +1032,7 @@ def intercept__interval(self, *, alpha=0.05): lower, upper: tuple(type of :meth:`intercept_()`, type of :meth:`intercept_()`) The lower and upper bounds of the confidence interval. """ - pass + raise NotImplementedError("Defer to inference") @BaseCateEstimator._defer_to_inference def intercept__inference(self): @@ -1045,7 +1044,7 @@ def intercept__inference(self): InferenceResults: object The inference of the intercept in the final linear model """ - pass + raise NotImplementedError("Defer to inference") def summary(self, alpha=0.05, value=0, decimals=3, feature_names=None, treatment_names=None, output_names=None): """ The summary of coefficient and intercept in the linear model of the constant marginal treatment @@ -1274,7 +1273,7 @@ def coef__interval(self, T, *, alpha=0.05): lower, upper: tuple(type of :meth:`coef_(T)`, type of :meth:`coef_(T)`) The lower and upper bounds of the confidence interval for each quantity. """ - pass + raise NotImplementedError("Defer to inference") @BaseCateEstimator._defer_to_inference def coef__inference(self, T): @@ -1291,7 +1290,7 @@ def coef__inference(self, T): InferenceResults: object The inference of the coefficients in the final linear model """ - pass + raise NotImplementedError("Defer to inference") @BaseCateEstimator._defer_to_inference def intercept__interval(self, T, *, alpha=0.05): @@ -1311,7 +1310,7 @@ def intercept__interval(self, T, *, alpha=0.05): lower, upper: tuple(type of :meth:`intercept_(T)`, type of :meth:`intercept_(T)`) The lower and upper bounds of the confidence interval. """ - pass + raise NotImplementedError("Defer to inference") @BaseCateEstimator._defer_to_inference def intercept__inference(self, T): @@ -1329,7 +1328,7 @@ def intercept__inference(self, T): The inference of the intercept in the final linear model """ - pass + raise NotImplementedError("Defer to inference") def summary(self, T, *, alpha=0.05, value=0, decimals=3, feature_names=None, treatment_names=None, output_names=None): diff --git a/econml/_ensemble/__init__.py b/econml/_ensemble/__init__.py index bffd9e92f..5ea69417b 100644 --- a/econml/_ensemble/__init__.py +++ b/econml/_ensemble/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. from ._ensemble import BaseEnsemble, _partition_estimators diff --git a/econml/_ensemble/_ensemble.py b/econml/_ensemble/_ensemble.py index 34d9ef925..cdc23da4c 100644 --- a/econml/_ensemble/_ensemble.py +++ b/econml/_ensemble/_ensemble.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. # # This code is a fork from: @@ -158,8 +158,8 @@ def _partition_estimators(n_estimators, n_jobs): # Partition estimators between jobs n_estimators_per_job = np.full(n_jobs, n_estimators // n_jobs, - dtype=np.int) - n_estimators_per_job[:n_estimators % n_jobs] += 1 + dtype=int) + n_estimators_per_job[: n_estimators % n_jobs] += 1 starts = np.cumsum(n_estimators_per_job) return n_jobs, n_estimators_per_job.tolist(), [0] + starts.tolist() diff --git a/econml/_ensemble/_utilities.py b/econml/_ensemble/_utilities.py index d3317e403..aa69ed0e8 100644 --- a/econml/_ensemble/_utilities.py +++ b/econml/_ensemble/_utilities.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import numbers diff --git a/econml/_ortho_learner.py b/econml/_ortho_learner.py index 0d5aabe81..becff2499 100644 --- a/econml/_ortho_learner.py +++ b/econml/_ortho_learner.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """ @@ -469,7 +469,7 @@ def _gen_ortho_learner_model_nuisance(self): If the estimator also provides a score method with the same arguments as fit, it will be used to calculate scores during training. """ - pass + raise NotImplementedError("Abstract method") @abstractmethod def _gen_ortho_learner_model_final(self): @@ -492,7 +492,7 @@ def _gen_ortho_learner_model_final(self): then the input ``T`` to both above calls will be the one-hot encoding of the original input ``T``, excluding the first column of the one-hot. """ - pass + raise NotImplementedError("Abstract method") def _check_input_dims(self, Y, T, X=None, W=None, Z=None, *other_arrays): assert shape(Y)[0] == shape(T)[0], "Dimension mis-match!" @@ -899,7 +899,7 @@ def score(self, Y, T, X=None, W=None, Z=None, sample_weight=None, groups=None): nuisances = [np.zeros((n_iters * n_splits,) + nuis.shape) for nuis in nuisance_temp] for it, nuis in enumerate(nuisance_temp): - nuisances[it][i * n_iters + j] = nuis + nuisances[it][j * n_iters + i] = nuis for it in range(len(nuisances)): nuisances[it] = np.mean(nuisances[it], axis=0) diff --git a/econml/_shap.py b/econml/_shap.py index cc417d717..eed548202 100644 --- a/econml/_shap.py +++ b/econml/_shap.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Helper functions to get shap values for different cate estimators. diff --git a/econml/_tree_exporter.py b/econml/_tree_exporter.py index e7ac4d162..d00a39403 100644 --- a/econml/_tree_exporter.py +++ b/econml/_tree_exporter.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. # # This code contains some snippets of code from: @@ -612,7 +612,7 @@ def _make_dot_exporter(self, *, out_file, feature_names, treatment_names, max_de Number of digits of precision for floating point in the values of impurity, threshold and value attributes of each node. """ - pass + raise NotImplementedError("Abstract method") @abc.abstractmethod def _make_mpl_exporter(self, *, title=None, feature_names=None, treatment_names=None, max_depth=None, @@ -650,7 +650,7 @@ def _make_mpl_exporter(self, *, title=None, feature_names=None, treatment_names= fontsize : int Fontsize for text """ - pass + raise NotImplementedError("Abstract method") def export_graphviz(self, out_file=None, feature_names=None, treatment_names=None, max_depth=None, diff --git a/econml/_version.py b/econml/_version.py index 31cb0d8a8..643337c8c 100644 --- a/econml/_version.py +++ b/econml/_version.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. -__version__ = '0.14.0' +__version__ = '0.14.1' diff --git a/econml/automated_ml/__init__.py b/econml/automated_ml/__init__.py index 9914c36e9..23b2162cd 100644 --- a/econml/automated_ml/__init__.py +++ b/econml/automated_ml/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. from ._automated_ml import (setAutomatedMLWorkspace, addAutomatedML, diff --git a/econml/automated_ml/_automated_ml.py b/econml/automated_ml/_automated_ml.py index 8a6be0977..1454d2456 100644 --- a/econml/automated_ml/_automated_ml.py +++ b/econml/automated_ml/_automated_ml.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. # AzureML diff --git a/econml/cate_interpreter/__init__.py b/econml/cate_interpreter/__init__.py index d0aa3700d..390c29a83 100644 --- a/econml/cate_interpreter/__init__.py +++ b/econml/cate_interpreter/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. from ._interpreters import SingleTreeCateInterpreter, SingleTreePolicyInterpreter diff --git a/econml/cate_interpreter/_interpreters.py b/econml/cate_interpreter/_interpreters.py index e0bd97be0..f4a55a76d 100644 --- a/econml/cate_interpreter/_interpreters.py +++ b/econml/cate_interpreter/_interpreters.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import abc @@ -31,7 +31,7 @@ def interpret(self, cate_estimator, X): must be compatible shape-wise with the features used to fit the estimator """ - pass + raise NotImplementedError("Abstract method") class SingleTreeCateInterpreter(_SingleTreeInterpreter): diff --git a/econml/data/dynamic_panel_dgp.py b/econml/data/dynamic_panel_dgp.py index 82b842912..cb7ffa17c 100644 --- a/econml/data/dynamic_panel_dgp.py +++ b/econml/data/dynamic_panel_dgp.py @@ -135,7 +135,7 @@ def simulate_residuals(ind): def simulate_residuals_all(res_df): - res_df_new = res_df.copy(deep=True) + res_df_new = res_df.astype(dtype='float64', copy=True, errors='raise') for i in range(res_df.shape[1]): res_df_new.iloc[:, i] = simulate_residuals(i) # demean the new residual again diff --git a/econml/dml/__init__.py b/econml/dml/__init__.py index 3688628c9..ce58cf8c0 100644 --- a/econml/dml/__init__.py +++ b/econml/dml/__init__.py @@ -1,5 +1,5 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Double Machine Learning. The method uses machine learning methods to identify the diff --git a/econml/dml/_rlearner.py b/econml/dml/_rlearner.py index d816c31f7..d13b99a2f 100644 --- a/econml/dml/_rlearner.py +++ b/econml/dml/_rlearner.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """ @@ -295,7 +295,7 @@ def _gen_model_y(self): model_y.fit(X, W, Y, sample_weight=sample_weight) model_y.predict(X, W) """ - pass + raise NotImplementedError("Abstract method") @abstractmethod def _gen_model_t(self): @@ -310,7 +310,7 @@ def _gen_model_t(self): model_t.fit(X, W, T, sample_weight=sample_weight) model_t.predict(X, W) """ - pass + raise NotImplementedError("Abstract method") @abstractmethod def _gen_rlearner_model_final(self): @@ -326,7 +326,7 @@ def _gen_rlearner_model_final(self): sample_weight=sample_weight, freq_weight=freq_weight, sample_var=sample_var) model_final.predict(X) """ - pass + raise NotImplementedError("Abstract method") def _gen_ortho_learner_model_nuisance(self): return _ModelNuisance(self._gen_model_y(), self._gen_model_t()) diff --git a/econml/dml/causal_forest.py b/econml/dml/causal_forest.py index 76dbd54f3..07a356d75 100644 --- a/econml/dml/causal_forest.py +++ b/econml/dml/causal_forest.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. from warnings import warn diff --git a/econml/dml/dml.py b/econml/dml/dml.py index d33ccc638..713554dad 100644 --- a/econml/dml/dml.py +++ b/econml/dml/dml.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. from warnings import warn diff --git a/econml/dowhy.py b/econml/dowhy.py index b494a86bd..7c6489743 100644 --- a/econml/dowhy.py +++ b/econml/dowhy.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. @@ -6,7 +6,7 @@ References ---------- -DoWhy, https://microsoft.github.io/dowhy/ +DoWhy, https://www.pywhy.org/dowhy/ """ diff --git a/econml/dr/__init__.py b/econml/dr/__init__.py index a69bc9bfe..c64ad7b06 100644 --- a/econml/dr/__init__.py +++ b/econml/dr/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. from ._drlearner import (DRLearner, LinearDRLearner, SparseLinearDRLearner, ForestDRLearner) diff --git a/econml/dr/_drlearner.py b/econml/dr/_drlearner.py index 5490ffeed..3ca702a0c 100644 --- a/econml/dr/_drlearner.py +++ b/econml/dr/_drlearner.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """ diff --git a/econml/dynamic/__init__.py b/econml/dynamic/__init__.py index 8e4ecd538..489deb950 100755 --- a/econml/dynamic/__init__.py +++ b/econml/dynamic/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. __all__ = ["dml"] diff --git a/econml/dynamic/dml/__init__.py b/econml/dynamic/dml/__init__.py index b645bbb2a..0185ea702 100755 --- a/econml/dynamic/dml/__init__.py +++ b/econml/dynamic/dml/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Double Machine Learning for Dynamic Treatment Effects. diff --git a/econml/grf/__init__.py b/econml/grf/__init__.py index be3c91392..6dbb9bcf6 100644 --- a/econml/grf/__init__.py +++ b/econml/grf/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """ An efficient Cython implementation of Generalized Random Forests [grf]_ and special diff --git a/econml/grf/_base_grf.py b/econml/grf/_base_grf.py index 625915c28..3fbc79c71 100644 --- a/econml/grf/_base_grf.py +++ b/econml/grf/_base_grf.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. # # This code contains snippets of code from @@ -103,6 +103,7 @@ def __init__(self, self.warm_start = warm_start self.max_samples = max_samples + @abstractmethod def _get_alpha_and_pointJ(self, X, T, y, **kwargs): """ This function must be implemented by child class and given input variables X, T, y and any auxiliary variables passed as keyword only, should be calculating @@ -116,8 +117,9 @@ def _get_alpha_and_pointJ(self, X, T, y, **kwargs): J : array of shape (n_samples, n_outputs * n_outputs) The J matrix part of the moment equation, flattened in Fortran-contiguous format. """ - pass + raise NotImplementedError("Abstract method") + @abstractmethod def _get_n_outputs_decomposition(self, X, T, y, **kwargs): """ This function must be implemented by child class and given input variables X, T, y and any auxiliary variables passed as keyword only, should return a tuple @@ -131,7 +133,7 @@ def _get_n_outputs_decomposition(self, X, T, y, **kwargs): n_relevant_outputs : int The length of the prefix of parameters that we care about (remainder are nuisance) """ - pass + raise NotImplementedError("Abstract method") def apply(self, X): """ diff --git a/econml/grf/_base_grftree.py b/econml/grf/_base_grftree.py index 7da779397..4d05bd650 100644 --- a/econml/grf/_base_grftree.py +++ b/econml/grf/_base_grftree.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. # # This code contains snippets of code from: diff --git a/econml/grf/_criterion.pxd b/econml/grf/_criterion.pxd index e4b7cd4fe..9bbf1d9d6 100644 --- a/econml/grf/_criterion.pxd +++ b/econml/grf/_criterion.pxd @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. # published under the following license and copyright: # BSD 3-Clause License diff --git a/econml/grf/_criterion.pyx b/econml/grf/_criterion.pyx index 59a448a68..5f4544ce7 100644 --- a/econml/grf/_criterion.pyx +++ b/econml/grf/_criterion.pyx @@ -2,7 +2,7 @@ # cython: boundscheck=False # cython: wraparound=False -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. # # This code contains some snippets of code from: diff --git a/econml/grf/_utils.pxd b/econml/grf/_utils.pxd index 812bb99ea..c66370f93 100644 --- a/econml/grf/_utils.pxd +++ b/econml/grf/_utils.pxd @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import numpy as np diff --git a/econml/grf/_utils.pyx b/econml/grf/_utils.pyx index 8795f1ea0..7a04e0335 100644 --- a/econml/grf/_utils.pyx +++ b/econml/grf/_utils.pyx @@ -2,7 +2,7 @@ # cython: boundscheck=False # cython: wraparound=False -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. from libc.stdlib cimport free diff --git a/econml/grf/classes.py b/econml/grf/classes.py index 4a5df80b8..51daca428 100644 --- a/econml/grf/classes.py +++ b/econml/grf/classes.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import numpy as np diff --git a/econml/inference/__init__.py b/econml/inference/__init__.py index 921b6b4f5..113ff78ab 100644 --- a/econml/inference/__init__.py +++ b/econml/inference/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. from ._inference import (BootstrapInference, GenericModelFinalInference, GenericSingleTreatmentModelFinalInference, diff --git a/econml/inference/_bootstrap.py b/econml/inference/_bootstrap.py index 640eeed0e..767ffdff2 100644 --- a/econml/inference/_bootstrap.py +++ b/econml/inference/_bootstrap.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Bootstrap sampling.""" diff --git a/econml/inference/_inference.py b/econml/inference/_inference.py index 671345550..5745a6a43 100644 --- a/econml/inference/_inference.py +++ b/econml/inference/_inference.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import abc @@ -33,7 +33,7 @@ def fit(self, estimator, *args, **kwargs): This is called after the estimator's fit. """ - pass + raise NotImplementedError("Abstract method") def ate_interval(self, X=None, *, T0=0, T1=1, alpha=0.05): return self.effect_inference(X=X, T0=T0, T1=T1).population_summary(alpha=alpha).conf_int_mean() @@ -738,7 +738,7 @@ def stderr(self): the corresponding singleton dimensions in the output will be collapsed (e.g. if both are vectors, then the output of this method will also be a vector) """ - pass + raise NotImplementedError("Abstract method") @property def var(self): @@ -776,7 +776,7 @@ def conf_int(self, alpha=0.05): the corresponding singleton dimensions in the output will be collapsed (e.g. if both are vectors, then the output of this method will also be a vector) """ - pass + raise NotImplementedError("Abstract method") @abc.abstractmethod def pvalue(self, value=0): @@ -796,7 +796,7 @@ def pvalue(self, value=0): the corresponding singleton dimensions in the output will be collapsed (e.g. if both are vectors, then the output of this method will also be a vector) """ - pass + raise NotImplementedError("Abstract method") def zstat(self, value=0): """ @@ -963,7 +963,7 @@ def _expand_outputs(self, n_rows): results: InferenceResults The expanded results """ - pass + raise NotImplementedError("Abstract method") def translate(self, offset): """ diff --git a/econml/iv/__init__.py b/econml/iv/__init__.py index 6579a9f50..b771315a8 100644 --- a/econml/iv/__init__.py +++ b/econml/iv/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. __all__ = ["dml", "dr", "nnet", "sieve"] diff --git a/econml/iv/dml/__init__.py b/econml/iv/dml/__init__.py index 1fd7d9cca..60ff3769d 100644 --- a/econml/iv/dml/__init__.py +++ b/econml/iv/dml/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Orthogonal IV for Heterogeneous Treatment Effects. diff --git a/econml/iv/dml/_dml.py b/econml/iv/dml/_dml.py index 9647292f1..af0134ba3 100644 --- a/econml/iv/dml/_dml.py +++ b/econml/iv/dml/_dml.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Orthogonal IV for Heterogeneous Treatment Effects. diff --git a/econml/iv/dr/__init__.py b/econml/iv/dr/__init__.py index a47995a85..e0586f2b0 100644 --- a/econml/iv/dr/__init__.py +++ b/econml/iv/dr/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Orthogonal IV for Heterogeneous Treatment Effects. diff --git a/econml/iv/dr/_dr.py b/econml/iv/dr/_dr.py index 5ef669bcc..6e3689453 100644 --- a/econml/iv/dr/_dr.py +++ b/econml/iv/dr/_dr.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Doubly Robust IV for Heterogeneous Treatment Effects. diff --git a/econml/iv/nnet/__init__.py b/econml/iv/nnet/__init__.py index dd4f68a72..470c783d6 100644 --- a/econml/iv/nnet/__init__.py +++ b/econml/iv/nnet/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. from ._deepiv import DeepIV diff --git a/econml/iv/nnet/_deepiv.py b/econml/iv/nnet/_deepiv.py index 4f92c2683..4a1b8f059 100644 --- a/econml/iv/nnet/_deepiv.py +++ b/econml/iv/nnet/_deepiv.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Deep IV estimator and related components.""" diff --git a/econml/iv/sieve/__init__.py b/econml/iv/sieve/__init__.py index 4cc9d29c1..cb217b7f9 100644 --- a/econml/iv/sieve/__init__.py +++ b/econml/iv/sieve/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. from ._tsls import HermiteFeatures, DPolynomialFeatures, SieveTSLS diff --git a/econml/iv/sieve/_tsls.py b/econml/iv/sieve/_tsls.py index 08ea06e8d..53a2d92be 100644 --- a/econml/iv/sieve/_tsls.py +++ b/econml/iv/sieve/_tsls.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Provides a non-parametric two-stage least squares instrumental variable estimator.""" diff --git a/econml/metalearners/__init__.py b/econml/metalearners/__init__.py index ed7735c1d..a12392242 100644 --- a/econml/metalearners/__init__.py +++ b/econml/metalearners/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. from ._metalearners import (TLearner, SLearner, XLearner, DomainAdaptationLearner) diff --git a/econml/metalearners/_metalearners.py b/econml/metalearners/_metalearners.py index 50c204fd4..37dc2f6d2 100644 --- a/econml/metalearners/_metalearners.py +++ b/econml/metalearners/_metalearners.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Metalearners for heterogeneous treatment effects in the context of discrete treatments. diff --git a/econml/orf/__init__.py b/econml/orf/__init__.py index 96d5e4d9a..fb95af040 100644 --- a/econml/orf/__init__.py +++ b/econml/orf/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """ An implementation of Orthogonal Random Forests [orf]_ and special diff --git a/econml/orf/_causal_tree.py b/econml/orf/_causal_tree.py index 21b625e41..e24d186d5 100644 --- a/econml/orf/_causal_tree.py +++ b/econml/orf/_causal_tree.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Basic tree utilities and methods. diff --git a/econml/orf/_ortho_forest.py b/econml/orf/_ortho_forest.py index 4c81a0cbb..d97ad8b36 100644 --- a/econml/orf/_ortho_forest.py +++ b/econml/orf/_ortho_forest.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Orthogonal Random Forest. diff --git a/econml/panel/__init__.py b/econml/panel/__init__.py index 34e76781c..3f3688a8b 100644 --- a/econml/panel/__init__.py +++ b/econml/panel/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. __all__ = ["dml"] diff --git a/econml/panel/dml/__init__.py b/econml/panel/dml/__init__.py index 6fb1669e3..8f83c8eb1 100644 --- a/econml/panel/dml/__init__.py +++ b/econml/panel/dml/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Double Machine Learning for Dynamic Treatment Effects. diff --git a/econml/panel/dml/_dml.py b/econml/panel/dml/_dml.py index 32207565b..a12385e36 100644 --- a/econml/panel/dml/_dml.py +++ b/econml/panel/dml/_dml.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import abc @@ -547,32 +547,29 @@ def _gen_model_t(self): def _gen_model_final(self): return StatsModelsLinearRegression(fit_intercept=False) - def _gen_ortho_learner_model_nuisance(self, n_periods): + def _gen_ortho_learner_model_nuisance(self): return _DynamicModelNuisance( model_t=self._gen_model_t(), model_y=self._gen_model_y(), - n_periods=n_periods) + n_periods=self._n_periods) - def _gen_ortho_learner_model_final(self, n_periods): + def _gen_ortho_learner_model_final(self): wrapped_final_model = _DynamicFinalWrapper( StatsModelsLinearRegression(fit_intercept=False), fit_cate_intercept=self.fit_cate_intercept, featurizer=self.featurizer, use_weight_trick=False) - return _LinearDynamicModelFinal(wrapped_final_model, n_periods=n_periods) + return _LinearDynamicModelFinal(wrapped_final_model, n_periods=self._n_periods) def _prefit(self, Y, T, *args, groups=None, only_final=False, **kwargs): + # we need to set the number of periods before calling super()._prefit, since that will generate the + # final and nuisance models, which need to have self._n_periods set u_periods = np.unique(np.unique(groups, return_counts=True)[1]) if len(u_periods) > 1: raise AttributeError( "Imbalanced panel. Method currently expects only panels with equal number of periods. Pad your data") self._n_periods = u_periods[0] - # generate an instance of the final model - self._ortho_learner_model_final = self._gen_ortho_learner_model_final(self._n_periods) - if not only_final: - # generate an instance of the nuisance model - self._ortho_learner_model_nuisance = self._gen_ortho_learner_model_nuisance(self._n_periods) - TreatmentExpansionMixin._prefit(self, Y, T, *args, **kwargs) + super()._prefit(Y, T, *args, **kwargs) def _postfit(self, Y, T, *args, **kwargs): super()._postfit(Y, T, *args, **kwargs) diff --git a/econml/policy/__init__.py b/econml/policy/__init__.py index eebcbcbea..512526f67 100644 --- a/econml/policy/__init__.py +++ b/econml/policy/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. from ._forest import PolicyTree, PolicyForest diff --git a/econml/policy/_base.py b/econml/policy/_base.py index d2e1d847d..42546b1dd 100644 --- a/econml/policy/_base.py +++ b/econml/policy/_base.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Base classes for all Policy estimators.""" diff --git a/econml/policy/_drlearner.py b/econml/policy/_drlearner.py index 6aaabdf68..05a50989a 100644 --- a/econml/policy/_drlearner.py +++ b/econml/policy/_drlearner.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. from warnings import warn diff --git a/econml/policy/_forest/__init__.py b/econml/policy/_forest/__init__.py index 39bd122f1..08d88decd 100644 --- a/econml/policy/_forest/__init__.py +++ b/econml/policy/_forest/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. from ._tree import PolicyTree diff --git a/econml/policy/_forest/_criterion.pxd b/econml/policy/_forest/_criterion.pxd index 15f732ed5..a0dcb6834 100644 --- a/econml/policy/_forest/_criterion.pxd +++ b/econml/policy/_forest/_criterion.pxd @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. # published under the following license and copyright: # BSD 3-Clause License diff --git a/econml/policy/_forest/_criterion.pyx b/econml/policy/_forest/_criterion.pyx index 82a3017f7..d71f4b965 100644 --- a/econml/policy/_forest/_criterion.pyx +++ b/econml/policy/_forest/_criterion.pyx @@ -2,7 +2,7 @@ # cython: boundscheck=False # cython: wraparound=False -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import numpy as np diff --git a/econml/policy/_forest/_forest.py b/econml/policy/_forest/_forest.py index cd9197782..1cb35e906 100644 --- a/econml/policy/_forest/_forest.py +++ b/econml/policy/_forest/_forest.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. # # This code contains snippets of code from diff --git a/econml/policy/_forest/_tree.py b/econml/policy/_forest/_tree.py index 5a390bcb2..4fb9bc8db 100644 --- a/econml/policy/_forest/_tree.py +++ b/econml/policy/_forest/_tree.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. # # This code contains snippets of code from: diff --git a/econml/score/__init__.py b/econml/score/__init__.py index e5db03594..45c0c740e 100644 --- a/econml/score/__init__.py +++ b/econml/score/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """ diff --git a/econml/score/ensemble_cate.py b/econml/score/ensemble_cate.py index f7d0b4a49..605694067 100644 --- a/econml/score/ensemble_cate.py +++ b/econml/score/ensemble_cate.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import numpy as np diff --git a/econml/score/rscorer.py b/econml/score/rscorer.py index 838502392..bbb2da86e 100644 --- a/econml/score/rscorer.py +++ b/econml/score/rscorer.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. from ..dml import LinearDML diff --git a/econml/sklearn_extensions/linear_model.py b/econml/sklearn_extensions/linear_model.py index dd3a9c94c..a7f5d029c 100644 --- a/econml/sklearn_extensions/linear_model.py +++ b/econml/sklearn_extensions/linear_model.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Collection of scikit-learn extensions for linear models. diff --git a/econml/sklearn_extensions/model_selection.py b/econml/sklearn_extensions/model_selection.py index 004728fdb..79b714bbc 100644 --- a/econml/sklearn_extensions/model_selection.py +++ b/econml/sklearn_extensions/model_selection.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Collection of scikit-learn extensions for model selection techniques.""" diff --git a/econml/solutions/causal_analysis/__init__.py b/econml/solutions/causal_analysis/__init__.py index eb691b2fd..c6049a95d 100644 --- a/econml/solutions/causal_analysis/__init__.py +++ b/econml/solutions/causal_analysis/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. from ._causal_analysis import CausalAnalysis diff --git a/econml/solutions/causal_analysis/_causal_analysis.py b/econml/solutions/causal_analysis/_causal_analysis.py index db636bed1..4ca71bfed 100644 --- a/econml/solutions/causal_analysis/_causal_analysis.py +++ b/econml/solutions/causal_analysis/_causal_analysis.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Module for assessing causal feature importance.""" diff --git a/econml/tests/dgp.py b/econml/tests/dgp.py index 403783447..88e2aff07 100644 --- a/econml/tests/dgp.py +++ b/econml/tests/dgp.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import abc import numpy as np diff --git a/econml/tests/test_ate_inference.py b/econml/tests/test_ate_inference.py index e6b9edaeb..c376049cd 100644 --- a/econml/tests/test_ate_inference.py +++ b/econml/tests/test_ate_inference.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import numpy as np diff --git a/econml/tests/test_automated_ml.py b/econml/tests/test_automated_ml.py index 3c3f65f2a..ba222fad9 100644 --- a/econml/tests/test_automated_ml.py +++ b/econml/tests/test_automated_ml.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import unittest diff --git a/econml/tests/test_bootstrap.py b/econml/tests/test_bootstrap.py index 3cb6dac78..df15f9cdb 100644 --- a/econml/tests/test_bootstrap.py +++ b/econml/tests/test_bootstrap.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. from econml.inference._bootstrap import BootstrapEstimator diff --git a/econml/tests/test_cate_interpreter.py b/econml/tests/test_cate_interpreter.py index a36140d14..d3f8adb78 100644 --- a/econml/tests/test_cate_interpreter.py +++ b/econml/tests/test_cate_interpreter.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import numpy as np diff --git a/econml/tests/test_causal_analysis.py b/econml/tests/test_causal_analysis.py index b0edeb08c..8e5e1bb16 100644 --- a/econml/tests/test_causal_analysis.py +++ b/econml/tests/test_causal_analysis.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import unittest diff --git a/econml/tests/test_deepiv.py b/econml/tests/test_deepiv.py index f4e1ec354..f86389d26 100644 --- a/econml/tests/test_deepiv.py +++ b/econml/tests/test_deepiv.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Tests for `deepiv` module.""" diff --git a/econml/tests/test_dml.py b/econml/tests/test_dml.py index 69e2e847c..57b5c3ec4 100644 --- a/econml/tests/test_dml.py +++ b/econml/tests/test_dml.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import unittest @@ -1095,6 +1095,7 @@ def test_nuisance_scores(self): est.fit(y, T, X=X, W=W) assert len(est.nuisance_scores_t) == len(est.nuisance_scores_y) == mc_iters assert len(est.nuisance_scores_t[0]) == len(est.nuisance_scores_y[0]) == cv + est.score(y, T, X=X, W=W) def test_categories(self): dmls = [LinearDML, SparseLinearDML] diff --git a/econml/tests/test_dmliv.py b/econml/tests/test_dmliv.py index 54175d0c9..ab739c77a 100644 --- a/econml/tests/test_dmliv.py +++ b/econml/tests/test_dmliv.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import pickle diff --git a/econml/tests/test_dominicks.py b/econml/tests/test_dominicks.py index a19411bbf..126084e84 100644 --- a/econml/tests/test_dominicks.py +++ b/econml/tests/test_dominicks.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import os.path @@ -20,7 +20,7 @@ def test_dominicks(): if not os.path.isfile(file_name): print("Downloading file (this might take a few seconds)...") urllib.request.urlretrieve( - "https://msalicedatapublic.blob.core.windows.net/datasets/OrangeJuice/oj_large.csv", file_name) + "https://msalicedatapublic.z5.web.core.windows.net/datasets/OrangeJuice/oj_large.csv", file_name) oj_data = pd.read_csv(file_name) brands = sorted(set(oj_data["brand"])) diff --git a/econml/tests/test_dowhy.py b/econml/tests/test_dowhy.py index 4daca4af2..a247cf507 100644 --- a/econml/tests/test_dowhy.py +++ b/econml/tests/test_dowhy.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import numpy as np diff --git a/econml/tests/test_driv.py b/econml/tests/test_driv.py index bddff8904..eabe093b4 100644 --- a/econml/tests/test_driv.py +++ b/econml/tests/test_driv.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. from econml.iv.dr import (DRIV, LinearDRIV, SparseLinearDRIV, ForestDRIV, IntentToTreatDRIV, LinearIntentToTreatDRIV,) diff --git a/econml/tests/test_drlearner.py b/econml/tests/test_drlearner.py index a77878ef1..e0f251046 100644 --- a/econml/tests/test_drlearner.py +++ b/econml/tests/test_drlearner.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. from contextlib import ExitStack diff --git a/econml/tests/test_dynamic_dml.py b/econml/tests/test_dynamic_dml.py index 4a24aca56..0c2c7339f 100644 --- a/econml/tests/test_dynamic_dml.py +++ b/econml/tests/test_dynamic_dml.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import unittest import pytest diff --git a/econml/tests/test_grf_cython.py b/econml/tests/test_grf_cython.py index bb3aa4c30..f3a879dae 100644 --- a/econml/tests/test_grf_cython.py +++ b/econml/tests/test_grf_cython.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import unittest diff --git a/econml/tests/test_grf_python.py b/econml/tests/test_grf_python.py index 34f515216..147c5cabe 100644 --- a/econml/tests/test_grf_python.py +++ b/econml/tests/test_grf_python.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import unittest diff --git a/econml/tests/test_inference.py b/econml/tests/test_inference.py index f36a55541..5a09b563a 100644 --- a/econml/tests/test_inference.py +++ b/econml/tests/test_inference.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import numpy as np diff --git a/econml/tests/test_integration.py b/econml/tests/test_integration.py index ef9c1851f..a57a06880 100644 --- a/econml/tests/test_integration.py +++ b/econml/tests/test_integration.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. from econml.utilities import get_feature_names_or_default diff --git a/econml/tests/test_linear_model.py b/econml/tests/test_linear_model.py index ac012e009..723b35a03 100644 --- a/econml/tests/test_linear_model.py +++ b/econml/tests/test_linear_model.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Tests for linear_model extensions.""" diff --git a/econml/tests/test_metalearners.py b/econml/tests/test_metalearners.py index cb13b98c9..534f1623b 100644 --- a/econml/tests/test_metalearners.py +++ b/econml/tests/test_metalearners.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import numpy as np diff --git a/econml/tests/test_montecarlo.py b/econml/tests/test_montecarlo.py index 2ca70c198..00da85c3e 100644 --- a/econml/tests/test_montecarlo.py +++ b/econml/tests/test_montecarlo.py @@ -1,8 +1,7 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. + import unittest from sklearn.linear_model import LinearRegression, LogisticRegression from econml.dml import (DML, LinearDML, SparseLinearDML, KernelDML, NonParamDML, CausalForestDML) diff --git a/econml/tests/test_notebooks.py b/econml/tests/test_notebooks.py index e38616554..ad569a614 100644 --- a/econml/tests/test_notebooks.py +++ b/econml/tests/test_notebooks.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import re @@ -7,6 +7,7 @@ import os _nbdir = os.path.join(os.path.dirname(__file__), '..', '..', 'notebooks') +_maindir = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', '..')) _nbsubdirs = ['.', 'CustomerScenarios', 'Solutions'] # TODO: add AutoML notebooks @@ -28,6 +29,15 @@ def test_notebook(file): import nbconvert nb = nbformat.read(os.path.join(_nbdir, file), as_version=4) + + # make sure that coverage outputs reflect notebook contents + nb.cells.insert(0, nbformat.v4.new_code_cell(f""" + import os, coverage + cwd = os.getcwd() + os.chdir({_maindir!r}) # change to the root directory, so that setup.cfg is found + coverage.process_startup() + os.chdir(cwd) # change back to the original directory""")) + # require all cells to complete within 15 minutes, which will help prevent us from # creating notebooks that are annoying for our users to actually run themselves ep = nbconvert.preprocessors.ExecutePreprocessor( diff --git a/econml/tests/test_orf.py b/econml/tests/test_orf.py index fe2736aeb..25f823636 100644 --- a/econml/tests/test_orf.py +++ b/econml/tests/test_orf.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import numpy as np diff --git a/econml/tests/test_ortho_learner.py b/econml/tests/test_ortho_learner.py index 57ffcf685..846d9facd 100644 --- a/econml/tests/test_ortho_learner.py +++ b/econml/tests/test_ortho_learner.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. from econml._ortho_learner import _OrthoLearner, _crossfit diff --git a/econml/tests/test_policy_forest.py b/econml/tests/test_policy_forest.py index a953f11ff..762c7a55c 100644 --- a/econml/tests/test_policy_forest.py +++ b/econml/tests/test_policy_forest.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import unittest diff --git a/econml/tests/test_rscorer.py b/econml/tests/test_rscorer.py index f1de2748c..33c79196a 100644 --- a/econml/tests/test_rscorer.py +++ b/econml/tests/test_rscorer.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import unittest diff --git a/econml/tests/test_shap.py b/econml/tests/test_shap.py index 2c69b39d4..b3605a564 100644 --- a/econml/tests/test_shap.py +++ b/econml/tests/test_shap.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import numpy as np diff --git a/econml/tests/test_statsmodels.py b/econml/tests/test_statsmodels.py index dc4573d5c..de55740fb 100644 --- a/econml/tests/test_statsmodels.py +++ b/econml/tests/test_statsmodels.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import unittest diff --git a/econml/tests/test_treatment_featurization.py b/econml/tests/test_treatment_featurization.py index 085754413..a58bf5754 100644 --- a/econml/tests/test_treatment_featurization.py +++ b/econml/tests/test_treatment_featurization.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import pytest import unittest diff --git a/econml/tests/test_tree.py b/econml/tests/test_tree.py index b5d898f56..35296ca6e 100644 --- a/econml/tests/test_tree.py +++ b/econml/tests/test_tree.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import unittest diff --git a/econml/tests/test_two_stage_least_squares.py b/econml/tests/test_two_stage_least_squares.py index 03255b10b..feb3bc039 100644 --- a/econml/tests/test_two_stage_least_squares.py +++ b/econml/tests/test_two_stage_least_squares.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Tests for two stage least squares module.""" diff --git a/econml/tests/test_utilities.py b/econml/tests/test_utilities.py index eb849d07d..7deb1669a 100644 --- a/econml/tests/test_utilities.py +++ b/econml/tests/test_utilities.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import unittest diff --git a/econml/tests/utilities.py b/econml/tests/utilities.py index 83e0a656e..5f92e2201 100644 --- a/econml/tests/utilities.py +++ b/econml/tests/utilities.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. import unittest diff --git a/econml/tree/__init__.py b/econml/tree/__init__.py index ebccae49e..457d73bf7 100644 --- a/econml/tree/__init__.py +++ b/econml/tree/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. from ._criterion import Criterion, RegressionCriterion, MSE diff --git a/econml/tree/_criterion.pxd b/econml/tree/_criterion.pxd index d13368113..2eb6b8ba3 100644 --- a/econml/tree/_criterion.pxd +++ b/econml/tree/_criterion.pxd @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. # # This code is a fork from: https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/tree/_criterion.pxd diff --git a/econml/tree/_criterion.pyx b/econml/tree/_criterion.pyx index 63f210280..d0b12a92f 100644 --- a/econml/tree/_criterion.pyx +++ b/econml/tree/_criterion.pyx @@ -2,7 +2,7 @@ # cython: boundscheck=False # cython: wraparound=False -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. # # This code is a fork from: https://github.com/scikit-learn/scikit-learn/blob/main/sklearn/tree/_criterion.pyx diff --git a/econml/tree/_splitter.pxd b/econml/tree/_splitter.pxd index 0ab66cabc..c911a90c3 100644 --- a/econml/tree/_splitter.pxd +++ b/econml/tree/_splitter.pxd @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. # # This code is a fork from: https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/tree/_splitter.pxd diff --git a/econml/tree/_splitter.pyx b/econml/tree/_splitter.pyx index 8b7ae406d..557dc6e59 100644 --- a/econml/tree/_splitter.pyx +++ b/econml/tree/_splitter.pyx @@ -2,7 +2,7 @@ # cython: boundscheck=False # cython: wraparound=False -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. # # This code is a fork from: https://github.com/scikit-learn/scikit-learn/blob/main/sklearn/tree/_splitter.pyx diff --git a/econml/tree/_tree.pxd b/econml/tree/_tree.pxd index 53309a787..26f5dd68b 100644 --- a/econml/tree/_tree.pxd +++ b/econml/tree/_tree.pxd @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. # # This code is a fork from: https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/tree/_tree.pxd diff --git a/econml/tree/_tree.pyx b/econml/tree/_tree.pyx index e40fac8f8..daba1a121 100644 --- a/econml/tree/_tree.pyx +++ b/econml/tree/_tree.pyx @@ -2,7 +2,7 @@ # cython: boundscheck=False # cython: wraparound=False -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. # # This code is a fork from: https://github.com/scikit-learn/scikit-learn/blob/main/sklearn/tree/_tree.pyx diff --git a/econml/tree/_utils.pxd b/econml/tree/_utils.pxd index 2eaebe9ed..6a0bd2b70 100644 --- a/econml/tree/_utils.pxd +++ b/econml/tree/_utils.pxd @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. # # This code is a fork from: https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/tree/_utils.pxd diff --git a/econml/tree/_utils.pyx b/econml/tree/_utils.pyx index d9e9968ac..8588f7547 100644 --- a/econml/tree/_utils.pyx +++ b/econml/tree/_utils.pyx @@ -2,7 +2,7 @@ # cython: boundscheck=False # cython: wraparound=False -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. # # This code is a fork from: https://github.com/scikit-learn/scikit-learn/blob/main/sklearn/tree/_utils.pyx diff --git a/econml/utilities.py b/econml/utilities.py index a7becc0ad..90324dcf6 100644 --- a/econml/utilities.py +++ b/econml/utilities.py @@ -1,4 +1,4 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) PyWhy contributors. All rights reserved. # Licensed under the MIT License. """Utility methods.""" diff --git a/lkg-notebook.txt b/lkg-notebook.txt new file mode 100644 index 000000000..8ecd8e6b2 --- /dev/null +++ b/lkg-notebook.txt @@ -0,0 +1,154 @@ +Jinja2==3.1.2 +Keras-Applications==1.0.8; python_version<='3.8' +Keras-Preprocessing==1.1.2; python_version<='3.8' +Keras==2.3.1; python_version<='3.8' +Markdown==3.4.3; python_version<='3.8' +MarkupSafe==2.1.2 +Pillow==9.5.0 +PyYAML==6.0 +Pygments==2.15.1 +QtPy==2.3.1 +Send2Trash==1.8.2 +Werkzeug==2.3.4; python_version<='3.8' +absl-py==1.4.0; python_version<='3.8' +anyio==3.6.2 +argon2-cffi-bindings==21.2.0 +argon2-cffi==21.3.0 +arrow==1.2.3 +asttokens==2.2.1 +astunparse==1.6.3; python_version<='3.8' +attrs==23.1.0 +backcall==0.2.0 +beautifulsoup4==4.12.2 +bleach==6.0.0 +cachetools==4.2.4; python_version<='3.8' +certifi==2023.5.7; python_version<='3.8' +cffi==1.15.1 +charset-normalizer==3.1.0; python_version<='3.8' +cloudpickle==2.2.1 +comm==0.1.3 +cycler==0.11.0 +debugpy==1.6.7 +decorator==5.1.1 +defusedxml==0.7.1 +dowhy==0.8; '3.9'<=python_version +executing==1.2.0 +fastjsonschema==2.16.3 +fonttools==4.39.4 +fqdn==1.5.1 +gast==0.3.3; python_version<='3.8' +google-auth-oauthlib==0.4.6; python_version<='3.8' +google-auth==1.35.0; python_version<='3.8' +google-pasta==0.2.0; python_version<='3.8' +graphviz==0.20.1 +grpcio==1.54.2; python_version<='3.8' +h5py==2.10.0; python_version<='3.8' +idna==3.4 +importlib-metadata==6.6.0 +importlib-resources==5.12.0; python_version<='3.8' +ipykernel==6.23.1 +ipython-genutils==0.2.0 +ipython==8.12.2; python_version<='3.8' +ipython==8.13.2; '3.9'<=python_version +ipywidgets==8.0.6 +isoduration==20.11.0 +jedi==0.18.2 +joblib==1.2.0 +jsonpointer==2.3 +jsonschema==4.17.3 +jupyter-console==6.6.3 +jupyter-events==0.6.3 +jupyter==1.0.0 +jupyter_client==8.2.0 +jupyter_core==5.3.0 +jupyter_server==2.5.0 +jupyter_server_terminals==0.4.4 +jupyterlab-pygments==0.2.2 +jupyterlab-widgets==3.0.7 +kiwisolver==1.4.4 +lightgbm==3.3.5 +llvmlite==0.40.0 +matplotlib-inline==0.1.6 +matplotlib==3.5.3 +mistune==2.0.5 +mpmath==1.3.0; '3.9'<=python_version +nbclassic==1.0.0 +nbclient==0.7.4 +nbconvert==7.4.0 +nbformat==5.8.0 +nest-asyncio==1.5.6 +networkx==3.1; '3.9'<=python_version +notebook==6.5.4 +notebook_shim==0.2.3 +numba==0.57.0 +numpy==1.23.5; python_version<='3.8' +numpy==1.24.3; '3.9'<=python_version +oauthlib==3.2.2; python_version<='3.8' +opt-einsum==3.3.0; python_version<='3.8' +packaging==23.1 +pandas==2.0.1 +pandocfilters==1.5.0 +parso==0.8.3 +patsy==0.5.3 +pexpect==4.8.0 +pickleshare==0.7.5 +pkgutil_resolve_name==1.3.10; python_version<='3.8' +platformdirs==3.5.1 +prometheus-client==0.16.0 +prompt-toolkit==3.0.38 +protobuf==3.20.3; python_version<='3.8' +psutil==5.9.5 +ptyprocess==0.7.0 +pure-eval==0.2.2 +pyasn1-modules==0.3.0; python_version<='3.8' +pyasn1==0.5.0; python_version<='3.8' +pycparser==2.21 +pydot==1.4.2; '3.9'<=python_version +pyparsing==3.0.9 +pyrsistent==0.19.3 +python-dateutil==2.8.2 +python-json-logger==2.0.7 +pytz==2023.3 +pyzmq==25.0.2 +qtconsole==5.4.3 +requests-oauthlib==1.3.1; python_version<='3.8' +requests==2.30.0; python_version<='3.8' +rfc3339-validator==0.1.4 +rfc3986-validator==0.1.1 +rsa==4.9; python_version<='3.8' +scikit-learn==1.2.2 +scipy==1.10.1; '3.9'<=python_version +scipy==1.4.1; python_version<='3.8' +seaborn==0.12.2 +shap==0.41.0 +six==1.16.0 +slicer==0.0.7 +sniffio==1.3.0 +soupsieve==2.4.1 +sparse==0.14.0 +stack-data==0.6.2 +statsmodels==0.14.0 +sympy==1.12; '3.9'<=python_version +tensorboard-plugin-wit==1.8.1; python_version<='3.8' +tensorboard==2.2.2; python_version<='3.8' +tensorflow-estimator==2.2.0; python_version<='3.8' +tensorflow==2.2.0; python_version<='3.8' +termcolor==2.3.0; python_version<='3.8' +terminado==0.17.1 +threadpoolctl==3.1.0 +tinycss2==1.2.1 +tornado==6.3.2 +tqdm==4.65.0 +traitlets==5.9.0 +typing_extensions==4.5.0 +tzdata==2023.3 +uri-template==1.2.0 +urllib3==2.0.2; python_version<='3.8' +wcwidth==0.2.6 +webcolors==1.13 +webencodings==0.5.1 +websocket-client==1.5.1 +widgetsnbextension==4.0.7 +wrapt==1.15.0; python_version<='3.8' +xgboost==1.7.5 +zipp==3.15.0 \ No newline at end of file diff --git a/lkg.txt b/lkg.txt new file mode 100644 index 000000000..dd79c8c59 --- /dev/null +++ b/lkg.txt @@ -0,0 +1,89 @@ +Keras-Applications==1.0.8; python_version<='3.8' +Keras-Preprocessing==1.1.2; python_version<='3.8' +Keras==2.3.1; python_version<='3.8' +Markdown==3.4.3; python_version<='3.8' +MarkupSafe==2.1.2; python_version<='3.8' +Pillow==9.5.0 +PyYAML==6.0; python_version<='3.8' +Werkzeug==2.2.3; python_version<='3.7' +Werkzeug==2.3.4; python_version=='3.8' +absl-py==1.4.0; python_version<='3.8' +argcomplete==3.0.8; '3.9'<=python_version and platform_system=='Windows' +astunparse==1.6.3; python_version<='3.8' +cachetools==4.2.4; python_version<='3.8' +certifi==2023.5.7; python_version<='3.8' +charset-normalizer==3.1.0; python_version<='3.8' +click==8.1.3; '3.9'<=python_version and platform_system=='Windows' +cloudpickle==2.2.1 +colorama==0.4.6; platform_system=='Windows' +cycler==0.11.0 +dowhy==0.8 +fonttools==4.38.0; python_version<='3.7' +fonttools==4.39.4; '3.8'<=python_version +gast==0.3.3; python_version<='3.8' +google-auth-oauthlib==0.4.6; python_version<='3.8' +google-auth==1.35.0; python_version<='3.8' +google-pasta==0.2.0; python_version<='3.8' +graphviz==0.20.1 +grpcio==1.54.0; python_version<='3.8' +h5py==2.10.0; python_version<='3.8' +idna==3.4; python_version<='3.8' +importlib-metadata==6.6.0; python_version<='3.8' +joblib==1.2.0 +kiwisolver==1.4.4 +lightgbm==3.3.5 +llvmlite==0.39.1; python_version<='3.7' +llvmlite==0.40.0; '3.8'<=python_version +matplotlib==3.5.3 +mpmath==1.3.0 +networkx==2.6.3; python_version<='3.7' +networkx==3.1; '3.8'<=python_version +numba==0.56.4; python_version<='3.7' +numba==0.57.0; '3.8'<=python_version +numpy==1.18.5; python_version<='3.7' +numpy==1.23.5; '3.8'<=python_version +oauthlib==3.2.2; python_version<='3.8' +opt-einsum==3.3.0; python_version<='3.8' +packaging==23.1 +pandas==1.3.5; python_version<='3.7' +pandas==2.0.1; '3.8'<=python_version +patsy==0.5.3 +pipx==1.2.0; '3.9'<=python_version and platform_system=='Windows' +protobuf==3.20.3 +pyasn1-modules==0.3.0; python_version<='3.8' +pyasn1==0.5.0; python_version<='3.8' +pydot==1.4.2 +pyparsing==3.0.9 +python-dateutil==2.8.2 +pytz==2023.3 +requests-oauthlib==1.3.1; python_version<='3.8' +requests==2.30.0; python_version<='3.8' +rsa==4.9; python_version<='3.8' +scikit-learn==1.0.2; python_version<='3.7' +scikit-learn==1.2.2; '3.8'<=python_version +scipy==1.10.1; '3.9'<=python_version +scipy==1.4.1; python_version=='3.8' +scipy==1.7.3; python_version<='3.7' +shap==0.41.0 +six==1.16.0 +slicer==0.0.7 +sparse==0.13.0; python_version<='3.7' +sparse==0.14.0; '3.8'<=python_version +statsmodels==0.13.5; python_version<='3.7' +statsmodels==0.14.0; '3.8'<=python_version +sympy==1.10.1; python_version<='3.7' +sympy==1.12; '3.8'<=python_version +tensorboard-plugin-wit==1.8.1; python_version<='3.8' +tensorboard==2.2.2; python_version<='3.8' +tensorflow-estimator==2.2.0; python_version<='3.8' +tensorflow==2.2.0; python_version=='3.8' +tensorflow==2.2.3; python_version<='3.7' +termcolor==2.3.0; python_version<='3.8' +threadpoolctl==3.1.0 +tqdm==4.65.0 +typing_extensions==4.5.0; python_version<='3.7' +tzdata==2023.3; '3.8'<=python_version +urllib3==2.0.2; python_version<='3.8' +userpath==1.8.0; '3.9'<=python_version and platform_system=='Windows' +wrapt==1.15.0; python_version<='3.8' +zipp==3.15.0; python_version<='3.8' \ No newline at end of file diff --git a/notebooks/AutomatedML/Automated Machine Learning For EconML.ipynb b/notebooks/AutomatedML/Automated Machine Learning For EconML.ipynb index cd000b974..3c7a34f7d 100644 --- a/notebooks/AutomatedML/Automated Machine Learning For EconML.ipynb +++ b/notebooks/AutomatedML/Automated Machine Learning For EconML.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Copyright (c) Microsoft Corporation. All rights reserved.\n", + "Copyright (c) PyWhy contributors. All rights reserved.\n", "\n", "Licensed under the MIT License." ] diff --git a/notebooks/Causal Forest and Orthogonal Random Forest Examples.ipynb b/notebooks/Causal Forest and Orthogonal Random Forest Examples.ipynb index 443f3240a..673c669ea 100644 --- a/notebooks/Causal Forest and Orthogonal Random Forest Examples.ipynb +++ b/notebooks/Causal Forest and Orthogonal Random Forest Examples.ipynb @@ -1510,7 +1510,7 @@ "\n", "if not os.path.isfile(file_name):\n", " print(\"Downloading file (this might take a few seconds)...\")\n", - " urllib.request.urlretrieve(\"https://msalicedatapublic.blob.core.windows.net/datasets/OrangeJuice/oj_large.csv\", file_name)\n", + " urllib.request.urlretrieve(\"https://msalicedatapublic.z5.web.core.windows.net/datasets/OrangeJuice/oj_large.csv\", file_name)\n", "oj_data = pd.read_csv(file_name)\n", "oj_data.head()" ] diff --git a/notebooks/CustomerScenarios/Case Study - Customer Segmentation at An Online Media Company - EconML + DoWhy.ipynb b/notebooks/CustomerScenarios/Case Study - Customer Segmentation at An Online Media Company - EconML + DoWhy.ipynb index 387d73710..33e9906d5 100644 --- a/notebooks/CustomerScenarios/Case Study - Customer Segmentation at An Online Media Company - EconML + DoWhy.ipynb +++ b/notebooks/CustomerScenarios/Case Study - Customer Segmentation at An Online Media Company - EconML + DoWhy.ipynb @@ -2,19 +2,20 @@ "cells": [ { "cell_type": "markdown", + "metadata": {}, "source": [ "" - ], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "# Customer Segmentation: Estimate Individualized Responses to Incentives\n", "\n", "Nowadays, business decision makers rely on estimating the causal effect of interventions to answer what-if questions about shifts in strategy, such as promoting specific product with discount, adding new features to a website or increasing investment from a sales team. However, rather than learning whether to take action for a specific intervention for all users, people are increasingly interested in understanding the different responses from different users to the two alternatives. Identifying the characteristics of users having the strongest response for the intervention could help make rules to segment the future users into different groups. This can help optimize the policy to use the least resources and get the most profit.\n", "\n", - "In this case study, we will use a personalized pricing example to explain how the [EconML](https://aka.ms/econml) and [DoWhy](https://github.com/microsoft/dowhy) libraries could fit into this problem and provide robust and reliable causal solutions.\n", + "In this case study, we will use a personalized pricing example to explain how the [EconML](https://aka.ms/econml) and [DoWhy](https://github.com/py-why/dowhy) libraries could fit into this problem and provide robust and reliable causal solutions.\n", "\n", "### Summary\n", "\n", @@ -32,11 +33,11 @@ "8. [Conclusions](#conclusion)\n", "\n", "\n" - ], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "# Background \n", "\n", @@ -45,42 +46,42 @@ "The global online media market is growing fast over the years. Media companies are always interested in attracting more users into the market and encouraging them to buy more songs or become members. In this example, we'll consider a scenario where one experiment a media company is running is to give small discount (10%, 20% or 0) to their current users based on their income level in order to boost the likelihood of their purchase. The goal is to understand the **heterogeneous price elasticity of demand** for people with different income level, learning which users would respond most strongly to a small discount. Furthermore, their end goal is to make sure that despite decreasing the price for some consumers, the demand is raised enough to boost the overall revenue.\n", "\n", "The EconML and DoWhy libraries complement each other in implementing this solution. On one hand, the DoWhy library can help [build a causal model, indentify the causal effect](#identify) and [test causal assumptions](#robustness). On the other hand, EconML’s `DML` based estimators can be used to take the discount variation in existing data, along with a rich set of user features, to [estimate heterogeneous price sensitivities](#estimate) that vary with multiple customer features. Then, the `SingleTreeCateInterpreter` provides a [presentation-ready summary](#interpret) of the key features that explain the biggest differences in responsiveness to a discount, and the `SingleTreePolicyInterpreter` recommends a [policy](#policy) on who should receive a discount in order to increase revenue (not only demand), which could help the company to set an optimal price for those users in the future." - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": 2, + "metadata": {}, + "outputs": [], "source": [ - "# Some imports to get us started\r\n", - "import warnings\r\n", - "warnings.simplefilter('ignore')\r\n", - "\r\n", - "# Utilities\r\n", - "import os\r\n", - "import urllib.request\r\n", - "import numpy as np\r\n", - "import pandas as pd\r\n", - "from networkx.drawing.nx_pydot import to_pydot\r\n", - "from IPython.display import Image, display\r\n", - "\r\n", - "# Generic ML imports\r\n", - "from sklearn.preprocessing import PolynomialFeatures\r\n", - "from sklearn.ensemble import GradientBoostingRegressor\r\n", - "\r\n", - "# EconML imports\r\n", - "from econml.dml import LinearDML, CausalForestDML\r\n", - "from econml.cate_interpreter import SingleTreeCateInterpreter, SingleTreePolicyInterpreter\r\n", - "\r\n", - "import matplotlib.pyplot as plt\r\n", - "\r\n", + "# Some imports to get us started\n", + "import warnings\n", + "warnings.simplefilter('ignore')\n", + "\n", + "# Utilities\n", + "import os\n", + "import urllib.request\n", + "import numpy as np\n", + "import pandas as pd\n", + "from networkx.drawing.nx_pydot import to_pydot\n", + "from IPython.display import Image, display\n", + "\n", + "# Generic ML imports\n", + "from sklearn.preprocessing import PolynomialFeatures\n", + "from sklearn.ensemble import GradientBoostingRegressor\n", + "\n", + "# EconML imports\n", + "from econml.dml import LinearDML, CausalForestDML\n", + "from econml.cate_interpreter import SingleTreeCateInterpreter, SingleTreePolicyInterpreter\n", + "\n", + "import matplotlib.pyplot as plt\n", + "\n", "%matplotlib inline" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "# Data \n", "\n", @@ -127,46 +128,26 @@ "Y &= \\gamma(X) \\cdot T + \\beta(X,W)\n", "\\end{align}\n", "\n" - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": 3, + "metadata": {}, + "outputs": [], "source": [ - "# Import the sample pricing data\r\n", - "file_url = \"https://msalicedatapublic.blob.core.windows.net/datasets/Pricing/pricing_sample.csv\"\r\n", + "# Import the sample pricing data\n", + "file_url = \"https://msalicedatapublic.z5.web.core.windows.net/datasets/Pricing/pricing_sample.csv\"\n", "train_data = pd.read_csv(file_url)" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": 4, - "source": [ - "# Data sample\r\n", - "train_data.head()" - ], + "metadata": {}, "outputs": [ { - "output_type": "execute_result", "data": { - "text/plain": [ - " account_age age avg_hours days_visited friends_count has_membership \\\n", - "0 3 53 1.834234 2 8 1 \n", - "1 5 54 7.171411 7 9 0 \n", - "2 3 33 5.351920 6 9 0 \n", - "3 2 34 6.723551 0 8 0 \n", - "4 4 30 2.448247 5 8 1 \n", - "\n", - " is_US songs_purchased income price demand \n", - "0 1 4.903237 0.960863 1.0 3.917117 \n", - "1 1 3.330161 0.732487 1.0 11.585706 \n", - "2 1 3.036203 1.130937 1.0 24.675960 \n", - "3 1 7.911926 0.929197 1.0 6.361776 \n", - "4 0 7.148967 0.533527 0.8 12.624123 " - ], "text/html": [ "
\n", "