diff --git a/.all-contributorsrc b/.all-contributorsrc index bc6e83c6f7b..5b4285e8946 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -209,7 +209,9 @@ "avatar_url": "https://avatars.githubusercontent.com/u/54197164?v=4", "profile": "https://github.com/achieveordie", "contributions": [ - "test" + "bug", + "code", + "test" ] }, { @@ -285,6 +287,14 @@ "tutorial" ] }, + { + "login": "vnicholson1", + "name": "Vincent Nicholson", + "profile": "https://github.com/vnicholson1", + "contributions": [ + "code" + ] + }, { "login": "lnthach", "name": "Thach Le Nguyen", @@ -309,6 +319,14 @@ "tutorial" ] }, + { + "login": "Riyabelle25", + "name": "Riya Elizabeth John", + "avatar_url": "https://avatars.githubusercontent.com/u/55790848?v=4", + "contributions": [ + "code" + ] + }, { "login": "ninfueng", "name": "Ninnart Fuengfusin", @@ -2376,6 +2394,15 @@ "code" ] }, + { + "login": "sz85512678", + "name": "Zhen Shao", + "avatar_url": "https://avatars.githubusercontent.com/sz85512678", + "profile": "https://github.com/sz85512678", + "contributions": [ + "code" + ] + }, { "login": "Vasudeva-bit", "name": "Vasudeva Kilaru", @@ -2421,6 +2448,16 @@ "avatar_url": "https://avatars.githubusercontent.com/u/19709277?v=4", "profile": "https://github.com/adamkells", "contributions": [ + "test" + ] + }, + { + "login": "YHallouard", + "name": "Yann Hallouard", + "avatar_url": "https://avatars.githubusercontent.com/YHallouard", + "profile": "https://www.linkedin.com/in/yann-hallouard/", + "contributions": [ + "code", "test" ] }, @@ -2442,6 +2479,101 @@ "bug", "code" ] + }, + { + "login": "rahulporuri", + "name": "Poruri Sai Rahul", + "avatar_url": "https://avatars.githubusercontent.com/u/1926457?v=4", + "profile": "https://github.com/rahulporuri", + "contributions": [ + "doc" + ] + }, + { + "login": "fspinna", + "name": "Francesco Spinnato", + "avatar_url": "https://avatars.githubusercontent.com/u/35352023?v=4", + "profile": "https://github.com/fspinna", + "contributions": [ + "code" + ] + }, + { + "login": "sbuse", + "name": "Simon B.", + "avatar_url": "https://avatars.githubusercontent.com/u/24408707?v=4", + "profile": "https://github.com/sbuse", + "contributions": [ + "code" + ] + }, + { + "login": "sd2k", + "name": "Ben Sully", + "avatar_url": "https://avatars.githubusercontent.com/u/5464991?&v=4", + "profile": "https://github.com/sd2k", + "contributions": [ + "bug", + "code" + ] + }, + { + "login": "wayneadams", + "name": "Wayne Adams", + "avatar_url": "https://avatars.githubusercontent.com/u/15034841?s=400&u=d717e9945910bcc844c5e64cd56d570c6cc4e8e6&v=4", + "profile": "https://github.com/wayneadams", + "contributions": [ + "doc" + ] + }, + { + "login": "sssilvar", + "name": "Santiago Smith Silva", + "avatar_url": "https://avatars.githubusercontent.com/u/16252054?v=4", + "profile": "https://github.com/sssilvar", + "contributions": [ + "code" + ] + }, + { + "login": "DManowitz", + "name": "David Manowitz", + "avatar_url": "https://avatars.githubusercontent.com/u/66927103?v=4", + "profile": "https://github.com/DManowitz", + "contributions": [ + "bug", + "maintenance" + ] + }, + { + "login": "ninedigits", + "name": "Max Frohlich", + "avatar_url": "https://avatars.githubusercontent.com/u/16393653?v=4", + "profile": "https://www.linkedin.com/in/maxfrohlich/", + "contributions": [ + "code", + "ideas", + "maintenance" + ] + }, + { + "login": "steenrotsman", + "name": "Stijn J. Rotman", + "avatar_url": "https://avatars.githubusercontent.com/u/78110080?s=400&v=4", + "profile": "https://github.com/steenrotsman", + "contributions": [ + "code", + "doc" + ] + }, + { + "login": "tvdboom", + "name": "Mavs", + "avatar_url": "https://avatars.githubusercontent.com/u/32366550?v=4", + "profile": "https://github.com/tvdboom", + "contributions": [ + "code" + ] } ] } diff --git a/.binder/Dockerfile b/.binder/Dockerfile index e7cbaef9a80..8932745f889 100644 --- a/.binder/Dockerfile +++ b/.binder/Dockerfile @@ -1,9 +1,7 @@ # This Dockerfile is used to build sktime when launching binder. # Find out more at: https://mybinder.readthedocs.io/en/latest/index.html -# Load jupyter python 3.8 image -# 3.8 is the highest currently supported version we can use -FROM jupyter/scipy-notebook:python-3.8.8 +FROM jupyter/scipy-notebook:python-3.11.6 # Set up user to avoid running as root ARG NB_USER ARG NB_UID diff --git a/.github/actions/test-base/action.yml b/.github/actions/test-base/action.yml index c87d95235b9..5e6fc1196b9 100644 --- a/.github/actions/test-base/action.yml +++ b/.github/actions/test-base/action.yml @@ -15,23 +15,41 @@ runs: steps: - name: repository checkout step uses: actions/checkout@v4 + - name: update tracking reference step run: git remote set-branches origin main shell: bash + - name: shallow clone update step run: git fetch --depth 1 shell: bash + - name: python environment step uses: actions/setup-python@v4 with: python-version: ${{ inputs.python-version-identifier }} - - name: dependencies installation step + + - name: Display Python version + run: python -c "import sys; print(sys.version)" + shell: bash + + - name: Install sktime and dependencies run: python3 -m pip install .[tests] shell: bash + + - name: Show dependencies + run: python -m pip list + shell: bash + + - name: Show available branches + run: git branch -a + shell: bash + - name: unit test step - run: python3 -m pytest sktime/base --matrixdesign ${{ inputs.sub-sample-estimators }} --only_changed_modules ${{ inputs.test-affected-estimators }} + run: >- + python3 + -m pytest + sktime/base + --matrixdesign ${{ inputs.sub-sample-estimators }} + --only_changed_modules ${{ inputs.test-affected-estimators }} shell: bash - - name: test coverage step - uses: codecov/codecov-action@v3 - with: - flags: ${{ inputs.python-version-identifier }},base diff --git a/.github/actions/test-component/action.yml b/.github/actions/test-component/action.yml index 4b154aa1f90..3c1d72eac2e 100644 --- a/.github/actions/test-component/action.yml +++ b/.github/actions/test-component/action.yml @@ -1,5 +1,5 @@ -name: test specific sktime component -description: run unit tests on individual component of sktime framework +name: test +description: test inputs: sktime-component-identifier: description: name of sktime component @@ -18,23 +18,41 @@ runs: steps: - name: repository checkout step uses: actions/checkout@v4 + - name: update tracking reference step run: git remote set-branches origin main shell: bash + - name: shallow clone update step run: git fetch --depth 1 shell: bash + - name: python environment step uses: actions/setup-python@v4 with: python-version: ${{ inputs.python-version-identifier }} - - name: dependencies installation step + + - name: Display Python version + run: python -c "import sys; print(sys.version)" + shell: bash + + - name: Install sktime and dependencies run: python3 -m pip install .[${{ inputs.sktime-component-identifier }},tests] shell: bash + + - name: Show dependencies + run: python -m pip list + shell: bash + + - name: Show available branches + run: git branch -a + shell: bash + - name: unit test step - run: python3 -m pytest sktime/${{ inputs.sktime-component-identifier }} --matrixdesign ${{ inputs.sub-sample-estimators }} --only_changed_modules ${{ inputs.test-affected-estimators }} + run: >- + python3 + -m pytest + sktime/${{ inputs.sktime-component-identifier }} + --matrixdesign ${{ inputs.sub-sample-estimators }} + --only_changed_modules ${{ inputs.test-affected-estimators }} shell: bash - - name: test coverage step - uses: codecov/codecov-action@v3 - with: - flags: ${{ inputs.python-version-identifier }},${{ inputs.sktime-component-identifier }} diff --git a/.github/actions/validate-extra/action.yml b/.github/actions/test-install/action.yml similarity index 94% rename from .github/actions/validate-extra/action.yml rename to .github/actions/test-install/action.yml index 4358b31b154..f5bf2b58645 100644 --- a/.github/actions/validate-extra/action.yml +++ b/.github/actions/test-install/action.yml @@ -1,4 +1,4 @@ -name: test specific sktime extra +name: test install description: install individual extra of sktime inputs: sktime-extra-identifier: @@ -12,10 +12,12 @@ runs: steps: - name: repository checkout step uses: actions/checkout@v4 + - name: python environment step uses: actions/setup-python@v4 with: python-version: ${{ inputs.python-version-identifier }} + - name: extra installation step run: python3 -m pip install .[${{ inputs.sktime-extra-identifier }}] shell: bash diff --git a/.github/workflows/cancel.yml b/.github/workflows/cancel.yml index 685c74e8dec..3372a1100a8 100644 --- a/.github/workflows/cancel.yml +++ b/.github/workflows/cancel.yml @@ -8,6 +8,6 @@ jobs: cancel: runs-on: ubuntu-latest steps: - - uses: styfle/cancel-workflow-action@0.12.0 + - uses: styfle/cancel-workflow-action@0.12.1 with: workflow_id: ${{ github.event.workflow.id }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0ee0b597340..a08da3e6bed 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,14 +13,14 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 - id: file_changes uses: trilom/file-changes-action@v1.2.4 with: output: " " - name: List changed files run: echo '${{ steps.file_changes.outputs.files}}' - - uses: pre-commit/action@v3.0.0 + - uses: pre-commit/action@v3.0.1 with: extra_args: --files ${{ steps.file_changes.outputs.files}} - name: Check for missing init files @@ -33,7 +33,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.9 - name: Install dependencies @@ -44,13 +44,30 @@ jobs: run: build_tools/run_examples.sh shell: bash + run-blogpost-examples: + needs: code-quality + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: 3.9 + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install .[all_extras,binder,dev,mlflow] + - name: Run example notebooks + run: build_tools/run_blogposts.sh + shell: bash + test-nodevdeps: needs: code-quality runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.9 - name: Display Python version @@ -70,7 +87,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.9 - name: Display Python version @@ -97,7 +114,7 @@ jobs: - run: git fetch --depth 1 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.9 @@ -120,7 +137,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.9 - name: Display Python version @@ -147,7 +164,7 @@ jobs: - run: git fetch --depth 1 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.9 - name: Display Python version @@ -167,7 +184,7 @@ jobs: run: make PYTESTOPTIONS="--cov --cov-report=xml --only_cython_estimators=True --matrixdesign=False --timeout=600" test_check_suite - name: Publish code coverage - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 test-full: needs: test-nosoftdeps @@ -185,7 +202,7 @@ jobs: - run: git fetch --depth 1 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -194,7 +211,7 @@ jobs: - name: Install sktime and dependencies run: | - python -m pip install .[all_extras_pandas2,dev] --no-cache-dir + python -m pip install .[all_extras_pandas2,dev,dl] --no-cache-dir - name: Show dependencies run: python -m pip list @@ -203,10 +220,10 @@ jobs: run: git branch -a - name: Run tests - run: make test + run: make test_without_datasets - name: Publish code coverage - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 test-unix-pandas1: needs: test-nosoftdeps @@ -223,7 +240,7 @@ jobs: - run: git fetch --depth 1 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -241,7 +258,7 @@ jobs: run: git branch -a - name: Run tests - run: make test + run: make test_without_datasets - name: Publish code coverage - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 diff --git a/.github/workflows/test_all.yml b/.github/workflows/test_all.yml index c30a1547d36..3cdc7ffab96 100644 --- a/.github/workflows/test_all.yml +++ b/.github/workflows/test_all.yml @@ -1,17 +1,17 @@ -name: test all workflow +name: test all on: schedule: - cron: 0 0 * * 0 workflow_dispatch: jobs: code_quality: - name: validate code quality + name: code quality runs-on: ubuntu-latest steps: - name: repository checkout step uses: actions/checkout@v4 - name: python environment step - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.8" - name: install pre-commit @@ -23,7 +23,7 @@ jobs: shell: bash test_base: needs: code_quality - name: test base framework + name: base strategy: fail-fast: false matrix: @@ -47,9 +47,13 @@ jobs: python-version-identifier: ${{ matrix.python-version }} sub-sample-estimators: "False" test-affected-estimators: "False" - test_components: + - name: upload coverage + uses: codecov/codecov-action@v4 + with: + flags: ${{ matrix.operating-system }},${{ matrix.python-version }},base,complete + test_module: needs: code_quality - name: test individual components + name: module strategy: fail-fast: false matrix: @@ -84,3 +88,59 @@ jobs: python-version-identifier: ${{ matrix.python-version }} sub-sample-estimators: "False" test-affected-estimators: "False" + - name: upload coverage + uses: codecov/codecov-action@v4 + with: + flags: ${{ matrix.operating-system }},${{ matrix.python-version }},${{ matrix.sktime-component }},complete + test_other: + needs: code_quality + name: other + strategy: + fail-fast: false + matrix: + python-version: + - "3.8" + - "3.9" + - "3.10" + - "3.11" + - "3.12" + operating-system: + - macos-latest + - ubuntu-latest + - windows-latest + runs-on: ${{ matrix.operating-system }} + steps: + - name: checkout pull request branch + uses: actions/checkout@v4 + - name: update local git tracking reference + run: git remote set-branches origin main + - name: update local shallow clone + run: git fetch --depth 1 + - name: create python virtual environment + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: install core, test and all soft dependencies + run: python3 -m pip install .[all_extras_pandas2,tests] + - name: run unit tests + run: >- + python3 + -m pytest + sktime + --ignore sktime/base + --ignore sktime/datasets + --ignore sktime/alignment + --ignore sktime/annotation + --ignore sktime/classification + --ignore sktime/clustering + --ignore sktime/forecasting + --ignore sktime/networks + --ignore sktime/param_est + --ignore sktime/regression + --ignore sktime/transformations + --matrixdesign False + --only_changed_modules False + - name: upload coverage + uses: codecov/codecov-action@v4 + with: + flags: ${{ matrix.operating-system }},${{ matrix.python-version }},components_without_extras,complete diff --git a/.github/workflows/test_base.yml b/.github/workflows/test_base.yml index 921ede71977..0684c735f04 100644 --- a/.github/workflows/test_base.yml +++ b/.github/workflows/test_base.yml @@ -1,24 +1,25 @@ -name: test base workflow +name: base on: workflow_call: jobs: detect: - name: check for changes in base framework + name: detect runs-on: ubuntu-latest permissions: pull-requests: read outputs: base: ${{ steps.filter.outputs.base }} steps: - - uses: dorny/paths-filter@v2 + - uses: dorny/paths-filter@v3 id: filter with: filters: | base: + - pyproject.toml - sktime/base/** test: needs: detect - name: test base framework + name: if: ${{ needs.detect.outputs.base == 'true' }} strategy: fail-fast: false @@ -37,9 +38,15 @@ jobs: steps: - name: checkout pull request branch uses: actions/checkout@v4 + - name: run tests on python ${{ matrix.python-version }} uses: ./.github/actions/test-base with: python-version-identifier: ${{ matrix.python-version }} sub-sample-estimators: "True" test-affected-estimators: "True" + + - name: upload coverage + uses: codecov/codecov-action@v4 + with: + flags: ${{ matrix.operating-system }},${{ matrix.python-version }},base,incomplete diff --git a/.github/workflows/test_code_quality.yml b/.github/workflows/test_code_quality.yml deleted file mode 100644 index 20b2eb76be2..00000000000 --- a/.github/workflows/test_code_quality.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: validate code quality workflow -on: - pull_request: - branches: - - main -jobs: - code_quality: - name: test code quality - runs-on: ubuntu-latest - steps: - - name: repository checkout step - uses: actions/checkout@v4 - - name: python environment step - uses: actions/setup-python@v4 - with: - python-version: "3.8" - - name: install pre-commit - run: python3 -m pip install pre-commit - - id: changed-files - name: identify modified files - uses: tj-actions/changed-files@v40 - - name: run pre-commit hooks on modified files - run: pre-commit run --color always --files ${{ steps.changed-files.outputs.all_changed_files }} --show-diff-on-failure - - name: check missing __init__ files - run: build_tools/fail_on_missing_init_files.sh - shell: bash - unit_test_base: - needs: code_quality - name: run unit tests for base framework - uses: ./.github/workflows/test_base.yml - unit_test_components: - needs: code_quality - name: run unit tests for individual components - uses: ./.github/workflows/test_components.yml diff --git a/.github/workflows/test_datasets.yml b/.github/workflows/test_datasets.yml new file mode 100644 index 00000000000..cc0ea1d9d6e --- /dev/null +++ b/.github/workflows/test_datasets.yml @@ -0,0 +1,85 @@ +name: datasets +on: + schedule: + - cron: 0 0 1 * * + workflow_call: + workflow_dispatch: +jobs: + test_internal_data: + name: onboard + strategy: + fail-fast: false + matrix: + python-version: + - "3.8" + - "3.9" + - "3.10" + - "3.11" + - "3.12" + operating-system: + - macos-latest + - ubuntu-latest + - windows-latest + runs-on: ${{ matrix.operating-system }} + steps: + - name: repository checkout step + uses: actions/checkout@v4 + - name: update tracking reference step + run: git remote set-branches origin main + shell: bash + - name: shallow clone update step + run: git fetch --depth 1 + shell: bash + - name: python environment step + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: dependencies installation step + run: python3 -m pip install .[tests] + shell: bash + - name: unit test step + run: python3 -m pytest -m "not datadownload" sktime/datasets + shell: bash + - name: upload coverage step + uses: codecov/codecov-action@v4 + with: + flags: ${{ matrix.operating-system }},${{ matrix.python-version }},datasets + test_external_data: + name: downloads + strategy: + fail-fast: false + matrix: + python-version: + - "3.8" + - "3.9" + - "3.10" + - "3.11" + - "3.12" + operating-system: + - macos-latest + - ubuntu-latest + - windows-latest + runs-on: ${{ matrix.operating-system }} + steps: + - name: repository checkout step + uses: actions/checkout@v4 + - name: update tracking reference step + run: git remote set-branches origin main + shell: bash + - name: shallow clone update step + run: git fetch --depth 1 + shell: bash + - name: python environment step + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: dependencies installation step + run: python3 -m pip install .[tests] + shell: bash + - name: unit test step + run: python3 -m pytest -m "datadownload" sktime/datasets + shell: bash + - name: upload coverage step + uses: codecov/codecov-action@v4 + with: + flags: ${{ matrix.operating-system }},${{ matrix.python-version }},datasets diff --git a/.github/workflows/validate_extras.yml b/.github/workflows/test_install.yml similarity index 84% rename from .github/workflows/validate_extras.yml rename to .github/workflows/test_install.yml index 1f0f8225904..f2820fcee9a 100644 --- a/.github/workflows/validate_extras.yml +++ b/.github/workflows/test_install.yml @@ -1,16 +1,12 @@ -name: extras validation +name: test softdep set install on: - pull_request: - branches: - - main - paths: - - pyproject.toml schedule: - cron: 0 0 1 * * + workflow_call: workflow_dispatch: jobs: test_installations: - name: extras installation + name: install strategy: fail-fast: false matrix: @@ -25,6 +21,7 @@ jobs: - ubuntu-latest - windows-latest sktime-extra: + - all_extras_pandas2 - alignment - annotation - classification @@ -39,7 +36,7 @@ jobs: - name: checkout pull request branch uses: actions/checkout@v4 - name: install ${{ matrix.sktime-extra }} extra on python ${{ matrix.python-version }} - uses: ./.github/actions/validate-extra + uses: ./.github/actions/test-install with: sktime-extra-identifier: ${{ matrix.sktime-extra }} python-version-identifier: ${{ matrix.python-version }} diff --git a/.github/workflows/test_main.yml b/.github/workflows/test_main.yml new file mode 100644 index 00000000000..c9a6281f4e7 --- /dev/null +++ b/.github/workflows/test_main.yml @@ -0,0 +1,67 @@ +name: CI +on: + pull_request: + branches: + - main +jobs: + code_quality: + name: code quality + runs-on: ubuntu-latest + steps: + - name: repository checkout step + uses: actions/checkout@v4 + - name: python environment step + uses: actions/setup-python@v5 + with: + python-version: "3.8" + - name: install pre-commit + run: python3 -m pip install pre-commit + - id: changed-files + name: identify modified files + uses: tj-actions/changed-files@v42 + - name: run pre-commit hooks on modified files + run: pre-commit run --color always --files ${{ steps.changed-files.outputs.all_changed_files }} --show-diff-on-failure + - name: check missing __init__ files + run: build_tools/fail_on_missing_init_files.sh + shell: bash + detect: + needs: code_quality + name: detect changes + runs-on: ubuntu-latest + permissions: + pull-requests: read + outputs: + datasets: ${{ steps.filter.outputs.datasets }} + pyproject: ${{ steps.filter.outputs.pyproject }} + steps: + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + datasets: + - sktime/base/** + - sktime/datasets/** + pyproject: + - pyproject.toml + test: + needs: detect + name: install + if: ${{ needs.detect.outputs.pyproject == 'true' }} + uses: ./.github/workflows/test_install.yml + unit_test_base: + needs: code_quality + name: base + uses: ./.github/workflows/test_base.yml + unit_test_module: + needs: code_quality + name: module + uses: ./.github/workflows/test_module.yml + unit_test_other: + needs: code_quality + name: other + uses: ./.github/workflows/test_other.yml + unit_test_datasets: + needs: detect + name: datasets + if: ${{ needs.detect.outputs.datasets == 'true' }} + uses: ./.github/workflows/test_datasets.yml diff --git a/.github/workflows/test_components.yml b/.github/workflows/test_module.yml similarity index 57% rename from .github/workflows/test_components.yml rename to .github/workflows/test_module.yml index cf66c2a8e15..42ea6cf2739 100644 --- a/.github/workflows/test_components.yml +++ b/.github/workflows/test_module.yml @@ -1,40 +1,58 @@ -name: test individual components workflow +name: test module on: workflow_call: jobs: detect: - name: check for changes in individual components + name: detect runs-on: ubuntu-latest permissions: pull-requests: read outputs: - components: ${{ steps.filter.outputs.changes }} + module_changes: ${{ steps.filter.outputs.changes }} steps: - - uses: dorny/paths-filter@v2 + - uses: dorny/paths-filter@v3 id: filter with: filters: | alignment: + - pyproject.toml + - sktime/base/** - sktime/alignment/** annotation: + - pyproject.toml + - sktime/base/** - sktime/annotation/** classification: + - pyproject.toml + - sktime/base/** - sktime/classification/** clustering: + - pyproject.toml + - sktime/base/** - sktime/clustering/** forecasting: + - pyproject.toml + - sktime/base/** - sktime/forecasting/** networks: + - pyproject.toml + - sktime/base/** - sktime/networks/** param_est: + - pyproject.toml + - sktime/base/** - sktime/param_est/** regression: + - pyproject.toml + - sktime/base/** - sktime/regression/** transformations: + - pyproject.toml + - sktime/base/** - sktime/transformations/** test: needs: detect - name: test specific component + name: strategy: fail-fast: false matrix: @@ -48,15 +66,21 @@ jobs: - macos-latest - ubuntu-latest - windows-latest - sktime-component: ${{ fromJSON(needs.detect.outputs.components) }} + sktime-component: ${{ fromJSON(needs.detect.outputs.module_changes) }} runs-on: ${{ matrix.operating-system }} steps: - name: checkout pull request branch uses: actions/checkout@v4 - - name: run tests for component ${{ matrix.sktime-component }} on python ${{ matrix.python-version }} + + - name: ${{ matrix.sktime-component }}, ${{ matrix.operating-system }}, ${{ matrix.python-version }} uses: ./.github/actions/test-component with: sktime-component-identifier: ${{ matrix.sktime-component }} python-version-identifier: ${{ matrix.python-version }} sub-sample-estimators: "True" test-affected-estimators: "True" + + - name: upload coverage + uses: codecov/codecov-action@v4 + with: + flags: ${{ matrix.operating-system }},${{ matrix.python-version }},${{ matrix.sktime-component }},incomplete diff --git a/.github/workflows/test_other.yml b/.github/workflows/test_other.yml new file mode 100644 index 00000000000..76c1ad5f9fc --- /dev/null +++ b/.github/workflows/test_other.yml @@ -0,0 +1,85 @@ +name: test other +on: + workflow_call: +jobs: + detect: + name: detect + runs-on: ubuntu-latest + permissions: + pull-requests: read + outputs: + other_change: ${{ steps.filter.outputs.other_change }} + steps: + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + other_change: + - pyproject.toml + - sktime/base/** + - sktime/_contrib/** + - sktime/benchmarking/** + - sktime/datatypes/** + - sktime/distances/** + - sktime/dists_kernels/** + - sktime/performance_metrics/** + - sktime/pipeline/** + - sktime/proba/** + - sktime/registry/** + - sktime/series_as_features/** + - sktime/split/** + - sktime/tests/** + - sktime/utils/** + test_module: + needs: detect + name: + if: ${{ needs.detect.outputs.other_change == 'true' }} + strategy: + fail-fast: false + matrix: + python-version: + - "3.8" + - "3.9" + - "3.10" + - "3.11" + - "3.12" + operating-system: + - macos-latest + - ubuntu-latest + - windows-latest + runs-on: ${{ matrix.operating-system }} + steps: + - name: checkout pull request branch + uses: actions/checkout@v4 + - name: update local git tracking reference + run: git remote set-branches origin main + - name: update local shallow clone + run: git fetch --depth 1 + - name: create python virtual environment + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: install core, test and all soft dependencies + run: python3 -m pip install .[all_extras_pandas2,tests] + - name: run unit tests + run: >- + python3 + -m pytest + sktime + --ignore sktime/base + --ignore sktime/datasets + --ignore sktime/alignment + --ignore sktime/annotation + --ignore sktime/classification + --ignore sktime/clustering + --ignore sktime/forecasting + --ignore sktime/networks + --ignore sktime/param_est + --ignore sktime/regression + --ignore sktime/transformations + --matrixdesign True + --only_changed_modules True + - name: upload coverage + uses: codecov/codecov-action@v4 + with: + flags: ${{ matrix.operating-system }},${{ matrix.python-version }},components_without_extras,incomplete diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index c482476a130..4f40c1f6891 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -12,7 +12,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.10' @@ -22,7 +22,7 @@ jobs: python -m build --wheel --sdist --outdir wheelhouse - name: Store wheels - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: wheels path: wheelhouse/* @@ -39,15 +39,18 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: wheels path: wheelhouse + - name: Display downloaded artifacts + run: ls -l wheelhouse + - name: Get wheel filename run: echo "WHEELNAME=$(ls ./wheelhouse/sktime-*none-any.whl)" >> $GITHUB_ENV @@ -55,7 +58,7 @@ jobs: run: python -m pip install "${{ env.WHEELNAME }}[all_extras_pandas2,dev]" - name: Run tests - run: make test + run: make test_without_datasets test_windows_wheels: needs: build_wheels @@ -64,75 +67,31 @@ jobs: strategy: fail-fast: false # to not fail all combinations if just one fail matrix: - include: - # Window 64 bit - - os: windows-latest - python: 38 - python-version: '3.8' - bitness: 64 - platform_id: win_amd64 - - os: windows-latest - python: 39 - python-version: '3.9' - bitness: 64 - platform_id: win_amd64 - - os: windows-latest - python: 310 - python-version: '3.10' - bitness: 64 - platform_id: win_amd64 - - os: windows-latest - python: 311 - python-version: '3.11' - bitness: 64 - platform_id: win_amd64 - - os: windows-latest - python: 312 - python-version: '3.12' - bitness: 64 - platform_id: win_amd64 + os: [windows-latest] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] steps: - uses: actions/checkout@v4 - - uses: conda-incubator/setup-miniconda@v2 + - uses: actions/setup-python@v5 with: - activate-environment: test - auto-update-conda: true python-version: ${{ matrix.python-version }} - channels: anaconda, conda-forge, - - - run: conda --version - - run: which python - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: wheels path: wheelhouse - - name: Install conda libpython - run: conda install -c anaconda -n test -y libpython - - name: Display downloaded artifacts run: ls -l wheelhouse - name: Get wheel filename run: echo "WHEELNAME=$(ls ./wheelhouse/sktime-*none-any.whl)" >> $env:GITHUB_ENV - - name: Activate conda env - run: conda activate test - - name: Install wheel and extras run: python -m pip install "${env:WHEELNAME}[all_extras_pandas2,dev]" - - name: Show conda packages - run: conda list -n test - - - name: Run tests - run: | - mkdir -p testdir/ - cp .coveragerc testdir/ - cp setup.cfg testdir/ - python -m pytest + - name: Run tests # explicit commands as windows does not support make + run: python -m pytest --ignore sktime/datasets upload_wheels: name: Upload wheels to PyPI @@ -140,7 +99,7 @@ jobs: needs: [build_wheels,test_unix_wheels,test_windows_wheels] steps: - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: wheels path: wheelhouse diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3bda1e00104..6e256366205 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,9 +1,10 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: check-added-large-files - args: ["--maxkb=1000"] + args: + - --maxkb=1000 - id: check-case-conflict - id: check-merge-conflict - id: check-symlinks @@ -18,27 +19,26 @@ repos: - id: trailing-whitespace - repo: https://github.com/asottile/pyupgrade - rev: v3.10.1 + rev: v3.15.0 hooks: - id: pyupgrade args: - --py38-plus - repo: https://github.com/pycqa/isort - rev: 5.12.0 + rev: 5.13.2 hooks: - id: isort name: isort - repo: https://github.com/psf/black - rev: 23.7.0 + rev: 23.12.1 hooks: - id: black language_version: python3 - # args: [--line-length 79] - repo: https://github.com/pycqa/flake8 - rev: 6.1.0 + rev: 7.0.0 hooks: - id: flake8 exclude: docs/conf.py @@ -51,28 +51,30 @@ repos: stages: [manual] - repo: https://github.com/nbQA-dev/nbQA - rev: 1.7.0 + rev: 1.7.1 hooks: - id: nbqa-black - args: [--nbqa-mutate, --nbqa-dont-skip-bad-cells] - additional_dependencies: [black==22.3.0] + args: + - --nbqa-dont-skip-bad-cells - id: nbqa-isort - args: [--nbqa-mutate, --nbqa-dont-skip-bad-cells] - additional_dependencies: [isort==5.6.4] + args: + - --nbqa-dont-skip-bad-cells - id: nbqa-flake8 - args: [--nbqa-dont-skip-bad-cells, "--extend-ignore=E402,E203"] - additional_dependencies: [flake8==3.8.3] + args: + - --nbqa-dont-skip-bad-cells + - --extend-ignore=E402,E203 - repo: https://github.com/pycqa/pydocstyle rev: 6.3.0 hooks: - id: pydocstyle - args: ["--config=setup.cfg"] + args: + - --config=setup.cfg # We use the Python version instead of the original version which seems to require Docker # https://github.com/koalaman/shellcheck-precommit - repo: https://github.com/shellcheck-py/shellcheck-py - rev: v0.9.0.5 + rev: v0.9.0.6 hooks: - id: shellcheck name: shellcheck diff --git a/CODEOWNERS b/CODEOWNERS index 0e2122e79af..720a0e57dd3 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,89 +1,14 @@ -# The file lists sktime's algorithm maintainers as specified in GOVERNANCE.md. -# Each line is a file pattern followed by one or more owners. +# The file specifies framework level core developers for automated review requests +# +# Note: historically, this file has been used to maintain a list of +# algorithm maintainers as specified in GOVERNANCE.md. +# This is no longer the case, algorithm maintainers are now +# specified directly in the estimator, +# in the "maintainers" tag of the respective scikit-base object. +# +# Algorithm maintainers are programmatically queriable +# via Estimator.get_class_tag("maintainers"). +# Further lookup such as "which algorithms does M maintain" +# can be carried out using registry.all_estimators * @achieveordie @benheid @fkiraly @yarnabrina - -sktime/annotation/hmm_learn/ @miraep8 -sktime/annotation/clasp.py @patrickzib @ermshaua -sktime/annotation/eagglo.py @KatieBuc -sktime/annotation/stray.py @KatieBuc - -sktime/classification/dictionary_based/_boss.py @patrickzib @MatthewMiddlehurst -sktime/classification/dictionary_based/_cboss.py @patrickzib @MatthewMiddlehurst -sktime/classification/dictionary_based/_muse.py @patrickzib @MatthewMiddlehurst -sktime/classification/dictionary_based/_tde.py @patrickzib @MatthewMiddlehurst -sktime/classification/dictionary_based/_weasel.py @patrickzib @MatthewMiddlehurst -sktime/classification/distance_based/ @goastler -sktime/classification/dummy/ @ZiyaoWei -sktime/classification/early_classification/_probability_threshold.py @MatthewMiddlehurst -sktime/classification/early_classification/_teaser.py @patrickzib @MatthewMiddlehurst -sktime/classification/feature_based/_catch22_classifier.py @MatthewMiddlehurst -sktime/classification/feature_based/_fresh_prince.py @MatthewMiddlehurst -sktime/classification/feature_based/_matrix_profile_classifier.py @MatthewMiddlehurst -sktime/classification/feature_based/_random_interval_classifier.py @MatthewMiddlehurst -sktime/classification/feature_based/_signature_classifier.py @jambo6 -sktime/classification/feature_based/_summary_classifier.py @MatthewMiddlehurst -sktime/classification/feature_based/_tsfresh_classifier.py @MatthewMiddlehurst -sktime/classification/hybrid/_hivecote_v1.py @MatthewMiddlehurst -sktime/classification/hybrid/_hivecote_v2.py @MatthewMiddlehurst -sktime/classification/interval_based/_cif.py @MatthewMiddlehurst -sktime/classification/interval_based/_drcif.py @MatthewMiddlehurst -sktime/classification/interval_based/_rise.py @MatthewMiddlehurst -sktime/classification/interval_based/_stsf.py @MatthewMiddlehurst -sktime/classification/interval_based/_tsf.py @MatthewMiddlehurst -sktime/classification/kernel_based/_arsenal.py @MatthewMiddlehurst -sktime/classification/kernel_based/_rocket_classifier.py @MatthewMiddlehurst -sktime/classification/shapelet_based/_stc.py @ABostrom @MatthewMiddlehurst -sktime/classification/sklearn/_continuous_interval_tree.py @MatthewMiddlehurst -sktime/classification/sklearn/_rotation_forest.py @MatthewMiddlehurst - -sktime/forecasting/adapters/_hcrystalball.py @MichalChromcak -sktime/forecasting/arch/_uarch.py @Vasudeva-bit -sktime/forecasting/arima.py @HYang1996 -sktime/forecasting/base/adapters/_statsforecast.py @FedericoGarza -sktime/forecasting/bats.py @aiwalter -sktime/forecasting/compose/_ensemble.py @aiwalter -sktime/forecasting/compose/_hierarchy_ensemble.py @VyomkeshVyas -sktime/forecasting/ets.py @HYang1996 -sktime/forecasting/fbprophet.py @aiwalter -sktime/forecasting/model_selection/_split @koralturkk -sktime/forecasting/online_learning/ @magittan -sktime/forecasting/sarimax.py @TNTran92 -sktime/forecasting/statsforecast.py @FedericoGarza -sktime/forecasting/structural.py @juanitorduz -sktime/forecasting/tests/test_ets.py @HYang1996 -sktime/forecasting/tbats.py @aiwalter - -sktime/regression/dummy/ @badrmarani - -sktime/transformations/panel/augmenter.py @MrPr3ntice @iljamaurer -sktime/transformations/panel/catch22.py @MatthewMiddlehurst -sktime/transformations/panel/catch22wrapper.py @MatthewMiddlehurst -sktime/transformations/panel/channel_selection.py @haskarb @a-pasos-ruiz -sktime/transformations/panel/dictionary_based/_paa.py @patrickzib @MatthewMiddlehurst -sktime/transformations/panel/dictionary_based/_sax.py @patrickzib @MatthewMiddlehurst -sktime/transformations/panel/dictionary_based/_sfa.py @patrickzib @MatthewMiddlehurst -sktime/transformations/panel/dictionary_based/_sfa_fast.py @patrickzib @MatthewMiddlehurst -sktime/transformations/panel/random_intervals.py @MatthewMiddlehurst -sktime/transformations/panel/rocket/ @angus924 -sktime/transformations/panel/rocket/_multirocket.py @ChangWeiTan @fstinner @angus924 -sktime/transformations/panel/rocket/_multirocket_multivariate.py @ChangWeiTan @fstinner @angus924 -sktime/transformations/panel/signature_based/ @jambo6 -sktime/transformations/panel/shapelet_transform.py @ABostrom @MatthewMiddlehurst -sktime/transformations/panel/supervised_intervals.py @MatthewMiddlehurst - -sktime/transformations/series/clear_sky.py @ciaran-g -sktime/transformations/series/clasp.py @patrickzib @ermshaua -sktime/transformations/series/date.py @danbartl @KishManani -sktime/transformations/series/difference.py @rnkuhns -sktime/transformations/series/exponent.py @rnkuhns -sktime/transformations/series/feature_selection.py @aiwalter -sktime/transformations/series/impute.py @aiwalter -sktime/transformations/series/kalman_filter.py @NoaBenAmi -sktime/transformations/series/outlier_detection.py @aiwalter -sktime/transformations/series/scaledlogit.py @ltsaprounis -sktime/transformations/series/time_since.py @KishManani -sktime/transformations/series/theta.py @GuzalBulatova -sktime/transformations/series/scaledasinh.py @ali-parizad - -sktime/utils/mlflow_sktime.py @benjaminbluhm diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 369a573ba47..5f938eba351 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,8 +1,12 @@ Contributors ============ +<!-- IMPORTANT - DO NOT MODIFY THIS FILE DIRECTLY. --> +<!-- This file is updated automatically from .all-contributorsrc --> +<!-- Please add your badges to .all-contibutorsrc --> + <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section --> -[![All Contributors](https://img.shields.io/badge/all_contributors-238-orange.svg)](#contributors) +[![All Contributors](https://img.shields.io/badge/all_contributors-252-orange.svg)](#contributors) <!-- ALL-CONTRIBUTORS-BADGE:END --> This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! @@ -54,11 +58,12 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/ayushmaan-seth-4a96364a/"><img src="https://avatars1.githubusercontent.com/u/29939762?v=4?s=100" width="100px;" alt="Ayushmaan Seth"/><br /><sub><b>Ayushmaan Seth</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Ayushmaanseth" title="Code">π»</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3AAyushmaanseth" title="Reviewed Pull Requests">π</a> <a href="https://github.com/sktime/sktime/commits?author=Ayushmaanseth" title="Tests">β οΈ</a> <a href="https://github.com/sktime/sktime/commits?author=Ayushmaanseth" title="Documentation">π</a> <a href="#eventOrganizing-Ayushmaanseth" title="Event Organizing">π</a> <a href="#tutorial-Ayushmaanseth" title="Tutorials">β </a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/BandaSaiTejaReddy"><img src="https://avatars0.githubusercontent.com/u/31387911?v=4?s=100" width="100px;" alt="BANDASAITEJAREDDY"/><br /><sub><b>BANDASAITEJAREDDY</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=BandaSaiTejaReddy" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=BandaSaiTejaReddy" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/badrmarani"><img src="https://avatars.githubusercontent.com/badrmarani?s=100" width="100px;" alt="Badr-Eddine Marani"/><br /><sub><b>Badr-Eddine Marani</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=badrmarani" title="Code">π»</a></td> + <td align="center" valign="top" width="11.11%"><a href="https://github.com/sd2k"><img src="https://avatars.githubusercontent.com/u/5464991?&v=4?s=100" width="100px;" alt="Ben Sully"/><br /><sub><b>Ben Sully</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Asd2k" title="Bug reports">π</a> <a href="https://github.com/sktime/sktime/commits?author=sd2k" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/benheid"><img src="?s=100" width="100px;" alt="Benedikt Heidrich"/><br /><sub><b>Benedikt Heidrich</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Abenheid" title="Bug reports">π</a> <a href="https://github.com/sktime/sktime/commits?author=benheid" title="Code">π»</a> <a href="#design-benheid" title="Design">π¨</a> <a href="https://github.com/sktime/sktime/commits?author=benheid" title="Documentation">π</a> <a href="#example-benheid" title="Examples">π‘</a> <a href="#ideas-benheid" title="Ideas, Planning, & Feedback">π€</a> <a href="#mentoring-benheid" title="Mentoring">π§βπ«</a> <a href="#question-benheid" title="Answering Questions">π¬</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3Abenheid" title="Reviewed Pull Requests">π</a> <a href="#tutorial-benheid" title="Tutorials">β </a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/benjaminbluhm"><img src="?s=100" width="100px;" alt="Benjamin Bluhm"/><br /><sub><b>Benjamin Bluhm</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=benjaminbluhm" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=benjaminbluhm" title="Documentation">π</a> <a href="#example-benjaminbluhm" title="Examples">π‘</a></td> - <td align="center" valign="top" width="11.11%"><a href="https://haskarb.github.io/"><img src="https://avatars.githubusercontent.com/u/20501023?v=4?s=100" width="100px;" alt="Bhaskar Dhariyal"/><br /><sub><b>Bhaskar Dhariyal</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=haskarb" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=haskarb" title="Tests">β οΈ</a></td> </tr> <tr> + <td align="center" valign="top" width="11.11%"><a href="https://haskarb.github.io/"><img src="https://avatars.githubusercontent.com/u/20501023?v=4?s=100" width="100px;" alt="Bhaskar Dhariyal"/><br /><sub><b>Bhaskar Dhariyal</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=haskarb" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=haskarb" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/BINAYKUMAR943"><img src="https://avatars.githubusercontent.com/u/38756834?v=4?s=100" width="100px;" alt="Binay Kumar"/><br /><sub><b>Binay Kumar</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=BINAYKUMAR943" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=BINAYKUMAR943" title="Documentation">π</a> <a href="https://github.com/sktime/sktime/commits?author=BINAYKUMAR943" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://angelpone.github.io/"><img src="https://avatars.githubusercontent.com/u/32930283?v=4?s=100" width="100px;" alt="Bohan Zhang"/><br /><sub><b>Bohan Zhang</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=AngelPone" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/boukepostma"><img src="https://avatars.githubusercontent.com/boukepostma?s=100" width="100px;" alt="Bouke Postma"/><br /><sub><b>Bouke Postma</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=boukepostma" title="Code">π»</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Aboukepostma" title="Bug reports">π</a> <a href="#ideas-boukepostma" title="Ideas, Planning, & Feedback">π€</a></td> @@ -67,9 +72,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d <td align="center" valign="top" width="11.11%"><a href="https://github.com/vnmabus"><img src="https://avatars1.githubusercontent.com/u/2364173?v=4?s=100" width="100px;" alt="Carlos Ramos CarreΓ±o"/><br /><sub><b>Carlos Ramos CarreΓ±o</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=vnmabus" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/ChangWeiTan"><img src="https://avatars.githubusercontent.com/u/570744?v=4?s=100" width="100px;" alt="Chang Wei Tan"/><br /><sub><b>Chang Wei Tan</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=ChangWeiTan" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="http://cheuk.dev"><img src="https://avatars1.githubusercontent.com/u/28761465?v=4?s=100" width="100px;" alt="Cheuk Ting Ho"/><br /><sub><b>Cheuk Ting Ho</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Cheukting" title="Code">π»</a></td> - <td align="center" valign="top" width="11.11%"><a href="https://github.com/ckastner"><img src="https://avatars.githubusercontent.com/u/15859947?v=4?s=100" width="100px;" alt="Christian Kastner"/><br /><sub><b>Christian Kastner</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=ckastner" title="Code">π»</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Ackastner" title="Bug reports">π</a></td> </tr> <tr> + <td align="center" valign="top" width="11.11%"><a href="https://github.com/ckastner"><img src="https://avatars.githubusercontent.com/u/15859947?v=4?s=100" width="100px;" alt="Christian Kastner"/><br /><sub><b>Christian Kastner</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=ckastner" title="Code">π»</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Ackastner" title="Bug reports">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/hoesler/"><img src="https://avatars.githubusercontent.com/u/1052770?v=4?s=100" width="100px;" alt="Christoph HΓΆsler"/><br /><sub><b>Christoph HΓΆsler</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=hoesler" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/cdahlin"><img src="https://avatars.githubusercontent.com/u/1567780?v=4?s=100" width="100px;" alt="Christopher Dahlin"/><br /><sub><b>Christopher Dahlin</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=cdahlin" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/topher-lo"><img src="?s=100" width="100px;" alt="Christopher Lo"/><br /><sub><b>Christopher Lo</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=topher-lo" title="Code">π»</a> <a href="#ideas-topher-lo" title="Ideas, Planning, & Feedback">π€</a></td> @@ -78,20 +83,21 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d <td align="center" valign="top" width="11.11%"><a href="https://github.com/ClaudiaSanches"><img src="https://avatars3.githubusercontent.com/u/28742178?v=4?s=100" width="100px;" alt="ClaudiaSanches"/><br /><sub><b>ClaudiaSanches</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=ClaudiaSanches" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=ClaudiaSanches" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/CTFallon"><img src="https://avatars.githubusercontent.com/u/19725980?v=4?s=100" width="100px;" alt="Colin Fallon"/><br /><sub><b>Colin Fallon</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=CTFallon" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://sites.google.com/view/corvinpaul/"><img src="https://lh3.googleusercontent.com/zMvwkuxyIsRN1I0-HLojbcbbHaERXa-b9eztZ23z_C2m7cXdMiU4z36ekS5-cgBmikPhZA=w1280?s=100" width="100px;" alt="Corvin Paul"/><br /><sub><b>Corvin Paul</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=corvusrabus" title="Documentation">π</a></td> - <td align="center" valign="top" width="11.11%"><a href="https://github.com/DBCerigo"><img src="https://avatars.githubusercontent.com/u/8318425?v=4?s=100" width="100px;" alt="Daniel Burkhardt Cerigo"/><br /><sub><b>Daniel Burkhardt Cerigo</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=DBCerigo" title="Code">π»</a></td> </tr> <tr> + <td align="center" valign="top" width="11.11%"><a href="https://github.com/DBCerigo"><img src="https://avatars.githubusercontent.com/u/8318425?v=4?s=100" width="100px;" alt="Daniel Burkhardt Cerigo"/><br /><sub><b>Daniel Burkhardt Cerigo</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=DBCerigo" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/daniel-martin-martinez"><img src="https://avatars.githubusercontent.com/dainelli98?s=100" width="100px;" alt="Daniel MartΓn MartΓnez"/><br /><sub><b>Daniel MartΓn MartΓnez</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=dainelli98" title="Documentation">π</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Adainelli98" title="Bug reports">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/dashapetr"><img src="https://avatars.githubusercontent.com/u/54349415?v=4?s=100" width="100px;" alt="Darya Petrashka"/><br /><sub><b>Darya Petrashka</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=dashapetr" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://dhirschfeld.github.io/"><img src="https://avatars1.githubusercontent.com/u/881019?v=4?s=100" width="100px;" alt="Dave Hirschfeld"/><br /><sub><b>Dave Hirschfeld</b></sub></a><br /><a href="#infra-dhirschfeld" title="Infrastructure (Hosting, Build-Tools, etc)">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/davidbp"><img src="https://avatars3.githubusercontent.com/u/4223580?v=4?s=100" width="100px;" alt="David Buchaca Prats"/><br /><sub><b>David Buchaca Prats</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=davidbp" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/davidgilbertson"><img src="https://avatars.githubusercontent.com/u/4443482?v=4?s=100" width="100px;" alt="David Gilbertson"/><br /><sub><b>David Gilbertson</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=davidgilbertson" title="Code">π»</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Adavidgilbertson" title="Bug reports">π</a></td> <td align="center" valign="top" width="11.11%"><a href="http://www.uco.es/grupos/ayrna/index.php/es/publicaciones/articulos?publications_view_all=1&theses_view_all=0&projects_view_all=0&task=show&view=member&id=22"><img src="https://avatars1.githubusercontent.com/u/47889499?v=4?s=100" width="100px;" alt="David Guijo Rubio"/><br /><sub><b>David Guijo Rubio</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=dguijo" title="Code">π»</a> <a href="#ideas-dguijo" title="Ideas, Planning, & Feedback">π€</a></td> + <td align="center" valign="top" width="11.11%"><a href="https://github.com/DManowitz"><img src="https://avatars.githubusercontent.com/u/66927103?v=4?s=100" width="100px;" alt="David Manowitz"/><br /><sub><b>David Manowitz</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3ADManowitz" title="Bug reports">π</a> <a href="#maintenance-DManowitz" title="Maintenance">π§</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/DmitriyValetov"><img src="https://avatars0.githubusercontent.com/u/27976850?v=4?s=100" width="100px;" alt="Dmitriy Valetov"/><br /><sub><b>Dmitriy Valetov</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=DmitriyValetov" title="Code">π»</a> <a href="#tutorial-DmitriyValetov" title="Tutorials">β </a></td> - <td align="center" valign="top" width="11.11%"><a href="https://github.com/dougollerenshaw"><img src="https://avatars.githubusercontent.com/u/19944442?v=4?s=100" width="100px;" alt="Doug Ollerenshaw"/><br /><sub><b>Doug Ollerenshaw</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=dougollerenshaw" title="Documentation">π</a></td> - <td align="center" valign="top" width="11.11%"><a href="https://github.com/Dbhasin1"><img src="https://avatars.githubusercontent.com/u/56479884?v=4?s=100" width="100px;" alt="Drishti Bhasin "/><br /><sub><b>Drishti Bhasin </b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Dbhasin1" title="Code">π»</a></td> </tr> <tr> + <td align="center" valign="top" width="11.11%"><a href="https://github.com/dougollerenshaw"><img src="https://avatars.githubusercontent.com/u/19944442?v=4?s=100" width="100px;" alt="Doug Ollerenshaw"/><br /><sub><b>Doug Ollerenshaw</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=dougollerenshaw" title="Documentation">π</a></td> + <td align="center" valign="top" width="11.11%"><a href="https://github.com/Dbhasin1"><img src="https://avatars.githubusercontent.com/u/56479884?v=4?s=100" width="100px;" alt="Drishti Bhasin "/><br /><sub><b>Drishti Bhasin </b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Dbhasin1" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/dsherry"><img src="https://avatars.githubusercontent.com/dsherry?s=100" width="100px;" alt="Dylan Sherry"/><br /><sub><b>Dylan Sherry</b></sub></a><br /><a href="#infra-dsherry" title="Infrastructure (Hosting, Build-Tools, etc)">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/Emiliathewolf"><img src="https://avatars2.githubusercontent.com/u/22026218?v=4?s=100" width="100px;" alt="Emilia Rose"/><br /><sub><b>Emilia Rose</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Emiliathewolf" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=Emiliathewolf" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/erjieyong"><img src="https://avatars.githubusercontent.com/u/109052378?v=4?s=100" width="100px;" alt="Er Jie Yong"/><br /><sub><b>Er Jie Yong</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Aerjieyong" title="Bug reports">π</a> <a href="https://github.com/sktime/sktime/commits?author=erjieyong" title="Code">π»</a></td> @@ -99,153 +105,163 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d <td align="center" valign="top" width="11.11%"><a href="https://github.com/eyalshafran"><img src="https://avatars.githubusercontent.com/u/16999574?v=4?s=100" width="100px;" alt="Eyal Shafran"/><br /><sub><b>Eyal Shafran</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=eyalshafran" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/eyjo"><img src="https://avatars.githubusercontent.com/eyjo?s=100" width="100px;" alt="EyjΓ³lfur SigurΓ°sson"/><br /><sub><b>EyjΓ³lfur SigurΓ°sson</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=eyjo" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=eyjo" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/FedericoGarza"><img src="https://avatars.githubusercontent.com/u/10517170?v=4?s=100" width="100px;" alt="Federico Garza"/><br /><sub><b>Federico Garza</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=FedericoGarza" title="Code">π»</a> <a href="#example-FedericoGarza" title="Examples">π‘</a></td> - <td align="center" valign="top" width="11.11%"><a href="https://github.com/felipeangelimvieira"><img src="https://avatars.githubusercontent.com/felipeangelimvieira?s=100" width="100px;" alt="Felipe Angelim"/><br /><sub><b>Felipe Angelim</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=felipeangelimvieira" title="Code">π»</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Afelipeangelimvieira" title="Bug reports">π</a></td> - <td align="center" valign="top" width="11.11%"><a href="https://github.com/flix6x"><img src="https://avatars.githubusercontent.com/u/30658763?v=4?s=100" width="100px;" alt="Felix Claessen"/><br /><sub><b>Felix Claessen</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Flix6x" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=Flix6x" title="Documentation">π</a> <a href="https://github.com/sktime/sktime/commits?author=Flix6x" title="Tests">β οΈ</a> <a href="https://github.com/sktime/sktime/issues?q=author%3AFlix6x" title="Bug reports">π</a></td> </tr> <tr> + <td align="center" valign="top" width="11.11%"><a href="https://github.com/felipeangelimvieira"><img src="https://avatars.githubusercontent.com/felipeangelimvieira?s=100" width="100px;" alt="Felipe Angelim"/><br /><sub><b>Felipe Angelim</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=felipeangelimvieira" title="Code">π»</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Afelipeangelimvieira" title="Bug reports">π</a></td> + <td align="center" valign="top" width="11.11%"><a href="https://github.com/flix6x"><img src="https://avatars.githubusercontent.com/u/30658763?v=4?s=100" width="100px;" alt="Felix Claessen"/><br /><sub><b>Felix Claessen</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Flix6x" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=Flix6x" title="Documentation">π</a> <a href="https://github.com/sktime/sktime/commits?author=Flix6x" title="Tests">β οΈ</a> <a href="https://github.com/sktime/sktime/issues?q=author%3AFlix6x" title="Bug reports">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/fstinner"><img src="https://avatars.githubusercontent.com/u/11679462?v=4?s=100" width="100px;" alt="Florian Stinner"/><br /><sub><b>Florian Stinner</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=fstinner" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=fstinner" title="Tests">β οΈ</a></td> + <td align="center" valign="top" width="11.11%"><a href="https://github.com/fspinna"><img src="https://avatars.githubusercontent.com/u/35352023?v=4?s=100" width="100px;" alt="Francesco Spinnato"/><br /><sub><b>Francesco Spinnato</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=fspinna" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/fkiraly"><img src="https://avatars1.githubusercontent.com/u/7985502?v=4?s=100" width="100px;" alt="Franz Kiraly"/><br /><sub><b>Franz Kiraly</b></sub></a><br /><a href="#blog-fkiraly" title="Blogposts">π</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Afkiraly" title="Bug reports">π</a> <a href="#business-fkiraly" title="Business development">πΌ</a> <a href="https://github.com/sktime/sktime/commits?author=fkiraly" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=fkiraly" title="Documentation">π</a> <a href="#design-fkiraly" title="Design">π¨</a> <a href="#eventOrganizing-fkiraly" title="Event Organizing">π</a> <a href="#example-fkiraly" title="Examples">π‘</a> <a href="#financial-fkiraly" title="Financial">π΅</a> <a href="#fundingFinding-fkiraly" title="Funding Finding">π</a> <a href="#ideas-fkiraly" title="Ideas, Planning, & Feedback">π€</a> <a href="#maintenance-fkiraly" title="Maintenance">π§</a> <a href="#mentoring-fkiraly" title="Mentoring">π§βπ«</a> <a href="#projectManagement-fkiraly" title="Project Management">π</a> <a href="#question-fkiraly" title="Answering Questions">π¬</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3Afkiraly" title="Reviewed Pull Requests">π</a> <a href="#talk-fkiraly" title="Talks">π’</a> <a href="https://github.com/sktime/sktime/commits?author=fkiraly" title="Tests">β οΈ</a> <a href="#tutorial-fkiraly" title="Tutorials">β </a> <a href="#video-fkiraly" title="Videos">πΉ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/freddyaboulton"><img src="https://avatars.githubusercontent.com/u/41651716?v=4?s=100" width="100px;" alt="Freddy A Boulton"/><br /><sub><b>Freddy A Boulton</b></sub></a><br /><a href="#infra-freddyaboulton" title="Infrastructure (Hosting, Build-Tools, etc)">π</a> <a href="https://github.com/sktime/sktime/commits?author=freddyaboulton" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/chernika158"><img src="https://avatars.githubusercontent.com/u/43787741?s=400&v=4?s=100" width="100px;" alt="Galina Chernikova"/><br /><sub><b>Galina Chernikova</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=chernika158" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/goastler"><img src="https://avatars0.githubusercontent.com/u/7059456?v=4?s=100" width="100px;" alt="George Oastler"/><br /><sub><b>George Oastler</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=goastler" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=goastler" title="Tests">β οΈ</a> <a href="#platform-goastler" title="Packaging/porting to new platform">π¦</a> <a href="#example-goastler" title="Examples">π‘</a> <a href="https://github.com/sktime/sktime/commits?author=goastler" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/geronimos"><img src="https://avatars.githubusercontent.com/u/29955288?s=96&v=4?s=100" width="100px;" alt="Geronimo Bergk"/><br /><sub><b>Geronimo Bergk</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Ageronimos" title="Bug reports">π</a> <a href="https://github.com/sktime/sktime/commits?author=geronimos" title="Code">π»</a></td> + </tr> + <tr> <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/gracewgao/"><img src="https://avatars0.githubusercontent.com/u/38268331?v=4?s=100" width="100px;" alt="Grace Gao"/><br /><sub><b>Grace Gao</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=gracewgao" title="Code">π»</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Agracewgao" title="Bug reports">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/GuzalBulatova"><img src="https://avatars.githubusercontent.com/GuzalBulatova?s=100" width="100px;" alt="Guzal Bulatova"/><br /><sub><b>Guzal Bulatova</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3AGuzalBulatova" title="Bug reports">π</a> <a href="https://github.com/sktime/sktime/commits?author=GuzalBulatova" title="Code">π»</a> <a href="#eventOrganizing-GuzalBulatova" title="Event Organizing">π</a> <a href="#mentoring-GuzalBulatova" title="Mentoring">π§βπ«</a> <a href="#projectManagement-GuzalBulatova" title="Project Management">π</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3AGuzalBulatova" title="Reviewed Pull Requests">π</a> <a href="https://github.com/sktime/sktime/commits?author=GuzalBulatova" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/HYang1996"><img src="https://avatars0.githubusercontent.com/u/44179303?v=4?s=100" width="100px;" alt="HYang1996"/><br /><sub><b>HYang1996</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=HYang1996" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=HYang1996" title="Tests">β οΈ</a> <a href="https://github.com/sktime/sktime/commits?author=HYang1996" title="Documentation">π</a> <a href="#tutorial-HYang1996" title="Tutorials">β </a></td> - </tr> - <tr> <td align="center" valign="top" width="11.11%"><a href="https://github.com/BensHamza"><img src="https://avatars.githubusercontent.com/u/96446862?v=4?s=100" width="100px;" alt="Hamza Benslimane"/><br /><sub><b>Hamza Benslimane</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3ABensHamza" title="Bug reports">π</a> <a href="https://github.com/sktime/sktime/commits?author=BensHamza" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/hazrulakmal"><img src="https://avatars.githubusercontent.com/u/24774385?v=4?s=100" width="100px;" alt="Hazrul Akmal"/><br /><sub><b>Hazrul Akmal</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=hazrulakmal" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=hazrulakmal" title="Documentation">π</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Ahazrulakmal" title="Bug reports">π</a> <a href="https://github.com/sktime/sktime/commits?author=hazrulakmal" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/hliebert"><img src="https://avatars.githubusercontent.com/u/20834265?s=100" width="100px;" alt="Helge Liebert"/><br /><sub><b>Helge Liebert</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Ahliebert" title="Bug reports">π</a> <a href="https://github.com/sktime/sktime/commits?author=hliebert" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/huayiwei/"><img src="https://avatars3.githubusercontent.com/u/22870735?v=4?s=100" width="100px;" alt="Huayi Wei"/><br /><sub><b>Huayi Wei</b></sub></a><br /><a href="#tutorial-huayicodes" title="Tutorials">β </a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/Ifeanyi30"><img src="https://avatars.githubusercontent.com/u/49926145?v=4?s=100" width="100px;" alt="Ifeanyi30"/><br /><sub><b>Ifeanyi30</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Ifeanyi30" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/iljamaurer"><img src="https://avatars.githubusercontent.com/u/45882103?v=4?s=100" width="100px;" alt="Ilja Maurer"/><br /><sub><b>Ilja Maurer</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=iljamaurer" title="Code">π»</a></td> + </tr> + <tr> <td align="center" valign="top" width="11.11%"><a href="https://github.com/IlyasMoutawwakil"><img src="https://avatars.githubusercontent.com/IlyasMoutawwakil?s=100" width="100px;" alt="Ilyas Moutawwakil"/><br /><sub><b>Ilyas Moutawwakil</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=IlyasMoutawwakil" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=IlyasMoutawwakil" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/ireoluwatomiwa-sanusi/"><img src="https://avatars.githubusercontent.com/u/61966277?v=4?s=100" width="100px;" alt="Ireoluwatomiwa"/><br /><sub><b>Ireoluwatomiwa</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Tomiiwa" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/ishannangia001"><img src="https://avatars.githubusercontent.com/u/29480389?v=4?s=100" width="100px;" alt="Ishan Nangia"/><br /><sub><b>Ishan Nangia</b></sub></a><br /><a href="#ideas-ishannangia001" title="Ideas, Planning, & Feedback">π€</a></td> - </tr> - <tr> <td align="center" valign="top" width="11.11%"><a href="https://github.com/jnrusson1"><img src="https://avatars.githubusercontent.com/u/51986332?v=4?s=100" width="100px;" alt="Jack Russon"/><br /><sub><b>Jack Russon</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=jnrusson1" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="http://www.timeseriesclassification.com/"><img src="https://avatars0.githubusercontent.com/u/44509982?v=4?s=100" width="100px;" alt="James Large"/><br /><sub><b>James Large</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=James-Large" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=James-Large" title="Documentation">π</a> <a href="https://github.com/sktime/sktime/commits?author=James-Large" title="Tests">β οΈ</a> <a href="#infra-James-Large" title="Infrastructure (Hosting, Build-Tools, etc)">π</a> <a href="#maintenance-James-Large" title="Maintenance">π§</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/jambo6"><img src="https://https://avatars.githubusercontent.com/jambo6?s=100" width="100px;" alt="James Morrill"/><br /><sub><b>James Morrill</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=jambo6" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/janpipek"><img src="https://avatars.githubusercontent.com/janpipek?s=100" width="100px;" alt="Jan Pipek"/><br /><sub><b>Jan Pipek</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=janpipek" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/jasmineliaw"><img src="?s=100" width="100px;" alt="Jasmine Liaw"/><br /><sub><b>Jasmine Liaw</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=jasmineliaw" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="http://www.timeseriesclassification.com"><img src="https://avatars1.githubusercontent.com/u/38794632?v=4?s=100" width="100px;" alt="Jason Lines"/><br /><sub><b>Jason Lines</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=jasonlines" title="Code">π»</a> <a href="#business-jasonlines" title="Business development">πΌ</a> <a href="https://github.com/sktime/sktime/commits?author=jasonlines" title="Documentation">π</a> <a href="#design-jasonlines" title="Design">π¨</a> <a href="#eventOrganizing-jasonlines" title="Event Organizing">π</a> <a href="#fundingFinding-jasonlines" title="Funding Finding">π</a> <a href="#ideas-jasonlines" title="Ideas, Planning, & Feedback">π€</a> <a href="#projectManagement-jasonlines" title="Project Management">π</a> <a href="#question-jasonlines" title="Answering Questions">π¬</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3Ajasonlines" title="Reviewed Pull Requests">π</a> <a href="#talk-jasonlines" title="Talks">π’</a> <a href="#example-jasonlines" title="Examples">π‘</a></td> + </tr> + <tr> <td align="center" valign="top" width="11.11%"><a href="https://github.com/whackteachers"><img src="https://avatars0.githubusercontent.com/u/33785383?v=4?s=100" width="100px;" alt="Jason Pong"/><br /><sub><b>Jason Pong</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=whackteachers" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=whackteachers" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/mateuja"><img src="https://avatars.githubusercontent.com/mateuja?s=100" width="100px;" alt="Jaume Mateu"/><br /><sub><b>Jaume Mateu</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=mateuja" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/pirnerjonas"><img src="https://avatars.githubusercontent.com/u/48887249?v=4?s=100" width="100px;" alt="Jonas Pirner"/><br /><sub><b>Jonas Pirner</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=pirnerjonas" title="Documentation">π</a></td> - </tr> - <tr> <td align="center" valign="top" width="11.11%"><a href="https://github.com/JonathanBechtel"><img src="https://avatars.githubusercontent.com/u/481696?v=4?s=100" width="100px;" alt="JonathanBechtel"/><br /><sub><b>JonathanBechtel</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=JonathanBechtel" title="Code">π»</a> <a href="#ideas-JonathanBechtel" title="Ideas, Planning, & Feedback">π€</a> <a href="https://github.com/sktime/sktime/commits?author=JonathanBechtel" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/jorenham"><img src="?s=100" width="100px;" alt="Joren Hammudoglu"/><br /><sub><b>Joren Hammudoglu</b></sub></a><br /><a href="#infra-jorenham" title="Infrastructure (Hosting, Build-Tools, etc)">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://juanitorduz.github.io/"><img src="https://avatars1.githubusercontent.com/u/22996444?v=4?s=100" width="100px;" alt="Juan Orduz"/><br /><sub><b>Juan Orduz</b></sub></a><br /><a href="#tutorial-juanitorduz" title="Tutorials">β </a> <a href="https://github.com/sktime/sktime/commits?author=juanitorduz" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/julia-kraus"><img src="https://avatars.githubusercontent.com/julia-kraus?s=100" width="100px;" alt="Julia Kraus"/><br /><sub><b>Julia Kraus</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=julia-kraus" title="Documentation">π</a> <a href="https://github.com/sktime/sktime/commits?author=julia-kraus" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=julia-kraus" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/jelc53"><img src="?s=100" width="100px;" alt="Julian Cooper"/><br /><sub><b>Julian Cooper</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=jelc53" title="Code">π»</a> <a href="#ideas-jelc53" title="Ideas, Planning, & Feedback">π€</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/julnow"><img src="https://avatars.githubusercontent.com/u/21206185?v=4?s=100" width="100px;" alt="Julian Nowak"/><br /><sub><b>Julian Nowak</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Ajulnow" title="Bug reports">π</a> <a href="https://github.com/sktime/sktime/commits?author=julnow" title="Code">π»</a></td> + </tr> + <tr> <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/julianarn/"><img src="https://avatars.githubusercontent.com/u/19613567?v=4?s=100" width="100px;" alt="Juliana"/><br /><sub><b>Juliana</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=julramos" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://www.justinshenk.com/"><img src="https://avatars.githubusercontent.com/u/10270308?v=4?s=100" width="100px;" alt="Justin Shenk"/><br /><sub><b>Justin Shenk</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=justinshenk" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/kcc-lion"><img src="?s=100" width="100px;" alt="Kai Lion"/><br /><sub><b>Kai Lion</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=kcc-lion" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=kcc-lion" title="Tests">β οΈ</a> <a href="https://github.com/sktime/sktime/commits?author=kcc-lion" title="Documentation">π</a></td> - </tr> - <tr> <td align="center" valign="top" width="11.11%"><a href="https://github.com/kanand77"><img src="https://avatars.githubusercontent.com/kanand77?s=100" width="100px;" alt="Kavin Anand"/><br /><sub><b>Kavin Anand</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=kanand77" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://kejsitake.com/"><img src="https://avatars.githubusercontent.com/u/23707808?v=4?s=100" width="100px;" alt="Kejsi Take"/><br /><sub><b>Kejsi Take</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=kejsitake" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/kevinlam2"><img src="https://avatars.githubusercontent.com/u/114420932?s=400&v=4?s=100" width="100px;" alt="Kevin Lam"/><br /><sub><b>Kevin Lam</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=klam-data" title="Code">π»</a> <a href="#example-klam-data" title="Examples">π‘</a> <a href="https://github.com/sktime/sktime/commits?author=klam-data" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://whitakerlab.github.io/"><img src="https://avatars1.githubusercontent.com/u/3626306?v=4?s=100" width="100px;" alt="Kirstie Whitaker"/><br /><sub><b>Kirstie Whitaker</b></sub></a><br /><a href="#ideas-KirstieJane" title="Ideas, Planning, & Feedback">π€</a> <a href="#fundingFinding-KirstieJane" title="Funding Finding">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/kishmanani"><img src="https://avatars.githubusercontent.com/u/30973056?v=4?s=100" width="100px;" alt="Kishan Manani"/><br /><sub><b>Kishan Manani</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=KishManani" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=KishManani" title="Documentation">π</a> <a href="https://github.com/sktime/sktime/commits?author=KishManani" title="Tests">β οΈ</a> <a href="https://github.com/sktime/sktime/issues?q=author%3AKishManani" title="Bug reports">π</a> <a href="#ideas-KishManani" title="Ideas, Planning, & Feedback">π€</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/krumeto"><img src="https://avatars3.githubusercontent.com/u/11272436?v=4?s=100" width="100px;" alt="Krum Arnaudov"/><br /><sub><b>Krum Arnaudov</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Akrumeto" title="Bug reports">π</a> <a href="https://github.com/sktime/sktime/commits?author=krumeto" title="Code">π»</a></td> + </tr> + <tr> <td align="center" valign="top" width="11.11%"><a href="https://github.com/koralturkk"><img src="https://avatars2.githubusercontent.com/u/18037789?s=460&v=4?s=100" width="100px;" alt="Kutay Koralturk"/><br /><sub><b>Kutay Koralturk</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=koralturkk" title="Code">π»</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Akoralturkk" title="Bug reports">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/ltsaprounis"><img src="https://avatars.githubusercontent.com/u/64217214?v=4?s=100" width="100px;" alt="Leonidas Tsaprounis"/><br /><sub><b>Leonidas Tsaprounis</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=ltsaprounis" title="Code">π»</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Altsaprounis" title="Bug reports">π</a> <a href="#mentoring-ltsaprounis" title="Mentoring">π§βπ«</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3Altsaprounis" title="Reviewed Pull Requests">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/lielleravid"><img src="https://avatars.githubusercontent.com/u/37774194?v=4?s=100" width="100px;" alt="Lielle Ravid"/><br /><sub><b>Lielle Ravid</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=lielleravid" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=lielleravid" title="Documentation">π</a></td> - </tr> - <tr> <td align="center" valign="top" width="11.11%"><a href="https://github.com/chillerobscuro"><img src="https://avatars.githubusercontent.com/u/5232872?v=4?s=100" width="100px;" alt="Logan Duffy"/><br /><sub><b>Logan Duffy</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=chillerobscuro" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=chillerobscuro" title="Documentation">π</a> <a href="https://github.com/sktime/sktime/commits?author=chillerobscuro" title="Tests">β οΈ</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Achillerobscuro" title="Bug reports">π</a> <a href="#ideas-chillerobscuro" title="Ideas, Planning, & Feedback">π€</a></td> <td align="center" valign="top" width="11.11%"><a href="http://lpantano.github.io/"><img src="https://avatars2.githubusercontent.com/u/1621788?v=4?s=100" width="100px;" alt="Lorena Pantano"/><br /><sub><b>Lorena Pantano</b></sub></a><br /><a href="#ideas-lpantano" title="Ideas, Planning, & Feedback">π€</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/ltoniazzi"><img src="https://avatars.githubusercontent.com/u/61414566?s=100" width="100px;" alt="Lorenzo Toniazzi"/><br /><sub><b>Lorenzo Toniazzi</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=ltoniazzi" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/Lovkush-A"><img src="https://avatars.githubusercontent.com/u/25344832?v=4?s=100" width="100px;" alt="Lovkush"/><br /><sub><b>Lovkush</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Lovkush-A" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=Lovkush-A" title="Tests">β οΈ</a> <a href="#ideas-Lovkush-A" title="Ideas, Planning, & Feedback">π€</a> <a href="#mentoring-Lovkush-A" title="Mentoring">π§βπ«</a> <a href="#projectManagement-Lovkush-A" title="Project Management">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/luca-miniati"><img src="https://avatars.githubusercontent.com/u/87467600?v=4?s=100" width="100px;" alt="Luca Miniati"/><br /><sub><b>Luca Miniati</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=luca-miniati" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=luca-miniati" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/lbventura"><img src="https://avatars.githubusercontent.com/u/68004282?s=96&v=4?s=100" width="100px;" alt="Luis Ventura"/><br /><sub><b>Luis Ventura</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=lbventura" title="Code">π»</a></td> + </tr> + <tr> <td align="center" valign="top" width="11.11%"><a href="https://github.com/luiszugasti"><img src="https://avatars.githubusercontent.com/u/11198457?s=460&u=0645b72683e491824aca16db9702f1d3eb990389&v=4?s=100" width="100px;" alt="Luis Zugasti"/><br /><sub><b>Luis Zugasti</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=luiszugasti" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/lmmentel"><img src="https://avatars.githubusercontent.com/u/8989838?v=4?s=100" width="100px;" alt="Lukasz Mentel"/><br /><sub><b>Lukasz Mentel</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=lmmentel" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=lmmentel" title="Documentation">π</a> <a href="#infra-lmmentel" title="Infrastructure (Hosting, Build-Tools, etc)">π</a> <a href="https://github.com/sktime/sktime/commits?author=lmmentel" title="Tests">β οΈ</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Almmentel" title="Bug reports">π</a> <a href="#maintenance-lmmentel" title="Maintenance">π§</a> <a href="#mentoring-lmmentel" title="Mentoring">π§βπ«</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/marrov"><img src="https://avatars.githubusercontent.com/u/54272586?v=4?s=100" width="100px;" alt="Marc Rovira"/><br /><sub><b>Marc Rovira</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=marrov" title="Documentation">π</a></td> - </tr> - <tr> <td align="center" valign="top" width="11.11%"><a href="http://marcelotryle.com"><img src="https://avatars3.githubusercontent.com/u/7353520?v=4?s=100" width="100px;" alt="Marcelo Trylesinski"/><br /><sub><b>Marcelo Trylesinski</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Kludex" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/MarcoGorelli"><img src="https://avatars2.githubusercontent.com/u/33491632?v=4?s=100" width="100px;" alt="Marco Gorelli"/><br /><sub><b>Marco Gorelli</b></sub></a><br /><a href="#infra-MarcoGorelli" title="Infrastructure (Hosting, Build-Tools, etc)">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/margaret-gorlin/"><img src="?s=100" width="100px;" alt="Margaret Gorlin"/><br /><sub><b>Margaret Gorlin</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=mgorlin" title="Code">π»</a> <a href="#example-mgorlin" title="Examples">π‘</a> <a href="https://github.com/sktime/sktime/commits?author=mgorlin" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/mariamjabara"><img src="?s=100" width="100px;" alt="Mariam Jabara"/><br /><sub><b>Mariam Jabara</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=mariamjabara" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://twitter.com/marielli"><img src="https://avatars2.githubusercontent.com/u/13499809?v=4?s=100" width="100px;" alt="Marielle"/><br /><sub><b>Marielle</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=marielledado" title="Documentation">π</a> <a href="https://github.com/sktime/sktime/commits?author=marielledado" title="Code">π»</a> <a href="#ideas-marielledado" title="Ideas, Planning, & Feedback">π€</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/mloning"><img src="https://avatars3.githubusercontent.com/u/21020482?v=4?s=100" width="100px;" alt="Markus LΓΆning"/><br /><sub><b>Markus LΓΆning</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=mloning" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=mloning" title="Tests">β οΈ</a> <a href="#maintenance-mloning" title="Maintenance">π§</a> <a href="#platform-mloning" title="Packaging/porting to new platform">π¦</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3Amloning" title="Reviewed Pull Requests">π</a> <a href="#infra-mloning" title="Infrastructure (Hosting, Build-Tools, etc)">π</a> <a href="#example-mloning" title="Examples">π‘</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Amloning" title="Bug reports">π</a> <a href="#tutorial-mloning" title="Tutorials">β </a> <a href="#business-mloning" title="Business development">πΌ</a> <a href="https://github.com/sktime/sktime/commits?author=mloning" title="Documentation">π</a> <a href="#design-mloning" title="Design">π¨</a> <a href="#eventOrganizing-mloning" title="Event Organizing">π</a> <a href="#fundingFinding-mloning" title="Funding Finding">π</a> <a href="#ideas-mloning" title="Ideas, Planning, & Feedback">π€</a> <a href="#projectManagement-mloning" title="Project Management">π</a> <a href="#question-mloning" title="Answering Questions">π¬</a> <a href="#talk-mloning" title="Talks">π’</a> <a href="#mentoring-mloning" title="Mentoring">π§βπ«</a> <a href="#video-mloning" title="Videos">πΉ</a></td> + </tr> + <tr> <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/martin-walter-1a33b3114/"><img src="https://avatars0.githubusercontent.com/u/29627036?v=4?s=100" width="100px;" alt="Martin Walter"/><br /><sub><b>Martin Walter</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=aiwalter" title="Code">π»</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Aaiwalter" title="Bug reports">π</a> <a href="#projectManagement-aiwalter" title="Project Management">π</a> <a href="#fundingFinding-aiwalter" title="Funding Finding">π</a> <a href="#mentoring-aiwalter" title="Mentoring">π§βπ«</a> <a href="#ideas-aiwalter" title="Ideas, Planning, & Feedback">π€</a> <a href="#design-aiwalter" title="Design">π¨</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3Aaiwalter" title="Reviewed Pull Requests">π</a> <a href="https://github.com/sktime/sktime/commits?author=aiwalter" title="Documentation">π</a> <a href="#talk-aiwalter" title="Talks">π’</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/martinagvilas"><img src="https://avatars2.githubusercontent.com/u/37339384?v=4?s=100" width="100px;" alt="Martina G. Vilas"/><br /><sub><b>Martina G. Vilas</b></sub></a><br /><a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3Amartinagvilas" title="Reviewed Pull Requests">π</a> <a href="#ideas-martinagvilas" title="Ideas, Planning, & Feedback">π€</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/MCRE-BE"><img src="https://avatars.githubusercontent.com/u/99316631?s=100" width="100px;" alt="Mathias Creemers"/><br /><sub><b>Mathias Creemers</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3AMCRE-BE" title="Bug reports">π</a> <a href="https://github.com/sktime/sktime/commits?author=MCRE-BE" title="Code">π»</a></td> - </tr> - <tr> <td align="center" valign="top" width="11.11%"><a href="http://www.timeseriesclassification.com"><img src="https://avatars0.githubusercontent.com/u/25731235?v=4?s=100" width="100px;" alt="Matthew Middlehurst"/><br /><sub><b>Matthew Middlehurst</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=MatthewMiddlehurst" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=MatthewMiddlehurst" title="Documentation">π</a> <a href="https://github.com/sktime/sktime/commits?author=MatthewMiddlehurst" title="Tests">β οΈ</a> <a href="#tutorial-MatthewMiddlehurst" title="Tutorials">β </a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3AMatthewMiddlehurst" title="Reviewed Pull Requests">π</a> <a href="https://github.com/sktime/sktime/issues?q=author%3AMatthewMiddlehurst" title="Bug reports">π</a></td> + <td align="center" valign="top" width="11.11%"><a href="https://github.com/tvdboom"><img src="https://avatars.githubusercontent.com/u/32366550?v=4?s=100" width="100px;" alt="Mavs"/><br /><sub><b>Mavs</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=tvdboom" title="Code">π»</a></td> + <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/maxfrohlich/"><img src="https://avatars.githubusercontent.com/u/16393653?v=4?s=100" width="100px;" alt="Max Frohlich"/><br /><sub><b>Max Frohlich</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=ninedigits" title="Code">π»</a> <a href="#ideas-ninedigits" title="Ideas, Planning, & Feedback">π€</a> <a href="#maintenance-ninedigits" title="Maintenance">π§</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/solen0id"><img src="https://avatars.githubusercontent.com/u/20767606?v=4?s=100" width="100px;" alt="Max Patzelt"/><br /><sub><b>Max Patzelt</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=solen0id" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/Hephaest"><img src="https://avatars2.githubusercontent.com/u/37981444?v=4?s=100" width="100px;" alt="Miao Cai"/><br /><sub><b>Miao Cai</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3AHephaest" title="Bug reports">π</a> <a href="https://github.com/sktime/sktime/commits?author=Hephaest" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="michaelfeil.eu"><img src="https://avatars.githubusercontent.com/u/63565275?v=4?s=100" width="100px;" alt="Michael Feil"/><br /><sub><b>Michael Feil</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=michaelfeil" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=michaelfeil" title="Tests">β οΈ</a> <a href="#ideas-michaelfeil" title="Ideas, Planning, & Feedback">π€</a></td> + </tr> + <tr> <td align="center" valign="top" width="11.11%"><a href="https://github.com/mgazian000"><img src="https://avatars.githubusercontent.com/mgazian000?s=100" width="100px;" alt="Michael Gaziani"/><br /><sub><b>Michael Gaziani</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=mgazian000" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/MichalChromcak"><img src="https://avatars1.githubusercontent.com/u/12393430?v=4?s=100" width="100px;" alt="Michal Chromcak"/><br /><sub><b>Michal Chromcak</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=MichalChromcak" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=MichalChromcak" title="Documentation">π</a> <a href="https://github.com/sktime/sktime/commits?author=MichalChromcak" title="Tests">β οΈ</a> <a href="#tutorial-MichalChromcak" title="Tutorials">β </a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/miraep8"><img src="https://avatars.githubusercontent.com/u/10511777?s=400&u=10a774fd4be767fa3b23a82a98bbfe102c17f0f3&v=4?s=100" width="100px;" alt="Mirae Parker"/><br /><sub><b>Mirae Parker</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=miraep8" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=miraep8" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/MBristle"><img src="https://avatars.githubusercontent.com/MBristle?s=100" width="100px;" alt="Mirko Bristle"/><br /><sub><b>Mirko Bristle</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=MBristle" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://mo-saif.github.io/"><img src="https://avatars0.githubusercontent.com/u/27867617?v=4?s=100" width="100px;" alt="Mohammed Saif Kazamel"/><br /><sub><b>Mohammed Saif Kazamel</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3AMo-Saif" title="Bug reports">π</a></td> - </tr> - <tr> <td align="center" valign="top" width="11.11%"><a href="https://moradabaz.github.io/"><img src="https://avatars.githubusercontent.com/u/29915156?v=4?s=100" width="100px;" alt="Morad :)"/><br /><sub><b>Morad :)</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=moradabaz" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=moradabaz" title="Tests">β οΈ</a> <a href="https://github.com/sktime/sktime/commits?author=moradabaz" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/Multivin12"><img src="https://avatars3.githubusercontent.com/u/36476633?v=4?s=100" width="100px;" alt="Multivin12"/><br /><sub><b>Multivin12</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Multivin12" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=Multivin12" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/marcio55afr"><img src="https://avatars.githubusercontent.com/u/42646282?v=4?s=100" width="100px;" alt="MΓ‘rcio A. Freitas Jr"/><br /><sub><b>MΓ‘rcio A. Freitas Jr</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=marcio55afr" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/niekvanderlaan"><img src="https://avatars.githubusercontent.com/u/9962825?v=4?s=100" width="100px;" alt="Niek van der Laan"/><br /><sub><b>Niek van der Laan</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=niekvanderlaan" title="Code">π»</a></td> + </tr> + <tr> <td align="center" valign="top" width="11.11%"><a href="https://github.com/ngupta23"><img src="https://avatars0.githubusercontent.com/u/33585645?v=4?s=100" width="100px;" alt="Nikhil Gupta"/><br /><sub><b>Nikhil Gupta</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=ngupta23" title="Code">π»</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Angupta23" title="Bug reports">π</a> <a href="https://github.com/sktime/sktime/commits?author=ngupta23" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/nshahpazov/"><img src="https://avatars.githubusercontent.com/nshahpazov?s=100" width="100px;" alt="Nikola Shahpazov"/><br /><sub><b>Nikola Shahpazov</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=nshahpazov" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/nilesh05apr"><img src="https://avatars.githubusercontent.com/u/65773314?v=4?s=100" width="100px;" alt="Nilesh Kumar"/><br /><sub><b>Nilesh Kumar</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=nilesh05apr" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/ninfueng"><img src="https://avatars2.githubusercontent.com/u/28499769?v=4?s=100" width="100px;" alt="Ninnart Fuengfusin"/><br /><sub><b>Ninnart Fuengfusin</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=ninfueng" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/NoaBenAmi"><img src="https://avatars.githubusercontent.com/u/37590002?v=4?s=100" width="100px;" alt="Noa Ben Ami"/><br /><sub><b>Noa Ben Ami</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=NoaBenAmi" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=NoaBenAmi" title="Tests">β οΈ</a> <a href="https://github.com/sktime/sktime/commits?author=NoaBenAmi" title="Documentation">π</a></td> - </tr> - <tr> <td align="center" valign="top" width="11.11%"><a href="https://github.com/shchur"><img src="https://avatars.githubusercontent.com/u/6944857?v=4?s=100" width="100px;" alt="Oleksandr Shchur"/><br /><sub><b>Oleksandr Shchur</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Ashchur" title="Bug reports">π</a> <a href="https://github.com/sktime/sktime/commits?author=shchur" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/kachayev"><img src="https://avatars.githubusercontent.com/u/485647?v=4?s=100" width="100px;" alt="Oleksii Kachaiev"/><br /><sub><b>Oleksii Kachaiev</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=kachayev" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=kachayev" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/olivermatthews"><img src="https://avatars.githubusercontent.com/u/31141490?v=4?s=100" width="100px;" alt="Oliver Matthews"/><br /><sub><b>Oliver Matthews</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=OliverMatthews" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/prockenschaub"><img src="https://avatars0.githubusercontent.com/u/15381732?v=4?s=100" width="100px;" alt="Patrick Rockenschaub"/><br /><sub><b>Patrick Rockenschaub</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=prockenschaub" title="Code">π»</a> <a href="#design-prockenschaub" title="Design">π¨</a> <a href="#ideas-prockenschaub" title="Ideas, Planning, & Feedback">π€</a> <a href="https://github.com/sktime/sktime/commits?author=prockenschaub" title="Tests">β οΈ</a></td> + </tr> + <tr> <td align="center" valign="top" width="11.11%"><a href="http://www2.informatik.hu-berlin.de/~schaefpa/"><img src="https://avatars0.githubusercontent.com/u/7783034?v=4?s=100" width="100px;" alt="Patrick SchΓ€fer"/><br /><sub><b>Patrick SchΓ€fer</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=patrickzib" title="Code">π»</a> <a href="#tutorial-patrickzib" title="Tutorials">β </a></td> <td align="center" valign="top" width="11.11%"><a href="https://ber.gp"><img src="https://avatars1.githubusercontent.com/u/9824244?v=4?s=100" width="100px;" alt="Paul"/><br /><sub><b>Paul</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Pangoraw" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/paulyim97/"><img src="https://avatars.githubusercontent.com/pyyim?s=100" width="100px;" alt="Paul Yim"/><br /><sub><b>Paul Yim</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=pyyim" title="Code">π»</a> <a href="#example-pyyim" title="Examples">π‘</a> <a href="https://github.com/sktime/sktime/commits?author=pyyim" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://www.imes.uni-hannover.de/de/institut/team/m-sc-karl-philipp-kortmann/"><img src="https://avatars.githubusercontent.com/u/20466981?v=4?s=100" width="100px;" alt="Philipp Kortmann"/><br /><sub><b>Philipp Kortmann</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=MrPr3ntice" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=MrPr3ntice" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/Piyush1729"><img src="https://avatars2.githubusercontent.com/u/64950012?v=4?s=100" width="100px;" alt="Piyush Gade"/><br /><sub><b>Piyush Gade</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Piyush1729" title="Code">π»</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3APiyush1729" title="Reviewed Pull Requests">π</a></td> - </tr> - <tr> + <td align="center" valign="top" width="11.11%"><a href="https://github.com/rahulporuri"><img src="https://avatars.githubusercontent.com/u/1926457?v=4?s=100" width="100px;" alt="Poruri Sai Rahul"/><br /><sub><b>Poruri Sai Rahul</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=rahulporuri" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/pranav-prajapati-a5b413226/"><img src="https://avatars.githubusercontent.com/u/94780581?v=4?s=100" width="100px;" alt="Pranav Prajapati"/><br /><sub><b>Pranav Prajapati</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=pranavvp16" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=pranavvp16" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/pul95"><img src="https://avatars.githubusercontent.com/pul95?s=100" width="100px;" alt="Pulkit Verma"/><br /><sub><b>Pulkit Verma</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=pul95" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/Quaterion"><img src="https://avatars2.githubusercontent.com/u/23200273?v=4?s=100" width="100px;" alt="Quaterion"/><br /><sub><b>Quaterion</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3AQuaterion" title="Bug reports">π</a></td> + </tr> + <tr> <td align="center" valign="top" width="11.11%"><a href="https://github.com/rakshitha123"><img src="https://avatars.githubusercontent.com/u/7654679?v=4?s=100" width="100px;" alt="Rakshitha Godahewa"/><br /><sub><b>Rakshitha Godahewa</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=rakshitha123" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=rakshitha123" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/Ram0nB"><img src="https://avatars.githubusercontent.com/u/45173421?s=100" width="100px;" alt="Ramon Bussing"/><br /><sub><b>Ramon Bussing</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Ram0nB" title="Documentation">π</a> <a href="https://github.com/sktime/sktime/commits?author=Ram0nB" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/RavenRudi"><img src="https://avatars.githubusercontent.com/u/46402968?v=4?s=100" width="100px;" alt="RavenRudi"/><br /><sub><b>RavenRudi</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=RavenRudi" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/wolph"><img src="?s=100" width="100px;" alt="Rick van Hattem"/><br /><sub><b>Rick van Hattem</b></sub></a><br /><a href="#infra-wolph" title="Infrastructure (Hosting, Build-Tools, etc)">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/Ris-Bali"><img src="https://avatars.githubusercontent.com/u/81592570?v=4?s=100" width="100px;" alt="Rishabh Bali"/><br /><sub><b>Rishabh Bali</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Ris-Bali" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/RishiKumarRay"><img src="https://avatars.githubusercontent.com/u/87641376?v=4?s=100" width="100px;" alt="Rishi Kumar Ray"/><br /><sub><b>Rishi Kumar Ray</b></sub></a><br /><a href="#infra-RishiKumarRay" title="Infrastructure (Hosting, Build-Tools, etc)">π</a></td> - </tr> - <tr> + <td align="center" valign="top" width="11.11%"><img src="https://avatars.githubusercontent.com/u/55790848?v=4?s=100" width="100px;" alt="Riya Elizabeth John"/><br /><sub><b>Riya Elizabeth John</b></sub><br /><a href="https://github.com/sktime/sktime/commits?author=Riyabelle25" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/Riyabelle25"><img src="https://avatars.githubusercontent.com/u/55790848?v=4?s=100" width="100px;" alt="Riya Elizabeth John"/><br /><sub><b>Riya Elizabeth John</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Riyabelle25" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=Riyabelle25" title="Tests">β οΈ</a> <a href="https://github.com/sktime/sktime/commits?author=Riyabelle25" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/romanlutz/"><img src="https://avatars.githubusercontent.com/u/10245648?v=4?s=100" width="100px;" alt="Roman Lutz"/><br /><sub><b>Roman Lutz</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=romanlutz" title="Documentation">π</a></td> + </tr> + <tr> <td align="center" valign="top" width="11.11%"><a href="https://github.com/ronnie-llamado"><img src="https://avatars.githubusercontent.com/ronnie-llamado?s=100" width="100px;" alt="Ronnie Llamado"/><br /><sub><b>Ronnie Llamado</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=ronnie-llamado" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/rnkuhns"><img src="https://avatars0.githubusercontent.com/u/26907244?v=4?s=100" width="100px;" alt="Ryan Kuhns"/><br /><sub><b>Ryan Kuhns</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=RNKuhns" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=RNKuhns" title="Documentation">π</a> <a href="#tutorial-RNKuhns" title="Tutorials">β </a> <a href="#example-RNKuhns" title="Examples">π‘</a> <a href="#ideas-RNKuhns" title="Ideas, Planning, & Feedback">π€</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3ARNKuhns" title="Reviewed Pull Requests">π</a> <a href="https://github.com/sktime/sktime/commits?author=RNKuhns" title="Tests">β οΈ</a></td> - <td align="center" valign="top" width="11.11%"><a href="https://github.com/achieveordie"><img src="https://avatars.githubusercontent.com/u/54197164?v=4?s=100" width="100px;" alt="Sagar Mishra"/><br /><sub><b>Sagar Mishra</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=achieveordie" title="Tests">β οΈ</a></td> + <td align="center" valign="top" width="11.11%"><a href="https://github.com/achieveordie"><img src="https://avatars.githubusercontent.com/u/54197164?v=4?s=100" width="100px;" alt="Sagar Mishra"/><br /><sub><b>Sagar Mishra</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Aachieveordie" title="Bug reports">π</a> <a href="https://github.com/sktime/sktime/commits?author=achieveordie" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=achieveordie" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://sajay.online"><img src="https://avatars2.githubusercontent.com/u/25329624?v=4?s=100" width="100px;" alt="Sajaysurya Ganesh"/><br /><sub><b>Sajaysurya Ganesh</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=sajaysurya" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=sajaysurya" title="Documentation">π</a> <a href="#design-sajaysurya" title="Design">π¨</a> <a href="#example-sajaysurya" title="Examples">π‘</a> <a href="#ideas-sajaysurya" title="Ideas, Planning, & Feedback">π€</a> <a href="https://github.com/sktime/sktime/commits?author=sajaysurya" title="Tests">β οΈ</a> <a href="#tutorial-sajaysurya" title="Tutorials">β </a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/SamiAlavi"><img src="https://avatars.githubusercontent.com/u/32700289?v=4?s=100" width="100px;" alt="Sami Alavi"/><br /><sub><b>Sami Alavi</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=SamiAlavi" title="Code">π»</a> <a href="#maintenance-SamiAlavi" title="Maintenance">π§</a></td> + <td align="center" valign="top" width="11.11%"><a href="https://github.com/sssilvar"><img src="https://avatars.githubusercontent.com/u/16252054?v=4?s=100" width="100px;" alt="Santiago Smith Silva"/><br /><sub><b>Santiago Smith Silva</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=sssilvar" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/Saransh-cpp"><img src="https://avatars.githubusercontent.com/u/74055102?v=4?s=100" width="100px;" alt="Saransh Chopra"/><br /><sub><b>Saransh Chopra</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Saransh-cpp" title="Documentation">π</a> <a href="#infra-Saransh-cpp" title="Infrastructure (Hosting, Build-Tools, etc)">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/satya-pattnaik-77a430144/"><img src="https://avatars.githubusercontent.com/u/22102468?v=4?s=100" width="100px;" alt="Satya Prakash Pattnaik"/><br /><sub><b>Satya Prakash Pattnaik</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=satya-pattnaik" title="Documentation">π</a></td> + <td align="center" valign="top" width="11.11%"><a href="https://github.com/dasgupsa"><img src="https://avatars2.githubusercontent.com/u/10398956?v=4?s=100" width="100px;" alt="Saurabh Dasgupta"/><br /><sub><b>Saurabh Dasgupta</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=dasgupsa" title="Code">π»</a></td> </tr> <tr> - <td align="center" valign="top" width="11.11%"><a href="https://github.com/dasgupsa"><img src="https://avatars2.githubusercontent.com/u/10398956?v=4?s=100" width="100px;" alt="Saurabh Dasgupta"/><br /><sub><b>Saurabh Dasgupta</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=dasgupsa" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/SebasKoel"><img src="https://avatars3.githubusercontent.com/u/66252156?v=4?s=100" width="100px;" alt="Sebastiaan Koel"/><br /><sub><b>Sebastiaan Koel</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=SebasKoel" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=SebasKoel" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/shagn"><img src="https://avatars.githubusercontent.com/u/16029092?v=4?s=100" width="100px;" alt="Sebastian Hagn"/><br /><sub><b>Sebastian Hagn</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=shagn" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/ShivamPathak99"><img src="https://avatars.githubusercontent.com/u/98941325?s=400&v=4?s=100" width="100px;" alt="Shivam Pathak"/><br /><sub><b>Shivam Pathak</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=ShivamPathak99" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/AurumnPegasus"><img src="https://avatars.githubusercontent.com/u/54315149?v=4?s=100" width="100px;" alt="Shivansh Subramanian"/><br /><sub><b>Shivansh Subramanian</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=AurumnPegasus" title="Documentation">π</a> <a href="https://github.com/sktime/sktime/commits?author=AurumnPegasus" title="Code">π»</a></td> + <td align="center" valign="top" width="11.11%"><a href="https://github.com/sbuse"><img src="https://avatars.githubusercontent.com/u/24408707?v=4?s=100" width="100px;" alt="Simon B."/><br /><sub><b>Simon B.</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=sbuse" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/solomon-botchway-a1383821b/"><img src="https://avatars.githubusercontent.com/u/62394255?v=4?s=100" width="100px;" alt="Solomon Botchway"/><br /><sub><b>Solomon Botchway</b></sub></a><br /><a href="#maintenance-snnbotchway" title="Maintenance">π§</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/khrapovs"><img src="https://avatars.githubusercontent.com/u/3774663?v=4?s=100" width="100px;" alt="Stanislav Khrapov"/><br /><sub><b>Stanislav Khrapov</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=khrapovs" title="Code">π»</a></td> + <td align="center" valign="top" width="11.11%"><a href="https://github.com/steenrotsman"><img src="https://avatars.githubusercontent.com/u/78110080?s=400&v=4?s=100" width="100px;" alt="Stijn J. Rotman"/><br /><sub><b>Stijn J. Rotman</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=steenrotsman" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=steenrotsman" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/SveaMeyer13"><img src="https://avatars.githubusercontent.com/u/46671894?v=4?s=100" width="100px;" alt="Svea Marie Meyer"/><br /><sub><b>Svea Marie Meyer</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=SveaMeyer13" title="Documentation">π</a> <a href="https://github.com/sktime/sktime/commits?author=SveaMeyer13" title="Code">π»</a></td> - <td align="center" valign="top" width="11.11%"><a href="https://github.com/TNTran92"><img src="https://avatars.githubusercontent.com/u/55965636?v=4?s=100" width="100px;" alt="TNTran92"/><br /><sub><b>TNTran92</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=TNTran92" title="Code">π»</a></td> </tr> <tr> + <td align="center" valign="top" width="11.11%"><a href="https://github.com/TNTran92"><img src="https://avatars.githubusercontent.com/u/55965636?v=4?s=100" width="100px;" alt="TNTran92"/><br /><sub><b>TNTran92</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=TNTran92" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/Taise228"><img src="https://avatars.githubusercontent.com/u/95762401?s=400&v=4?s=100" width="100px;" alt="Taisei Yamamoto"/><br /><sub><b>Taisei Yamamoto</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Taise228" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://thayeylolu.github.io/portfolio/"><img src="https://avatars.githubusercontent.com/u/13348874?v=4?s=100" width="100px;" alt="Taiwo Owoseni"/><br /><sub><b>Taiwo Owoseni</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=thayeylolu" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/lnthach"><img src="https://avatars0.githubusercontent.com/u/7788363?v=4?s=100" width="100px;" alt="Thach Le Nguyen"/><br /><sub><b>Thach Le Nguyen</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=lnthach" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=lnthach" title="Tests">β οΈ</a></td> @@ -254,53 +270,57 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d <td align="center" valign="top" width="11.11%"><a href="https://github.com/xxl4tomxu98"><img src="https://avatars.githubusercontent.com/u/62292177?s=40&v=4?s=100" width="100px;" alt="Tom Xu"/><br /><sub><b>Tom Xu</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=xxl4tomxu98" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=xxl4tomxu98" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/tpvasconcelos"><img src="https://avatars.githubusercontent.com/u/17701527?v=4?s=100" width="100px;" alt="Tomas P. de Vasconcelos"/><br /><sub><b>Tomas P. de Vasconcelos</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Atpvasconcelos" title="Bug reports">π</a> <a href="https://github.com/sktime/sktime/commits?author=tpvasconcelos" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/tch"><img src="https://avatars3.githubusercontent.com/u/184076?v=4?s=100" width="100px;" alt="Tomasz Chodakowski"/><br /><sub><b>Tomasz Chodakowski</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=tch" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=tch" title="Documentation">π</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Atch" title="Bug reports">π</a></td> - <td align="center" valign="top" width="11.11%"><a href="http://www.timeseriesclassification.com"><img src="https://avatars1.githubusercontent.com/u/9594042?v=4?s=100" width="100px;" alt="Tony Bagnall"/><br /><sub><b>Tony Bagnall</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=TonyBagnall" title="Code">π»</a> <a href="#business-TonyBagnall" title="Business development">πΌ</a> <a href="https://github.com/sktime/sktime/commits?author=TonyBagnall" title="Documentation">π</a> <a href="#design-TonyBagnall" title="Design">π¨</a> <a href="#eventOrganizing-TonyBagnall" title="Event Organizing">π</a> <a href="#fundingFinding-TonyBagnall" title="Funding Finding">π</a> <a href="#ideas-TonyBagnall" title="Ideas, Planning, & Feedback">π€</a> <a href="#projectManagement-TonyBagnall" title="Project Management">π</a> <a href="#question-TonyBagnall" title="Answering Questions">π¬</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3ATonyBagnall" title="Reviewed Pull Requests">π</a> <a href="#talk-TonyBagnall" title="Talks">π’</a> <a href="#data-TonyBagnall" title="Data">π£</a></td> </tr> <tr> + <td align="center" valign="top" width="11.11%"><a href="http://www.timeseriesclassification.com"><img src="https://avatars1.githubusercontent.com/u/9594042?v=4?s=100" width="100px;" alt="Tony Bagnall"/><br /><sub><b>Tony Bagnall</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=TonyBagnall" title="Code">π»</a> <a href="#business-TonyBagnall" title="Business development">πΌ</a> <a href="https://github.com/sktime/sktime/commits?author=TonyBagnall" title="Documentation">π</a> <a href="#design-TonyBagnall" title="Design">π¨</a> <a href="#eventOrganizing-TonyBagnall" title="Event Organizing">π</a> <a href="#fundingFinding-TonyBagnall" title="Funding Finding">π</a> <a href="#ideas-TonyBagnall" title="Ideas, Planning, & Feedback">π€</a> <a href="#projectManagement-TonyBagnall" title="Project Management">π</a> <a href="#question-TonyBagnall" title="Answering Questions">π¬</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3ATonyBagnall" title="Reviewed Pull Requests">π</a> <a href="#talk-TonyBagnall" title="Talks">π’</a> <a href="#data-TonyBagnall" title="Data">π£</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/utsavcoding"><img src="https://avatars3.githubusercontent.com/u/55446385?v=4?s=100" width="100px;" alt="Utsav Kumar Tiwari"/><br /><sub><b>Utsav Kumar Tiwari</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=utsavcoding" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=utsavcoding" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/Vasudeva-bit"><img src="https://avatars.githubusercontent.com/u/70791259?v=4?s=100" width="100px;" alt="Vasudeva Kilaru"/><br /><sub><b>Vasudeva Kilaru</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=Vasudeva-bit" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=Vasudeva-bit" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/victordremov"><img src="https://avatars.githubusercontent.com/u/32140716?s=100" width="100px;" alt="Viktor Dremov"/><br /><sub><b>Viktor Dremov</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=victordremov" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/ViktorKaz"><img src="https://avatars0.githubusercontent.com/u/33499138?v=4?s=100" width="100px;" alt="ViktorKaz"/><br /><sub><b>ViktorKaz</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=ViktorKaz" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=ViktorKaz" title="Documentation">π</a> <a href="#design-ViktorKaz" title="Design">π¨</a></td> + <td align="center" valign="top" width="11.11%"><a href="https://github.com/vnicholson1"><img src="?s=100" width="100px;" alt="Vincent Nicholson"/><br /><sub><b>Vincent Nicholson</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=vnicholson1" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/VyomkeshVyas"><img src="?s=100" width="100px;" alt="Vyomkesh Vyas"/><br /><sub><b>Vyomkesh Vyas</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=VyomkeshVyas" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=VyomkeshVyas" title="Documentation">π</a> <a href="#example-VyomkeshVyas" title="Examples">π‘</a> <a href="https://github.com/sktime/sktime/commits?author=VyomkeshVyas" title="Tests">β οΈ</a></td> + <td align="center" valign="top" width="11.11%"><a href="https://github.com/wayneadams"><img src="https://avatars.githubusercontent.com/u/15034841?s=400&u=d717e9945910bcc844c5e64cd56d570c6cc4e8e6&v=4?s=100" width="100px;" alt="Wayne Adams"/><br /><sub><b>Wayne Adams</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=wayneadams" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/templierw/"><img src="https://github.com/templierw.png?s=100" width="100px;" alt="William Templier"/><br /><sub><b>William Templier</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=templierw" title="Documentation">π</a></td> + </tr> + <tr> <td align="center" valign="top" width="11.11%"><a href="https://github.com/magittan"><img src="https://avatars0.githubusercontent.com/u/14024202?v=4?s=100" width="100px;" alt="William Zheng"/><br /><sub><b>William Zheng</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=magittan" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=magittan" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/yairbeer"><img src="https://avatars.githubusercontent.com/yairbeer?s=100" width="100px;" alt="Yair Beer"/><br /><sub><b>Yair Beer</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=yairbeer" title="Code">π»</a></td> + <td align="center" valign="top" width="11.11%"><a href="https://www.linkedin.com/in/yann-hallouard/"><img src="https://avatars.githubusercontent.com/YHallouard?s=100" width="100px;" alt="Yann Hallouard"/><br /><sub><b>Yann Hallouard</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=YHallouard" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=YHallouard" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/yashlamba"><img src="https://avatars.githubusercontent.com/u/44164398?v=4?s=100" width="100px;" alt="Yash Lamba"/><br /><sub><b>Yash Lamba</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=yashlamba" title="Code">π»</a></td> - </tr> - <tr> <td align="center" valign="top" width="11.11%"><a href="https://github.com/xuyxu"><img src="https://avatars2.githubusercontent.com/u/22359569?v=4?s=100" width="100px;" alt="Yi-Xuan Xu"/><br /><sub><b>Yi-Xuan Xu</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=xuyxu" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=xuyxu" title="Tests">β οΈ</a> <a href="#maintenance-xuyxu" title="Maintenance">π§</a> <a href="https://github.com/sktime/sktime/commits?author=xuyxu" title="Documentation">π</a></td> + <td align="center" valign="top" width="11.11%"><a href="https://github.com/sz85512678"><img src="https://avatars.githubusercontent.com/sz85512678?s=100" width="100px;" alt="Zhen Shao"/><br /><sub><b>Zhen Shao</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=sz85512678" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/ZiyaoWei"><img src="https://avatars.githubusercontent.com/u/940823?v=4?s=100" width="100px;" alt="Ziyao Wei"/><br /><sub><b>Ziyao Wei</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=ZiyaoWei" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/aa25desh"><img src="https://avatars1.githubusercontent.com/u/29518290?v=4?s=100" width="100px;" alt="aa25desh"/><br /><sub><b>aa25desh</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=aa25desh" title="Code">π»</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Aaa25desh" title="Bug reports">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/abandus"><img src="https://avatars2.githubusercontent.com/u/46486474?v=4?s=100" width="100px;" alt="abandus"/><br /><sub><b>abandus</b></sub></a><br /><a href="#ideas-abandus" title="Ideas, Planning, & Feedback">π€</a> <a href="https://github.com/sktime/sktime/commits?author=abandus" title="Code">π»</a></td> + </tr> + <tr> <td align="center" valign="top" width="11.11%"><a href="https://github.com/adoherty21"><img src="https://avatars.githubusercontent.com/u/52799751?s=400&v=4?s=100" width="100px;" alt="adoherty21"/><br /><sub><b>adoherty21</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Aadoherty21" title="Bug reports">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/bethrice44"><img src="https://avatars.githubusercontent.com/u/11226988?v=4?s=100" width="100px;" alt="bethrice44"/><br /><sub><b>bethrice44</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Abethrice44" title="Bug reports">π</a> <a href="https://github.com/sktime/sktime/commits?author=bethrice44" title="Code">π»</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3Abethrice44" title="Reviewed Pull Requests">π</a> <a href="https://github.com/sktime/sktime/commits?author=bethrice44" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/big-o"><img src="https://avatars1.githubusercontent.com/u/1134151?v=4?s=100" width="100px;" alt="big-o"/><br /><sub><b>big-o</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=big-o" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=big-o" title="Tests">β οΈ</a> <a href="#design-big-o" title="Design">π¨</a> <a href="#ideas-big-o" title="Ideas, Planning, & Feedback">π€</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3Abig-o" title="Reviewed Pull Requests">π</a> <a href="#tutorial-big-o" title="Tutorials">β </a> <a href="#mentoring-big-o" title="Mentoring">π§βπ«</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/bobbys-dev"><img src="https://avatars.githubusercontent.com/bobbys-dev?s=100" width="100px;" alt="bobbys"/><br /><sub><b>bobbys</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=bobbys-dev" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/brettkoonce"><img src="https://avatars2.githubusercontent.com/u/11281814?v=4?s=100" width="100px;" alt="brett koonce"/><br /><sub><b>brett koonce</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=brettkoonce" title="Documentation">π</a></td> - </tr> - <tr> <td align="center" valign="top" width="11.11%"><a href="https://github.com/btrtts"><img src="https://avatars3.githubusercontent.com/u/66252156?v=4?s=100" width="100px;" alt="btrtts"/><br /><sub><b>btrtts</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=btrtts" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/chizzi25"><img src="https://avatars3.githubusercontent.com/u/67911243?v=4?s=100" width="100px;" alt="chizzi25"/><br /><sub><b>chizzi25</b></sub></a><br /><a href="#blog-chizzi25" title="Blogposts">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/chrisholder"><img src="https://avatars.githubusercontent.com/u/4674372?v=4?s=100" width="100px;" alt="chrisholder"/><br /><sub><b>chrisholder</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=chrisholder" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=chrisholder" title="Tests">β οΈ</a> <a href="https://github.com/sktime/sktime/commits?author=chrisholder" title="Documentation">π</a> <a href="#design-chrisholder" title="Design">π¨</a> <a href="#example-chrisholder" title="Examples">π‘</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/danbartl"><img src="https://avatars.githubusercontent.com/u/19947407?v=4?s=100" width="100px;" alt="danbartl"/><br /><sub><b>danbartl</b></sub></a><br /><a href="https://github.com/sktime/sktime/issues?q=author%3Adanbartl" title="Bug reports">π</a> <a href="https://github.com/sktime/sktime/commits?author=danbartl" title="Code">π»</a> <a href="https://github.com/sktime/sktime/pulls?q=is%3Apr+reviewed-by%3Adanbartl" title="Reviewed Pull Requests">π</a> <a href="#talk-danbartl" title="Talks">π’</a> <a href="https://github.com/sktime/sktime/commits?author=danbartl" title="Tests">β οΈ</a> <a href="#tutorial-danbartl" title="Tutorials">β </a> <a href="#video-danbartl" title="Videos">πΉ</a></td> + </tr> + <tr> <td align="center" valign="top" width="11.11%"><a href="https://github.com/hamzahiqb"><img src="https://avatars3.githubusercontent.com/u/10302415?v=4?s=100" width="100px;" alt="hamzahiqb"/><br /><sub><b>hamzahiqb</b></sub></a><br /><a href="#infra-hamzahiqb" title="Infrastructure (Hosting, Build-Tools, etc)">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/hiqbal2"><img src="https://avatars3.githubusercontent.com/u/10302415?v=4?s=100" width="100px;" alt="hiqbal2"/><br /><sub><b>hiqbal2</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=hiqbal2" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/jesellier"><img src="https://avatars0.githubusercontent.com/u/51952076?v=4?s=100" width="100px;" alt="jesellier"/><br /><sub><b>jesellier</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=jesellier" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/jschemm"><img src="https://avatars.githubusercontent.com/u/81151346?v=4?s=100" width="100px;" alt="jschemm"/><br /><sub><b>jschemm</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=jschemm" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/kkoziara"><img src="https://avatars1.githubusercontent.com/u/4346849?v=4?s=100" width="100px;" alt="kkoziara"/><br /><sub><b>kkoziara</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=kkoziara" title="Code">π»</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Akkoziara" title="Bug reports">π</a></td> - </tr> - <tr> <td align="center" valign="top" width="11.11%"><a href="https://github.com/matteogales"><img src="https://avatars0.githubusercontent.com/u/9269326?v=4?s=100" width="100px;" alt="matteogales"/><br /><sub><b>matteogales</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=matteogales" title="Code">π»</a> <a href="#design-matteogales" title="Design">π¨</a> <a href="#ideas-matteogales" title="Ideas, Planning, & Feedback">π€</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/oleskiewicz"><img src="https://avatars1.githubusercontent.com/u/5682158?v=4?s=100" width="100px;" alt="oleskiewicz"/><br /><sub><b>oleskiewicz</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=oleskiewicz" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=oleskiewicz" title="Documentation">π</a> <a href="https://github.com/sktime/sktime/commits?author=oleskiewicz" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/pabworks"><img src="https://avatars.githubusercontent.com/u/32725127?v=4?s=100" width="100px;" alt="pabworks"/><br /><sub><b>pabworks</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=pabworks" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=pabworks" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/xloem"><img src="?s=100" width="100px;" alt="patiently pending world peace"/><br /><sub><b>patiently pending world peace</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=xloem" title="Code">π»</a></td> + </tr> + <tr> <td align="center" valign="top" width="11.11%"><a href="https://github.com/raishubham1"><img src="https://avatars3.githubusercontent.com/u/29356417?v=4?s=100" width="100px;" alt="raishubham1"/><br /><sub><b>raishubham1</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=raishubham1" title="Documentation">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/simone-pignotti"><img src="https://avatars1.githubusercontent.com/u/44410066?v=4?s=100" width="100px;" alt="simone-pignotti"/><br /><sub><b>simone-pignotti</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=simone-pignotti" title="Code">π»</a> <a href="https://github.com/sktime/sktime/issues?q=author%3Asimone-pignotti" title="Bug reports">π</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/sophijka"><img src="https://avatars2.githubusercontent.com/u/47450591?v=4?s=100" width="100px;" alt="sophijka"/><br /><sub><b>sophijka</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=sophijka" title="Documentation">π</a> <a href="#maintenance-sophijka" title="Maintenance">π§</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/sri1419"><img src="https://avatars2.githubusercontent.com/u/65078278?v=4?s=100" width="100px;" alt="sri1419"/><br /><sub><b>sri1419</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=sri1419" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/tensorflow-as-tf"><img src="https://avatars.githubusercontent.com/u/51345718?v=4?s=100" width="100px;" alt="tensorflow-as-tf"/><br /><sub><b>tensorflow-as-tf</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=tensorflow-as-tf" title="Code">π»</a></td> - </tr> - <tr> <td align="center" valign="top" width="11.11%"><a href="https://github.com/vedazeren"><img src="https://avatars3.githubusercontent.com/u/63582874?v=4?s=100" width="100px;" alt="vedazeren"/><br /><sub><b>vedazeren</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=vedazeren" title="Code">π»</a> <a href="https://github.com/sktime/sktime/commits?author=vedazeren" title="Tests">β οΈ</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/vincent-nich12"><img src="https://avatars3.githubusercontent.com/u/36476633?v=4?s=100" width="100px;" alt="vincent-nich12"/><br /><sub><b>vincent-nich12</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=vincent-nich12" title="Code">π»</a></td> <td align="center" valign="top" width="11.11%"><a href="https://github.com/vollmersj"><img src="https://avatars2.githubusercontent.com/u/12613127?v=4?s=100" width="100px;" alt="vollmersj"/><br /><sub><b>vollmersj</b></sub></a><br /><a href="https://github.com/sktime/sktime/commits?author=vollmersj" title="Documentation">π</a></td> diff --git a/Makefile b/Makefile index e916f804495..0697bdbf4a6 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,20 @@ test: ## Run unit tests cp setup.cfg ${TEST_DIR} python -m pytest +full_test: ## Run all tests + -rm -rf ${TEST_DIR} + mkdir -p ${TEST_DIR} + cp .coveragerc ${TEST_DIR} + cp setup.cfg ${TEST_DIR} + python -m pytest --only_changed_modules False + +test_without_datasets: ## Run unit tests skipping sktime/datasets + -rm -rf ${TEST_DIR} + mkdir -p ${TEST_DIR} + cp .coveragerc ${TEST_DIR} + cp setup.cfg ${TEST_DIR} + python -m pytest --ignore sktime/datasets + test_check_suite: ## run only estimator contract tests in TestAll classes -rm -rf ${TEST_DIR} mkdir -p ${TEST_DIR} @@ -46,12 +60,12 @@ test_softdeps: ## Run unit tests to check soft dependency handling in estimators python -m pytest -v -n auto --showlocals -k 'test_check_estimator_does_not_raise' $(PYTESTOPTIONS) --pyargs sktime.utils.tests python -m pytest -v -n auto --showlocals $(PYTESTOPTIONS) --pyargs sktime.tests.test_softdeps -test_softdeps_full: ## Run all non-suite unit tests without soft dependencies +test_softdeps_full: ## Run all non-suite unit tests without soft dependencies or downloading datasets -rm -rf ${TEST_DIR} mkdir -p ${TEST_DIR} cp setup.cfg ${TEST_DIR} cd ${TEST_DIR} - python -m pytest -v --showlocals -k 'not TestAll' $(PYTESTOPTIONS) + python -m pytest -v --showlocals --ignore sktime/datasets -k 'not TestAll' $(PYTESTOPTIONS) test_mlflow: ## Run mlflow integration tests -rm -rf ${TEST_DIR} @@ -94,4 +108,4 @@ nb: clean dockertest: docker build -t sktime -f build_tools/docker/$(PYTHON_VERSION).dockerfile . - docker run -it --name sktime sktime bash -c "make test" + docker run -it --name sktime sktime bash -c "make full_test" diff --git a/README.md b/README.md index bcb9a99f126..33b146fe906 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ > A unified interface for machine learning with time series -:rocket: **Version 0.24.0 out now!** [Check out the release notes here](https://www.sktime.net/en/latest/changelog.html). +:rocket: **Version 0.26.0 out now!** [Check out the release notes here](https://www.sktime.net/en/latest/changelog.html). sktime is a library for time series analysis in Python. It provides a unified interface for multiple time series learning tasks. Currently, this includes time series classification, regression, clustering, annotation, and forecasting. It comes with [time series algorithms](https://www.sktime.net/en/stable/estimator_overview.html) and [scikit-learn] compatible tools to build, tune and validate time series models. @@ -66,8 +66,6 @@ Our objective is to enhance the interoperability and usability of the time serie sktime also provides **interfaces to related libraries**, for example [scikit-learn], [statsmodels], [tsfresh], [PyOD], and [fbprophet], among others. -For **deep learning**, see our companion package: [sktime-dl](https://github.com/sktime/sktime-dl). - [statsmodels]: https://www.statsmodels.org/stable/index.html [tsfresh]: https://tsfresh.readthedocs.io/en/latest/ [pyod]: https://pyod.readthedocs.io/en/latest/ @@ -84,6 +82,7 @@ For **deep learning**, see our companion package: [sktime-dl](https://github.com | **[Time Series Distances/Kernels]** | maturing | [Tutorial](https://github.com/sktime/sktime/blob/main/examples/03_transformers.ipynb) Β· [API Reference](https://www.sktime.net/en/latest/api_reference/dists_kernels.html) Β· [Extension Template](https://github.com/sktime/sktime/blob/main/extension_templates/dist_kern_panel.py) | | **[Time Series Alignment]** | experimental | [API Reference](https://www.sktime.net/en/latest/api_reference/alignment.html) Β· [Extension Template](https://github.com/sktime/sktime/blob/main/extension_templates/alignment.py) | | **[Annotation]** | experimental | [Extension Template](https://github.com/sktime/sktime/blob/main/extension_templates/annotation.py) | +| **[Time Series Splitters]** | maturing | [Extension Template](https://github.com/sktime/sktime/blob/main/extension_templates/split.py) | | | **[Distributions and simulation]** | experimental | | [forecasting]: https://github.com/sktime/sktime/tree/main/sktime/forecasting @@ -95,6 +94,7 @@ For **deep learning**, see our companion package: [sktime-dl](https://github.com [time series alignment]: https://github.com/sktime/sktime/tree/main/sktime/alignment [transformations]: https://github.com/sktime/sktime/tree/main/sktime/transformations [distributions and simulation]: https://github.com/sktime/sktime/tree/main/sktime/proba +[time series splitters]: https://github.com/sktime/sktime/tree/main/sktime/split [parameter fitting]: https://github.com/sktime/sktime/tree/main/sktime/param_est @@ -169,8 +169,8 @@ flexible choice of soft dependencies is unavailable via `conda`) ``` python from sktime.datasets import load_airline from sktime.forecasting.base import ForecastingHorizon -from sktime.forecasting.model_selection import temporal_train_test_split from sktime.forecasting.theta import ThetaForecaster +from sktime.split import temporal_train_test_split from sktime.performance_metrics.forecasting import mean_absolute_percentage_error y = load_airline() diff --git a/build_tools/run_blogposts.sh b/build_tools/run_blogposts.sh new file mode 100755 index 00000000000..95e00b97b7a --- /dev/null +++ b/build_tools/run_blogposts.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# Script to run all blog post notebooks. +set -euxo pipefail + +CMD="jupyter nbconvert --to notebook --inplace --execute --ExecutePreprocessor.timeout=600" + +for notebook in examples/blog_posts/*.ipynb; do + echo "Running: $notebook" + $CMD "$notebook" +done diff --git a/docs/source/api_reference.rst b/docs/source/api_reference.rst index 657c06571db..9dc6307d578 100644 --- a/docs/source/api_reference.rst +++ b/docs/source/api_reference.rst @@ -24,6 +24,7 @@ For a scientific manual, see the :ref:`user_guide`. api_reference/dists_kernels api_reference/param_est api_reference/performance_metrics + api_reference/split api_reference/alignment api_reference/annotation api_reference/datasets diff --git a/docs/source/api_reference/alignment.rst b/docs/source/api_reference/alignment.rst index 5306ed44cb4..eecec7e7ef3 100644 --- a/docs/source/api_reference/alignment.rst +++ b/docs/source/api_reference/alignment.rst @@ -6,6 +6,12 @@ Time series alignment The :mod:`sktime.alignment` module contains time series aligners, such as dynamic time warping aligners. +All time series aligners in ``sktime`` can be listed using the +``sktime.registry.all_estimators`` utility, +using ``estimator_types="aligner"``, optionally filtered by tags. +Valid tags can be listed using ``sktime.registry.all_tags``. + + Naive aligners -------------- diff --git a/docs/source/api_reference/classification.rst b/docs/source/api_reference/classification.rst index 1994630b232..ebb3d53b257 100644 --- a/docs/source/api_reference/classification.rst +++ b/docs/source/api_reference/classification.rst @@ -21,6 +21,18 @@ Composition ClassifierPipeline ColumnEnsembleClassifier SklearnClassifierPipeline + MultiplexClassifier + +Model selection and tuning +-------------------------- + +.. currentmodule:: sktime.classification.model_selection + +.. autosummary:: + :toctree: auto_generated/ + :template: class.rst + + TSCGridSearchCV Ensembles --------- @@ -45,12 +57,14 @@ Deep learning :template: class.rst CNNClassifier + CNTCClassifier FCNClassifier LSTMFCNClassifier InceptionTimeClassifier MACNNClassifier MLPClassifier MCDCNNClassifier + ResNetClassifier SimpleRNNClassifier TapNetClassifier @@ -180,8 +194,15 @@ Shapelet-based MrSEQL MrSQM -sklearn -------- + +sklearn classifiers +------------------- + +This section contains classifiers which are not time series classifiers but +simple tabular classifiers in ``sklearn`` compatible API. + +They are used internally in time series classifiers, but can also be used +directly in a tabular setting. .. currentmodule:: sktime.classification.sklearn diff --git a/docs/source/api_reference/forecasting.rst b/docs/source/api_reference/forecasting.rst index c73f70d3761..4abc257491d 100644 --- a/docs/source/api_reference/forecasting.rst +++ b/docs/source/api_reference/forecasting.rst @@ -51,6 +51,8 @@ Pipelines can also be constructed using ``*``, ``+``, and ``|`` dunders. Permute HierarchyEnsembleForecaster FhPlexForecaster + IgnoreX + FallbackForecaster Reduction --------- @@ -72,6 +74,7 @@ Use ``make_reduction`` for easy specification. DirectTabularRegressionForecaster DirectTimeSeriesRegressionForecaster + DirectReductionForecaster MultioutputTabularRegressionForecaster MultioutputTimeSeriesRegressionForecaster RecursiveTabularRegressionForecaster @@ -150,6 +153,7 @@ Trend forecasters PolynomialTrendForecaster STLForecaster CurveFitForecaster + ProphetPiecewiseLinearTrendForecaster .. currentmodule:: sktime.forecasting.statsforecast @@ -228,6 +232,7 @@ All "ARIMA" and "Auto-ARIMA" models below include SARIMAX capability. :template: class.rst ARIMA + StatsModelsARIMA .. currentmodule:: sktime.forecasting.sarimax @@ -256,6 +261,8 @@ All "ARIMA" and "Auto-ARIMA" models below include SARIMAX capability. Auto-ARIMA models ~~~~~~~~~~~~~~~~~ +.. currentmodule:: sktime.forecasting.arima + .. autosummary:: :toctree: auto_generated/ :template: class.rst @@ -287,6 +294,14 @@ ARCH models Structural time series models ----------------------------- +.. currentmodule:: sktime.forecasting.ardl + +.. autosummary:: + :toctree: auto_generated/ + :template: class.rst + + ARDL + .. currentmodule:: sktime.forecasting.bats .. autosummary:: @@ -303,6 +318,14 @@ Structural time series models TBATS +.. currentmodule:: sktime.forecasting.statsforecast + +.. autosummary:: + :toctree: auto_generated/ + :template: class.rst + + StatsForecastAutoTBATS + .. currentmodule:: sktime.forecasting.fbprophet .. autosummary:: @@ -327,6 +350,20 @@ Structural time series models DynamicFactor +Transformer (deep learning) based forecasters +--------------------------------------------- + +.. currentmodule:: sktime.forecasting.ltsf + +.. autosummary:: + :toctree: auto_generated/ + :template: class.rst + + LTSFLinearForecaster + LTSFDLinearForecaster + LTSFNLinearForecaster + + Intermittent time series forecasters ------------------------------------ @@ -422,25 +459,8 @@ Model Evaluation (Backtesting) evaluate -Time series splitters ---------------------- - -Time series splitters can be used in both evaluation and tuning. - -.. currentmodule:: sktime.forecasting.model_selection - -.. autosummary:: - :toctree: auto_generated/ - :template: class.rst - - CutoffSplitter - SingleWindowSplitter - SlidingWindowSplitter - ExpandingWindowSplitter - ExpandingGreedySplitter - -.. autosummary:: - :toctree: auto_generated/ - :template: function.rst +Time index splitters +-------------------- - temporal_train_test_split +Evaluation and tuning can be customized using time index based splitters, +for a list of these consult the :ref:`splitter API <split_ref>` diff --git a/docs/source/api_reference/param_est.rst b/docs/source/api_reference/param_est.rst index 4352b6d32ae..9bb1a2cdd07 100644 --- a/docs/source/api_reference/param_est.rst +++ b/docs/source/api_reference/param_est.rst @@ -14,10 +14,6 @@ All parameter estimators in ``sktime`` can be listed using the using ``estimator_types="param_est"``, optionally filtered by tags. Valid tags can be listed using ``sktime.registry.all_tags``. -.. automodule:: sktime.param_est - :no-members: - :no-inherited-members: - Parameter estimators -------------------- @@ -32,6 +28,12 @@ Composition ParamFitterPipeline +.. autosummary:: + :toctree: auto_generated/ + :template: class.rst + + FunctionParamFitter + .. currentmodule:: sktime.param_est.plugin .. autosummary:: @@ -75,3 +77,9 @@ Stationarity estimators StationarityADF StationarityKPSS + StationarityADFArch + StationarityDFGLS + StationarityPhillipsPerron + StationarityKPSSArch + StationarityZivotAndrews + StationarityVarianceRatio diff --git a/docs/source/api_reference/split.rst b/docs/source/api_reference/split.rst new file mode 100644 index 00000000000..7786983b334 --- /dev/null +++ b/docs/source/api_reference/split.rst @@ -0,0 +1,74 @@ + +.. _split_ref: + +Splitters +========= + +The :mod:`sktime.split` module contains algorithms for splitting and resampling data. + +All splitters in ``sktime`` can be listed using the ``sktime.registry.all_estimators`` utility, +using ``estimator_types="splitter"``, optionally filtered by tags. +Valid tags can be listed using ``sktime.registry.all_tags``. + + +Splitting utilities +------------------- + +``temporal_train_test_split`` is a quick utility function for +splitting a single time series into training and test fold. + +Forecasting users interested in performance evaluation are advised +to use full backtesting instead of a single split, e.g., via ``evaluate``, +see :ref:`forecasting API reference <forecasting_ref>`. + +.. currentmodule:: sktime.split + +.. autosummary:: + :toctree: auto_generated/ + :template: function.rst + + temporal_train_test_split + + +Time index splitters +-------------------- + +Time index splitters split one or multiple time series by temporal order. +They are typically used in both evaluation and tuning of forecasters. + +.. currentmodule:: sktime.split + +.. autosummary:: + :toctree: auto_generated/ + :template: class.rst + + CutoffSplitter + SingleWindowSplitter + SlidingWindowSplitter + ExpandingWindowSplitter + ExpandingGreedySplitter + TemporalTrainTestSplitter + + +Time index splitter composition +------------------------------- + +The following splitters are compositions that can be used to create +more complex time index based splitting strategies. + +.. currentmodule:: sktime.split.compose + +.. autosummary:: + :toctree: auto_generated/ + :template: class.rst + + Repeat + +.. currentmodule:: sktime.split + +.. autosummary:: + :toctree: auto_generated/ + :template: class.rst + + SameLocSplitter + TestPlusTrainSplitter diff --git a/docs/source/api_reference/transformations.rst b/docs/source/api_reference/transformations.rst index df9413e1051..0481a8739c1 100644 --- a/docs/source/api_reference/transformations.rst +++ b/docs/source/api_reference/transformations.rst @@ -7,7 +7,7 @@ The :mod:`sktime.transformations` module contains classes for data transformations. All (simple) transformers in ``sktime`` can be listed using the ``sktime.registry.all_estimators`` utility, -using ``estimator_types="regressor"``, optionally filtered by tags. +using ``estimator_types="transformer"``, optionally filtered by tags. Valid tags can be listed using ``sktime.registry.all_tags``. For pairwise transformers (time series distances, kernels), instead see :ref:`_transformations_pairwise_ref`. @@ -188,9 +188,7 @@ Dictionary-based features :toctree: auto_generated/ :template: class.rst - PAA SFA - SAX Moment-based features ~~~~~~~~~~~~~~~~~~~~~ @@ -242,6 +240,7 @@ Lagging :template: class.rst Lag + ReducerTransform Element-wise transforms ~~~~~~~~~~~~~~~~~~~~~~~ @@ -410,8 +409,8 @@ Differencing, slope, kinematics KinematicFeatures -Binning and segmentation -~~~~~~~~~~~~~~~~~~~~~~~~ +Binning, sampling and segmentation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. currentmodule:: sktime.transformations.series.binning @@ -438,6 +437,39 @@ Binning and segmentation IntervalSegmenter RandomIntervalSegmenter +.. currentmodule:: sktime.transformations.series.dilation_mapping + +.. autosummary:: + :toctree: auto_generated/ + :template: class.rst + + DilationMappingTransformer + +.. currentmodule:: sktime.transformations.series.paa + +.. autosummary:: + :toctree: auto_generated/ + :template: class.rst + + PAA2 + +.. currentmodule:: sktime.transformations.series.sax + +.. autosummary:: + :toctree: auto_generated/ + :template: class.rst + + SAX2 + +.. currentmodule:: sktime.transformations.panel.dictionary_based + +.. autosummary:: + :toctree: auto_generated/ + :template: class.rst + + PAA + SAX + Missing value treatment ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -447,9 +479,16 @@ Missing value treatment :toctree: auto_generated/ :template: class.rst - DropNA Imputer +.. currentmodule:: sktime.transformations.series.dropna + +.. autosummary:: + :toctree: auto_generated/ + :template: class.rst + + DropNA + Seasonality and Date-Time Features ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -657,6 +696,19 @@ Bootstrap transformations SplitterBootstrapTransformer STLBootstrapTransformer +Panel-to-Series transformers +---------------------------- + +These transformers create a single series from a panel. + +.. currentmodule:: sktime.transformations.merger + +.. autosummary:: + :toctree: auto_generated/ + :template: class.rst + + Merger + Outlier detection, changepoint detection ---------------------------------------- diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 268a3bbb6c2..04e219f8643 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -3,7 +3,12 @@ Changelog ========= -All notable changes to this project will be documented in this file. We keep track of changes in this file since v0.4.0. The format is based on `Keep a Changelog <https://keepachangelog.com/en/1.0.0/>`_ and we adhere to `Semantic Versioning <https://semver.org/spec/v2.0.0.html>`_. The source code for all `releases <https://github.com/sktime/sktime/releases>`_ is available on GitHub. +All notable changes to this project will be documented in this file. +We keep track of changes in this file since v0.4.0. +The format is based on `Keep a Changelog <https://keepachangelog.com/en/1.0.0/>`_ and +we adhere to `Semantic Versioning <https://semver.org/spec/v2.0.0.html>`_. +The source code for all `releases <https://github.com/sktime/sktime/releases>`_ is +available on GitHub. .. note:: @@ -14,6 +19,936 @@ For upcoming changes and next releases, see our `milestones <https://github.com/ For our long-term plan, see our :ref:`roadmap`. +Version 0.26.0 - 2023-01-27 +--------------------------- + +Maintenance release: + +* support for ``scikit-learn 1.4.X`` +* scheduled deprecations +* minor bugfix + +For last non-maintenance content updates, see 0.25.1. + +Dependency changes +~~~~~~~~~~~~~~~~~~ + +* ``scikit-learn`` bounds have been updated to ``>=0.24.0,<1.5.0``. + +Deprecations and removals +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Benchmarking, Metrics, Splitters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* in forecasting ``evaluate``, ``kwargs`` have been removed. + Users should pass backend parameters via the ``backend_params`` + parameter instead. + +Data types, checks, conversions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* in ``check_is_mtype``, the default of ``msg_return_dict`` has now changed to ``"dict"`` + +Forecasting tuners +^^^^^^^^^^^^^^^^^^ + +* in forecasting tuners ``ForecastingGridSearchCV``, ``ForecastingRandomizedSearchCV``, + ``ForecastingSkoptSearchCV``, use of ``joblib`` backend specific parameters ``n_jobs``, + ``pre_dispatch`` has been deprecated, and will be removed in ``sktime`` 0.27.0. + Users should pass backend parameters via the ``backend_params`` parameter instead. + +Time series classification +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* In ``SimpleRNNClassifier``, the ``num_epochs`` parameter has been + renamed to ``n_epochs``. The original parameter of name ``num_epochs`` has now + been removed. + +Time series regression +^^^^^^^^^^^^^^^^^^^^^^ + +* In ``SimpleRNNRegressor``, the ``num_epochs`` parameter has been + renamed to ``n_epochs``. The original parameter of name ``num_epochs`` has now + been removed. + +Contents +~~~~~~~~ + +* [MNT] 0.26.0 deprecations and change actions (:pr:`5817`) :user:`fkiraly` +* [MNT] [Dependabot](deps-dev): Update ``scikit-learn`` requirement from + ``<1.4.0,>=0.24`` to ``>=0.24,<1.5.0`` (:pr:`5776`) :user:`dependabot[bot]` +* [MNT] [Dependabot](deps): Bump styfle/cancel-workflow-action from ``0.12.0`` + to ``0.12.1`` (:pr:`5839`) :user:`dependabot[bot]` +* [MNT] [Dependabot](deps): Bump dorny/paths-filter + from ``2`` to ``3`` (:pr:`5838`) :user:`dependabot[bot]` +* [BUG] fix tag handling in ``IgnoreX`` (:pr:`5843`) :user:`tpvasconcelos`, :user:`fkiraly` + + +Version 0.25.1 - 2023-01-24 +--------------------------- + +Highlights +~~~~~~~~~~ + +* in ``make_reduction``, direct reduction forecaster now supports probabilistic tabular regressors from ``skpro`` (:pr:`5536`) :user:`fkiraly` +* new, efficient, parallelizable PAA and SAX transformer implementations, available as ``PAA2``, ``SAX2`` (:pr:`5742`) :user:`steenrotsman` +* ``FallbackForecaster``, fallback chain of multiple forecaster for exception handling (:pr:`5779`) :user:`ninedigits` +* time series classification: ``sktime`` native grid search, multiplexer for autoML (:pr:`4596`, :pr:`5678`) :user:`achieveordie`, :user:`fkiraly` +* ``IgnoreX`` - forecasting compositor to ignore exogenous data, for use in tuning (:pr:`5769`) :user:`hliebert`, :user:`fkiraly` +* classifier migrated from ``sktime-dl``: CNTC classifier (:pr:`3978`) :user:`aurumnpegasus` +* authors and maintainers of algorithms are now tracked via tags ``"authors"`` and ``"maintainers"``, see below + +Dependency changes +~~~~~~~~~~~~~~~~~~ + +* ``arch`` (forecasting and parameter estimation soft dependency) bounds have been updated to ``>=5.6,<6.4.0`` (:pr:`5771`) :user:`dependabot[bot]` +* ``mne`` (transformations soft dependency) bounds have been updated to ``>=1.5,<1.7`` (:pr:`5585`) :user:`dependabot[bot]` +* ``dask`` (data container and parallelization back-end) bounds have been updated to ``<2024.1.1`` (:pr:`5748`) :user:`dependabot[bot]` + +Core interface changes +~~~~~~~~~~~~~~~~~~~~~~ + +BaseObject and base framework +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* estimators and objects now record author and maintainer information in the new + tags ``"authors"`` and ``"maintainers"``. This is required only for estimators + in ``sktime`` proper and compatible third party packages. It is also used to generate + mini-package headers used in lookup functionality of the ``sktime`` webpage. +* author and maintainer information in the ``sktime`` package is no longer recorded in + ``CODEOWNERS``, but in the new tags ``"authors"`` and ``"maintainers"``. + Authors and maintainer do not need to action this change, as it has been carried out + by the ``sktime`` maintainers. However, authors and maintainers are encouraged to + check the information in the tags, and to flag any accidental omissions or errors. + +Benchmarking, Metrics, Splitters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* forecasting point prediction metrics now also support parallelization via + ``set_config``, for broadcasting on hierarchical or multivariate data + +Forecasting +^^^^^^^^^^^ + +* forecasters can now be prevented from storing a reference to all seen data + as ``self._y`` and ``self._X`` by setting the config ``"remember_data"`` to + ``False`` via ``set_config``. This is useful for serialization of forecasters. + Currently, the setting is only supported for a combination of data and forecasters + where instance or variable broadcasting is not triggered, + but the feature will be extended to all situations in the future. + +Parameter estimation and hypothesis testing +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Parameter plugin or estimation based parameter tuning estimators can now be quickly constructed + with the ``*`` dunder, which will construct a ``PluginParamsForecaster`` or ``PluginParamsTransformer`` + with all fitted paramters (``get_fitted_params``) of the left element plugged in into the right element + (``set_params``), where parameter names match. + For instance, ``SeasonalityACF() * Deseasonalizer()`` will construct + a ``Deseasonalizer`` whose ``sp`` (seasonality period) parameter is tuned + by ``SeasonalityACF``, estimating ``sp`` via the ACF significance criterion on the series. +* The ``*`` dunder binds to the left, for instance + ``Differencer() * SeasonalityACF() * Deseasonalizer()`` will construct + a ``Deseasonalizer`` whose ``sp`` (seasonality period) parameter is tuned + by ``SeasonalityACF``, estimating ``sp`` via the ACF significance criterion + on first differenced data (for stationarity). + Here first differencing is not applied to the ``Deseasonalizer``, + but only to the input of ``SeasonalityACF``, as the first ``*`` constructs + a parameter estimator, and the second ``*`` plugs in the parameter estimator into + the ``Deseasonalizer``. + +Transformations +^^^^^^^^^^^^^^^ + +* transformations, i.e., ``BaseTransformer`` descendant instances, + can now also return ``None`` in ``_transform``, this is interpreted as empty data. + +Deprecations and removals +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Transformations +^^^^^^^^^^^^^^^ + +* ``panel.dictionary_based.PAA`` will be renamed to ``PAAlegacy`` in ``sktime`` 0.27.0, + while ``sktime.transformations.series.PAA2`` will be renamed to ``PAA``. + ``PAA2`` will become the primary PAA implementation in ``sktime``, + while the current ``PAA`` will continue to be available as ``PAAlegacy``. + Both estimators are also available under their future name at their + current location, and will be available under their deprecated name + until 0.28.0. + To prepare for the name change, do one of the following: + 1. replace use of ``PAA`` from ``sktime.transformations.panel.dictionary_based`` + by use of ``PAA2`` from ``sktime.transformations.series.paa``, switching + parameter names appropriately, or + 2. replace use of ``PAA`` from ``sktime.transformations.panel.dictionary_based`` + by use of ``PAAlegacy`` from ``sktime.transformations.panel.dictionary_based``, + without change of parameter values. +* ``panel.dictionary_based.SAX`` will be renamed to ``SAXlegacy`` in ``sktime`` 0.27.0, + while ``sktime.transformations.series.SAX2`` will be renamed to ``SAX``. + ``SAX2`` will become the primary SAX implementation in ``sktime``, + while the current ``SAX`` will continue to be available as ``SAXlegacy``. + Both estimators are also available under their future name at their + current location, and will be available under their deprecated name + until 0.28.0. + To prepare for the name change, do one of the following: + 1. replace use of ``SAX`` from ``sktime.transformations.panel.dictionary_based`` + by use of ``SAX2`` from ``sktime.transformations.series.paa``, switching + parameter names appropriately, or + 2. replace use of ``SAX`` from ``sktime.transformations.panel.dictionary_based`` + by use of ``SAXlegacy`` from ``sktime.transformations.panel.dictionary_based``, + without change of parameter values. + +Enhancements +~~~~~~~~~~~~ + +BaseObject and base framework +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [ENH] update ``deep_equals`` to accommodate plugins, e.g., for ``polars`` (:pr:`5504`) :user:`fkiraly` +* [ENH] Replace ``isinstance`` by ``object_type`` tag based checks (:pr:`5657`) :user:`benheid` +* [ENH] author and maintainer tags (:pr:`5754`) :user:`fkiraly` +* [ENH] enable ``all_tags`` to retrieve estimator and object tags (:pr:`5798`) :user:`fkiraly` +* [ENH] remove maintainer information from ``CODEOWNERS`` in favour of estimator tags (:pr:`5808`) :user:`fkiraly` +* [ENH] author and maintainer tags for alignment and distances modules (:pr:`5801`) :user:`fkiraly` +* [ENH] author and maintainer tags for forecasting module (:pr:`5802`) :user:`fkiraly` +* [ENH] author and maintainer tags for distributions and parameter fitting module (:pr:`5803`) :user:`fkiraly` +* [ENH] author and maintainer tags for classification, clustering and regression modules (:pr:`5807`) :user:`fkiraly` +* [ENH] author and maintainer tags for transformer module (:pr:`5800`) :user:`fkiraly` + +Benchmarking, Metrics, Splitters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [ENH] Repeat splitter composition (:pr:`5737`) :user:`fkiraly` +* [ENH] parallelization support and config for forecasting performance metrics (:pr:`5813`) :user:`fkiraly` + +Data types, checks, conversions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [ENH] in ``VectorizedDF``, partially decouple internal data store from methods (:pr:`5681`) :user:`fkiraly` + +Forecasting +^^^^^^^^^^^ + +* [ENH] ``Imputer``: conditional parameter handling logic (:pr:`3916`) :user:`aiwalter`, :user:`fkiraly`` +* [ENH] support for probabilistic regressors (``skpro``) in ``make_reduction``, direct reduction (:pr:`5536`) :user:`fkiraly` +* [ENH] private utility for ``BaseForecaster`` get columns, for all ``predict``-like functions (:pr:`5590`) :user:`fkiraly` +* [ENH] adding second test parameters for ``TBATS`` (:pr:`5689`) :user:`NguyenChienFelix33` +* [ENH] config to turn off data memory in forecasters (:pr:`5676`) :user:`fkiraly`, :user:`corradomio` +* [ENH] Simplify conditional statements in direct reducer (:pr:`5725`) :user:`fkiraly` +* [ENH] forecasting compositor to ignore exogenous data (:pr:`5769`) :user:`hliebert`, :user:`fkiraly` +* [ENH] add ``disp`` parameter to ``SARIMAX`` to control output verbosity (:pr:`5770`) :user:`tvdboom` +* [ENH] expose parameters supported by ``fit`` method of ``SARIMAX`` in ``statsmodels`` (:pr:`5787`) :user:`yarnabrina` +* [ENH] ``FallbackForecaster``, fallback upon fail with multiple forecaster chain (:pr:`5779`) :user:`ninedigits` + +Parameter estimation and hypothesis testing +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [ENH] Simplify ``BaseEstimator._get_fitted_params()`` and ``BaseParamFitter`` inheritance of that method (:pr:`5633`) :user:`tpvasconcelos` +* [ENH] parameter plugin for estimator into transformers, right concat dunder (:pr:`5764`) :user:`fkiraly` + +Probability distributions and simulators +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [ENH] bring distributions module on par with ``skpro`` distributions (:pr:`5708`) :user:`fkiraly`, :user:`alex-jg3` + +Time series classification +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [ENH] migrating CNTC network and classifier for classification from ``sktime-dl`` (:pr:`3978`) :user:`aurumnpegasus`, :user:`fkiraly` +* [ENH] grid search for time series classification (:pr:`4596`) :user:`achieveordie`, :user:`fkiraly` +* [ENH] reduce private coupling of ``IndividualBOSS`` classifier and ``BaseClassifier`` (:pr:`5654`) :user:`fkiraly` +* [ENH] multiplexer classifier (:pr:`5678`) :user:`fkiraly` +* [ENH] refactor structure of time series forest classifier related files (:pr:`5751`) :user:`fkiraly` + +Transformations +^^^^^^^^^^^^^^^ + +* [ENH] better explanation about fit/transform instance linking in instance-wise transformers in error messages, and pointer to common solution (:pr:`5652`) :user:`fkiraly` +* [ENH] New ``PAA`` and ``SAX`` transformer implementations (:pr:`5742`) :user:`steenrotsman` +* [ENH] feature upgrade for ``SplitterSummarizer`` - granular control of inner ``fit``/``transform`` input (:pr:`5750`) :user:`fkiraly` +* [ENH] allow ``BaseTransformer._transform`` to return ``None`` (:pr:`5772`) :user:`fkiraly`, :user:`hliebert` + +Test framework +^^^^^^^^^^^^^^ + +* [ENH] refactor tests with parallelization backend fixtures to programmatic backend fixture lookup (:pr:`5714`) :user:`fkiraly` +* [ENH] further refactor parallelization backend test fixtures to use central location (:pr:`5734`) :user:`fkiraly` + + +Fixes +~~~~~ + +BaseObject and base framework +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [BUG] fix scitype inference utility for all cases (:pr:`5672`) :user:`fkiraly` +* [BUG] fixes for minor typos in error message related to custom ``joblib`` backend selection (:pr:`5724`) :user:`fkiraly` +* [BUG] handles ``AttributeError`` in ``show_versions`` when dependency lacks ``__version__`` (:pr:`5793`) :user:`yarnabrina` +* [BUG] fix type error in parallelization backend test fixture refactor (:pr:`5760`) :user:`fkiraly` + +Benchmarking, Metrics, Splitters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [BUG] Fix dynamic ``make_forecasting_scorer`` for newer ``sklearn`` metrics (:pr:`5717`) :user:`fkiraly` +* [BUG] fix ``test_evaluate_error_score`` to skip test of expected warning raised if the ``joblib`` backend is ``"loky"`` or ``"multiprocessing"`` (:pr:`5780`) :user:`fkiraly` + +Data loaders +^^^^^^^^^^^^ + +* [BUG] fix ``extract_path`` arg in ``sktime.datasets.load_UCR_UEA_dataset`` (:pr:`5744`) :user:`steenrotsman` + +Data types, checks, conversions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [BUG] fix ``deep_equals`` for ``np.array`` with ``dtype="object"`` (:pr:`5697`) :user:`fkiraly` + +Forecasting +^^^^^^^^^^^ + +* [BUG] fix ``ForecastingHorizon.get_expected_pred_idx`` ``sort_time`` (:pr:`5726`) :user:`fkiraly` +* [BUG] in ``BaggingForecaster``, fix ``random_state`` handling (:pr:`5730`) :user:`fkiraly` + +Pipelines +^^^^^^^^^ + +* [BUG] Enable ``pipeline.fit`` without X (:pr:`5656`) :user:`benheid` + +Time series classification +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [BUG] fix ``predict`` output conversion failure in ``BaseClassifier``, ``BaseRegressor``, if ``y_inner_mtype`` tag is a list (:pr:`5680`) :user:`fkiraly` +* [BUG] fix ``test_multioutput`` for genuinely multioutput classifiers (:pr:`5700`) :user:`fkiraly` + +Time series regression +^^^^^^^^^^^^^^^^^^^^^^ + +* [BUG] fix ``predict`` output conversion failure in ``BaseClassifier``, ``BaseRegressor``, if ``y_inner_mtype`` tag is a list (:pr:`5680`) :user:`fkiraly` + +Transformations +^^^^^^^^^^^^^^^ + +* [BUG] skip sporadic test errors in ``ExponentialSmoothing`` (:pr:`5516`) :user:`achieveordie` +* [BUG] fix sporadic permutation of internal feature columns in ``TSFreshClassifier.predict`` (:pr:`5673`) :user:`fkiraly` +* [BUG] fix backend strings in transformer ``test_base`` (:pr:`5695`) :user:`fkiraly` +* [BUG] Ensure ``MultiRocketMultivariate`` uses ``random_state`` (:pr:`5710`) :user:`chrico-bu-uab` + +Test framework +^^^^^^^^^^^^^^ + +* [BUG] Fixing dockerized tests (:pr:`5426`) :user:`kurayami07734` + + +Maintenance +~~~~~~~~~~~ + +* [MNT] [Dependabot](deps-dev): Update sphinx-issues requirement from ``<4.0.0`` to ``<5.0.0`` (:pr:`5792`) :user:`dependabot[bot]` +* [MNT] [Dependabot](deps): Bump tj-actions/changed-files from 41 to 42 (:pr:`5777`) :user:`dependabot[bot]` +* [MNT] [Dependabot](deps-dev): Update arch requirement from ``<6.3.0,>=5.6`` to ``>=5.6,<6.4.0`` (:pr:`5771`) :user:`dependabot[bot]` +* [MNT] [Dependabot](deps-dev): Update mne requirement from ``<1.6,>=1.5`` to ``>=1.5,<1.7`` (:pr:`5585`) :user:`dependabot[bot]` +* [MNT] [Dependabot](deps-dev): Update dask requirement from ``<2023.12.2`` to ``<2024.1.1`` (:pr:`5748`) :user:`dependabot[bot]` +* [MNT] improvements to modular CI framework - clearer naming, ``pyproject`` handling (:pr:`5713`) :user:`fkiraly` +* [MNT] temporary deactivation of new CI (:pr:`5795`) :user:`fkiraly` +* [MNT] fix faulty deprecation logic for ``n_jobs``, ``pre_dispatch`` in forecasting tuners, bump deprecation to 0.27.0 (:pr:`5784`) :user:`fkiraly` +* [MNT] update python version in binder dockerfile to 3.11 (:pr:`5762`) :user:`fkiraly` +* [MNT] address various deprecations from ``pandas`` (:pr:`5733`) :user:`fkiraly`, :user:`yarnabrina` +* [MNT] ``scikit-learn 1.4.0`` compatibility patches (:pr:`5782`, :pr:`5811`) :user:`fkiraly` +* [MNT] Code quality updates (:pr:`5786`) :user:`yarnabrina` +* [MNT] change cycle for making ``SAX2`` and ``PAA2`` primary implementation renamed to ``SAX``, ``PAA`` (:pr:`5799`) :user:`fkiraly` +* [MNT] remove maintainer information from ``CODEOWNERS`` in favour of estimator tags (:pr:`5808`) :user:`fkiraly` +* [MNT] addressing more ``pandas`` deprecations (:pr:`5816`) :user:`fkiraly` +* [MNT] address ``pd.DataFrame.groupby(axis=1)`` deprecation in ``EnsembleForecaster`` (:pr:`5707`) :user:`ninedigits` +* [MNT] add missing ``__author__`` field for ``MultiRocket`` and ``MultiRocketMultivariate`` (:pr:`5698`) :user:`fkiraly` +* [MNT] addressing ``DataFrame.groupby(axis=1)`` deprecation in metric classes (:pr:`5709`) :user:`fkiraly` +* [MNT] added upper bound ``pycatch22<0.4.5`` in ``transformations`` dependency set to avoid installation error on windows (:pr:`5670`) :user:`yarnabrina` +* [MNT] refactoring new CI to fix some bugs and other minor enhancements (:pr:`5638`) :user:`yarnabrina` +* [MNT] Update ``tslearn`` dependency version in pyproject.toml (:pr:`5686`) :user:`DManowitz` +* [MNT] fix several spelling mistakes (:pr:`5639`) :user:`yarnabrina` + +Documentation +~~~~~~~~~~~~~ + +* [DOC] comment in ``CONTRIBUTORS.md`` that source file is ``all-contributorsrc`` (:pr:`5687`) :user:`fkiraly` +* [DOC] improved docstring for ``TrendForecaster`` and ``PolynomialTrendForecaster`` (:pr:`5747`) :user:`fkiraly` +* [DOC] updated algorithm inclusion guide (:pr:`5753`) :user:`fkiraly` +* [DOC] improved docstring for ``TimeSeriesForestClassifier`` (:pr:`5741`) :user:`fkiraly` +* [DOC] fix ``scitype`` string of transformers in API ref (:pr:`5759`) :user:`fkiraly` +* [DOC] improved formatting of tag section in extension templates (:pr:`5812`) :user:`fkiraly` +* [DOC] ``Imputer``: docstring clarity improvement, conditional parameter handling logic (:pr:`3916`) :user:`aiwalter`, :user:`fkiraly`` +* [DOC] extension template for time series splitters (:pr:`5769`) :user:`fkiraly` +* [DOC] update soft dependency handling guide for tests with tag based dependency checking (:pr:`5756`) :user:`fkiraly` +* [DOC] fix all import failures in API docs and related missing exports (:pr:`5752`) :user:`fkiraly` +* [DOC] improve clarity in describing ``strategy="refit"`` in forecasting tuners' docstrings (:pr:`5711`) :user:`fkiraly` +* [DOC] correct type statement in forecasting tuner regarding ``forecaster`` (:pr:`5699`) :user:`fkiraly` +* [DOC] various minor API reference improvements (:pr:`5721`) :user:`fkiraly` +* [DOC] add ``ReducerTransform`` and ``DirectReductionForecaster`` to API reference (:pr:`5690`) :user:`fkiraly` +* [DOC] remove outdated ``sktime-dl`` reference in ``README.md`` (:pr:`5685`) :user:`fkiraly` + +Contributors +~~~~~~~~~~~~ + +:user:`achieveordie`, +:user:`aiwalter`, +:user:`alex-jg3`, +:user:`aurumnpegasus`, +:user:`benheid`, +:user:`chrico-bu-uab`, +:user:`corradomio`, +:user:`DManowitz`, +:user:`fkiraly`, +:user:`hliebert`, +:user:`NguyenChienFelix33`, +:user:`ninedigits`, +:user:`kurayami07734`, +:user:`steenrotsman`, +:user:`tpvasconcelos`, +:user:`tvdboom`, +:user:`yarnabrina` + + +Version 0.25.0 - 2023-12-26 +--------------------------- + +Release with base class updates and scheduled deprecations: + +* framework support for multioutput classifiers, regressors + (:pr:`5408`, :pr:`5651`, :pr:`5662`) :user:`Vasudeva-bit`, :user:`fkiraly` +* framework support for panel-to-series transformers (:pr:`5351`) :user:`benHeid` +* scheduled deprecations + +For last larger feature update, see 0.24.2. + +Core interface changes +~~~~~~~~~~~~~~~~~~~~~~ + +Time series classification and regression +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* the base class framework now supports multioutput classifiers or regressors. + All classifiers and regressors are now able to make multioutput predictions, + including all third party classifiers and regressors. + A multioutput ``y`` can now be passed, in the form of a 2D ``np.ndarray`` or + ``pd.DataFrame``, with one column per output. + The ``predict`` method will then return a predicted output of the same type. + To retain downwards compatibility, ``predict`` will always return a 1D ``np.ndarray`` + for univariate outputs, this is currently not subject to deprecation. + +* Genuinely multioutput classifiers and regressors are labelled with the new + tag ``capability:multioutput`` being ``True``. + All other classifiers and regressors broadcast by column of ``y``, + and a parallelization backend can be selected via ``set_config``, + by setting the ``backend:parallel`` and ``backend:parallel:params`` configuration + flags, see the ``set_config`` docstring for details. + Broadcasting extends automatically to all existing third party classifiers + and regressors via base class inheritance once ``sktime`` is updated, + the estimator classes themselves do not need to be updated. + +* classifiers and regressors now have a tag ``y_inner_mtype``, this allows extenders + to specify an internal ``mtype``, of ``Table`` scitype. + The mtype specified i the tag is the guaranteed + mtype of ``y`` seen in the private ``_fit`` method. + The default is the same as previously + implicit, the ``numpy1D`` mtype. + Therefore, third party classifiers and regressors do not need to be updated, + and should be fully upwards compatible. + +Transformations +^^^^^^^^^^^^^^^ + +* the base class framework now supports transformations that aggregate ``Panel`` data + to ``Series`` data, i.e., panel-to-series transformers, e.g., averaging. + Such transformers are identified by the tags + ``scitype:transform-input`` being ``"Panel"``, + and ``scitype:transform-output`` being ``"Series"``. + An example is ``Merger``. + +Deprecations and removals +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Benchmarking, Metrics, Splitters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* time series splitters, i.e., descendants of ``BaseSplitter``, have moved from + ``sktime.forecasting.model_selection`` to ``sktime.split``. + They are no longer available in the old location + ``sktime.forecasting.model_selection``, since 0.25.0. + Forecasting tuners are still present in ``sktime.forecasting.model_selection``, + and their locationn is not subject to deprecation. + +* in forecasting ``evaluate``, the order of columns in the return data frame + has changed. Users should consult the docstring of ``evaluate`` for details. + +* in forecasting ``evaluate``, the ``compute`` argument was removed, + after deprecation in 0.24.0. + Its purpose was to distinguish lazy or eager evaluation in + the ``dask`` parallelization backend. + To switch between lazy and eager evaluation, users should instead + select ``dask`` or ``dask_lazy`` via the ``backend`` parameter. + +* in forecasting ``evaluate``, ``kwargs`` are deprecated, removal has been + moved to 0.26.0. Users should pass backend parameters via the ``backend_params`` + parameter instead. + + +Contents +~~~~~~~~ + +* [ENH] Multioutput capability for all time series classifiers and regressors, broadcasting and tag (:pr:`5408`) :user:`Vasudeva-bit` +* [ENH] Support for panel-to-series transformers, merger transformation (:pr:`5351`) :user:`benHeid` +* [ENH] allow object ``dtype``-s in ``pandas`` based ``Table`` mtype-s (:pr:`5651`) :user:`fkiraly` +* [ENH] intermediate base class for panel tasks - classification, regression (:pr:`5662`) :user:`fkiraly` +* [MNT] CI element to test blogpost notebooks (:pr:`5663`) :user:`fkiraly`, :user:`yarnabrina` +* [MNT] 0.25.0 deprecations and change actions (:pr:`5613`) :user:`fkiraly` + +Contributors +~~~~~~~~~~~~ + +:user:`benHeid`, +:user:`fkiraly`, +:user:`Vasudeva-bit`, +:user:`yarnabrina` + +Version 0.24.2 - 2023-12-24 +--------------------------- + +Highlights +~~~~~~~~~~ + +* ``FunctionParamFitter`` for custom parameter switching, e.g., applying forecaster or transformer + conditional on instance properties (:pr:`5630`) :user:`tpvasconcelos` +* ``calibration_plot`` for probabilistic forecasts (:pr:`5632`) :user:`benHeid` +* ``prophet`` based piecewise linear trend forecaster (:pr:`5592`) :user:`sbuse` +* new transformer: dilation mapping (:pr:`5557`) :user:`fspinna` +* custom ``joblib`` backends are now supported in parallelization via ``set_config`` (:pr:`5537`) :user:`fkiraly` + +Dependency changes +~~~~~~~~~~~~~~~~~~ + +* ``dask`` (data container and parallelization back-end) bounds have been updated to ``<2023.12.2``. +* ``holidays`` (transformations soft dependency) bounds have been updated to ``>=0.29,<0.40``. + +Core interface changes +~~~~~~~~~~~~~~~~~~~~~~ + +Forecasting +^^^^^^^^^^^ + +* ``fit_predict`` now allows specification of ``X_pred`` argument for ``predict``. + If passed, ``X_pred`` is used as ``X`` in ``predict``, instead of ``X``. + This is useful for forecasters that expect ``X`` to be subset to the + forecasting horizon. +* custom ``joblib`` backends for hierarchical and multivariate forecast broadcasting + are now supported. To use a custom ``joblib`` backend, use ``set_config`` to + set the ``backend:parallel`` configuration flag to ``"joblib"``, + and set the ``backend`` parameter in the ``dict`` set via ``backend:parallel:params`` + to the name of the custom ``joblib`` backend. Further bakcend parameters + can be passed in the same ``dict``. See docstring of ``set_config`` for details. + +Time series classification +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* In ``SimpleRNNClassifier``, the ``num_epochs`` parameter is deprecated and has been + renamed to ``n_epochs``. ``num_epochs`` can be used until ``sktime`` 0.25.last, + but will be removed in ``sktime`` 0.26.0. A deprecation warning is raised if + ``num_epochs`` is used. + +Time series regression +^^^^^^^^^^^^^^^^^^^^^^ + +* In ``SimpleRNNRegressor``, the ``num_epochs`` parameter is deprecated and has been + renamed to ``n_epochs``. ``num_epochs`` can be used until ``sktime`` 0.25.last, + but will be removed in ``sktime`` 0.26.0. A deprecation warning is raised if + ``num_epochs`` is used. + +Transformations +^^^^^^^^^^^^^^^ + +* custom ``joblib`` backends for hierarchical and multivariate transformer broadcasting + are now supported. To use a custom ``joblib`` backend, use ``set_config`` to + set the ``backend:parallel`` configuration flag to ``"joblib"``, + and set the ``backend`` parameter in the ``dict`` set via ``backend:parallel:params`` + to the name of the custom ``joblib`` backend. Further bakcend parameters + can be passed in the same ``dict``. See docstring of ``set_config`` for details. + +Enhancements +~~~~~~~~~~~~ + +BaseObject and base framework +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [ENH] improved error messages for input checks in base classes (:pr:`5510`) :user:`fkiraly` +* [ENH] support for custom ``joblib`` backends in parallelization (:pr:`5537`) :user:`fkiraly` +* [ENH] consistent use of ``np.ndarray`` for mtype tags (:pr:`5648`) :user:`fkiraly` +* [ENH] set output format parameter in ``sktime`` internal ``check_is_mtype`` calls to silence deprecation warnings (:pr:`5563`) :user:`benHeid` + +Benchmarking, Metrics, Splitters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [ENH] cutoff and forecasting horizon ``loc`` based splitter (:pr:`5575`) :user:`fkiraly` +* [ENH] enable tag related registry tests for ``splitter`` estimator type (:pr:`5576`) :user:`fkiraly` + +Data types, checks, conversions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [ENH] ``sklearn`` facing coercion utility for ``pd.DataFrame``, to ``str`` columns (:pr:`5550`) :user:`fkiraly` +* [ENH] ``deep_equals`` - clearer return on diffs from ``dtypes`` and ``index``, relaxation of ``MultiIndex`` equality check (:pr:`5560`) :user:`fkiraly` +* [ENH] Uniformization of ``pandas`` index types in mtypes (:pr:`5561`) :user:`fkiraly` +* [ENH] ``n_features`` and ``feature_names`` metadata field for time series mtypes (:pr:`5596`) :user:`fkiraly` + +Forecasting +^^^^^^^^^^^ + +* [ENH] expected forecast prediction index utility in ``ForecastingHorizon`` (:pr:`5501`) :user:`fkiraly` +* [ENH] refactor index generation in reducers to use ``ForecastingHorizon`` method (:pr:`5539`) :user:`fkiraly` +* [ENH] fix index name check for reduction forecasters (:pr:`5543`) :user:`fkiraly` +* [ENH] forecaster ``fit_predict`` with ``X_pred`` argument for ``predict`` (:pr:`5562`) :user:`fkiraly` +* [ENH] refactor ``DirectReductionForecaster``to use ``sklearn`` input coercion utility (:pr:`5581`) :user:`fkiraly` +* [ENH] export and test ``DirectReductionForecaster`` (:pr:`5582`) :user:`fkiraly` +* [ENH] ``prophet`` based piecewise linear trend forecaster (:pr:`5592`) :user:`sbuse` +* [ENH] Add ``fit_kwargs`` to ``Prophet`` (:pr:`5597`) :user:`tpvasconcelos` +* [ENH] ``Croston`` test parameters - integer smoothing parameter (:pr:`5608`) :user:`NguyenChienFelix33` +* [ENH] ``prophet`` adapter - safer handling of ``fit_kwargs`` (:pr:`5622`) :user:`fkiraly` + +Parameter estimation and hypothesis testing +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [ENH] Add new ``FunctionParamFitter`` parameter estimator (:pr:`5630`) :user:`tpvasconcelos` + +Time series annotation +^^^^^^^^^^^^^^^^^^^^^^ +* [ENH] Change ``GGS`` to inherit from ``BaseSeriesAnnotator`` (:pr:`5315`) :user:`Alex-JG3` + +Time series classification +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [ENH] enable testing ``MrSQM`` for persistence in ``nsfa>0`` case after upstream bugfix (:pr:`5171`) :user:`fkiraly` +* [ENH] ``num_epochs`` renamed to ``n_epochs`` in ``SimpleRNNClassifier`` and ``SimpleRNNRegressor`` (:pr:`5607`) :user:`aeyazadil` + +Time series clustering +^^^^^^^^^^^^^^^^^^^^^^ + +* [ENH] enable tag related registry tests for ``clusterer`` estimator type (:pr:`5576`) :user:`fkiraly` + +Transformations +^^^^^^^^^^^^^^^ + +* [ENH] dilation mapping transformer (:pr:`5557`) :user:`fspinna` +* [ENH] second test parameter set for ``TSFreshRelevantFeatureExtractor`` (:pr:`5623`) :user:`fkiraly` + +Visualization +^^^^^^^^^^^^^ + +* [ENH] Add ``calibration_plot`` for probabilistic forecasts (:pr:`5632`) :user:`benHeid` + +Test framework +^^^^^^^^^^^^^^ + +* [ENH] reactivate and fix ``test_multiprocessing_idempotent`` (:pr:`5573`) :user:`fkiraly` +* [ENH] test class register, refactor ``check_estimator`` test gathering to central location (:pr:`5574`) :user:`fkiraly` +* [ENH] conditional testing of objects - test if covering test class has changed (:pr:`5579`) :user:`fkiraly` + + +Fixes +~~~~~ + +BaseObject and base framework +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [BUG] fix ``scitype`` ``coerce_to_list`` parameter, add test coverage (:pr:`5578`) :user:`fkiraly` + +Data types, checks, conversions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [BUG] Fix typos in mtype tags ``np.ndarray``, from erroneous ``nd.array`` (:pr:`5645`) :user:`yarnabrina` + +Forecasting +^^^^^^^^^^^ + +* [BUG] in ``ARCH``, fix ``str`` coercion of ``pd.Series`` name (:pr:`5407`) :user:`Vasudeva-bit` +* [BUG] in reduced regressor, copy or truncate ``X`` if it does not fit the forecasting horizon (:pr:`5542`) :user:`benHeid` +* [BUG] pass correct level argument from ``StatsForecastBackAdapter`` to ``statsforecast`` (:pr:`5587`) :user:`sd2k` +* [BUG] fix ``HierarchyEnsembleForecaster`` returned unexpected predictions if data had only one hierarchy level and forecasters specified by node (:pr:`5615`) :user:`VyomkeshVyas` +* [BUG] fix loss of time zone attribute in ``ForecastingHorizon.to_absolute`` (:pr:`5628`) :user:`fkiraly` +* [BUG] change index match to integer in ``_StatsModelsAdapter`` predict (:pr:`5642`) :user:`ciaran-g` + +Transformations +^^^^^^^^^^^^^^^ + +* [BUG] ``TsFreshFeatureExtractor`` - correct wrong forwarded parameter name ``profiling`` (:pr:`5600`) :user:`sssilvar` +* [BUG] Correct inference of ``TransformerPipeline`` output type tag (:pr:`5625`) :user:`fkiraly` + +Visualization +^^^^^^^^^^^^^ + +* [BUG] Fix multiple figures created by ``plot_windows`` (:pr:`5636`) :user:`benHeid` + + +Maintenance +~~~~~~~~~~~ + +* [MNT] CI Modifications (:pr:`5498`) :user:`yarnabrina` +* [MNT] rename variables in base (:pr:`5502`) :user:`yarnabrina` +* [MNT] addressing various ``pandas`` related deprecations (:pr:`5583`) :user:`fkiraly` +* [MNT] Update pre commit hooks (:pr:`5646`) :user:`yarnabrina` +* [MNT] [Dependabot](deps-dev): Update ``pytest-xdist`` requirement from ``<3.4,>=3.3`` to ``>=3.3,<3.5`` (:pr:`5551`) :user:`dependabot[bot]` +* [MNT] [Dependabot](deps-dev): Update ``dask`` requirement from ``<2023.7.1`` to ``<2023.11.1`` (:pr:`5552`) :user:`dependabot[bot]` +* [MNT] [Dependabot](deps-dev): Update ``dask`` requirement from ``<2023.11.1`` to ``<2023.12.2`` (:pr:`5629`) :user:`dependabot[bot]` +* [MNT] [Dependabot](deps-dev): Update ``holidays`` requirement from ``<0.36,>=0.29`` to ``>=0.29,<0.37`` (:pr:`5538`) :user:`dependabot[bot]` +* [MNT] [Dependabot](deps-dev): Update ``holidays`` requirement from ``<0.37,>=0.29`` to ``>=0.29,<0.38`` (:pr:`5565`) :user:`dependabot[bot]` +* [MNT] [Dependabot](deps-dev): Update ``holidays`` requirement from ``<0.38,>=0.29`` to ``>=0.29,<0.40`` (:pr:`5637`) :user:`dependabot[bot]` +* [MNT] [Dependabot](deps-dev): Update ``sphinx-gallery`` requirement from ``<0.15.0`` to ``<0.16.0`` (:pr:`5566`) :user:`dependabot[bot]` +* [MNT] [Dependabot](deps-dev): Update ``pytest-xdist`` requirement from ``<3.5,>=3.3`` to ``>=3.3,<3.6`` (:pr:`5567`) :user:`dependabot[bot]` +* [MNT] [Dependabot](deps-dev): Update ``pycatch22`` requirement from ``<0.4.4`` to ``<0.4.5`` (:pr:`5542`) :user:`dependabot[bot]` +* [MNT] [Dependabot](deps): Bump actions/download-artifact from 3 to 4 (:pr:`5627`) :user:`dependabot[bot]` +* [MNT] [Dependabot](deps): Bump actions/setup-python from 4 to 5 (:pr:`5605`) :user:`dependabot[bot]` +* [MNT] [Dependabot](deps): Bump actions/upload-artifact from 3 to 4 (:pr:`5626`) :user:`dependabot[bot]` + +Documentation +~~~~~~~~~~~~~ + +* [DOC] splitter full API reference page (:pr:`5577`) :user:`fkiraly` +* [DOC] Correct ReST syntax in "RocketClassifier" (:pr:`5564`) :user:`rahulporuri` +* [DOC] Added notebook accompanying Joanna Lenczuk's blog post for testing (:pr:`5604`) :user:`onyekaugochukwu`, :user:`joanlenczuk` +* [DOC] Remove extra parameter in docstring with incorrect definition (:pr:`5617`) :user:`wayneadams` +* [DOC] fix and complete ``YfromX`` docstring (:pr:`5593`) :user:`fkiraly` +* [DOC] fix typo in ``AA_datatypes_and_datasets.ipynb`` panel data loading example (:pr:`5594`) :user:`fkiraly` +* [DOC] forecasting ``evaluate`` utility - improved algorithm description in docstring #5603 (:pr:`5603`) :user:`adamkells` +* [DOC] add explanation about fit/transform instance linking behaviour of rocket transformers (:pr:`5621`) :user:`fkiraly` +* [DOC] Adjust ``FunctionTransformer``'s docstring (:pr:`5634`) :user:`tpvasconcelos` +* [DOC] fixed typo in ``pytest.mark.skipif`` (:pr:`5640`) :user:`yarnabrina` + +Contributors +~~~~~~~~~~~~ + +:user:`adamkells`, +:user:`aeyazadil`, +:user:`Alex-JG3`, +:user:`benHeid`, +:user:`ciaran-g`, +:user:`fkiraly`, +:user:`fspinna`, +:user:`joanlenczuk`, +:user:`NguyenChienFelix33`, +:user:`onyekaugochukwu`, +:user:`rahulporuri`, +:user:`sbuse`, +:user:`sd2k`, +:user:`sssilvar`, +:user:`tpvasconcelos`, +:user:`Vasudeva-bit`, +:user:`VyomkeshVyas`, +:user:`wayneadams`, +:user:`yarnabrina` + +Version 0.24.1 - 2023-11-05 +--------------------------- + +Highlights +~~~~~~~~~~ + +* ``torch`` adapter, LTSF forecasters - linear, D-linear, N-linear (:pr:`4891`, :pr:`5514`) :user:`luca-miniati` +* more period options in ``FourierFeatures``: ``pandas`` period alias and from offset column (:pr:`5513`) :user:`Ram0nB` +* ``iisignature`` backend option for ``SignatureTransformer`` (:pr:`5398`) :user:`sz85512678` +* ``TimeSeriesForestClassifier`` feature importance and optimized interval generation (:pr:`5338`) :user:`YHallouard` +* all stationarity tests from ``arch`` package available as estimators (:pr:`5439`) :user:`Vasudeva-bit` +* Hyperbolic sine transformation and its inverse, ``ScaledAsinhTransformer``, for soft input or output clipping (:pr:`5389`) :user:`ali-parizad` +* estimator serialization: user choice of ``serialization_format`` in ``save`` method and ``mlfow`` plugin, + support for ``cloudpickle`` (:pr:`5486`, :pr:`5526`) :user:`achieveordie` + +Dependency changes +~~~~~~~~~~~~~~~~~~ + +* ``holidays`` (transformations soft dependency) bounds have been updated to ``>=0.29,<0.36``. +* ``torch`` is now a managed soft dependency for neural networks (``dl`` test set) + +Core interface changes +~~~~~~~~~~~~~~~~~~~~~~ + +* if using ``scikit-base>=0.6.1``: ``set_params`` now recognizes unique ``__``-separated + suffixes as aliases for full parameter string, e.g., ``set_params(foo="bar")`` + instead of ``set_params(estimator__detrender__forecaster__supercalifragilistic__foo="bar")``. + This extends to use of parameter names in tuners, e.g., ``ForecastingGridSearchCV`` grids, + and estimators internally using ``set_params``. The behaviour of ``get_params`` is unchanged. +* ``sktime`` now supports ``cloudpickle`` for estimator serialization, with ``pickle`` + being the standard serialization backend. + To select the serialization backend, use the ``serialization_format`` parameter + of estimators' ``save`` method. + ``cloudpickle`` is already a soft dependency, therefore no dependency change is required. + +Enhancements +~~~~~~~~~~~~ + +BaseObject and base framework +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [ENH] test that ``set_params`` recognizes unique suffixes as aliases for full parameter string (:pr:`2931`) :user:`fkiraly` +* [ENH] estimator serialization: user choice of ``serialization_format``, support for ``cloudpickle`` (:pr:`5486`) :user:`achieveordie` + +Benchmarking, Metrics, Splitters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [ENH] in ``ExpandingGreedySplitter``, allow ``float`` ``step_size`` (:pr:`5329`) :user:`fkiraly` +* [ENH] Sensible default for ``BaseSplitter.get_n_splits`` (:pr:`5412`) :user:`fkiraly` + +Data sets and data loaders +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [ENH] Add tecator dataset for time series regression as ``sktime`` onboard dataset (:pr:`5428`) :user:`JonathanBechtel` + +Forecasting +^^^^^^^^^^^ + +* [ENH] ``LTSFLinearForecaster``, ``LTSFLinearNetwork``, ``BaseDeepNetworkPyTorch`` (:pr:`4891`) :user:`luca-miniati` +* [ENH] ``LTSFDLinearForecaster``, ``LTSFNLinearForecaster`` (:pr:`5514`) :user:`luca-miniati` +* [ENH] parallel backend selection for forecasting tuners (:pr:`5430`) :user:`fkiraly` +* [ENH] in ``NaiveForecaster``, add valid variance prediction for in-sample forecasts (:pr:`5499`) :user:`fkiraly` + +MLOps & Deployment +~~~~~~~~~~~~~~~~~~ + +* [ENH] in ``mlflow`` plugin, improve informativity of ``ModuleNotFoundError`` messages (:pr:`5487`) :user:`achieveordie` +* [ENH] Add support for DL estimator persistence in ``mlflow`` plugin (:pr:`5526`) :user:`achieveordie` + +Neural networks +^^^^^^^^^^^^^^^ + +* [ENH] ``pytorch`` adapter for neural networks (:pr:`4891`) :user:`luca-miniati` +* [ENH] add placeholder test suite for neural networks (:pr:`5511`) :user:`fkiraly` + +Parameter estimation and hypothesis testing +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [ENH] Interface to stationarity tests from ``arch`` package (:pr:`5439`) :user:`Vasudeva-bit` + +Time series annotation +^^^^^^^^^^^^^^^^^^^^^^ + +* [ENH] Add unit tests for change point and segmentation plotting functions (:pr:`5509`) :user:`adamkells` + +Time series classification +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [ENH] ``TimeSeriesForestClassifier`` feature importance and optimized interval generation (:pr:`5338`) :user:`YHallouard` + +Transformations +^^^^^^^^^^^^^^^ + +* [ENH] Add Hyperbolic Sine transformation and its inverse (ScaledAsinhTransformer) (:pr:`5389`) :user:`ali-parizad` +* [ENH] ``iisignature`` backend option for ``SignatureTransformer`` (:pr:`5398`) :user:`sz85512678` +* [ENH] general inverse transform for ``MSTL`` transformer (:pr:`5457`) :user:`fkiraly` +* [ENH] more period options in ``FourierFeatures``: ``pandas`` period alias and from offset column (:pr:`5513`) :user:`Ram0nB` + +Maintenance +~~~~~~~~~~~ + +* [MNT] Auto format pyproject (:pr:`5425`) :user:`yarnabrina` +* [MNT] bound ``pycatch22<0.4.4`` due to breaking change in patch version (:pr:`5434`) :user:`fkiraly` +* [MNT] removed two recently added hooks (:pr:`5453`) :user:`yarnabrina` +* [MNT] xfail remote data loaders to silence sporadic failures (:pr:`5461`) :user:`fkiraly` +* [MNT] new CI workflow to test extras (:pr:`5375`) :user:`yarnabrina` +* [MNT] Split CI jobs per components with specific soft-dependencies (:pr:`5304`) :user:`yarnabrina` +* [MNT] Programmatically fix (all) typos (:pr:`5424`) :user:`kianmeng` +* [MNT] fix typos in ``base`` module (:pr:`5313`) :user:`yarnabrina` +* [MNT] fix typos in ``forecasting`` module (:pr:`5314`) :user:`yarnabrina` +* [MNT] added missing checkout steps (:pr:`5471`) :user:`yarnabrina` +* [MNT] adds code quality checks without outdated/deprecated Github actions (:pr:`5427`) :user:`yarnabrina` +* [MNT] revert PR #4681 (:pr:`5508`) :user:`yarnabrina` +* [MNT] address ``pandas`` constructor deprecation message from ``ExpandingGreedySplitter`` (:pr:`5500`) :user:`fkiraly` +* [MNT] address deprecation of ``pd.DataFrame.fillna`` with ``method`` arg (:pr:`5497`) :user:`fkiraly` +* [MNT] Dataset downloader testing workflow (:pr:`5437`) :user:`yarnabrina` +* [MNT] shorter names for CI workflow elements (:pr:`5470`) :user:`fkiraly` +* [MNT] skip ``load_solar`` in doctests (:pr:`5528`) :user:`fkiraly` +* [MNT] revert PR #4681 (:pr:`5508`) :user:`yarnabrina` +* [MNT] exclude downloads in "no soft dependencies" CI element (:pr:`5529`) :user:`fkiraly` + +* [MNT] [Dependabot](deps): Bump actions/setup-node from 3 to 4 (:pr:`5483`) :user:`dependabot[bot]` +* [MNT] [Dependabot](deps-dev): Update pytest-timeout requirement from <2.2,>=2.1 to >=2.1,<2.3 (:pr:`5482`) :user:`dependabot[bot]` +* [MNT] [Dependabot](deps): Bump tj-actions/changed-files from 39 to 40 (:pr:`5492`) :user:`dependabot[bot]` +* [MNT] [Dependabot](deps-dev): Update holidays requirement from <0.35,>=0.29 to >=0.29,<0.36 (:pr:`5443`) :user:`dependabot[bot]` + +Documentation +~~~~~~~~~~~~~ + +* [DOC] fixing docstring example for ``FhPlexForecaster`` (:pr:`4931`) :user:`fkiraly` +* [DOC] Programmatically fix (all) typos (:pr:`5424`) :user:`kianmeng` +* [DOC] comments for readability of ``pyproject.toml`` (:pr:`5472`) :user:`fkiraly` +* [DOC] streamlining API reference, fixing minor issues (:pr:`5466`) :user:`fkiraly` +* [DOC] Fix more typos (:pr:`5478`) :user:`szepeviktor` +* [DOC] update docstring of ``STLTransformer`` to correct statements on inverse and pipelines (:pr:`5455`) :user:`fkiraly` +* [DOC] improved docstrings for ``statsforecast`` estimators (:pr:`5409`) :user:`fkiraly` +* [DOC] add missing API reference entries for five deep learning classifiers (:pr:`5522`) :user:`fkiraly` +* [DOC] fixed docstrings for stationarity tests (:pr:`5531`) :user:`fkiraly` + +Fixes +~~~~~ + +BaseObject and base framework +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [BUG] fix error message in ``_check_python_version`` (:pr:`5473`) :user:`fkiraly` + +Benchmarking, Metrics, Splitters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [BUG] fix bug in deprecation logic of ``kwargs`` in ``evaluate`` that always set + backend to ``dask_lazy`` if deprecated ``kwargs`` are passed (:pr:`5469`) :user:`fkiraly` + +Forecasting +^^^^^^^^^^^ + +* [BUG] Fix ``pandas`` ``FutureWarning`` for silent upcasting (:pr:`5395`) :user:`tpvasconcelos` +* [BUG] fix predict function of ``make_reduction`` (recursive, global) to work with tz aware data (:pr:`5464`) :user:`ciaran-g` +* [BUG] in ``TransformedTargetForecaster``, ensure correct setting of ``ignores-exogenous-X`` tag if forecaster ignores ``X``, but at least one transformer uses ``y=X``, e.g., feature selector (:pr:`5521`) :user:`fkiraly` + +Parameter estimation and hypothesis testing +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [BUG] fixed incorrect signs for some stationarity tests (:pr:`5531`) :user:`fkiraly` + +Time series annotation +^^^^^^^^^^^^^^^^^^^^^^ + +* [BUG] CLASP logic: remove indexes from exclusion zone that are out of range (:pr:`5459`) :user:`Alex-JG3` +* [BUG] in ``ClaSPSegmentation``, deal with ``k`` when it is too large for ``np.argpartition`` (:pr:`5490`) :user:`Alex-JG3` + +Time series classification +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* [BUG] fix missing epochs parameter in ``MCDCNNClassifier._fit`` (#4996) (:pr:`5422`) :user:`pseudomo` +* [BUG] add missing exports five deep learning classifiers (:pr:`5522`) :user:`fkiraly` + +Transformations +^^^^^^^^^^^^^^^ + +* [BUG] fix test excepts for ``SignatureTransformer`` (:pr:`5474`) :user:`fkiraly` + +Visualization +^^^^^^^^^^^^^ + +* [BUG] fix ``plot_series`` prediction interval plotting for 3 or less points in forecasting horizon (:pr:`5494`) :user:`fkiraly` + +Contributors +~~~~~~~~~~~~ + +:user:`achieveordie`, +:user:`adamkells`, +:user:`Alex-JG3`, +:user:`ali-parizad`, +:user:`ciaran-g`, +:user:`fkiraly`, +:user:`JonathanBechtel`, +:user:`kianmeng`, +:user:`luca-miniati`, +:user:`pseudomo`, +:user:`Ram0nB`, +:user:`sz85512678`, +:user:`szepeviktor`, +:user:`tpvasconcelos`, +:user:`Vasudeva-bit`, +:user:`yarnabrina`, +:user:`YHallouard` + + Version 0.24.0 - 2023-10-13 --------------------------- @@ -129,7 +1064,7 @@ Benchmarking, Metrics, Splitters ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * time series splitters, i.e., descendants of ``BaseSplitter``, have moved from - ``sktime.forecasting.model_selection`` to ``sktime.`split``. + ``sktime.forecasting.model_selection`` to ``sktime.split``. The old location ``model_selection`` is deprecated and will be removed in 0.25.0. Until 0.25.0, it is still available but will raise an informative warning message. @@ -198,7 +1133,7 @@ Transformations * [ENH] add proper ``inverse_transform`` to ``STLTransformer`` (:pr:`5300`) :user:`fkiraly` * [ENH] ``joblib`` and ``dask`` backends in broadcasting of estimators in multivariate or hierarchical case - part 1, ``VectorizedDF.vectorize_est`` (:pr:`5267`) :user:`fkiraly` * [ENH] ``joblib`` and ``dask`` backends in broadcasting of estimators in multivariate or hierarchical case - part 2, base class config (:pr:`5301`) :user:`fkiraly` -* [ENH] Refactor of `DateTimeFeatures` tests to `pytest` fixtures (:pr:`5397`) :user:`adamkells` +* [ENH] Refactor of ``DateTimeFeatures`` tests to ``pytest`` fixtures (:pr:`5397`) :user:`adamkells` Testing framework ^^^^^^^^^^^^^^^^^ @@ -253,7 +1188,7 @@ Benchmarking, Metrics, Splitters Forecasting ^^^^^^^^^^^ -* [BUG] fix ``STLForecaster`` tag ``ignores-exogenous-X`` to be correctly set for composites (:pr:`5365`) :user:`yarnabrina` +* [BUG] fix ``STLForecaster`` tag ``ignores-exogeneous-X`` to be correctly set for composites (:pr:`5365`) :user:`yarnabrina` * [BUG] ``statsforecast 1.6.0`` compatibility - in ``statsforecast`` adapter, fixing ``RuntimeError: dictionary changed size during iteration`` (:pr:`5317`) :user:`arnaujc91` * [BUG] ``statsforecast 1.6.0`` compatibility - fix argument differences between ``sktime`` and ``statsforecast`` (:pr:`5393`) :user:`luca-miniati` * [BUG] Fix ``ARCH._check_predict_proba`` (:pr:`5384`) :user:`Vasudeva-bit` @@ -393,8 +1328,8 @@ Benchmarking, Metrics, Splitters * [ENH] speed up ``BaseSplitter`` boilerplate (:pr:`5063`) :user:`fkiraly` * [ENH] Allow unrestricted ID string for ``BaseBenchmarking`` (:pr:`5130`) :user:`hazrulakmal` -Data loaders -^^^^^^^^^^^^ +Data sets and data loaders +^^^^^^^^^^^^^^^^^^^^^^^^^^ * [ENH] set mirrors for time series classification data loaders (:pr:`5260`) :user:`fkiraly` @@ -670,8 +1605,8 @@ Benchmarking, Metrics, Splitters * [ENH] input checks for ``BaseBenchmark``, allow ``add_estimator`` to accept multiple estimators (:pr:`4877`) :user:`hazrulakmal` * [ENH] tests and fixes for ``numpy`` weights in performance metrics - probabilistic metrics (:pr:`5104`) :user:`fkiraly` -Data loaders -^^^^^^^^^^^^ +Data sets and data loaders +^^^^^^^^^^^^^^^^^^^^^^^^^^ * [ENH] rework data loader module, ability to specify download mirrors (:pr:`4985`) :user:`fkiraly` diff --git a/docs/source/conf.py b/docs/source/conf.py index 40e61719795..66c87cff0f5 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -4,7 +4,6 @@ import datetime import os import sys -from importlib import import_module import sktime @@ -325,33 +324,41 @@ def _process_author_info(author_info): Multiple author names will be separated by a comma, with the final name always preceded by "&". """ - if isinstance(author_info, list): - if len(author_info) > 1: - return ", ".join(author_info[:-1]) + " & " + author_info[-1] - else: - return author_info[0] + if isinstance(author_info, str) and author_info.lower() == "sktime developers": + link = ( + '<a href="https://www.sktime.net/en/stable/about/team.html">' + "sktime developers</a>" + ) + return link + + if not isinstance(author_info, list): + author_info = [author_info] + + def _add_link(github_id_str): + link = '<a href="https://www.github.com/{0}">{0}</a>'.format(github_id_str) + return link + + author_info = [_add_link(author) for author in author_info] + + if len(author_info) > 1: + return ", ".join(author_info[:-1]) + " & " + author_info[-1] else: - return author_info + return author_info[0] def _does_not_start_with_underscore(input_string): return not input_string.startswith("_") # creates dataframe as df - COLNAMES = ["Class Name", "Estimator Type", "Authors"] + COLNAMES = ["Class Name", "Estimator Type", "Authors", "Maintainers"] - df = pd.DataFrame([], columns=COLNAMES) + records = [] for modname, modclass in all_estimators(): - algorithm_type = "::".join(str(modclass).split(".")[1:-2]) - try: - author_info = _process_author_info(modclass.__author__) - except AttributeError: - try: - author_info = _process_author_info( - import_module(modclass.__module__).__author__ - ) - except AttributeError: - author_info = "no author info" + algorithm_type = modclass.get_class_tag("object_type", "object") + author_tag = modclass.get_class_tag("authors", "sktime developers") + author_info = _process_author_info(author_tag) + maintainer_tag = modclass.get_class_tag("maintainers", "sktime developers") + maintainer_info = _process_author_info(maintainer_tag) # includes part of class string modpath = str(modclass)[8:-2] @@ -368,8 +375,9 @@ def _does_not_start_with_underscore(input_string): + "</a>" ) - record = pd.DataFrame([modname, algorithm_type, author_info], index=COLNAMES).T - df = pd.concat([df, record], ignore_index=True) + records.append([modname, algorithm_type, author_info, maintainer_info]) + + df = pd.DataFrame(records, columns=COLNAMES) with open("estimator_overview_table.md", "w") as file: df.to_markdown(file, index=False) diff --git a/docs/source/developer_guide/dependencies.rst b/docs/source/developer_guide/dependencies.rst index 92f4f3b4ac2..c083398493a 100644 --- a/docs/source/developer_guide/dependencies.rst +++ b/docs/source/developer_guide/dependencies.rst @@ -52,11 +52,19 @@ Estimators with a soft dependency need to ensure the following: To do this, add a ``# doctest: +SKIP`` to the end of each line in the doctest to skip it entirely. See ``forecasting.arima.ARIMA`` as as an example. If concerned that skipping the test will reduce test coverage, consider exposing the doctest example as a pytest test function instead, see below how to handle soft dependencies in pytest functions. -* Decorate all ``pytest`` tests that import soft dependencies with a ``@pytest.mark.skipif(...)`` conditional on a check to ``_check_soft_dependencies`` - for your new soft dependency, with ``severity="none"``. Be sure that all soft dependencies imported for testing are imported within the test function itself, - rather than for the whole module! This decorator will then skip your test, including imports, unless the system has the required packages installed. - This prevents crashes for any users running ``check_estimator`` on all estimators, or a full local ``pytest`` run without the required soft dependency. - See the tests in ``forecasting.tests.test_pmdarima`` for a concrete example. +* Decorate all ``pytest`` tests that import soft dependencies with a ``@pytest.mark.skipif(...)`` conditional on a soft dependency check. + If the test is specific to a single estimator or object, use ``run_test_for_class`` from ``sktime.tests.test_switch`` + to mediate the condition through the class tags. + Otherwise, use ``_check_soft_dependencies`` for your new soft dependency, with ``severity="none"``. + Be sure that all soft dependencies imported for testing are imported within the test function itself, + rather than at root level (at the top) of the module. + This decorator will then skip your test, including imports, + unless the system has the required packages installed. + This prevents crashes for any users running ``check_estimator`` on all estimators, + or a full local ``pytest`` run without the required soft dependency. + See the tests in ``forecasting.tests.test_pmdarima`` for a concrete example of + ``run_test_for_class`` usage to decorate a test. See ``utils.tests.test_plotting`` + for an example of ``_check_soft_dependencies`` usage. Adding and maintaining soft dependencies ---------------------------------------- diff --git a/docs/source/developer_guide/deprecation.rst b/docs/source/developer_guide/deprecation.rst index 80f0ca94b55..a37a88f85be 100644 --- a/docs/source/developer_guide/deprecation.rst +++ b/docs/source/developer_guide/deprecation.rst @@ -83,6 +83,157 @@ Special deprecations This section outlines the deprecation process for some advanced cases. +Deprecating and change of parameters +------------------------------------ + +The following are common cases of deprecation or change around parameters +of functions or classes (e.g., estimators): + +* changing the default value of a parameter +* renaming a parameter +* adding a parameter with a default value that changes prior behaviour +* changing the sequence of parameters +* removing a parameter + +In all cases, it needs to be ensured that: + +* warnings are raised in cases where user logic would change +* the warning message includes a complete recipe for how to change the code, + to retain current behaviour, or change to alternative behaviour +* sufficient notice is given, i.e., the warning message is present for at least + one MINOR version cycle before the change is carried out +* "todo" comments are left for the release managers to carry out the change, + and optimally a merge-ready change branch/PR is provided, to be merged at the + scheduled version of change + +No such warning is necessary if no working user logic would change, this is the case if: + +* a parameter is added with a default value that retains prior behaviour, + at the end of the parameter list +* a parameter is removed where non-defaults would always raise unexpected exceptions + +Recipes for individual cases above follow. + +Changing the default value of a parameter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To change the default value of a parameter, follow steps 1-3 in the pull request +implementing the change. + +1. at current version, change the default value to ``"changing_value"``. + Internally, add logic that overrides the value of the parameter with the old default + value, if the parameter is set to ``"changing_value"``. If the parameter is an + ``__init__`` parameter of an estimator class, + the value cannot be directly overridden, but this needs to be done in a private + parameter copy, since all ``__init__`` parameters must be written + to ``self`` unchanged. I.e., write the parameter to ``self._<param_name>`` unchanged, + and add logic that overrides the value of ``self._<param_name>`` with the old default, + and ensure to use ``self._<param_name>`` in the rest of the code instead of + ``self.<param_name>``. +2. add a warning, using ``sktime.utils.warnings.warn``, if the parameter is called + with a non-default. This warning should always include the name of the estimator/function, + the version of change, and a clear instruction on how to change the code to retain + prior behaviour. E.g., ``"Parameter <param_name> of <estimator_name> will change + default value from <old_value> to <new_value> in sktime version <version_number>. + To retain prior behaviour, set <param_name> to <old_value> explicitly"``. +3. add a TODO comment to the code, to remove the warning and change the default value, + in the next MINOR version cycle. E.g., add the comment + ``# TODO <version_number>: change default of <param_name> to <new_value>, + update docstring, and remove warning``, + at the top of the function or class where the parameter is defined. +4. the release manager will carry out the TODO action in the next MINOR version cycle, + and remove the TODO comment. Optimally, a change branch is provided that the + release manager can merge, and its PR ID is mentioned in the todo. + +Renaming a parameter +~~~~~~~~~~~~~~~~~~~~ + +To rename a parameter, follow steps 1-6 in the pull request +implementing the change. + +1. at current version, add a parameter with the new name at the end of the + list of parameters, with the same default value as the old parameter. + Do not remove the old parameter. +2. change the value of the old parameter to the string ``"deprecated"``. + Change all code in the function or class that uses the old parameter to use + the new parameter instead. This can be done by a bulk-replace. +3. at the start of the function or class init, add logic that overrides the value + of the new parameter with the value of the old parameter, if the old parameter + is not ``"deprecated"``. If the parameter is an ``__init__`` parameter + of an estimator class, + the value cannot be directly overridden, but this needs to be done in a private + parameter, since all ``__init__`` parameters must be written to ``self`` unchanged. +4. add a warning, using ``sktime.utils.warnings.warn``, if the old parameter is called + with a non-default. This warning should always include the name of the estimator/function, + the version of change, and a clear instruction on how to change the code to retain + prior behaviour. E.g., ``"Parameter <param_name> of <estimator_name> will be renamed + from <old_name> to <new_name> in sktime version <version_number>. + To retain prior behaviour, use a kwargs call of <new_name> instead of <old_name>"``. +5. update the docstring of the function or class to refer only to the new parameter. +6. add a TODO comment to the code, to remove the warning and change the default value, + in the next MINOR version cycle. E.g., add the comment + ``# TODO <version_number>: change name of parameter <old_name> to <new_name>, + remove old parameter at the end, and remove warning``, + at the top of the function or class where the parameter is defined. +7. the release manager will carry out the TODO action in the next MINOR version cycle, + and remove the TODO comment. Optimally, a change branch is provided that the + release manager can merge, and its PR ID is mentioned in the todo. + +Adding a parameter with a default value that changes prior behaviour +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This should be done in two steps: + +* adding the parameter, but with a default value that retains prior behaviour. + As this preserves prior behaviour, no deprecation or change mechanism is necessary. +* then, follow the steps for changing the default value of a parameter, above. + +Changing the sequence of parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This type of change should be avoided, as it it is difficult to carry out. +If instead one of the above change patterns can be used, that is preferred. + +To change the sequence of parameters, follow steps 1-6 in the pull request +implementing the change. + +1. at current version, change the defaults of all parameters after and including + the first parameter to change position to ``"position_change"``. +2. Internally, add logic that overrides the value of the parameter with the old default + value, if the parameter is set to ``"position_change"``. + For ``__init__`` parameters of an estimator class, + the values cannot be directly overridden, but this needs to be done in a private + parameter copy, since all ``__init__`` parameters must be written + to ``self`` unchanged. I.e., write the parameter to ``self._<param_name>`` unchanged, + and add logic that overrides the value of ``self._<param_name>`` with the old default, + and ensure to use ``self._<param_name>`` in the rest of the code instead of + ``self.<param_name>``. +3. add a warning, using ``sktime.utils.warnings.warn``, if any of the position changing + paramters are called with a non-default. This warning should always include + the name of the estimator/function, the version of change, and a clear instruction + on how to change the code to retain prior behaviour. The instruction + should direct the user to use ``kwargs`` calls instead of positional calls, for + all parameters that change position. +4. add a TODO comment to the code, to remove the warning and change the sequence, + as well as changing default values to the old defaults, + in the next MINOR version cycle. + The TODO comment should contain complete lines of code. + Optimally, a change branch is provided that the + release manager can merge, and its PR ID is mentioned in the todo. + +Removing a parameter +~~~~~~~~~~~~~~~~~~~~ + +If the parameter is removed a position that is not at the end of the parameter list, +it should be first moved to the end o the parameter list. + +For removal of a parameter, follow the steps of "changing the default value", +with a different warning message, namely that the parameter will be removed. + +The error message should contain details on whether prior behaviour can be retained, +if yes in which cases, and if yes, how. + + Deprecating tags ---------------- @@ -108,3 +259,76 @@ When removing/renaming tags after the deprecation period, ensure to remove the removed tags from the dictionaries in ``TagAliaserMixin`` class. If no tags are deprecated anymore (e.g., all deprecated tags are removed/renamed), ensure to remove this class as a parent of ``BaseObject`` or ``BaseEstimator``. + +Example +======= +Here is a simple example template for renaming a parameter of an estimator while changing default value as well. + +Step 1: before any change +------------------------- + +.. code:: python + + class EstimatorName: + def __init__(self, old_parameter="old"): + self.old_parameter = old_parameter + + def fit(self, X, y): + # Fit the model using old_parameter + pass + + def predict(self, X): + # Predict using the fitted model + pass + +Step 2: during deprecation period +--------------------------------- + +.. code:: python + + from sktime.utils.warnings import warn + + + class EstimatorName: + def __init__(self, old_parameter=None, new_parameter="new"): + # TODO (release <MAJOR>.<MINOR>.0) + # remove the 'old_parameter' argument from '__init__' signature + # remove the following 'if' check + # de-indent the following 'else' check + if old_parameter is not None: + warn( + "'old_parameter' of `EstimatorName` is deprecated and will be removed" + " in the version '<MAJOR>.<MINOR>.0'. This has been renamed to " + " 'new_parameter', where you can pass 'old' to keep current behaviour." + " The new argument will use 'new' as its default value.", + category=DeprecationWarning, + obj=self, + ) + self.new_parameter = old_parameter + else: + self.new_parameter = new_parameter + + def fit(self, X, y): + # Fit the model using new_parameter + pass + + def predict(self, X): + # Predict using the fitted model + pass + +Step 3: after deprecation period +-------------------------------- + +.. code:: python + + class FinalEstimator: + def __init__(self, new_parameter="new"): + self.new_parameter = new_parameter + + def fit(self, X, y): + # Fit the model using new_parameter + pass + + def predict(self, X): + # Predict using the fitted model + pass diff --git a/docs/source/get_involved/governance.rst b/docs/source/get_involved/governance.rst index 153f8f411fb..d20d7e62713 100644 --- a/docs/source/get_involved/governance.rst +++ b/docs/source/get_involved/governance.rst @@ -160,11 +160,17 @@ Appointment The contributor who contributes an algorithm is automatically appointed as its first maintainer. -Algorithm maintainers are listed in the `CODEOWNERS <https://github -.com/alan-turing-institute/sktime/blob/main/CODEOWNERS>`__ file. +Algorithm maintainers are listed in the ``"maintainers"`` tag of the estimator class, +by their GitHub ID. The GitHub ID can be linked to further information via +the ``all-contributorsrc`` file. +The tag can be inspected directly in the source code of the class, +or via ``EstimatorName.get_class_tag("maintainers").`` +Inverse lookup such as "which algorithms does maintainer M maintain" +can be carried out using ``registry.all_estimators``. When an algorithm maintainer resigns, they can appoint another contributor as the -new algorithm maintainer. No vote is required. This change should be reflected in the ``CODEOWNERS`` file. +new algorithm maintainer. No vote is required. +This change should be reflected in the ``"maintainers"`` tag. Algorithm maintainers can be appointed by CC simple majority for any algorithm without maintainers. @@ -664,18 +670,19 @@ We have the following guidelines: will have to be extended first. For extending current API, see the `decision making process <#Decision-making>`__ for major changes. -Note that your implementation need not be in sktime to be used together -with sktime tools. You can implement your favorite algorithm in a sktime -compatible way in one of `our companion -repositories <https://github.com/sktime>`__ on GitHub. We will be happy -to list it under `related +Note that an algorithm need not be in sktime to be fully compatible with +sktime interfaces. You can implement your favorite algorithm in a sktime +compatible way in a third party codebase - open or closed - following +the guide for implmenting compatible estimators (see :ref:`developer_guide_add_estimators:`). + +We are happy to list any compatible open source project under `related software <https://github.com/sktime/sktime/wiki/related-software>`__. +Contributions are also welcome to any one of `our companion +repositories <https://github.com/sktime>`__ on GitHub. -If algorithms require major dependencies, we encourage to create a -separate companion repository. For smaller -dependencies which are limited to a few files, we encourage to use soft -dependencies, which are only required for particular modules, but not -for most of sktime's functionality and not for installing sktime. +Dependencies are managed on the level of estimators, hence it is entirely possible +to maintain an algorithm primarily in a third or second party package, and add a +thin interface to sktime proper which has that package as a dependency. .. _acknowledging-contributions: diff --git a/docs/source/get_started.rst b/docs/source/get_started.rst index cce05ec1370..5295cf59476 100644 --- a/docs/source/get_started.rst +++ b/docs/source/get_started.rst @@ -75,9 +75,9 @@ Forecasting >>> from sktime.datasets import load_airline >>> from sktime.forecasting.base import ForecastingHorizon - >>> from sktime.forecasting.model_selection import temporal_train_test_split >>> from sktime.forecasting.theta import ThetaForecaster >>> from sktime.performance_metrics.forecasting import mean_absolute_percentage_error + >>> from sktime.split import temporal_train_test_split >>> y = load_airline() >>> y_train, y_test = temporal_train_test_split(y) diff --git a/docs/source/installation.rst b/docs/source/installation.rst index f5340428f33..5b7a1403813 100644 --- a/docs/source/installation.rst +++ b/docs/source/installation.rst @@ -10,8 +10,6 @@ Installation See here for a `full list of precompiled wheels available on PyPI <https://pypi.org/simple/sktime/>`_. -We appreciate community contributions towards compatibility with python 3.10, or other operating systems. - .. contents:: :local: diff --git a/docs/source/user_guide/introduction.rst b/docs/source/user_guide/introduction.rst index 672dca8a61a..70f6c7fd88b 100644 --- a/docs/source/user_guide/introduction.rst +++ b/docs/source/user_guide/introduction.rst @@ -31,8 +31,8 @@ can simply write: from sktime.datasets import load_airline from sktime.forecasting.compose import make_reduction from sklearn.ensemble import RandomForestRegressor - from sktime.forecasting.model_selection import temporal_train_test_split from sktime.performance_metrics.forecasting import MeanAbsolutePercentageError + from sktime.split import temporal_train_test_split y = load_airline() y_train, y_test = temporal_train_test_split(y) diff --git a/examples/01b_forecasting_proba.ipynb b/examples/01b_forecasting_proba.ipynb index 9f5b00dd08f..ec5ff971cb3 100644 --- a/examples/01b_forecasting_proba.ipynb +++ b/examples/01b_forecasting_proba.ipynb @@ -102,12 +102,12 @@ " </tr>\n", " <tr>\n", " <th>1961-02</th>\n", - " <td>344.853206</td>\n", + " <td>344.853205</td>\n", " <td>497.712761</td>\n", " </tr>\n", " <tr>\n", " <th>1961-03</th>\n", - " <td>324.223996</td>\n", + " <td>324.223995</td>\n", " <td>508.191104</td>\n", " </tr>\n", " </tbody>\n", @@ -119,8 +119,8 @@ " 0.9 \n", " lower upper\n", "1961-01 371.535093 481.554608\n", - "1961-02 344.853206 497.712761\n", - "1961-03 324.223996 508.191104" + "1961-02 344.853205 497.712761\n", + "1961-03 324.223995 508.191104" ] }, "execution_count": 2, @@ -206,243 +206,257 @@ " <tbody>\n", " <tr>\n", " <th>0</th>\n", + " <td>ARCH</td>\n", + " <td><class 'sktime.forecasting.arch._uarch.ARCH'></td>\n", + " </tr>\n", + " <tr>\n", + " <th>1</th>\n", " <td>ARIMA</td>\n", " <td><class 'sktime.forecasting.arima.ARIMA'></td>\n", " </tr>\n", " <tr>\n", - " <th>1</th>\n", + " <th>2</th>\n", " <td>AutoARIMA</td>\n", " <td><class 'sktime.forecasting.arima.AutoARIMA'></td>\n", " </tr>\n", " <tr>\n", - " <th>2</th>\n", + " <th>3</th>\n", " <td>AutoETS</td>\n", " <td><class 'sktime.forecasting.ets.AutoETS'></td>\n", " </tr>\n", " <tr>\n", - " <th>3</th>\n", + " <th>4</th>\n", " <td>BATS</td>\n", " <td><class 'sktime.forecasting.bats.BATS'></td>\n", " </tr>\n", " <tr>\n", - " <th>4</th>\n", + " <th>5</th>\n", " <td>BaggingForecaster</td>\n", " <td><class 'sktime.forecasting.compose._bagging.Ba...</td>\n", " </tr>\n", " <tr>\n", - " <th>5</th>\n", + " <th>6</th>\n", " <td>ColumnEnsembleForecaster</td>\n", " <td><class 'sktime.forecasting.compose._column_ens...</td>\n", " </tr>\n", " <tr>\n", - " <th>6</th>\n", + " <th>7</th>\n", " <td>ConformalIntervals</td>\n", " <td><class 'sktime.forecasting.conformal.Conformal...</td>\n", " </tr>\n", " <tr>\n", - " <th>7</th>\n", + " <th>8</th>\n", " <td>DynamicFactor</td>\n", " <td><class 'sktime.forecasting.dynamic_factor.Dyna...</td>\n", " </tr>\n", " <tr>\n", - " <th>8</th>\n", + " <th>9</th>\n", " <td>FhPlexForecaster</td>\n", " <td><class 'sktime.forecasting.compose._fhplex.FhP...</td>\n", " </tr>\n", " <tr>\n", - " <th>9</th>\n", + " <th>10</th>\n", " <td>ForecastX</td>\n", " <td><class 'sktime.forecasting.compose._pipeline.F...</td>\n", " </tr>\n", " <tr>\n", - " <th>10</th>\n", + " <th>11</th>\n", " <td>ForecastingGridSearchCV</td>\n", " <td><class 'sktime.forecasting.model_selection._tu...</td>\n", " </tr>\n", " <tr>\n", - " <th>11</th>\n", + " <th>12</th>\n", " <td>ForecastingPipeline</td>\n", " <td><class 'sktime.forecasting.compose._pipeline.F...</td>\n", " </tr>\n", " <tr>\n", - " <th>12</th>\n", + " <th>13</th>\n", " <td>ForecastingRandomizedSearchCV</td>\n", " <td><class 'sktime.forecasting.model_selection._tu...</td>\n", " </tr>\n", " <tr>\n", - " <th>13</th>\n", + " <th>14</th>\n", " <td>ForecastingSkoptSearchCV</td>\n", " <td><class 'sktime.forecasting.model_selection._tu...</td>\n", " </tr>\n", " <tr>\n", - " <th>14</th>\n", + " <th>15</th>\n", " <td>NaiveForecaster</td>\n", " <td><class 'sktime.forecasting.naive.NaiveForecast...</td>\n", " </tr>\n", " <tr>\n", - " <th>15</th>\n", + " <th>16</th>\n", " <td>NaiveVariance</td>\n", " <td><class 'sktime.forecasting.naive.NaiveVariance'></td>\n", " </tr>\n", " <tr>\n", - " <th>16</th>\n", + " <th>17</th>\n", " <td>Permute</td>\n", " <td><class 'sktime.forecasting.compose._pipeline.P...</td>\n", " </tr>\n", " <tr>\n", - " <th>17</th>\n", + " <th>18</th>\n", " <td>Prophet</td>\n", " <td><class 'sktime.forecasting.fbprophet.Prophet'></td>\n", " </tr>\n", " <tr>\n", - " <th>18</th>\n", + " <th>19</th>\n", " <td>SARIMAX</td>\n", " <td><class 'sktime.forecasting.sarimax.SARIMAX'></td>\n", " </tr>\n", " <tr>\n", - " <th>19</th>\n", + " <th>20</th>\n", " <td>SquaringResiduals</td>\n", " <td><class 'sktime.forecasting.squaring_residuals....</td>\n", " </tr>\n", " <tr>\n", - " <th>20</th>\n", + " <th>21</th>\n", " <td>StatsForecastARCH</td>\n", - " <td><class 'sktime.forecasting.arch.StatsForecastA...</td>\n", + " <td><class 'sktime.forecasting.arch._statsforecast...</td>\n", " </tr>\n", " <tr>\n", - " <th>21</th>\n", + " <th>22</th>\n", " <td>StatsForecastAutoARIMA</td>\n", " <td><class 'sktime.forecasting.statsforecast.Stats...</td>\n", " </tr>\n", " <tr>\n", - " <th>22</th>\n", + " <th>23</th>\n", " <td>StatsForecastAutoCES</td>\n", " <td><class 'sktime.forecasting.statsforecast.Stats...</td>\n", " </tr>\n", " <tr>\n", - " <th>23</th>\n", + " <th>24</th>\n", " <td>StatsForecastAutoETS</td>\n", " <td><class 'sktime.forecasting.statsforecast.Stats...</td>\n", " </tr>\n", " <tr>\n", - " <th>24</th>\n", + " <th>25</th>\n", " <td>StatsForecastAutoTheta</td>\n", " <td><class 'sktime.forecasting.statsforecast.Stats...</td>\n", " </tr>\n", " <tr>\n", - " <th>25</th>\n", + " <th>26</th>\n", " <td>StatsForecastGARCH</td>\n", - " <td><class 'sktime.forecasting.arch.StatsForecastG...</td>\n", + " <td><class 'sktime.forecasting.arch._statsforecast...</td>\n", " </tr>\n", " <tr>\n", - " <th>26</th>\n", + " <th>27</th>\n", " <td>StatsForecastMSTL</td>\n", " <td><class 'sktime.forecasting.statsforecast.Stats...</td>\n", " </tr>\n", " <tr>\n", - " <th>27</th>\n", + " <th>28</th>\n", " <td>TBATS</td>\n", " <td><class 'sktime.forecasting.tbats.TBATS'></td>\n", " </tr>\n", " <tr>\n", - " <th>28</th>\n", + " <th>29</th>\n", " <td>ThetaForecaster</td>\n", " <td><class 'sktime.forecasting.theta.ThetaForecast...</td>\n", " </tr>\n", " <tr>\n", - " <th>29</th>\n", + " <th>30</th>\n", " <td>TransformedTargetForecaster</td>\n", " <td><class 'sktime.forecasting.compose._pipeline.T...</td>\n", " </tr>\n", " <tr>\n", - " <th>30</th>\n", + " <th>31</th>\n", " <td>UnobservedComponents</td>\n", " <td><class 'sktime.forecasting.structural.Unobserv...</td>\n", " </tr>\n", " <tr>\n", - " <th>31</th>\n", + " <th>32</th>\n", " <td>VAR</td>\n", " <td><class 'sktime.forecasting.var.VAR'></td>\n", " </tr>\n", " <tr>\n", - " <th>32</th>\n", + " <th>33</th>\n", " <td>VECM</td>\n", " <td><class 'sktime.forecasting.vecm.VECM'></td>\n", " </tr>\n", + " <tr>\n", + " <th>34</th>\n", + " <td>YfromX</td>\n", + " <td><class 'sktime.forecasting.compose._reduce.Yfr...</td>\n", + " </tr>\n", " </tbody>\n", "</table>\n", "</div>" ], "text/plain": [ " name \\\n", - "0 ARIMA \n", - "1 AutoARIMA \n", - "2 AutoETS \n", - "3 BATS \n", - "4 BaggingForecaster \n", - "5 ColumnEnsembleForecaster \n", - "6 ConformalIntervals \n", - "7 DynamicFactor \n", - "8 FhPlexForecaster \n", - "9 ForecastX \n", - "10 ForecastingGridSearchCV \n", - "11 ForecastingPipeline \n", - "12 ForecastingRandomizedSearchCV \n", - "13 ForecastingSkoptSearchCV \n", - "14 NaiveForecaster \n", - "15 NaiveVariance \n", - "16 Permute \n", - "17 Prophet \n", - "18 SARIMAX \n", - "19 SquaringResiduals \n", - "20 StatsForecastARCH \n", - "21 StatsForecastAutoARIMA \n", - "22 StatsForecastAutoCES \n", - "23 StatsForecastAutoETS \n", - "24 StatsForecastAutoTheta \n", - "25 StatsForecastGARCH \n", - "26 StatsForecastMSTL \n", - "27 TBATS \n", - "28 ThetaForecaster \n", - "29 TransformedTargetForecaster \n", - "30 UnobservedComponents \n", - "31 VAR \n", - "32 VECM \n", + "0 ARCH \n", + "1 ARIMA \n", + "2 AutoARIMA \n", + "3 AutoETS \n", + "4 BATS \n", + "5 BaggingForecaster \n", + "6 ColumnEnsembleForecaster \n", + "7 ConformalIntervals \n", + "8 DynamicFactor \n", + "9 FhPlexForecaster \n", + "10 ForecastX \n", + "11 ForecastingGridSearchCV \n", + "12 ForecastingPipeline \n", + "13 ForecastingRandomizedSearchCV \n", + "14 ForecastingSkoptSearchCV \n", + "15 NaiveForecaster \n", + "16 NaiveVariance \n", + "17 Permute \n", + "18 Prophet \n", + "19 SARIMAX \n", + "20 SquaringResiduals \n", + "21 StatsForecastARCH \n", + "22 StatsForecastAutoARIMA \n", + "23 StatsForecastAutoCES \n", + "24 StatsForecastAutoETS \n", + "25 StatsForecastAutoTheta \n", + "26 StatsForecastGARCH \n", + "27 StatsForecastMSTL \n", + "28 TBATS \n", + "29 ThetaForecaster \n", + "30 TransformedTargetForecaster \n", + "31 UnobservedComponents \n", + "32 VAR \n", + "33 VECM \n", + "34 YfromX \n", "\n", " object \n", - "0 <class 'sktime.forecasting.arima.ARIMA'> \n", - "1 <class 'sktime.forecasting.arima.AutoARIMA'> \n", - "2 <class 'sktime.forecasting.ets.AutoETS'> \n", - "3 <class 'sktime.forecasting.bats.BATS'> \n", - "4 <class 'sktime.forecasting.compose._bagging.Ba... \n", - "5 <class 'sktime.forecasting.compose._column_ens... \n", - "6 <class 'sktime.forecasting.conformal.Conformal... \n", - "7 <class 'sktime.forecasting.dynamic_factor.Dyna... \n", - "8 <class 'sktime.forecasting.compose._fhplex.FhP... \n", - "9 <class 'sktime.forecasting.compose._pipeline.F... \n", - "10 <class 'sktime.forecasting.model_selection._tu... \n", - "11 <class 'sktime.forecasting.compose._pipeline.F... \n", - "12 <class 'sktime.forecasting.model_selection._tu... \n", + "0 <class 'sktime.forecasting.arch._uarch.ARCH'> \n", + "1 <class 'sktime.forecasting.arima.ARIMA'> \n", + "2 <class 'sktime.forecasting.arima.AutoARIMA'> \n", + "3 <class 'sktime.forecasting.ets.AutoETS'> \n", + "4 <class 'sktime.forecasting.bats.BATS'> \n", + "5 <class 'sktime.forecasting.compose._bagging.Ba... \n", + "6 <class 'sktime.forecasting.compose._column_ens... \n", + "7 <class 'sktime.forecasting.conformal.Conformal... \n", + "8 <class 'sktime.forecasting.dynamic_factor.Dyna... \n", + "9 <class 'sktime.forecasting.compose._fhplex.FhP... \n", + "10 <class 'sktime.forecasting.compose._pipeline.F... \n", + "11 <class 'sktime.forecasting.model_selection._tu... \n", + "12 <class 'sktime.forecasting.compose._pipeline.F... \n", "13 <class 'sktime.forecasting.model_selection._tu... \n", - "14 <class 'sktime.forecasting.naive.NaiveForecast... \n", - "15 <class 'sktime.forecasting.naive.NaiveVariance'> \n", - "16 <class 'sktime.forecasting.compose._pipeline.P... \n", - "17 <class 'sktime.forecasting.fbprophet.Prophet'> \n", - "18 <class 'sktime.forecasting.sarimax.SARIMAX'> \n", - "19 <class 'sktime.forecasting.squaring_residuals.... \n", - "20 <class 'sktime.forecasting.arch.StatsForecastA... \n", - "21 <class 'sktime.forecasting.statsforecast.Stats... \n", + "14 <class 'sktime.forecasting.model_selection._tu... \n", + "15 <class 'sktime.forecasting.naive.NaiveForecast... \n", + "16 <class 'sktime.forecasting.naive.NaiveVariance'> \n", + "17 <class 'sktime.forecasting.compose._pipeline.P... \n", + "18 <class 'sktime.forecasting.fbprophet.Prophet'> \n", + "19 <class 'sktime.forecasting.sarimax.SARIMAX'> \n", + "20 <class 'sktime.forecasting.squaring_residuals.... \n", + "21 <class 'sktime.forecasting.arch._statsforecast... \n", "22 <class 'sktime.forecasting.statsforecast.Stats... \n", "23 <class 'sktime.forecasting.statsforecast.Stats... \n", "24 <class 'sktime.forecasting.statsforecast.Stats... \n", - "25 <class 'sktime.forecasting.arch.StatsForecastG... \n", - "26 <class 'sktime.forecasting.statsforecast.Stats... \n", - "27 <class 'sktime.forecasting.tbats.TBATS'> \n", - "28 <class 'sktime.forecasting.theta.ThetaForecast... \n", - "29 <class 'sktime.forecasting.compose._pipeline.T... \n", - "30 <class 'sktime.forecasting.structural.Unobserv... \n", - "31 <class 'sktime.forecasting.var.VAR'> \n", - "32 <class 'sktime.forecasting.vecm.VECM'> " + "25 <class 'sktime.forecasting.statsforecast.Stats... \n", + "26 <class 'sktime.forecasting.arch._statsforecast... \n", + "27 <class 'sktime.forecasting.statsforecast.Stats... \n", + "28 <class 'sktime.forecasting.tbats.TBATS'> \n", + "29 <class 'sktime.forecasting.theta.ThetaForecast... \n", + "30 <class 'sktime.forecasting.compose._pipeline.T... \n", + "31 <class 'sktime.forecasting.structural.Unobserv... \n", + "32 <class 'sktime.forecasting.var.VAR'> \n", + "33 <class 'sktime.forecasting.vecm.VECM'> \n", + "34 <class 'sktime.forecasting.compose._reduce.Yfr... " ] }, "execution_count": 3, @@ -609,7 +623,7 @@ { "data": { "text/html": [ - "<style>#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e {color: black;background-color: white;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e pre{padding: 0;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-toggleable {background-color: white;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e label.sk-toggleable__label-arrow:before {content: \"βΈ\";float: left;margin-right: 0.25em;color: #696969;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"βΎ\";}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-estimator:hover {background-color: #d4ebff;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 2em;bottom: 0;left: 50%;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-item {z-index: 1;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-parallel::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 2em;bottom: 0;left: 50%;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-parallel-item {display: flex;flex-direction: column;position: relative;background-color: white;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-parallel-item:only-child::after {width: 0;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;position: relative;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-label label {font-family: monospace;font-weight: bold;background-color: white;display: inline-block;line-height: 1.2em;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-label-container {position: relative;z-index: 2;text-align: center;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e div.sk-text-repr-fallback {display: none;}</style><div id='sk-628dc63f-6155-4eae-8eb6-2bdc0dc4437e' class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>ThetaForecaster(sp=12)</pre><b>Please rerun this cell to show the HTML repr or trust the notebook.</b></div><div class=\"sk-container\" hidden><div class='sk-item'><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('8ad53796-209d-4b30-87f5-e9980e415ced') type=\"checkbox\" checked><label for=UUID('8ad53796-209d-4b30-87f5-e9980e415ced') class='sk-toggleable__label sk-toggleable__label-arrow'>ThetaForecaster</label><div class=\"sk-toggleable__content\"><pre>ThetaForecaster(sp=12)</pre></div></div></div></div></div>" + "<style>#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff {color: black;background-color: white;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff pre{padding: 0;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-toggleable {background-color: white;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff label.sk-toggleable__label-arrow:before {content: \"βΈ\";float: left;margin-right: 0.25em;color: #696969;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"βΎ\";}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-estimator:hover {background-color: #d4ebff;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 2em;bottom: 0;left: 50%;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-item {z-index: 1;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-parallel::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 2em;bottom: 0;left: 50%;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-parallel-item {display: flex;flex-direction: column;position: relative;background-color: white;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-parallel-item:only-child::after {width: 0;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;position: relative;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-label label {font-family: monospace;font-weight: bold;background-color: white;display: inline-block;line-height: 1.2em;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-label-container {position: relative;z-index: 2;text-align: center;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff div.sk-text-repr-fallback {display: none;}</style><div id='sk-9b5446bb-0900-46a6-988d-1aa88ae0e4ff' class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>ThetaForecaster(sp=12)</pre><b>Please rerun this cell to show the HTML repr or trust the notebook.</b></div><div class=\"sk-container\" hidden><div class='sk-item'><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('119f3171-5281-4480-893d-ca664488469f') type=\"checkbox\" checked><label for=UUID('119f3171-5281-4480-893d-ca664488469f') class='sk-toggleable__label sk-toggleable__label-arrow'>ThetaForecaster</label><div class=\"sk-toggleable__content\"><pre>ThetaForecaster(sp=12)</pre></div></div></div></div></div>" ], "text/plain": [ "ThetaForecaster(sp=12)" @@ -745,7 +759,7 @@ " </tr>\n", " <tr>\n", " <th>1961-09</th>\n", - " <td>477.658056</td>\n", + " <td>477.658055</td>\n", " <td>573.047752</td>\n", " </tr>\n", " <tr>\n", @@ -756,7 +770,7 @@ " <tr>\n", " <th>1961-11</th>\n", " <td>346.942924</td>\n", - " <td>451.082016</td>\n", + " <td>451.082017</td>\n", " </tr>\n", " <tr>\n", " <th>1961-12</th>\n", @@ -779,9 +793,9 @@ "1961-06 506.585814 587.087737\n", "1961-07 561.496768 647.248956\n", "1961-08 557.363322 648.062363\n", - "1961-09 477.658056 573.047752\n", + "1961-09 477.658055 573.047752\n", "1961-10 407.915090 507.775355\n", - "1961-11 346.942924 451.082016\n", + "1961-11 346.942924 451.082017\n", "1961-12 394.708221 502.957142" ] }, @@ -812,7 +826,7 @@ "outputs": [ { "data": { - "image/png": "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1Wrlgw8+YPPmzTz22GOkp6eH93nkkUd44oknePbZZ1m1ahVJSUmcccYZeDwNI9evuOIKNm3axOLFi3n33Xf59NNPue666zrjKTXJ8LsxdR96bQmm7pNeBEIIIYQQQgghRC8VyowcnZ3c6HGXx4+rzh/xGFedn0pP5G29nemvwdR1LAlZVK17OuI+1rRhVK55JGKgsnLNo1hTh2DqMsSmI3Rqbu/DDz/MoEGDeOmll8KP5eY2jLc3TZPHH3+cu+66i/PPPx+Al19+mezsbN566y1++MMfsmXLFj788ENWr17NlClTAHjyySc5++yzefTRR+nfv3/HPqkIjIAnQorw9aQdd1vUI+e7Ip/Ph80macxCCCGEEEIIIURL/LrB9tJggtKRmZFOhxVngjViQNKZYCXNYe2QNXY3hr8GVBXdWxEONB5OTcjEMfAUDn34k4jHV617Gudxt+OvORDnlQro5MzId955hylTpnDxxRfTt29fJk2axPPPPx/eXlhYSFFREXPmzAk/lpaWxtSpU1m5ciUAK1euxOl0hgORAHPmzEFVVVatWhXxul6vl6qqqkY/rWWaJobf3eof3VdN5eqHI0Te76dy9SPovqpWn8s0zVat8eWXXyYjIwOv19vo8QsuuIArr7yy2WPvueceJk6cyF/+8hcGDRpEYmIil1xyCZWVleF9QqXVDzzwAP3792fkyJEA7N27l0suuQSn00mfPn04//zz2bVrV/g4Xde5+eabcTqdZGRkcNttt7X6OQkhhBBCCCGEED3BjlI3AcMk2a4xMK1xgpLfMJg3PTficfOm5+I3jI5YYrdjeKswdT+aIx3V7jxqu5aYg157KGKgMni8C93rwgxIZmRH6NTMyJ07d/L//t//4+abb+bOO+9k9erVzJs3D5vNxk9+8hOKiooAyM7ObnRcdnZ2eFtRURF9+/ZttN1isdCnT5/wPkd68MEHuffee9u0ZjNQy+6n01vekWDkfdA125tMEa5a9xRpU25h74vDMepKWzzfkLkVKNakFve7+OKLmTdvHu+88w4XX3wxACUlJbz33nssWrSoxeN37NjB66+/zv/+9z+qqqq49tpr+dWvfsWrr74a3mfJkiWkpqayePFiAPx+P2eccQbTpk3js88+w2KxcP/993PmmWeyYcMGbDYbjz32GAsXLuTFF19k9OjRPPbYY/z3v/9l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i2Ig8qamNllpLp2tXYn3iIiIiIiIiIjqc2lmZH0ikcgoM1IQBHTo0AEvvvgi/v73vwMAysrKEBoaio0bN+KRRx7BmTNn0KNHDxw5cgQDBw4EAGzbtg33338/8vPz0aFDB5PPpVQqoVQqDf9fXl6O8PDwFpcZSZY1NTOSiIiIiIiIiIjqNIvMSEtyc3NRWFiIxMREw2MBAQEYNGgQ0tPTAQDp6ekIDAw0BCIBIDExEWKxGIcOHTJ77uXLlyMgIMDwEx4e7rgLIbelX1fTFP26mkREREREREREZD9uG4wsLCwEAISGhho9HhoaathWWFiIkJAQo+0SiQRt27Y17GPKvHnzUFZWZvi5dOmSnUdPzYG+ycrCkbEI9JICqMuIXDgyFnOHR7OkmIiIiIiIiIjIzlpltEUul0Mul7t6GOQG9OtqvjIixqjJCtfVJCIiIiIiIiKyP7fNjFQoFACAoqIio8eLiooM2xQKBYqLi422azQaXL9+3bAPUUPYZIWIiIiIiIiIyDncNhgZGRkJhUKBXbt2GR4rLy/HoUOHEBcXBwCIi4tDaWkpjh49athn9+7d0Ol0GDRokNPHTEREREREREREROa5NAWssrISWVlZhv/Pzc3FsWPH0LZtW3Tq1AnPP/88li1bhpiYGERGRmLBggXo0KGDoeN29+7dMXr0aDz11FN47733oFarkZycjEceecRsJ20iIiIiIiIiIiJyDZcGI3/99VcMGzbM8P8vvPACAGDKlCnYuHEjXnrpJVRVVWH69OkoLS1FQkICtm3bBk9PT8Mxn332GZKTkzFixAiIxWJMmDABa9ascfq1EBERERERERERkWUiQRAEVw/C1crLyxEQEICysjL4+/u7ejhERERERERERETNSmPja267ZiQRERERERERERG1LAxGEhERERERERERkVMwGElERERERERERERO4dIGNu5Cv2xmeXm5i0dCRERERERERETU/Ojjag21p2EwEkBFRQUAIDw83MUjISIiIiIiIiIiar4qKioQEBBgdju7aQPQ6XS4cuUK/Pz8IBKJXD0cuysvL0d4eDguXbrEbuFkE84hsgfOI2oqziGyB84jairOIbIHziNqKs4hsgd7zyNBEFBRUYEOHTpALDa/MiQzIwGIxWKEhYW5ehgO5+/vzxcpahLOIbIHziNqKs4hsgfOI2oqziGyB84j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8QXCw8PRv39/AEB0dLThR5/qHRcXh127dhmdIzU1FXFxcQ6+WnIEc3PIFP080r8JxsXF4eTJk0ZvdqmpqfD390ePHj0gkUiM5pD+Q7c1c8ia8ZHrNGUeAcDp06cxbNgwTJkyBf/4xz+M9rfHPNLLz89HSUmJ0XOTe2jKHPrvf/+L48ePG97vPvjgAwDAzz//jBkzZth1DpF7a+prkal92rRpA7lczve0VsIec6iyshJfffWVUVYkwPez1sIec4jfz8jcPIqIiECHDh1w7tw5o/3Pnz+Pzp07A6ibD6WlpUbrjO7evRs6nc4QAG/qPPLx8UH79u1x48YNbN++ne9nZF8ubqDTqlVUVAgZGRlCRkaGAEB48803hYyMDOHChQuCIAjCV199JaSlpQnZ2dnCt99+K3Tu3FkYP368xXPCRNe0VatWCSdOnBBOnTolLFmyRJBKpQ12VsvJyRG8vb2FOXPmCGfOnBHWr18veHh4CNu2bWv0+MnxmjqHsrKyhCVLlgi//vqrkJubK/zvf/8TunTpIgwZMsSwj0ajEXr16iUkJSUJx44dE7Zt2yYEBwcL8+bNszi2AwcOCBKJRHj99deFM2fOCCkpKYJUKhVOnjxp2MeWOU7254x5dPLkSSE4OFh47LHHhIKCAsNPcXGxxbE1NI8qKiqEv//970J6erqQm5sr7Ny5U+jfv78QExMj1NbWOuBukSnOmEO3SktLa1Q37ca8FpWUlAgZGRnCDz/8IAAQNm3aJGRkZAgFBQVNuzFkFWfMo++++07497//LZw8eVLIzMwU3nnnHcHb21tYuHChxbHxPa15cOZr0QcffCB4eno2+Bqkx/ez5sFZc4jfz1o2e3zPf+uttwR/f39h8+bNQmZmpjB//nzB09NTyMrKMuwzevRooV+/fsKhQ4eE/fv3CzExMcKkSZMsjq0x82jbtm3CTz/9JOTk5Ag7duwQ+vTpIwwaNEhQqVR2vEvU2jEY6UL6L1K3/kyZMkUQBEF4++23hbCwMEEqlQqdOnUS5s+fLyiVSovnNBWMHDZsmBAQECB4enoKgwYNEn788cdGj69v376CTCYTunTpImzYsMGq8ZPjNXUOXbx4URgyZIjQtm1bQS6XC9HR0cKcOXOEsrIyo+fJy8sT7rvvPsHLy0sICgoSXnzxRUGtVjc4vq+++kqIjY0VZDKZ0LNnT+GHH34w2m7LHCf7c8Y8SklJMfkcnTt3bnB8luZRdXW1kJSUJAQHBwtSqVTo3Lmz8NRTTwmFhYV2uz/UMGe9Fpl6zsYEAhp6LdqwYYPJ8aekpNhyO8hGzphHP/30k9C3b1/B19dX8PHxEfr06SO89957glarbXB8fE9zf858LYqLixMeffRRq8bH9zP356w5xO9nLZu9vucvX75cCAsLE7y9vYW4uDjh559/NtpeUlIiTJo0SfD19RX8/f2FqVOnChUVFY0an6V59OWXXwpdunQRZDKZoFAohBkzZgilpaU23w8iU0SCcHPRJSIiIiIiIiIiIiIH4pqRRERERERERERE5BQMRhIREREREREREZFTMBhJRERERERERERETsFgJBERERERERERETkFg5FERERERERERETkFAxGEhERERERERERkVMwGElEREREREREREROwWAkEREREREREREROQWDkUREREREREREROQUDEYSERERERERERGRUzAYSURERERERERERE7x/5Jkr8/x0DclAAAAAElFTkSuQmCC", + "image/png": "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JDLKjBQEAR06dMCLL76Iv//97wCAsrIyhIaGYuPGjXjkkUdw5swZ9OjRA0eOHMHAgQMBANu2bcP999+P/Px8dOjQweRzKZVKKJVKw/+Xl5cjPDy8xWVGkmVNzYwkIiIiIiIiIqI6zSIz0pLc3FwUFhYiMTHR8FhAQAAGDRqE9PR0AEB6ejoCAwMNgUgASExMhFgsxqFDh8yee/ny5QgICDD8hIeHO+5CyG3p19U0Rb+uJhERERERERER2Y/bBiMLCwsBAKGhoUaPh4aGGrYVFhYiJCTEaLtEIkHbtm0N+5gyb948lJWVGX4uXbpk59FTc6BvsrJwZCwCvaQA6jIiF46Mxdzh0SwpJiIiIiIiIiKys1YZbZHL5ZDL5a4eBrkB/bqar4yIMWqywnU1iYiIiIiIiIjsz20zIxUKBQCgqKjI6PGioiLDNoVCgeLiYqPtGo0G169fN+xD1BA2WSEiIiIiIiIicg63DUZGRkZCoVBg165dhsfKy8tx6NAhxMXFAQDi4uJQWlqKo0ePGvbZvXs3dDodBg0a5PQxExERERERERERkXkuTQGrrKxEVlaW4f9zc3Nx7NgxtG3bFp06dcLzzz+PZcuWISYmBpGRkViwYAE6dOhg6LjdvXt3jB49Gk899RTee+89qNVqJCcn45FHHjHbSZuIiIiIiIiIiIhcw6XByF9//RXDhg0z/P8LL7wAAJgyZQo2btyIl156CVVVVZg+fTpKS0uRkJCAbdu2wdPT03DMZ599huTkZIwYMQJisRgTJkzAmjVrnH4tREREREREREREZJlIEATB1YNwtfLycgQEBKCsrAz+/v6uHg4REREREREREVGz0tj4mtuuGUlEREREREREREQtC4ORRERERERERERE5BQMRhIREREREREREZFTuLSBjbvQL5tZXl7u4pEQERERERERERE1P/q4WkPtaRiMBFBRUQEACA8Pd/FIiIiIiIiIiIiImq+KigoEBASY3c5u2gB0Oh2uXLkCPz8/iEQiVw/H7srLyxEeHo5Lly6xWzjZhHOI7IHziJqKc4jsgfOImopziOyB84iainOI7MHe80gQBFRUVKBDhw4Qi82vDMnMSABisRhhYWGuHobD+fv780WKmoRziOyB84iainOI7IHziJqKc4jsgfOImopziOzBnvPIUkakHhvYEBERERERERERkVMwGElE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RVxcnIOvlhzB3BwyRT+P9G+CcXFxOHnypNGbXWpqKvz9/dGjRw9IJBKjOaT/0G3NHLJmfOQ6TZlHAHD69GkMGzYMU6ZMwT/+8Q+j/e0xj/Ty8/NRUlJi9NzkHpoyh/773//i+PHjhve7Dz74AADw888/Y8aMGXadQ+TemvpaZGqfNm3aQC6X8z2tlbDHHKqsrMRXX31llBUJ8P2stbDHHOL3MzI3jyIiItChQwecO3fOaP/z58+jc+fOAOrmQ2lpqdE6o7t374ZOpzMEwJs6j3x8fNC+fXvcuHED27dv5/sZ2ZeLG+i0ahUVFUJGRoaQkZEhABDefPNNISMjQ7hw4YIgCILw1VdfCWlpaUJ2drbw7bffCp07dxbGjx9v8Zww0TVt1apVwokTJ4RTp04JS5YsEaRSaYOd1XJycgRvb29hzpw5wpkzZ4T169cLHh4ewrZt2xo9fnK8ps6hrKwsYcmSJcKvv/4q5ObmCv/73/+ELl26CEOGDDHso9FohF69eglJSUnCsWPHhG3btgnBwcHCvHnzLI7twIEDgkQiEV5//XXhzJkzQkpKiiCVSoWTJ08a9rFljpP9OWMenTx5UggODhYee+wxoaCgwPBTXFxscWwNzaOKigrh73//u5Ceni7k5uYKO3fuFPr37y/ExMQItbW1DrhbZIoz5tCt0tLSGtVNuzGvRSUlJUJGRobwww8/CACETZs2CRkZGUJBQUHTbgxZxRnz6LvvvhP+/e9/CydPnhQyMzOFd955R/D29hYWLlxocWx8T2senPla9MEHHwienp4Nvgbp8f2seXDWHOL3s5bNHt/z33rrLcHf31/YvHmzkJmZKcyfP1/w9PQUsrKyDPuMHj1a6Nevn3Do0CFh//79QkxMjDBp0iSLY2vMPNq2bZvw008/CTk5OcKOHTuEPn36CIMGDRJUKpUd7xK1dgxGupD+i9StP1OmTBEEQRDefvttISwsTJBKpUKnTp2E+fPnC0ql0uI5TQUjhw0bJgQEBAienp7CoEGDhB9//LHR4+vbt68gk8mELl26CBs2bLBq/OR4TZ1DFy9eFIYMGSK0bdtWkMvlQnR0tDBnzhyhrKzM6Hny8vKE++67T/Dy8hKCgoKEF198UVCr1Q2O76uvvhJiY2MFmUwm9OzZU/jhhx+Mttsyx8n+nDGPUlJSTD5H586dGxyfpXlUXV0tJCUlCcHBwYJUKhU6d+4sPPXUU0JhYaHd7g81zFmvRaaeszGBgIZeizZs2GBy/CkpKbbcDrKRM+bRTz/9JPTt21fw9fUVfHx8hD59+gjvvfeeoNVqGxwf39PcnzNfi+Li4oRHH33UqvHx/cz9OWsO8ftZy2av7/nLly8XwsLCBG9vbyEuLk74+eefjbaXlJQIkyZNEnx9fQV/f39h6tSpQkVFRaPGZ2keffnll0KXLl0EmUwmKBQKYcaMGUJpaanN94PIFJEg3Fx0iYiIiIiIiIiIiMiBuGYkEREREREREREROQWDkUREREREREREROQUDEYSERERERERERGRUzAYSURERERERERERE7BYCQRERERERERERE5BYORRERERERERERE5BQMRhIREREREREREZFTMBhJRERERERERERETsFgJBERERERERERETkFg5FERERERERERETkFAxGEhERERERERERkVP8P4xwsROewyxZAAAAAElFTkSuQmCC", "text/plain": [ "<Figure size 1600x400 with 1 Axes>" ] @@ -964,7 +978,7 @@ " <th>1961-09</th>\n", " <td>505.795123</td>\n", " <td>544.910684</td>\n", - " <td>477.658056</td>\n", + " <td>477.658055</td>\n", " <td>573.047752</td>\n", " <td>468.520987</td>\n", " <td>582.184821</td>\n", @@ -983,9 +997,9 @@ " <td>377.660798</td>\n", " <td>420.364142</td>\n", " <td>346.942924</td>\n", - " <td>451.082016</td>\n", + " <td>451.082017</td>\n", " <td>336.967779</td>\n", - " <td>461.057161</td>\n", + " <td>461.057162</td>\n", " </tr>\n", " <tr>\n", " <th>1961-12</th>\n", @@ -993,7 +1007,7 @@ " <td>471.026993</td>\n", " <td>394.708221</td>\n", " <td>502.957142</td>\n", - " <td>384.339409</td>\n", + " <td>384.339408</td>\n", " <td>513.325954</td>\n", " </tr>\n", " </tbody>\n", @@ -1012,9 +1026,9 @@ "1961-06 530.331440 563.342111 506.585814 587.087737 \n", "1961-07 586.791063 621.954661 561.496768 647.248956 \n", "1961-08 584.116789 621.308897 557.363322 648.062363 \n", - "1961-09 505.795123 544.910684 477.658056 573.047752 \n", + "1961-09 505.795123 544.910684 477.658055 573.047752 \n", "1961-10 437.370840 478.319605 407.915090 507.775355 \n", - "1961-11 377.660798 420.364142 346.942924 451.082016 \n", + "1961-11 377.660798 420.364142 346.942924 451.082017 \n", "1961-12 426.638370 471.026993 394.708221 502.957142 \n", "\n", " \n", @@ -1030,8 +1044,8 @@ "1961-08 548.675556 656.750129 \n", "1961-09 468.520987 582.184821 \n", "1961-10 398.349800 517.340645 \n", - "1961-11 336.967779 461.057161 \n", - "1961-12 384.339409 513.325954 " + "1961-11 336.967779 461.057162 \n", + "1961-12 384.339408 513.325954 " ] }, "execution_count": 7, @@ -1153,7 +1167,7 @@ " </tr>\n", " <tr>\n", " <th>1961-06</th>\n", - " <td>515.476124</td>\n", + " <td>515.476123</td>\n", " <td>530.331440</td>\n", " <td>546.836776</td>\n", " <td>563.342111</td>\n", @@ -1161,7 +1175,7 @@ " </tr>\n", " <tr>\n", " <th>1961-07</th>\n", - " <td>570.966896</td>\n", + " <td>570.966895</td>\n", " <td>586.791063</td>\n", " <td>604.372862</td>\n", " <td>621.954661</td>\n", @@ -1219,8 +1233,8 @@ "1961-03 466.829089 478.296822 491.038306 503.779790 \n", "1961-04 450.188398 462.886144 476.994261 491.102379 \n", "1961-05 451.794965 465.613670 480.967253 496.320837 \n", - "1961-06 515.476124 530.331440 546.836776 563.342111 \n", - "1961-07 570.966896 586.791063 604.372862 621.954661 \n", + "1961-06 515.476123 530.331440 546.836776 563.342111 \n", + "1961-07 570.966895 586.791063 604.372862 621.954661 \n", "1961-08 567.379760 584.116789 602.712843 621.308897 \n", "1961-09 488.192511 505.795123 525.352904 544.910684 \n", "1961-10 418.943257 437.370840 457.845222 478.319605 \n", @@ -1270,7 +1284,7 @@ "outputs": [ { "data": { - "image/png": "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p05p6NChKi0t9cWhwQc8lU/nW7RokcaNG6fg4OBq95+bm6vmzZu7bWvevLlyc3Mr7f/OO+8oPDxct9566yUcJbzBU7kUHh6uzz//XO+++66Cg4MVFhamdevWae3atfL3969y/1XlUkFBgdv6N3v37lVYWJgCAwP10EMPadWqVerSpYsHzwQ8wdf5hIbFU/mUlJSkbdu26b333lN5ebm+//57zZ49W5Lc3ud8Nb0+VVi9erXy8vJ0zz33XOGRozbUJJ8OHz4sSXrmmWf0wAMPaN26derVq5cGDx7sWrstNzf3gqVs/P39FR0dXeXnoIrXcb9rOHydT2hYPJVPl6uq61NF2/m+/vprpaen6/7777+i/aJhoRhZR9lsNq1cuVIHDhxQdHS0QkJClJycrBEjRrit8fCb3/xGSUlJ6tatm8aPH6+lS5dq1apVOnTokCTJ6XTK4XDo1VdfVVJSkq677jq99957ysrKUnJysiQpLCzM9VPZw29Q/3kqn86VkpKi/fv3u41ezM7OdsunF1988bLiffvttzV+/PgLRqbA9zyVS0VFRZo0aZL69eunv//979q6dauuueYajRw50vUl60quTQkJCdq1a5e2b9+uyZMna+LEidq3b5/nTgQ8or7kE+oHT+XTsGHDNH/+fD300EMKDAxUp06ddOONN0qS6308kU+LFi3SiBEj1KJFiys8ctSGmuST0+mUJD344IO699571bNnTy1YsEAJCQl6++23a7wv7ncNX33JJ9QP3synrl27uvJpxIgRlxXvokWL1K1bN/3iF7+4rNejYWK4QB3Wu3dv7dq1S/n5+SotLVVMTIz69u3rNiz/fH379pUkHTx4UB06dNBVV10lSW5/IY2JiVHTpk2VnZ0tSdq1a5erzW6318KRoC7wRD6da+HChbr22mvVu3dv17YWLVq45VN0dLQkKTY2VidOnHB7/YkTJypdHPurr75SZmam3n///Us+RniHJ3Jp2bJlOnr0qFJSUlwfmpYtW6aoqCh99NFHuvPOOyu9NlWVS3a73W2EbkBAgOLj413xpqam6pVXXtFbb73lkXMAz/FlPqHh8dS97oknntDjjz+unJwcRUVF6ejRo5o5c6bat28vqfLPTjW9PknSt99+q02bNmnlypVXfMyoPRfLp8o+Z0tS586dXZ+zY2NjdfLkSbf2srIynTp1yvU5iPtd4+DLfELD44l8qok1a9a4HgZYce2p6vpU0XauwsJCLV++3DXDAKhAMbIeiIiIkCRlZWVpx44deu6556rsW3Hzqbj49OvXT5KUmZmpVq1aSZJOnTqlH3/8UXFxcZLk+gCDxuFK8qnC2bNntWLFCs2ZM8dtu7+/f6X5lJiYqM2bN2vq1KmubRs3bqx0TaNFixapd+/eVT7pD3XHleTSTz/9JKvV6rZOWsW/K/6SW1UurVmzxm1bVbl0LqfT6VpfB3WTL/IJDZcn7nUWi8U1avG9995T69at1atXL0lXfn1avHixmjVrppEjR9b8oOAzVeVT27Zt1aJFC2VmZrr1P3DggGsEUWJiovLy8rRz507XH3A/++wzOZ1OVyGc+13j4ot8QsN1JflUExU1g3MlJibqySeflMPhkM1mk/Tz9SkhIUFRUVFufT/44AOVlJRUu/QXGilfP0GnMTtz5oxJS0szaWlpRpL54x//aNLS0sy3335rjDFmxYoVJjk52Rw6dMisXr3axMXFmVtvvdX1+oMHD5rZs2ebHTt2mCNHjpiPPvrItG/f3gwYMMBtP6NGjTJdu3Y1W7duNXv37jU33XST6dKliyktLa02vorYevfubcaNG2fS0tJMRkaGq72kpMTV56qrrjL/+Z//adLS0mr85FJ4lrfyyRhjFi5caIKCgszp06drFNvWrVuNv7+/+f3vf2/2799vnn76aWOz2czevXvd+uXn55uQkBDz5ptvXv6JwBXzRi7t37/fBAYGmsmTJ5t9+/aZ9PR0c9ddd5mIiAhz/PjxKmM7fPiwCQkJMdOmTTP79+83r7/+uvHz8zPr1q1z9ZkxY4b54osvzJEjR8yePXvMjBkzjMViMRs2bKiFs4WLqcv5ZAz3uvrGW/e6efPmmT179pj09HQze/ZsY7PZ3J5kWpmaXJ+M+fmJp23atDHTp0/3zEnBZbvSfDLm5yfE2u1288EHH5isrCwza9YsExQUZA4ePOjqM3z4cNOzZ0+zfft2s2XLFtOxY0czduzYamPjflf/1OV8Mob7XX3jrXz69ttvTVpamnn22WdNWFiYa59nzpypMra8vDzTvHlzc/fdd5v09HSzfPlyExISYt56660L+vbv39/ccccdHjoraEgoRvpQcnKykXTBz8SJE40xxrzyyiumVatWxmazmTZt2phZs2aZkpIS1+uzs7PNgAEDTHR0tAkMDDTx8fFm2rRpJj8/320/+fn55r777jORkZEmOjra3HLLLSY7O/ui8VUWW1xcnKv9yJEjlfYZOHCgJ04PLpG38skYYxITE824ceMuKb4VK1aYTp06mYCAANO1a1fz6aefXtDnrbfeMsHBwSYvL+/SDh4e5a1c2rBhg+nXr5+JiIgwUVFRZtCgQSYlJaVG8V177bUmICDAtG/f3ixevNit/b777jNxcXEmICDAxMTEmMGDB/PFzIfqej5xr6tfvJVPN9xwg4mIiDBBQUGmb9++Zs2aNTWOr7rrkzHGrF+/3kgymZmZl30e4BlXmk8V5syZY1q1amVCQkJMYmKi+eqrr9za//GPf5ixY8easLAwY7fbzb333lvtF/1z4+N+V3/U9Xzifle/eCufJk6cWOl+kpOTq41v9+7dpn///iYwMNC0bNnSzJ0794I+33zzjZHEdQmVshhjzCUNpQQAAAAAAACAy8DTtAEAAAAAAAB4BcVIAAAAAAAAAF5BMRIAAAAAAACAV1CMBAAAAAAAAOAVFCMBAAAAAAAAeAXFSAAAAAAAAABeQTESAAAAAAAAgFdQjAQAAAAAAADgFRQjAQAAAAAAAHgFxUgAAAAAAAAAXkExEgAAAAAAAIBXUIwEAAAAAAAA4BX/B27z9D6aNR7nAAAAAElFTkSuQmCC", + "image/png": "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p05p6NChKi0t9cWhwQc8lU/nW7RokcaNG6fg4OBq95+bm6vmzZu7bWvevLlyc3Mr7f/OO+8oPDxct9566yUcJbzBU7kUHh6uzz//XO+++66Cg4MVFhamdevWae3atfL3969y/1XlUkFBgdv6N3v37lVYWJgCAwP10EMPadWqVerSpYsHzwQ8wdf5hIbFU/mUlJSkbdu26b333lN5ebm+//57zZ49W5Lc3ud8Nb0+VVi9erXy8vJ0zz33XOGRozbUJJ8OHz4sSXrmmWf0wAMPaN26derVq5cGDx7sWrstNzf3gqVs/P39FR0dXeXnoIrXcb9rOHydT2hYPJVPl6uq61NF2/m+/vprpaen6/7777+i/aJhoRhZR9lsNq1cuVIHDhxQdHS0QkJClJycrBEjRrit8fCb3/xGSUlJ6tatm8aPH6+lS5dq1apVOnTokCTJ6XTK4XDo1VdfVVJSkq677jq99957ysrKUnJysiQpLCzM9VPZw29Q/3kqn86VkpKi/fv3u41ezM7OdsunF1988bLiffvttzV+/PgLRqbA9zyVS0VFRZo0aZL69eunv//979q6dauuueYajRw50vUl60quTQkJCdq1a5e2b9+uyZMna+LEidq3b5/nTgQ8or7kE+oHT+XTsGHDNH/+fD300EMKDAxUp06ddOONN0qS6308kU+LFi3SiBEj1KJFiys8ctSGmuST0+mUJD344IO699571bNnTy1YsEAJCQl6++23a7wv7ncNX33JJ9QP3synrl27uvJpxIgRlxXvokWL1K1bN/3iF7+4rNejYWK4QB3Wu3dv7dq1S/n5+SotLVVMTIz69u3rNiz/fH379pUkHTx4UB06dNBVV10lSW5/IY2JiVHTpk2VnZ0tSdq1a5erzW6318KRoC7wRD6da+HChbr22mvVu3dv17YWLVq45VN0dLQkKTY2VidOnHB7/YkTJypdHPurr75SZmam3n///Us+RniHJ3Jp2bJlOnr0qFJSUlwfmpYtW6aoqCh99NFHuvPOOyu9NlWVS3a73W2EbkBAgOLj413xpqam6pVXXtFbb73lkXMAz/FlPqHh8dS97oknntDjjz+unJwcRUVF6ejRo5o5c6bat28vqfLPTjW9PknSt99+q02bNmnlypVXfMyoPRfLp8o+Z0tS586dXZ+zY2NjdfLkSbf2srIynTp1yvU5iPtd4+DLfELD44l8qok1a9a4HgZYce2p6vpU0XauwsJCLV++3DXDAKhAMbIeiIiIkCRlZWVpx44deu6556rsW3Hzqbj49OvXT5KUmZmpVq1aSZJOnTqlH3/8UXFxcZLk+gCDxuFK8qnC2bNntWLFCs2ZM8dtu7+/f6X5lJiYqM2bN2vq1KmubRs3bqx0TaNFixapd+/eVT7pD3XHleTSTz/9JKvV6rZOWsW/K/6SW1UurVmzxm1bVbl0LqfT6VpfB3WTL/IJDZcn7nUWi8U1avG9995T69at1atXL0lXfn1avHixmjVrppEjR9b8oOAzVeVT27Zt1aJFC2VmZrr1P3DggGsEUWJiovLy8rRz507XH3A/++wzOZ1OVyGc+13j4ot8QsN1JflUExU1g3MlJibqySeflMPhkM1mk/Tz9SkhIUFRUVFufT/44AOVlJRUu/QXGilfP0GnMTtz5oxJS0szaWlpRpL54x//aNLS0sy3335rjDFmxYoVJjk52Rw6dMisXr3axMXFmVtvvdX1+oMHD5rZs2ebHTt2mCNHjpiPPvrItG/f3gwYMMBtP6NGjTJdu3Y1W7duNXv37jU33XST6dKliyktLa02vorYevfubcaNG2fS0tJMRkaGq72kpMTV56qrrjL/+Z//adLS0mr85FJ4lrfyyRhjFi5caIKCgszp06drFNvWrVuNv7+/+f3vf2/2799vnn76aWOz2czevXvd+uXn55uQkBDz5ptvXv6JwBXzRi7t37/fBAYGmsmTJ5t9+/aZ9PR0c9ddd5mIiAhz/PjxKmM7fPiwCQkJMdOmTTP79+83r7/+uvHz8zPr1q1z9ZkxY4b54osvzJEjR8yePXvMjBkzjMViMRs2bKiFs4WLqcv5ZAz3uvrGW/e6efPmmT179pj09HQze/ZsY7PZ3J5kWpmaXJ+M+fmJp23atDHTp0/3zEnBZbvSfDLm5yfE2u1288EHH5isrCwza9YsExQUZA4ePOjqM3z4cNOzZ0+zfft2s2XLFtOxY0czduzYamPjflf/1OV8Mob7XX3jrXz69ttvTVpamnn22WdNWFiYa59nzpypMra8vDzTvHlzc/fdd5v09HSzfPlyExISYt56660L+vbv39/ccccdHjoraEgoRvpQcnKykXTBz8SJE40xxrzyyiumVatWxmazmTZt2phZs2aZkpIS1+uzs7PNgAEDTHR0tAkMDDTx8fFm2rRpJj8/320/+fn55r777jORkZEmOjra3HLLLSY7O/ui8VUWW1xcnKv9yJEjlfYZOHCgJ04PLpG38skYYxITE824ceMuKb4VK1aYTp06mYCAANO1a1fz6aefXtDnrbfeMsHBwSYvL+/SDh4e5a1c2rBhg+nXr5+JiIgwUVFRZtCgQSYlJaVG8V177bUmICDAtG/f3ixevNit/b777jNxcXEmICDAxMTEmMGDB/PFzIfqej5xr6tfvJVPN9xwg4mIiDBBQUGmb9++Zs2aNTWOr7rrkzHGrF+/3kgymZmZl30e4BlXmk8V5syZY1q1amVCQkJMYmKi+eqrr9za//GPf5ixY8easLAwY7fbzb333lvtF/1z4+N+V3/U9Xzifle/eCufJk6cWOl+kpOTq41v9+7dpn///iYwMNC0bNnSzJ0794I+33zzjZHEdQmVshhjzCUNpQQAAAAAAACAy8DTtAEAAAAAAAB4BcVIAAAAAAAAAF5BMRIAAAAAAACAV1CMBAAAAAAAAOAVFCMBAAAAAAAAeAXFSAAAAAAAAABeQTESAAAAAAAAgFdQjAQAAAAAAADgFRQjAQAAAAAAAHgFxUgAAAAAAAAAXkExEgAAAAAAAIBXUIwEAAAAAAAA4BX/B27z9D6aNR7nAAAAAElFTkSuQmCC", "text/plain": [ "<Figure size 1600x400 with 1 Axes>" ] @@ -1348,47 +1362,47 @@ " </tr>\n", " <tr>\n", " <th>1961-02</th>\n", - " <td>276.196509</td>\n", + " <td>276.196510</td>\n", " </tr>\n", " <tr>\n", " <th>1961-03</th>\n", - " <td>356.852968</td>\n", + " <td>356.852970</td>\n", " </tr>\n", " <tr>\n", " <th>1961-04</th>\n", - " <td>437.509428</td>\n", + " <td>437.509430</td>\n", " </tr>\n", " <tr>\n", " <th>1961-05</th>\n", - " <td>518.165887</td>\n", + " <td>518.165890</td>\n", " </tr>\n", " <tr>\n", " <th>1961-06</th>\n", - " <td>598.822347</td>\n", + " <td>598.822350</td>\n", " </tr>\n", " <tr>\n", " <th>1961-07</th>\n", - " <td>679.478807</td>\n", + " <td>679.478810</td>\n", " </tr>\n", " <tr>\n", " <th>1961-08</th>\n", - " <td>760.135266</td>\n", + " <td>760.135270</td>\n", " </tr>\n", " <tr>\n", " <th>1961-09</th>\n", - " <td>840.791726</td>\n", + " <td>840.791730</td>\n", " </tr>\n", " <tr>\n", " <th>1961-10</th>\n", - " <td>921.448185</td>\n", + " <td>921.448190</td>\n", " </tr>\n", " <tr>\n", " <th>1961-11</th>\n", - " <td>1002.104645</td>\n", + " <td>1002.104650</td>\n", " </tr>\n", " <tr>\n", " <th>1961-12</th>\n", - " <td>1082.761105</td>\n", + " <td>1082.761110</td>\n", " </tr>\n", " </tbody>\n", "</table>\n", @@ -1397,17 +1411,17 @@ "text/plain": [ " Number of airline passengers\n", "1961-01 195.540049\n", - "1961-02 276.196509\n", - "1961-03 356.852968\n", - "1961-04 437.509428\n", - "1961-05 518.165887\n", - "1961-06 598.822347\n", - "1961-07 679.478807\n", - "1961-08 760.135266\n", - "1961-09 840.791726\n", - "1961-10 921.448185\n", - "1961-11 1002.104645\n", - "1961-12 1082.761105" + "1961-02 276.196510\n", + "1961-03 356.852970\n", + "1961-04 437.509430\n", + "1961-05 518.165890\n", + "1961-06 598.822350\n", + "1961-07 679.478810\n", + "1961-08 760.135270\n", + "1961-09 840.791730\n", + "1961-10 921.448190\n", + "1961-11 1002.104650\n", + "1961-12 1082.761110" ] }, "execution_count": 10, @@ -1476,183 +1490,183 @@ " <tbody>\n", " <tr>\n", " <th>1961-01</th>\n", - " <td>292.337338</td>\n", - " <td>255.743002</td>\n", - " <td>264.805454</td>\n", - " <td>227.703065</td>\n", - " <td>146.093860</td>\n", - " <td>154.452835</td>\n", - " <td>157.976801</td>\n", - " <td>105.160769</td>\n", - " <td>78.330257</td>\n", - " <td>81.835803</td>\n", + " <td>292.337333</td>\n", + " <td>255.742991</td>\n", + " <td>264.805437</td>\n", + " <td>227.703049</td>\n", + " <td>146.093848</td>\n", + " <td>154.452828</td>\n", + " <td>157.976795</td>\n", + " <td>105.160767</td>\n", + " <td>78.330263</td>\n", + " <td>81.835807</td>\n", " <td>78.048880</td>\n", - " <td>197.364513</td>\n", + " <td>197.364510</td>\n", " </tr>\n", " <tr>\n", " <th>1961-02</th>\n", - " <td>255.743002</td>\n", - " <td>422.704619</td>\n", - " <td>402.539279</td>\n", - " <td>353.437066</td>\n", - " <td>291.205423</td>\n", - " <td>236.587887</td>\n", - " <td>227.199386</td>\n", - " <td>205.653016</td>\n", - " <td>152.067422</td>\n", - " <td>121.629136</td>\n", - " <td>156.199113</td>\n", - " <td>245.437913</td>\n", + " <td>255.742991</td>\n", + " <td>422.704601</td>\n", + " <td>402.539255</td>\n", + " <td>353.437043</td>\n", + " <td>291.205404</td>\n", + " <td>236.587874</td>\n", + " <td>227.199374</td>\n", + " <td>205.653010</td>\n", + " <td>152.067425</td>\n", + " <td>121.629138</td>\n", + " <td>156.199110</td>\n", + " <td>245.437907</td>\n", " </tr>\n", " <tr>\n", " <th>1961-03</th>\n", - " <td>264.805454</td>\n", - " <td>402.539279</td>\n", - " <td>588.085358</td>\n", - " <td>506.095484</td>\n", - " <td>426.997535</td>\n", - " <td>394.503941</td>\n", - " <td>311.457854</td>\n", - " <td>282.072157</td>\n", + " <td>264.805437</td>\n", + " <td>402.539255</td>\n", + " <td>588.085328</td>\n", + " <td>506.095455</td>\n", + " <td>426.997512</td>\n", + " <td>394.503923</td>\n", + " <td>311.457837</td>\n", + " <td>282.072145</td>\n", " <td>243.688600</td>\n", - " <td>185.938841</td>\n", - " <td>185.070365</td>\n", - " <td>305.461220</td>\n", + " <td>185.938840</td>\n", + " <td>185.070360</td>\n", + " <td>305.461211</td>\n", " </tr>\n", " <tr>\n", " <th>1961-04</th>\n", - " <td>227.703065</td>\n", - " <td>353.437066</td>\n", - " <td>506.095484</td>\n", - " <td>634.350469</td>\n", - " <td>526.180900</td>\n", - " <td>482.653111</td>\n", - " <td>422.777319</td>\n", - " <td>323.453753</td>\n", - " <td>280.749314</td>\n", - " <td>242.065791</td>\n", - " <td>211.397170</td>\n", - " <td>294.971041</td>\n", + " <td>227.703049</td>\n", + " <td>353.437043</td>\n", + " <td>506.095455</td>\n", + " <td>634.350443</td>\n", + " <td>526.180879</td>\n", + " <td>482.653094</td>\n", + " <td>422.777303</td>\n", + " <td>323.453741</td>\n", + " <td>280.749312</td>\n", + " <td>242.065788</td>\n", + " <td>211.397164</td>\n", + " <td>294.971031</td>\n", " </tr>\n", " <tr>\n", " <th>1961-05</th>\n", - " <td>146.093860</td>\n", - " <td>291.205423</td>\n", - " <td>426.997535</td>\n", - " <td>526.180900</td>\n", - " <td>628.659359</td>\n", - " <td>570.277532</td>\n", - " <td>499.460195</td>\n", - " <td>419.166450</td>\n", + " <td>146.093848</td>\n", + " <td>291.205404</td>\n", + " <td>426.997512</td>\n", + " <td>526.180879</td>\n", + " <td>628.659343</td>\n", + " <td>570.277520</td>\n", + " <td>499.460184</td>\n", + " <td>419.166444</td>\n", " <td>325.582777</td>\n", - " <td>281.608607</td>\n", - " <td>269.847443</td>\n", - " <td>318.534683</td>\n", + " <td>281.608605</td>\n", + " <td>269.847439</td>\n", + " <td>318.534675</td>\n", " </tr>\n", " <tr>\n", " <th>1961-06</th>\n", - " <td>154.452835</td>\n", - " <td>236.587887</td>\n", - " <td>394.503941</td>\n", - " <td>482.653111</td>\n", - " <td>570.277532</td>\n", - " <td>728.132505</td>\n", - " <td>629.184846</td>\n", - " <td>527.767036</td>\n", - " <td>444.690514</td>\n", - " <td>330.643653</td>\n", - " <td>313.248427</td>\n", - " <td>382.803221</td>\n", + " <td>154.452828</td>\n", + " <td>236.587874</td>\n", + " <td>394.503923</td>\n", + " <td>482.653094</td>\n", + " <td>570.277520</td>\n", + " <td>728.132497</td>\n", + " <td>629.184840</td>\n", + " <td>527.767034</td>\n", + " <td>444.690518</td>\n", + " <td>330.643655</td>\n", + " <td>313.248426</td>\n", + " <td>382.803216</td>\n", " </tr>\n", " <tr>\n", " <th>1961-07</th>\n", - " <td>157.976801</td>\n", - " <td>227.199386</td>\n", - " <td>311.457854</td>\n", - " <td>422.777319</td>\n", - " <td>499.460195</td>\n", - " <td>629.184846</td>\n", - " <td>753.550007</td>\n", + " <td>157.976795</td>\n", + " <td>227.199374</td>\n", + " <td>311.457837</td>\n", + " <td>422.777303</td>\n", + " <td>499.460184</td>\n", + " <td>629.184840</td>\n", + " <td>753.550004</td>\n", " <td>629.138725</td>\n", - " <td>536.407564</td>\n", - " <td>441.998603</td>\n", - " <td>352.570968</td>\n", - " <td>415.110922</td>\n", + " <td>536.407567</td>\n", + " <td>441.998605</td>\n", + " <td>352.570966</td>\n", + " <td>415.110916</td>\n", " </tr>\n", " <tr>\n", " <th>1961-08</th>\n", - " <td>105.160769</td>\n", - " <td>205.653016</td>\n", - " <td>282.072157</td>\n", - " <td>323.453753</td>\n", - " <td>419.166450</td>\n", - " <td>527.767036</td>\n", + " <td>105.160767</td>\n", + " <td>205.653010</td>\n", + " <td>282.072145</td>\n", + " <td>323.453741</td>\n", + " <td>419.166444</td>\n", + " <td>527.767034</td>\n", " <td>629.138725</td>\n", - " <td>729.423302</td>\n", - " <td>615.142484</td>\n", - " <td>506.155610</td>\n", - " <td>439.994837</td>\n", - " <td>430.992295</td>\n", + " <td>729.423304</td>\n", + " <td>615.142491</td>\n", + " <td>506.155614</td>\n", + " <td>439.994838</td>\n", + " <td>430.992291</td>\n", " </tr>\n", " <tr>\n", " <th>1961-09</th>\n", - " <td>78.330257</td>\n", - " <td>152.067422</td>\n", + " <td>78.330263</td>\n", + " <td>152.067425</td>\n", " <td>243.688600</td>\n", - " <td>280.749314</td>\n", + " <td>280.749312</td>\n", " <td>325.582777</td>\n", - " <td>444.690514</td>\n", - " <td>536.407564</td>\n", - " <td>615.142484</td>\n", - " <td>744.225555</td>\n", - " <td>609.227136</td>\n", - " <td>527.489574</td>\n", - " <td>546.637590</td>\n", + " <td>444.690518</td>\n", + " <td>536.407567</td>\n", + " <td>615.142491</td>\n", + " <td>744.225561</td>\n", + " <td>609.227140</td>\n", + " <td>527.489573</td>\n", + " <td>546.637585</td>\n", " </tr>\n", " <tr>\n", " <th>1961-10</th>\n", - " <td>81.835803</td>\n", - " <td>121.629136</td>\n", - " <td>185.938841</td>\n", - " <td>242.065791</td>\n", - " <td>281.608607</td>\n", - " <td>330.643653</td>\n", - " <td>441.998603</td>\n", - " <td>506.155610</td>\n", - " <td>609.227136</td>\n", - " <td>697.805477</td>\n", - " <td>590.542045</td>\n", - " <td>604.681136</td>\n", + " <td>81.835807</td>\n", + " <td>121.629138</td>\n", + " <td>185.938840</td>\n", + " <td>242.065788</td>\n", + " <td>281.608605</td>\n", + " <td>330.643655</td>\n", + " <td>441.998605</td>\n", + " <td>506.155614</td>\n", + " <td>609.227140</td>\n", + " <td>697.805479</td>\n", + " <td>590.542043</td>\n", + " <td>604.681130</td>\n", " </tr>\n", " <tr>\n", " <th>1961-11</th>\n", " <td>78.048880</td>\n", - " <td>156.199113</td>\n", - " <td>185.070365</td>\n", - " <td>211.397170</td>\n", - " <td>269.847443</td>\n", - " <td>313.248427</td>\n", - " <td>352.570968</td>\n", - " <td>439.994837</td>\n", - " <td>527.489574</td>\n", - " <td>590.542045</td>\n", - " <td>706.960631</td>\n", - " <td>698.982589</td>\n", + " <td>156.199110</td>\n", + " <td>185.070360</td>\n", + " <td>211.397164</td>\n", + " <td>269.847439</td>\n", + " <td>313.248426</td>\n", + " <td>352.570966</td>\n", + " <td>439.994838</td>\n", + " <td>527.489573</td>\n", + " <td>590.542043</td>\n", + " <td>706.960626</td>\n", + " <td>698.982580</td>\n", " </tr>\n", " <tr>\n", " <th>1961-12</th>\n", - " <td>197.364513</td>\n", - " <td>245.437913</td>\n", - " <td>305.461220</td>\n", - " <td>294.971041</td>\n", - " <td>318.534683</td>\n", - " <td>382.803221</td>\n", - " <td>415.110922</td>\n", - " <td>430.992295</td>\n", - " <td>546.637590</td>\n", - " <td>604.681136</td>\n", - " <td>698.982589</td>\n", - " <td>913.698243</td>\n", + " <td>197.364510</td>\n", + " <td>245.437907</td>\n", + " <td>305.461211</td>\n", + " <td>294.971031</td>\n", + " <td>318.534675</td>\n", + " <td>382.803216</td>\n", + " <td>415.110916</td>\n", + " <td>430.992291</td>\n", + " <td>546.637585</td>\n", + " <td>604.681130</td>\n", + " <td>698.982580</td>\n", + " <td>913.698229</td>\n", " </tr>\n", " </tbody>\n", "</table>\n", @@ -1660,46 +1674,46 @@ ], "text/plain": [ " 1961-01 1961-02 1961-03 1961-04 1961-05 \\\n", - "1961-01 292.337338 255.743002 264.805454 227.703065 146.093860 \n", - "1961-02 255.743002 422.704619 402.539279 353.437066 291.205423 \n", - "1961-03 264.805454 402.539279 588.085358 506.095484 426.997535 \n", - "1961-04 227.703065 353.437066 506.095484 634.350469 526.180900 \n", - "1961-05 146.093860 291.205423 426.997535 526.180900 628.659359 \n", - "1961-06 154.452835 236.587887 394.503941 482.653111 570.277532 \n", - "1961-07 157.976801 227.199386 311.457854 422.777319 499.460195 \n", - "1961-08 105.160769 205.653016 282.072157 323.453753 419.166450 \n", - "1961-09 78.330257 152.067422 243.688600 280.749314 325.582777 \n", - "1961-10 81.835803 121.629136 185.938841 242.065791 281.608607 \n", - "1961-11 78.048880 156.199113 185.070365 211.397170 269.847443 \n", - "1961-12 197.364513 245.437913 305.461220 294.971041 318.534683 \n", + "1961-01 292.337333 255.742991 264.805437 227.703049 146.093848 \n", + "1961-02 255.742991 422.704601 402.539255 353.437043 291.205404 \n", + "1961-03 264.805437 402.539255 588.085328 506.095455 426.997512 \n", + "1961-04 227.703049 353.437043 506.095455 634.350443 526.180879 \n", + "1961-05 146.093848 291.205404 426.997512 526.180879 628.659343 \n", + "1961-06 154.452828 236.587874 394.503923 482.653094 570.277520 \n", + "1961-07 157.976795 227.199374 311.457837 422.777303 499.460184 \n", + "1961-08 105.160767 205.653010 282.072145 323.453741 419.166444 \n", + "1961-09 78.330263 152.067425 243.688600 280.749312 325.582777 \n", + "1961-10 81.835807 121.629138 185.938840 242.065788 281.608605 \n", + "1961-11 78.048880 156.199110 185.070360 211.397164 269.847439 \n", + "1961-12 197.364510 245.437907 305.461211 294.971031 318.534675 \n", "\n", " 1961-06 1961-07 1961-08 1961-09 1961-10 \\\n", - "1961-01 154.452835 157.976801 105.160769 78.330257 81.835803 \n", - "1961-02 236.587887 227.199386 205.653016 152.067422 121.629136 \n", - "1961-03 394.503941 311.457854 282.072157 243.688600 185.938841 \n", - "1961-04 482.653111 422.777319 323.453753 280.749314 242.065791 \n", - "1961-05 570.277532 499.460195 419.166450 325.582777 281.608607 \n", - "1961-06 728.132505 629.184846 527.767036 444.690514 330.643653 \n", - "1961-07 629.184846 753.550007 629.138725 536.407564 441.998603 \n", - "1961-08 527.767036 629.138725 729.423302 615.142484 506.155610 \n", - "1961-09 444.690514 536.407564 615.142484 744.225555 609.227136 \n", - "1961-10 330.643653 441.998603 506.155610 609.227136 697.805477 \n", - "1961-11 313.248427 352.570968 439.994837 527.489574 590.542045 \n", - "1961-12 382.803221 415.110922 430.992295 546.637590 604.681136 \n", + "1961-01 154.452828 157.976795 105.160767 78.330263 81.835807 \n", + "1961-02 236.587874 227.199374 205.653010 152.067425 121.629138 \n", + "1961-03 394.503923 311.457837 282.072145 243.688600 185.938840 \n", + "1961-04 482.653094 422.777303 323.453741 280.749312 242.065788 \n", + "1961-05 570.277520 499.460184 419.166444 325.582777 281.608605 \n", + "1961-06 728.132497 629.184840 527.767034 444.690518 330.643655 \n", + "1961-07 629.184840 753.550004 629.138725 536.407567 441.998605 \n", + "1961-08 527.767034 629.138725 729.423304 615.142491 506.155614 \n", + "1961-09 444.690518 536.407567 615.142491 744.225561 609.227140 \n", + "1961-10 330.643655 441.998605 506.155614 609.227140 697.805479 \n", + "1961-11 313.248426 352.570966 439.994838 527.489573 590.542043 \n", + "1961-12 382.803216 415.110916 430.992291 546.637585 604.681130 \n", "\n", " 1961-11 1961-12 \n", - "1961-01 78.048880 197.364513 \n", - "1961-02 156.199113 245.437913 \n", - "1961-03 185.070365 305.461220 \n", - "1961-04 211.397170 294.971041 \n", - "1961-05 269.847443 318.534683 \n", - "1961-06 313.248427 382.803221 \n", - "1961-07 352.570968 415.110922 \n", - "1961-08 439.994837 430.992295 \n", - "1961-09 527.489574 546.637590 \n", - "1961-10 590.542045 604.681136 \n", - "1961-11 706.960631 698.982589 \n", - "1961-12 698.982589 913.698243 " + "1961-01 78.048880 197.364510 \n", + "1961-02 156.199110 245.437907 \n", + "1961-03 185.070360 305.461211 \n", + "1961-04 211.397164 294.971031 \n", + "1961-05 269.847439 318.534675 \n", + "1961-06 313.248426 382.803216 \n", + "1961-07 352.570966 415.110916 \n", + "1961-08 439.994838 430.992291 \n", + "1961-09 527.489573 546.637585 \n", + "1961-10 590.542043 604.681130 \n", + "1961-11 706.960626 698.982580 \n", + "1961-12 698.982580 913.698229 " ] }, "execution_count": 11, @@ -1748,7 +1762,7 @@ { "data": { "text/html": [ - "<style>#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 {color: black;background-color: white;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 pre{padding: 0;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-toggleable {background-color: white;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 label.sk-toggleable__label-arrow:before {content: \"βΈ\";float: left;margin-right: 0.25em;color: #696969;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"βΎ\";}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-estimator:hover {background-color: #d4ebff;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 2em;bottom: 0;left: 50%;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-item {z-index: 1;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-parallel::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 2em;bottom: 0;left: 50%;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-parallel-item {display: flex;flex-direction: column;position: relative;background-color: white;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-parallel-item:only-child::after {width: 0;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;position: relative;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-label label {font-family: monospace;font-weight: bold;background-color: white;display: inline-block;line-height: 1.2em;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-label-container {position: relative;z-index: 2;text-align: center;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409 div.sk-text-repr-fallback {display: none;}</style><div id='sk-b9a6a3c0-6c86-4f30-b3b2-b0775dd73409' class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>Normal(columns=Index(['Number of airline passengers'], dtype='object'),\n", + "<style>#sk-8125c019-59cd-4edc-b962-4062375337e4 {color: black;background-color: white;}#sk-8125c019-59cd-4edc-b962-4062375337e4 pre{padding: 0;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-toggleable {background-color: white;}#sk-8125c019-59cd-4edc-b962-4062375337e4 label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-8125c019-59cd-4edc-b962-4062375337e4 label.sk-toggleable__label-arrow:before {content: \"βΈ\";float: left;margin-right: 0.25em;color: #696969;}#sk-8125c019-59cd-4edc-b962-4062375337e4 label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-8125c019-59cd-4edc-b962-4062375337e4 input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-8125c019-59cd-4edc-b962-4062375337e4 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"βΎ\";}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-8125c019-59cd-4edc-b962-4062375337e4 input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-estimator:hover {background-color: #d4ebff;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 2em;bottom: 0;left: 50%;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-item {z-index: 1;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-parallel::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 2em;bottom: 0;left: 50%;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-parallel-item {display: flex;flex-direction: column;position: relative;background-color: white;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-parallel-item:only-child::after {width: 0;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;position: relative;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-label label {font-family: monospace;font-weight: bold;background-color: white;display: inline-block;line-height: 1.2em;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-label-container {position: relative;z-index: 2;text-align: center;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-8125c019-59cd-4edc-b962-4062375337e4 div.sk-text-repr-fallback {display: none;}</style><div id='sk-8125c019-59cd-4edc-b962-4062375337e4' class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>Normal(columns=Index(['Number of airline passengers'], dtype='object'),\n", " index=PeriodIndex(['1961-01', '1961-02', '1961-03', '1961-04', '1961-05', '1961-06',\n", " '1961-07', '1961-08', '1961-09', '1961-10', '1961-11', '1961-12'],\n", " dtype='period[M]'),\n", @@ -1776,8 +1790,8 @@ "1961-08 27.570551\n", "1961-09 28.996409\n", "1961-10 30.355365\n", - "1961-11 31.656036\n", - "1961-12 32.905336)</pre><b>Please rerun this cell to show the HTML repr or trust the notebook.</b></div><div class=\"sk-container\" hidden><div class='sk-item'><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('bb0b02b9-326f-47df-87cb-c88bfdc5a336') type=\"checkbox\" checked><label for=UUID('bb0b02b9-326f-47df-87cb-c88bfdc5a336') class='sk-toggleable__label sk-toggleable__label-arrow'>Normal</label><div class=\"sk-toggleable__content\"><pre>Normal(columns=Index(['Number of airline passengers'], dtype='object'),\n", + "1961-11 31.656037\n", + "1961-12 32.905336)</pre><b>Please rerun this cell to show the HTML repr or trust the notebook.</b></div><div class=\"sk-container\" hidden><div class='sk-item'><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('7e30e48d-3be6-4e33-a8b5-ba4ff8e29a87') type=\"checkbox\" checked><label for=UUID('7e30e48d-3be6-4e33-a8b5-ba4ff8e29a87') class='sk-toggleable__label sk-toggleable__label-arrow'>Normal</label><div class=\"sk-toggleable__content\"><pre>Normal(columns=Index(['Number of airline passengers'], dtype='object'),\n", " index=PeriodIndex(['1961-01', '1961-02', '1961-03', '1961-04', '1961-05', '1961-06',\n", " '1961-07', '1961-08', '1961-09', '1961-10', '1961-11', '1961-12'],\n", " dtype='period[M]'),\n", @@ -1805,7 +1819,7 @@ "1961-08 27.570551\n", "1961-09 28.996409\n", "1961-10 30.355365\n", - "1961-11 31.656036\n", + "1961-11 31.656037\n", "1961-12 32.905336)</pre></div></div></div></div></div>" ], "text/plain": [ @@ -1837,7 +1851,7 @@ "1961-08 27.570551\n", "1961-09 28.996409\n", "1961-10 30.355365\n", - "1961-11 31.656036\n", + "1961-11 31.656037\n", "1961-12 32.905336)" ] }, @@ -1914,12 +1928,12 @@ " </tr>\n", " <tr>\n", " <th>1961-06</th>\n", - " <td>515.476124</td>\n", + " <td>515.476123</td>\n", " <td>578.197428</td>\n", " </tr>\n", " <tr>\n", " <th>1961-07</th>\n", - " <td>570.966896</td>\n", + " <td>570.966895</td>\n", " <td>637.778829</td>\n", " </tr>\n", " <tr>\n", @@ -1959,8 +1973,8 @@ "1961-03 466.829089 515.247523\n", "1961-04 450.188398 503.800124\n", "1961-05 451.794965 510.139542\n", - "1961-06 515.476124 578.197428\n", - "1961-07 570.966896 637.778829\n", + "1961-06 515.476123 578.197428\n", + "1961-07 570.966895 637.778829\n", "1961-08 567.379760 638.045925\n", "1961-09 488.192511 562.513297\n", "1961-10 418.943257 496.747188\n", @@ -2067,63 +2081,63 @@ " <tbody>\n", " <tr>\n", " <th>1951-01</th>\n", - " <td>125.707998</td>\n", - " <td>141.744251</td>\n", + " <td>125.708002</td>\n", + " <td>141.744261</td>\n", " </tr>\n", " <tr>\n", " <th>1951-02</th>\n", - " <td>135.554586</td>\n", - " <td>154.422381</td>\n", + " <td>135.554588</td>\n", + " <td>154.422393</td>\n", " </tr>\n", " <tr>\n", " <th>1951-03</th>\n", - " <td>149.921348</td>\n", - " <td>171.247998</td>\n", + " <td>149.921349</td>\n", + " <td>171.248013</td>\n", " </tr>\n", " <tr>\n", " <th>1951-04</th>\n", - " <td>140.807417</td>\n", - " <td>164.337362</td>\n", + " <td>140.807416</td>\n", + " <td>164.337377</td>\n", " </tr>\n", " <tr>\n", " <th>1951-05</th>\n", - " <td>127.941097</td>\n", - " <td>153.484993</td>\n", + " <td>127.941095</td>\n", + " <td>153.485009</td>\n", " </tr>\n", " <tr>\n", " <th>1951-06</th>\n", - " <td>152.968277</td>\n", - " <td>180.378548</td>\n", + " <td>152.968275</td>\n", + " <td>180.378566</td>\n", " </tr>\n", " <tr>\n", " <th>1951-07</th>\n", - " <td>167.193935</td>\n", - " <td>196.351356</td>\n", + " <td>167.193932</td>\n", + " <td>196.351377</td>\n", " </tr>\n", " <tr>\n", " <th>1951-08</th>\n", - " <td>166.316512</td>\n", - " <td>197.122153</td>\n", + " <td>166.316508</td>\n", + " <td>197.122174</td>\n", " </tr>\n", " <tr>\n", " <th>1951-09</th>\n", - " <td>150.425516</td>\n", - " <td>182.795561</td>\n", + " <td>150.425511</td>\n", + " <td>182.795583</td>\n", " </tr>\n", " <tr>\n", " <th>1951-10</th>\n", - " <td>128.623033</td>\n", - " <td>162.485285</td>\n", + " <td>128.623026</td>\n", + " <td>162.485306</td>\n", " </tr>\n", " <tr>\n", " <th>1951-11</th>\n", - " <td>109.567283</td>\n", - " <td>144.858705</td>\n", + " <td>109.567274</td>\n", + " <td>144.858726</td>\n", " </tr>\n", " <tr>\n", " <th>1951-12</th>\n", - " <td>125.641292</td>\n", - " <td>162.306217</td>\n", + " <td>125.641283</td>\n", + " <td>162.306240</td>\n", " </tr>\n", " </tbody>\n", "</table>\n", @@ -2133,18 +2147,18 @@ " Number of airline passengers \n", " 0.9 \n", " lower upper\n", - "1951-01 125.707998 141.744251\n", - "1951-02 135.554586 154.422381\n", - "1951-03 149.921348 171.247998\n", - "1951-04 140.807417 164.337362\n", - "1951-05 127.941097 153.484993\n", - "1951-06 152.968277 180.378548\n", - "1951-07 167.193935 196.351356\n", - "1951-08 166.316512 197.122153\n", - "1951-09 150.425516 182.795561\n", - "1951-10 128.623033 162.485285\n", - "1951-11 109.567283 144.858705\n", - "1951-12 125.641292 162.306217" + "1951-01 125.708002 141.744261\n", + "1951-02 135.554588 154.422393\n", + "1951-03 149.921349 171.248013\n", + "1951-04 140.807416 164.337377\n", + "1951-05 127.941095 153.485009\n", + "1951-06 152.968275 180.378566\n", + "1951-07 167.193932 196.351377\n", + "1951-08 166.316508 197.122174\n", + "1951-09 150.425511 182.795583\n", + "1951-10 128.623026 162.485306\n", + "1951-11 109.567274 144.858726\n", + "1951-12 125.641283 162.306240" ] }, "execution_count": 15, @@ -2206,63 +2220,63 @@ " <tbody>\n", " <tr>\n", " <th>1951-02</th>\n", - " <td>136.659398</td>\n", - " <td>152.695651</td>\n", + " <td>136.659402</td>\n", + " <td>152.695661</td>\n", " </tr>\n", " <tr>\n", " <th>1951-03</th>\n", - " <td>150.894540</td>\n", - " <td>169.762336</td>\n", + " <td>150.894543</td>\n", + " <td>169.762349</td>\n", " </tr>\n", " <tr>\n", " <th>1951-04</th>\n", - " <td>141.748826</td>\n", - " <td>163.075476</td>\n", + " <td>141.748827</td>\n", + " <td>163.075491</td>\n", " </tr>\n", " <tr>\n", " <th>1951-05</th>\n", - " <td>128.876521</td>\n", - " <td>152.406466</td>\n", + " <td>128.876520</td>\n", + " <td>152.406481</td>\n", " </tr>\n", " <tr>\n", " <th>1951-06</th>\n", - " <td>153.906406</td>\n", - " <td>179.450302</td>\n", + " <td>153.906405</td>\n", + " <td>179.450320</td>\n", " </tr>\n", " <tr>\n", " <th>1951-07</th>\n", - " <td>168.170069</td>\n", - " <td>195.580339</td>\n", + " <td>168.170068</td>\n", + " <td>195.580359</td>\n", " </tr>\n", " <tr>\n", " <th>1951-08</th>\n", - " <td>167.339648</td>\n", - " <td>196.497069</td>\n", + " <td>167.339646</td>\n", + " <td>196.497090</td>\n", " </tr>\n", " <tr>\n", " <th>1951-09</th>\n", - " <td>151.478088</td>\n", - " <td>182.283729</td>\n", + " <td>151.478084</td>\n", + " <td>182.283750</td>\n", " </tr>\n", " <tr>\n", " <th>1951-10</th>\n", - " <td>129.681615</td>\n", - " <td>162.051660</td>\n", + " <td>129.681609</td>\n", + " <td>162.051681</td>\n", " </tr>\n", " <tr>\n", " <th>1951-11</th>\n", - " <td>110.621201</td>\n", - " <td>144.483453</td>\n", + " <td>110.621193</td>\n", + " <td>144.483474</td>\n", " </tr>\n", " <tr>\n", " <th>1951-12</th>\n", - " <td>126.786551</td>\n", - " <td>162.077973</td>\n", + " <td>126.786543</td>\n", + " <td>162.077995</td>\n", " </tr>\n", " <tr>\n", " <th>1952-01</th>\n", - " <td>121.345120</td>\n", - " <td>158.010045</td>\n", + " <td>121.345111</td>\n", + " <td>158.010067</td>\n", " </tr>\n", " </tbody>\n", "</table>\n", @@ -2272,18 +2286,18 @@ " Number of airline passengers \n", " 0.9 \n", " lower upper\n", - "1951-02 136.659398 152.695651\n", - "1951-03 150.894540 169.762336\n", - "1951-04 141.748826 163.075476\n", - "1951-05 128.876521 152.406466\n", - "1951-06 153.906406 179.450302\n", - "1951-07 168.170069 195.580339\n", - "1951-08 167.339648 196.497069\n", - "1951-09 151.478088 182.283729\n", - "1951-10 129.681615 162.051660\n", - "1951-11 110.621201 144.483453\n", - "1951-12 126.786551 162.077973\n", - "1952-01 121.345120 158.010045" + "1951-02 136.659402 152.695661\n", + "1951-03 150.894543 169.762349\n", + "1951-04 141.748827 163.075491\n", + "1951-05 128.876520 152.406481\n", + "1951-06 153.906405 179.450320\n", + "1951-07 168.170068 195.580359\n", + "1951-08 167.339646 196.497090\n", + "1951-09 151.478084 182.283750\n", + "1951-10 129.681609 162.051681\n", + "1951-11 110.621193 144.483474\n", + "1951-12 126.786543 162.077995\n", + "1952-01 121.345111 158.010067" ] }, "execution_count": 16, @@ -2352,63 +2366,63 @@ " <tbody>\n", " <tr>\n", " <th>1951-03</th>\n", - " <td>151.754366</td>\n", - " <td>167.790619</td>\n", + " <td>151.754371</td>\n", + " <td>167.790630</td>\n", " </tr>\n", " <tr>\n", " <th>1951-04</th>\n", - " <td>142.481687</td>\n", - " <td>161.349482</td>\n", + " <td>142.481690</td>\n", + " <td>161.349495</td>\n", " </tr>\n", " <tr>\n", " <th>1951-05</th>\n", " <td>129.549186</td>\n", - " <td>150.875836</td>\n", + " <td>150.875849</td>\n", " </tr>\n", " <tr>\n", " <th>1951-06</th>\n", " <td>154.439360</td>\n", - " <td>177.969305</td>\n", + " <td>177.969321</td>\n", " </tr>\n", " <tr>\n", " <th>1951-07</th>\n", " <td>168.623239</td>\n", - " <td>194.167135</td>\n", + " <td>194.167153</td>\n", " </tr>\n", " <tr>\n", " <th>1951-08</th>\n", - " <td>167.770039</td>\n", - " <td>195.180310</td>\n", + " <td>167.770038</td>\n", + " <td>195.180329</td>\n", " </tr>\n", " <tr>\n", " <th>1951-09</th>\n", - " <td>151.929281</td>\n", - " <td>181.086702</td>\n", + " <td>151.929278</td>\n", + " <td>181.086722</td>\n", " </tr>\n", " <tr>\n", " <th>1951-10</th>\n", - " <td>130.167033</td>\n", - " <td>160.972675</td>\n", + " <td>130.167028</td>\n", + " <td>160.972694</td>\n", " </tr>\n", " <tr>\n", " <th>1951-11</th>\n", - " <td>111.133102</td>\n", - " <td>143.503147</td>\n", + " <td>111.133094</td>\n", + " <td>143.503166</td>\n", " </tr>\n", " <tr>\n", " <th>1951-12</th>\n", - " <td>127.264390</td>\n", - " <td>161.126643</td>\n", + " <td>127.264383</td>\n", + " <td>161.126664</td>\n", " </tr>\n", " <tr>\n", " <th>1952-01</th>\n", - " <td>121.830227</td>\n", - " <td>157.121649</td>\n", + " <td>121.830219</td>\n", + " <td>157.121670</td>\n", " </tr>\n", " <tr>\n", " <th>1952-02</th>\n", - " <td>132.976436</td>\n", - " <td>169.641361</td>\n", + " <td>132.976427</td>\n", + " <td>169.641384</td>\n", " </tr>\n", " </tbody>\n", "</table>\n", @@ -2418,18 +2432,18 @@ " Number of airline passengers \n", " 0.9 \n", " lower upper\n", - "1951-03 151.754366 167.790619\n", - "1951-04 142.481687 161.349482\n", - "1951-05 129.549186 150.875836\n", - "1951-06 154.439360 177.969305\n", - "1951-07 168.623239 194.167135\n", - "1951-08 167.770039 195.180310\n", - "1951-09 151.929281 181.086702\n", - "1951-10 130.167033 160.972675\n", - "1951-11 111.133102 143.503147\n", - "1951-12 127.264390 161.126643\n", - "1952-01 121.830227 157.121649\n", - "1952-02 132.976436 169.641361" + "1951-03 151.754371 167.790630\n", + "1951-04 142.481690 161.349495\n", + "1951-05 129.549186 150.875849\n", + "1951-06 154.439360 177.969321\n", + "1951-07 168.623239 194.167153\n", + "1951-08 167.770038 195.180329\n", + "1951-09 151.929278 181.086722\n", + "1951-10 130.167028 160.972694\n", + "1951-11 111.133094 143.503166\n", + "1951-12 127.264383 161.126664\n", + "1952-01 121.830219 157.121670\n", + "1952-02 132.976427 169.641384" ] }, "execution_count": 17, @@ -2489,63 +2503,63 @@ " <tbody>\n", " <tr>\n", " <th>1951-04</th>\n", - " <td>143.421741</td>\n", - " <td>159.457994</td>\n", + " <td>143.421746</td>\n", + " <td>159.458004</td>\n", " </tr>\n", " <tr>\n", " <th>1951-05</th>\n", - " <td>130.401488</td>\n", - " <td>149.269284</td>\n", + " <td>130.401490</td>\n", + " <td>149.269296</td>\n", " </tr>\n", " <tr>\n", " <th>1951-06</th>\n", - " <td>155.166803</td>\n", - " <td>176.493453</td>\n", + " <td>155.166804</td>\n", + " <td>176.493468</td>\n", " </tr>\n", " <tr>\n", " <th>1951-07</th>\n", - " <td>169.300650</td>\n", - " <td>192.830595</td>\n", + " <td>169.300651</td>\n", + " <td>192.830612</td>\n", " </tr>\n", " <tr>\n", " <th>1951-08</th>\n", " <td>168.451755</td>\n", - " <td>193.995651</td>\n", + " <td>193.995669</td>\n", " </tr>\n", " <tr>\n", " <th>1951-09</th>\n", - " <td>152.643333</td>\n", - " <td>180.053604</td>\n", + " <td>152.643331</td>\n", + " <td>180.053622</td>\n", " </tr>\n", " <tr>\n", " <th>1951-10</th>\n", - " <td>130.913435</td>\n", - " <td>160.070856</td>\n", + " <td>130.913430</td>\n", + " <td>160.070874</td>\n", " </tr>\n", " <tr>\n", " <th>1951-11</th>\n", - " <td>111.900919</td>\n", - " <td>142.706560</td>\n", + " <td>111.900912</td>\n", + " <td>142.706578</td>\n", " </tr>\n", " <tr>\n", " <th>1951-12</th>\n", - " <td>128.054402</td>\n", - " <td>160.424448</td>\n", + " <td>128.054396</td>\n", + " <td>160.424468</td>\n", " </tr>\n", " <tr>\n", " <th>1952-01</th>\n", - " <td>122.645052</td>\n", - " <td>156.507304</td>\n", + " <td>122.645044</td>\n", + " <td>156.507325</td>\n", " </tr>\n", " <tr>\n", " <th>1952-02</th>\n", - " <td>133.834107</td>\n", - " <td>169.125529</td>\n", + " <td>133.834100</td>\n", + " <td>169.125551</td>\n", " </tr>\n", " <tr>\n", " <th>1952-03</th>\n", - " <td>149.605277</td>\n", - " <td>186.270202</td>\n", + " <td>149.605269</td>\n", + " <td>186.270225</td>\n", " </tr>\n", " </tbody>\n", "</table>\n", @@ -2555,18 +2569,18 @@ " Number of airline passengers \n", " 0.9 \n", " lower upper\n", - "1951-04 143.421741 159.457994\n", - "1951-05 130.401488 149.269284\n", - "1951-06 155.166803 176.493453\n", - "1951-07 169.300650 192.830595\n", - "1951-08 168.451755 193.995651\n", - "1951-09 152.643333 180.053604\n", - "1951-10 130.913435 160.070856\n", - "1951-11 111.900919 142.706560\n", - "1951-12 128.054402 160.424448\n", - "1952-01 122.645052 156.507304\n", - "1952-02 133.834107 169.125529\n", - "1952-03 149.605277 186.270202" + "1951-04 143.421746 159.458004\n", + "1951-05 130.401490 149.269296\n", + "1951-06 155.166804 176.493468\n", + "1951-07 169.300651 192.830612\n", + "1951-08 168.451755 193.995669\n", + "1951-09 152.643331 180.053622\n", + "1951-10 130.913430 160.070874\n", + "1951-11 111.900912 142.706578\n", + "1951-12 128.054396 160.424468\n", + "1952-01 122.645044 156.507325\n", + "1952-02 133.834100 169.125551\n", + "1952-03 149.605269 186.270225" ] }, "execution_count": 18, @@ -2600,7 +2614,18 @@ "outputs": [ { "data": { - "image/png": "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uVmvvfZa+PE//vGP9cILL2jlypXh695//315PB699dZbKikpUb9+/XT//fdHfB6Pn/70p3r88ce1ceNGSVJBQYF+8YtfaNasWZ3u29Wu04MHD9bs2bM1e/ZsSR9vHXjTTTfpf/7nfyRJfr9fDodDK1as0AUXXKD58+frb3/7m7Zs2RJu3HTTTbrjjjv00UcfqbCw8JhrPVE32p9rW/tYu2WvX78+vMXlJZdcIr/fr6KiIj366KO67LLLJEmHDx8O/wzmzp2rtWvXqrKyUqtXr9bnP/95SdIzzzyjCy+8UC0tLcc8BEA8dp22fHTUtk0433jjDa1bt07PPvusbr75ZhmGoXHjxmnZsmVWkwAAAAAAAEiAyspKPfDAA+HLdvvHQ8o333xT5513XruTlpx//vnav3+/3n//fZWWlkqSPv3pT7frbd68WWvWrJHD4ej0vWpra9XU1KTW1tbwcOtYnnjiCf385z9XbW2t9u/fr0Ag0G54NWfOHH3ta1/T73//e02YMEEXX3yxysrKLD/3008/vd3zLigoUGNjoyTprbfe0tlnn93u/uecc07M3Wh/rl3ZuXOnpk2bpu9973vhrUZra2t1+PBhnX/++eH75eTk6JxzztGbb77Z5VpLSkokSY2NjeF1xFvUp2EaOXKkAoGADh06pIMHD2rlypV64oknGDQCAAAAAICMZjP6aNB1H0V034O7XtSev0w54f1c0/6feg/4TETf2wq73R71GabbHn+0/fv3a8qUKbrzzjs73bekpETvvvvucXv//Oc/NWPGDN12222aNGmSnE6nHn/8cf3sZz8L3+fWW2/VZZddpr/97W9asWKFbrnlFj3++OP60pesnTQnJyen3WWbzaZQKGSpkahux5/rsfj9fk2dOlXnnXeebr/9dkv9NkevtW34GY+fQVcsH6Px7rvv1tSpU9W3b1+de+65+sMf/qDy8nL96U9/0t69exOxRgAAAAAAgJRhs9mUlWOP6CuvdIKyHQMk2bqqKdsxUHmlEyLqHb2lXCxGjBihf/7zn+2O+fjSSy8pPz9fAwcO7PJxZ511lv7v//5PgwcP1tChQ9t92e12DRs2THl5efrHP/5xzMe//PLLGjRokH74wx9q1KhRGjZsmHbs2NHpfuXl5brxxhv17LPP6qKLLgqfObtXr14KBoMxPntp+PDh4V212xx9MpVoRftz7cg0Tc2cOVOhUEi///3v2/25l5WVhY/v2Obw4cPasGGDvF5vzM8hFpYHjW2Dxd/97nf64IMPtHHjxvDwsagoOccnAAAAAAAASEW2rGz1HXd326WOt0qS+o77mWxZ2d26rm9961uqq6vTt7/9bf373//WU089pVtuuUVz5sxRVlbX46LrrrtOH374ob761a9qw4YNqq2t1cqVK3XllVcqGAyqd+/emjdvnr7//e/rd7/7nWpra7V+/Xo98sgjkqRhw4Zp586devzxx1VbW6uf//znWr78yFm3W1padP3112vt2rXasWOHXnrpJW3YsEEjRoyQ9PGxGPfv369//OMf+uCDD3TgwIGonv83v/lN/fvf/9a8efP09ttv649//GP4jM6xDHOj/bl2dOutt2r16tX69a9/rf3792v37t3avXu3WlpaZLfbde2112ru3Ln6+9//rpqaGn3961/XgQMHdPXVV0e99niwPGjcsGGDfvrTn+q//uu/5HQ6E7EmAAAAAACAjGEf+iX1/6/Hle1wt7s+2zFA/f/rcdmHWtslOB4GDBigZ555Rv/6179UUVGha665RldffbVuuumm4z7O7XbrpZdeUjAY1MSJEzVy5EjNnj1bhYWF4UHazTffrO9+97v60Y9+pBEjRujSSy8NH8Nw6tSpuvHGG3X99dfrjDPO0Msvv6ybb7453M/OztZ//vMf/fd//7fKy8t1ySWXaPLkybrtttskSWPGjNE111yjSy+9VP369dNdd90V1fMfMmSInnzySf35z3/W6aefrgceeCB81unc3NyomlL0P9eO1q1bp/3792vMmDEqKSkJfz3xxBOSpEWLFunLX/6yLr/8cp111ll65513tHLlyqRvBGj5rNOS1NTUpEceeSR8gEmv16urr746JQePnHUaAAAAAADE4nhn47XCDAV1cNeLCvoblG0vUe8Bn+n2LRnRtTvuuEMPPvig6urqkr2UpEjKWac3btyoSZMmKS8vL3w2nnvuuUc/+clP9Oyzz+qss86ymgQAAAAAAMh4tqxs5XnGJnsZ+MSvfvUrnX322erbt69eeuklLV68WNdff32yl5XWLA8ab7zxRk2dOlUPP/ywDOPjhwcCAX3ta1/T7Nmz9fzzz8d9kQAAAAAAAEA8bdu2TT/+8Y/14YcfqrS0VN/97ne1YMGCZC8rrVnedTovL0+vv/66TjnllHbX19TUaNSoUVEfhDNR2HUaAAAAAADEIl67TgOpLCm7ThcUFGjnzp2dBo11dXXKz8+3mkMMAsGQVtXsUr2vRW5nnqq8A2RkWz6/D23atGnTpk2bNm3atCMQCgbUVLtagf31MhxuFZZNUFa25X9S0aZNO47tRPfb2i37/qNQzghFcZqLLpmmqVAoJNM0ZbPZlJWVFdPZjmlnZjvdWN6i8Tvf+Y6WL1+un/70pxozZowk6aWXXtLcuXP15S9/Wffee2/cFhcMBnXrrbdq6dKl2r17t9xut6644grddNNNEf+BZeoWjUvX12ruire1xx8IX+eyG1o8uVwzR5fRpk2bNm3atGnTpk07ju29m5dp38vzZWvdE77OzHUpf8wi9auYQZs27SS0E90/uh3M86jljF+qdGCJ+hQNVE6fvjG1A4GADh8+3On6nJyc8GHqaNPubi0tLXrvvfdi2qLR8qDx0KFDmjt3rh588EEFAh//BZ6Tk6Nrr71WixYtiukU4B395Cc/0d13363q6mqdeuqp2rhxo6688krdcccd+s53vhNRIxMHjUvX12rWkzXq+AfXNnqtnu6N+hcp2rRp06ZNmzZt2rRpt7d38zLtW3OVJDPc01GX8iuXRD3QoE2bdvTDwO5ceyinSP6zHpHbXaL83lJW/uCoh41dDabaxDKgop057WT4z3/+o8bGRpWXlys7u/3Z0BM2aGxz4MAB1dbWSpLKysrUp0+faDLH9V//9V9yuVx65JFHwtd9+ctfVl5enpYuXRpRI9MGjYFgSJ7bV7b7lLYjV59s1cwbb3kXkUAwpBF3PqfGA0HatGnTpk2bNm3atDOmbdPHWza+d1OV5XYoGNDO35RJrXvaDTLamJKU69LAWW9Y3lUzFAzo/eqRUmsjbdq0LerutZuy6UD5D5QzYIJcJ/VWVpahnKJhUhS7x7a2tp7wPtFuxEU7tdo2m029evVK+d2oTdPUgQMH1NjYqMLCQpWUlHS6T8IHjd3hJz/5iR566CE9++yzKi8v1+bNmzVx4kTdfffdmjHj2J9KtLa2tvuDbm5ulsfjyZhB44otdbqwelOylwEAAACknUcmFevskjxLj8n6cKPyXvtGglYEIJ2EevWT/9Q7ZevdV5JNZq++MrN6JXtZSHGGYSgrKz7HCk60wsJCFRcXH3MwGteTwVx00UURL+rPf/5zxPc9kfnz56u5uVmnnHKKsrOzFQwGdccdd3Q5ZJSkhQsX6rbbbovbGlJNva8l2UsAAAAA0tLelq63puyK7dAHCVgJgHSUdWivHJu+oVBusWTLVuuwGxX81GeSvSykuH79+qXFhm85OTmddpeORkSDRqfTGf5v0zS1fPlyOZ1OjRo1SpL06quvqqmpydJAMhJ//OMftWzZMj322GM69dRTtWnTJs2ePVtut1uzZs065mMWLFigOXPmhC+3bdGYKdzOyD6BffKykaryui21V9XUa/pjW2jTpk2bNm3atGnTzsj2aUPc8noHWmp/1KtOzVtPfL+CiU/IWTbBUttXu1rNz15KmzZti+1E94/XtpkBZR98X5JUPHCIioaeZqnt9/u1Y8eOE95v0KBBstvttDOg3adPn04nVslkEQ0af/vb34b/e968ebrkkkv04IMPhiedwWBQ3/rWt+I+oZ07d67mz5+vr3zlK5KkkSNHaseOHVq4cGGXg8bc3Ny4npAm1VR5B8hl36pGf6DTga6lI8efmVpRavn4M1MrSuV66k3atGnTpk2bNm3atDOyPdE70PLua0VlVfLluj45Vlvnuimb1NulouFTLB8Hrmj4FPnW0aZNO5pjNKbE2suqLL+nOBwOGYYRPrnuseTk5MjhcFg+rh/t1GxbHWCmO8s7iS9ZskTf+9732m1OmZ2drTlz5mjJkiVxXdyBAwc6vWizs7MVCoXi+n3SiZGdpcWTyyUdOYNem7bLd00ut/zLGW3atGnTpk2bNm3atDvLyjaUP2aRpI7ntT3qzLbnLYxqUEKbNu3o2onuJ7Jts9mOeaKNo3V1jDzaPaedziz/TRsIBPTvf/+70/X//ve/4z4AnDJliu644w797W9/03vvvafly5fr7rvv1pe+9KW4fp90M3N0maqne9Xf3v5NzWU3VD3dq5mjy2jTpk2bNm3atGnTph2ndr+KGcqvXCLl9m9/Q2+X8iuXqF9F18eQp02bdmLaie4nsu10OuXxeGQY7d+vcnJy5PF42h2+jnbPbacry2ednjNnjn73u9/pBz/4gc455xxJ0iuvvKJFixbp8ssv19133x23xe3bt08333yzli9frsbGRrndbn31q1/Vj370I/XqFdmZnSI9K046CgRDWlWzS/W+FrmdearyDojqU1ratGnTpk2bNm3atGmfWCgY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xhvV0NCgoqIivffee1qwYIFOPvlkSdKmTZvCjy0oKJAkFRcXa8+ePe26e/bsUUFBgfLy8tpdf/311+uvf/2rnn/+eQ0cODCOPwEg9aTD67JXr14aOnRoeL0bNmzQfffdp1//+tfx/FEAKSOVX5evvvqqGhsbddZZZ4VvDwaDev7553X//fertbVV2dnZcf6JAMmXyq/LYyksLFR5ebneeeedODx7IDWl+uuypKSk0144I0aM0J/+9Kd4/QiAlJPqr8s2O3bs0OrVq/XnP/85Ls+bQWOSOZ1OSR8fR2bjxo36n//5H0nS/Pnz9bWvfa3dfUeOHKl77rlHU6ZMaXe9zWYLT53/8Ic/yOPxhP/R0zaQONp5552nZ555pt11q1atanecN9M09e1vf1vLly/X2rVrNWTIkBifKZA+UvV1eSyhUCh8/A8gk6Xi6/Lzn/+8tmzZ0u72K6+8UqeccormzZvHkBEZLxVfl8eyf/9+1dbW6vLLL7f4DIH0k6qvy/PPP19vvfVWu/u8/fbbGjRoUDRPE0grqfq6bPPb3/5W/fv314UXXhjlM+wgplPJoEv79u0zX3/9dfP11183JZl33323+frrr5s7duwwTdM0//jHP5pr1qwxa2trzb/85S/moEGDzIsuuui4TXU4+5BpmuZdd91lvvHGG+bWrVvN22+/3czJyel0n47effdds0+fPubcuXPNN9980/zlL39pZmdnm3//+9/D97n22mtNp9Nprl271mxoaAh/HThwIKqfB5AK0v11OX/+fHPdunXm9u3bzTfeeMOcP3++abPZzGeffTaqnweQCtL9ddkRZ51GJkj31+V3v/tdc+3ateb27dvNl156yZwwYYL5qU99ymxsbIzq5wGkgnR/Xf7rX/8yDcMw77jjDnPbtm3msmXLzD59+phLly6N6ucBpIJ0f12a5sdnwi4tLTXnzZtn+fl3+RziVkI7a9asMSV1+po1a5ZpmqZ53333mQMHDjRzcnLM0tJS86abbjJbW1uP2zzW/3CVlZWm0+k0e/fubZ577rnmM888E/H6zjjjDLNXr17mySefbP72t7/t9L2O9dXxfkA6SffX5VVXXWUOGjTI7NWrl9mvXz/z85//PENGpL10f112xKARmSDdX5eXXnqpWVJSYvbq1cscMGCAeemll5rvvPNOpE8fSEnp/ro0TdP8f//v/5mnnXaamZuba55yyinmQw89FFEbSFWZ8LpcuXKlKcl86623ImpGwmaaphmfbSMBAAAAAAAA9FScdRoAAAAAAABAzBg0AgAAAAAAAIgZg0YAAAAAAAAAMWPQCAAAAAAAACBmDBoBAAAAAAAAxIxBIwAAAAAAAICYMWgEAAAAAAAAEDMGjQAAAAAAAABixqARAAAACXfFFVdo2rRpyV4GAAAAEshI9gIAAACQ3mw223Fvv+WWW3TffffJNM1uWhEAAACSgUEjAAAAYtLQ0BD+7yeeeEI/+tGP9NZbb4WvczgccjgcyVgaAAAAuhG7TgMAACAmxcXF4S+n0ymbzdbuOofD0WnX6XHjxunb3/62Zs+eraKiIrlcLj388MPy+/268sorlZ+fr6FDh2rFihXtvtfWrVs1efJkORwOuVwuXX755frggw+6+RkDAADgWBg0AgAAICmqq6v1qU99Sv/617/07W9/W9dee60uvvhijRkzRq+99pomTpyoyy+/XAcOHJAkNTU1afz48TrzzDO1ceNG/f3vf9eePXt0ySWXJPmZAAAAQGLQCAAAgCSpqKjQTTfdpGHDhmnBggXq3bu3PvWpT+nrX/+6hg0bph/96Ef6z3/+ozfeeEOSdP/99+vMM8/UT37yE51yyik688wztWTJEq1Zs0Zvv/12kp8NAAAAOEYjAAAAkuL0008P/3d2drb69u2rkSNHhq9zuVySpMbGRknS5s2btWbNmmMe77G2tlbl5eUJXjEAAACOh0EjAAAAkiInJ6fdZZvN1u66trNZh0IhSdL+/fs1ZcoU3XnnnZ1aJSUlCVwpAAAAIsGgEQAAAGnhrLPO0p/+9CcNHjxYhsGvsQAAAKmGYzQCAAAgLVx33XX68MMP9dWvflUbNmxQbW2tVq5cqSuvvFLBYDDZywMAAOjxGDQCAAAgLbjdbr300ksKBoOaOHGiRo4cqdmzZ6uwsFBZWfxaCwAAkGw20zTNZC8CAAAAAAAAQHrjo18AAAAAAAAAMWPQCAAAAAAAACBmDBoBAAAAAAAAxIxBIwAAAAAAAICYMWgEAAAAAAAAEDMGjQAAAAAAAABixqARAAAAAAAAQMwYNAIAAAAAAACIGYNGAAAAAAAAADFj0AgAAAAAAAAgZgwaAQAAAAAAAMTs/wM5fDr6o6jjfAAAAABJRU5ErkJggg==", + "text/plain": [ + "(<Figure size 1600x480 with 1 Axes>,\n", + " <Axes: xlabel='Time', ylabel='Window number'>)" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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vJYXla4Gjd3laIPGWKXCn6sUn0Gj5Y8NDxw4oKeeeko/+tGPNHr0aH3mM5/Rpk2bdM011+ixxx6z/lMAAAAAAABkMP/by7TnH19vN2SUpGBzg/b84+vyv70sYd87NzdXJSUl7b7ahoxr167V2WefrdzcXJWWlmru3LntToIzduxYXXPNNZo1a5ZOPPFETZw4UZK0ZcsWTZo0SQ6HQy6XS5dcconef//98ONCoZDuuOMODRkyRLm5uSorK9Ntt90Wvv2GG25QRUWFevfurZNOOkk33nijDh06FL5906ZNqqqqUkFBgQoLC3XmmWdqw4YNWrNmjS677DL5fD7ZbDbZbDbdfPPNkjrvOm2z2fS73/1OX/7yl9W7d28NHTpUTzzxRLs/myeeeEJDhw5VXl6eqqqqVFNTI5vNdtwh5vvvv3/MbrR/rkfuOn3zzTeHf8Yjvx566CFJUmtrq77//e+rX79+ysvL0+c+9zmtX78+/D3WrFkjm82mp59+WiNHjlTv3r01evRovfnmm8f82WJledDYp08fXXLJJfr44481d+5cNTQ06LXXXtOdd96pCy64IBFrBAAAAAAASBmmaSp0yB/RV7C1SR+svk46ytmx2677YM1sBVubIurFuGNq2M6dO/WlL31JZ511ljZt2qR7771XDz74oH7605+2u19NTY169eqlF154Qffdd5/27duncePG6fTTT9eGDRv0r3/9S7t379aFF14Yfsy8efO0cOFC3XjjjaqtrdXDDz8sl8sVvr2goEAPPfSQamtrdffdd+uBBx7QnXfeGb59+vTpGjBggNavX69XXnlFc+fOVU5OjkaPHq277rpLhYWFamxsVGNjo374wx92+TPecsstuvDCC/X666/rS1/6kqZPn64PP/xQkrRt2zZNmzZNU6dO1aZNm/Ttb39bP/7xjyP6sztWN9o/145++MMfhn/GxsZG/fznP1fv3r01cuRISdL111+vv/3tb6qpqdGrr76qIUOGaOLEieF1tPnxj3+sX/ziF9qwYYMMw9Dll18e0c8YLcu7Tk+dOlXPP/+8evXqpbFjx4a/KioqErXGmLDrNAAAAAAAiEXHXUpDh/za/puipKxl4NUfKSvHHtF9L730Ui1ZsqTdbrCTJk3SX//6V/34xz/W3/72N73xxhvh4wn+9re/1Q033CCfz6esrCyNHTtWTU1NevXVV8OP/+lPf6rnnntOK1asCF/33nvvyePx6M0331RpaamKi4t1zz33RHwej5///Of685//rA0bNkiSCgsL9etf/1ozZ87sdN+udp0eNGiQZs2apVmzZkn6ZOvA+fPn63//938lSX6/Xw6HQ8uXL9d5552nuXPn6p///Kc2b94cbsyfP1+33XabPvroI/Xp0+eoaz1eN9o/17b20XbLXrduXXiLywsvvFB+v19FRUV66KGHdPHFF0uSDh06FP4zmDNnjtasWaOqqiqtWrVKX/ziFyVJTz75pM4//3y1tLQc9RAA8dh12vLRUds24Xz99de1du1aPfXUU7rxxhtlGIbGjh2rpUuXWk0CAAAAAAAgAaqqqnTvvfeGL9vtnwwp33jjDZ177rntTlry2c9+Vs3NzXrvvfdUVlYmSTrzzDPb9TZt2qTVq1fL4XB0+l51dXXat2+fWltbw8Oto3nkkUf0q1/9SnV1dWpublYgEGg3vJo9e7a++c1v6o9//KPGjx+vr33tayovL7f8s3/mM59p93MXFhZqz549kqQ333xTZ511Vrv7n3322TF3o/1z7cqOHTs0depU/fCHPwxvNVpXV6dDhw7ps5/9bPh+OTk5Ovvss/XGG290udbS0lJJ0p49e8LriLeoT8M0YsQIBQIBHTx4UB9//LFWrFihRx55hEEjAAAAAADIaDajtwZe/VFE9/145/Pa/ffJx72fa+r/p7z+n4voe1tht9ujPsN02+OP1NzcrMmTJ+v222/vdN/S0lK98847x+y99NJLmj59um655RZNnDhRTqdTf/7zn/WLX/wifJ+bb75ZF198sf75z39q+fLluummm/TnP/9ZX/6ytZPm5OTktLtss9kUCoUsNRLV7fjnejR+v19TpkzRueeeq1tvvdVSv82Ra20bfsbjz6Arlo/R+Mtf/lJTpkxR3759dc455+hPf/qTKioq9Le//U179+5NxBoBAAAAAABShs1mU1aOPaKv/LLxynb0l2TrqqZsxwDll42PqHfklnKxGD58uF566aV2x3x84YUXVFBQoAEDBnT5uDPOOEP/+c9/NGjQIA0ZMqTdl91u19ChQ5Wfn6+nn376qI9/8cUXNXDgQP34xz/WyJEjNXToUG3fvr3T/SoqKnTdddfpqaee0le+8pXwmbN79eqlYDAY408vDRs2LLyrdpsjT6YS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", "text/plain": [ "<Figure size 1600x480 with 1 Axes>" ] @@ -2650,7 +2675,7 @@ { "data": { "text/html": [ - "<style>#sk-98a069bc-b795-48e2-9eac-e0374eab901a {color: black;background-color: white;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a pre{padding: 0;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-toggleable {background-color: white;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a label.sk-toggleable__label-arrow:before {content: \"βΈ\";float: left;margin-right: 0.25em;color: #696969;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"βΎ\";}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-estimator:hover {background-color: #d4ebff;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 2em;bottom: 0;left: 50%;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-item {z-index: 1;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-parallel::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 2em;bottom: 0;left: 50%;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-parallel-item {display: flex;flex-direction: column;position: relative;background-color: white;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-parallel-item:only-child::after {width: 0;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;position: relative;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-label label {font-family: monospace;font-weight: bold;background-color: white;display: inline-block;line-height: 1.2em;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-label-container {position: relative;z-index: 2;text-align: center;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-98a069bc-b795-48e2-9eac-e0374eab901a div.sk-text-repr-fallback {display: none;}</style><div id='sk-98a069bc-b795-48e2-9eac-e0374eab901a' class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>VAR()</pre><b>Please rerun this cell to show the HTML repr or trust the notebook.</b></div><div class=\"sk-container\" hidden><div class='sk-item'><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('c1503cc9-3f13-4fe9-aa27-2267fe0497e1') type=\"checkbox\" checked><label for=UUID('c1503cc9-3f13-4fe9-aa27-2267fe0497e1') class='sk-toggleable__label sk-toggleable__label-arrow'>VAR</label><div class=\"sk-toggleable__content\"><pre>VAR()</pre></div></div></div></div></div>" + "<style>#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 {color: black;background-color: white;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 pre{padding: 0;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-toggleable {background-color: white;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 label.sk-toggleable__label-arrow:before {content: \"βΈ\";float: left;margin-right: 0.25em;color: #696969;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"βΎ\";}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-estimator:hover {background-color: #d4ebff;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 2em;bottom: 0;left: 50%;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-item {z-index: 1;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-parallel::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 2em;bottom: 0;left: 50%;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-parallel-item {display: flex;flex-direction: column;position: relative;background-color: white;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-parallel-item:only-child::after {width: 0;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;position: relative;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-label label {font-family: monospace;font-weight: bold;background-color: white;display: inline-block;line-height: 1.2em;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-label-container {position: relative;z-index: 2;text-align: center;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-f23c3876-2cde-4425-8d64-a316fb81fd51 div.sk-text-repr-fallback {display: none;}</style><div id='sk-f23c3876-2cde-4425-8d64-a316fb81fd51' class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>VAR()</pre><b>Please rerun this cell to show the HTML repr or trust the notebook.</b></div><div class=\"sk-container\" hidden><div class='sk-item'><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('890d0cd6-eea0-4b29-a628-0deaaf61884c') type=\"checkbox\" checked><label for=UUID('890d0cd6-eea0-4b29-a628-0deaaf61884c') class='sk-toggleable__label sk-toggleable__label-arrow'>VAR</label><div class=\"sk-toggleable__content\"><pre>VAR()</pre></div></div></div></div></div>" ], "text/plain": [ "VAR()" @@ -2724,23 +2749,23 @@ " <th rowspan=\"5\" valign=\"top\">h0_0</th>\n", " <th rowspan=\"5\" valign=\"top\">h1_0</th>\n", " <th>2000-01-01</th>\n", - " <td>1.000000</td>\n", + " <td>5.272974</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-02</th>\n", - " <td>3.518414</td>\n", + " <td>4.416770</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-03</th>\n", - " <td>3.439018</td>\n", + " <td>2.991815</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-04</th>\n", - " <td>4.930397</td>\n", + " <td>2.360916</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-05</th>\n", - " <td>4.612988</td>\n", + " <td>2.269617</td>\n", " </tr>\n", " <tr>\n", " <th>...</th>\n", @@ -2752,23 +2777,23 @@ " <th rowspan=\"5\" valign=\"top\">h0_1</th>\n", " <th rowspan=\"5\" valign=\"top\">h1_3</th>\n", " <th>2000-01-08</th>\n", - " <td>3.877603</td>\n", + " <td>4.388797</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-09</th>\n", - " <td>2.867442</td>\n", + " <td>5.096147</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-10</th>\n", - " <td>5.020762</td>\n", + " <td>3.347833</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-11</th>\n", - " <td>4.566137</td>\n", + " <td>3.560713</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-12</th>\n", - " <td>3.806208</td>\n", + " <td>4.467743</td>\n", " </tr>\n", " </tbody>\n", "</table>\n", @@ -2778,17 +2803,17 @@ "text/plain": [ " c0\n", "h0 h1 time \n", - "h0_0 h1_0 2000-01-01 1.000000\n", - " 2000-01-02 3.518414\n", - " 2000-01-03 3.439018\n", - " 2000-01-04 4.930397\n", - " 2000-01-05 4.612988\n", + "h0_0 h1_0 2000-01-01 5.272974\n", + " 2000-01-02 4.416770\n", + " 2000-01-03 2.991815\n", + " 2000-01-04 2.360916\n", + " 2000-01-05 2.269617\n", "... ...\n", - "h0_1 h1_3 2000-01-08 3.877603\n", - " 2000-01-09 2.867442\n", - " 2000-01-10 5.020762\n", - " 2000-01-11 4.566137\n", - " 2000-01-12 3.806208\n", + "h0_1 h1_3 2000-01-08 4.388797\n", + " 2000-01-09 5.096147\n", + " 2000-01-10 3.347833\n", + " 2000-01-11 3.560713\n", + " 2000-01-12 4.467743\n", "\n", "[96 rows x 1 columns]" ] @@ -2867,131 +2892,131 @@ " <th rowspan=\"12\" valign=\"top\">h0_0</th>\n", " <th rowspan=\"3\" valign=\"top\">h1_0</th>\n", " <th>2000-01-13</th>\n", - " <td>1.547240</td>\n", - " <td>5.656626</td>\n", + " <td>1.722621</td>\n", + " <td>5.035875</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-14</th>\n", - " <td>1.486515</td>\n", - " <td>6.111832</td>\n", + " <td>1.880358</td>\n", + " <td>5.280790</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-15</th>\n", - " <td>1.524294</td>\n", - " <td>6.277836</td>\n", + " <td>1.924552</td>\n", + " <td>5.329570</td>\n", " </tr>\n", " <tr>\n", " <th rowspan=\"3\" valign=\"top\">h1_1</th>\n", " <th>2000-01-13</th>\n", - " <td>3.285397</td>\n", - " <td>5.304444</td>\n", + " <td>1.847150</td>\n", + " <td>4.690652</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-14</th>\n", - " <td>3.357664</td>\n", - " <td>5.387562</td>\n", + " <td>1.874098</td>\n", + " <td>4.740716</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-15</th>\n", - " <td>3.349540</td>\n", - " <td>5.379555</td>\n", + " <td>1.878830</td>\n", + " <td>4.745823</td>\n", " </tr>\n", " <tr>\n", " <th rowspan=\"3\" valign=\"top\">h1_2</th>\n", " <th>2000-01-13</th>\n", - " <td>2.916079</td>\n", - " <td>6.618686</td>\n", + " <td>2.012331</td>\n", + " <td>5.262287</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-14</th>\n", - " <td>2.920492</td>\n", - " <td>6.653291</td>\n", + " <td>1.717852</td>\n", + " <td>4.986732</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-15</th>\n", - " <td>2.922742</td>\n", - " <td>6.656034</td>\n", + " <td>1.748543</td>\n", + " <td>5.017644</td>\n", " </tr>\n", " <tr>\n", " <th rowspan=\"3\" valign=\"top\">h1_3</th>\n", " <th>2000-01-13</th>\n", - " <td>2.830648</td>\n", - " <td>5.936913</td>\n", + " <td>2.673739</td>\n", + " <td>4.996850</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-14</th>\n", - " <td>2.753652</td>\n", - " <td>5.974169</td>\n", + " <td>2.589237</td>\n", + " <td>4.975105</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-15</th>\n", - " <td>2.744015</td>\n", - " <td>5.972928</td>\n", + " <td>2.599973</td>\n", + " <td>4.989230</td>\n", " </tr>\n", " <tr>\n", " <th rowspan=\"12\" valign=\"top\">h0_1</th>\n", " <th rowspan=\"3\" valign=\"top\">h1_0</th>\n", " <th>2000-01-13</th>\n", - " <td>2.371798</td>\n", - " <td>4.871334</td>\n", + " <td>2.596552</td>\n", + " <td>4.620861</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-14</th>\n", - " <td>2.447080</td>\n", - " <td>5.252941</td>\n", + " <td>2.144881</td>\n", + " <td>4.272040</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-15</th>\n", - " <td>2.526418</td>\n", - " <td>5.406628</td>\n", + " <td>2.268863</td>\n", + " <td>4.406453</td>\n", " </tr>\n", " <tr>\n", " <th rowspan=\"3\" valign=\"top\">h1_1</th>\n", " <th>2000-01-13</th>\n", - " <td>2.648028</td>\n", - " <td>5.302283</td>\n", + " <td>2.353941</td>\n", + " <td>5.390139</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-14</th>\n", - " <td>2.673720</td>\n", - " <td>5.360916</td>\n", + " <td>2.267849</td>\n", + " <td>5.321420</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-15</th>\n", - " <td>2.679975</td>\n", - " <td>5.367988</td>\n", + " <td>2.259457</td>\n", + " <td>5.313227</td>\n", " </tr>\n", " <tr>\n", " <th rowspan=\"3\" valign=\"top\">h1_2</th>\n", " <th>2000-01-13</th>\n", - " <td>3.541852</td>\n", - " <td>5.942392</td>\n", + " <td>1.877079</td>\n", + " <td>5.224196</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-14</th>\n", - " <td>3.423455</td>\n", - " <td>5.869728</td>\n", + " <td>1.975364</td>\n", + " <td>5.387870</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-15</th>\n", - " <td>3.441320</td>\n", - " <td>5.889336</td>\n", + " <td>2.000103</td>\n", + " <td>5.415163</td>\n", " </tr>\n", " <tr>\n", " <th rowspan=\"3\" valign=\"top\">h1_3</th>\n", " <th>2000-01-13</th>\n", - " <td>3.150096</td>\n", - " <td>5.231645</td>\n", + " <td>2.655375</td>\n", + " <td>5.049080</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-14</th>\n", - " <td>2.981736</td>\n", - " <td>5.161234</td>\n", + " <td>2.577533</td>\n", + " <td>4.986714</td>\n", " </tr>\n", " <tr>\n", " <th>2000-01-15</th>\n", - " <td>3.014187</td>\n", - " <td>5.202889</td>\n", + " <td>2.569449</td>\n", + " <td>4.978829</td>\n", " </tr>\n", " </tbody>\n", "</table>\n", @@ -3002,30 +3027,30 @@ " 0.9 \n", " lower upper\n", "h0 h1 time \n", - "h0_0 h1_0 2000-01-13 1.547240 5.656626\n", - " 2000-01-14 1.486515 6.111832\n", - " 2000-01-15 1.524294 6.277836\n", - " h1_1 2000-01-13 3.285397 5.304444\n", - " 2000-01-14 3.357664 5.387562\n", - " 2000-01-15 3.349540 5.379555\n", - " h1_2 2000-01-13 2.916079 6.618686\n", - " 2000-01-14 2.920492 6.653291\n", - " 2000-01-15 2.922742 6.656034\n", - " h1_3 2000-01-13 2.830648 5.936913\n", - " 2000-01-14 2.753652 5.974169\n", - " 2000-01-15 2.744015 5.972928\n", - "h0_1 h1_0 2000-01-13 2.371798 4.871334\n", - " 2000-01-14 2.447080 5.252941\n", - " 2000-01-15 2.526418 5.406628\n", - " h1_1 2000-01-13 2.648028 5.302283\n", - " 2000-01-14 2.673720 5.360916\n", - " 2000-01-15 2.679975 5.367988\n", - " h1_2 2000-01-13 3.541852 5.942392\n", - " 2000-01-14 3.423455 5.869728\n", - " 2000-01-15 3.441320 5.889336\n", - " h1_3 2000-01-13 3.150096 5.231645\n", - " 2000-01-14 2.981736 5.161234\n", - " 2000-01-15 3.014187 5.202889" + "h0_0 h1_0 2000-01-13 1.722621 5.035875\n", + " 2000-01-14 1.880358 5.280790\n", + " 2000-01-15 1.924552 5.329570\n", + " h1_1 2000-01-13 1.847150 4.690652\n", + " 2000-01-14 1.874098 4.740716\n", + " 2000-01-15 1.878830 4.745823\n", + " h1_2 2000-01-13 2.012331 5.262287\n", + " 2000-01-14 1.717852 4.986732\n", + " 2000-01-15 1.748543 5.017644\n", + " h1_3 2000-01-13 2.673739 4.996850\n", + " 2000-01-14 2.589237 4.975105\n", + " 2000-01-15 2.599973 4.989230\n", + "h0_1 h1_0 2000-01-13 2.596552 4.620861\n", + " 2000-01-14 2.144881 4.272040\n", + " 2000-01-15 2.268863 4.406453\n", + " h1_1 2000-01-13 2.353941 5.390139\n", + " 2000-01-14 2.267849 5.321420\n", + " 2000-01-15 2.259457 5.313227\n", + " h1_2 2000-01-13 1.877079 5.224196\n", + " 2000-01-14 1.975364 5.387870\n", + " 2000-01-15 2.000103 5.415163\n", + " h1_3 2000-01-13 2.655375 5.049080\n", + " 2000-01-14 2.577533 4.986714\n", + " 2000-01-15 2.569449 4.978829" ] }, "execution_count": 22, @@ -3175,99 +3200,99 @@ " <tbody>\n", " <tr>\n", " <th>1951-01</th>\n", - " <td>127.478978</td>\n", - " <td>130.438207</td>\n", - " <td>133.726125</td>\n", - " <td>137.014043</td>\n", - " <td>139.973272</td>\n", + " <td>127.478982</td>\n", + " <td>130.438212</td>\n", + " <td>133.726132</td>\n", + " <td>137.014051</td>\n", + " <td>139.973281</td>\n", " </tr>\n", " <tr>\n", " <th>1951-02</th>\n", - " <td>137.638269</td>\n", - " <td>141.120013</td>\n", - " <td>144.988483</td>\n", - " <td>148.856953</td>\n", - " <td>152.338697</td>\n", + " <td>137.638273</td>\n", + " <td>141.120018</td>\n", + " <td>144.988491</td>\n", + " <td>148.856963</td>\n", + " <td>152.338709</td>\n", " </tr>\n", " <tr>\n", " <th>1951-03</th>\n", - " <td>152.276577</td>\n", - " <td>156.212063</td>\n", - " <td>160.584673</td>\n", - " <td>164.957283</td>\n", - " <td>168.892768</td>\n", + " <td>152.276580</td>\n", + " <td>156.212068</td>\n", + " <td>160.584681</td>\n", + " <td>164.957294</td>\n", + " <td>168.892782</td>\n", " </tr>\n", " <tr>\n", " <th>1951-04</th>\n", - " <td>143.405969</td>\n", - " <td>147.748037</td>\n", - " <td>152.572389</td>\n", - " <td>157.396741</td>\n", - " <td>161.738809</td>\n", + " <td>143.405971</td>\n", + " <td>147.748041</td>\n", + " <td>152.572397</td>\n", + " <td>157.396752</td>\n", + " <td>161.738823</td>\n", " </tr>\n", " <tr>\n", " <th>1951-05</th>\n", " <td>130.762062</td>\n", - " <td>135.475772</td>\n", - " <td>140.713045</td>\n", - " <td>145.950318</td>\n", - " <td>150.664027</td>\n", + " <td>135.475775</td>\n", + " <td>140.713052</td>\n", + " <td>145.950329</td>\n", + " <td>150.664042</td>\n", " </tr>\n", " <tr>\n", " <th>1951-06</th>\n", " <td>155.995358</td>\n", - " <td>161.053476</td>\n", - " <td>166.673412</td>\n", - " <td>172.293349</td>\n", - " <td>177.351467</td>\n", + " <td>161.053480</td>\n", + " <td>166.673421</td>\n", + " <td>172.293362</td>\n", + " <td>177.351484</td>\n", " </tr>\n", " <tr>\n", " <th>1951-07</th>\n", - " <td>170.413963</td>\n", - " <td>175.794490</td>\n", - " <td>181.772645</td>\n", - " <td>187.750801</td>\n", - " <td>193.131328</td>\n", + " <td>170.413964</td>\n", + " <td>175.794494</td>\n", + " <td>181.772655</td>\n", + " <td>187.750815</td>\n", + " <td>193.131346</td>\n", " </tr>\n", " <tr>\n", " <th>1951-08</th>\n", - " <td>169.718563</td>\n", - " <td>175.403241</td>\n", - " <td>181.719332</td>\n", - " <td>188.035423</td>\n", - " <td>193.720101</td>\n", + " <td>169.718562</td>\n", + " <td>175.403245</td>\n", + " <td>181.719341</td>\n", + " <td>188.035437</td>\n", + " <td>193.720120</td>\n", " </tr>\n", " <tr>\n", " <th>1951-09</th>\n", - " <td>154.000334</td>\n", - " <td>159.973698</td>\n", - " <td>166.610539</td>\n", - " <td>173.247380</td>\n", - " <td>179.220743</td>\n", + " <td>154.000332</td>\n", + " <td>159.973701</td>\n", + " <td>166.610547</td>\n", + " <td>173.247393</td>\n", + " <td>179.220762</td>\n", " </tr>\n", " <tr>\n", " <th>1951-10</th>\n", - " <td>132.362644</td>\n", - " <td>138.611370</td>\n", - " <td>145.554159</td>\n", - " <td>152.496947</td>\n", - " <td>158.745674</td>\n", + " <td>132.362640</td>\n", + " <td>138.611371</td>\n", + " <td>145.554166</td>\n", + " <td>152.496960</td>\n", + " <td>158.745692</td>\n", " </tr>\n", " <tr>\n", " <th>1951-11</th>\n", - " <td>113.464726</td>\n", + " <td>113.464721</td>\n", " <td>119.977182</td>\n", - " <td>127.212994</td>\n", - " <td>134.448805</td>\n", - " <td>140.961262</td>\n", + " <td>127.213000</td>\n", + " <td>134.448818</td>\n", + " <td>140.961280</td>\n", " </tr>\n", " <tr>\n", " <th>1951-12</th>\n", - " <td>129.690419</td>\n", + " <td>129.690414</td>\n", " <td>136.456333</td>\n", - " <td>143.973754</td>\n", - " <td>151.491176</td>\n", - " <td>158.257090</td>\n", + " <td>143.973761</td>\n", + " <td>151.491189</td>\n", + " <td>158.257109</td>\n", " </tr>\n", " </tbody>\n", "</table>\n", @@ -3276,33 +3301,33 @@ "text/plain": [ " Number of airline passengers \\\n", " 0.10 0.25 0.50 0.75 \n", - "1951-01 127.478978 130.438207 133.726125 137.014043 \n", - "1951-02 137.638269 141.120013 144.988483 148.856953 \n", - "1951-03 152.276577 156.212063 160.584673 164.957283 \n", - "1951-04 143.405969 147.748037 152.572389 157.396741 \n", - "1951-05 130.762062 135.475772 140.713045 145.950318 \n", - "1951-06 155.995358 161.053476 166.673412 172.293349 \n", - "1951-07 170.413963 175.794490 181.772645 187.750801 \n", - "1951-08 169.718563 175.403241 181.719332 188.035423 \n", - "1951-09 154.000334 159.973698 166.610539 173.247380 \n", - "1951-10 132.362644 138.611370 145.554159 152.496947 \n", - "1951-11 113.464726 119.977182 127.212994 134.448805 \n", - "1951-12 129.690419 136.456333 143.973754 151.491176 \n", + "1951-01 127.478982 130.438212 133.726132 137.014051 \n", + "1951-02 137.638273 141.120018 144.988491 148.856963 \n", + "1951-03 152.276580 156.212068 160.584681 164.957294 \n", + "1951-04 143.405971 147.748041 152.572397 157.396752 \n", + "1951-05 130.762062 135.475775 140.713052 145.950329 \n", + "1951-06 155.995358 161.053480 166.673421 172.293362 \n", + "1951-07 170.413964 175.794494 181.772655 187.750815 \n", + "1951-08 169.718562 175.403245 181.719341 188.035437 \n", + "1951-09 154.000332 159.973701 166.610547 173.247393 \n", + "1951-10 132.362640 138.611371 145.554166 152.496960 \n", + "1951-11 113.464721 119.977182 127.213000 134.448818 \n", + "1951-12 129.690414 136.456333 143.973761 151.491189 \n", "\n", " \n", " 0.90 \n", - "1951-01 139.973272 \n", - "1951-02 152.338697 \n", - "1951-03 168.892768 \n", - "1951-04 161.738809 \n", - "1951-05 150.664027 \n", - "1951-06 177.351467 \n", - "1951-07 193.131328 \n", - "1951-08 193.720101 \n", - "1951-09 179.220743 \n", - "1951-10 158.745674 \n", - "1951-11 140.961262 \n", - "1951-12 158.257090 " + "1951-01 139.973281 \n", + "1951-02 152.338709 \n", + "1951-03 168.892782 \n", + "1951-04 161.738823 \n", + "1951-05 150.664042 \n", + "1951-06 177.351484 \n", + "1951-07 193.131346 \n", + "1951-08 193.720120 \n", + "1951-09 179.220762 \n", + "1951-10 158.745692 \n", + "1951-11 140.961280 \n", + "1951-12 158.257109 " ] }, "execution_count": 23, @@ -3350,9 +3375,9 @@ "text/plain": [ "0.10 2.706601\n", "0.25 5.494502\n", - "0.50 8.162435\n", - "0.75 8.003799\n", - "0.90 5.220249\n", + "0.50 8.162432\n", + "0.75 8.003790\n", + "0.90 5.220235\n", "Name: 0, dtype: float64" ] }, @@ -3416,98 +3441,98 @@ " <tr>\n", " <th>0</th>\n", " <td>1.752102</td>\n", - " <td>3.640448</td>\n", - " <td>5.636938</td>\n", - " <td>5.989468</td>\n", - " <td>4.524056</td>\n", + " <td>3.640447</td>\n", + " <td>5.636934</td>\n", + " <td>5.989462</td>\n", + " <td>4.524047</td>\n", " </tr>\n", " <tr>\n", " <th>1</th>\n", " <td>1.236173</td>\n", - " <td>2.219997</td>\n", - " <td>2.505758</td>\n", - " <td>0.857285</td>\n", - " <td>0.233870</td>\n", + " <td>2.219995</td>\n", + " <td>2.505755</td>\n", + " <td>0.857278</td>\n", + " <td>0.233871</td>\n", " </tr>\n", " <tr>\n", " <th>2</th>\n", " <td>2.572342</td>\n", - " <td>5.446984</td>\n", - " <td>8.707664</td>\n", - " <td>9.782038</td>\n", - " <td>8.196509</td>\n", + " <td>5.446983</td>\n", + " <td>8.707660</td>\n", + " <td>9.782030</td>\n", + " <td>8.196497</td>\n", " </tr>\n", " <tr>\n", " <th>3</th>\n", " <td>1.959403</td>\n", - " <td>3.812991</td>\n", - " <td>5.213805</td>\n", - " <td>4.202444</td>\n", - " <td>1.135072</td>\n", + " <td>3.812990</td>\n", + " <td>5.213802</td>\n", + " <td>4.202436</td>\n", + " <td>1.135059</td>\n", " </tr>\n", " <tr>\n", " <th>4</th>\n", " <td>4.123794</td>\n", - " <td>9.131057</td>\n", - " <td>15.643478</td>\n", - " <td>19.537261</td>\n", - " <td>19.202375</td>\n", + " <td>9.131056</td>\n", + " <td>15.643474</td>\n", + " <td>19.537253</td>\n", + " <td>19.202362</td>\n", " </tr>\n", " <tr>\n", " <th>5</th>\n", " <td>2.200464</td>\n", - " <td>4.236631</td>\n", - " <td>5.663294</td>\n", - " <td>4.279988</td>\n", - " <td>0.583679</td>\n", + " <td>4.236630</td>\n", + " <td>5.663290</td>\n", + " <td>4.279979</td>\n", + " <td>0.583664</td>\n", " </tr>\n", " <tr>\n", " <th>6</th>\n", " <td>2.858604</td>\n", - " <td>5.801378</td>\n", - " <td>8.613677</td>\n", - " <td>8.436899</td>\n", - " <td>5.281805</td>\n", + " <td>5.801376</td>\n", + " <td>8.613673</td>\n", + " <td>8.436889</td>\n", + " <td>5.281789</td>\n", " </tr>\n", " <tr>\n", " <th>7</th>\n", " <td>2.928144</td>\n", - " <td>5.899190</td>\n", - " <td>8.640334</td>\n", - " <td>8.223433</td>\n", - " <td>4.751909</td>\n", + " <td>5.899189</td>\n", + " <td>8.640329</td>\n", + " <td>8.223422</td>\n", + " <td>4.751892</td>\n", " </tr>\n", " <tr>\n", " <th>8</th>\n", " <td>2.999967</td>\n", - " <td>6.006576</td>\n", - " <td>8.694731</td>\n", - " <td>8.064465</td>\n", - " <td>4.301331</td>\n", + " <td>6.006575</td>\n", + " <td>8.694726</td>\n", + " <td>8.064455</td>\n", + " <td>4.301314</td>\n", " </tr>\n", " <tr>\n", " <th>9</th>\n", " <td>2.963736</td>\n", " <td>5.847157</td>\n", - " <td>8.222921</td>\n", - " <td>7.127290</td>\n", - " <td>2.928894</td>\n", + " <td>8.222917</td>\n", + " <td>7.127280</td>\n", + " <td>2.928877</td>\n", " </tr>\n", " <tr>\n", " <th>10</th>\n", - " <td>3.253527</td>\n", + " <td>3.253528</td>\n", " <td>6.505704</td>\n", - " <td>9.393503</td>\n", - " <td>8.663396</td>\n", - " <td>4.534864</td>\n", + " <td>9.393500</td>\n", + " <td>8.663387</td>\n", + " <td>4.534848</td>\n", " </tr>\n", " <tr>\n", " <th>11</th>\n", - " <td>3.630958</td>\n", + " <td>3.630959</td>\n", " <td>7.385917</td>\n", - " <td>11.013123</td>\n", - " <td>10.881618</td>\n", - " <td>6.968619</td>\n", + " <td>11.013119</td>\n", + " <td>10.881608</td>\n", + " <td>6.968602</td>\n", " </tr>\n", " </tbody>\n", "</table>\n", @@ -3515,18 +3540,18 @@ ], "text/plain": [ " 0.10 0.25 0.50 0.75 0.90\n", - "0 1.752102 3.640448 5.636938 5.989468 4.524056\n", - "1 1.236173 2.219997 2.505758 0.857285 0.233870\n", - "2 2.572342 5.446984 8.707664 9.782038 8.196509\n", - "3 1.959403 3.812991 5.213805 4.202444 1.135072\n", - "4 4.123794 9.131057 15.643478 19.537261 19.202375\n", - "5 2.200464 4.236631 5.663294 4.279988 0.583679\n", - "6 2.858604 5.801378 8.613677 8.436899 5.281805\n", - "7 2.928144 5.899190 8.640334 8.223433 4.751909\n", - "8 2.999967 6.006576 8.694731 8.064465 4.301331\n", - "9 2.963736 5.847157 8.222921 7.127290 2.928894\n", - "10 3.253527 6.505704 9.393503 8.663396 4.534864\n", - "11 3.630958 7.385917 11.013123 10.881618 6.968619" + "0 1.752102 3.640447 5.636934 5.989462 4.524047\n", + "1 1.236173 2.219995 2.505755 0.857278 0.233871\n", + "2 2.572342 5.446983 8.707660 9.782030 8.196497\n", + "3 1.959403 3.812990 5.213802 4.202436 1.135059\n", + "4 4.123794 9.131056 15.643474 19.537253 19.202362\n", + "5 2.200464 4.236630 5.663290 4.279979 0.583664\n", + "6 2.858604 5.801376 8.613673 8.436889 5.281789\n", + "7 2.928144 5.899189 8.640329 8.223422 4.751892\n", + "8 2.999967 6.006575 8.694726 8.064455 4.301314\n", + "9 2.963736 5.847157 8.222917 7.127280 2.928877\n", + "10 3.253528 6.505704 9.393500 8.663387 4.534848\n", + "11 3.630959 7.385917 11.013119 10.881608 6.968602" ] }, "execution_count": 25, @@ -3557,7 +3582,7 @@ { "data": { "text/plain": [ - "5.917517291566615" + "5.917511873790087" ] }, "execution_count": 26, @@ -3591,18 +3616,18 @@ { "data": { "text/plain": [ - "0 4.308602\n", - "1 1.410617\n", - "2 6.941107\n", - "3 3.264743\n", - "4 13.527593\n", - "5 3.392811\n", - "6 6.198473\n", - "7 6.088602\n", - "8 6.013414\n", - "9 5.417999\n", - "10 6.470199\n", - "11 7.976047\n", + "0 4.308598\n", + "1 1.410614\n", + "2 6.941102\n", + "3 3.264738\n", + "4 13.527588\n", + "5 3.392805\n", + "6 6.198466\n", + "7 6.088595\n", + "8 6.013407\n", + "9 5.417993\n", + "10 6.470193\n", + "11 7.976041\n", "dtype: float64" ] }, @@ -3690,63 +3715,63 @@ " <tbody>\n", " <tr>\n", " <th>1951-01</th>\n", - " <td>127.478978</td>\n", - " <td>139.973272</td>\n", + " <td>127.478982</td>\n", + " <td>139.973281</td>\n", " </tr>\n", " <tr>\n", " <th>1951-02</th>\n", - " <td>137.638269</td>\n", - " <td>152.338697</td>\n", + " <td>137.638273</td>\n", + " <td>152.338709</td>\n", " </tr>\n", " <tr>\n", " <th>1951-03</th>\n", - " <td>152.276577</td>\n", - " <td>168.892768</td>\n", + " <td>152.276580</td>\n", + " <td>168.892782</td>\n", " </tr>\n", " <tr>\n", " <th>1951-04</th>\n", - " <td>143.405969</td>\n", - " <td>161.738809</td>\n", + " <td>143.405971</td>\n", + " <td>161.738823</td>\n", " </tr>\n", " <tr>\n", " <th>1951-05</th>\n", " <td>130.762062</td>\n", - " <td>150.664027</td>\n", + " <td>150.664042</td>\n", " </tr>\n", " <tr>\n", " <th>1951-06</th>\n", " <td>155.995358</td>\n", - " <td>177.351467</td>\n", + " <td>177.351484</td>\n", " </tr>\n", " <tr>\n", " <th>1951-07</th>\n", - " <td>170.413963</td>\n", - " <td>193.131328</td>\n", + " <td>170.413964</td>\n", + " <td>193.131346</td>\n", " </tr>\n", " <tr>\n", " <th>1951-08</th>\n", - " <td>169.718563</td>\n", - " <td>193.720101</td>\n", + " <td>169.718562</td>\n", + " <td>193.720120</td>\n", " </tr>\n", " <tr>\n", " <th>1951-09</th>\n", - " <td>154.000334</td>\n", - " <td>179.220743</td>\n", + " <td>154.000332</td>\n", + " <td>179.220762</td>\n", " </tr>\n", " <tr>\n", " <th>1951-10</th>\n", - " <td>132.362644</td>\n", - " <td>158.745674</td>\n", + " <td>132.362640</td>\n", + " <td>158.745692</td>\n", " </tr>\n", " <tr>\n", " <th>1951-11</th>\n", - " <td>113.464726</td>\n", - " <td>140.961262</td>\n", + " <td>113.464721</td>\n", + " <td>140.961280</td>\n", " </tr>\n", " <tr>\n", " <th>1951-12</th>\n", - " <td>129.690419</td>\n", - " <td>158.257090</td>\n", + " <td>129.690414</td>\n", + " <td>158.257109</td>\n", " </tr>\n", " </tbody>\n", "</table>\n", @@ -3756,18 +3781,18 @@ " Number of airline passengers \n", " 0.8 \n", " lower upper\n", - "1951-01 127.478978 139.973272\n", - "1951-02 137.638269 152.338697\n", - "1951-03 152.276577 168.892768\n", - "1951-04 143.405969 161.738809\n", - "1951-05 130.762062 150.664027\n", - "1951-06 155.995358 177.351467\n", - "1951-07 170.413963 193.131328\n", - "1951-08 169.718563 193.720101\n", - "1951-09 154.000334 179.220743\n", - "1951-10 132.362644 158.745674\n", - "1951-11 113.464726 140.961262\n", - "1951-12 129.690419 158.257090" + "1951-01 127.478982 139.973281\n", + "1951-02 137.638273 152.338709\n", + "1951-03 152.276580 168.892782\n", + "1951-04 143.405971 161.738823\n", + "1951-05 130.762062 150.664042\n", + "1951-06 155.995358 177.351484\n", + "1951-07 170.413964 193.131346\n", + "1951-08 169.718562 193.720120\n", + "1951-09 154.000332 179.220762\n", + "1951-10 132.362640 158.745692\n", + "1951-11 113.464721 140.961280\n", + "1951-12 129.690414 158.257109" ] }, "execution_count": 28, @@ -3798,7 +3823,7 @@ "data": { "text/plain": [ "0.1 2.706601\n", - "0.9 5.220249\n", + "0.9 5.220235\n", "Name: 0, dtype: float64" ] }, @@ -3820,7 +3845,7 @@ { "data": { "text/plain": [ - "3.9634248763342055" + "3.9634182197580174" ] }, "execution_count": 30, @@ -3869,7 +3894,7 @@ " <th></th>\n", " <th>test_PinballLoss</th>\n", " <th>fit_time</th>\n", - " <th>pred_time</th>\n", + " <th>pred_quantiles_time</th>\n", " <th>len_train_window</th>\n", " <th>cutoff</th>\n", " </tr>\n", @@ -3878,40 +3903,40 @@ " <tr>\n", " <th>0</th>\n", " <td>0.865788</td>\n", - " <td>0.013478</td>\n", - " <td>0.013374</td>\n", + " <td>0.004671</td>\n", + " <td>0.002910</td>\n", " <td>72</td>\n", " <td>1954-12</td>\n", " </tr>\n", " <tr>\n", " <th>1</th>\n", " <td>0.958340</td>\n", - " <td>0.011405</td>\n", - " <td>0.012645</td>\n", + " <td>0.003195</td>\n", + " <td>0.003149</td>\n", " <td>84</td>\n", " <td>1955-12</td>\n", " </tr>\n", " <tr>\n", " <th>2</th>\n", " <td>0.981744</td>\n", - " <td>0.012250</td>\n", - " <td>0.016469</td>\n", + " <td>0.003315</td>\n", + " <td>0.002972</td>\n", " <td>96</td>\n", " <td>1956-12</td>\n", " </tr>\n", " <tr>\n", " <th>3</th>\n", " <td>1.411309</td>\n", - " <td>0.011964</td>\n", - " <td>0.011275</td>\n", + " <td>0.003242</td>\n", + " <td>0.003038</td>\n", " <td>108</td>\n", " <td>1957-12</td>\n", " </tr>\n", " <tr>\n", " <th>4</th>\n", " <td>1.187198</td>\n", - " <td>0.012172</td>\n", - " <td>0.011219</td>\n", + " <td>0.003085</td>\n", + " <td>0.002992</td>\n", " <td>120</td>\n", " <td>1958-12</td>\n", " </tr>\n", @@ -3920,12 +3945,12 @@ "</div>" ], "text/plain": [ - " test_PinballLoss fit_time pred_time len_train_window cutoff\n", - "0 0.865788 0.013478 0.013374 72 1954-12\n", - "1 0.958340 0.011405 0.012645 84 1955-12\n", - "2 0.981744 0.012250 0.016469 96 1956-12\n", - "3 1.411309 0.011964 0.011275 108 1957-12\n", - "4 1.187198 0.012172 0.011219 120 1958-12" + " test_PinballLoss fit_time pred_quantiles_time len_train_window cutoff\n", + "0 0.865788 0.004671 0.002910 72 1954-12\n", + "1 0.958340 0.003195 0.003149 84 1955-12\n", + "2 0.981744 0.003315 0.002972 96 1956-12\n", + "3 1.411309 0.003242 0.003038 108 1957-12\n", + "4 1.187198 0.003085 0.002992 120 1958-12" ] }, "execution_count": 31, @@ -3984,6 +4009,49 @@ "contributions are appreciated!" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Visual Evaluation \n", + "\n", + "Often, the probabilistic forecast's calibration is important. I.e., how many values are smaller then the 0.1 quantile, 0.2 quantile, etc.\n", + "\n", + "This evaluation can be made using calibration plots:" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(<Figure size 1600x400 with 1 Axes>, <Axes: >)" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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paWl6bnnnutU09zcrHvvvVcZGRmKjIzU+PHjtWLFivbPHz16VDfccIMyMjIUERGhyy67TL/73e+61cf8+fP1z3/+U8uXL9cdd9yhUaNG6YILLtC0adO0du1aDRkyRJK0bNkyFRYWKjY2VgkJCfra176mPXv2nPHrrlixQg6Ho9Ntx++9956GDBmisLAwTZkyRfv372//3KOPPqpRo0bp17/+tfLy8hQWFtal187LM/+lYPTo0XI4HLriiiskmdOc1113nd+P549//GMlJycrLCxMhYWFWr9+faeely9frrFjxyoiIkKTJk3Szp07u/VjCgAAAADAabU0maHgiqelxV+TnsqWXr9a+r8npH3/MIPCiARp2Nelq5+Vfrhaum+PdP1vpAm3S6nDCQo/R0Nzq363rkySNKOAqcKuCrzJQsPoPJLbW4IjJIfjnJ5633336R//+If+/Oc/Kzk5WQ888IA2bdrkN8V355136tNPP9WSJUuUnp6uP/3pT/rqV7+qbdu2aciQIWpqatKYMWM0e/ZsRUdHa+nSpbrppps0ePBg5efnd6mP3/72t5o8ebJGjx7d+e0FB7ffgtzQ0KBZs2ZpxIgRqq+v19y5c/WNb3xDW7ZskbOLv1A1NjbqiSee0JtvvqmQkBD96Ec/0ve+9z2VlJS01+zevVvvvPOO3n33Xblcri699rp165Sfn6+//e1vuvTSS884jfjTn/5U77zzjt544w3l5OTomWee0ZQpU7R7927Fx8e31z344IN67rnnlJSUpNtvv10zZszw6xEAAAAAgC5paZIOrO+YHDywXvI2+9dEJvmfOZg09JyzhoHunU0HVNfUqrzESF15cbLd7fQbgRcWtjRKT6bb89oPHJRCIrv9tPr6ei1cuFC/+c1vdNVVV0mS3njjDWVmZrbXlJWV6fXXX1dZWZnS0833d++992rZsmV6/fXX9eSTTyojI0P33ntv+3PuuusuffDBB/r973/f5bDws88+a5/E+zzf+ta3/D5etGiRkpKS9Omnn2r48OFdeq2Wlha9/PLLGj9+vCTzPQ8bNqw97JPMW4/ffPNNJSUldfm122oTEhLOeOtzQ0ODXn31VS1evFhXX321JGnBggX68MMPtXDhQt13333ttU888YS+9KUvSZLmzJmja6+9Vk1NTe2TjgAAAAAAnFbLCfNWYnexua34wHrJ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eb3e3mobCCjnch1OmjRJGzdubL9Vee/evXr//fd1zTXX9ErPwEA3kLOZILsbCHRVVVXyer1KSUnxezwlJUU7duw47XMqKipOW19RUdFjfQKB6lyuwVPNnj1b6enpnX6jANA153IdFhcXa+HChdqyZUsvdAgEtnO5Bvfu3au///3vuvHGG/X+++9r9+7d+tGPfqSWlhY98sgjvdE2EFDO5TqcNm2aqqqqVFhYKMMw1Nraqttvv53bkIFecqZspra2VidOnFB4eLhNnfU8JgsB4HM89dRTWrJkif70pz8pLCzM7naAAaGurk433XSTFixYoMTERLvbAQYkn8+n5ORk/epXv9KYMWN0/fXX68EHH+RIHKAXrVixQk8++aT+4z/+Q5s2bdK7776rpUuX6vHHH7e7NQABjsnCHpaYmCiXy6XKykq/xysrK5Wamnra56SmpnarHsCZncs12OYXv/iFnnrqKf3tb3/TiBEjerJNIKB19zrcs2eP3G63pk6d2v6Yz+eTJAUFBWnnzp0aPHhwzzYNBJBz+b0wLS1NwcHBcrlc7Y8NGzZMFRUV8ng8CgkJ6dGegUBzLtfhww8/rJtuukm33XabJOmyyy5TQ0ODfvCDH+jBBx+U08nsD9CTzpTNREdHB/RUocRkYY8LCQnRmDFj/A6l9fl8Wr58uSZOnHja50ycONGvXpI+/PDDM9YDOLNzuQYl6ZlnntHjjz+uZcuWaezYsb3RKhCwunsdDh06VNu2bdOWLVvav339619v30SXlZXVm+0D/d65/F5YUFCg3bt3twf1krRr1y6lpaURFALn4Fyuw8bGxk6BYFuAz55SoOcN6GzGQI9bsmSJERoaaixevNj49NNPjR/84AdGbGysUVFRYRiGYdx0003GnDlz2utLSkqMoKAg4xe/+IWxfft245FHHjGCg4ONbdu22fUWgH6tu9fgU089ZYSEhBh//OMfjUOHDrV/q6urs+stAP1ed6/DU918883Gv/7rv/ZSt0Dg6e41WFZWZkRFRRl33nmnsXPnTuOvf/2rkZycbPz85z+36y0A/V53r8NHHnnEiIqKMn73u98Ze/fuNf73f//XGDx4sPHd737XrrcA9Gt1dXXG5s2bjc2bNxuSjOeff97YvHmzUVpaahiGYcyZM8e46aab2uv37t1rREREGPfdd5+xfft245VXXjFcLpexbNkyu95Cr+E25F5w/fXX68iRI5o7d64qKio0atQoLVu2rP2gzLKyMr9/MZo0aZLeeustPfTQQ3rggQc0ZMgQvffeexo+fLhdbwHo17p7Db766qvyeDz69re/7fd1HnnkET366KO92ToQMLp7HQI4v7p7DWZlZemDDz7QPffcoxEjRigjI0M/+clPNHv2bLveAtDvdfc6fOihh+RwOPTQQw+pvLxcSUlJmjp1qp544gm73gLQr23YsEFXXnll+8ezZs2SJN18881avHixDh06pLKysvbP5+XlaenSpbrnnnv04osvKjMzU7/+9a81ZcqUXu+9tzkMg/llAAAAAAAAAJxZCAAAAAAAAMBCWAgAAAAAAABAEmEhAAAAAAAAAAthIQAAAAAAAABJhIUAAAAAAAAALISFAAAAAAAAACQRFgIAAAAAAACwEBYCAAAAAAAAkERYCAAAAAAAAMBCWAgAAAAAAABAEmEhAAAAAAAAAMv/D4YQzapsrj4pAAAAAElFTkSuQmCC", + "text/plain": [ + "<Figure size 1600x400 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from sktime.utils.plotting import plot_calibration\n", + "\n", + "plot_calibration(y_true=y_test.loc[pred_quantiles.index], y_pred=pred_quantiles)" + ] + }, { "cell_type": "markdown", "id": "public-union", @@ -4027,7 +4095,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 33, "id": "6abda0ed", "metadata": {}, "outputs": [ @@ -4037,7 +4105,7 @@ "False" ] }, - "execution_count": 32, + "execution_count": 33, "metadata": {}, "output_type": "execute_result" } @@ -4061,7 +4129,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 34, "id": "60b0664a", "metadata": {}, "outputs": [ @@ -4071,7 +4139,7 @@ "True" ] }, - "execution_count": 33, + "execution_count": 34, "metadata": {}, "output_type": "execute_result" } @@ -4097,7 +4165,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 35, "id": "99e6bc89", "metadata": {}, "outputs": [ @@ -4137,18 +4205,18 @@ " <tbody>\n", " <tr>\n", " <th>1961-01</th>\n", - " <td>341.950660</td>\n", - " <td>522.049339</td>\n", + " <td>341.960792</td>\n", + " <td>522.039207</td>\n", " </tr>\n", " <tr>\n", " <th>1961-02</th>\n", - " <td>319.828426</td>\n", - " <td>544.171573</td>\n", + " <td>319.835453</td>\n", + " <td>544.164546</td>\n", " </tr>\n", " <tr>\n", " <th>1961-03</th>\n", - " <td>307.334366</td>\n", - " <td>556.665632</td>\n", + " <td>307.334056</td>\n", + " <td>556.665943</td>\n", " </tr>\n", " </tbody>\n", "</table>\n", @@ -4158,12 +4226,12 @@ " Number of airline passengers \n", " 0.9 \n", " lower upper\n", - "1961-01 341.950660 522.049339\n", - "1961-02 319.828426 544.171573\n", - "1961-03 307.334366 556.665632" + "1961-01 341.960792 522.039207\n", + "1961-02 319.835453 544.164546\n", + "1961-03 307.334056 556.665943" ] }, - "execution_count": 34, + "execution_count": 35, "metadata": {}, "output_type": "execute_result" } @@ -4218,7 +4286,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 36, "id": "difficult-belarus", "metadata": {}, "outputs": [], @@ -4247,20 +4315,20 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 37, "id": "562b301e", "metadata": {}, "outputs": [ { "data": { "text/html": [ - "<style>#sk-cd404a54-ceab-4e6f-957f-192d402ecaba {color: black;background-color: white;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba pre{padding: 0;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-toggleable {background-color: white;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba label.sk-toggleable__label-arrow:before {content: \"βΈ\";float: left;margin-right: 0.25em;color: #696969;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"βΎ\";}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-estimator:hover {background-color: #d4ebff;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 2em;bottom: 0;left: 50%;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-item {z-index: 1;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-parallel::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 2em;bottom: 0;left: 50%;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-parallel-item {display: flex;flex-direction: column;position: relative;background-color: white;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-parallel-item:only-child::after {width: 0;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;position: relative;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-label label {font-family: monospace;font-weight: bold;background-color: white;display: inline-block;line-height: 1.2em;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-label-container {position: relative;z-index: 2;text-align: center;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-cd404a54-ceab-4e6f-957f-192d402ecaba div.sk-text-repr-fallback {display: none;}</style><div id='sk-cd404a54-ceab-4e6f-957f-192d402ecaba' class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>ForecastingGridSearchCV(cv=SlidingWindowSplitter(fh=[1, 2, 3],\n", + "<style>#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 {color: black;background-color: white;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 pre{padding: 0;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-toggleable {background-color: white;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 label.sk-toggleable__label-arrow:before {content: \"βΈ\";float: left;margin-right: 0.25em;color: #696969;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"βΎ\";}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-estimator:hover {background-color: #d4ebff;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 2em;bottom: 0;left: 50%;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-item {z-index: 1;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-parallel::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 2em;bottom: 0;left: 50%;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-parallel-item {display: flex;flex-direction: column;position: relative;background-color: white;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-parallel-item:only-child::after {width: 0;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;position: relative;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-label label {font-family: monospace;font-weight: bold;background-color: white;display: inline-block;line-height: 1.2em;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-label-container {position: relative;z-index: 2;text-align: center;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935 div.sk-text-repr-fallback {display: none;}</style><div id='sk-6648d0d2-8b27-4abf-ad8b-a038b4f6e935' class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>ForecastingGridSearchCV(cv=SlidingWindowSplitter(fh=[1, 2, 3],\n", " window_length=36),\n", " forecaster=ThetaForecaster(),\n", - " param_grid={'sp': [1, 6, 12]}, scoring=PinballLoss())</pre><b>Please rerun this cell to show the HTML repr or trust the notebook.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item sk-dashed-wrapped\"><div class='sk-label-container'><div class=\"sk-label sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('95124b26-981a-40b4-8d48-671c42998f34') type=\"checkbox\" ><label for=UUID('95124b26-981a-40b4-8d48-671c42998f34') class='sk-toggleable__label sk-toggleable__label-arrow'>ForecastingGridSearchCV</label><div class=\"sk-toggleable__content\"><pre>ForecastingGridSearchCV(cv=SlidingWindowSplitter(fh=[1, 2, 3],\n", + " param_grid={'sp': [1, 6, 12]}, scoring=PinballLoss())</pre><b>Please rerun this cell to show the HTML repr or trust the notebook.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item sk-dashed-wrapped\"><div class='sk-label-container'><div class=\"sk-label sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('5eb0427b-8e34-4027-8226-bf4b7929717e') type=\"checkbox\" ><label for=UUID('5eb0427b-8e34-4027-8226-bf4b7929717e') class='sk-toggleable__label sk-toggleable__label-arrow'>ForecastingGridSearchCV</label><div class=\"sk-toggleable__content\"><pre>ForecastingGridSearchCV(cv=SlidingWindowSplitter(fh=[1, 2, 3],\n", " window_length=36),\n", " forecaster=ThetaForecaster(),\n", - " param_grid={'sp': [1, 6, 12]}, scoring=PinballLoss())</pre></div></div></div><div class=\"sk-parallel\"><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-serial\"><div class='sk-item'><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('79234729-8ca2-4697-9e23-5d63111a1261') type=\"checkbox\" ><label for=UUID('79234729-8ca2-4697-9e23-5d63111a1261') class='sk-toggleable__label sk-toggleable__label-arrow'>SlidingWindowSplitter</label><div class=\"sk-toggleable__content\"><pre>SlidingWindowSplitter(fh=[1, 2, 3], window_length=36)</pre></div></div></div></div></div></div><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-serial\"><div class='sk-item'><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('41954e69-e437-4eea-a4db-9d71aee1f9d9') type=\"checkbox\" ><label for=UUID('41954e69-e437-4eea-a4db-9d71aee1f9d9') class='sk-toggleable__label sk-toggleable__label-arrow'>ThetaForecaster</label><div class=\"sk-toggleable__content\"><pre>ThetaForecaster()</pre></div></div></div></div></div></div><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-serial\"><div class='sk-item'><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('512b4501-de7b-4f64-be99-62b0bef6117f') type=\"checkbox\" ><label for=UUID('512b4501-de7b-4f64-be99-62b0bef6117f') class='sk-toggleable__label sk-toggleable__label-arrow'>PinballLoss</label><div class=\"sk-toggleable__content\"><pre>PinballLoss()</pre></div></div></div></div></div></div></div></div></div></div>" + " param_grid={'sp': [1, 6, 12]}, scoring=PinballLoss())</pre></div></div></div><div class=\"sk-parallel\"><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-serial\"><div class='sk-item'><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('21d23b04-8b92-4647-828b-a38d62f12de7') type=\"checkbox\" ><label for=UUID('21d23b04-8b92-4647-828b-a38d62f12de7') class='sk-toggleable__label sk-toggleable__label-arrow'>SlidingWindowSplitter</label><div class=\"sk-toggleable__content\"><pre>SlidingWindowSplitter(fh=[1, 2, 3], window_length=36)</pre></div></div></div></div></div></div><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-serial\"><div class='sk-item'><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('50d9faf8-d515-4ab7-a4d0-f337413ecd96') type=\"checkbox\" ><label for=UUID('50d9faf8-d515-4ab7-a4d0-f337413ecd96') class='sk-toggleable__label sk-toggleable__label-arrow'>ThetaForecaster</label><div class=\"sk-toggleable__content\"><pre>ThetaForecaster()</pre></div></div></div></div></div></div><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-serial\"><div class='sk-item'><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('32a30784-a4fc-472d-827d-c779193775f4') type=\"checkbox\" ><label for=UUID('32a30784-a4fc-472d-827d-c779193775f4') class='sk-toggleable__label sk-toggleable__label-arrow'>PinballLoss</label><div class=\"sk-toggleable__content\"><pre>PinballLoss()</pre></div></div></div></div></div></div></div></div></div></div>" ], "text/plain": [ "ForecastingGridSearchCV(cv=SlidingWindowSplitter(fh=[1, 2, 3],\n", @@ -4269,7 +4337,7 @@ " param_grid={'sp': [1, 6, 12]}, scoring=PinballLoss())" ] }, - "execution_count": 36, + "execution_count": 37, "metadata": {}, "output_type": "execute_result" } @@ -4292,7 +4360,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 38, "id": "comparative-sampling", "metadata": {}, "outputs": [ @@ -4302,7 +4370,7 @@ "{'sp': 12}" ] }, - "execution_count": 37, + "execution_count": 38, "metadata": {}, "output_type": "execute_result" } @@ -4321,7 +4389,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 39, "id": "133d779e", "metadata": {}, "outputs": [ @@ -4367,11 +4435,11 @@ " <tr>\n", " <th>1954-02</th>\n", " <td>195.638436</td>\n", - " <td>226.620354</td>\n", + " <td>226.620355</td>\n", " </tr>\n", " <tr>\n", " <th>1954-03</th>\n", - " <td>221.947953</td>\n", + " <td>221.947952</td>\n", " <td>256.967883</td>\n", " </tr>\n", " </tbody>\n", @@ -4383,11 +4451,11 @@ " 0.9 \n", " lower upper\n", "1954-01 190.832917 217.164705\n", - "1954-02 195.638436 226.620354\n", - "1954-03 221.947953 256.967883" + "1954-02 195.638436 226.620355\n", + "1954-03 221.947952 256.967883" ] }, - "execution_count": 38, + "execution_count": 39, "metadata": {}, "output_type": "execute_result" } @@ -4406,7 +4474,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 40, "id": "differential-growth", "metadata": {}, "outputs": [ @@ -4416,7 +4484,7 @@ "{'selected_forecaster': 'naive'}" ] }, - "execution_count": 39, + "execution_count": 40, "metadata": {}, "output_type": "execute_result" } @@ -4491,7 +4559,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 41, "id": "dcab36a8", "metadata": {}, "outputs": [], @@ -4505,7 +4573,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 42, "id": "610257c8", "metadata": {}, "outputs": [], @@ -4519,7 +4587,7 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 43, "id": "1c04ef29", "metadata": {}, "outputs": [ @@ -4607,7 +4675,7 @@ "1998Q1 4.501319 5.913611" ] }, - "execution_count": 42, + "execution_count": 43, "metadata": {}, "output_type": "execute_result" } @@ -4671,7 +4739,7 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 44, "id": "behavioral-anger", "metadata": {}, "outputs": [], @@ -4684,7 +4752,7 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 45, "id": "5b4f08da", "metadata": {}, "outputs": [], @@ -4695,7 +4763,7 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 46, "id": "underlying-australia", "metadata": {}, "outputs": [ @@ -4761,7 +4829,7 @@ "2010Q2 8.438112 10.337207" ] }, - "execution_count": 45, + "execution_count": 46, "metadata": {}, "output_type": "execute_result" } @@ -4781,7 +4849,7 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 47, "id": "8c47e57b", "metadata": {}, "outputs": [ @@ -4842,7 +4910,7 @@ "2010Q2 8.438112 10.337207" ] }, - "execution_count": 46, + "execution_count": 47, "metadata": {}, "output_type": "execute_result" } @@ -4861,7 +4929,7 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 48, "id": "07deb7ec", "metadata": {}, "outputs": [], @@ -4871,7 +4939,7 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 49, "id": "4c9e9228", "metadata": {}, "outputs": [ @@ -4937,7 +5005,7 @@ "2010Q2 8.438112 10.337207" ] }, - "execution_count": 48, + "execution_count": 49, "metadata": {}, "output_type": "execute_result" } @@ -4980,7 +5048,7 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 50, "id": "59af90ce", "metadata": {}, "outputs": [], @@ -5006,7 +5074,7 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 51, "id": "12cdfc8e", "metadata": {}, "outputs": [], @@ -5075,7 +5143,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.3" + "version": "3.11.5" } }, "nbformat": 4, diff --git a/examples/01c_forecasting_hierarchical_global.ipynb b/examples/01c_forecasting_hierarchical_global.ipynb index b486a2e165b..63c84a79939 100644 --- a/examples/01c_forecasting_hierarchical_global.ipynb +++ b/examples/01c_forecasting_hierarchical_global.ipynb @@ -2717,7 +2717,7 @@ "* focus on modeling individual products\n", "* hierarchical information is provided as exgoneous information. \n", "\n", - "For the M5 competition, winning solution used exogeneous features about the hierarchies like `\"dept_id\"`, `\"store_id\"` etc. to capture similarities and dissimilarities of the products. Other features include holiday events and snap days (specific assisstance program of US social security paid on certain days)." + "For the M5 competition, winning solution used exogeneous features about the hierarchies like `\"dept_id\"`, `\"store_id\"` etc. to capture similarities and dissimilarities of the products. Other features include holiday events and snap days (specific assistance program of US social security paid on certain days)." ] }, { diff --git a/examples/AA_datatypes_and_datasets.ipynb b/examples/AA_datatypes_and_datasets.ipynb index 867016e0fb5..8a17bb5b923 100644 --- a/examples/AA_datatypes_and_datasets.ipynb +++ b/examples/AA_datatypes_and_datasets.ipynb @@ -3166,7 +3166,7 @@ } ], "source": [ - "df_panel = df_panel.set_index([\"timepoints\", \"level_0\"])\n", + "df_panel = df_panel.set_index([\"level_0\", \"timepoints\"])\n", "type(df_panel.index)" ] }, diff --git a/examples/blog_posts/Overview_of_sktime_functionalities_for_forecasting.ipynb b/examples/blog_posts/Overview_of_sktime_functionalities_for_forecasting.ipynb new file mode 100644 index 00000000000..6fc534b219b --- /dev/null +++ b/examples/blog_posts/Overview_of_sktime_functionalities_for_forecasting.ipynb @@ -0,0 +1,4084 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "d7b47a21", + "metadata": { + "id": "d7b47a21" + }, + "source": [ + "# **Overview of sktime's forecasting functionality**\n", + "## by Joanna Lenczuk\n", + "\n", + "The code in this notebook is explained comprehensively in this article:\n", + "https://towardsdatascience.com/why-start-using-sktime-for-forecasting-8d6881c0a518" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "bd82fa45-b5ab-456d-93a8-aa04b3fbb04b", + "metadata": { + "id": "bd82fa45-b5ab-456d-93a8-aa04b3fbb04b" + }, + "outputs": [], + "source": [ + "# %%capture\n", + "# !pip install numpy\n", + "# !pip install pandas\n", + "# !pip install seaborn\n", + "# !pip install 'sktime[all_extras]'" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "fb6368a7", + "metadata": { + "id": "fb6368a7", + "scrolled": true + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "import seaborn as sns\n", + "import matplotlib.pyplot as plt\n", + "import statsmodels.api as sm\n", + "\n", + "from sklearn.linear_model import LinearRegression\n", + "from sklearn.ensemble import RandomForestRegressor\n", + "\n", + "from sktime.forecasting.base import ForecastingHorizon\n", + "from sktime.forecasting.model_selection import temporal_train_test_split\n", + "from sktime.forecasting.arima import AutoARIMA\n", + "from sktime.forecasting.exp_smoothing import ExponentialSmoothing\n", + "from sktime.forecasting.ets import AutoETS\n", + "from sktime.forecasting.naive import NaiveForecaster\n", + "from sktime.forecasting.tbats import TBATS\n", + "from sktime.forecasting.theta import ThetaForecaster\n", + "from sktime.forecasting.compose import (\n", + " EnsembleForecaster,\n", + " MultiplexForecaster,\n", + " TransformedTargetForecaster,\n", + " make_reduction,\n", + " ForecastingPipeline,\n", + " DirectTabularRegressionForecaster\n", + ")\n", + "from sktime.forecasting.model_selection import (\n", + " SlidingWindowSplitter,\n", + " ExpandingWindowSplitter,\n", + " ForecastingGridSearchCV,\n", + " ForecastingRandomizedSearchCV)\n", + "from sktime.forecasting.model_evaluation import evaluate\n", + "from sktime.transformations.series.detrend import Detrender, Deseasonalizer\n", + "from sktime.transformations.series.boxcox import BoxCoxTransformer, LogTransformer\n", + "from sktime.transformations.series.outlier_detection import HampelFilter\n", + "from sktime.transformations.compose import OptionalPassthrough\n", + "from sktime.performance_metrics.forecasting import (\n", + " mean_absolute_scaled_error,\n", + " median_absolute_percentage_error,\n", + " make_forecasting_scorer,\n", + " MeanAbsolutePercentageError,\n", + " MedianAbsolutePercentageError)\n", + "from sktime.utils.plotting import plot_series" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "ae03dede-08f1-404b-bd41-a68381ed34d6", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 36 + }, + "id": "ae03dede-08f1-404b-bd41-a68381ed34d6", + "outputId": "9ab4377a-cfc7-43e8-ad03-49a379c5eab9" + }, + "outputs": [ + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, + "text/plain": [ + "'0.24.1'" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import sktime\n", + "sktime.__version__" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "6be7e172", + "metadata": { + "id": "6be7e172" + }, + "outputs": [], + "source": [ + "import warnings\n", + "warnings.filterwarnings(\"ignore\")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "f3acc607", + "metadata": { + "id": "f3acc607" + }, + "outputs": [], + "source": [ + "sns.set(rc={'figure.figsize':(12,6)})" + ] + }, + { + "cell_type": "markdown", + "id": "22d3683b", + "metadata": { + "id": "22d3683b" + }, + "source": [ + "### Importing data" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "59029473", + "metadata": { + "id": "59029473" + }, + "outputs": [], + "source": [ + "df = sm.datasets.macrodata.load_pandas()['data']" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "31a71346", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 214 + }, + "id": "31a71346", + "outputId": "6cb4d182-93cf-4cac-ff52-6aed528cb181" + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " <div id=\"df-ed3371a3-71a8-4953-84ff-ec4c49f66ebb\" class=\"colab-df-container\">\n", + " <div>\n", + "<style scoped>\n", + " .dataframe tbody tr th:only-of-type {\n", + " vertical-align: middle;\n", + " }\n", + "\n", + " .dataframe tbody tr th {\n", + " vertical-align: top;\n", + " }\n", + "\n", + " .dataframe thead th {\n", + " text-align: right;\n", + " }\n", + "</style>\n", + "<table border=\"1\" class=\"dataframe\">\n", + " <thead>\n", + " <tr style=\"text-align: right;\">\n", + " <th></th>\n", + " <th>year</th>\n", + " <th>quarter</th>\n", + " <th>realgdp</th>\n", + " <th>realcons</th>\n", + " <th>realinv</th>\n", + " <th>realgovt</th>\n", + " <th>realdpi</th>\n", + " <th>cpi</th>\n", + " <th>m1</th>\n", + " <th>tbilrate</th>\n", + " <th>unemp</th>\n", + " <th>pop</th>\n", + " <th>infl</th>\n", + " <th>realint</th>\n", + " </tr>\n", + " </thead>\n", + " <tbody>\n", + " <tr>\n", + " <th>0</th>\n", + " <td>1959.0</td>\n", + " <td>1.0</td>\n", + " <td>2710.349</td>\n", + " <td>1707.4</td>\n", + " <td>286.898</td>\n", + " <td>470.045</td>\n", + " <td>1886.9</td>\n", + " <td>28.98</td>\n", + " <td>139.7</td>\n", + " <td>2.82</td>\n", + " <td>5.8</td>\n", + " <td>177.146</td>\n", + " <td>0.00</td>\n", + " <td>0.00</td>\n", + " </tr>\n", + " <tr>\n", + " <th>1</th>\n", + " <td>1959.0</td>\n", + " <td>2.0</td>\n", + " <td>2778.801</td>\n", + " <td>1733.7</td>\n", + " <td>310.859</td>\n", + " <td>481.301</td>\n", + " <td>1919.7</td>\n", + " <td>29.15</td>\n", + " <td>141.7</td>\n", + " <td>3.08</td>\n", + " <td>5.1</td>\n", + " <td>177.830</td>\n", + " <td>2.34</td>\n", + " <td>0.74</td>\n", + " </tr>\n", + " <tr>\n", + " <th>2</th>\n", + " <td>1959.0</td>\n", + " <td>3.0</td>\n", + " <td>2775.488</td>\n", + " <td>1751.8</td>\n", + " <td>289.226</td>\n", + " <td>491.260</td>\n", + " <td>1916.4</td>\n", + " <td>29.35</td>\n", + " <td>140.5</td>\n", + " <td>3.82</td>\n", + " <td>5.3</td>\n", + " <td>178.657</td>\n", + " <td>2.74</td>\n", + " <td>1.09</td>\n", + " </tr>\n", + " <tr>\n", + " <th>3</th>\n", + " <td>1959.0</td>\n", + " <td>4.0</td>\n", + " <td>2785.204</td>\n", + " <td>1753.7</td>\n", + " <td>299.356</td>\n", + " <td>484.052</td>\n", + " <td>1931.3</td>\n", + " <td>29.37</td>\n", + " <td>140.0</td>\n", + " <td>4.33</td>\n", + " <td>5.6</td>\n", + " <td>179.386</td>\n", + " <td>0.27</td>\n", + " <td>4.06</td>\n", + " </tr>\n", + " <tr>\n", + " <th>4</th>\n", + " <td>1960.0</td>\n", + " <td>1.0</td>\n", + " <td>2847.699</td>\n", + " <td>1770.5</td>\n", + " <td>331.722</td>\n", + " <td>462.199</td>\n", + " <td>1955.5</td>\n", + " <td>29.54</td>\n", + " <td>139.6</td>\n", + " <td>3.50</td>\n", + " <td>5.2</td>\n", + " <td>180.007</td>\n", + " <td>2.31</td>\n", + " <td>1.19</td>\n", + " </tr>\n", + " </tbody>\n", + "</table>\n", + "</div>\n", + " <div class=\"colab-df-buttons\">\n", + "\n", + " <div class=\"colab-df-container\">\n", + " <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-ed3371a3-71a8-4953-84ff-ec4c49f66ebb')\"\n", + " title=\"Convert this dataframe to an interactive table.\"\n", + " style=\"display:none;\">\n", + "\n", + " <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n", + " <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n", + " </svg>\n", + " </button>\n", + "\n", + " <style>\n", + " .colab-df-container {\n", + " display:flex;\n", + " gap: 12px;\n", + " }\n", + "\n", + " .colab-df-convert {\n", + " background-color: #E8F0FE;\n", + " border: none;\n", + " border-radius: 50%;\n", + " cursor: pointer;\n", + " display: none;\n", + " fill: #1967D2;\n", + " height: 32px;\n", + " padding: 0 0 0 0;\n", + " width: 32px;\n", + " }\n", + "\n", + " .colab-df-convert:hover {\n", + " background-color: #E2EBFA;\n", + " box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n", + " fill: #174EA6;\n", + " }\n", + "\n", + " .colab-df-buttons div {\n", + " margin-bottom: 4px;\n", + " }\n", + "\n", + " [theme=dark] .colab-df-convert {\n", + " background-color: #3B4455;\n", + " fill: #D2E3FC;\n", + " }\n", + "\n", + " [theme=dark] .colab-df-convert:hover {\n", + " background-color: #434B5C;\n", + " box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n", + " filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n", + " fill: #FFFFFF;\n", + " }\n", + " </style>\n", + "\n", + " <script>\n", + " const buttonEl =\n", + " document.querySelector('#df-ed3371a3-71a8-4953-84ff-ec4c49f66ebb button.colab-df-convert');\n", + " buttonEl.style.display =\n", + " google.colab.kernel.accessAllowed ? 'block' : 'none';\n", + "\n", + " async function convertToInteractive(key) {\n", + " const element = document.querySelector('#df-ed3371a3-71a8-4953-84ff-ec4c49f66ebb');\n", + " const dataTable =\n", + " await google.colab.kernel.invokeFunction('convertToInteractive',\n", + " [key], {});\n", + " if (!dataTable) return;\n", + "\n", + " const docLinkHtml = 'Like what you see? Visit the ' +\n", + " '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n", + " + ' to learn more about interactive tables.';\n", + " element.innerHTML = '';\n", + " dataTable['output_type'] = 'display_data';\n", + " await google.colab.output.renderOutput(dataTable, element);\n", + " const docLink = document.createElement('div');\n", + " docLink.innerHTML = docLinkHtml;\n", + " element.appendChild(docLink);\n", + " }\n", + " </script>\n", + " </div>\n", + "\n", + "\n", + "<div id=\"df-34af8841-7076-498a-9e0b-c0e2357031b6\">\n", + " <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-34af8841-7076-498a-9e0b-c0e2357031b6')\"\n", + " title=\"Suggest charts\"\n", + " style=\"display:none;\">\n", + "\n", + "<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n", + " width=\"24px\">\n", + " <g>\n", + " <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n", + " </g>\n", + "</svg>\n", + " </button>\n", + "\n", + "<style>\n", + " .colab-df-quickchart {\n", + " --bg-color: #E8F0FE;\n", + " --fill-color: #1967D2;\n", + " --hover-bg-color: #E2EBFA;\n", + " --hover-fill-color: #174EA6;\n", + " --disabled-fill-color: #AAA;\n", + " --disabled-bg-color: #DDD;\n", + " }\n", + "\n", + " [theme=dark] .colab-df-quickchart {\n", + " --bg-color: #3B4455;\n", + " --fill-color: #D2E3FC;\n", + " --hover-bg-color: #434B5C;\n", + " --hover-fill-color: #FFFFFF;\n", + " --disabled-bg-color: #3B4455;\n", + " --disabled-fill-color: #666;\n", + " }\n", + "\n", + " .colab-df-quickchart {\n", + " background-color: var(--bg-color);\n", + " border: none;\n", + " border-radius: 50%;\n", + " cursor: pointer;\n", + " display: none;\n", + " fill: var(--fill-color);\n", + " height: 32px;\n", + " padding: 0;\n", + " width: 32px;\n", + " }\n", + "\n", + " .colab-df-quickchart:hover {\n", + " background-color: var(--hover-bg-color);\n", + " box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n", + " fill: var(--button-hover-fill-color);\n", + " }\n", + "\n", + " .colab-df-quickchart-complete:disabled,\n", + " .colab-df-quickchart-complete:disabled:hover {\n", + " background-color: var(--disabled-bg-color);\n", + " fill: var(--disabled-fill-color);\n", + " box-shadow: none;\n", + " }\n", + "\n", + " .colab-df-spinner {\n", + " border: 2px solid var(--fill-color);\n", + " border-color: transparent;\n", + " border-bottom-color: var(--fill-color);\n", + " animation:\n", + " spin 1s steps(1) infinite;\n", + " }\n", + "\n", + " @keyframes spin {\n", + " 0% {\n", + " border-color: transparent;\n", + " border-bottom-color: var(--fill-color);\n", + " border-left-color: var(--fill-color);\n", + " }\n", + " 20% {\n", + " border-color: transparent;\n", + " border-left-color: var(--fill-color);\n", + " border-top-color: var(--fill-color);\n", + " }\n", + " 30% {\n", + " border-color: transparent;\n", + " border-left-color: var(--fill-color);\n", + " border-top-color: var(--fill-color);\n", + " border-right-color: var(--fill-color);\n", + " }\n", + " 40% {\n", + " border-color: transparent;\n", + " border-right-color: var(--fill-color);\n", + " border-top-color: var(--fill-color);\n", + " }\n", + " 60% {\n", + " border-color: transparent;\n", + " border-right-color: var(--fill-color);\n", + " }\n", + " 80% {\n", + " border-color: transparent;\n", + " border-right-color: var(--fill-color);\n", + " border-bottom-color: var(--fill-color);\n", + " }\n", + " 90% {\n", + " border-color: transparent;\n", + " border-bottom-color: var(--fill-color);\n", + " }\n", + " }\n", + "</style>\n", + "\n", + " <script>\n", + " async function quickchart(key) {\n", + " const quickchartButtonEl =\n", + " document.querySelector('#' + key + ' button');\n", + " quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n", + " quickchartButtonEl.classList.add('colab-df-spinner');\n", + " try {\n", + " const charts = await google.colab.kernel.invokeFunction(\n", + " 'suggestCharts', [key], {});\n", + " } catch (error) {\n", + " console.error('Error during call to suggestCharts:', error);\n", + " }\n", + " quickchartButtonEl.classList.remove('colab-df-spinner');\n", + " quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n", + " }\n", + " (() => {\n", + " let quickchartButtonEl =\n", + " document.querySelector('#df-34af8841-7076-498a-9e0b-c0e2357031b6 button');\n", + " quickchartButtonEl.style.display =\n", + " google.colab.kernel.accessAllowed ? 'block' : 'none';\n", + " })();\n", + " </script>\n", + "</div>\n", + " </div>\n", + " </div>\n" + ], + "text/plain": [ + " year quarter realgdp realcons realinv realgovt realdpi cpi \\\n", + "0 1959.0 1.0 2710.349 1707.4 286.898 470.045 1886.9 28.98 \n", + "1 1959.0 2.0 2778.801 1733.7 310.859 481.301 1919.7 29.15 \n", + "2 1959.0 3.0 2775.488 1751.8 289.226 491.260 1916.4 29.35 \n", + "3 1959.0 4.0 2785.204 1753.7 299.356 484.052 1931.3 29.37 \n", + "4 1960.0 1.0 2847.699 1770.5 331.722 462.199 1955.5 29.54 \n", + "\n", + " m1 tbilrate unemp pop infl realint \n", + "0 139.7 2.82 5.8 177.146 0.00 0.00 \n", + "1 141.7 3.08 5.1 177.830 2.34 0.74 \n", + "2 140.5 3.82 5.3 178.657 2.74 1.09 \n", + "3 140.0 4.33 5.6 179.386 0.27 4.06 \n", + "4 139.6 3.50 5.2 180.007 2.31 1.19 " + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "markdown", + "id": "cdcd575a", + "metadata": { + "id": "cdcd575a" + }, + "source": [ + "### Data overview\n", + "\n", + "Dataset contains USA quarterly macroeconomic data between 1959 and 2009.\n", + "\n", + "**Target variable - `realgdp`**" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "85619169", + "metadata": { + "id": "85619169" + }, + "outputs": [], + "source": [ + "df['q_date'] = df.apply(lambda x: str(int(x['year'])) + \"-\" + 'Q'+ str(int(x['quarter'])), axis=1)\n", + "df['date'] = pd.PeriodIndex(df['q_date'], freq='Q').to_timestamp()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "d9529063", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 214 + }, + "id": "d9529063", + "outputId": "856234d4-5d6a-46bb-de59-091f49ea4b98" + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " <div id=\"df-77b0ca1d-7761-4c8c-981e-2efe12d93883\" class=\"colab-df-container\">\n", + " <div>\n", + "<style scoped>\n", + " .dataframe tbody tr th:only-of-type {\n", + " vertical-align: middle;\n", + " }\n", + "\n", + " .dataframe tbody tr th {\n", + " vertical-align: top;\n", + " }\n", + "\n", + " .dataframe thead th {\n", + " text-align: right;\n", + " }\n", + "</style>\n", + "<table border=\"1\" class=\"dataframe\">\n", + " <thead>\n", + " <tr style=\"text-align: right;\">\n", + " <th></th>\n", + " <th>year</th>\n", + " <th>quarter</th>\n", + " <th>realgdp</th>\n", + " <th>realcons</th>\n", + " <th>realinv</th>\n", + " <th>realgovt</th>\n", + " <th>realdpi</th>\n", + " <th>cpi</th>\n", + " <th>m1</th>\n", + " <th>tbilrate</th>\n", + " <th>unemp</th>\n", + " <th>pop</th>\n", + " <th>infl</th>\n", + " <th>realint</th>\n", + " <th>q_date</th>\n", + " <th>date</th>\n", + " </tr>\n", + " </thead>\n", + " <tbody>\n", + " <tr>\n", + " <th>0</th>\n", + " <td>1959.0</td>\n", + " <td>1.0</td>\n", + " <td>2710.349</td>\n", + " <td>1707.4</td>\n", + " <td>286.898</td>\n", + " <td>470.045</td>\n", + " <td>1886.9</td>\n", + " <td>28.98</td>\n", + " <td>139.7</td>\n", + " <td>2.82</td>\n", + " <td>5.8</td>\n", + " <td>177.146</td>\n", + " <td>0.00</td>\n", + " <td>0.00</td>\n", + " <td>1959-Q1</td>\n", + " <td>1959-01-01</td>\n", + " </tr>\n", + " <tr>\n", + " <th>1</th>\n", + " <td>1959.0</td>\n", + " <td>2.0</td>\n", + " <td>2778.801</td>\n", + " <td>1733.7</td>\n", + " <td>310.859</td>\n", + " <td>481.301</td>\n", + " <td>1919.7</td>\n", + " <td>29.15</td>\n", + " <td>141.7</td>\n", + " <td>3.08</td>\n", + " <td>5.1</td>\n", + " <td>177.830</td>\n", + " <td>2.34</td>\n", + " <td>0.74</td>\n", + " <td>1959-Q2</td>\n", + " <td>1959-04-01</td>\n", + " </tr>\n", + " <tr>\n", + " <th>2</th>\n", + " <td>1959.0</td>\n", + " <td>3.0</td>\n", + " <td>2775.488</td>\n", + " <td>1751.8</td>\n", + " <td>289.226</td>\n", + " <td>491.260</td>\n", + " <td>1916.4</td>\n", + " <td>29.35</td>\n", + " <td>140.5</td>\n", + " <td>3.82</td>\n", + " <td>5.3</td>\n", + " <td>178.657</td>\n", + " <td>2.74</td>\n", + " <td>1.09</td>\n", + " <td>1959-Q3</td>\n", + " <td>1959-07-01</td>\n", + " </tr>\n", + " <tr>\n", + " <th>3</th>\n", + " <td>1959.0</td>\n", + " <td>4.0</td>\n", + " <td>2785.204</td>\n", + " <td>1753.7</td>\n", + " <td>299.356</td>\n", + " <td>484.052</td>\n", + " <td>1931.3</td>\n", + " <td>29.37</td>\n", + " <td>140.0</td>\n", + " <td>4.33</td>\n", + " <td>5.6</td>\n", + " <td>179.386</td>\n", + " <td>0.27</td>\n", + " <td>4.06</td>\n", + " <td>1959-Q4</td>\n", + " <td>1959-10-01</td>\n", + " </tr>\n", + " <tr>\n", + " <th>4</th>\n", + " <td>1960.0</td>\n", + " <td>1.0</td>\n", + " <td>2847.699</td>\n", + " <td>1770.5</td>\n", + " <td>331.722</td>\n", + " <td>462.199</td>\n", + " <td>1955.5</td>\n", + " <td>29.54</td>\n", + " <td>139.6</td>\n", + " <td>3.50</td>\n", + " <td>5.2</td>\n", + " <td>180.007</td>\n", + " <td>2.31</td>\n", + " <td>1.19</td>\n", + " <td>1960-Q1</td>\n", + " <td>1960-01-01</td>\n", + " </tr>\n", + " </tbody>\n", + "</table>\n", + "</div>\n", + " <div class=\"colab-df-buttons\">\n", + "\n", + " <div class=\"colab-df-container\">\n", + " <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-77b0ca1d-7761-4c8c-981e-2efe12d93883')\"\n", + " title=\"Convert this dataframe to an interactive table.\"\n", + " style=\"display:none;\">\n", + "\n", + " <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n", + " <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n", + " </svg>\n", + " </button>\n", + "\n", + " <style>\n", + " .colab-df-container {\n", + " display:flex;\n", + " gap: 12px;\n", + " }\n", + "\n", + " .colab-df-convert {\n", + " background-color: #E8F0FE;\n", + " border: none;\n", + " border-radius: 50%;\n", + " cursor: pointer;\n", + " display: none;\n", + " fill: #1967D2;\n", + " height: 32px;\n", + " padding: 0 0 0 0;\n", + " width: 32px;\n", + " }\n", + "\n", + " .colab-df-convert:hover {\n", + " background-color: #E2EBFA;\n", + " box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n", + " fill: #174EA6;\n", + " }\n", + "\n", + " .colab-df-buttons div {\n", + " margin-bottom: 4px;\n", + " }\n", + "\n", + " [theme=dark] .colab-df-convert {\n", + " background-color: #3B4455;\n", + " fill: #D2E3FC;\n", + " }\n", + "\n", + " [theme=dark] .colab-df-convert:hover {\n", + " background-color: #434B5C;\n", + " box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n", + " filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n", + " fill: #FFFFFF;\n", + " }\n", + " </style>\n", + "\n", + " <script>\n", + " const buttonEl =\n", + " document.querySelector('#df-77b0ca1d-7761-4c8c-981e-2efe12d93883 button.colab-df-convert');\n", + " buttonEl.style.display =\n", + " google.colab.kernel.accessAllowed ? 'block' : 'none';\n", + "\n", + " async function convertToInteractive(key) {\n", + " const element = document.querySelector('#df-77b0ca1d-7761-4c8c-981e-2efe12d93883');\n", + " const dataTable =\n", + " await google.colab.kernel.invokeFunction('convertToInteractive',\n", + " [key], {});\n", + " if (!dataTable) return;\n", + "\n", + " const docLinkHtml = 'Like what you see? Visit the ' +\n", + " '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n", + " + ' to learn more about interactive tables.';\n", + " element.innerHTML = '';\n", + " dataTable['output_type'] = 'display_data';\n", + " await google.colab.output.renderOutput(dataTable, element);\n", + " const docLink = document.createElement('div');\n", + " docLink.innerHTML = docLinkHtml;\n", + " element.appendChild(docLink);\n", + " }\n", + " </script>\n", + " </div>\n", + "\n", + "\n", + "<div id=\"df-0d62868d-3511-4048-98b6-b0d1d4cd3e1b\">\n", + " <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-0d62868d-3511-4048-98b6-b0d1d4cd3e1b')\"\n", + " title=\"Suggest charts\"\n", + " style=\"display:none;\">\n", + "\n", + "<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n", + " width=\"24px\">\n", + " <g>\n", + " <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n", + " </g>\n", + "</svg>\n", + " </button>\n", + "\n", + "<style>\n", + " .colab-df-quickchart {\n", + " --bg-color: #E8F0FE;\n", + " --fill-color: #1967D2;\n", + " --hover-bg-color: #E2EBFA;\n", + " --hover-fill-color: #174EA6;\n", + " --disabled-fill-color: #AAA;\n", + " --disabled-bg-color: #DDD;\n", + " }\n", + "\n", + " [theme=dark] .colab-df-quickchart {\n", + " --bg-color: #3B4455;\n", + " --fill-color: #D2E3FC;\n", + " --hover-bg-color: #434B5C;\n", + " --hover-fill-color: #FFFFFF;\n", + " --disabled-bg-color: #3B4455;\n", + " --disabled-fill-color: #666;\n", + " }\n", + "\n", + " .colab-df-quickchart {\n", + " background-color: var(--bg-color);\n", + " border: none;\n", + " border-radius: 50%;\n", + " cursor: pointer;\n", + " display: none;\n", + " fill: var(--fill-color);\n", + " height: 32px;\n", + " padding: 0;\n", + " width: 32px;\n", + " }\n", + "\n", + " .colab-df-quickchart:hover {\n", + " background-color: var(--hover-bg-color);\n", + " box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n", + " fill: var(--button-hover-fill-color);\n", + " }\n", + "\n", + " .colab-df-quickchart-complete:disabled,\n", + " .colab-df-quickchart-complete:disabled:hover {\n", + " background-color: var(--disabled-bg-color);\n", + " fill: var(--disabled-fill-color);\n", + " box-shadow: none;\n", + " }\n", + "\n", + " .colab-df-spinner {\n", + " border: 2px solid var(--fill-color);\n", + " border-color: transparent;\n", + " border-bottom-color: var(--fill-color);\n", + " animation:\n", + " spin 1s steps(1) infinite;\n", + " }\n", + "\n", + " @keyframes spin {\n", + " 0% {\n", + " border-color: transparent;\n", + " border-bottom-color: var(--fill-color);\n", + " border-left-color: var(--fill-color);\n", + " }\n", + " 20% {\n", + " border-color: transparent;\n", + " border-left-color: var(--fill-color);\n", + " border-top-color: var(--fill-color);\n", + " }\n", + " 30% {\n", + " border-color: transparent;\n", + " border-left-color: var(--fill-color);\n", + " border-top-color: var(--fill-color);\n", + " border-right-color: var(--fill-color);\n", + " }\n", + " 40% {\n", + " border-color: transparent;\n", + " border-right-color: var(--fill-color);\n", + " border-top-color: var(--fill-color);\n", + " }\n", + " 60% {\n", + " border-color: transparent;\n", + " border-right-color: var(--fill-color);\n", + " }\n", + " 80% {\n", + " border-color: transparent;\n", + " border-right-color: var(--fill-color);\n", + " border-bottom-color: var(--fill-color);\n", + " }\n", + " 90% {\n", + " border-color: transparent;\n", + " border-bottom-color: var(--fill-color);\n", + " }\n", + " }\n", + "</style>\n", + "\n", + " <script>\n", + " async function quickchart(key) {\n", + " const quickchartButtonEl =\n", + " document.querySelector('#' + key + ' button');\n", + " quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n", + " quickchartButtonEl.classList.add('colab-df-spinner');\n", + " try {\n", + " const charts = await google.colab.kernel.invokeFunction(\n", + " 'suggestCharts', [key], {});\n", + " } catch (error) {\n", + " console.error('Error during call to suggestCharts:', error);\n", + " }\n", + " quickchartButtonEl.classList.remove('colab-df-spinner');\n", + " quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n", + " }\n", + " (() => {\n", + " let quickchartButtonEl =\n", + " document.querySelector('#df-0d62868d-3511-4048-98b6-b0d1d4cd3e1b button');\n", + " quickchartButtonEl.style.display =\n", + " google.colab.kernel.accessAllowed ? 'block' : 'none';\n", + " })();\n", + " </script>\n", + "</div>\n", + " </div>\n", + " </div>\n" + ], + "text/plain": [ + " year quarter realgdp realcons realinv realgovt realdpi cpi \\\n", + "0 1959.0 1.0 2710.349 1707.4 286.898 470.045 1886.9 28.98 \n", + "1 1959.0 2.0 2778.801 1733.7 310.859 481.301 1919.7 29.15 \n", + "2 1959.0 3.0 2775.488 1751.8 289.226 491.260 1916.4 29.35 \n", + "3 1959.0 4.0 2785.204 1753.7 299.356 484.052 1931.3 29.37 \n", + "4 1960.0 1.0 2847.699 1770.5 331.722 462.199 1955.5 29.54 \n", + "\n", + " m1 tbilrate unemp pop infl realint q_date date \n", + "0 139.7 2.82 5.8 177.146 0.00 0.00 1959-Q1 1959-01-01 \n", + "1 141.7 3.08 5.1 177.830 2.34 0.74 1959-Q2 1959-04-01 \n", + "2 140.5 3.82 5.3 178.657 2.74 1.09 1959-Q3 1959-07-01 \n", + "3 140.0 4.33 5.6 179.386 0.27 4.06 1959-Q4 1959-10-01 \n", + "4 139.6 3.50 5.2 180.007 2.31 1.19 1960-Q1 1960-01-01 " + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "b53d0557", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 530 + }, + "id": "b53d0557", + "outputId": "dfb17682-8a89-43c1-953a-b9c2319ff749" + }, + "outputs": [ + { + "data": { + "image/png": "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jARplMtlHDlypKlsjoyMgDFGZZM4KsdTNjuhm8omifnTgPXr1wMAnn766Ui4Pz8kn88DAKampgAAH/zgB3HFFVfgG9/4Bq666ircdddd+MEPfhAcVygUIhYon2w2G6RFEJ3Qadls5Gc/+xlisRiuuOKKSHihUEAmk2mKT2WTOB46LZ+6ruPb3/428vk8Lr/8crz61a/GZz7zGXz+85/H9u3bg+OofBKLRadlc8OGDRgbG8P4+HgQp1QqYffu3ZibmwvC6L1OHC+/+c1vcN999+Gv/uqvANTLXmNd53/393dS5orFYsu0TNNEIpGgskksyPGWzU7oprJJYv40YPPmzTj//PPxmc98Bjt37sTs7Cy+/vWv49e//jWA+lASIQQA4JprrsF73vMeXHDBBfjgBz+Iq666Cl/96ldPWf6J5UunZTOMEAL33nsvLrnkEqTT6Zc7y8RpRKfls1qt4n3vex+klPjyl7+Mb33rW7jmmmtw22234b//+79P5SUQy5ROy+ZVV12FVCqF22+/HQcPHsTY2Bg+8pGPoFwudzSMlCAWYmxsDB/4wAfw2te+Fm9/+9tPdXYIIuB0Kpsk5k8T7rjjDvT29uK6667DBRdcgH/+53/GX//1XwNAMOfY71264IILIsdeeOGFOHLkSLBETSaTablcTT6fRzabPZmXQSxDOimbYX71q19hcnISb3rTm5r2ZTKZoLc0DJVN4njppHz++Mc/xtNPP427774bl19+OS688EJ84hOfwHnnnYfPfe5zQVpUPonFpJOymcvl8LnPfQ4vvPACLr/8crzuda/D5OQkrrnmmkj9Su914lgpFAq48cYbkcvl8MUvfjHw8+CXl8a6rlAoRPZ3UuZ8y31jWpZloVKpUNkkWnKiZbMTuqls6i/bmYhTytq1a3HPPffg0KFDqFar2LhxI775zW9icHAQq1evBgCceeaZC6bhz9EbGRnBCy+8ENknpcS+ffsijkwIohM6KZthfvrTnyKTyeB1r3td077wXDufYrGIycnJpnlNBNEJnZTP3bt3Y2hoqMn5ztatW/GTn/wk+E7lk1hMOq07/+AP/gD/9V//hf3798M0TaxduxbvfOc7sW3btiAOvdeJY6FareJd73oXisUifvjDH0aGy/t1WaMfhr1798IwDKxduzaI99hjj0FKGRklsm/fPmzevBkAkEwmMTw83FRv7tu3D1JKqjeJJhajbHZCN5VNssyfZqxZswZnnHEGbNvGj3/8Y/zZn/1ZsG/btm3I5XJ49NFHI8c8+uijWLVqVdBQ3bFjB5577jns378/iPPYY49hbm6upcAiiE5YqGz6WJaFn//853j961/f0qnTjh078Oijjwa9rABw//33g3NODVLihFiofK5atQpjY2OYmZmJHLNr166IqKLySZwMOqk7NU3Dpk2bsHbtWuzZswePPvpoJB6914lOcRwHt9xyC/bu3Yt/+qd/wtDQUGT/2rVrsWHDBtx///2R8Pvuuw8XXnhh8O7esWMH8vk8HnvssSDOvn378Mwzz2DHjh1B2I4dO/CLX/wCtm1H0spkMhGfJASxWGWzU7qlbJJlfhlQqVSCpWNGR0cxPz8fFNTXvOY16Ovrw/e+9z2k02kMDw9jdHQU3/zmNxGLxXDjjTcG6RiGgZtvvhmf/vSnkc1mcd555+Ghhx7Cvffei09+8pNBvDe84Q24++67cfPNN+PWW29FpVLBnXfeiUsuuQTnnnvuy3vxRFezWGXT54EHHkChUGg5xB4ArrvuOnz3u9/FTTfdhHe9610YHx/HnXfeieuuu66pUieIxSqfb3rTm3D33XfjxhtvxDvf+U6kUincf//9ePzxx3HnnXcG8ah8Ep2ymHXnXXfdhW3btiGdTuP555/HV77yFVxzzTW48MILgzj0Xic65ROf+AR++ctf4sMf/jDm5+cDp4sAcPbZZ8M0Tdx888344Ac/iHXr1uG1r30t7rvvPjz99NP43ve+F8Tdvn07Lr74Ytx+++340Ic+hFgshs9//vPYsmVLxLntO97xDvz0pz/Fbbfdhre+9a144YUX8PWvfx0f+MAHjll8EcubxSqbgGpvVioV/P73vwcA/PKXv0QqlcIZZ5yBM844A0D3lE0mw4vgEkuSQ4cO4bLLLmu57zvf+Q5e+9rX4hvf+Aa+//3vY2xsDLlcDldccQXe//73t5zT8d3vfhff/va3MTY2htWrV+OGG25o6ukfHx/Hpz71KTz88MPQdR2vf/3rcfvtt5NDMiLCYpfN973vfXjiiSfw4IMPtl2Hec+ePfjkJz+JnTt3IpVK4eqrr6aXPtGSxSyfu3btwj/8wz9g165dqFar2LBhA66//npcffXVkXhUPolOWMyyedttt+Hxxx9HPp/HmjVrcO211+Ltb387NE2LxKP3OtEJf/iHf4jR0dGW+37xi19gzZo1AIAf/ehH+NrXvobDhw9j48aNuPXWW3HppZdG4heLRXz605/Gz3/+cziOg4svvhgf+chHmjo3n3jiCdxxxx149tln0dfXh7e97W248cYbyYkjEWExy2a7tN773vfi5ptvDr53Q9kkMU8QBEEQBEEQBEEQSwyaM08QBEEQBEEQBEEQSwwS8wRBEARBEARBEASxxCAxTxAEQRAEQRAEQRBLDBLzBEEQBEEQBEEQBLHEIDFPEARBEARBEARBEEsMEvMEQRAEQRAEQRAEscQgMU8QBEEQBEEQBEEQSwwS8wRBEARBEARBEASxxCAxTxAEQRAEQRAEQRBLDBLzBEEQBEEQBEEQBLHEIDFPEARBEARBEARBEEsMEvMEQRAEQRAEQRAEscT4/wEVA7/XUn5SCgAAAABJRU5ErkJggg==", + "text/plain": [ + "<Figure size 1200x600 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "for val in df.columns[2:14]:\n", + " plt.plot(df.date, df[val], label = val)\n", + "plt.legend();" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "c89a7230-33f7-42fa-9f31-90f6f38448a9", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "c89a7230-33f7-42fa-9f31-90f6f38448a9", + "outputId": "29f889a3-72ff-4c97-f7ce-2fd0235d826c" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['year', 'quarter', 'realgdp', 'realcons', 'realinv', 'realgovt',\n", + " 'realdpi', 'cpi', 'm1', 'tbilrate', 'unemp', 'pop', 'infl', 'realint',\n", + " 'q_date', 'date'],\n", + " dtype='object')" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.columns" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "8b17033d", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "8b17033d", + "outputId": "39adfd46-b976-4ebe-b9d1-bc3901b35d9f", + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "PeriodIndex(['1959Q1', '1959Q2', '1959Q3', '1959Q4', '1960Q1', '1960Q2',\n", + " '1960Q3', '1960Q4', '1961Q1', '1961Q2',\n", + " ...\n", + " '2007Q2', '2007Q3', '2007Q4', '2008Q1', '2008Q2', '2008Q3',\n", + " '2008Q4', '2009Q1', '2009Q2', '2009Q3'],\n", + " dtype='period[Q-DEC]', name='date', length=203)" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = df.set_index('date').to_period(\"Q\")\n", + "df.index" + ] + }, + { + "cell_type": "markdown", + "id": "746efe42", + "metadata": { + "id": "746efe42" + }, + "source": [ + "## 1. Unified API" + ] + }, + { + "cell_type": "markdown", + "id": "632599a2", + "metadata": { + "id": "632599a2" + }, + "source": [ + "### Basic forecasters interface" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "95bbf1c7", + "metadata": { + "id": "95bbf1c7" + }, + "outputs": [], + "source": [ + "y = df['realgdp']\n", + "y_train, y_test = temporal_train_test_split(y, test_size=30)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "59a99374", + "metadata": { + "id": "59a99374" + }, + "outputs": [], + "source": [ + "forecaster = NaiveForecaster()\n", + "forecaster.fit(y_train)\n", + "y_pred = forecaster.predict(fh=1) #forecasting one step ahead" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "831cf6a8", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "831cf6a8", + "outputId": "2ecaca4b-4109-4a19-a61a-b2101051c3da", + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "2002Q2 11477.868\n", + "Freq: Q-DEC, Name: realgdp, dtype: float64" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "y_pred" + ] + }, + { + "cell_type": "markdown", + "id": "28d6351b", + "metadata": { + "id": "28d6351b" + }, + "source": [ + "### Forecasting horizons" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "47684b1e", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "47684b1e", + "outputId": "4f72af3c-7bbd-4887-e231-b1b699ef774e", + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "ForecastingHorizon(['2002Q2', '2002Q3', '2002Q4', '2003Q1', '2003Q2', '2003Q3',\n", + " '2003Q4', '2004Q1', '2004Q2', '2004Q3', '2004Q4', '2005Q1',\n", + " '2005Q2', '2005Q3', '2005Q4', '2006Q1', '2006Q2', '2006Q3',\n", + " '2006Q4', '2007Q1', '2007Q2', '2007Q3', '2007Q4', '2008Q1',\n", + " '2008Q2', '2008Q3', '2008Q4', '2009Q1', '2009Q2', '2009Q3'],\n", + " dtype='period[Q-DEC]', name='date', is_relative=False)" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fh_abs = ForecastingHorizon(y_test.index, is_relative=False) #specific data points\n", + "fh_abs" + ] + }, + { + "cell_type": "markdown", + "id": "63ed7cf0", + "metadata": { + "id": "63ed7cf0" + }, + "source": [ + "**Forecasts on the test set**" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "69dfa56d", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "69dfa56d", + "outputId": "50500432-938a-4d1a-e765-7d9f9d89d56a", + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "ForecastingHorizon([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,\n", + " 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],\n", + " dtype='int64', is_relative=True)" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#cutoff is the last point in the training series\n", + "cutoff = pd.Period(\"2002-01-01\", freq=\"Q\")\n", + "\n", + "#forecasting 1, 2, ..., 30 steps ahead of the last point in the training series\n", + "fh_rel = fh_abs.to_relative(cutoff)\n", + "fh_rel" + ] + }, + { + "cell_type": "markdown", + "id": "e8206c7c", + "metadata": { + "id": "e8206c7c" + }, + "source": [ + "**In-sample forecasts**" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "d8ec488c", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "d8ec488c", + "outputId": "9b7210f5-910d-44c4-e29e-2a62302dd447" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "ForecastingHorizon([-29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17,\n", + " -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4,\n", + " -3, -2, -1, 0],\n", + " dtype='int64', is_relative=True)" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#cutoff is 29 quarters after the last point in the training series\n", + "cutoff_insample = pd.Period(\"2009-09-01\", freq=\"Q\")\n", + "\n", + "#forecasting 0, 1, ..., 29 steps before the last point in the training series\n", + "fh_rel_insample = fh_abs.to_relative(cutoff_insample)\n", + "fh_rel_insample" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "e724f098", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 346 + }, + "id": "e724f098", + "outputId": "32ca1c27-bbcc-4962-d733-adad9ee2adb2" + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABUAAAAFkCAYAAADhdJEIAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAC1bUlEQVR4nOzdeXwTdf4/8NdMriZt0/TikqtUCrigoMgZ7ksucV28VlkVRP1yo7KcoghKxQspIsrhjSf6EwWFoggWUZcvIutXkCIgVShXmzZt7mR+f5QMmSZpk9JCW17Px8NH6eQzk5nsx668+z4ESZIkEBEREREREREREdVD4qW+ASIiIiIiIiIiIqKawgAoERERERERERER1VsMgBIREREREREREVG9xQAoERERERERERER1VsMgBIREREREREREVG9xQAoERERERERERER1VsMgBIREREREREREVG9xQAoERERERERERER1VsMgBIREREREREREVG9pb7UN3A5kyQJPp90qW+jxoiiUK+fj6oX9wtFinuFosH9QpHiXqFocL9QpLhXKBrcLxQp7pXzRFGAIAiVrmMA9BLy+SQUFJRe6tuoEWq1iMTEWBQX2+Dx+C717VAtx/1CkeJeoWhwv1CkuFcoGtwvFCnuFYoG9wtFintFKSkpFipV5QFQlsATERERERERERFRvcUAKBEREREREREREdVbDIASERERERERERFRvcUAKBEREREREREREdVbHIJUB/h8Xni93kt9G1Hx+QQ4HCq4XE54vZxMRmVUKhVEUXWpb4OIiIiIiIiILiMMgNZikiShuLgAdnspgLoXRDxzRoTPx4lkFEiAXh8LozEJglD5lDYiIiIiIiIiogvFAGgtZreXwm4vQVycCTpdDIC6FTBSqQRmf1IACU6nAyUlFmg0OhgMcZf6hoiIiIiIiIjoMsAAaC0lSRJKSiyIiYlFXFzCpb6dKlGrRXg8zACl8zQaHTweN0pKLNDrY5kFSkRERERERHWaIAgQRQE+nwRJqjwJLNr1VD0YAK2lfD4ffD4vYmIMl/pWiKpVTIwBDkcpfD4fVCr2AyUiIiIiIqK6R6USYdB5oY3RweewQIwxweVwwOZUwev1BQU6K1tPNYsB0FrK5ysbesSBMVTf+Pe0z+dlAJSIiIiIiIjqDH9QUxAAY5yI4t3P4uTel+BzWiDq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IWsxVsgWjBeyFmNFqkaNKnBwePgMn6wAJbsRirSY2M4XAB5avVmyotJQpSmpstTokKc20W7u2DasqG6uL1dlJyIiIiIiIiKqfJgAJbvR6fRQ5RuGkzdErloDDxdHKNUai3NnMiFJRERERERERETlhQlQsiudTg+oiqDSalHbswqyswug1bAkm4iIiIiIiIiIHo+HD5InKgPDiHVOpUlERERERERERI8TE6BERERERERERERUaTEBSkRERERERERERJUWE6BERERERERERERUaTEBSkRERERERERERJUWE6BERERERERERERUaTEBSkRERERERERERJWWTBAE4XGfxLNKEATo9ZX37XdwkEOn0z/u06CnBOOFrMVYIVswXshajBWyBeOFrMVYIVswXshajJW/yeUyyGSyh/ZjApSIiIiIiIiIiIgqLQ6BJyIiIiIiIiIiokqLCVAiIiIiIiIiIiKqtJgAJSIiIiIiIiIiokqLCVAiIiIiIiIiIiKqtJgAJSIiIiIiIiIiokqLCVAiIiIiIiIiIiKqtJgAJSIiIiIiIiIiokqLCVAiIiIiIiIiIiKqtJgAJSIiIiIiIiIiokqLCVAiIiIiIiIiIiKqtJgAJSIiIiIiIiIiokqLCVAiIiIiIiIiIiKqtJgAfYZcvXoV06ZNQ9euXdGoUSN06dLFqE9RUREWLlyIyMhING3aFP/85z9x+PBho37+/v5Gf1q1amXUb+/evejevTsaN26MNm3aYMmSJdDpdEb91Go1PvvsM7z++uto0qQJwsPDMXz4cKSlpRn1TU1Nxbhx49CxY0f4+/tj5syZZXxHyBx7xgoApKenY8SIEQgNDUVQUBC6deuG1NRUcfvRo0dNxtSYMWOM9mVtrOh0OiQlJaFv374IDw9HWFgYYmJicPz48Ud8d6g0e8XL5s2bTcaBv78/Bg8ebNPxDHJycjB//nx07NgRjRs3xquvvopx48YhMzPTqO/8+fPxxhtvIDg4GM2bN0ePHj2wY8eOR3hnqLSKjpWYmBiz/Ur/29oSKyXt3r0b/v7+FuOQysaen0U3b97E2LFjERkZieDgYPTo0QM///yz2WMXFBQgKioK/v7++P3334222xIvycnJiI+PF/e3evVqG98Jehh7xsqdO3cwevRotGjRAsHBwRg2bBiuX79usl98fDyCg4MRFhaGyZMnIz8/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Wq2Gl5cX+vfvj65du5o9/tGjR9GvXz9s3LjRaISLLfGydOlSLFu2zGj//CyyH3vGyrhx43DkyBHk5OSgfv36ePvtt9GvXz+jRZDu3LmDDz/8EAcPHoRCoUB0dDQSEhKMKrb43PLkeRzxolQq8cknn2DHjh3Iz89HYGAgJkyYYPTFnFarxTfffINNmzYhIyNDHCI/f/58oxFxc+fOxYEDB3Dr1i0oFArUr18f3bp1Q58+fbjYjZ20b98eN2/eNLnt119/Rf369QEAP/zwA5KSknDr1i14e3tj7NixYuWvQV5eHubOnYtdu3ZBq9UiMjISU6ZMkVQK+vv7mz2X0r/nZmVlYfny5di/fz/u3bsHvV4PLy8vJCUl4cUXX7R4XTExMXBzc0NiYqLFfmS9io6V1NRULFiwAFevXoVCoUBYWBjGjRtn9CU9wGeWkpgApSfSsWPHMHDgQAwfPhwjRox43KdDTzDGCtli+/btGD9+PObNm8epNcgixgrZgvFC1uJzC9kiPT0dPXv2ROfOnTF79uzHfTr0BEtMTMTSpUuRlJRkVEBEVNKz/MzCOUDpiRQaGopJkyZhyZIl2LJly+M+HXqCMVbIFl26dMHAgQMxZcoUydw6RKUxVsgWjBeyFp9byBa+vr5YuHAhNm3ahM8+++xxnw49wYYOHYoOHTogPj5eMoUGUWnP8jMLK0CJiIiIiIiIiIio0mIFKBEREREREREREVVaTIASERERERERERFRpcUEKBEREREREREREVVaTIASERERERERERFRpcUEKBEREREREREREVVaTIASERERERERERFRpcUEKBEREREREREREVVaTIASERERERERERFRpcUEKBEREREREREREVVaTIASERERERERERFRpfX/C75L466nZPwAAAAASUVORK5CYII=", + "text/plain": [ + "<Figure size 1600x400 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "forecaster = NaiveForecaster()\n", + "forecaster.fit(y_train)\n", + "y_pred = forecaster.predict(fh=fh_rel)\n", + "y_pred_insample = forecaster.predict(fh=fh_rel_insample)\n", + "\n", + "plot_series(y_train, y_test, y_pred, y_pred_insample, labels=[\"y_train\", \"y_test\", \"y_pred\", \"y_pred_insample\"]);" + ] + }, + { + "cell_type": "markdown", + "id": "7b7017ad", + "metadata": { + "id": "7b7017ad" + }, + "source": [ + "**Forward forecasts**" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "5032d756", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "5032d756", + "outputId": "a8111b9e-c7b6-48b7-b4d8-9f0a2e89c3e9" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "ForecastingHorizon([13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,\n", + " 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42],\n", + " dtype='int64', is_relative=True)" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#cutoff is 12 quarters before the last point in the training series\n", + "cutoff_forward = pd.Period(\"1999-01-01\", freq=\"Q\")\n", + "\n", + "#forecasting 13, 14, ..., 42 steps after the last point in the training series\n", + "fh_rel_forward = fh_abs.to_relative(cutoff_forward)\n", + "fh_rel_forward" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "acdb1926", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 346 + }, + "id": "acdb1926", + "outputId": "b0f31fc8-b743-4804-8647-18fddc59ee12" + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABUAAAAFkCAYAAADhdJEIAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAACzJklEQVR4nOzdeXxTVdoH8N+92Zq0TdPSsslWCmUZFVAsW9g3QVBHcRtlRBD1RVaVgQKiCEplXCkiiqDjwsi4vS6gUgVhiojDsKivIIUWqUJla7plz73vH20uSZO06Ua33/fz4QM9Offk3nomA0+f5zyCLMsyiIiIiIiIiIiIiJogsb5vgIiIiIiIiIiIiKiuMABKRERERERERERETRYDoERERERERERERNRkMQBKRERERERERERETRYDoERERERERERERNRkMQBKRERERERERERETRYDoERERERERERERNRkMQBKRERERERERERETRYDoERERERERERERNRkqev7BpozWZYhSXJ930adEUWhST8fVQ33A/nifiAv7gXyxf1AvrgfyIt7gXxxP5Av7gcSRQGCIFQ6jwHQeiRJMi5cKKnv26gTarWI2NhIFBZa4XZL9X07VM+4H8gX9wN5cS+QL+4H8sX9QF7cC+SL+4F8cT8QAMTFRUKlqjwAyhJ4IiIiIiIiIiIiarIYACUiIiIiIiIiIqImiwFQIiIiIiIiIiIiarIYACUiIiIiIiIiIqImi02QGgFJ8sDj8dT3bVSJJAmw21VwOh3weNiRralTqVQQRVV93wYRERERERERUQAGQBswWZZRWHgBNlsJgMYXRDx3ToQksRNb8yBAr4+E0RgHQai8+xoRERERERER0aXCAGgDZrOVwGYrRlSUCTpdBIDGFVhSqQRmfzYLMhwOO4qLLdBodDAYour7hoiIiIiIiIiIFAyANlCyLKO42IKIiEhERcXU9+1Ui1otwu1mBmhzoNHo4Ha7UFxsgV4fySxQIiIiIiKiZkgQBIiiAEmSIcsVJ0RVZS5RTTEA2kBJkgRJ8iAiwlDft0IUlogIA+z2EkiSBJWK54ESERERERE1FyqVCIPOA22EDpLdAjHCBKfdDqtDBY9H8gt2iqJQ4VyiusAAaAMlSaVNj9hYhhoL716VJA8DoERERERERE2cN6gpCIAxSkThvmfwx8GXIDksEHUmGHvPREzfv8HtkqDRaZVgJyQPCoLOnY/CYkCWwaxQqnVifd8AVYylxNRYcK8SERERERE1fSqViGiDjLhYLYy6EhgjZRTuWwXL3ichOSwAAMlhQcnR9yFIDlgPPYfcV9shd3072E9+jYL/PB10rttyDCajBkZdCeJitYg2yFCpGLai2sGdRERERERERERElVKpRMREi7D98DxyX22H39/uDUEQUHjwpYC5seYnUfDf55Vgp6iPR0S7ISg8tNZvnia2O9rc8jWsWR/gZFmgNPfVdrD98AJiokUGQalWcBdRg7dhwyv48cdDtbrm/v37YDb3xZEjP9fqukRERERERERNjSAIUKlEREZ4/LI9VYbW8FjPKNmcXqI+HvoOI/yCnaHmxpqfROHBl2D5/im/rFDL3hUo3Pd3GHSeOn46ag4YAG1GvB9Yja1U+fXX1+PHH3+o1TW7deuOdeteR8eOibW6LhEREREREVFT4V/uboVWF+GX7emx5kFlaAlRZ/K/LkiwM9jcYIFSX4UH10AbEdHo4hjU8DAA2gyoVCLUei2iTXq4NCpEm/RQ67VNLo3c4bCHPTcyMgqXX34F9Hp9Hd4RERERERERUeNUvtw978OxcBef8gtqSrZzsJ3cDmOvGX7XBgt2BpsbKitUucZhgWQvhEbT+JK5qGFpWhEwCqBSidBH6fDC7hy0WZah/Hpx9wnoo3R1HgTNzNwFs7kvcnNP+o0XFhZixIhB+PDD9yq83mzuCwBYu/ZFmM19YTb3xf79+5TX3nrrDaxduxrXXz8WEyaMAQD89NMPWLBgHm644VqMGmXGlCl/wRdfbPFbN1gJvNncF++88w9s2PAKJk4cg+uuG4mnnloGm81W4+8DERERERERUWMQqty9NKiZEJDtmZ+5GMbeD8KUsujia5IbLks2jL1nBp/bbzFEnSlkBilQejZoqxs+hirCiEh1MRsjUY2o6/sGqGpkWYbVJYU9P9qoQdqOY1iekaWMWWwuPJFxFAAwc0BHlNhcYa1lqMZPXAYMGISEhJbYsuUTPPDAxQ++jIwvAACjR19b4fXr1r2OBx64B5Mm3YZRo0rnJiZeLFt///1/omfPK7Bw4aPweNwAgLy807jiil648cabodXq8OOPh5CWthyyLGPcuAkVvt8HH/wLvXr1weLFjyM39yTWrn0RsbFx+J//mVWl5yYiIiIiIiJqyARBgCgKkCQZslwaWDToPNBG6CDZC6DSxSDPp9zdN4PT8v1Tyrgr/whOvzcSCePfganfInjsBRAjYuByOBHTdz6A0lJ2bxC1+Oh7MF79EGJSUiHZCyDLMoy9Z8Kyd4WyprcxUuHBl3D2i7tLmyjpTDD2nomYvvNRUHTpvk/UNDAA2ojIsoyJ7xzAf34vDGt+fKQWOYtHIj3zRNDXV2fmYP7wJPR8di/OlTgrXS/lMiM+ubNPlYKgKpUK48dPxJYtn2D69P+BSqUCAGzZ8gmGDh2O6OjoCq+//PIrAAAtW7ZW/uwrOjoGTz31d797GjVqrPJnWZbRq1cfnDnzBz7++MNKA6AtWsTjscdKP3T79x+Io0eP4JtvvmYAlIiIiIiIiJoE/0CnBWKECS6HExqNiIJ9z+CPgy9BFdUOra7/MKA0PT9zMdrc8jUAoPDQWiUwGZk8CWpTF1gKXZBlAySbsyyoKsFw5VzEpCyEVBYYddrtKCgWIUlOiKIBghMwlguUxg15WmmM5OVtjAQAhivnwuZUXZpvGDUJDIA2MlXJv2wdrcOZYicsITI8LTYXzhY70TpaF1YAtLomTLgBb765EXv37sHAgWYcO5aFo0eP4MEH59R47f79BwYEZAsLC7Fx4yv497934ty5s/B4SjvGxcTEVLreNdf08/u6U6dEfP31thrfJxEREREREVF9857rWVgW6PQGMFtP+hoFxz6EZe+TpRNFtVLu7hsE9WZ7xg1OQ4d+i+BxFEDUlQU1iyR4PP4Vqx6PhCKrAMFWGuwsDYwKAKSy12UAQEERfAKlhVBFGHH2i7uDPkPhwTWISVkIuyu8atbyma7UPDEA2ogIgoBP7uwTdgm8KApoZdTBpNcEDYKa9Bq0Merw2Z19IEmVfwhUpwQeANq0aYtrrumHzz77GAMHmrFlyydo0+YyXHVV3yqvVV5cXFzA2FNPPY6ffvoBU6bci8TEJERGRuKjj97H9u0Zla4XFeWfkarRaOB01l1wmIiIiIiIiKg2BQv4ecdKz/V85mKgEwBENTSmzn7d3UOVuwOlQVDHH/sgthoMq8MAyeof1AxGlmUl2BmMb6BUozEg0m6ppDFSAQQhssLvQ7BMV6fdDqtDFRCopaaPAdBGRhAERGrDT/O22t2YbU5Uzvz0NducCKvdDb267g8QnjjxRixbtgRnz55BRsbnmDTp9lrq4Oa/hsPhwLffZmLmzHmYNOl2ZZw/5SEiIiIiIqKmxjfYKYpC0NJ2QIZGpw16ricQuhN7qHJ3Y++ZMPadHzTjs6ZkWYbLJUGMMgVkn3qJOhPEiBig2FX2Pbj4mvf7IQiAMSow09X3DFEGQZsXBkCbONnpxoLhSQBKz/y02Fww6TWYbU7EguFJsBU7Lsl9DB48DNHRRixbtgSFhYWVnsXpS61Ww+kM7z5dLhckSYJGo1HGrNYSZGbuqvI9ExERERERETVEwbIbIXmUMzwlhwXaVtegzU1bUbD/BRRWcK6nbyf2mpS71xZZluG02wMaI3mZ+i+Fx1GI6CgjPNYzMEaXD/RaIGgMSgd7r/JniBZZayMpixoLBkCbOI9Hgq3YgTmDOiF1ZBcU2NyI0athtbthK3Zcsp94qNVqjBt3HTZtegspKQPQqlXrsK/t2DERmZm70KtXH+j1enTo0BEGQ/BU96ioKPTo0RNvv/0GTCYTVCo13n77DURGRsFiuVBbj0NERERERERUL4Kd49nqho/hOL3Xr1zdlLIQBf99/uJYiHM9a7vcvTZYHaqADvKizgRT/6WIvmIaCr5/WslKLR/ohahG+6lZfiX9vrxniApljZqoeaj72meqdx6PBLfNiSKLDWqXG0UWG9w25yVP9x4yZDgA4Lrrrq/SdQ89tACSJOGRR2bj3nv/iiNHDlc4/7HHnkS7du3x5JOP44UX/o5hw0bi2mvHV/u+iYiIiIiIiBoKg86jZDdKDgtEfTwi2g1B4aG1yhxRHw99hxF+Y76BzvLyMxcj5up5MPVbAlFnKl1DZ4Kp3xIY+86H1SHC45EuWcDQ45FQUCRBf+VctL/vN7Sf/jva3/cbIntMRsH3T8Py/VNKEFcJ9JZ9P0KV9Ht5zxAVRWaANifMAG1GKjt0uK599923iImJweDBQ6t0Xa9evbFx49sB45mZ+4LOb9euPV588eWA8WnT7lf+fNVVfQOuD7berbf+Bbfe+pcq3S8RERERERFRbfKebSnLMrQROvzhk90YLOBX1XM9I5MnQRZ1MPTydmIvgBhR9+XuFSnfQV62OxFr0gcN9J7bNu3idSFK+pVrys4QlWxseNycMABKde7kyRM4efJXvP/+Ztx00y3QarX1fUtEREREREREDV7gWZ+xkOz5foG9YAG/6p3r6YHHI0CwlgYcJdulKXevjDeZS6USIZXrDh8s0FtRST8AGHvPhNNuL3s2ai5YAk91btWqp7B0aSr69LkKkyff4/ea2+0O+cvj8dTTHRMRERERERHVD0EQoFKJUKtLz/q0/fA8cl9th9z17fD7m1dC1EUrZepA8NL2isrdved6OuwOFNoNuJDvRJFVULI8SwOOl67cPVySJEOMMPk9u2+g11d+5mIYez8IU8qiECX9qkt349QgMAOU6tyaNa8GHT99+hRuuSX0eaC9e18V8loiIiIiIiKipqR8tmewTubuguOw/foVjL0f9BtXStsFAYVljZEs36ehzU1bAUH0ayRk7D0Txr7z6620vbqCdYcPle3pzXRNGP8OTP0WwdMASvqpfjEASvUmPj4Br732ZsjXDQbDJbwbIiIiIiIiokvLe7anIADGqIud3SvqZJ6fuRhtbt0OQFACmx5rHoqPvgfj1Q8hJiVVOcPT5XA2qHM9aypYd/hQgd7I5ElQm7rAUuiCLDeckn6qHwyAUr3RaDTo3r1nfd8GERERERER0SVVWbanpsXlITuZu/KP4PS/RqDNbbsCA5vFIiTJ9wxPGUDDO9ezukq7wwOGK0uDurKjAIKu6QV6qfYxAEpEREREREREVIe8mZ6SJEMUBcREV5ztWVknc481D4LGgHyLE4IQGNj0ePzP7/Q2EmoKvN3hNS4XTKYEWCwlcLmaVqCXah+bIBERERERERER1QGVSkS0QUZcrBZGXUnp7waPku0pOSyVdjIPxtvJXJIaZsOiS8H7yL6P3lAbOFH9YwYoEREREREREVEtU6lEv0xPyWGBOiYJl03eH1a2p9LYCEDhobVBmxgxw5EoPAyAEhERERERERHVEm+5e2SEB4X7nvHr1i6o9fCU5IXM9mQnc6K6wQAoEREREREREVEN+Tc2KoBKF4O8cl3cq5rtyU7mRLWDAVAiIiIiIiIiohooX+6uimqHVtd/GNDAiNmeRPWDTZCowduw4RX8+OOhOll7//59ePPNjXWyNhERERERETVtgiBApRLLyt0vNjYqzfRMgKgzBVyTn7kYxj4zYeq3RHm9fLZnocOAC/lOFFkFBj+JagEDoM2I94NZEIT6vpUqef319fjxxx/qZO0DB/6Lt956vU7WJiIiIiIioqbJv7u7FVpdhF9jo4q6uLvyj6D4l38hus8ctL/vN7Sf/jva3/cb9FfORUGRBLdbYidzolrGEvhmwP8cEgvECBOcdjusDhV/kkREREREREQUBm9zI0EAjFGVl7tX1MU96k/3oKBIgiQ5IYo825OorjEDtInznkNi++F55L7aDrnr2yH31Xaw/fACYqJFqFR1uwUyM3fBbO6L3NyTfuOFhYUYMWIQPvzwvQqvN5v7AgDWrn0RZnNfmM19sX//PgCALMvYtOkt3H77TRg+fABuueUGbN78jt/1Z878gUcfXYiJE8dgxIiBuOWW67F69bMASkvrX399PWw2m7L2zJn31dajExERERERURPgn+1ZAmOkHFa5u/dcT13rFHS47ze0v88/09Ob5clsT6K6xwzQRkaWZcBjDXu+Qa9D4b7VsOx9UhmTHBZY9q4off2KWSgscoS3mMpQ5fL5AQMGISGhJbZs+QQPPDBTGc/I+AIAMHr0tRVev27d63jggXswadJtGDWqdG5iYiIA4MUXn8Gnn/4v/vrXqejZ83L89NMPePnldOh0Otx44yQAwIoVj+HcubOYO/cRxMbG4Y8/8vDLL4cBABMn3oizZ88gI+MLvPjiOgBAZGRklZ6PiIiIiIiImhZvpqckyRBFwa+5EUQ12k/NClnu7tvYCCgNgjr+2Aex1WBYHQZIVmZ6EtUHBkAbEVmWYds2HtK578OaL+rjET81q/RDOojCg2sQ0/dh2N75EyTbucrXS+gH/egtVQqCqlQqjB8/EVu2fILp0/8HKpUKALBlyycYOnQ4oqOjK7z+8suvAAC0bNla+TMA/P77b/jgg3/hkUdSccMNNwEArrmmH+x2O15/fT2uv/4miKKIw4f/D/ff/yBGjhyjXDtu3ISyNVshIaElRFH0W5uIiIiIiIian2DHx0kuOwr3PaMkFWlaXA6P9UyVyt2NfeezkztRPWMJfGNTleCjoXXQD2YvyWGBx3YWKkPrWrq54CZMuAHnz5/D3r17AADHjmXh6NEjmDDhhmqv+Z//7AUADBs2Am63W/nVt28Kzp8/jzNn/gAAJCd3xz//+TY++uh9/PZbbs0fhoiIiIiIiJqcYMfH/f5mL4hqjV+2Z2m5e8tqlbsTUf1pUBmgv/76KzZs2IBDhw4hKysLnTt3xmeffaa8XlxcjNdffx07d+7EiRMnoNVqceWVV2LevHno1q2b31pFRUVYuXIlvvrqK7hcLgwePBhLlixBy5Yt/ebt378fTz/9NA4fPowWLVrgjjvuwPTp0/2yHGVZxvr167Fp0yZcuHABPXr0QGpqKnr37l2n34/yBEGAfvSWsEvgBVGAKtIEUWcKGgQVdSaoDG2gG/M5tFIY541UowQeANq0aYtrrumHzz77GAMHmrFlyydo0+YyXHVV3yqv5VVQYIEsy7juulFBX//jjz/QunUbLFu2Eq+++hJefXUtnn02DR06dMT99z+IoUNHVPu9iYiIiIiIqGnwlrtHRnj8Mj0BQFDr4SnJ8/v3NMvdiRqnBhUAzcrKws6dO9GrVy9IUuAhwKdOncLmzZtx8803Y+7cuXA4HNi4cSNuu+02fPDBB0hKSlLmzp07F8eOHcPjjz8OnU6HF154AdOnT8cHH3wAtbr0sX/99VdMmzYNgwYNwty5c/HLL7/gmWeegUqlwrRp05S11q9fj9WrV+ORRx5Bt27d8M4772Dq1Kn4+OOP0b59+0vzzSkjCAKgDv+cSqfDAWPvmcqZn76MvWfC6XAAogFCHecCT5x4I5YtW1J25ubnmDTp9moFU72MxhgIgoC1a1+DRqMJeL1Dh44AgPj4eCxa9BgkScIvvxzGP/6xAUuXpmLTpg9w2WXtqv3+RERERERE1Hj5l7sXQKWLQV654+N8sz19g6AsdydqfBpUAHTEiBEYNao0o2/hwoX46aef/F5v164dMjIyoNfrlbH+/ftjxIgR2LRpEx599FEAwIEDB5CZmYkNGzbAbDYDKG2cM378eGzbtg3jx48HAGzYsAGxsbF47rnnoNVqMWDAAFy4cAHr1q3D5MmTodVq4XA48Morr2Dq1KmYMmUKAODqq6/Gtddeiw0bNuDxxx+v4+9KzVgdKsT0nQ+g9MzPYB/Ml+KnUYMHD0N0tBHLli1BYWGhcg5nONRqNZxO/0ZNV199DQCgoKAAZvOQStcQRRE9evwJ06fPQGbmLvz++2+47LJ20Gg0cDqdVXsYIiIiIiIiarS85e7exkaqqHZodf2HAZWTobI9veXuCePfganfInjsBRAjYuC02xn8JGqgGlQAVBQrTkM0GAwBY5GRkejQoQPOnDmjjO3atQtGoxGDBg1Sxjp37owePXpg165dSgB0165dGD16NLRarTJv/PjxeOWVV3DgwAH069cP+/fvR3FxMcaNG6fM0Wq1GD16NDIyMqr9rJeKxyOhoAgwXDkXMSkLIdXTB7Narca4cddh06a3kJIyAK1ahX/uaMeOicjM3IVevfpAr9ejQ4eO6NChI2666RasWLEUd9wxGT17Xg63243c3JM4cGAfVq58FsXFxXjooZkYO3Y8OnToCLfbhfff/xeioqKRnNxdWdvj8eBf//onrrjiyrL91KmOvgtERERERERUX0KWu4tqqAwJQY+Py89cjDa3bgcE0S+pKDJ5EtSmLrAUuiDLBkg2lrsTNWQNKgBaHYWFhcjKysLAgQOVsezsbCQmJgaUWHfu3BnZ2dkAAKvVitOnT6Nz584BcwRBQHZ2Nvr166fMLz8vKSkJ//jHP2C32xEREVEXj1ZrPB4JRVYBgs0JUay/D+YhQ4Zj06a3cN1111fpuoceWoAXX3wGjzwyGw6HA6tXr8NVV/XF3Lnz0aFDR3z88Yd4443XoNcb0KFDRwwfPhJAaaA6KakLPvhgM/74Iw86XQS6d++B559fA5PJBAAYNGgw/vznW/D2228gP/8CevXqgzVrXq3tRyciIiIiIqJ6Ulm5e2Xnehb/8i9E95lTr0lFRFQzjT4A+ve//x2CIOCOO+5QxgoLCxEdHR0wNyYmRimrLyoqAgAYjUa/OVqtFnq9HgUFBcpaWq0WOp3Ob57RaIQsyygoKKhRAFStDp71KknVPx8zFFmW4fGE0eyoFnhjz4IAeI9y/e67bxETE4PBg4dWaa1evXpj48a3g7yHgJtvvg0333xb0Ou0Wi0WLFhS4dpqtRoPP7wADz+8oEr3RKGpVELAvlapRL/fqXnjfiAv7gXyxf1AvrgfyIt7gXxVZz+IooBog4CCSsrdKzrXM/pP96DIKkO2uyAIkZCLXJBlFQQh9L/pqe7x84GqolEHQD/44AP861//QlpaGlq3Dr+kuqEQRQGxscEbGtntKpw7JwYNJjUmKpWIX389gV9//RUffLAZN998KwyGhp0xS9UjSQJEUURMjCHkDwWMRn3QcWqeuB/Ii3uBfHE/kC/uB/LiXiBfVdkPkqsEBfv+Xmm5u/dcz7jBaejQbxEkRwFEXQxkyQVRo0dMTC0/BNUafj5QOBptAHTnzp1YunQpZsyYgT//+c9+rxmNRuTl5QVcU1BQgJiyTy1vhqg3E9TL6XTCZrMp84xGI5xOJxwOh18WaGFhIQRBUOZVhyTJKCy0Bn3N6XRAkiR4PDLc7saXUi8IpcFPj0fCypUr8PPPP6FfvwG4884pfs/jdrsrWEOASqW6FLdLtcDjkSFJEgoKrLDZPH6vqVQijEY9CgttLBEh7gdScC+QL+4H8sX9QF7cC+SrqvtBEABjtAaFVSh3d/yxD6rWg2F3RUJ2usoqGktq+UmoNvDzgYDSAHg4WcCNMgB68OBBzJkzBzfeeCPmzJkT8Hrnzp2xZ88eyLLsdw5oTk4OkpOTAZQ2VGrTpo1yxqfvHFmWlTM/vb/n5OSge/fuyrzs7Gy0bdu2xud/hgpuXqpS9briLXuXZYQ8U/P06VO45ZbQ54H27n0Vz+NshCoK2ns8UqMM6FPd4H4gL+4F8sX9QL64H8iLe4F8hbMfBEGARiNCsluqVO5u7Du/7GxPT5BVqSHi5wOFo9EFQI8dO4b7778f/fv3x7Jly4LOGTJkCNauXYs9e/YozZFycnLw888/49577/Wb9/XXX2P+/PnQaDQAgK1bt8JoNKJPnz4AgKuuugpRUVH4/PPPlQCoy+XCtm3bMGTIkLp81CYvPj4Br732ZsjXDQbDJbwbIiIiIiIiauwCGh5FmCotd/eUlbuzsRFR09WgAqA2mw07d+4EAPz+++8oLi7GF198AQBISUmBLMuYNm0adDod7r77bqWhEQBERUWhS5cuAIA+ffrAbDZj0aJFWLBgAXQ6HZ5//nl069YNY8aMUa6ZNm0aPv30Uzz88MO44447cPToUWzYsAHz5s2DVqsFAOh0Otx///1IT09HXFwckpOT8c9//hMWiwXTpk27VN+aJkmj0aB79571fRtERERERETUSAmCAFEUIEkyRFFATLSIwrKGR5LDglY3fAxj7wcvngFaxlvuLrYaDKvDAMnqhCwLABj8JGqKGlQA9Pz58wEl7d6v33yzNFPQe7bnlClT/OalpKTgrbfeUr5+4YUXsHLlSixduhRutxtmsxlLliyBWn3xkTt27IgNGzYgLS0N9913H+Li4jB79mxMnTrVb+3p06dDlmVs3LgRFy5cQI8ePbBhwwa0b9++1p6diIiIiIiIiEr5BjblsjPWvCfceXtOXMz0tECMMEFy2VG47xm/YOeFXQsulruXBUUDy90Z9CRq6gTZ+0lCl5zHI+HCheCHKbtcTpw/fxotWrSBRqO9xHdWO9RqkedwNCMV7Vm1WkRsbCTy80u4J4j7gRTcC+SL+4F8cT+QF/dC83MxsBmhBDZdDicAGRqdDrLDAkFnAiQPCvatUoKa6pgkXDZ5P3LXdww481MT2x1xg9Og7zjKr9zd6lAx+NmI8fOBACAuLrLpNkEiIiIiIiIioqbBm+0pCIAxyr+EXdvqGrS5aSsK9r+gBDtb3fAxHKf3+nVxF9R6eEryAoKfQGm5+x+f3Ij200+hxB0JF8vdiZqdykOkREREREREREQ1JAgCVCoRQlktu0olItogIy5WC2OEHcZIGYX7VpWWsItqaFpcDlP/pSj47/PKmO4yMyLaDUHhobUAAFEfD02LyyFLTqgMLSHqTH7joj6+9GudCWKEEZJU8T2FGqvK3KqsKYoCtFoVRFGo8lhNr2/8a/r/XtXr6+K/Z0Nbs6Lx5oYZoERERERERERUZ1QqEYJWDUOEGhabCya9BnaHB9FaCUUFuRC0nWDxuBGri4HQfhRiLhuOyDbXwGIvhMbQAi5NFGLajSgbK4Zb1MF43XuQIZSO2Qph0htRbLuAuKHPw6GLQ3SHYbDYCpGgN8J6+nuI0e3ghginzgOTTg+70wUZgF6rgcVhCzlmdTghOAFZCxh02grnVmVNlVuATu2GRquFpyQfqphYuF0uABLUmorHXE47XJIWGtFVreubzpoauArOIDrSBLc2/Osdbg20ggvaCB081nyoomPhcjoAufSYhaqOOe022D0aRKjcDWbNUNc77TZYXepmefQDA6BEREREREREVCdUKhH6KB3SdhxDeuYJJQB6YHYKtBodnv81B+lH3oHFaUNKfAd8MXY6Vv+0C+n/fqrSsed9xkxaPZb1GY1pybfi2R++Rvq/gsw9/IbP2H144aedSD+cGXKsdM2xmJbcD0//sL3CuVVZc3W/G3FHh544+9nfkZ+RDslqQUTnFHScvw3nv3gOFzJWhxwTDSbE3/QE4obei7OfPYP8CuZyzdDXn/vs2cC5Xwa5vpIx0WBCwk1PILYBrRnqetFgQtzo2Whx3UIUlKDZBUHZBKkesQlSw5aV9QvuuedOrF69Dldd1be+b6fBYxMkChf3A3lxL5Av7gfyxf1AXtwLDUuwzuyVzRW1ajy/OwfLM7KU1+IjtchePATP/PgNlv/wtTL+0cgp2HfuNzx56Ksqj3nH/3vud6w4lNGg1zx103zg65dw/uPlylj7Of8LW84+nPtkRYVjyviJ/+JcNa5vzms2xHu6lM/pFX/DUhhHP4Qie9M4FTPcJkhN42kpLDz3gYiIiIiIiMqr7N+KKpUItV6LaJMeLo0K0SY91HqtEnTwvd53rlurgiFCg/TME37r9WgZBa1Kg/Qj3ypj8bpIjGyTjJcO767ymO/4msOZDXrNbsYEJETGIj8j/eL3NzoekX8ahQtfralwzG+8Gtc35zUb4j1dyuf0dSFjNbQR+mYXG2IJfDOgUokQIgS/80qsDidku9ykU54dDjt0uoj6vg0iIiIiIqIGKdjZnFa7G7LTDUmSlc7sEZGBJeyzzYlYODwJdpcHel3p9bF6DTwykLb9GNIzc9AuJgKfTE2BxeYKeG+L0waL06Z83doQjTP24mqN1fT6S7lmj9hWcJfkQ7JalDF1TGu4C89UOlaVuVyz4d/TpXxOX5LVAo/NAlGMhMfTfIrCmQHaxKlUIvTRWrx45N9o++4ytN28DG3fXYYXj/wb+mhtWGnCNZGZuQtmc1/k5p70Gy8sLMSIEYPw4YfvVbqG2dwXb731BtaufRETJozC6NFD8OSTj8NqvXh8wP79+2A298W332ZiyZK/YcyYoXj00YUAgKKiIjzzTBpuuGEshg8fgKlT78L3338X8D5vvPEarr9+LEaPHoxFi+YjPz+/hk9PRERERERUPyrrCK1Wl57N+cLuHLRZlqH8eufgKWgMWkSbDHBpVFAbtEjbcRzLM7KUQKbF5sK/Dp2CQ5LxfOYJ5dqMrHNYuT0LyzOOwmJzIa/IgYQoLUx6jd89HD5TDKNGD5NWr4zlWYvQMiKqWmM1vf5Srnk4/w+oI2MhGkzKmLsgD2pjy0rHqjKXazb8e7qUz+lLNJig0psgSc0n+AkwANroyLKMErcz7F+yDnj6x+1YfihD+cmTxWnD8kMZePrH7ZB0CH+tahwXO2DAICQktMSWLZ/4jWdkfAEAGD362rDW+eCDzThx4gQWL34cDzwwE998sx1PP70iYN6qVU+ibdt2eOqpv+P22++Cy+XCvHkP4ttv/43p02cgLe05JCYmYv78OTh+/Jjf+q+9tg5jx47HihWr0LbtZUhLCzwrg4iIiIiIqCELVa6u0aj8xoMFNltH63Bb77b4+87jaLNsG654ZidEQUB6Zk7A+6wc3wPPfnNcCXbGR2oxLKkF1viUu58rceKro+cwc1Anv2vPlTiReeIcZvUwXxxzlODr00fxYI9BVR7zHZ/ZwNf8pfAszpbkI3b0bGXMU3QOJf/3FeJGzaxwzG989KwqX9+c12yI93Qpn9NX3OjZcNpt1YrxNGYsgW9EZFnG9d++jv/k54Y1P14XiexbFiPd57wSX+mHMzH/iuH4045VOOcI3ozJV0pse3w88J4qnROhUqkwfvxEbNnyCaZP/x+oVCoAwJYtn2Do0OGIjo4Oax2NRouVK59RrtfpdHj66RWYOvV+dOzYSZlnNg/BjBkX/49ky5ZPkJX1C954459ITOwMAOjXbwByc3PxxhuvYfnyNHg8Hrz11hsYO3Y8HnxwjjInP/8Cvvxya9jPSkREREREVJ9CdVx/Ymw3TOvXQSlNV4sCchaPDAhsrhzfA+mZOVjxVWnDostbR+NMsTOghD0+UotRyfG4Z/NBZax1tC7o3NSth7FzxkAAwJrdF+/pSJ4NC/qPAAClQ/rKQ9vxxdj7IEKo8phJq8fJYgsWXjkCQgNf86uzv+GOCaUVi95O5mc/fQod528DBFHp2h1sTDSY4Dh/EvETUiFDqPL1zXlN3+sBIXCuKOLCtqqNiQYTnA1szVDXK13gJyxEQbEEoOkeiRgMu8DXo6p2gZdlGTd8+zq+DzMAenlsa/zvyKno8v5TIeccn7QIN3y9ET/l51W6XlUDoN4u8KdPn8Ktt96Ap59+HgMHmnHsWBamTLkDL774Mq6++ppK1zGb+2LSpNsxd+4jylhJSTHGjh2GxYsfx7hxE7B//z7Mnv0Ann76eQwaNFiZ99hji5Cb+yteffUffmu+/vp6bNv2Od577xPk5Z3GpEkT8eSTf8fQocOVOZmZO7Fw4cPsAh8mdoGncHE/kBf3AvnifiBf3A/kxb1QNWq9Fi+U67gOAB9NuQb//d2CFRkXA5sfT01B0lMXO7DHR2qRs3gk2i//SgliBhuryvVe3VtGYdWEnhiTnACLzYUYvRpWuxuC2wNZCxh0WhQ47YjRRsDudEGWAb1OEzBm0GlQ4LIjRhMBW5B5VocTghNVWrOysbpaU+UWoFO7oNFGwGO1QGUwwe1yAbIEtVZX4ZjLaYdL0kIjOqt1fXNe0+W0w+HWQCs4oY3Qw2OzQKU3weV0ALIMjS6iymNOuw12jwYRKleDWTPU9U67DVaXukn1gwm3CzwzQBsRQRDw8cB7YPUEHiAdjCgKaGUwwqTVBxy8DAAmrR5tDEZ8OmBqWGc/GFSaanUJa9OmLa65ph8+++xjDBxoxpYtn6BNm8uqFFSMjY31+zoyMgparQ7nz5/zG4+Li/P7uqDAgqNHf8GwYf0D1vRmk547dy7oe8TGtgj7/oiIiIiIiOqTIAgwRKgDOq4Hy9bMK3KgZdnZnL7l7+UzOH1L2L1ZoaGuDzUXAI6cKca+XAvMHUxQu9wocrgult+6gCKrHWpRQFGJXRl3Wz0BY1anhARTFCyWErhcUsh5VVkz3LHaXtMNwOEQINqcUKuj4C5wKv8ur3xMAOCCDdW9vmmsqXW5EBPTEgUFJXA6pSpc74YDIgSHE6IYCanAidL/TAIEe3XGRAAeuFwNac1Q14tobpmfXgyANjKCICBSra18Yhmrw4lZPcxYfigj4LVZPcywOpzQi5o6Pw124sQbsWzZEpw9ewYZGZ9j0qTbqxRMLd+QqKSkGE6nAy1axPuNl1/TaIxBUlJXpKY+GnLt+Pj4oO+Rn38+7PsjIiIiIiKqT6IowGJzBWRfhhvYDBbUBIKXsLslGdnnrZhtTsQTGUcD5goCAjrGLxieBFuxI2jmmSzLAd2og4/5/x5qXtXWDG+srtaUJBlOp6daYzW9vvGv6f97Va9vLHukLq5vjhgAbeJku4wFV/ifq2LS6jGrhxkLrhgBW5HzktzH4MHDEB1txLJlS1BYWIhx4yZU6frdu/+NWbPmKVmbO3Z8DUEQ0KPHnyq8rm/fFOzZsxvx8QmIj08IOichoSVatIjHrl07/Ergd+z4Ouh8IiIiIiKihkQQBAgCYNIHBjDDDWyeK3Him+PnMcvcya+E/siZYgxd+y3enXw1Fo9KRkFZCbvd4cGC4V0AAKszc5Su75sPnsIjQ5OwaOTFuVa7O2Twk4joUmAAtInzeCTYipyY030wUnuN9DtzxFbkvGT/B6RWqzFu3HXYtOktpKQMQKtWrat0vcvlRGrqI/jznyfh9OlTePnldAwbNhKdOiVWeN21116Hjz/+EDNn3o877rgL7dt3QHFxMbKyfoHL5cIDD8yESqXCXXdNwYsvPoO4uBa45pp++P7773DgwH9r8shERERERES1ThAEiKIASZIhigIErRqGCDUsNhfUbg9mmROx3Ccr05vtGU5g06RXY0SXeAgQlKCmSa/Brb3aomsLA6xFNqhlKCXsHpWIOYM6IXVkFxTY3Eqw02V1wiHJpSXfvuXuRET1hAHQZsDjkYCS4OeVXEpDhgzHpk1v4brrrq/ytTfffBsslnwsX74ULpcLQ4YMw0MP/a3S67RaLVavfhkbN76KN9/ciPPnzyEmxoTk5G74859vUeZNmnQbiouL8OGH7+Gjj95D374pWLBgCR5+eFaV75WIiIiIiKi2qVSiX7AzVq+BR4bS2d1icyGlgwlfTu8PAfALYOZabFg4omulgc1ChwuiKAQNagbL4PR4JMDmRJHdFTTYybJbImoo2AW+HlW1C3xj4+0C7/Xaa+vw0Ufv4aOPPodWG/4zmc19MWPGHPzlL5Pr4japlrALPIWL+4G8uBfIF/cD+eJ+IC/uhVIqlQh9lA5pO44pZ2t+Oi0Fe0/mK53dvbq3jMK7k69Gt4QovxJ0we2BrFbBEKH2C2zKTnfQykDfTNOGEjbgfiBf3A8EhN8Fvo5b3xABJ0+eQGbmTrz//mbccMPNVQp+EhERERERNXeCVo20HcewPCMLFpsL8ZFaDEtqgTXlOr4DpaXtw9Z+C0CGxu1BkcUGt80Jl8sDt82JIouttBN72XioY9FKG6dIDSb4SURUEyyBpzq3atVT+Pnnn9Cv3wBMnnyP32tutzvkdYIgKE2PiIiIiIiImiNBEGCIUCPdJ9gZrLO7L4vNhQKbG2o5MHuTHaGJqDliAJTq3Jo1rwYdP336FG65JfR5oL17X4U1a15FZua+uro1IiIiIiKiBksQBGg0Iiw2V1id3b1Meg1i9GoUOYIHSImImhsGQKnexMcn4LXX3gz5usFguIR3Q0RERERE1DD4NjwqsLsQG+Ef7PR2dp85qBNWfJUVcP1sc2Lp+Z4sXyciAsAAKNUjjUaD7t171vdtEBERERERNRihGh7NMnfCcp+GR6lbD2PnjIEQBCjzTHoNZpsTsWB4EmzFjnp8CiKihoUBUCIiIiIiIqJ65Ntx3bfhkdf8T3/GzhkDAVwMduYVObD54Ck8MjQJi0Ym+3V8txU7QjY3IiJqjhgAJSIiIiIiIqoHvqXu3gxOQPBreASUdnYfuvZbrJrQE3mPJcPiE+x0WZ1wSDLUooAih4tl70REQYj1fQNEREREREREzYUgCFCpRKjVpaXuL+zOQZtlGWizLAMj1u3B2WJH0MZGR84U4/qN36PA7oJO8qDIYoPb5oTHI5V1dpcY/CQiCoEBUCIiIiIiIqI6plKJUOu1iDbp4dKooDZokbbjOJZnZCkBz6yzJYg1aMoyQQOZ9BoYI9RwuRjsJCKqCgZAiYiIiIiIiOqQt7GRN9vzimd2QhQEpGfm+M3z7e4eDLu7ExFVDwOgRCFkZf0Cs7kv9u/fF/Y1//nPd/jrX2/D8OEDcO21w+ru5i6x1NSHMXPmffV9G0REREREjYq33F30aWxksbnQOlqHM8XOoKXuqVsPY5Y5EUtHJyuZoCa9BktHJ2PB8CTITvelfgwiokaPTZCIatFTTz2BpKQuePjhhdDpdPV9O0REREREVA98mxsV2F0wRWj8GhvlFTnQMkoLk14TEAQ9cqYYEzd+j4z7+yN1ZFd2dyciqgXMAG1GvD99FAShvm/lknA47Jf0/axWK86ePYNhw0aiV68+6N69Z7XXkmUZTqezFu+ucpf6+0VERERE1BSVL3cfte47nCq0+wU6Kyt1v7ZbS7hdEoosVqhdbr+GR0REVHUMgDYDKpWI6AgZcTFaRKuKS3+PkKBS1f1//szMXTCb+yI396TfeGFhIUaMGIQPP3yv0jXM5r546603sHbti5gwYRRGjx6CJ598HFZriTJn//59MJv74ttvM7Fkyd8wZsxQPProQgBAUVERnnkmDTfcMBbDhw/A1Kl34fvvvwt4nzfeeA3XXz8Wo0cPxqJF85Gfnx/2c27d+inGjBkCAEhLWw6zuS+efPJxAIDD4UB6+nO44YZrMWLEQEyZ8hfs3LnD7/onn3wckyffij17MnH33Xdg+PAB2L17F2699QasX/+yMu+bb76G2dwXL730ojK2d+8emM19lfv99ttMzJ07AxMmjMaYMUMxffrd+O67bwPu12zui59++gFz587AqFFmZc0TJ3Iwc+Z9GDFiIG699QZ8/vlnYX8fiIiIiIiaO6FcuXtekQMJZdmevryl7ktGdQ1Z6s7u7kREtYMl8E2cSiUiJlLE+S2rcCFjNSSrBaLBhLjRs9HiuoUoKEGd/hRxwIBBSEhoiS1bPsEDD8xUxjMyvgAAjB59bVjrfPDBZiQnd8fixY/j1KlTWLduDZxOB5YtW+k3b9WqJzFmzDg89dQkiKIIl8uFefMexIUL5zF9+gwkJLTEtm1bMX/+HGzc+A6Skroo67/22jrcccdk9O2bgv/8Zy/S0pZX4TnNeP75lzBv3oO4++5pGDDAjNjYWADAE08swd69e3DffTPQoUMnfPHFFixZ8jesXPkMzOahyhrnzp3DCy88g7vvnoZWrVqjVavW6N37Khw6dECZc/Dgfmi1Ohw8uN9vrGPHTsr7nT79OwYNGoI77pgMURTw3XffYv78OXjxxZdx1VV9/e572bIluP76P+Ovf50KnS4CDocDDz00ExEREViy5AkAwIYN61BSUoJ27dqH/f0gIiIiImqOBEGAIULtV+7um+254qssZfzImWIMXfst3p18NRaPSmapOxFRHWIAtJGRZRlwWsOeb4jW4fyWF3Du4yeUMclqUb42jpyLQqsjvMW0hiqXz6tUKowfPxFbtnyC6dP/ByqVCgCwZcsnGDp0OKKjo8NaR6PRYuXKZ5TrdTodnn56BaZOvR8dO3ZS5pnNQzBjxmzl6y1bPkFW1i94441/IjGxMwCgX78ByM3NxRtvvIbly9Pg8Xjw1ltvYOzY8XjwwTnKnPz8C/jyy61h3V9sbKxS8n7ZZe1w+eVXAACOHcvCzp078MgjqbjxxpsBAP37D0Re3mls3LjeLwBaVFSIZ55ZjT/96XJlrFevPvjqq21wOp3QarU4ePAAJk68Af/7vx/AarXCYDDg4MH96NWrj3LNzTffpvxZkiT06dMXOTnZ+OSTjwICoDfccBPuumuK8vX//u/7OHfuLN555320b98BAJCc3A1/+cvNDIASEREREVVAEARoNCIsNlfAuZ6pWw9j54yBAIA1u0/AYnPBpNfg1l5t0bWFAdYiG9QyUORwMduTiKgOMADaiMiyDMtLY+A+sTes+aroeMQ/ewIXMlYHff1CxmrEX/c35C9OhqfoXKXrqTv1h+nBL6scBJ0w4Qa8+eZG7N27BwMHmnHsWBaOHj2iBBvDMWjQYCX4CQDDh49EWtpy/PzzT34B0AEDzH7Xff/9d0hK6oL27TvA7b7YLfGaa/ph27bPAQBnz57BuXNnMWTIcL9rhw8fGXYANBRv9uaIEaP8xkeMGI309Odgs9mg1+sBADExMX7BTwDo3fsqOJ0OHD78f+jcuQuys49h2bKnkJHxJX788RB6974KR478jD//eZJyzZkzf+DVV9di377vcf78OeUvUN269Qi4v4ED/b9fP//8f0hMTFKCnwDQrl17dOnStQbfBSIiIiKipqt8w6PYiMDmRt5sz1UTeiJvVDIszPYkIrqkGABtdMIPPqpjWsNdeAaS1RL0dclqgbvwLNQxrcMKgFZXmzZtcc01/fDZZx9j4EAztmz5BG3aXBaQjVgRb3m3V2RkFLRaHc6f97/vuLg4v68LCiw4evQXDBvWP2BNb0D13LlzQd8jNrZF2PcXSlFRIdRqNYzGmID7lGUZxcVFSgA02Ptddlk7JCS0xMGD+1FcXIzY2Fh07NgJV17ZCwcP7odGo4HL5VIyQCVJwsKFD6G4uBj33ns/LrusPfR6PV57bR3++CMvYP3y73nu3LmA74N3HpskERERERH58zY8SttxDOmZpZmdn05LwSxzJyzPyPKbe+RMMfblWmDuYCptbMRsTyKiS4YB0EZEEASYHvwy7BJ4QRSgNpkgGkxBg6CiwQS1qQ2MD34FWQrj/3irUQLvNXHijVi2bAnOnj2DjIzPMWnS7VVaq3xDopKSYjidDrRoEe83Xn5NozEGSUldkZr6aMi14+Pjg75Hfv75sO8vFKMxBm63G4WFhTAajcr4hQsXIAgCoqIuHgEQ6tvRq1cfHDp0ACUlxbjyyj5lY1dh164d0Gq1aN26DVq1ag0A+O23XBw9+gtWrnwGgwcPU9ZwOIIfc1D++xUfH49ffjkSMC8//zwMhsiwnpmIiIiIqCkTBAGiKECSZL+GR17zP/1ZKXf3BkVNeg1mmxOxYHgSMz6JiOoBu8A3MoIgQNBFhvULGgOcdgfiRs8Oulbc6Nlw2u2AxhDemtUMfgLA4MHDEB1txLJlS1BYWIhx4yZU6frdu/8Nj8ejfL1jx9cQBAE9evypwuv69k3BqVO/Iz4+Ad279wz4BQAJCS3RokU8du3y78y+Y8fXVbrHYK68snfZWl+VW/srdO3aTcn+rEjv3n3w448/4L//3Yfeva8CAPTpU1r6vnfvHr/zP72BTrX6YofJvLzT+PHHQ2Hdb48ef0JOznH89luuMvbbb7k4diyrgquIiIiIiJo+lUqEWq9FtEkPl0aFaJMehgiNX8Mj4GK5+zXtY5H32BjkPTYGpx8bjTmDOjH4SURUT5gB2sRZXSq0uG4hAAR2gZ+wEAXFEoC6/z9gtVqNceOuw6ZNbyElZYCSsRgul8uJ1NRH8Oc/T8Lp06fw8svpGDZsJDp1SqzwumuvvQ4ff/whZs68H3fccRfat++A4uJiZGX9ApfLhQcemAmVSoW77pqCF198BnFxLXDNNf3w/fff4cCB/9bkkQEAXbp0xdChw7FmzfNwOBzo0KEjtm37HD/99ANWrnw2rDV69boKNpsVv/xyGIsWPQYA6Nq1GzQaLX766Qdcd931ytyOHTuhZctWWLduDSRJgs1mxYYNryAhoWVY7zV+/AT84x8b8Le/zcW99/4PgNIu8HFxNT8OgIiIiIiosfFmewoCEBHpX+o+oFMsNt91dUDDI6A0CHr9xu/xx+NjoJM8KLKw3J2IqD4xANrEeTwSCkoA4+iHED9xMTw2C1R6E5x2GwqKpUv608chQ4Zj06a3/AJ24br55ttgseRj+fKlcLlcGDJkGB566G+VXqfVarF69cvYuPFVvPnmRpw/fw4xMSYkJ3fDn/98izJv0qTbUFxchA8/fA8fffQe+vZNwYIFS/Dww7OqfK/lLV26HK+88hLeeecNFBYWokOHTlix4mmYzUPCuj4xsTNMplhIkoTOnZMAlJ5fesUVvbB377d+GaBarRZPPrkKzz33NB59dCFatmyFu++eiv379+HIkZ8rfS+dLgLPPbcGzz6bhuXLH0V8fEtMmTINmZk7UVRUVL1vABERERFRI+Pb2Mhic8GgVSFtx3G/UvessyWINWgCGh55mfQaGCPUDH4SETUAgtyAPol//fVXbNiwAYcOHUJWVhY6d+6Mzz77LGDee++9h9deew2nTp1CYmIi5s2bh+HD/Tt4FxUVYeXKlfjqq6/gcrkwePBgLFmyBC1b+mfC7d+/H08//TQOHz6MFi1a4I477sD06dP9yr1lWcb69euxadMmXLhwAT169EBqaip69+5do+f1eCRcuFAS9DWXy4nz50+jRYs20Gi0NXofL9+zai7Ff3a1WoTbfTHA+tpr6/DRR+/ho48+h1Yb/jOZzX0xY8Yc/OUvk+viNqmWVLRn1WoRsbGRyM8v8dsT1DxxP5AX9wL54n4gX9wP5FUfe6F8YyO1KCBn8Ui0X/5VQKDzoynX4L+/WbDiq8Ajo5aOTsacQZ3gtjkvyX03B/xsIF/cDwQAcXGRUKkqP+GzQZ0BmpWVhZ07d6Jjx45ISkoKOmfLli149NFHMW7cOKxfvx69e/fGzJkzcfDgQb95c+fOxe7du/H444/jmWeeQU5ODqZPnw63263M+fXXXzFt2jQkJCTglVdewd13343Vq1dj48aNfmutX78eq1evxpQpU/DKK68gISEBU6dORW5uLhoTWZbh8UiX/KePJ0+eQGbmTrz//mbccMPNVQp+EhERERERXQqCIEClEiH6NDay2FxoHa3DmWJn0CzP1K2HMcuciKWjk2HSl57Db9JrsHR0MhYMT4LsdAdcQ0REl16DKoEfMWIERo0aBQBYuHAhfvrpp4A5q1evxnXXXYe5c+cCAPr374+jR4/ipZdewvr16wEABw4cQGZmJjZs2ACz2QwASExMxPjx47Ft2zaMHz8eALBhwwbExsbiueeeg1arxYABA3DhwgWsW7cOkydPhlarhcPhwCuvvIKpU6diypQpAICrr74a1157LTZs2IDHH3+8br8pTcCqVU/h559/Qr9+AzB58j1+r/kGpMsr/QuIqq5vLyySJEGSQv9ESaVS1ahJFBERERER1Q/fcvcCuwumco2N8oocaBmlDVrqfuRMMSZu/B4Z9/dH6siuKLC5EKNXw2p3s+EREVED0qACoKJYcUJqbm4uTpw4gfnz5/uNjx8/HqtWrYLT6YRWq8WuXbtgNBoxaNAgZU7nzp3Ro0cP7Nq1SwmA7tq1C6NHj/bLSBw/fjxeeeUVHDhwAP369cP+/ftRXFyMcePGKXO0Wi1Gjx6NjIyM2njsJm/NmleDjp8+fQq33BL6PNDeva/CmjWvIjNzX13dWthef309Xn99fcjXFy16DOPHT7yEd0RERERERNXhezSYKAp+5e7tYiLwydQUv0DnuRInvjp6DjMHdQpa6n5tt5ZwuyQ4ihxQiwKKHDzzk4iooWlQAdDKZGdnAyjN5vSVlJQEl8uF3NxcJCUlITs7G4mJiQEZeZ07d1bWsFqtOH36NDp37hwwRxAEZGdno1+/fsr88vOSkpLwj3/8A3a7HREREbX6nM1FfHwCXnvtzZCvGwyGS3g3FbvhhpswaNDgkK+3adP2Et4NERERERFVVfnGRia9BnaXx6+5kVoUkBAk2zN162HsnDEQALBm9wnl+tnmRCwYngRbsaPsyDEGPomIGqJGFQAtKCgAABiNRr9x79fe1wsLCxEdHR1wfUxMjFJW7+1oXX4trVYLvV7vt5ZWq4VOpwt4T1mWUVBQUKMAqFodPOtVkhp3ObU39iwIQKgffmo0GnTv3vPS3VQNxMcnID4+ob5vo1FQqYSAfe09kDicg4mp6eN+IC/uBfLF/UC+uB/Iq7b2gigK0Oq9mZ45sNhcSGphwA+PDEN6Zo4yL1S255EzxRi69lu8O/lqLBmVDIvNhRi9BjaHC06bE4IQ+t92VHv42UC+uB+oKhpVALSpEUUBsbGRQV+z21U4d04MGkxqTPhB1HxIkgBRFBETYwj5QwGjUX+J74oaMu4H8uJeIF/cD+SL+4G8aroXSpzussZGR5UxvUaFvCJHwLmeobI9b+3VFsnxkdCqRbSMLk2Q0an9E2Xo0uBnA/nifqBwNKoAaExMDIDS7M2EhIvZeIWFhX6vG41G5OXlBVxfUFCgzPFmiHozQb2cTidsNpvfWk6nEw6Hwy8LtLCwEIIgKPOqQ5JkFBZag77mdDohSRLcbgmi2PgOzhaE0uBnadf5+r4buhTc7tJGUQUFNthsHr/XVCoRRqMehYU2HgRP3A+k4F4gX9wP5Iv7gbyquxdEUQDUKkToNCiwO2GK0PplegKhmxt5sz1XTeiJvHLZng6rAzaJ/8CpL/xsIF/cDwSUBsDDSb5rVAFQ7zmc2dnZfmdyZmdnQ6PRoH379sq8PXv2QJZlv3NAc3JykJycDKD0fMk2bdooZ3z6zpFlWVnf+3tOTg66d+/u955t27at8fmfbneo/5GW3rfT6YBW2/h+qugNejL42Xw4nY6yP4kh97XHI1Ww56m54X4gL+4F8sX9QL64H8irKntBpRKh1WsrbGwEVNzc6MiZYuzLtcDcwQS1y83GRg0MPxvIF/cDhaNRBUDbt2+PTp064YsvvsCoUaOU8a1bt2LAgAFKN/chQ4Zg7dq12LNnDwYOLC1dyMnJwc8//4x7771XuW7IkCH4+uuvMX/+fGg0GmUto9GIPn36AACuuuoqREVF4fPPP1cCoC6XC9u2bcOQIUPq7FlFUQW9PgrFxfkAAK1WF9DUqaGTJIGHgDcDsizD6XSguDgfen0URJHHHhARERFR/RG06rJy94obGwGl5e67ZgyEKAhYXXY2aPnmRswsIyJq/BpUANRms2Hnzp0AgN9//x3FxcX44osvAAApKSmIi4vDrFmz8Mgjj6BDhw7o168ftm7dih9++AFvv/22sk6fPn1gNpuxaNEiLFiwADqdDs8//zy6deuGMWPGKPOmTZuGTz/9FA8//DDuuOMOHD16FBs2bMC8efOUYKpOp8P999+P9PR0xMXFITk5Gf/85z9hsVgwbdq0Ov1+GI1xAKAEQRsbURQhSfzLQnOh10cpe5aIiIiI6FITBAEqlQBDhAbpmSeU8coyPd89eArzBicidWQXFNjciNGrYbW7GfwkImpCBLkB5fH/9ttvGDlyZNDX3nzzTfTr1w8A8N5772H9+vU4deoUEhMT8dBDD2H48OF+84uKirBy5UpkZGTA7XbDbDZjyZIlaNWqld+8/fv3Iy0tDYcPH0ZcXBzuvPNOTJ8+3S/bUpZlvPrqq9i0aRMuXLiAHj16IDU1VckSrS6PR8KFCyWVzpMkCR6Pu0bvdampVAJiYgwoKLAyC7QZUKnUFWZ+qtUiYmMjkZ9fwtIE4n4gBfcC+eJ+IF/cD+QVzl5QqUQIWjUMEWoUO9zwyEDrx7f5zeneMgo7ZwxEemaOX2Mj30xPSZIhigIkSWa5ewPFzwbyxf1AABAXFxnWGaANKgDa3IQbAG2M+EFEvrgfyBf3A3lxL5Av7gfyxf1AXqH2giAIEEUBggBEROqU8z7VooCcxSPRfvlXAeXu3VtGYdWEnhiTnFDW2Kg001N2upnp2Ujws4F8cT8QEH4AlIf1ERERERERUaOgUolQ67WINunh0qigNmiRtuM4lmdkwWJz+ZW7l+dtbGS1u0obG1lscNucDH4SETUDDeoMUCIiIiIiIqJgVCoR+qjAbM/0zBy/ealbD2PnjNJmuKHK3Rn0JCJqXhgAJSIiIiIiogbJ25pBEABo/Lu7X946GmeKnQGl7kfOFGPo2m/x1PgeOP3YGBT4lLsz+ElE1DyxBJ6IiIiIiIgaFG+puz5KjzPFDuij9AHd3fOKHGgZpYVJrwm4/siZYkzdfBCADI3bw3J3IqJmjgFQIiIiIiIiqneCIJQGPtWlpe4v7M5Bm2Xb0PrxbRix7lucLXb4ZXtWdN4nAMw2J8Jqd8Pt9rCrOxFRM8cSeCIiIiIiIqo3KpUIQauGIUINi80Fg1alNDbyyjpbgliDBia9xi8IGs55n0RERAyAEhERERERUb0It7GRb7bniq8uBka9532+O/lqLB6VzPM+iYgoKAZAiYiIiIiIqF4I2vAaGwEXsz1FQcDqzBwl2/PWXm3RtYUB1iIb1DJQ5HCx5J2IiPwwAEpERERERESXVOl5n0KFjY2CdXefuPF7ZNzfH6kjuzLbk4iIwsYmSERERERERFRnvM2NlCZHei2iTXpIWjUK7K4qNTa6tltLuF0SiixWqF1udncnIqKwMAOUiIiIiIiIal355kaxeg08MpC2/RjSM3OU8z6r09hIlmV4PCxzJyKi8DAASkRERERERDUmCAJEUYAkyRBFwa+5kcXmwqfTUrD3ZD5W+HR3r6yx0ZJRySiwu2CM0MBqd7HUnYiIqoUBUCIiIiIiIqq28pmeJr0GdpcHaTuOK82N4iO1GJbUApM3HfC7NlS2p7exkd1qR4LRAIulBG4XA59ERFQ9DIASERERERFRlXizPQUBiIj0z/RMamHAD48MQ3pmjjK/dbQuaHd3b7bnU+N74PRjYwIaGwlC6Tw2dScioppgEyQiIiIiIiIC4N+wKNiYbxMjl0YFtUGrZHp6g5t6jQp5RQ6/YKdvd/fyjpwpxtTNBwHI0Lg9bGxERES1jgFQIiIiIiKiZq58YDPapIfWoIPGcHHMaNJDHx2BF3afQJtlGbjimZ0QBcEv0xMIHuysrLv7bHMirHY33G4PZKZ7EhFRLauVEnhZlnHhwgUAQFxcnN9PC4mIiIiIiKjhUqnEgIZFKR1M+PK+/nh+Zw7SM3OCNjG6vHV00LJ232Cnb3Mj73mfggDlfcp3dyciIqoLNQqAHjt2DKtXr8a///1v2O12AEBERAQGDx6MmTNnIjk5uVZukoiIiIiIiGqPb8d2QatG2o5jSsMiAEgd0RXPfnNcCWAGa2Lkm+lZPgiauvUwds0YCFEQsLosgJpX5MDmg6fwyNAkLBqZHHDeJ0veiYiorlQ7ALpv3z5Mnz4dkiRh5MiR6NSpEwAgJycH27dvx65du/Daa6+hb9++tXWvREREREREVEW+wU5RFAI6tgMC0jNPKPPjI7UYlRyPezYfVMaCNTEKlekJlJ7r+e7BU5g3OBGpI7ugwOZWgp0uqxMOSYZaFFDkcLHknYiI6ly1A6BPPfUU4uLi8Pbbb6NNmzZ+r50+fRp33nknVq5ciQ8++KDGN0lERERERERVo1KJfsHOWL0GHhlI235MKWsf0CkWm++62i+wGSzYGSrb01vWDgBrdvuXtU9LaQ9bsQNFVmfQYKfHw8AnERFdGtUOgB47dgxz5swJCH4CQJs2bXDHHXdgzZo1Nbo5IiIiIiIiqrpg53qWP8MTALLOliDWoPELbAYLdobK9jxyphhD136LdydfjcWjQpe1M9hJRET1qdpd4Nu2bQun0xnydZfLhdatW1d3eSIiIiIiIqoiQRCgUokQfc71tNhcyhmea3xK3YHg3dlDdWxP3XoYs8yJeHR0V6XDu0mvwa292qJrCwOsRTaoXW4UWWxw25w805OIiBqMameAPvjgg1i5ciWGDRuGHj16+L32888/4+2338aiRYtqfINERERERERUMd9y9wK7C6YIjd+5nsHK2r28Zey+DYtWbs/Cl/f1ZxMjIiJqEqodAD106BBatGiBm266CX369EHHjh0BACdOnMDBgwfRtWtXHDx4EAcPHvS7bsmSJTW6YSIiIiIiIrqofLl7u5gIfDI1JawzPIHSMvaJG79Hxv39kTqyqxLYtDs8mGvuxCZGRETU6FU7APr2228rf96/fz/279/v9/rRo0dx9OhRvzFBEBgAJSIiIiIiqiHfzu6CT7k7AKhFAQlhnuHpdW23lnC7JDiKHAGBTbfNxSZGRETUqFU7AHrkyJHavA8iIiIiIiKqRPnO7qVncQp+5e6hgp3eUndBgNIYyduxfcHwJNiKHZBlOSCwGWyMiIioMal2AJSIiIiIiIgunWCd3Qd0isXmu64OKGv3BjsBYM3uEzzDk4iImjUGQImIiIiIiBowb7m7WK7UHQCyzpYg1qAJONvzyJliDF37LVZN6Im8Ucmw+AQ7eYYnERE1N2EHQLt37w5BEKr8BocPH67yNURERERERM2R79meoihU2NkdqPhszyNnirEv1wJzBxPULjfP8CQiomYr7ADogw8+GBAAzcjIwLFjx2A2m5GYmAgAyM7Oxu7du9G1a1eMGjWqdu+WiIiIiIioiQgV7LTYXIjVa+CRgbTtx5CemRO0s7uXt9xdFASszswJerYny9uJiKg5CzsAOmvWLL+vN2/ejPPnz+PTTz9F586d/V47fvw47r77brRs2bJ27pKIiIiIiKiR8g10yrIc0MiofLDTYnPh02kp2HsyHysq6OzudeRMMSZu/B4Z9/dH6siuPNuTiIioHLG6F27YsAF33XVXQPATAJKSknDnnXfitddeq9HNERERERERNVYqlQi1Xotokx4ujQrRJj20Bh30URF4YXcO2izLQJtlGcjIOoeV27OwPOMoLDYX4iO1GJbUAmtCdHYP5tpuLeF2SSiyWEvL3S02uG1OBj+JiIhQgyZIeXl5UKtDX65Wq5GXl1fd5YmIiIiIiBodb7anIAARkf4d2016DXbOGIj3fzitNDLyBjsnbzqg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6qabT+v093RzTbGA9D8KMDrcy2hf3dT0B/lFOJD2B2LDPcU+phKduudPaN8YMyK9LZrabmoKOxERERERERERPT04BZ5sws5Ohiyl2mBqubGiQZa2AaaLC6kKtZjc4UUAMFtdXeEiR8cX60iqsM9Puow9Ma1hJ/u7TZfodLKTGa3Ebm5qOxERERERERERPb2YACWbKC4WoHBxMFhDEygZWXlo5MuShKOxJKS5xKQ4AlOAWB1da29XZnX1nEI17OxkBv1UhVqjic6CvxKdpiqxExERERERERHRP4tMYHbnidFqi/HwYf6TPgybkbs44uPkq5i995LBY8t7NEVUSw84O9pLkpACBLg4yc22Fag0EIo0JkdgymQy2NnJUFwsmE1WGutn6XPp0cjldqhZsxr+/DMfGg1H0lZ1jAfSYSyQPsYD6WM8kA5jgfQxHkgf44EAoFatarC3L3uFT44AJZsRijSY3KExAEhGcI4O98KQkIZQ5hUit6DIYGSlsdGW1ozAtLS6urF+rMxORERERERERFS5MQFKNqPVFkOZV/jXdPMmyFGp4e7sgAKVWrKGpiVJSCYmiYiIiIiIiIjIFpgAJZvSaosBZRGUGg3qKqohKysfGjWHohMRERERERER0ZNR9iR5onLQzVrnsppERERERERERPQkMQFKRERERERERERElRYToERERERERERERFRpMQFKRERERERERERElRYToERERERERERERFRpMQFKRERERERERERElRYToERERERERERERFRpyQRBEJ70QVRVgiCguLjyvvz29nbQaouf9GHQU4LxQPoYD6TDWCB9jAfSx3ggHcYC6WM8kD7GA9nZySCTycrsxwQoERERERERERERVVqcAk9ERERERERERESVFhOgREREREREREREVGkxAUpERERERERERESVFhOgREREREREREREVGkxAUpERERERERERESVFhOgREREREREREREVGkxAUpERERERERERESVFhOgREREREREREREVGkxAUpERERERERERESVFhOgREREREREREREVGkxAUpERERERERERESVFhOgREREREREREREVGkxAVqFXLt2DTNmzED37t3h5+eHbt26GfQpKirC4sWLER4ejubNm+Ott95CSkqKQT8fHx+Df9q0aWPQb//+/ejZsyeaNm2Kdu3aYfny5dBq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", + "text/plain": [ + "<Figure size 1600x400 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "forecaster = NaiveForecaster()\n", + "forecaster.fit(y_train)\n", + "y_pred = forecaster.predict(fh=fh_rel)\n", + "y_pred_forward = forecaster.predict(fh=fh_rel_forward)\n", + "\n", + "plot_series(y_train, y_test, y_pred,y_pred_forward, labels=[\"y_train\", \"y_test\", \"y_pred\", \"y_pred_forward\"]);" + ] + }, + { + "cell_type": "markdown", + "id": "1b5f0813", + "metadata": { + "id": "1b5f0813" + }, + "source": [ + "### Univariate time series" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "f52e9196", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 365 + }, + "id": "f52e9196", + "outputId": "551a19a5-14dd-4387-d36c-16ca9bbacb38" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MASE: 2.864\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABUAAAAFkCAYAAADhdJEIAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAACsiklEQVR4nOzdeXhU5dk/8O85Z5bMJJlMEkBAWZJAABUBRdZhDaDgWuv6tlQlRfoia8ViABHUSqQuSJCCGNxxr69aqCUKQoOo9QdILSBLgqAQI8skk8w+c35/hDnMycwkM1nI9v1clxflzDMnZ+JjKl/v+7kFWZZlEBEREREREREREbVCYlM/ABEREREREREREVFjYQBKRERERERERERErRYDUCIiIiIiIiIiImq1GIASERERERERERFRq8UAlIiIiIiIiIiIiFotBqBERERERERERETUajEAJSIiIiIiIiIiolaLASgRERERERERERG1WgxAiYiIiIiIiIiIqNXSNPUDtGWyLMPvl5v6MRqNKAqt+vNRw+J+oWhxr1AsuF8oWtwrFAvuF4oW9wrFgvuFosW9cp4oChAEodZ1zSoA/eGHH5Cfn49vv/0Whw4dQnp6Ov7+979HXP/pp5/i/vvvR8+ePUPW2Ww2LFu2DJ9++ik8Hg9GjBiBRYsWoUOHDqp1u3btwpNPPon9+/cjNTUVd911F6ZOnar65smyjHXr1mHDhg04c+YM+vTpg5ycHPTv379en9fvl3HmTGW97tFcaTQikpPjUV5uh9frb+rHoWaO+4Wixb1CseB+oWhxr1AsuF8oWtwrFAvuF4oW94paSko8JKn2ALRZtcAfOnQI27ZtQ7du3ZCRkVHjWqfTiSeeeALt2rUL+/qcOXOwY8cOLFmyBE899RSKi4sxdepUeL1eZc0PP/yA7OxstG/fHmvXrsXdd9+NlStXYv369ap7rVu3DitXrsQ999yDtWvXon379pgyZQqOHz9e/w9NREREREREREREjaZZVYCOHTsW48aNAwA89NBD+O677yKuXbt2LTp37oxLLrkkZN3u3btRWFiI/Px8WCwWAEBaWhomTZqEzZs3Y9KkSQCA/Px8JCcn45lnnoFOp8PQoUNx5swZrFmzBpMnT4ZOp4PL5cLatWsxZcoU3HPPPQCAq666Ctdeey3y8/OxZMmShv9GEBERERERERERUYNoVhWgohjd4xw7dgwvvfQSFi1aFPb17du3w2QyYfjw4cq19PR09OnTB9u3b1ety8rKgk6nU65NmjQJ5eXl2L17N4CqFvmKigpMnDhRWaPT6TB+/HjVvYiIiIiIiIiIiKj5aVYBaLT+/Oc/46abbkLv3r3Dvl5UVIS0tLSQQ1DT09NRVFQEALDb7Th58iTS09ND1giCoKwL/Fp9XUZGBk6cOAGn09kgn4mIiIiIiIiIiIgaXrNqgY/Gli1bsHv3bnzyyScR15SXlyMxMTHkelJSktIub7PZAAAmk0m1RqfTwWAwoKysTLmXTqeDXq9XrTOZTJBlGWVlZYiLi6vz59Foas+g/X4fvF4fgJYz4cvnE+F0OuHzeeD3t9ZDeQVoNBJEUWrqB2nxJElU/UoUCfcKxYL7haLFvUKx4H6haHGvUCy4Xyha3Ct106ICUJfLhSeeeAIzZ85ESkpKUz9OvYmigOTk+Iivy7KMkydPwmotgyy3nPAz4Oefm/oJGp8gCDCbk9CpU6eQimOKnclkaOpHoBaCe4Viwf1C0eJeoVhwv1C0uFcoFtwvFC3uldi0qAD0lVdegSiKuO6661BeXg4A8HiqKgzLy8sRFxcHnU4Hk8mEkpKSkPeXlZUhKSkJAJQK0UAlaIDb7YbD4VDWmUwmuN1uuFwuVRVoeXk5BEFQ1tWF3y+jvNwe8fXKShvOnj2DhAQz9Po4AC0nYBOEqoDX75fRArPbKMlwuZw4ffoM/H4R8fGhVccUHUkSYTIZUF7ugM/XWiuGqSFwr1AsuF8oWtwrFAvuF4oW9wrFgvuFosW9omYyGaKqhm1RAWhRURF++OEHDB06NOS1q6++GkuWLMFdd92F9PR07Ny5E7Isq6ryiouLkZmZCQAwGo3o1KmTcsZn8BpZlpUzPwO/FhcXq84cLSoqQufOnevV/g4AXm/4zVrVXn8WcXHxSEioe8jalDQaMeLnay20Wj28Xg/Kys5CpzOyCrSefD5/q98z1DC4VygW3C8ULe4VigX3C0WLe4Viwf1C0Yp2rwiCEFSg1mor1GrVog4MmDp1Kl599VXVXxaLBRdffDFeffVVjB07FgAwcuRIlJWVYefOncp7i4uLsW/fPowcOVK5NnLkSHz22WfweDzKtU2bNsFkMmHAgAEAgCuvvBIJCQn4xz/+oazxeDzYvHmz6l4Nze/3w+/3IS7O2GhfgxpGXJwRfr+vFZ91SkREREREREQtiSSJ0MRLSEyOgyfOj8TkOGjipTZ7dmizqgB1OBzYtm0bAOCnn35CRUWFMuxo0KBByMjIQEZGhuo9H3zwAX7++WcMHjxYuTZgwABYLBYsWLAA8+fPh16vx7PPPotevXphwoQJyrrs7Gx8/PHHeOCBB3DXXXfh4MGDyM/Px9y5c6HT6QAAer0e06ZNQ15eHlJSUpCZmYk333wTVqsV2dnZjfa98Pt9AMABOy1A4O+R3++DJPHvFxERERERERFdWMGVnqIowJCow5P/2YK8/YWwuh0w6wyY2ceC+X3HwmFzt7n2+WYVgJ4+fRqzZ89WXQv8/tVXX1WFnLVZsWIFli1bhsWLF8Pr9cJisWDRokXQaM5/5G7duiE/Px+5ubm47777kJKSglmzZmHKlCmqe02dOhWyLGP9+vU4c+YM+vTpg/z8fHTp0qUenzY6bKlu/vj3iIiIiIiIiIiagiSJEOIEGPU6WF0OmPUGOL0ePPmfLXjs2wJlndXtUH4/u/cIoLKpnrhpCHJbPgCgifl8fpw5E37HeTxunD59EqmpnaDV6i7wkzWMtnAGKNA6/l41NY1GRHJyPM6erWwTe4bqjnuFYsH9QtHiXqFYcL9QtLhXKBbcLxQtrVaE2RwPq7USfj9CKj0zElPx7c3zcMnbj8LqdoS836wz4MSdj8B21tkqzgRNSYmPqq2/bTb+U4uSn78W//nPtw16z127voHFMhAHDuxr0PsSERERERERETUEQRCqKjzP/aqJl2BM1KPUUQFjoh5SvKhUegbCToNGixKHLWz4CVRVgpa5nRDFttXN2qxa4KlxtdTJXy+9tA4GgxF9+/ZrsHv26tUba9a8hG7d0hrsnkRERERERERE9VW9rT1Zb4BPlvHk3tBKz7z9har3ltht6BCXALPOELECNEkXB1ul80J9nGaBAWgbIEkiBJ0GxjgNrA4PzAYt7E4vZLe3VR1663I5odfHRbU2Pj4Bl1/et5GfiIiIiIiIiIjovHDFabUNMPp4XDa++uUYHg860zNSpecpVyU+O3kQ9/cZjj9/+2nI15/ZxwK7y92iCuMaAlvgWzlJEmFI0GPFjmJ0Wlqg/PXcjqMwJOijOiehPgoLt8NiGYjjx4+prpeXl2Ps2OH429/erfH9FstAAMDq1c/BYhkIi2Ugdu36RnnttddexurVK3Hjjdfg+usnAAC++24v5s+fi5tuuhbjxllwzz3/g08+2ai6b7gWeItlIN544xXk56/FDTdMwHXXZeGJJ5bC4QhfNk5EREREREREbVtwm3pNJElEolFGSrIOJn1l1a/xArQJGiQmx8ET50diclxIW3s7fTxGdczAqhoqPavL+WYTZl1qwcP9xiuvm3UGPNxvPOb3HQvZ2bbCT4AVoC2OLMuwe6Kv2kw0aZG79TAeKzikXLM6PHi04CAAYMbQbqh0eKK6l1Fb+z/Q1Q0dOhzt23fAxo0f4Q9/mKFcLyj4BAAwfvy1Nb5/zZqX8Ic/3Itbb70D48ZVrU1LO9+2/t57b+LSS/vioYcehs/nBQCUlJxE3779cPPNv4ZOp8d//vMtcnMfgyzLmDjx+hq/3vvvv4N+/QZg4cIlOH78GFavfg7JySn43/+dGdPnJiIiIiIiIqLWS5JEGPU+6OL08DutEOPMcDudsLsk+Hz+kKrOpEQR5d88hV8OvAVBY4AU3wnm69/Biu+219jW3tGYiFJnRUyVngfKSvFW0R7MvWwkcvplocztRJIuDnaXGw6bu1V1A0eLAWgLIssybnhjN/79U3lU69vF61C8MAt5hUfDvr6ysBgPjsnApU9/hVOV7lrvN+hiEz76zYCYQlBJkjBp0g3YuPEjTJ36v5AkCQCwceNHGDVqDBITE2t8f6BNvUOHjmFb1hMTk/DEE39RPdO4cdco/1uWZfTrNwClpT/jww//VmsAmpraDo888jgAYMiQYTh48AA+//wzBqBEREREREREbVwg1BQEwJRQFWj+vOd5+F1WiHozTP1nIGngn+D1+KHV65Rg1O9xouK/L8PXYRA6DPwTrI5yGONMePK77Xislrb2ms70zPlmE7ZNmg4RghKimnUGzOxjQXbPwXDY3LD5ndCIAmyVrWPqe10xAG1hYqm/7JioR2mFG9YIFZ5Whwe/VLjRMVEfVQBaV9dffxNefXU9vvpqJ4YNs+Dw4UM4ePAA7r9/dr3vPWTIsJBAtry8HOvXr8W//rUNp079Ap/PBwBISkqq9X5XXz1Y9fvu3dPw2Web6/2cRERERERERNQyVa/2FLRGlH+zHNav/qys8busqDz4HpKunA37tytQca7SU5Di0On2LdD2+h88u+9L5H35BDSCiKLbFkY1wKghKj19vrYbfAYwAG1BBEHAR78ZEHULvCgKuMikh9mgDRuCmg1adDLp8fffDIDfX/s/DHVpgQeATp064+qrB+Pvf/8Qw4ZZsHHjR+jU6WJceeXAmO9VXUpKSsi1J55Ygu++24t77vk90tIyEB8fjw8+eA9bthSEuYNaQoK6IlWr1cLtbrxwmIiIiIiIiIiaL0kSlfb1n/c8D4gadJlyCOV7ng9Zm2z5M2z7XlNVepoNSajw+fHM/i/x2N7PAACXJ3eMqa0955tN+HzSdAgQsIqVnnXCALSFEQQB8Top6vV2pxezLGnKmZ/BZlnSYHd6YdA0/iysG264GUuXLsIvv5SioOAfuPXWO+sUpoZS38PlcuGLLwoxY8Zc3Hrrncp1/sNPRERERERERNEIPr/TqPeh/JunlGpPberl8NlL4XdZAQCioR0kY0fIfjcMXbPg9LqUSk/1uZ5fKPePta29xGHD20V7MO/yUVjYLwtlHieStHGoZKVn1BiAtnKy24v5YzIAVJ35aXV4YDZoMcuShvljMuCocF2Q5xgxYjQSE01YunQRysvLaz2LM5hGo4HbHd1zejwe+P1+aLVa5ZrdXonCwu0xPzMRERERERERtR3hBhsJQFXl5zk+ewkkYwfoLroa+kGLkNh19PlKT7+60hMIf65nrW3tR3bhj5eHtrV7KnzwiT60NyfAaq2EN4Yh2W0dA9BWzufzw1Hhwuzh3ZGT1QNlDi+SDBrYnV44KlwXbPKXRqPBxInXYcOG1zBo0FBcdFHHqN/brVsaCgu3o1+/ATAYDOjatRuMxviwaxMSEtCnz6V4/fWXYTabIUkavP76y4iPT4DVeqahPg4RERERERERtQI1DTbSdxqKDpM2hFR7On/ejZRfb8aT/9leY6UnELnaM9DWDgDP799xvq2991BMybgCetkDARJSZBdE6GCQvbBDQqDBlY2usWn83mdqcj6fH16HGzarAxqPFzarA16H+4KFnwEjR44BAFx33Y0xve+Pf5wPv9+PefNm4fe//x0OHNhf4/pHHvkzLrmkC/785yVYseIvGD06C9deO6nOz01ERERERERELZsgCJCk87NNJElEolFGSrIOJn0lTPGyMtgoEHh6rIcgxpmhu+hqJN7wITpOOQLtTf+Ar8NVePK7Qjy29zMl1AxX6Qmoqz2DHSgrxehNq3Fr9ytw4s7FOHnrgzhx+wLMbGeEHjLKdz2L4y9cguMvdMLxFy6BY+8KJCWKEMWGOE6w7RFkHo7YZHw+P86cqQz7msfjxunTJ5Ga2glare4CP1nD0GhEeL3nQ9YXX1yDDz54Fx988A/odC3zM4XTGv5eNTWNRkRycjzOnq1U7Rmi6rhXKBbcLxQt7hWKBfcLRYt7hWLB/dJ4zre1xylt7R6XG1qthLJvllcNMzo32Oj4i2nwu6xKpafPXoL2E9+A0HFQVbXngS+UCe5d33lMFXa208eHvQ4AvZM6YNuk6Vi1b4dyrmfVEKPh+FOfQbB++Cv4PTb47CVoN24t3D//P1i/fiLks5gHL4Kx3xzojSbulXNSUuIhSbXXd7IFnhrdsWNHcezYD3jvvbdxyy23tarwk4iIiIiIiIiap+oT3P0uK0S9GR1v/Qxlh/8WMthIMnZE/IRXlHM92xtMcDjLseJctScQ+wR34Ny5nkV7MPcy9bmeHp8Hnn0vwXN2P/wuKzRJGTB0G4dTm7PDfp7yPauQNOihmL4HwQOd2nINJANQanTLlz+Bffu+w+DBQzF58r2q17xeb8T3VZWnRz/xnoiIiIiIiIjajkjhXuB6fJx6gjsAQNRAa06vqvxE1bmeYpwZkvEipNy+DcvDTnAvVN4e6wT3qkpPC7J7DobD5obN74RGFGCrdEIUBRh7/hZd+v4efmcZxDgz/K6zSgt+dX6XFX5XGURj+1q/N+EGOrmdTthd0gU/ErE5YABKjW7VqhfCXj958gRuuy3yeaD9+18Z8b1ERERERERE1DZUDzojhXtOjwZxWu+562WQ9EkoCQo6JWNHiHpz2GpPO0Q8tf/r+k9wD1PpaXe54bCdn8Xi88nKrza7AMHhhigaITtdSDabIerNYUNQUW+GqE869z2J/D0SRSFs5aup/wwkDXwQZTa0uRCUASg1mXbt2uPFF1+N+LrRaLyAT0NEREREREREzUm4oLPq/E4RZdXCPfPQJTBdfi/K/v0sft7zPKSES3DRjX8LCTrNhiR4ZCDljn9h+X+/QN6XTyjnegZXegJ1mOAeodKzttZzWZaVUNTtdMLUfwasXz2uWqNN7o32k96AAMBnL4UpMVzoW/U98nucIZWvfpdVuafxijmw2dvWMCUGoNRktFoteve+tKkfg4iIiIiIiIiamWjP7wSqwj1NYheUff0krF8/EdTW3iGkrd2sM+DzidPx/tG9dT7XMzDB/c3Rk7Go3zhYa6n0jIXdJSFp4IMAqs789Lus0F10NTrdsgllu1agpIbQN3CO6MWTdykt/tUFzhEVHO42dSYoA1AiIiIiIiIiImpWjPraz+9ULhvawdB1LKxf5yLxhg9rbGvXCCLSE1Prfa7nbd37oWdiO1SWu6CRo6v0jIbP50eZrapKM2nQQ/A7yyBoDSj7f0/XGPoGCBoDfJUlNZ8j6iyDKBrrFNC2VAxAiYiIiIiIiIioWagaiCxAF6fFz9WCTsnYET57qRLuqc71dJ5F8s0fY/m+r2psa+9oTAyp9myIcz0bks/nV84GlSQjkuK0EUPf6hPjffYSSMYONZ8jGpcEv8Pd4M/dnDEAJSIiIiIiIiKiJqU679Nlg+yqDAnwAuGe7qKroR+0SHWup0OW8cx3n9fa1n6hzvVsCLIsQ5YF+J3WkO9F9TA4wO84BcexLTD1m66qDA0w9Z8Bt9MJWeYZoERERERERERERI2mpqnlEDXoMuWQUsUYqPT02UvgPPk1Un69GU/+Z7tyrmdGYiq+vXke8vZ/odw/UtDZFOd61offL0OMC50MX1Ol59nCheh0+xZAEJVzRANT4E0DH0SZzQ+AU+CJiIiIiIiIiIgaXLjJ7uGmljuObYF5yGJ4TBlKpWd7gwkOZzlWfFeoOtfToNGixGGLuq0955tN+OL6WRfsXM/6kGU57GR4pdKz//3qc1IBeM4eQMX37yBxwGzlHFExLglupxNlNn+jtO03dwxAiYiIiIiIiIio0QSqPQUBMCWoJ7tXn1oeqPas/P5dmCa8iGf3bkHeO9UrPdXnesba1n5b937QCxLm9L5w53rWR7jJ8KLeDK/tOJKu/hMAIaTSM+Gye1Fm88Pvd0MUjfA73Ofa3pvXZ7tQGIBSs5efvxaDBg1B3779Gvzeu3Z9g+++24vf/W5Kg9+biIiIiIiIqC2rXu0paI0o/2a5qmIxMLVcMnZE/IRXlGpPQ5wJuXu34rGg6s1wlZ5A3dra7eeCTq/dd0HP9ayL6pPhZVcZBH1VRWd5hQxD0MT4cJWebWnaeyRiUz8AXThVk9RECELLOuj2pZfW4T//2dso9969+//htddeapR7ExEREREREbUlwbmDJIlIShTh2Pssjr9wCX56vT8EQVBVempTL4fsd0MyXoSU27dhlRXo/M4TuOLvqyEKUo2VntXlfLMJsy614OF+45XXQ9raHQJsZ53wVvqUcFCWZfh8/mYbfgYEJsOX2zyQjO1RbvPAZhfg8fhgsws4c9aNcpcRZ866YbMLza6KtamxArQNCHe+htvphN0l8R8IIiIiIiIiIqqXaM711KZeDp+9NKTS02wwocLnxTP7v6p1gntN53oeKCvFW0V7MPeyltHWXleBnLZ6XlsV5DbvELcpsQK0lav+X1yOr7sEx1+4BI69K5CUKEKSGncLFBZuh8UyEMePH1NdLy8vx9ixw/G3v71b4/stloEAgNWrn4PFMhAWy0Ds2vUNgKp/uDdseA133nkLxowZittuuwlvv/2G6v2lpT/j4Ycfwg03TMDYscNw2203YuXKpwFUtda/9NI6OBwO5d4zZtzXUB+diIiIiIiIqNULlzv89Go/iBqtqtpTjDOHVHp2fv8v6PvhCmg1ccjbv0O5Z10qPR/uNx7ZPQfDV+mH7awzbLUntV2sAG1hZFkGfPao1xsNepR/s1J1vobfZVUmhxn7zkS5zRXdzSRjzO3zQ4cOR/v2HbBx40f4wx9mKNcLCj4BAIwff22N71+z5iX84Q/34tZb78C4cVVr09LSAADPPfcUPv74//C7303BpZdeju++24u//jUPer0eN998KwDg8ccfwalTv2DOnHlITk7Bzz+X4Pvv9wMAbrjhZvzySykKCj7Bc8+tAQDEx8fH9PmIiIiIiIiI2prAUCO/X4ZR71MqPQNt7aLeHPZcTztEPLX/63pNcI+20pPVkBSMAWgLIssyHJsnwX/q66jWi4Z2aDflEH4+919cqivfswpJAx+A443L4Hecqv1+7QfDMH5jTCGoJEmYNOkGbNz4EaZO/V9IkgQA2LjxI4waNQaJiYk1vv/yy/sCADp06Kj8bwD46acf8f7772DevBzcdNMtAICrrx4Mp9OJl15ahxtvvAWiKGL//v9i2rT7kZU1QXnvxInXn7vnRWjfvgNEUVTdm4iIiIiIiIhChWt1FwCcProZiTd8GNTWngSPDKTc8S8s/+8XyPvyCWgEEUW3Laz3BPeZfSzI7jkYDpsbNr+z2Q8wouaBLfAtTSzho7EjfPZS+F3WsK/7XVb4HL9AMnZsoIcL7/rrb8Lp06fw1Vc7AQCHDx/CwYMHcP31N9X5nv/+91cAgNGjx8Lr9Sp/DRw4CKdPn0Zp6c8AgMzM3njzzdfxwQfv4ccfj9f/wxARERERERG1QcGt7j+92g8lf7sWpR/fCp/zLJJv/ljV1t75nT/jSMVZLN/3JR7b+xmsbgc6GhNrPdczWGCC+63d++HknY/g5J1LcOLORzC79wil0rOlDDCipscK0BZEEAQYxm+MugVeEAVI8WaIenPYEFTUmyEZO0E/4R/Q+aP4YVGHFngA6NSpM66+ejD+/vcPMWyYBRs3foROnS7GlVcOjPleAWVlVsiyjOuuGxf29Z9//hkdO3bC0qXL8MILz+OFF1bj6adz0bVrN0ybdj9GjRpb569NRERERERE1FYE2t3j43yo+O/L8HUYhA4D/6RUetplGc9897mqrV0jiEhPTFVVe0aq9ASqqj23TZoOEQLy9hcq1Z6qCe4yKz2p7hiAtjCCIACa6M+pdLtcMPWfoZz5GczUfwbcLhcgGiE0ci3wDTfcjKVLF507c/MfuPXWO+sUpgaYTEkQBAGrV78IrVYb8nrXrt0AAO3atcOCBY/A7/fj++/345VX8rF4cQ42bHgfF198SZ2/PhEREREREVFrpmp3d1VA0ifA1+t/8Oy+L5H35ROwuh3ISEzFtzfPQ97+L1TvDVftyQnu1JQYgLZydpeEpIEPAqg689PvskLUm2HqPwOmgQ+izOYH0Pg/SEaMGI3ERBOWLl2E8vJy5RzOaGg0Grjd6kFNV111NQCgrKwMFsvIWu8hiiL69LkMU6dOR2Hhdvz004+4+OJLoNVq4Xa7Y/swRERERERERK1M8GAjURSQlCihouw4BF13WH0+xPvlqAYYATzXk5ofBqCtnM/nR5kNMF4xB0mDHoLfWQYxLglupxNlNv8F+68oGo0GEydehw0bXsOgQUNx0UXRnzvarVsaCgu3o1+/ATAYDOjatRu6du2GW265DY8/vhh33TUZl156ObxeL44fP4bdu7/BsmVPo6KiAn/84wxcc80kdO3aDV6vB++99w4SEhKRmdlbubfP58M777yJvn2vQHx8PLp27d5I3wUiIiIiIiKi5kVd6WmDqE+E3+uGW/bh2R+KkXfgjZgHGEWq9gyc6/nm6MlY1G8crJzgThcIA9A2wOfzw2YXIDjcEEUj/A43ZFnAhaj8DDZy5Bhs2PAarrvuxpje98c/zsdzzz2FefNmweVyYeXKNbjyyoGYM+dBdO3aDR9++De8/PKLMBiM6Nq1G8aMyQIA6HQ6ZGT0wPvvv42ffy6BXh+H3r374NlnV8FsNgMAhg8fgV/96ja8/vrLOHv2DPr1G4BVq15o6I9ORERERERE1GwEqj0FATAlBFV6er0wa/1wCZLqXM/LkzvWOsCoelt7zjeb8MX1s3iuJzULDEDbkKrpaE33Q+XLL79AUlISRowYFdP7+vXrj/XrXw+5LggCfv3rO/DrX98R9n06nQ7z5y+q8d4ajQYPPDAfDzwwP6ZnIiIiIiIiImppqld7Cpo4VaVnpHM96zrASC9ImNOb53pS02MASo3u2LGjOHbsB7z33tu45ZbboNPpmvqRiIiIiIiIiFq9ms/19CJeq8FT//m81nM96zrAyH4u6PTafTzXk5pUswpAf/jhB+Tn5+Pbb7/FoUOHkJ6ejr///e/K6xUVFXjppZewbds2HD16FDqdDldccQXmzp2LXr16qe5ls9mwbNkyfPrpp/B4PBgxYgQWLVqEDh06qNbt2rULTz75JPbv34/U1FTcddddmDp1qmpCuSzLWLduHTZs2IAzZ86gT58+yMnJQf/+/Rv1+9FaLF/+BPbt+w6DBw/F5Mn3ql7zer0R3ycIAiRJauzHIyIiIiIiImpVGuNcz/oMMGrqjlSiZhWAHjp0CNu2bUO/fv3g9/tD/qvAiRMn8Pbbb+PXv/415syZA5fLhfXr1+OOO+7A+++/j4yMDGXtnDlzcPjwYSxZsgR6vR4rVqzA1KlT8f7770OjqfrYP/zwA7KzszF8+HDMmTMH33//PZ566ilIkoTs7GzlXuvWrcPKlSsxb9489OrVC2+88QamTJmCDz/8EF26dLkw35wWLNKZmidPnsBtt0U+D7R//yt5HicRERERERFRDCRJVFd6NtC5nhxgRC1ZswpAx44di3HjxgEAHnroIXz33Xeq1y+55BIUFBTAYDAo14YMGYKxY8diw4YNePjhhwEAu3fvRmFhIfLz82GxWAAAaWlpmDRpEjZv3oxJkyYBAPLz85GcnIxnnnkGOp0OQ4cOxZkzZ7BmzRpMnjwZOp0OLpcLa9euxZQpU3DPPfcAAK666ipce+21yM/Px5IlSxr5u9J6tWvXHi+++GrE141G4wV8GiIiIiIiIqKWSxQFaDQiDDq5Uc/17GniACNqeZpVACqKYo2vhwvE4uPj0bVrV5SWlirXtm/fDpPJhOHDhyvX0tPT0adPH2zfvl0JQLdv347x48erzqScNGkS1q5di927d2Pw4MHYtWsXKioqMHHiRGWNTqfD+PHjUVBQUOfPSoBWq0Xv3pc29WMQERERERERtVharQQpDtBrdbC6HZA0ukY919NRzgFG1PI0qwC0LsrLy3Ho0CEMGzZMuVZUVIS0tDTVOZ5AVQhaVFQEALDb7Th58iTS09ND1giCgKKiIgwePFhZX31dRkYGXnnlFTidTsTFxdX5+TWa8KGv3y+Evd5SBL71ggC0lf8YJElCxL+fVDNJElW/EkXCvUKx4H6haHGvUCy4Xyha3CsUi1j2iyBUzcyQZRmSJEJr0CB372fI27+jYc/1zBwMd6UHDtkFvSDC4XIBctXX5599mw5/ttRNiw9A//KXv0AQBNx1113KtfLyciQmJoasTUpKUtrqbTYbAMBkMqnW6HQ6GAwGlJWVKffS6XTQ6/WqdSaTCbIso6ysrM4BqCgKSE6OD/ua0ynh1CmxxYdqbeEfSL9fgCiKSEoy1isMJ8BkMtS+iAjcKxQb7heKFvcKxYL7haLFvUKxqG2/VHrc0IoirG4nzLo4OH0e5O79DI+dq+Cs77meZR4nkrRx8Pj9MGi0MCRpG/5DUoPgz5bYtOgA9P3338c777yD3NxcdOzYsakfJ2Z+v4zycnvY19xuF/x+P3w+GV5vyystF4Sq8NPn87f6ClCfT4bf70dZmR0Oh6+pH6dFkiQRJpMB5eUOtlJQjbhXKBbcLxQt7hWKBfcLRYt7hWIRbr8EV3oKggBdvBZ/+c9W5UzO8+d67lDuU59zPZ2VbuhkEXanC7IMuOG5oN8Dig5/tqiZTIaoiu9abAC6bds2LF68GNOnT8evfvUr1WsmkwklJSUh7ykrK0NSUhIAKBWigUrQALfbDYfDoawzmUxwu91wuVyqKtDy8nIIgqCsq6tI4WZLn5oWCD1be/gZrKWG1c2Jz+fn95Ciwr1CseB+oWhxr1AsuF8oWtwrFItAEZEQJ8Cg18HqcsCsN8Dp9eDJvVvw2LfnZ5HwXM+2jT9bYtMiA9A9e/Zg9uzZuPnmmzF79uyQ19PT07Fz507lv5IEFBcXIzMzE0DVQKVOnTopZ3wGr5FlWTnzM/BrcXExevfurawrKipC586d2fJMRERERERERPUSiC4kSYDWoMWT/9kSptKzYc71dJS7YfM7oRE5xZ3ajhZ3QOPhw4cxbdo0DBkyBEuXLg27ZuTIkSgrK8POnTuVa8XFxdi3bx9GjhypWvfZZ5/B4zlf1r1p0yaYTCYMGDAAAHDllVciISEB//jHP5Q1Ho8HmzdvVt2LiIiIiIiIiCgWkiRCEy/BmKhHqaMCokHCk/+pqvQMhJrhKj0BdbVnsMC5nrd2vwIn73wEJ+9cghN3PoLZvUcolZ6yLCu/ErUFzaoC1OFwYNu2bQCAn376CRUVFfjkk08AAIMGDYIsy8jOzoZer8fdd9+tDDQCgISEBPTo0QMAMGDAAFgsFixYsADz58+HXq/Hs88+i169emHChAnKe7Kzs/Hxxx/jgQcewF133YWDBw8iPz8fc+fOhU6nAwDo9XpMmzYNeXl5SElJQWZmJt58801YrVZkZ2dfqG8NNYFDh77Hvff+BitXrsGVVw5s6schIiIiIiKiFk4QBIiiAL9fhigKMCTqlGrPWCe4AzWd63kFMk3t4ahwQ+NjpSdRswpAT58+HdLSHvj9q6++CgDK2Z733HOPat2gQYPw2muvKb9fsWIFli1bhsWLF8Pr9cJisWDRokXQaM5/5G7duiE/Px+5ubm47777kJKSglmzZmHKlCmqe0+dOhWyLGP9+vU4c+YM+vTpg/z8fHTp0qXBPvuFEPyDlj/4iIiIiIiIiC4MSRIhxAkw6nVKSOn0epRqTyD2Ce5A4FzPXfjj5SOxoF8WytwOJOkMcHnccFZ44PFwUC8R0MwC0EsuuQTff/99jWtqez0gMTERTzzxBJ544oka11155ZV45513alwjCAKmTZuGadOmRfW1mxvVD9pzByjbXW7ITrlVH3Lscjmh1/OMViIiIiIiIrrwRFGARiNClmXoE3R4cm/N53rWpdJzZu+hmJJ2OXReByrsfugECTa7E34/i56IgrW4M0ApNpIkwpCow3MH/oXOby1F57eXovNbS/HcgX/BkKiDJDXuFigs3A6LZSCOHz+mul5eXo6xY4fjb397t9Z7WCwD8dprL2P16udw/fXjMH78SPz5z0tgt1cqa3bt+gYWy0B88UUhFi36EyZMGIWHH34IAGCz2fDUU7m46aZrMGbMUEyZ8lt8/fWXIV/n5ZdfxI03XoPx40dgwYIHcfbs2Xp+eiIiIiIiImprtFoJcYkSEs1xcOl80MRrlAnuNZ3rGelMT+BcpeeRXZjToy9O3L4AJ299ECduX4AZSTLO/t8NEPUJ8HpluN0+hp9EYTSrClCqnSzLsPs8tS88J9EYpyqpBwCr26H8fkYvCyrL3VHdyyhpIQRG00Vp6NDhaN++AzZu/Ah/+MMM5XpBQdXZruPHXxvVfd5//21kZvbGwoVLcOLECaxZswputwtLly5TrVu+/M+YMGEinnjiVoiiCI/Hg7lz78eZM6cxdep0tG/fAZs3b8KDD87G+vVvICOjh3L/F19cg7vumoyBAwfh3//+Crm5j8X0WYmIiIiIiKjtCT5uTqMREZegRe7ez5C3f0fM53rWOMG951U4/eZQlDlPQTJ2RIm9BH7HKZgHL4Lb6YQsx/bndaK2hAFoCyLLMm784iX8++zxqNa308eH/UEbkLe/EA/2HYPLti7HKVdl2DXBBiV3wYfD7o0pBJUkCZMm3YCNGz/C1Kn/C0mSAAAbN36EUaPGIDExMar7aLU6LFv2lPJ+vV6PJ598HFOmTEO3bt2VdRbLSEyfPkv5/caNH+HQoe/x8stvIi0tHQAwePBQHD9+HC+//CIeeywXPp8Pr732Mq65ZhLuv3+2subs2TP45z83Rf1ZiYiIiIiIqO2QJBGCTgNjnAZWhwdmgxZunwu5ez/DY+fO6oz1XM/ABPc3R/8WC/tlocx+BklxJlSc+Ao6vxvxmbeifM8qeE5/B1FvhnnwIpgGPogymx9A6z3ijqi+2ALfwsTy33M6GhPD/qANsLod+MVZgY7G6ELIurr++ptw+vQpfPXVTgDA4cOHcPDgAVx//U1R32P48BFK+AkAY8ZkQZZl7Nv3nWrd0KEW1e+//vpLZGT0QJcuXeH1epW/rr56MA4c2AcA+OWXUpw69QtGjhyjeu+YMVkxfU4iIiIiIiJqWQRBqAoyoyz0CazXaEQYEvRYsaMYnZYWoNPSAoxctQN6jQ55+3co64MrPavL+WYTZl1qwcP9xiuvBya49zDE4fS74+D+v4koWZ+B8g8moOLAm0gcMBtd7vsRXab+hC73/QjDFXNQZvO36vkeRA2BFaAtiCAI+HDYvVG3wIuigIuMprAHKANVP1g7GU34eOiUqM4IqUsLPAB06tQZV189GH//+4cYNsyCjRs/QqdOF+PKKwdGfY/k5GTV7+PjE6DT6XH69CnV9ZSUFNXvy8qsOHjwe4wePSTknoFA9dSpU2G/RnJyatTPR0RERERERM1DcEu6LIf/s2646k270wvZ7YXP5w+5R/X1Rp2E3K1H8FjBIeWel5ir/uwd6VzPsBPcz53rmdN3JMqc5UiKS4LH74Vn38vwnN0Pv8uqVHomXHYvymx++P1uiKIRfof7XNs7w0+i2jAAbWEEQUC8Rhf1ervLjZl9LKozQANm9rHA7nLDIGobvRb4hhtuxtKli/DLL6UoKPgHbr31zpjC1OoDiSorK+B2u5Ca2k51vfo9TaYkZGT0RE7OwxHv3a5du7Bf4+zZ01E/HxERERERETWtaENNQQDi4vXI3XoYeYVHlbWzLGl4aEwGnB4fDPrz93C6fNBpJeRuPYS8wqPQiAKKF2Yhr7BY9fX3/WyDWWeo97meUlw7tJ/0Brre9yN8zjKIcUlwO52qSk+fj4OOiGLBALSVk50y5vcdC6DqzM/gH7Tz+46FwxbdAKT6GjFiNBITTVi6dBHKy8sxceL1Mb1/x45/YebMuUrV5tatn0EQBPTpc1mN7xs4cBB27tyBdu3ao1279mHXtG/fAamp7bB9+1aMGnW+DX7r1s9iekYiIiIiIiJqHJGqOusSaoar3rQ6PHjn2xOYOyodzxYeRV5hsXKPbdOH4b29J5X1l3dMRGmFG1aHujvz+18q8bOtEjP7DFfOAAUineuZBKftR+hFKeRcz/jMW6Ex94C13ANZZqUnUUNgANrK+Xx+OGxuzO49Ajn9slDmdiJJFwe7yw2HzX3BzgnRaDSYOPE6bNjwGgYNGoqLLuoY0/s9HjdycubhV7+6FSdPnsBf/5qH0aOz0L17Wo3vu/ba6/Dhh3/DjBnTcNddv0WXLl1RUVGBQ4e+h8fjwR/+MAOSJOG3v70Hzz33FFJSUnH11YPx9ddfYvfu/1efj0xERERERET1FKmqU/D6IGukGlvSw4Wakao3AWDZpD54+vMjePzT8/fQiALSU42q9SU2Fzok6GA2aENC0P997wDevadqnkReULXnbd2vQKapPbSQkSJpIYoiZH0HlFf4YbhiDpIGPQTZVQZBH1rtSUT1xwC0DfD5/EAlYLM7oREF2CqdEc9BaUwjR47Bhg2v4brrboz5vb/+9R2wWs/isccWw+PxYOTI0fjjH/9U6/t0Oh1Wrvwr1q9/Aa++uh6nT59CUpIZmZm98Ktf3aasu/XWO1BRYcPf/vYuPvjgXQwcOAjz5y/CAw/MjPlZiYiIiIiIqP4kqWrQUPWqzkev6YXswV2Ru+VwzKFmpOrNdvE6jMtsh3vf3qO63jFRH7L+VKUbnx48hRnDu6vCUgDYdKAUf/v2Zzxw+Ugs6DcOZW4HknQGuDxuOCs8qPD6IYp6+O2Bqk4fPB4BWo8HZnN7WK2V8HhY7UnU0BiAtiGyLDfpOSFffvkFkpKSMGLEqJjfK0kSZs6ci5kz54Z9/corB6Kw8Juwr8XHJ2DmzD9i5sw/Rry/IAi4996puPfeqarrke5JREREREREjUvQaZC79XBIVWcXswHLthzC47W0pIcLNSNVb4YLOmtan7NpP7ZNHwYAWLVD3XJ/S9+OcFS44Jad0Gkk2OxO1eDhcH8uD9QoNUGtElGbwACUGt2xY0dx7NgPeO+9t3HLLbdBp4t+iBMRERERERG1PYIgwBinQV7hUdX1+oaakao3I90j0voDpRUYtfoLvDX5Kiwcl4kyhwdJBg3sTi8cFS6lfd3t9jXUt4SI6qGRZ38TAcuXP4HFi3MwYMCVmDz5XtVrXq834l8+H/+PgoiIiIiIqC0SRQFWhyekIrO2UDNYcKgZLGfTfsy0pGHRuJ7Ka16/jKLTdsyyhM6ZyNm0Hw+MzsDi8ZnKerNBi9v7dUbPVCPsNgc0Hi9sVge8jgs3a4OIoscKUGp0q1a9EPb6yZMncNttkc8D7d//Sqxa9QLb0ImIiIiIiNqIwFR3WZZhNmhDKjJjaUkPDjUfLTiorI1Uvel0+TB/TA8AwMqgKfC39+sMvShgjqU7crJ6oMzhDVvtSUTNFwNQajLt2rXHiy++GvF1o9F4AZ+GiIiIiIiILqRA2On3yxBFIWTa+6lKd0jreaDac6alu+ps0LqEmkr1pgzYXJ6quRmSiNnDQ4NO+7mg0+vwVA0XPreeiFoGBqDUZLRaLXr3vrSpH4OIiIiIiIguIEkSVWFnskELnwxlqnsgpFwyIRM5WT0hCFBNgT9udeChsT0hQKhXqBmuetPn8wMON2zO8EFnUw8XJqK6YQDazPG/KDV//HtEREREREQUHUkSYUjQI3frYSXU/Dh7EL46dlaZ6g5UTXuf8+F/IQjAH0ekY0FWT1V46ap0NVioGQ6DTqLWhUOQmilRlAAAfj8HATV3gb9Hgb9nREREREREFJ6g0yB362E8VnAIVocH7eJ1GJ2RilXVpr0HPPLPg4jTSagoUw8a8nh88DrcsFmjH0BUFWr6WcRC1AYxAG2mRFGEKEpwOu1N/ShUC6fTDlGUIIr8x4mIiIiIiKg6QRAgSSJEUYAxToO8oLAz3FT3YFaHB2UOLwRBCBteMtQkomiwBb6ZEgQBCQlmlJefRkWFFjpdHARBaOrHionfL7TqlgFZluF2O+F0VsJkSm1xf3+IiIiIiIgaU7izPs86vFFNdQ8wG7RIMmhgc4UPSImIosEAtBkzGOLh8bhQUVEGwNrUjxMzURTh90duP2gdBBgMCTAY4pv6QYiIiIiIiJqNcGd9ZqQasXfeaFXYGZjqXn3ae8AsSxrsTi8rPImoXhiANmOCICApKRWJiWb4fC3rLFBJEpCUZERZmb1VV4FKksSzP4mIiIiIiKoJPusz4MhpOzZ//wtmWrqrruds2o9t04eFTHufZUnD/DEZcFS4muIjEFErwgC0Bag6X7JlhWwajYi4uDg4HD54va29CpSIiIiIiIiAwHmfAoxxWtVZnwE5m/Zj+/RhECBgZWExrA4PSmwuvL3nBOaNysCCrEyUOTw1TnUnIooVA1AiIiIiIiIiqpfg8z4rXF6UOT1hz/Q8UFqBkau/wI4Zw5GT1VMVdnrsbrj8MjSiAJvLw7Z3ImowDECJiIiIiIiIKCaCIEAUBfj9MkRRUJ33qREFFC/MijjYqMTmglEnoaLMDo0QGna25mPUiKhpiE39AERERERERETUMkiSCI1Bh0SzAR6thESzAZJBi9ytR/BYwSFYHR7VYKNwAoON/H4ZPp+flZ5E1OhYAUpEREREREREEQWqPQUBiIsPP9k9r7BY9Z7AYCMAWLWDg42IqGkxACUiIiIiIiKiEMHnelodHhh1klLpGWDQSiixuUJa3Q+UVmDU6i/wxKQ+OPnIBA42IqImxRZ4IiIiIiIiIlKRJBGGBD1W7ChGp6UF6PvUNoiCEFLpWWJzoUOCDmaDNuQeB0orMOXtPQBkaL0+2KwOeB1uhp9EdMExACUiIiIiIiIiFUGnQe7Ww8q5nh0T9SitcIdUekZ73qfX6+NZn0TUZBiAEhEREREREZFCEAQY4zTIKzyqXKup0jNn037MsqRh8fhM5XWzQYvF4zMxf0wGZLf3Qj06EVFYPAOUiIiIiIiIiIKGHQmwOjyqas/gSs/HPz2ket+B0gq8tecE5o5IQ05WD5Q5vDzvk4iaFQagRERERERERG1Y9WFHZoMWRlRVcQaHoDVNds8e1AWOChdsdjc0ogCby8OWdyJqNhiAEhEREREREbVRgWFHuVsPI6/wfKj5+fRhmGVJw6MFB5W1gcnub02+CgvHZUac7O7zMfgkouaFASgRERERERFRGxJodff7ZdWwowCrw4M7X/t/2DnLAgBYWVisBKO39+uMnqlG2G0OaGSw0pOIWgQGoERERERERERtQLhWd0BQDTsKOFBagWte+BIF04YgJ6tnxGpPIqKWgAEoERERERERUSsXrtV9aPdkvP3bq1TnfAb7+pgVDrcfXq+b1Z5E1KKJTf0ARERERERERNQ4BEGAJIkQg1rdA4HnoV8qkWzUnqsEDWU2aJFk0MDnk+Hz+Rl+ElGLxQCUiIiIiIiIqJWRJBEagw6JZgO8OgnGOG1Iq/upSjc+PXgKM4Z3D3uPWZY02J1eBp9E1OI1qwD0hx9+wOLFi3HTTTfh0ksvxfXXXx923bvvvotrrrkGffv2xY033oitW7eGrLHZbFiwYAEGDRqEAQMGYNasWSgtLQ1Zt2vXLtxxxx244oorMGbMGLzwwgshP9xlWcYLL7yA0aNH44orrsAdd9yBPXv2NMhnJiIiIiIiIqqvQKVn4FdDgh4rdhSj09ICjFvzJU6UO8O2uuds2o+ZljQsHp+pVIKaDVosHp+J+WMyILu9F/qjEBE1uGYVgB46dAjbtm1Dt27dkJGREXbNxo0b8fDDD2PixIlYt24d+vfvjxkzZoQEknPmzMGOHTuwZMkSPPXUUyguLsbUqVPh9Z7/4f3DDz8gOzsb7du3x9q1a3H33Xdj5cqVWL9+vepe69atw8qVK3HPPfdg7dq1aN++PaZMmYLjx483+PeAiIiIiIiIKFrBlZ4erYREswGSQYvcrUeUdvcSmwvtE3RhW90PlFbghvVf44HR6Tj5yASUPDIBJx8Zj9nDu3PYERG1Gs1qCNLYsWMxbtw4AMBDDz2E7777LmTNypUrcd1112HOnDkAgCFDhuDgwYN4/vnnsW7dOgDA7t27UVhYiPz8fFgsFgBAWloaJk2ahM2bN2PSpEkAgPz8fCQnJ+OZZ56BTqfD0KFDcebMGaxZswaTJ0+GTqeDy+XC2rVrMWXKFNxzzz0AgKuuugrXXnst8vPzsWTJksb9phAREREREREFEQQBoihAEIC4ePVgo4xUI/bOG428wmJlfXCr++OfHgq537W9OsDr8cNlc0EjChx2REStTrOqABXFmh/n+PHjOHr0KCZOnKi6PmnSJOzcuRNutxsAsH37dphMJgwfPlxZk56ejj59+mD79u3Kte3btyMrKws6nU51r/LycuzevRtAVYt8RUWF6mvqdDqMHz9edS8iIiIiIiKixlS92lNj1KkqPQHAoJVQYnOFtLsHWt0XjesZsdVdljnsiIhap2ZVAVqboqIiAFXVnMEyMjLg8Xhw/PhxZGRkoKioCGlpaRAEQbUuPT1duYfdbsfJkyeRnp4eskYQBBQVFWHw4MHK+urrMjIy8Morr8DpdCIuLq7On0mjaVYZdIORJFH1K1FNuF8oWtwrFAvuF4oW9wrFgvuFotXQe0UUBegMgWrPYmhEAcULs1SVngBQYnOhw7l29+AQ9EBpBUat/gLLr78UJeMyYXV4kGTQwuHywO1wQxBa759PWwL+bKFoca/UTYsKQMvKygAAJpNJdT3w+8Dr5eXlSExMDHl/UlKS0lZvs9nC3kun08FgMKjupdPpoNfrQ76mLMsoKyurcwAqigKSk+Pr9N6WwmQyNPUjUAvC/ULR4l6hWHC/ULS4VygW3C8UrYbaK5VuL3K3HsZjBQcBAJd3TERphTuk0rOmdvcDpRX45rgVY3qkokNi1Z9x9Rr1n3WpafFnC0WLeyU2LSoAbW38fhnl5famfoxGIUkiTCYDyssdPDSbasX9QtHiXqFYcL9QtLhXKBbcLxSt+uwVURQAjYQ4vRZWhxtmgw5aUVRVe0aq9ASq2t23Tx8GURCwsrAYVocHZoMWsyxpmD+mB9wOF85Wuhrkc1LD4M8Wihb3iprJZIiqGrZFBaBJSUkAqqo327dvr1wvLy9XvW4ymVBSUhLy/rKyMmVNoEI0UAka4Ha74XA4VPdyu91wuVyqKtDy8nIIgqCsqyuvt3VvVp/P3+o/IzUc7heKFvcKxYL7haLFvUKx4H6haMW6VyRJhM6gUw02Gto9GW//9ipV0Flbpedbe05g7og05GT1QJnDiySDBnanF44KJ0OTZow/Wyha3CuxaVEHBgTO4QycyxlQVFQErVaLLl26KOuKi4tDDm4uLi5W7mE0GtGpU6eQewXeF1gX+LW4WH2uSlFRETp37lyv8z+JiIiIiIiIggk6zblW9/ODjQ79Uolko1YZXhRQ02Cj7EFd4HN6YLM6oPF4YbM64HW4GX4SUZvUogLQLl26oHv37vjkk09U1zdt2oShQ4cq09xHjhyJsrIy7Ny5U1lTXFyMffv2YeTIkcq1kSNH4rPPPoPH41Hdy2QyYcCAAQCAK6+8EgkJCfjHP/6hrPF4PNi8ebPqXkRERERERER1IQgCJEmEKAowxmmQV3hU9XpwtWewwGCjW/t1xslHJqDkkQk4+ch4zB7eHY4KlzLRnZPdiaita1Yt8A6HA9u2bQMA/PTTT6ioqFDCzkGDBiElJQUzZ87EvHnz0LVrVwwePBibNm3C3r178frrryv3GTBgACwWCxYsWID58+dDr9fj2WefRa9evTBhwgRlXXZ2Nj7++GM88MADuOuuu3Dw4EHk5+dj7ty5Spiq1+sxbdo05OXlISUlBZmZmXjzzTdhtVqRnZ19Ab87RERERERE1JpIkghBp4ExTgOrw4NkgxZnHd6QMz2BqmrPbWHO9by9X2f0TDXCbnNAIwM2l4dhJxFRNYLcjH4y/vjjj8jKygr72quvvorBgwcDAN59912sW7cOJ06cQFpaGv74xz9izJgxqvU2mw3Lli1DQUEBvF4vLBYLFi1ahIsuuki1bteuXcjNzcX+/fuRkpKC3/zmN5g6dSoEQVDWyLKMF154ARs2bMCZM2fQp08f5OTkKFWideXz+XHmTGW97tFcaTQikpPjcfZsJc+koFpxv1C0uFcoFtwvFC3uFYoF9wtFK9JeEQQBoihAEIC4eL3qrM+MVCP2zhuNix8tCBuCDupqRsG0IdBJEsocHuVcT9ntZWt7C8efLRQt7hW1lJT4qIYgNasAtK1hAEpUhfuFosW9QrHgfqFoca9QLLhfKFrV90r1ak+jTsJTnxfhsYKDqvd9cM/V2PWTFY8VHAq55+LxmZg9vDt8Tg9EUYDfL7Pas5XgzxaKFveKWrQBaLNqgSciIiIiIiJqDQJNhYJQ1epuSDhf7akRBRQvzEJeYXHI+3I27cf26cMgQN3qPsuShvljMuCocJ0715PBJxFRtBiAEhERERERETWQQKWnIU6L0goXkhIMcHq8yN16RKnqvLxjIkor3GHb3A+UVmDk6i+wY8Zw5GT1VLW6BwYbERFRbBiAEhEREREREdVDNOd6Bld7lthc6JCgg9mgDRuClthcMOokVJTZoREEDjYiIqqn2pvkiYiIiIiIiCiEJInQGHRINBvg0UrQGHVKpWcg2DRoJZTYXKqg81SlG58ePIUZw7uHve8sSxrsTi/8fhk+n5/hJxFRPTEAJSIiIiIiIopR4FzPFTuK0WlpAfo+tQ2iIISc6xlc7RksZ9N+zLSkYdG4nsprZoMWi8dnYv6YDMhu7wX7LERErR1b4ImIiIiIiIhiJOg0yN16uNZzPYOrPR//9Pxk9wOlFRi1+gu8NfkqLByXybM+iYgaEQNQIiIiIiIioigEzvqUZRnGOA3yCo8qr9V0rmdgsrsoqCe7396vM3qmGmG3OaCRwbM+iYgaCQNQIiIiIiIiohoEJrsb4zSwOjxINmhx1uGNeK5ncKUnUFXt+daeE5g7Ig05WT1Q5vCy2pOI6AJiAEpERERERERUTTST3atXe+Zs2o9t04cBAFbtOKpUes6ypCF7UBc4Klyw2d3QiJzsTkR0ITEAJSIiIiIiIjqnerWnUScpk90Djpy2Y/P3v2CmpbvqevC5novGZaLM6YEpTgu706Oq9PT5GHwSEV1IDRKAyrKMM2fOAABSUlIgCEJD3JaIiIiIiIioUQUqPf1+GaIowJBwvtpTIwooXpgVMtkdOH+up4Dw53o67U60NxlhtVbC62GLOxFRU6pXAHr48GGsXLkS//rXv+B0OgEAcXFxGDFiBGbMmIHMzMwGeUgiIiIiIiKihlS90tNs0MLp8amqPSNNdgeqqj1Hrv4CO2YMR05Wz5Ap7oG6IHa5ExE1vToHoN988w2mTp0Kv9+PrKwsdO/eHQBQXFyMLVu2YPv27XjxxRcxcODAhnpWIiIiIiIioloFV3UGztmsqdIz+FzP4GrPmia7B1436iRUlNmhEdTnemo04oX5sEREVKs6B6BPPPEEUlJS8Prrr6NTp06q106ePInf/OY3WLZsGd5///16PyQRERERERFRddWDzrBVnS4fZMgw6CNXegKAQSuhxOaKerI7AMyypMHu9MLvlwGw1JOIqLmq83+SOnz4MP7nf/4nJPwEgE6dOuGuu+7C4cOH6/VwRERERERERNVJkgiNQYdEswEerYREswE6ox6GhDis2FGMTksL0GlpAUat/gKQBDxbeFS5dvlfPodOI4Wc6xlc7RksZ9N+zLSkYdG4nsprZoMWi8dnYv6YDMhu7wX73EREVDd1rgDt3Lkz3G53xNc9Hg86duxY19sTERERERERKQLVnoIAxMWr29fNBi22TR+G9/aeVFV15oztiac/P6Kq3gxX6QlErvYMnuy+cFxmyFmfgcnuRETUfNW5AvT+++/Ha6+9hv3794e8tm/fPrz++uuYOXNmvR6OiIiIiIiI2rbq1Z4ao05pXw+EmBpRQHqqUVXV2S5eh3GZ7bBqx1HV/SJVegJV1Z6zLGlYPD5TVe0ZmOxutzmg8XhhszrgdbgZfhIRtRB1rgD99ttvkZqailtuuQUDBgxAt27dAABHjx7Fnj170LNnT+zZswd79uxRvW/RokX1emAiIiIiIiJqvWoaVqQRBRQvzAppX++YqA+Z1h7uGlDzuZ4HSivw1p4TmDsiDTlZPVDm8LLak4ioFahzAPr6668r/3vXrl3YtWuX6vWDBw/i4MGDqmuCIDAAJSIiIiIiohBhBxhVG1Z0ecfEsKFmuGntNU1wz9m0H9unD4MoCFhZWKx8vVmWNGQP6gJHhQs2uxsaUT3ZnYiIWqY6B6AHDhxoyOcgIiIiIiKiNkqSRFWlp9XhQUaqEXvnjVZVe0YKNcNVdTZEpafPx+CTiKg1qPMZoERERERERET1IQgCJEmEqNMgd+th1bme4YYVBYea1eVs2o8HRmeozu9ctuVQyLXABPfsQV3gc3pgs/JcTyKi1q7OFaBEREREREREdRHc7l7m9MAcp0Ve4VHVmkjVnjmb9mPb9GEAgFU7zk+Bv71fZ+hFAXMs3VVVnU6XL+QaKz2JiNqWqAPQ3r17QxCEmL9AuCnxRERERERE1HbUNNjokqQ4fDRlUNTDig6UVmDU6i/w1uSrsHBcJsocHiXUtJ8LNb0OT8j5neGuERFR2xB1AHr//feHBKAFBQU4fPgwLBYL0tLSAABFRUXYsWMHevbsiXHjxjXs0xIREREREVGLEc1gI40ooH2Mw4pu79cZPVONsNsc0MgICTVlWQ6p6gx3jYiI2oaoA9CZM2eqfv/222/j9OnT+Pjjj5Genq567ciRI7j77rvRoUOHhnlKIiIiIiIialGiHWzUEMOKiIiIalLnIUj5+fn47W9/GxJ+AkBGRgZ+85vf4MUXX6zXwxEREREREVHLERhqJAgChCgHGwFVlZ4zLWlYNK4nhxUREVGDq/MQpJKSEmg0kd+u0WhQUlJS19sTERERERFRM1b9XM/qre6AEPVgo8C5nsuvvxQl4zJhDTrXk8OKiIiovupcAdqzZ09s2LABP//8c8hrJSUlePPNN5GZmVmvhyMiIiIiIqKmFVzVCVS1tmsMOiSaDfBoJZjMBhgS47Bix1F0WlqATksLMHbNTvxSEVrpGdzuXt2B0gp8c9wKu9PDSk8iImpQda4AzcnJwe9//3tcc801GDduHLp16wYAOHr0KD777DPIsozly5c32IMSERERERFR46qtqtPp8kGnlZC79ZByrufH2YPw1bGzeLzg/Pmdh36pRLJRG9Ngo1mWNMwfk8GzPYmIqMHVOQAdOHAg3nnnHTz33HP49NNP4XQ6AQBxcXGwWCyYOXMmevXq1WAPSkRERERERI2j+rT2ZIMWPhnI3XIYeUEh5bbpw/De3pPKBPd28TqMzkjF5A27VffjYCMiImpO6hyAAkBmZiaef/55+P1+nDlzBgCQkpICUaxzZz0RERERERE1suqVntWntYer6tSIAtJTjaoJ7h0T9SitcIdUeQJVlZ7bIlR6Zg/qAkeFCza7GxpRgM3lgSzzfE8iImoc9QpAA0RRRLt27RriVkRERERERNRIqld6mg1aOD0+5G49UmtVZ7iwM9JQI6Cq0vOG9V+jYNoQ5GT1RBkHGxERUROpcwC6atWqGl8XBAF6vR4dO3bE1VdfjYsuuqiuX4qIiIiIiIjqoLZKz4xUI/bOGx1VVWe4sLOmVncAuLZXB3g9frhsLlZ6EhFRk6lXABqYAlj9/8CqX5ckCbfddhsWL17M9ngiIiIiIqJGFk2lJwAYtBJKbK6oqjojhZ2BVndBgBKsVh9qJMsyKz2JiKjJ1DkA3bZtG6ZNm4Y+ffpg8uTJ6Nq1KwDghx9+wOuvv47vv/8ezz77LOx2O1555RW8/fbb6NChA6ZPn95gD09ERERERERVAtWeggDExdde6QnEXtWZs2k/ds6yqM71LLG58PaeE5g3KgMLsjIjtroTERE1lTqXYy5duhTp6elYtmwZLr30UiQkJCAhIQGXXXYZli1bhm7duuHpp59Gnz59kJubC4vFgg8//LAhn52IiIiIiKjNkyQRGoMOiWYDPFoJGqNOqfQMhJrhKj0BddgZLGfTfsy0pOHh8T1hNmgBAGaDFrf36wy9KGCOpTtOPjIeJY9MwMlHxuM3/TvDY3fDZrVD4/HCZnXA63Az/CQiomahzgHol19+iauvvjri61dffTV27Nih/H7UqFE4ceJEXb8cERERERERoarSU5JE5VdDgh4rdhSj09IC9H1qG0RBqLHSs7qcTfsxy5KGxeMzldeDqzpPPjJBCTpnD+8Oe4XrXNjpCAk7q1rd/Tznk4iImpU6B6A6nQ579+6N+Pq3334Lrfb8/7l6vV4Yjca6fjmVzz77DLfddhsGDBgAi8WC2bNn4/jx4yHr3n33XVxzzTXo27cvbrzxRmzdujVkjc1mw4IFCzBo0CAMGDAAs2bNQmlpaci6Xbt24Y477sAVV1yBMWPG4IUXXuD/qRMRERERtVLBIaP6uvrXmtY29HNUr/RMNBsgGbSqas9IA4wiVXoCVdPa39pzAnNHpMVU1cmwk4iIWoo6B6DXX389/u///g9PPvkkjh07Br/fD7/fj2PHjiE3NxcfffQRrr/+emX9V199hR49etT7gb/66ivMmDEDPXr0wPPPP48FCxbgwIEDmDJlCpxOp7Ju48aNePjhhzFx4kSsW7cO/fv3x4wZM7Bnzx7V/ebMmYMdO3ZgyZIleOqpp1BcXIypU6fC6/Uqa3744QdkZ2ejffv2WLt2Le6++26sXLkS69evr/fnISIiIiKi5iNcyKgx6KDVStAYdDAkGFBa4YIhwQCdUQ+tMXStJFX9MSuWYLT62urPYTIbYEiMw4odR9FpaQE6LS3A5X/5HDqNpKr2jLXS02zQYvH4TGQP6gKf08OqTiIiapXqPATpwQcfxKlTp/DSSy/h5ZdfVqa7+/1V/8c4YcIEPPjggwAAl8uFyy67DFdeeWW9H3jjxo3o3LkznnjiCeVfDlJSUnD33Xfju+++w8CBAwEAK1euxHXXXYc5c+YAAIYMGYKDBw/i+eefx7p16wAAu3fvRmFhIfLz82GxWAAAaWlpmDRpEjZv3oxJkyYBAPLz85GcnIxnnnkGOp0OQ4cOxZkzZ7BmzRpMnjwZOp2u3p+LiIiIiIiaVqCdPHh4kNmgxaPX9EL24K7I3XIYeecG/wzqasY/7xuCZ7cVK9cCk88fGpMBp8cHg/78BHa70wvZ7YXP51eGFfn9ctXQourT2l0+6LQScrceUp7j4+xB+OrYWTxeywT3mgYYBVd65mT1QJnDG3ZYEae1ExFRa1PnAFSv12PFihXYt28f/vWvf+Gnn34CAFx88cWwWCy47LLLVGtnzJhR/6dFVSt9fHy86r+iJiYmAoDyXySPHz+Oo0ePKgFswKRJk7B8+XK43W7odDps374dJpMJw4cPV9akp6ejT58+2L59uxKAbt++HePHj1cFnZMmTcLatWuxe/duDB48uEE+GxERERERNZ7g4DG4mjFwXdRpkLv1MB4LChmtDg+6mA1YtuWQKnzMGdsTT39+RBUyWh0evPPtCcwdlY5nC4/WGowmG7TwyVAFq2aDFtumD8N7e08qz9EuXofRGamYvGG36vOEm+AOVFV6bps+DACwasdR1TNkD+oCR4ULNrsbGlGAzeVhZScREbV6dQ5AAy699FJceumlDfEsUbnlllvw4Ycf4o033sCNN94Iq9WKZ555BpdeeqlSYVpUVASgqpozWEZGBjweD44fP46MjAwUFRUhLS0tpCUlPT1duYfdbsfJkyeRnp4eskYQBBQVFTEAJSIiIiJqxiRJDKmytDu9ELw+yBoJxjgNypwemOO0yCs8qnpvu3gdxmW2w71v76nxWsCySX2iDkbDVXVqRAHpqUZVW3s053oGf70DpRUYtfoLvDX5Kiwcl4kyh4eVnkRE1KbVOwC90AYOHIhVq1bhgQcewKOPPgoA6NOnD1588UVIkgQAKCsrAwCYTCbVewO/D7xeXl6uVI8GS0pKwnfffQegakhSuHvpdDoYDAblXnWl0dT5GNZmLXDuUeBXoppwv1C0uFcoFtwvFC3uldZHEKqqOmVZhiAI0BkCbe3FEdvaL0mKw0dTBoWEjOHCx0iBZCzBaKSqznD3jlTpCVRVe26fPgyiIGBl0Oe7vV9n9EyNh8vuhF4GHBVeQK763rTWP4M0N/zZQrHgfqFoca/UTdQBaO/evWOeaigIAvbt2xfzQ9Vk165d+NOf/oTbb78do0ePhtVqxerVq3Hfffdhw4YNiIuLa9Cv15hEUUBycnxTP0ajMpkMTf0I1IJwv1C0uFcoFtwvFC3uldah0u2FVhRhPVfR6fT6zrW1H1TWhGtr14gC2ocJGcOFj5ECyViC0Uhrw907mnM9/zgqHQuyeqLM6UFSnBYevx8GnQSDzliP7yY1BP5soVhwv1C0uFdiE3UAev/998ccgDaGxx9/HEOGDMFDDz2kXOvfvz9Gjx6NDz/8EHfccQeSkpIAVFVvtm/fXllXXl4OAMrrJpMJJSUlIV+jrKxMWROoEA1Ugga43W44HA5lXV34/TLKy+11fn9zJkkiTCYDyssdSosNUSTcLxQt7hWKBfcLRYt7pWUSRQHQSIjTa2F1uJFs0MEny1i+9YhS6ZmRasTeeaNV7eRA+EAyUsgYuD7T0l05kzPS2liC0UhrI907cK6nIEA1oKnqXM+ucDtcsDvd0AkC7BVeyDLgrnTV/xtNdcafLRQL7heKFveKmslkiKoaNuoAdObMmfV6oIZy5MgRZGVlqa517NgRycnJOHbsGAAo53UWFRWpzu4sKiqCVqtFly5dlHU7d+5UWmMCiouLkZmZCQAwGo3o1KmTciZo8BpZlkPOBo2V19u6N6vP52/1n5EaDvcLRYt7hWLB/ULR4l5p3qpPTtcZdKpp7dFOSQciV19GGh503OrAQ2N7QsD5NvNlWw7hn/cNUbWee/0yik7bMcuShkeDKk5jrerM2bQfO2dZVPcusbnw9p4TmDcqAwuyqp/r6eQfgpsx/myhWHC/ULS4V2LT4s4A7dy5c0hb/U8//YSzZ8/i4osvBgB06dIF3bt3xyeffIJx48Yp6zZt2oShQ4cq09xHjhyJ1atXY+fOnRg2rOpfdIqLi7Fv3z78/ve/V943cuRIfPbZZ3jwwQeh1WqVe5lMJgwYMKBRPy8RERERUVsWboCR0+ND7tYjdZ6SHul6YHjQ8usvRcm4TFiDQkZXpQuzh3dHTlZPlDs9MMVp4XR5McfSHTlZPVDm8CLJoIHT5cP8MT0AoNZgNFJV5+39OkMvCiH3tju98NjdcPllTnAnIiKKQb0D0JKSEuzbtw82my3s//nefPPN9f0SKnfeeSeeeOIJPP744xg7diysViv++te/IjU1FRMnTlTWzZw5E/PmzUPXrl0xePBgbNq0CXv37sXrr7+urBkwYAAsFgsWLFiA+fPnQ6/X49lnn0WvXr0wYcIEZV12djY+/vhjPPDAA7jrrrtw8OBB5OfnY+7cuUqYSkREREREDUuSRBgS9KpKz3Bt7bFOSQ/X1h5woLQC3xy3wtLVDI3Hqw4ZPT44vF60N8fDaq2Ex1NVeeN1eFSBpE8Sz4WlNQejNVV12s9Na69+7wBOcCciIopenQNQl8uF+fPnY/PmzfD7/cqURQCqdvKGDkB/97vfQafT4c0338T777+P+Ph49O/fHytWrEBycrKy7vrrr4fD4cC6devwwgsvIC0tDatWrQqp2FyxYgWWLVuGxYsXw+v1wmKxYNGiRdBozn9runXrhvz8fOTm5uK+++5DSkoKZs2ahSlTpjToZyMiIiIiovPt7qJOc26AUc1t7XWZkh6urT1wpub8MRlwnAsgqwtkkMG1H7IsqwJJn88PONywOWsPRmur6qx+byIiIoqdINexZ2LZsmV4/fXXMXv2bAwYMACTJ09Gbm4uOnTogFdeeQWlpaV48sknlbM0KZTP58eZM5VN/RiNQqMRkZwcj7NnK3kmBdWK+4Wixb1CseB+oWhxrzSd4HM9ZVlWtbuXOT0wx+nQcelmVajZLl6H4oVZ6PLYp6rrH9xzNf7fj9aQ8zQBYOXNl2PylRcjTiepgkfB64Oskaq+XtB12e2NeKZmQ+yX6p+bWif+bKFYcL9QtLhX1FJS4qMaglT7igj++c9/4pZbbsF9992HHj2qWjkuuugiDBs2DGvXrkViYiLeeOONut6eiIiIiIhaKUkSoTHokGg2wKOVkGg2QGfUw5AQhxU7itFpaQHGrfkSJ8qdNba1B8vZtB8zLWl4eHxPmA1V5/abDVosHp+J7EFd4HN6YLM6qtrarQ54HW54PD54He6Q6409UKiqqtPP8JOIiOgCqXML/OnTp3HFFVcAAOLi4gAADodDef2aa67B888/j6VLl9bzEYmIiIiIqKULVD0KAhAXrz7X02zQYtv0YXhv70ml3V0jCmgfQ1t7zVPSz7ezh2snZ5s5ERFR61bnALRdu3Y4e/YsAMBgMCApKQnFxecPIq+oqIDL5ar/ExIRERERUYtRU1u71eGBUSepJrgDVWFneqpRNdgo0gAjoGpQ0Vt7TmDuiDROSSciIqJa1TkAveKKK7Br1y7l92PGjEF+fj7at28Pv9+Pl19+Gf3792+IZyQiIiIiomauetBpNmjhdPmg00rI3XoIeYVHoREFFC/MUgWdQOQp7jmb9mPb9GEAgFU7jqoGFWUP6gJHhQs2u5tT0omIiKhGdQ5AJ0+ejE8++QRutxs6nQ6zZ8/G7t278ac//QkA0LVrVyxcuLDBHpSIiIiIiJonSRJhSKi9rf3yjolhg85IU9wPlFZg1OovsPz6S1EyLhPWGNraiYiIiALqHIAOHDgQAwcOVH7fqVMn/OMf/8DBgwchiiLS09Oh0dT59kRERERE1IwFt7oLOg1ytx6uta09UtBZW7v7N8etsHQ1Vw0qYls7ERERxajOU+DD3kwU0bt3b2RmZjL8JCIiIiJqhcJNcDfGaZFXeFS1Llxbe6QJ7kBVu/sDozOweHxmyBT3+WMy4Hd7OTmdiIiI6qReKWVFRQU2bNiAr776CqdPn8ajjz6KK664AlarFR988AHGjh2Lbt26NdSzEhERERFRE6hpgvvQ7sl4+7dXRd3WHulcz9v7dYZeFDDH0j1ksFFwuzsRERFRrOocgJaUlOC3v/0tSkpK0K1bNxQVFaGyshIAYDab8dZbb+Gnn37CokWLGuxhiYiIiIjowolmgvuhXyqRbNRG3dYeONfzrclXYeG4TJQFnetpPxd0eh0eTnEnIiKiBlPnFvjly5ejsrIS//d//4fXXnst5F9Mxo0bh507d9b7AYmIiIiI6MIQBKEq9Dz3qyFBjxU7itFpaQH6PrUNoiCETHCvS1v77f06o2eqEXabo+pcT6sDXodbqfKUZZnt7kRERNRg6lwBumPHDtx9993o0aMHzp49G/J6ly5dcPLkyXo9HBERERERNY7gIUaiKKgqPc0GLZwen6raM9IEd+B8W7soCFhZWMy2diIiImpW6hyAOp1OpKSkRHw90A5PRERERERNJzjolGU5pK092aCFTwZytxxG3rnwMiPViL3zRkc1wR2oamu/Yf3XKJg2BDlZPdnWTkRERM1KnVvgMzIy8O9//zvi659++ikuvfTSut6eiIiIiIhiVL2Fvfq0dp1RD0NCnNLW3mlpAQoOncKyLYfwWMFBJdg0aCWU2FxRT3AHgGt7dYDX44fNamdbOxERETUrda4Avfvuu/HQQw+hV69emDhxIoCqf6n54YcfsGrVKuzZswd5eXkN9qBERERERFSlLlWdZoMW26YPw3t7Typt7e3idRidkYrJG3ar7h/rBPdZljTMH5MBR4XrXNDJkJOIiIiajzoHoDfddBNOnDiB5557DitWrAAA/P73v4csyxBFEXPnzsW4ceMa6jmJiIiIiNq86kGn2aCF0+WDTishd+sh5BVWhZIfZw/CV8fO4vGgae0aUUB6qlHV1t4xUR/2XM+6THDnmZ5ERETUXNUpAHU4HPjNb36D2267DQUFBdi8eTN++OEH+P1+dO3aFRMmTECXLl0a+lmJiIiIiNqU6oOKDAl65G49rASdsVR1hgs7azrXM2fTfmyPMNhImeAug2d6EhERUbNXpwDUYDDgxx9/hCAI6Ny5M+65554GfiwiIiIiorYl1qnsQGxVneHCzkiVnkBVtedbe05g7og0TnAnIiKiFq3OQ5BGjBiBwsLChnwWIiIiIqI2p/qwIpPZAENiHFbsOKoMKrr8L59Dp5FUQSdQe1VnsEhDjHI27cdMSxoeHt9TeY/ZoMXi8ZnIHtQFPqcHNqsj7GAjIiIiopagzmeATp8+HbNnz8aDDz6IO+64A126dIFerw9ZZzab6/N8REREREStliSJIW3t4c7vDDeVHYi9qjNn037snGVRtbWX2Fx4e88JzBuVgQVZkc/15GAjIiIiaqnqHIBed911AIDDhw/j73//e8R1+/fvr+uXICIiIiJqdYJb3QWdBrlbD9d5KnuksDMwrV0QoDov9PZ+naEXBcyxdA9pa/fY3XD5ZWhEged6EhERUatS5wD0/vvvhyAIDfksREREREStSm3negIC8gqPKutjncoOxF7VaT9X1el1eMKGnaz0JCIiotamzgHozJkzG/I5iIiIiIhaDUkSVWFnskELnwzkbjmMvHMh5dDuyXj7t1c1yFT2ulR1yrLMsJOIiIjahDoHoEREREREVKV6pWc053oe+qUSyUZtg0xlZ1UnERERUWR1ngJPRERERNTWCIJQVd157iio6hPcE80GSAYtcrcewWMFh2B1eJRzPVcFtboDjTOVvaqq08/zO4mIiIiCsAKUiIiIiKgW1VvazQYtnC4fdFoJuVsPKZWeGalG7J03GnmFxcp7I53rCZwfVsSp7ERERESNhwEoEREREVEYgbZ2QQDi4tUt7WaDFtumD8N7e08qE9wBwKCVUGJzRX2u54HSCtyw/msUTBuCnKyeqrCTU9mJiIiIGgZb4ImIiIiIglRva9cYdaqWdgDQiALSU42qSk9AHXYGRGp1D7i2Vwd4PX7YrPaQtna2tBMRERHVHwNQIiIiIqJzJEmEIUGPFTuK0WlpAfo+tQ2iIIQEnZHa2utyruf8MRmQ3V6GnURERESNhC3wRERERNSmnZtnVPWrVoPcrYeVtvbLOyaGDTpramvP2bQf2+t4ricRERERNTwGoERERETUJgUGGxnitCitcCEpwQAAyAua1h4p6Ayu9Hz800Oq+x4orcBbe05g7og05GT1QJnDy3M9iYiIiJoQW+CJiIiIqM1Rt7pvRsclmzF2zRf4pcIVMeisLmfTfjwwOgOLx2eGtLVnD+oCn9MDm9XBcz2JiIiImhgrQImIiIiozQhMdhd16lZ3ADj0SyWSjdqQas+cTfuxbfowAMCqHeenwN/erzP0ooA5lu4hlZ7Bbe0+H4NOIiIioqbEAJSIiIiIWr1Au7sxToMypwfmOK2q1R2I3NZ+oLQCo1Z/gbcmX4WF49Tnd9rPBZ1eh4dt7URERETNFANQIiIiImrVAu3uuVsPI6/wKC5JisNHUwaFDC8Czld7Bg8wClR79kw1wm5zQCMjJOisamtn8ElERETUHDEAJSIiIqJWJ9Dq7vfLEKq1u2tEAe0jTHA/UFqBG9Z/jYJpQ5CT1ZPT2omIiIhaAQ5BIiIiIqJWQ5JEaAw6JJoN8GglJJoNMFZrd69psBEAXNurA7weP2xWe8gAIyIiIiJqeVgBSkREREStQvVWd6vDg6Hdk/H2b68KqfSMNNholiUN88dkwFHhYls7ERERUSvBAJSIiIiIWrS6THYPDDZafv2lKBmXiTKnB6Y4LexOD1vdiYiIiFqZFtsC/8EHH+Dmm29G3759MXjwYPz+97+H0+lUXt+yZQtuvPFG9O3bF9dccw3ef//9kHu43W48+eSTGD58OPr37497770XRUVFIeuOHDmCe++9F/3798fw4cOxfPlyuN3uRv18RERERM2FIAhVU9QFoakfRSW43d2rk0Ja3YGa290PlFbgm+NWOF0etE/Qw1HBVnciIiKi1qhFVoD+9a9/xbp16/CHP/wB/fv3x9mzZ7Fz5074fD4AwDfffIMZM2bg1ltvxYIFC/Dll19i4cKFiI+Px7XXXqvc5/HHH8emTZvw0EMP4aKLLsKaNWtwzz33YOPGjUhMTAQAlJWV4e6770b37t2Rl5eHn3/+Gbm5uXA6nVi8eHGTfH4iIiKi+goeEhQ8zTyYJIkQdBoY4zRKi7jd6YXs9jZ5SNgQk90D7e5uR9V/2I7wbSAiIiKiFq7FBaBFRUVYtWoVVq9ejVGjRinXr7nmGuV///Wvf8UVV1yBRx99FAAwZMgQHD9+HCtXrlQC0JKSErz33nt45JFHcOuttwIA+vbtizFjxuCtt97C1KlTAQBvvfUWKisrsWrVKpjNZgCAz+fD0qVLMW3aNFx00UUX4mMTERERNYjaQs1AMCoIQFy8+jzN6mdk+v1yrSFqY2nIye7NrLCViIiIiBpYi2uB/9vf/oZLLrlEFX4Gc7vd+Oqrr1SVngAwadIkHDlyBD/++CMAoLCwEH6/X7XObDZj+PDh2L59u3Jt+/btGDp0qBJ+AsDEiRPh9/uxY8eOBvxkRERERKEasv08UDW5YkcxOi0tUP56bsdRGBP00BrPT0/XGHXI3XoEjxUcUgJFq8ODRwsOIv/r45AMWtWkdY1BB0lq3H+1DHwvRFGAMU7Dye5EREREFJUWF4B+++23yMzMxOrVqzF06FBcfvnluPPOO/Htt98CAI4dOwaPx4P09HTV+zIyMgBAOeOzqKgIqampSEpKClkXfA5oUVFRyL1MJhPat28f9rxQIiIiotqECzWrXws+37K+IaMSHAZVTQaHmu98ewIuv4xnC4+i09IC9H1qG0RBQF5hcci9endIwJ39O+OZ7aEhqiFBH/H5IgW5dfpeJBlgdXjCTnafaUnDonE9YTZoAQBmgxaLx2di/pgMyG7vucnu/gtesUpERERETafFtcD/8ssv+O6773Dw4EE88sgjMBgMWLNmDaZMmYLNmzejrKwMQFVIGSzw+8Dr5eXlyjmf1dcF1gTWVb8XACQlJanW1ZVG0+Iy6KgE/vDT2JUg1Dpwv1C0uFcoFs1hvwhCVZgnyzJkGRBFAdBIiNNrYXW4YTbo4HZ74QcQp9Oormk00rn28+pnVvaA21HVfl6b4K9X5nTDHGZIEAAsm9QHT39+BI9/WtVOfnnHRJRWuMOep7lsUh+sLCxW1gLnK0MBYK6lO0SPV/ncghD6mZ0uD0S/H35RrNP3IiPViL3zRtc62d3q8CDJoIXD5YHb4YYghP93r+awV6jl4H6haHGvUCy4Xyha3Ct10+ICUFmWYbfb8dxzz6F3794AgH79+mHs2LF4/fXXYbFYmvgJoyeKApKT45v6MRqVyWRo6kegFoT7haLFvUKxaKr9Uun2QiuKsDo9MMdp4fX7IQoClm05H+QN6mrGP+8bgme2FamCzm3Th+G9vSfx2LlQEVCHjA+OyUC8rvZ/jXN6fMrXizQkqF28DuMy2+Het/co10psLnQIc55muLXBPvm+FA+MzoBer1U+t0+WkbtFHeQ+ek0vZA/uqroey/fiyGk7Nn//C2ZauitngAYEJruP6ZGKDol6AIBeo6/1ewXwZwvFhvuFosW9QrHgfqFoca/EpsUFoCaTCWazWQk/gaqzOy+99FIcPnwY1113HQDAZrOp3ldeXg4ASsu7yWRCRUVFyP3Ly8tVbfEmkynkXkBVJWn19vlY+f0yysvt9bpHcyVJIkwmA8rLHTxbi2rF/ULR4l6hWDT0fglXvRmukjHZoINPlrF865Fag7ycsT1VlZdA1TCf9FRj2PZzAFhZWFw1yKesEsD56lJAXXEqaDV4pvCo8vUiDQnqmKgPqfYMPk8z+NnCrQ3o3SEBH08ZhKc+P/+5P84ehK+OncXjBepq0S5mA5ZtOaS6Huv3ImfTfmyfPgwCwk12r6qSPVvpCvs9rI4/WygW3C8ULe4VigX3C0WLe0XNZDJEVQ3b4gLQHj164NixY2Ffc7lc6Nq1K7RaLYqKijBixAjltcB5nYHzPNPT03Hq1KmQILP6mZ/p6ekhZ33abDb88ssvIWeD1oXX27o3q8/nb/WfkRoO9wtFi3uFYlGf/RI8EV1n0IVMRA9XyRgu9AsX5EWqpqwpZAy8bnd7YYw3nAtitXC6fJAhw6A/P9kdUJ/hGSnUjFTtmbNpP7ZNHwYAWLWj6jM7PD50TNSHnbS+bFIf5AW1xreL12F0Riomb9itWhfuc9fle3GgtAIjV3+BHTOGh5ns7qzTHwj4s4Viwf1C0eJeoVhwv1C0uFdi0+IODBgzZgysViv279+vXDt79iz++9//4rLLLoNOp8PgwYPxz3/+U/W+TZs2ISMjA5dccgkAwGKxQBRFbN68WVlTVlaGwsJCjBw5Urk2cuRIfPHFF0oFKQB88sknEEURw4cPb6yPSURERBdQbUN3Ik1ED1QyPlZwEFaHRwn9VlU7ZzNckBcp3AsOJKvr3SEB26cPw4p/FaPT0s3otLQAo1Z/AUiCMsCo09ICjF2zE79UuKIaEuT1yyg6bccsS5pqbeA8zVv7dcbJRyag5JEJ+O7B0XB7fSFrAwHmqh3nP3ekz9dQ34vA60adhIoyTnYnIiIioshaXAXouHHj0LdvX8yaNQtz586FXq/HCy+8AJ1Oh//5n/8BAPzv//4vfve732HJkiWYOHEivvrqK/z973/Hs88+q9ynY8eOuPXWW7F8+XKIooiLLroIa9euRWJiIu68805l3Z133onXXnsN999/P6ZNm4aff/4Zy5cvx5133omLLrrogn9+IiIiajiSJELQaWCMO1856XT5oNNKyN16CHmFR6ERBRQvzAppww5XtRhNkBd4LVLlZaRKTeDcAKIdxbW2jh/6pRLJRm2UQ4I0cLp8mD+mBwCo2slv79cZPVONsNsc0MiAzeWBKAqYPyZDtbZn+3ictaunskf6fA31vQCAWZY02J3ecwOhONWdiIiIiMJrcQGoKIp44YUXsGzZMixevBgejwcDBw7EG2+8gfbt2wMABg4ciLy8PKxYsQLvvfceOnfujMcffxwTJ05U3WvRokWIj4/H008/jcrKSlx55ZV46aWXVNPhk5KS8Morr+Cxxx7D/fffj/j4eNx6662YO3fuBf3cRERE1LAkSYQhQR/S1n7+rM6aJ6KHCztjCfJqCvdyNu3HzlkWiML58y0zUo2Y0Kt9VK3jNd07MCTI0tVcVTXp8kCWZfgkEbOHd0dOVg+UObxB7eQuVUWlzyfDUeEKWQsIqs8d6RkC14MHGMX6vTh/1mcGHBXRnfNJRERERG1XiwtAASAlJQV/+ctfalyTlZWFrKysGtfodDrMnz8f8+fPr3FdRkYGXn755Vgfk4iIiJoxQadB7tbDqini4c7qjKWSMdYgb9mWQ/jnfUNCwr3b+3WGXhQwx3I+ZDQbNDjr8EbVOh74etumD6sxOFQHm37A4YbN6YFGFJRgNJxwa6W4qns/Gjzk6dwzCAJUIfNxqwMPje2pGmAUy/ciUjhLRERERBROiwxAiYiIiOpDEAQY4zTIi+KszlgqGYHIoV+kIM/p8oUN9+znwj2v41zI6PbAnGSIqnUcqKr0vGH91yiYNiTMkKDIwaEsy/D5omsnD14ru70hrfElNhfe3nMC80ZlYEFWpuoZXJWhVaRRfy9qCGeJiIiIiKpjAEpERERtjigKsDo8IaFhLBPRI1Uy1hT61RTkRQr3gkNGu9OrqrKs7YzMa3t1gNfjh8vmavTg0Ofzh22Ntzu98NjdcPnl0Gfw+MJWnEbzvSAiIiIiihYDUCIiImrRBEGAKArw+2VVWHZuoLvya/BaWZZhNoQOCYoUKAaGB701+SosHFd7JWONoR/CB3nRhHvhqiwjtY4Ht7pfqOCwtjb6cM9Q1+8FEREREVG0GIASERFRixRugrvd6YXg9UHWSDDEaVFa4UJSggGCywsZMgz682t/trliGroTbiJ6bZWMQPjQr64iVVlGah1vqjMyGWASERERUXPCAJSIiIhajEAFpyAAcfGhE9wfvaYXsgd3Re6Ww8g7F14O6mrGP+8bgme3FSvXzAYtlkzIRE5WzwYbutMcqix5RiYRERERUSgGoERERNTsVa/2NOok5G49oho+ZHV40MVswLIth/B48FCisT3x9OdHVJWeVocHcz78L0RBwNwRaS1y6A5bx4mIiIiIoiM29QMQERER1USSRBgS9Fixoxidlhag71PbIAoC8gqLVevaxeswLrMdVgVNdleu7TiKcBb/83vE6SRUlDmg8XhhszrgdbiVKs+qQNHf7MJPIiIiIiKKHgNQIiIianYEQaiq+hQECDoNcrcexmMFh2B1eNAxUY/SCnfIBPdw1yOtDbA6PChzeCEIAoNOIiIiIqJWigEoERERNRuSJEJj0CHRbIBHKyHRbIAxTou8oKrOEpsLHRJ0MBu0qveGux5pbYDZoEWSQQO/n8EnEREREVFrxQCUiIiImkxwpWf1VvdOSwswds1O/FLhUlVwnqp049ODpzBjeHfVvQLXZ1q617o2YJYlDXanl5WfREREREStGIcgERERUYMKTGr3+2VVsBh8XRQF1VAjs0ELp8cXMtjo0C+VSDZqYTZoVSFozqb92DZ9GABg1Y7zU+CPWx14aGxPCDg/2X3ZlkP4531DQqa9z7KkYf6YDDgqXBfum0NERERERBecILPkocn4fH6cOVPZ1I/RKDQaEcnJ8Th7thJer7+pH4eaOe4Xihb3SvNTW6hpd3oheH2QNZJyPdmghU8GcrccRt65QDIj1Yi980bj4kcLQs7r/OCeq/H/frSqprgDQO8OCXhr8lXo1T4BZQ6PMsH9/NfTotzpgSlOC6fLCxkyDHqNatq77PYqA4+o7eLPFooF9wtFi3uFYsH9QtHiXlFLSYmHJNXe4M4KUCIiIoqZJImqsDNcqGk2aPHoNb2QPbir6vrH2YPw1bGzeDyo0tOglVBic4UdVhSo9qxewXl7v87omWqE3eaARgZsLs/5ilOPDw6vF+3N8bBaK+HxVP3LodfhgUYU1GuJiIiIiKhVYwBKREREMQmc1Zm79TDyCo9GDDWtDg+6mA1YtuWQcr1dvA6jM1IxecNu1T2DhxVVD0EPlFbghvVfo2DaEORk9VRVezoqXBErOAP5ZnDOKcsyfD4Gn0REREREbQmHIBEREVGtgocVCToNcrcexmMFh2B1eJRQc1XQpHagKuwcl9lOdb1joh6lFe6QkLO2YUXX9uoAr8cPm9UOjccLm9UBr8PN9nUiIiIiIqoVK0CJiIgaQKTBP/Vd29Sqt7qbDVoAAvKiCDXDXa+p0jNn035sD9PqHjysiBWcREREREQUKwagRERE9RAuIAwerhPNkKBwayNNT78QgWng6wkCEBevbnUf2j0Zb//2qqhCzXDXgys9qw81OlBagbf2nMDcEWnIyeqhGlZUU6s7ERERERFRTRiAEhERxaimgDBQsfjQmAw4PT4Y9DUPCQq3NtL09ODANBCoNmRYWj3MNeok5G49gseCzvU89Eslko3aqELNwPWZlu6qewSGGgkCQr5v2YO6wFHhgs3u5rAiIiIiIiJqEAxAiYiIohRNQGh1ePDOtycwd1Q6ni08WuPk80hrI01PD1y/e+Al0GkkWB3uqMLSSJWT1atTgwcbaUQBxQuzkFdYrHpPpLAzUqh53OrAQ2N7QsD5tvYSmwtv7zmBeaMysCArM+JQI7a6ExERERFRQ2AASkREFIXqk88jBYQAsGxSHzz9+RElIIw0+TzcWiD89HSg6kzNO/p3xl+2HcGqoJAxUlgaODvTWemCLEOpCg3Xtu/0+FRh7uUdE8Oe6wmcDzuDz+qsKdR0Vbowe3j3kLZ2j90Nl19mpScRERERETUqBqBEREQRBFdIBk8+ByIHhIHJ5/e+vUe5FmlIULi1NV1fNqkP8gqLowpLA9Wlv76iEzLbJyjVok6XDzqthNyth5RKzYxUI/bOG60Kc2saVnSgtAI3rP8aBdOGICerpyrsjBhqenywOT1hw05WehIRERERUWNiAEpERFRNNJPPIwWEsUw+j2V6eqxhae8OCdg2fRjyCouxasf5atFt04fhvb0nVW37Bq2EEptL9fVqGlYEANf26gCvxw+XzRV1qMkJ7kRERERE1BTEpn4AIiKi5kAQBEiSCI2mqtV9xY5idFpagE5LCzB2zU78UhE5IAwWHHbWZW2k67GEpYC6WjTwmkYUkJ5qDGnbj/QcOZv2Y6YlDYvG9VReMxu0WDw+E/PHZEB2e8+Fmn62rxMRERERUbPFAJSIiNqUQNApCAKAqmpPjUGHRLMBHq0EjVGnnIUZCA6DJ58HCxcQev0yik7bMcuSFnbtw+NrXxs8PT0glrA0UBW6asdR1dpIYWmkgPZAaQVGrf4Ct/brjJOPTEDJIxNw8pHxmD28u2pYERERERERUXPGFngiImoTwg7+qXYeZqyTzwMB4VuTr8LCcecH/zhdPswf0wMAah0SFG5tuOnppyrd+PzIacy0dFe1rweHpYHrkYLOms71zNm0H9urDTYyG7S4vV9n9Ew1wm5zQCODw4qIiIiIiKjFYQBKREStXvUJ7pHOw4x18nlNAaFPEqOefB5pbfXp6WaDBmN7tFNC0UhhaaSgs6ZzPQ+UVuCtPScwd0RayHOw2pOIiIiIiFoyBqBERNQq1TTBHQh/HmZdJ5+HCwh9Pj/gcEc1+bzGtUHT08tdHoiiEFVY6pdlzLKk4dGCg6rnytm0HztnWUKC3FmWNGQP6gJHhQs2uzvsMxMREREREbVEDECJiKhViWaCOxC+Tby+k8/DiWXyeaS1wdd9PjmqsNTrBeaPyQCAkIpVvShgjiU0RA0OcjmtnYiIiIiIWgsGoERE1GKcm1uk/Hr+elW1pyAAcfHqVveh3ZPx9m+vivo8zECrOwCs2nFUVSE5f0wGHBWumELNxhJNWOqocIWtFrWfCzq9jvDVqURERERERK0JA1AiImpSwa3qwSFc8HVRFCDoNDDEaVFa4UJSggGy0wPB64OskZRqT6NOUia4BwRPcI+m2jPSYKOWeBZmbW34zSHIJSIiIiIiamwMQImIqEmEa1W3O70hoWayQQufDORuOYy8oFbuR6/phezBXZXrsU5wByKfh9naJp8z6CQiIiIioraMASgRETW4SFWdAZGmslcPNa0ODz7OHoSvjp3F40FVnVaHB13MBizbcki5XtcJ7tGch0lEREREREQtFwNQIqI2IJo288D1+qyNVNUpu73w+fzKejHMVPZwoWa7eB1GZ6Ri8obdqs/TLl6HcZntcO/be5RrdZ3gzvMwiYiIiIiIWjcGoERErUi0gWT1NnOzQQunywcZMgz6uq11unzQaSXkbj2kquqcZUnDQ2My4PT4YNBrUOb0wBynDZnKHi7UDDepPdL1+k5wZ5s4ERERERFR68QAlIiohQo3JKh6SBkukAzXZj6oqxn/vG8Int1WXOM5mzWt3TZ9GN7bezKkqvOdb09g7qh0PFt4FHmFxbgkKQ4fTRkUVagZqaqzpU9wJyIiIiIioguHASgRUTNXW1VnpCFBkQLJ6m3mAJAztiee/vyIqnIylrUaUUB6qjFkABEALJvUR7VeIwpoH2WoGamqM3B9pqW76vO1pgnuRERERERE1DDEpn4AIiI6TxCEqoDz3K8agw6JZgM8WgmJZgN0Rj0MCXFYsaMYnZYWoNPSAhQcOoVlWw7hsYKDSnAYKZAMtJmvCmo/V67tOFrntZFa1cOtDw41gwWHmsFyNu3HTEsaHh7fE2aDFgBgNmhx3OrAQ2N7YvH4TNV11QR3jxc2qwNeh5vhJxERERERURvFClAioibQUFWdkYYExXJ2ZkOsjdSSHml9pFb1QKgp4Py09hKbC2/vOYF5ozKwMCsTZU4PTHFa2J0euCpdmD2cE9yJiIiIiIgoshYfgFZWVmLixIn4+eef8d5776Fv377Ka++++y5efPFFnDhxAmlpaZg7dy7GjBmjer/NZsOyZcvw6aefwuPxYMSIEVi0aBE6dOigWrdr1y48+eST2L9/P1JTU3HXXXdh6tSpEAThgnxOImodwg0lCndW58fZg/DVsbOq1vNwVZ2xBpLhrjfE2kit6pHWB1rVl19/KUrGZcIa1KoeKdT02N3wiUB7czys1kp4PecCTo8PNicnuBMREREREVF4Lb4FfvXq1fD5fCHXN27ciIcffhgTJ07EunXr0L9/f8yYMQN79uxRrZszZw527NiBJUuW4KmnnkJxcTGmTp0Kr9errPnhhx+QnZ2N9u3bY+3atbj77ruxcuVKrF+/vrE/HhG1Ako7u0aEIUGval/vtLQAx8qdyN16GI8VHILV4VGqOldVm5Je25CgYLG0mTfEWqCqqvOB0RmqlnSvX0bRaTtmWdJC1h8orcA3x62wOz2qVnWPxwevww2bNbSFPZBtVs84qwYb+Rl+EhERERERUYgWXQF65MgRbNiwAfPnz8cjjzyiem3lypW47rrrMGfOHADAkCFDcPDgQTz//PNYt24dAGD37t0oLCxEfn4+LBYLACAtLQ2TJk3C5s2bMWnSJABAfn4+kpOT8cwzz0Cn02Ho0KE4c+YM1qxZg8mTJ0On0124D01EzVZtbe1GnYTcrUdUQ3vqW9UZqfISqAokd86yQBTOt5NHajNftuUQ/nnfkHqtvb1fZ+hFAXMs6upNp8uH+WN6AIBqffBk9nDt6pzWTkRERERERA2hRQegjz/+OO68806kpakri44fP46jR4/iwQcfVF2fNGkSli9fDrfbDZ1Oh+3bt8NkMmH48OHKmvT0dPTp0wfbt29XAtDt27dj/PjxqqBz0qRJWLt2LXbv3o3Bgwc34qckoqZUPdQMdy2atnaNKKB4YVbIUKLaqjqjaTMPnKcpCFBa6GsKJCO1mTtdvnqvtZ8LM70OdUu6TxJ5VicRERERERE1iRYbgH7yySc4ePAg8vLy8N///lf1WlFREQCEBKMZGRnweDw4fvw4MjIyUFRUhLS0tJBzPNPT05V72O12nDx5Eunp6SFrBEFAUVERA1CiViDaUFOGDIO+5vM7ww0rurxjYqNVdQYPCVqQlYmyoPM0IwWSACKenVnvtQit3vT5/IDDzbM6iYiIiIiI6IJrkQGow+FAbm4u5s6di4SEhJDXy8rKAAAmk0l1PfD7wOvl5eVITEwMeX9SUhK+++47AFVDksLdS6fTwWAwKPeqK42mxR/DGpYkiapfiWrSWPtFEKqCTVmWVWdGBl8XBAHQSIjTa2F1uGE26OB2e6HRSMjden4C+6CuZvzzviF4dltxjVPZgfBt7Q1b1Sli7og05GT1PBd2auFweeB3eeBwuqEXBDgqvIBc9VmDf85IkgAgdHhbuOsNsTaSWNeffx9/tlD0uF8oWtwrFAvuF4oW9wrFgvuFosW9UjctMgD961//itTUVPz6179u6kepF1EUkJwc39SP0ahMJkNTPwK1IA25XyrdXmhFEVanB+Y4LTx+P+J1mpDrPllG7pbDEULNg8r9csb2xNOfH1GFlOGCTiB8W3t9qjoXZmWizOlB0rnPEaeTEKeTAAAdEvUAAL1G32Dfu5aAP1soFtwvFC3uFYoF9wtFi3uFYsH9QtHiXolNiwtAf/rpJ6xfvx7PP/+8Up1pt9uVXysrK5GUlASgqnqzffv2ynvLy8sBQHndZDKhpKQk5GuUlZUpawIVooGvFeB2u+FwOJR1deH3yygvt9f5/c2ZJIkwmQwoL3fwfD+qVV33iyhGrt5cvvWIKtR89JpeyB7cVXX94+xB+OrYWTxeS/Vmu3gdxmW2w71v71F9/ViGFQHnqzoBYNWO6Ks67U43dIIAe4UXsgy4K12xfHtbFf5soVhwv1C0uFcoFtwvFC3uFYoF9wtFi3tFzWQyRFUN2+IC0B9//BEejwf33XdfyGu/+93v0K9fPzz99NMAqs4CDT67s6ioCFqtFl26dAFQdY7nzp07z7fBnlNcXIzMzEwAgNFoRKdOnZQzQYPXyLIccjZorLze1r1ZfT5/q/+M1HCi2S+BszoFAdAZdOfa1MOdvXm+etPq8KCL2YBlWw4pYWe7eB1GZ6Ri8obdqvuHCzVjDTojVXseKK3AqNVf4K3JV2HhuOpndTrh8/nhsbt5RmYU+LOFYsH9QtHiXqFYcL9QtLhXKBbcLxQt7pXYtLgDA/r06YNXX31V9VdOTg4AYOnSpXjkkUfQpUsXdO/eHZ988onqvZs2bcLQoUOVae4jR45EWVkZdu7cqawpLi7Gvn37MHLkSOXayJEj8dlnn8Hj8ajuZTKZMGDAgMb8uER0jiSJ0Bh0SDQb4NFK0Bh1yN16BI8VHFLCx0gt6YEKzlWFR5Vr0YSaNV0D1EFndTmb9uOB0RlYPD5TeV+g2rNnqhF2mwMajxc2qwNeh1v5L3dVw4P8DD+JiIiIiIiIGkiLqwA1mUwRp65fdtlluOyyywAAM2fOxLx589C1a1cMHjwYmzZtwt69e/H6668r6wcMGACLxYIFCxZg/vz50Ov1ePbZZ9GrVy9MmDBBWZednY2PP/4YDzzwAO666y4cPHgQ+fn5mDt3rhKmElHDCp7KLooCDAl6pdpTIwooXpgV1dmbka7HUr0Z6/md59vaBcyxdEdOVg+UObxKtafj3GR2IiIiIiIiImp8LS4Ajdb1118Ph8OBdevW4YUXXkBaWhpWrVoVUrG5YsUKLFu2DIsXL4bX64XFYsGiRYug0Zz/1nTr1g35+fnIzc3Ffffdh5SUFMyaNQtTpky50B+LqNWTJBGCTgNjnEYJE50en1LtCQCXd0yMqSU93PVYQ81lWw7hn/cNiSnotJ8LOr0OD9vaiYiIiIiIiJqIIPNP403G5/PjzJnKpn6MRqHRiEhOjsfZs5U8k4JqpdWKMJvjUV5uhzZOfa5nRqoRe+eNxsWPFijhZbt4HYoXZqHLY5+GhKAf3HM1/t+P1pBQ84N7rsaun6xKiAoAvTskYNv0YVi1o1h1jugsSxoeGpMBp8cHg16jhJpOlw8yZNU1u9ML2e2Fz+dXVa3yR2vj4M8WigX3C0WLe4Viwf1C0eJeoVhwv1C0uFfUUlLiW+cQJCJquaoHhIFqT0OcFqUVLhj0OlWlJwAYtBJKbK6ohgwBkVvSj1sdeGhsTwg4f73E5sLbe05g3qgMLMiqPpQocvVmpIrOqvM7GXwSERERERERNScMQImo0YVta3f5oNNKyN16qMZzPSO1teds2o9t04cBAFbtOBpVS7qr0oXZw0Ove+xuuPxy1KEmg04iIiIiIiKiloMBKBE1ikC1pyAAcfF6VVu72aDFtunD8N7ek7We6xmp2vNAaQVGrf4Cb02+CgvHRV+9CY8PNmf4Ck6GmkREREREREStDwNQIqqXSG3tgWpPo04KaWvXiALSU42qas9IlZ5AVbXn9unDwg4g6plqhN3mgEZG1C3prOAkIiIiIiIiajsYgBJRVGoLOmNpa++YqA+p9qzpXM8DpRV4a88JzB2RFtK+7jhX7UlEREREREREFA4DUCIKERx2iqJQa9AZa1t7rOd6zrKkIXtQFzgqXLDZ3WHb14mIiIiIiIiIwmEASkSK6lWdyQYtfDKQu+Uw8oJaz6sHnUBsbe11OdczuNKT7etEREREREREFC0GoERtRPUW9urXRFGAIUE9rOjj7EH46thZPF5L0AnE3taes2k/ds6yxHyuJxERERERERFRLBiAErVykc7qlCHDoA+65vGphhW1i9dhdEYqJm/YrbpfuKATiL2t/fZ+naEXBcyxdEdOVs//396dx0VV9X8A/wybgoi4ZYoWSIKACyiLJCKapKU9opZr4ApuoeaSSS65i5aaS0q4hEs9lZr+BNI0VNxzJ82NxV0UM/YZmBnu7w+fuXGZAWdwBMPP+/XypZ57uOfe4cudw3fOgmyFEjbVzZGvUHJdTyIiIiIiIiIyGiZAiaqYp43q9H7NFnvD2mHZoTRxWrtjXSskTQ6QjOo0NNFZnmnt+ZpEp1KF+rY1kJmZB5WSiU8iIiIiIiIiMh6Tyr4AIio/mUz2ZITn//42s7RATVtLKM1NUdPWEqaW5uKoTk2yclrnZvjyYArm7rsmllmamyI9p0CS0Cye6CyueKKzpGnxlzEpwBEzA53Er9Oa1q5UISdTDpW8UBzlqZnhzpnuRERERERERGRsHAFK9ALRtU6nrnJ9NivSNaqzXg0LdHGqh6E/nJe0q2tUZ3nX7/xnWvsbyJKrdG5iRERERERERERUUZgAJaokJaeql1ynM1+hgkylhmBmqrV+p4W5KRYduF7mZkW6RnWWNq29tGSnZv1OmQxiW09LdGqmtavkSpiZyLiJERERERERERFVKiZAiZ6z8ozetLU0x5yuzhju85pW+aExb2Jb0v2nblaka1Rnaet3Ak+SnYlj3pSM6kzPKcAP5+9hckdHRLyle/3O0hKdgiBArWbik4iIiIiIiIgqFxOgREb0tFGd+o7ezJQr0cTWEgsTrkvKzUxkaFrXSq/NinSN6ixrWvuVh7n47/l7+LiDg9aoTmV+IQqKBCY6iYiIiIiIiOhfhwlQIiPQd1SnvqM3S1urU1ey09BRnQsTrmNvWDut9TvH+TlguHcTyHMLkJNfqDPZyUQnEREREREREf3bMAFKVA4lR3paWlfDogPJZY7qNGT0Zmnlhm5WVNqoTkWB+qkbFTHZSURERERERERVgUllXwCRoWQy2ZMRlzJZhbdlamoCM0sL1LS1hNLcFDVtLWFqaY5FB1Iwd991ZMqV4qjOVUduSM71tNGbxZVWXjzZWdy0+MsI93PAjMBm4tfYWppjZqAThns3gVqhRE6mHGZKFXIy5SjML4Ayv1BSppIXcpd2IiIiIiIiIqpyOAKU/jVKTjPX7JQuFKrEkZiajYY0Sm5AVFpZyXJ91+90rGuFpMkBeo3qNGT0pqY83M9enC6vMS3+Mo6P89N7s6KyRnVy/U4iIiIiIiIiquqYAKUK9SwJyZLTzDU7pQ/2bAwLM1NkygvFpKhMpYZgZqqVwBQgwLKaNIFasq6+63cCgKW5KdJzCvRak7O0ZOe0+Ms4NOZNyGSQ3NvtTDk+7dwMMkjX6uzbuhGqmch0TmEva7MiIiIiIiIiIqKXEROgVCF0jd7UNyFpa2kOhVItTjPXeLVmNfRzb4Qlh1KwqkRSdLjPa5IEpvdrttgb1g7LDqVJkpq66uq7fidg+Jqcho7eLMgrwPj22onO/P+N6lTJldysiIiIiIiIiIioDEyA0nOhWZ5TJnuS/Cw5etOQhKSuaeYAsPBdF6w8kiZJMmbKlWhia4mFCdclCcxpnZvhy4MpT61b2q7spU1rN3RUZ7lGbyrVyFHoTnRyCjsRERERERERUdmYACWj0oz0tKxujoe5BahlbQmFUqU1elPfhCSge5p5vRoW6OJUD0N/OC9pX1e5IXUNWb9TvJf4y0gc86beozrLM3qTiU4iIiIiIiIiovJhApSMRtdIT12jNw1JSAK6k4+lJSp1lRtS19D1OwHgysNc/Pf8PXzcwcGgNTmZ1CQiIiIiIiIiev5MKvsCqOqQWZhh0YFkzN13XUwe6hq9aUhCEpAmHzWKJyqL01VuSF1dbWlMi7+MSQGOmBnoJH6NraU5ZgY6Ybh3E6gVSuRkymGmVCEnUw6VvBBqddH/Ep1F3JCIiIiIiIiIiKgSMAFKRiGTyWBV3Qwrj9yQlD9rQlJjWvxljPNzEJOPj/IKcTDlL4T72UvqaRKYxctLS2rqqqtpK9zPATMCm0kSncXX77w/KxDps97G/VmBGN/eHvL/TWtnspOIiIiIiIiI6MXCKfBkFCYmMmTKlXptElTadPLiCcni64UCuqeZ21qaofMb9SDDP2tv2lqa43amHJ92biYpX5hwHXvD2knW6Syt7rOs30lERERERERERC8WmcDsTaVRq4vw+HFeZV+GUchkMtS0tUTD2fu0kqDNX7FG4pg3seroDTHJ+M8u8KmShKRmF/jIhGRJ+Tg/B0zt5Ah5bgGKigSYmMjEv2UWZrCqbiZZe1OmUkMwM5WUKwrUECDAstrT6+YrVBAKVZK2+KPy/JiZmaB27Rr4++88qFRFlX059AJjrJAhGC+kL8YKGYLxQvpirJAhGC+kL8aKVJ06NWBq+vQJ7kyAVqKqlAAFADNLC3x19Abm7LumdWxFUAsEt7FDdQvTZ0pIqtW6f7hlMpnORKWuckPqUsXgA5z0xVghQzBeSF+MFTIE44X0xVghQzBeSF+MFSl9E6CcAk9GIxSqMLWTIwBojd4c7t0E8twC5OQXak0d1zmdXKlGjkL/aeal7aiuq9yQukRERERERERE9O/GBCgZjVpdBHluAca3t8e0t5ohW6GETXVz5CuU4iZBT+oxIUlERERERERERBWDCVAyKrW6CJAXQq5Sob5tDWRm5kGl5JBsIiIiIiIiIiKqHE+fJE9UDpoZ61xKk4iIiIiIiIiIKhMToERERERERERERFRlMQFKREREREREREREVRYToERERERERERERFRlMQFKREREREREREREVRYToERERERERERERFRlMQFKREREREREREREVZZMEAShsi/iZSUIAoqKqu7Lb2pqArW6qLIvg/4lGC+kL8YKGYLxQvpirJAhGC+kL8YKGYLxQvpirPzDxEQGmUz21HpMgBIREREREREREVGVxSnwREREREREREREVGUxAUpERERERERERERVFhOgREREREREREREVGUxAUpERERERERERERVFhOgREREREREREREVGUxAUpERERERERERERVFhOgREREREREREREVGUxAUpERERERERERERVFhOgRERERERE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", + "text/plain": [ + "<Figure size 1600x400 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "y = df['realgdp']\n", + "y_train, y_test = temporal_train_test_split(y, test_size=30)\n", + "\n", + "forecaster = AutoARIMA(sp=4)\n", + "forecaster.fit(y_train)\n", + "y_pred = forecaster.predict(fh=fh_abs)\n", + "\n", + "print(f\"MASE: {round(mean_absolute_scaled_error(y_true=y_test, y_pred=y_pred, y_train=y_train), 3)}\")\n", + "plot_series(y_train, y_test, y_pred, labels=[\"y_train\", \"y_test\", \"y_pred\"]);" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "196a3a90", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 365 + }, + "id": "196a3a90", + "outputId": "31da0272-9c99-48ed-cfa7-49b4a10e32d9" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MASE: 5.496\n" + ] + }, + { + "data": { + "image/png": "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iIiIiIiIagcToGQRVlYyFMiVOrMsHzZ5qaVvmfnStCt6l55rd0/Xtt8trcD+rD9MPm5ecTm+OXsL07t74vb8l8xKdHKpOhERERERERHR44VL4MkiNBoBro62OkvSgftJxoMTXpAsHV+adgU/xnTRWU6uTV7KYNoyc1N3T3d1tEHP55uYfNwyhQrKsgqUawRuPkRERERERERE9DcmEzhVrdao1Rrcu1da25dhMTaOdvg4PRcLf76s89qqSD9EdXKDg521JHkpQICjvY0k8ShTqSHYWMPJQdouVKigVmsgk8lgZSWDRiOISUl9bVXbraxkkNnZmHVcqhk2NlZo2LAe/vyzFCoVywaQYYwVMgfjhUzFWCFzMF7IVIwVMgfjhUzFWJFq1KgerK0fvMCdM0DJYoQKFWb28AQAySzLSaEeGB3UEvKSchSXVejMqFTJlbqzLJVqFCv0tEP/7EtDMzIrt6vVAiCvMOu4RERERERERET098YEKFmMWq2BvES79Lw1ihRKuDjYokyhlOyGXp3kpSUx0UlERERERERE9ORgApQsSq3WAPIKyFUqNHWth4KCUqiUnJJNRERERERERES1g7vA0yOhXVnOUppERERERERERFSbmAAlIiIiIiIiIiKiOosJUCIiIiIiIiIiIqqzmAAlIiIiIiIiIiKiOosJUCIiIiIiIiIiIqqzmAAlIiIiIiIiIiKiOosJUCIiIiIiIiIiIqqzZIIgCLV9EU8qQRCg0dTdt9/a2gpqtaa2L4P+JhgvZCrGCpmD8UKmYqyQORgvZCrGCpmD8UKmYqz8xcpKBplM9sB+TIASERERERERERFRncUl8ERERERERERERFRnMQFKREREREREREREdRYToERERERERERERFRnMQFKREREREREREREdRYToERERERERERERFRnMQFKREREREREREREdRYToERERERERERERFRnMQFKREREREREREREdRYToERERERERERERFRnMQFKREREREREREREdRYToERERERERERERFRnMQFKREREREREREREdRYToE+Qq1evYt68eejXrx98fX3Rt29fnT4VFRVYvnw5QkND0b59e/zzn//E0aNHdfp5e3vr/K9r1646/fbt24f+/fvDz88P3bt3x6pVq6BWq3X6KRQKfPLJJ3jllVfQrl07BAcHY/z48cjIyNDp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", + "text/plain": [ + "<Figure size 1600x400 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "y = df['realgdp']\n", + "y_train, y_test = temporal_train_test_split(y, test_size=30)\n", + "\n", + "forecaster = DirectTabularRegressionForecaster(LinearRegression())\n", + "forecaster.fit(y_train, fh=fh_abs) #forecasting horizon necessary in the fit() method for this forecaster\n", + "y_pred = forecaster.predict()\n", + "\n", + "print(f\"MASE: {round(mean_absolute_scaled_error(y_true=y_test, y_pred=y_pred, y_train=y_train), 3)}\")\n", + "plot_series(y_train, y_test, y_pred, labels=[\"y_train\", \"y_test\", \"y_pred\"]);" + ] + }, + { + "cell_type": "markdown", + "id": "c6a0a392", + "metadata": { + "id": "c6a0a392" + }, + "source": [ + "### Multivariate exogenous time series\n", + "Forecasting with exogenous variables (i.e. multivariate X)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "e1f3f9a1", + "metadata": { + "id": "e1f3f9a1" + }, + "outputs": [], + "source": [ + "#creating lagged values to avoid data leakage\n", + "df.loc[:, 'realinv_lagged'] = df.loc[:, 'realinv'].shift()\n", + "df[['realinv_lagged']] = df[['realinv_lagged']].fillna(method='backfill')" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "f6fd09dd", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 365 + }, + "id": "f6fd09dd", + "outputId": "0b48e343-f29d-45ea-bb6f-c3f2960569a4" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MASE: 6.708\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABUAAAAFkCAYAAADhdJEIAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAACphklEQVR4nOzdeXhTZdo/8O852dM2TVtAQFlKpYCCgCJrWAsiuAyv4/o6jAqivsg64kCBQVFGKuOCgAyKoDOjCK4/degoVRCmyODLCDK+giwtgkJlTZs220lyfn+EHHKapE260IXv57q8kJMnpyf1mY5+ue/nFmRZlkFERERERERERETUDIkN/QBERERERERERERE9YUBKBERERERERERETVbDECJiIiIiIiIiIio2WIASkRERERERERERM0WA1AiIiIiIiIiIiJqthiAEhERERERERERUbPFAJSIiIiIiIiIiIiaLQagRERERERERERE1GwxACUiIiIiIiIiIqJmS9vQD3Apk2UZgYDc0I9Rb0RRaNafj+oW9wvFi3uFEsH9QvHiXqFEcL9QvLhXKBHcLxQv7pULRFGAIAjVrmMA2oACARlnz1Y09GPUC61WRFpaEsrKnPD5Ag39ONTIcb9QvLhXKBHcLxQv7hVKBPcLxYt7hRLB/ULx4l5RS09PgkZTfQDKFngiIiIiIiIiIiJqthiAEhERERERERERUbPFAJSIiIiIiIiIiIiaLQagRERERERERERE1GxxCFITEAj44ff7G/oxEhIICHC7NfB6PfD7m+9kMo1GA1HUNPRjEBERERERERFRDAxAGzFZllFWdhYuVwWAphcinj4tIhBo7hPJBJhMSbBY0iEI1U8dIyIiIiIiIiKii4sBaCPmclXA5SpHcrIVBoMRQNMK2DQaoVlXfwIyPB43ysvt0OkMMJuTG/qBiIiIiIiIiIioEgagjZQsyygvt8NoTEJycmpDP06NaLUifL7mXQGq0xng80koL7fDZEpiFSgRERERERHRJUQQBIiigEBAhixXXwSW6HqqGwxAG6lAIIBAwA+j0dzQj0LVMBrNcLsrEAgEoNHwPFAiIiIiIiKi5k6jEWE2+KE3GhBw2yEarfC63XB6NPD7AxFBZ3XrqX4xAG2kAoHg0CMO2Gn8Qv+MAgE/A1AiIiIiIiKiZioUagoCYEkWUbbrOfyy52UE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umJW/svY2AhGRkZPbMcCKBEREREREREREdVanAJPREREREREREREtRYLoERERERERERERFRrsQBKREREREREREREtRYLoERERERERERERFRrsQBKREREREREREREtRYLoERERERERERERFRrsQBKREREREREREREtRYLoERERERERERERFRrsQBKREREREREREREtRYLoERERERERERERFRrsQBKREREREREREREtRYLoERERERERERERFRrsQD6Arl58ybmzJmD/v37w8HBAf369dNoU1xcjOXLl8PLywsdOnTA+++/j+PHj2u0k8lkGv917dpVo93vv/8Of39/ODk5oXv37li9ejVKSko02ikUCnz99dd499130b59e3h4eGDChAlITk7WaJuUlISwsDD06tULMpkM8+fPr+IrQhUxZFYAIDU1FRMnToSbmxucnZ3h5+eHpKQk8fGTJ09qzdQnn3yisS9ds1JSUoKoqCgMHz4cHh4ecHd3R0BAAE6fPv2Urw6VZ6i87Nq1S2sOZDIZxowZo9fx1HJzcxEREYFevXrByckJb775JsLCwpCenq7RNiIiAn379oWLiws6deqEgQMHIi4u7ileGSqvurMSEBBQYbvyP1t9slLWwYMHIZPJKs0hVY0h34syMjIQGhoKLy8vuLi4YODAgdi/f3+Fxy4oKIC3tzdkMhn+/PNPjcf1yUt8fDxCQkLE/UVHR+v5StCTGDIrWVlZmDJlCjp37gwXFxeMHz8et2/f1touJCQELi4ucHd3x8yZM5Gfn6/Rjv2W509N5AUADh06hCFDhsDZ2Rlubm4ICAhAZmampE1JSQm2bdsGf39/dOzYEa6urhg5ciSOHj2qsb+ff/4ZgwYNgru7O9q3b4/evXtj3bp1KC4uruIrQ+X98ssvmDBhAry9veHs7Iz+/ftjx44dEARB0u6nn35C79690b59e/zrX//C77//rrGvR48eITw8HO7u7nBxccGkSZNw//59SZt///vfGD16NLp27YpOnTph0KBBOHjwoNZzy8rKwpw5c9C9e3fxb+05c+YgKyur0uf07bffQiaTYdy4cXq+GlSZ6s4KAOzcuRN9+vSBk5MTfH19sXXrVq3nxj7Lf5nW9AlQ9bl+/ToOHz6Mjh07orS0VOOXEQAWL16MPXv2YMqUKbC1tcWuXbsQFBSEH374AY6O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", + "text/plain": [ + "<Figure size 1600x400 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "y = df['realgdp']\n", + "X = df[['realinv_lagged']] #could be more features\n", + "y_train, y_test, X_train, X_test = temporal_train_test_split(y, X, fh=fh_abs)\n", + "\n", + "forecaster = AutoARIMA(sp=4)\n", + "forecaster.fit(y_train, X_train)\n", + "y_pred = forecaster.predict(X=X_test, fh=fh_abs)\n", + "\n", + "print(f\"MASE: {round(mean_absolute_scaled_error(y_true=y_test, y_pred=y_pred, y_train=y_train), 3)}\")\n", + "plot_series(y_train, y_test, y_pred, labels=[\"y_train\", \"y_test\", \"y_pred\"]);" + ] + }, + { + "cell_type": "markdown", + "id": "006a6c6c", + "metadata": { + "id": "006a6c6c" + }, + "source": [ + "### Updating a forecaster" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "e43675b4", + "metadata": { + "id": "e43675b4" + }, + "outputs": [], + "source": [ + "y_old_data = y_train[:-4]\n", + "forecaster = AutoARIMA(sp=4)\n", + "forecaster.fit(y_old_data)\n", + "y_old_pred = forecaster.predict(fh_rel)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "2443261e", + "metadata": { + "id": "2443261e" + }, + "outputs": [], + "source": [ + "#updating the model with new data (full year) and generating predictions for the next period\n", + "y_new_data = y_train[-4:]\n", + "forecaster.update(y_new_data)\n", + "y_new_pred = forecaster.predict(fh_rel)" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "93f0812b", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 346 + }, + "id": "93f0812b", + "outputId": "903e5276-4226-4259-caca-5673836b059c" + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABUAAAAFkCAYAAADhdJEIAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAACuSUlEQVR4nOzdeXhTZdoG8PucbE3apmkLCChLWyiLIovIGtYCSl0/BxdGGR0qMoOsioMFRFBHKuOCgAhiccd9HBcYhyoIU2RwHLZxACm0LAq1sqRNmz053x8lh5wmaZPS0oX7d11eyMmb05Ner1Vun+d9BEmSJBARERERERERERE1Q2JDPwARERERERERERFRfWEASkRERERERERERM0WA1AiIiIiIiIiIiJqthiAEhERERERERERUbPFAJSIiIiIiIiIiIiaLQagRERERERERERE1GwxACUiIiIiIiIiIqJmiwEoERERERERERERNVsMQImIiIiIiIiIiKjZUjf0A1zKJEmCzyc19GPUG1EUmvXno7rF/UKR4l6haHC/UKS4Vyga3C8UKe4Vigb3C0WKe+U8URQgCEKN6xpVAHr06FHk5uZiz549KCgoQGpqKr744ouw67/66is8+OCD6Ny5c9A6q9WKxYsX46uvvoLb7caQIUMwf/58tGrVSrFu586deOaZZ7B//34kJydj/PjxmDRpkuKbJ0kS1qxZg3Xr1uHMmTPo1q0bsrOz0atXrwv6vD6fhDNnKi7oHo2VWi0iMTEWZWU2eDy+hn4cauS4XyhS3CsUDe4XihT3CkWD+4Uixb1C0eB+oUhxryglJcVCpao5AG1ULfAFBQXYsmULOnTogLS0tGrXOhwOPP3002jRokXI12fOnIlt27Zh4cKFePbZZ1FUVIRJkybB4/HIa44ePYqsrCy0bNkSq1evxr333otly5Zh7dq1inutWbMGy5Ytw3333YfVq1ejZcuWmDhxIo4fP37hH5qIiIiIiIiIiIjqTaOqAB05ciRGjRoFAHj00Ufxww8/hF27evVqtG3bFldccUXQul27diE/Px+5ubkwm80AgJSUFGRmZmLjxo3IzMwEAOTm5iIxMRHPP/88tFotBg4ciDNnzmDVqlWYMGECtFotnE4nVq9ejYkTJ+K+++4DAFxzzTW4/vrrkZubi4ULF9b9N4KIiIiIiIiIiIjqRKOq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tcLFmHhZsWIFVq5cqXV8vheZjiljZcKECTh27BhycnLQuHFj9O3bFwMHDtTaBOnevXuYN28eDh06BAsLCwQHByM6OlprxhbHLc+eqoiXwsJCLF26FDt37kR+fj48PT0xadIkrQ/mVCoVvv/+e2zZsgXp6eniEvmYmBitFXELFy7EwYMHcefOHVhYWKBx48YICQlB//79udmNiXTt2hW3b9/W+djvv/+Oxo0bAwB+/vlnxMXF4c6dO3B2dkZUVJQ481cjLy8PCxcuxJ49e6BSqRAQEIDp06dLZgq6ubnpvZayv+dmZmZi1apVOHDgALKyslBSUgInJyfExcXh5ZdfLvd5hYWFwdbWFrGxseX2I8NVdqwcPnwYixcvxvXr12FhYQFfX19MmDBB60N6gGOW0pgApWfSiRMnMGTIEIwcORKjR4+u6suhZxhjhYyRkJCAiRMnYtGiRSytQeVirJAxGC9kKI5byBhpaWno06cPevTogfnz51f15dAzLDY2FitWrEBcXJzWBCKi0p7nMQtrgNIzycfHB1OnTsXy5cuxbdu2qr4ceoYxVsgYvXr1wpAhQzB9+nRJbR2ishgrZAzGCxmK4xYyhouLC5YsWYItW7bgyy+/rOrLoWfY8OHD8dprryEyMlJSQoOorOd5zMIZoERERERERERERFRtcQYoERERERERERERVVtMgBIREREREREREVG1xQQoERERERERERERVVtMgBIREREREREREVG1xQQoERERERERERERVVtMgBIREREREREREVG1xQQoERERERERERERVVtMgBIREREREREREVG1xQQoERERERERERERVVtMgBIREREREREREVG19f+DmFWdW/SYogAAAABJRU5ErkJggg==", + "text/plain": [ + "<Figure size 1600x400 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_series(y_train, y_old_pred, y_new_pred,\n", + " labels=[\"y_train\", \"y_old_pred\", 'y_new_pred']);" + ] + }, + { + "cell_type": "markdown", + "id": "3a0d9d7d", + "metadata": { + "id": "3a0d9d7d" + }, + "source": [ + "## 2. Reducing a forecasting task to a regression problem" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "d0c35fb5", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 365 + }, + "id": "d0c35fb5", + "outputId": "ccf76d17-c15e-4af6-f5a9-cba35cdbb4ca" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MASE: 4.104\n" + ] + }, + { + "data": { + "image/png": "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OxFd8hpVBqjT6cSWLVsAAL/88gvKy8vlYGd2djZSU1MxdepUzJw5E+3bt0e/fv2Qn5+PPXv24P3335ev06dPH1gsFsyZMwezZ8+GTqfDq6++ii5duuD666+X102YMAFffvklHn/8cdxzzz04cOAAVq9ejRkzZsjBVJ1Oh0mTJmHJkiVITU1FVlYWPvzwQ1itVkyYMOEifjpERERERETUnKhUIgStGka9Wi5TBwQsKTyiWBct2zM42GjduGswd0QWbE5vSKanWw52+v2c6k5El7ZGFQA9ffo0HnvsMcWx4O/fffdd9OvXDzfddBOcTidWrVqFlStXIj09HUuXLpUzNoNee+01LFy4EPPnz4fP54PFYsG8efOgVp9/5A4dOmD16tXIy8vDww8/jNTUVEybNg3jx49XXGvixImQJAlr1qzBmTNn0K1bN6xevVouuSciIiIiIiKKhSAIEEUBggDoE3Q1lroH5ebvw5YIfT3v7NUWndOMcNidUEuA3e2FJDHgSUQUSpD4zdhg/P4AzpypaOjbqBdqtYiUlAScPVvBnhRUI+4XihX3CsWD+4Vixb1C8eB+oVhV3StVsz2NWhVe+q5InuoOAC0StCiem4N2z34TMQia3d6Mgkn9oVWpFNmeksfH0vYmjt8tFCvuFaXU1ISYhiA1qR6gRERERERERE1BcB6vIFSWuhsSdXhtWzHaLChAj5e2QBQExVR3QFnqHskNXVrB5w3AbnWwrycRURwaVQk8ERERERERUVMWzPQ06DUoLXcjOdEAl9eHvM2H8WxBZf/Oq1onobTcE1ep+zRLOmYPy4Sz3A1JktjXk4goDnUSAJUkCWfOnAEApKamQgj+qIuIiIiIiIiomauur2dmmhF7Zg5VZHuW2N1olaiF2aAJC4LuLy3HzWv+iYJJ/ZGb0znqYCMiIordBQVADx06hMWLF+Nvf/sbXC4XAECv1+O6667DlClTkJWVVSc3SURERERERNTYROrrGZrpCQAGjQoldrci0BltqntQsNTdbXdDLQocbEREdIFqHQDdsWMHJk6ciEAggJycHHTs2BEAUFxcjE2bNmHr1q1488030bdv37q6VyIiIiIiIqJGIdjXM5jtqRYFFM/NCevrGS3bM1jqDgBLtx1hqTsRUT2qdQD0+eefR2pqKt5//320adNG8drJkydx7733YuHChfj0008v+CaJiIiIiIiIGhNBq0be5kM19vWMlu25v7QcQ5b9HevGXYO5I7JY6k5EVI9qPQX+0KFD+O///u+w4CcAtGnTBvfccw8OHTp0QTdHRERERERE1FgIggCVSoQoCjDq1VhSeER+LTTTs6rc/H2YZknH/JFZ8utmgwZ39mqLzmlGOOxOTnUnIqpHtc4Abdu2LTweT9TXvV4vWrduXdvLExERERERETUKVXt9phg0OOv0xdzXc39pOdbtPoEZ16UjN6cTbE4fsz2JiC6iWmeAPvroo3jvvfewb9++sNf27t2L999/H1OnTr2gmyMiIiIiIiJqCMFsT7W6stfna9uK0WZBAdosKMCVL34Hk14dlu2Zm78PUy3pmDeisyLTc/7ILEzIbge/ywu7ldmeREQXW60zQH/44QekpaXh9ttvR58+fdChQwcAwJEjR7B792507twZu3fvxu7duxXnzZs374JumIiIiIiIiKiuCIIAURQQCEiQJCmmye6HTzuw8affMNXSUXE8tK/nvBFZsLm8MOk1cLi8ikxPDjYiIrq4ah0Aff/99+X/vXPnTuzcuVPx+oEDB3DgwAHFMUEQGAAlIiIiIiKiBlc10Gk2aOBy+6HVqJC3+WC1k92BymzPrZMHQoCAxYXF8jWCfT1dDhdamoywWivg8zLLk4ioIdU6ALp///66vA8iIiIiIiKiehOa6SmKAgyJOuRtPoQlhUfk4OWWyQPxyZ6TNU52ByqzPQcv+zu2TRmE3JzOYVPcBaFyncRkTyKiBlfrACgRERERERFRQ6pavh7puCgK4ZmeXn9YWbtaFJCRZlRke4ZOdo8UBC2xu2HUqlBuc0AtCLC7vfJ9qNW1HrlBRER1jN/IRERERERE1KSoVCLUBi2SzAZ4NSokmQ1QG7TQaFSK4yazAYYkPV7bdkQeYHTVi99Bq1aFlbW3TtKFZXuGTnaPZJolHQ6XD4GABL8/oAjCEhFR4xFzBmjXrl0hBHP44xBpSjwRERERERFRbahUYsTy9WdGdcGEfu2Rt+kQlpzryfnlhGx8f+wsngvJ9DRoVCixu8MyOqNle+bm78OWyQMBAEu3nX+/aZZ0zB6WCWe5++I8OBER1VrMAdBHH300LABaUFCAQ4cOwWKxID09HQBQVFSEbdu2oXPnzhgxYkTd3i0RERERERFdkoJl7aJWjbzNhxTl61anF+3MBizcdFAOdrZI0GJoZhrGrd2luE60QGdotudz30Se7D53RFZYr8/gZHciImq8Yg6ATp06VfH79evX4/Tp0/jyyy+RkZGheO3w4cO4//770apVq7q5SyIiIiIiIrokVO3rGTqt3ebywqzXYEnhEcU5LRK0GJHVAg+u3y0fi1TSDkQPdAKV2Z7bp1kgCpEnuzvsTqglKHp9EhFR41frIUirV6/GfffdFxb8BIDMzEzce++9ePPNN3HnnXde0A0SERERERFR8xca6JSHFbn90GpUyNt8EEsKj+CKZD2+GJ8dFtSMFOysboBRbv4+bJ08MGKgUycKmG7piNycTrA5fcz2JCJqBmodAC0pKYFaHf10tVqNkpKS2l6eiIiIiIiILhHR+npumTwQn+w5KZe7q0UBLSMENSMFO6vL9NxfWo51u09gxnXpYYFOx7lAp8/phVoUmO1JRNQM1HoKfOfOnbF27Vr8+uuvYa+VlJTgww8/RFZW1gXdHBERERERETVfgiBApRIVfT2DAUy1KCAjzaiY1h5tKnvw+FSL8nhu/j5MtaTjyZGdYTZoAABmgwbzR2ZhQnY7+F1e2K1OqL0+2K1O+JweOctTkjjZnYiouah1Bmhubi4eeughjBo1CiNGjECHDh0AAEeOHMG3334LSZKwaNGiOrtRIiIiIiIiah5i6esZrYdntKnsx61OPDG8MwScL2svsbuxfvcJzBySiTk50QcY+f0MchIRNWe1DoD27dsXH330EV5//XV88803cLlcAAC9Xg+LxYKpU6eiS5cudXajRERERERE1DSFDjYSRUFR7h6tr2e0Hp7BqeyLbuqOkhFZsIYENd0Vbjw2KLx/p9fhgTsgsaSdiOgSVesAKABkZWXhjTfeQCAQwJkzZwAAqampEMVaV9YTERERERFRMxFxsJHXj7zNh2vs61lTD88dx62wtDdXlq+HBjW9fthdkft3MtOTiOjSdEEB0CBRFNGiRYu6uBQRERERERE1A5EGG2WmGbFn5tCofT2rBjpz8/dh+zRL2LT2aZZ0zB6WGXUye2X/TgY7iYioUq0DoEuXLq32dUEQoNPp0Lp1a1x77bW47LLLavtWRERERERE1ASElroLIYONggwaFUrs7pj7et7Zqy10ooDplvCy9mjBTyIioqouKAAqCAIAhPVPqXpcpVLhjjvuwPz581keT0RERERE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VG0xAUpERERERERERETVFhOgREREREREREREVG0xAUpERERERERERETVFhOgREREREREREREVG0xAUpERERERERERETVFhOgREREREREREREVG0xAUpERERERERERETVFhOgREREREREREREVG0xAUpERERERERERETV1v8BPxJuWqghDJAAAAAASUVORK5CYII=", + "text/plain": [ + "<Figure size 1600x400 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "regressor = LinearRegression()\n", + "forecaster = make_reduction(estimator=regressor, strategy='recursive', window_length=4)\n", + "forecaster.fit(y_train)\n", + "y_pred = forecaster.predict(fh_abs)\n", + "\n", + "print(f\"MASE: {round(mean_absolute_scaled_error(y_true=y_test, y_pred=y_pred, y_train=y_train), 3)}\")\n", + "plot_series(y_train, y_test, y_pred, labels=[\"y_train\", \"y_test\", \"y_pred\"]);" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "a50fc8aa", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 365 + }, + "id": "a50fc8aa", + "outputId": "7200c19f-85d0-4252-90bf-2792546a3f36" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MASE: 4.984\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABUAAAAFkCAYAAADhdJEIAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAACv00lEQVR4nOzdeXhTZdo/8O852dM2TVtAQFnaQlkUAUXWsJZFcJ0ZN37KqFTEF1lHHCwgiDpSlxGkyOACOi4ILuOrDh2lCsIUGR0HkPGlyNKyKNSypU2bPTm/P0oOOU3SJqWlC9/PdXkhJ09OT+pjZ/xy388tSJIkgYiIiIiIiIiIiKgFEhv7AYiIiIiIiIiIiIgaCgNQIiIiIiIiIiIiarEYgBIREREREREREVGLxQCUiIiIiIiIiIiIWiwGoERERERERERERNRiMQAlIiIiIiIiIiKiFosBKBEREREREREREbVYDECJiIiIiIiIiIioxWIASkRERERERERERC2WurEf4FImSRL8fqmxH6PBiKLQoj8f1S/uF4oW9wrFgvuFosW9QrHgfqFoca9QLLhfKFrcK+eJogBBEGpdxwC0Efn9Es6cqWzsx2gQarWIpKQ4lJfb4fX6G/txqInjfqFoca9QLLhfKFrcKxQL7heKFvcKxYL7haLFvaKUnBwHlar2AJQt8ERERERERERERNRiMQAlIiIiIiIiIiKiFosBKBEREREREREREbVYDECJiIiIiIiIiIioxeIQpGbA7/fB5/M19mPExO8X4HSq4Ha74PO13MlkKpUKoqhq7McgIiIiIiIiIqIIGIA2YZIkobz8DByOSgDNL0Q8dUqE39/SJ5IJMBjiYDIlQxBqnzpGREREREREREQXFwPQJszhqITDUYH4eDN0Oj2A5hWwqVRCi67+BCS4XE5UVFih0ehgNMY39gMREREREREREVE1DECbKEmSUFFhhV4fh/j4xMZ+nDpRq0V4vS27AlSj0cHr9aCiwgqDIY5VoERERERERETUZAiCAFEU4PdLkKSWXKRWMw5BaqL8fj/8fh/0emNjPwrVQq83wu/3XQLt/kRERERERETUHKhUItRxKiQk6eHR+5GQpIc6TgWV6tKMAlkB2kT5/VVDjzhgp+kL/DPy+31QqfjPi4iIiIiIiIguruBKT1EUYEjQ4tn/bkZuYQGsbgfMWgNm9LBgXq9RcNjc8PkurSIuBqBNHFuqmz7+MyIiIiIiIiKixqBSiRD0Aow6LawuB8w6A5xeD57972Y89UO+vM7qdsi/n9V9KFDZWE/cOC7NulciIiIiIiIiIqJmTKUSYUjQ4qV9/0T79UvQfsMS9Pr4eWhVauQWFoR9T25hAYw67SVXzMUAlJq8NWtewX//+0O93nPnzu9hsfTDvn176/W+REREREREREQNJZBbCgIg6AW50tPqdgAADGoNShw2+ffVWd0OlLmdEEUGoNRCCYJQVRrdzFL+N954Df/97556vWe3bt2xevUb6NQptV7vS0RERERERERU3wJDjYwJOpQ6KmBM0CFOpw2p9Cyx29BGHw+z1hD2PmatAYlaPfz+S2siPAPQS4BKJUJt0CLBbIBHo0KC2QC1QdviJn+5XM6o18bFxeOqq3rBYAj/A4GIiIiIiIiIqCkIbnVvt34J2q1/AqM+X42TzoqQSs9Trkp8dWI/Hu4xJOy9ZvSwwO5yQ5IYgFILolKJMMTrsHx7MdotyZf/emn7YRjidQ0eghYUbIPF0g/Hjh1VXC8vL8eoUUPwt799UOP7LZZ+AIBVq16CxdIPFks/7Nz5vfza22+/iVWrVuDmm8fhxhvHAgB+/HEP5s2bg1tuuR6jR1tw333/D59/vlFx33At8BZLP7z77l+xZs0ruOmmsbjhhkw888wSOBzhy8aJiIiIiIiIiBpKoJNX1Ishre4Hyk7CrDWGrfTM/j4PM3ta8HjvMfLrZq0Bj/ceg3m9RkFyXlrhJ8Ap8M2OJEmwe/xRr08waZCz5SCeyj8gX7M6PHgyfz8AYPqgTqh0eKK6l1ETe/v8oEFD0Lp1G2zc+Ckeemi6fD0//3MAwJgx19f4/tWr38BDD92P2267E6NHV61NTT3ftv7hh++hZ89eeOyxx+HzeQEAJSUn0KtXb9x66++g1erw3//+gJycpyBJEsaPv7HGr/fRR++jd+++WLDgCRw7dhSrVr2EpKRk/M//zIjpcxMRERERERER1UXwZPcylxNmnSak1T240vNPP3ypeG1fWSnWF+3GnCuHIbt3JsrcTiRq9bC73HDY3PD5os+VWgoGoM2IJEm46d1d+Pcv5VGtbxWnRfGCTOQWHA77+oqCYjw6Mh09//wtTlW6a71f/8tN+PTuvjGFoCqVChMm3ISNGz/FlCn/A5VKBQDYuPFTDB8+EgkJCTW+/6qregEA2rRpK/99sISERDzzzPOKZxo9epz895IkoXfvvigt/RWffPK3WgPQlJRWWLz4aQDAwIGDsX//Pnz99VcMQImIiIiIiIiowQXa3Z/972bkFhbgirhEfJI5OexQo+zv8/D1hGkQISC3sABWtwNmrQEzeliQ1XUAHDY3bH4n1KIAW6Xzkmt7D8YAtJmJpf6ybYIOpRVuWCNUeFodHpyscKNtgi6qALSubrzxFrz11lp8++0ODB5swcGDB7B//z48/PCsC773wIGDQwLZ8vJyrF37Cv75z604deokfD4fACAxMbHW+1133QDF7zt3TsVXX2264OckIiIiIiIiIgpHEASIogC/X1JMdgcAtSCi9bmhRtVD0H1lpbg5fy02XT+1xkpPn+/SDT4DmlQAeuTIEaxZswY//PADDhw4gLS0NPz973+PuP7LL7/Eww8/jK5du4ass9lsWLp0Kb788kt4PB4MHToUCxcuRJs2bRTrdu7ciWeffRaFhYVISUnBxIkTMWXKFEWoJkkSXnvtNaxbtw5nzpxBjx49kJ2djT59+tTr56+NIAj49O6+UbfAi6KAy0w6mA2asCGo2aBBO5MOf7+7b1TTv+rSAg8A7dq1x3XXDcDf//4JBg+2YOPGT9Gu3eW45pp+Md+ruuTk5JBrzzzzBH78cQ/uu+8BpKamIy4uDh9//CE2b86v9X7x8cqKVI1GA7e74cJhIiIiIiIiIro0Bbe6W10OmHUGCICi3b2mVncAGHd5N3g9PrjsHlZ61qBJDUE6cOAAtm7dik6dOiE9Pb3GtU6nE8888wxatWoV9vXZs2dj+/bteOKJJ/DCCy+guLgYU6ZMgdfrldccOXIEWVlZaN26NV555RXce++9WLFiBdauXau412uvvYYVK1bgvvvuwyuvvILWrVtj8uTJOHbs2IV/6BgJgoA4rSqqvwxqEXanFzMtqWHvNdOSCrvTC4NajOp+dQk/A2666VZ8880/cfJkKfLz/4Ebbrjpgu53nvIeLpcL33xTgN//Pgu33XYXrr32OnTv3pP/8hMRERERERFRkxE82b39+iVov2EJMj9fjdIwk92zv8/DjJ4WLOg9OuJQI0mS4PP5mX9E0KQqQEeNGoXRo0cDAB577DH8+OOPEde+8soraN++Pa644oqQdbt27UJBQQHWrFkDi8UCoGpwzoQJE7Bp0yZMmDABALBmzRokJSXhxRdfhFarxaBBg3DmzBmsXr0akyZNglarhcvlwiuvvILJkyfjvvvuAwBce+21uP7667FmzRo88cQT9f+NqEeS24t5I6vC5BUFxbA6PDAbNJhpScW8kelwVLguynMMHToCCQkmLFmyEOXl5bWexRlMrVbD7Y7uOT0eD/x+PzQajXzNbq9EQcG2mJ+ZiIiIiIiIiKg+Bdrdgye7BxwoO4mkc5Pdg0PQfWWlGJG3Cs9ddyMW9h6NMo8TiRo9Ki/hoUaxalIVoKIY3eMcPXoUb7zxBhYuXBj29W3btsFkMmHIkCHytbS0NPTo0QPbtm1TrMvMzIRWq5WvTZgwAeXl5di1axeAqhb5iooKjB8/Xl6j1WoxZswYxb2aKp/PD0eFC7OGdMaJxWNQsngsTiweg1lDOsNR4bpo/5Ko1WqMH38Ddu/eiX79BuCyy9pG/d5OnVJRULANu3b9B/v27YXdXhlxbXx8PHr06Il33nkTW7Z8iW3bvsbs2Q8jLi6+Pj4GEREREREREVHMVCoR6jgVEpL08OolGGuZ7F7dvrJS/PvkMTjdHrTWx8Nuc8Fb6WP4GaUmFYBG609/+hNuueUWdO/ePezrRUVFSE1NDWmxTktLQ1FREQDAbrfjxIkTSEtLC1kjCIK8LvBr9XXp6ek4fvw4nE5nvXymhuTz+eF1uGGzOqD2eGGzOuB1XPw/IRg2bCQA4IYbbo7pfX/4wzz4/X7MnTsTDzzwe+zbV1jj+sWL/4QrruiAP/3pCSxf/jxGjMjE9ddPqPNzExERERERERHVVfV29zGbVuO4vTziZPcZPS14vPeY8O3u7qoWd3a6x6ZJtcBHY/Pmzdi1axc+//zziGvKy8uRkJAQcj0xMVFul7fZbAAAk8mkWKPVamEwGFBWVibfS6vVQqfTKdaZTCZIkoSysjLo9fo6fx61OnwG7ffXx/mYSlXnQVycf0MC2bMgnP+X8l//+gaJiYkYOnR4TPfq3bsP1q59J+R6QcH3YddfcUUHvPTSX0KuZ2VNlf/+mmv6hbw/3P3uuOP/4Y47/l9Uz6lSCRH/eVLNVCpR8StRJNwrFAvuF4oW9wrFgvuFosW9QrHgfml5BKGq3V2SJAg6MebJ7vnXT8X83pmwup0wa/Wwuz1w2z1ysR/3SmyaVQDqcrnwzDPPYMaMGWGnfzc3oiggKSku7GtOpwqnTonNPlRTqUQcOXIYR44cwUcfbcDvfncHjMa6B8ZNkd8vQBRFJCYaLygMJ8BkMjT2I1Azwb1CseB+oWhxr1AsuF8oWtwrFAvul5ah0uOGRhTl8BKIfbK7AAFalRptDFVH+mkNaiBoe3CvxKZZBaB//etfIYoibrjhBpSXlwM4P/SmvLwcer0eWq0WJpMJJSUlIe8vKytDYmIiAMgVooFK0AC32w2HwyGvM5lMcLvdcLlciirQ8vJyCIIgr6sLv19Cebk97Gtutwt+vx8+nwSvt/md5yAIVeGnz+fH0qVPY+/eHzFgwCDcffd9is/j9XpruIcAlUp1MR73gvh8Evx+P8rK7HA4fI39OM2SSiXCZDKgvNzB80uoRtwrFAvuF4oW9wrFgvuFosW9QrHgfmkZRFGANk6D5/+7BbmFBbC6HRjUpjPWj7gn7GT3rydMAwC8XLgdVrcDZq0BM3pYMO/qUXBXenDW7wn5GtwrSiaTIapq2GYVgBYVFeHIkSMYNGhQyGvXXXcdnnjiCUycOBFpaWnYsWNHVZlx0DmgxcXFyMjIAAAYjUa0a9dOPuMzeI0kSfKZn4Ffi4uLFWeOFhUVoX379hdc8Rcp3LxYreoNJdD2LknAypWvhl1z4sRx3H575PNA+/S5JuJ7m6LmGlY3JT6fn99Digr3CsWC+4Wixb1CseB+oWhxr1AsuF+an8BUd79fAnQCnt1Tt8nuVrcTiVo97C43HOW1z23hXolNswpAp0yZgt/85jeKa6+++iqKi4uxdOlSdO7cGQAwbNgwrFq1Cjt27MDgwYMBVAWYe/fuxQMPPCC/d9iwYfjqq6/w6KOPQqPRAADy8vJgMpnQt29fAMA111yD+Ph4/OMf/5ADUI/Hg02bNmHYsGEN/ZFbtFatWuP119+K+LrRaLyIT0NEREREREREFB2VSoSgF2DUaWF1OWDWGSAANU52r97uHpjsPiSlM9ROAbZKJyRON2oQTSoAdTgc2Lp1KwDgl19+QUVFhTzsqH///khPT0d6erriPR9//DF+/fVXDBgwQL7Wt29fWCwWzJ8/H/PmzYNOp8OyZcvQrVs3jB07Vl6XlZWFzz77DI888ggmTpyI/fv3Y82aNZgzZw60Wi0AQKfTYerUqcjNzUVycjIyMjLw3nvvwWq1Iisrq6G/JS2aRqNB9+49G/sxiIiIiIiIiIiiFpjq/ux/Nyta3TeEaXUHzre7ixDk9XK7e69RcNhqr/ikC9OkAtDTp09j1qxZimuB37/11luKkLM2y5cvx9KlS7Fo0SJ4vV5YLBYsXLgQavX5j9ypUyesWbMGOTk5ePDBB5GcnIyZM2di8uTJintNmTIFkiRh7dq1OHPmDHr06IE1a9agQ4cOF/BpiYiIiIiIiIiouQi0u4t65VR3oKrV3Rym1R04P9l90/VTkd07E2XB7e4MPy8KQWJtbaPx+fw4c6Yy7GsejxunT59ASko7aDTai/xk9UOtFi+J8yhawj+rxqZWi0hKisPZs5WXxJ6huuNeoVhwv1C0uFcoFtwvFC3uFYoF90vTFtzuXuZywqzTo936JSFB58eZ9+H7Uz+Hnez+eO8xmNV9KHx2v3xmaF0iOe4VpeTkuJY3BImIiIiIiIiIiOhiqd7ufkVcIj7JnFznVndJkpr94OvmiAEoERERERERERHROcGT3QW9oGh3VwsiWuvj69zqHnxvNmVfPLXXiBIREREREREREbVwKpUIdZwKCUl6ePR+JCTpEafTKia7B091D2fc5d3g9fhgO+uE2iHAdtYJb6UPAJBglJCcpIVJV4nkJC0SjFJU7dt04VgBSkREREREREREl7RYJrsHWt0B4OXC7cpW96tHwVHuDrl3YoKI8u9fwK+7X4bfZYWoM8PUZzoS+z2KMhs4CKmBMQClJm/NmlfQv/9A9OrVu97vvXPn9/jxxz34/e8n1/u9iYiIiIiIiKhpq8tk931lpRiRtwrPXXcjFvYeDav9DBL1JjjKiqGV/BD1fmh0OvidVoh6M/weJ8q/fwHWb/8k38PvssL67dMAAOPVc2B3iWyLb0Css72ECIJQNblMEBr7UWLyxhuv4b//3dMg99616z94++03GuTeRERERERERNQ0Bbe7e/USjDqNotUdqLndfV9ZKf5dehi2o1/D/b/Xo2RtGio23gnB74T9hxdx7NUrcOy1K/DLW70hqjUo3/1yyD00Sd2ha3sddHod2+IbGCtALwEqlQijzget/vyfPridTthdKpZYExEREREREdElpV4mu3cfjD/2HIAz74+A5+w+AECr0a+g7D/LYP3uGfn9gtoAX2UJ/C6r4r6apO5od/tXKN/9Mk5+fi/b4hsYI+UWLnDOhGPPMvlPH469egUce5YjMUFs8D9VKCjYBoulH44dO6q4Xl5ejlGjhuBvf/ugxvdbLP0AAKtWvQSLpR8sln7YufN7AIAkSVi37m3cdddvMXLkINx++y3YsOFdxftLS3/F448/hptuGotRowbj9ttvxooVfwZQ1Vr/xhuvweFwyPeePv3B+vroRERERERERNREBHfFBk92t7odKLHb5Mnu1QUmuz9y1TAcv2MBTtw+DyfuWozpiX5F+CkaWsHQcRTKf1ileL/PXgKVsQ1EnVlxPcnyJ5TvfhnW756Rw9FAW3z598/DqPM1yPfhUsUK0GZGkiTAZ496vdGgQ/n3KyKfM9FrBsptruhupjLG3D4/aNAQtG7dBhs3foqHHpouX8/P/xwAMGbM9TW+f/XqN/DQQ/fjttvuxOjRVWtTU1MBAC+99AI+++x/8fvfT0bPnlfhxx/34C9/yYVOp8Ott94GAHj66cU4deokZs+ei6SkZPz6awl++qkQAHDTTbfi5MlS5Od/jpdeWg0AiIuLi+nzEREREREREVHTpVKJEPQCjDotrC4HzDoDBCDiZPc//fBlyD3Gte8K17EtOPPlA9Akd4f61s9QmX+/oqpTZWwLn700pNLT7zgFx9HNMPWeJleGBsLSU5uywj5z+e6VSOz/GESnG4Ig8GzQesAAtBmRJAmOTRPgP/VdVOtFQyu0mnwAv4Y5ZwI49y9Uv0fgePdK+B2nar9f6wEwjNkYUwiqUqkwYcJN2LjxU0yZ8j9QqVQAgI0bP8Xw4SORkJBQ4/uvuqoXAKBNm7by3wPAL7/8jI8+eh9z52bjllt+CwC47roBcDqdeOON13Dzzb+FKIooLPw/TJ36MDIzx8rvHT/+xnP3vAytW7eBKIqKexMRERERERFR81dfk93/2OM6nHl/BPyOU3D9UhASaALKSs/qIejZggVod8dmQBBRvnvlubD0ZMg6+bmNbSF57EgyG0OOMqS6YQt8cxNL+BjhTx8C/C4rfI6TUBnb1tPDhXfjjbfg9OlT+PbbHQCAgwcPYP/+fbjxxlvqfM9///tbAMCIEaPg9Xrlv/r164/Tp0+jtPRXAEBGRne89947+PjjD/Hzz8cu/MMQERERERERUZMWaHcPnuweCDyDJ7sHC0x2H9C6I07ctRgnbvsjjt+xAHOvGoaz/3uT3OoOVAWapj4Pw9x//vnWdr8XHmsRTH2mozrP2X2o+Ol9JPSdhQ4P/oy2v90EdXz7kLZ44NzZoHdsRvmul8IeZSiKzWuwdVPBCtBmRBAEGMZsjLoFXhAFqOLMYf/0AQBEnRkqYzvoxv4DWn8UpdR1aIEHgHbt2uO66wbg73//BIMHW7Bx46do1+5yXHNNv5jvFVBWZoUkSbjhhtFhX//111/Rtm07LFmyFK+++jJefXUV/vznHHTs2AlTpz6M4cNH1flrExEREREREVHTE9zuXuZywlzLZPfq7e6Bye4DvcfhLvgjSuwlaDX6FRg7jYH713/L6zxn9+HEB5loPeFdmAfMh89ZBlGfCI/LjcR+jwKo6roNHmwUf+X9KLP54fe7IYoGxAlOmPpMl48oDEiy/Anlu1YqqksVRxn2nl2f37JLBgPQZkYQBEAd/TmVbpcr7L9QAGDqMx1ulwsQjRAauBb4pptuxZIlC8+dufkP3HbbXXUKUwNMpkQIgoBVq16HRqMJeb1jx04AgFatWmH+/MXw+/346adC/PWva7BoUTbWrfsIl19+RZ2/PhERERERERE1LlEUoFaL8Hr9VUVjDTDZvXr7eiDUjMu4DWpzF1jLPZAkI/wONyRJgkrlh/Hq2Ujs/xj854JRt9OJMptfnuru80modKpCwlJ1YjoMnUbXejZoLARBgCjyHFEGoC2c3RX6L1TgTx9M/R5Fmc0PwN/gzzF06AgkJJiwZMlClJeXy+dwRkOtVsPtVg5quvba6wAAZWVlsFiG1XoPURTRo8eVmDJlGgoKtuGXX37G5ZdfAY1GA7fbHduHISIiIiIiIqKLpnqIp9GooNIDOo22KryMN8Dp9cjt7gCgFkR5snv1EDQw2X3TuCnI7jUcZc4ymI3JsJ85oAg/AWX7ek2hZoDP54fNLkBwuCGKgWBUQPXsxefzo8yGamGpGX7X2RqPMvS7yiEaW9V6QqJKJcKo80Gr14WcI1r9mS8FDEBbuPD/QkX+F7WhqNVqjB9/A9atexv9+w/CZZdFf+5op06pKCjYht69+8JgMKBjx07o2LETfvvb2/H004swceIk9Ox5FbxeL44dO4pdu77H0qV/RkVFBf7wh+kYN24COnbsBK/Xgw8/fB/x8QnIyOgu39vn8+H9999Dr15XIy4uDh07dm6g7wIRERERERERRUsR4rlsEHUJ8Lo98Gs0yNnzFXLPDStKT0jBD7fOjXGyexd5srvK2BanNAm47OYPIXX9Lcp/WFVD+3rkUDOYJEnw+WquuKwelkpOF5LM4Y8y1CR1R/KwZ6HSmeCzl8KUoAw0g0NiURSQmCCi/PsX8OvulxWfJbHfoyiz4ZILQRmAXgKi/dOHhjZs2EisW/c2brjh5pje94c/zMNLL72AuXNnwuVyYcWK1bjmmn6YPftRdOzYCZ988je8+ebrMBiM6NixE0aOzAQAaLVapKd3wUcfbcCvv5ZAp9Oje/ceWLZsJcxmMwBgyJCh+M1vbsc777yJs2fPoHfvvli58tX6/uhEREREREREFAOVSkRiggoVZccgaDvD6vXCrPHDJQIv7vkKTwWFmga1BiUOW4yT3fvjzPvD4Xecgt9xCgBw4oNMJA/NQccB8+FzlUHUhW9fr2/BYanbGXo2qCapO9rd/hXKd7+Mk5/fWy3Q/CO8Hj80Oq1c6en3OFH+/Quwfvsn+R6Kc0Svng2b/dIapiRIl/IBAI3M5/PjzJnKsK95PG6cPn0CKSntoNFoL/KT1Y/AORwBr7++Gh9//AE+/vgf0Gqb52cKpyX8s2psarWIpKQ4nD1bqdgzRNVxr1AsuF8oWtwrFAvuF4oW9wrFgvsllClOgF8t4Nn/bkPuvm8UlZ5XbHhSEXa20sWh6PYF6Pj+UyEhaPfENnjuuhsxpn0GrPYzSNQnwOU4DenQ/+LM1j+EfF3zgIUwXD0HdpfYKOdmVgW/Isq/f14+yvCyWz6B68S3isFIQFUw2v6uf6Js53KUn6v0VCem4/JJO3HstU4RB2J3ePBnnDnrbhFngiYnx0Glqn2wDStAqcEdPXoYR48ewYcfbsBvf3t7iwo/iYiIiIiIiKj+yIONNCKe37MFT+35Sn4tUqVnrJPdVfpWaH/XP+F3nok4L6WxWsRDjzIsh0pvwsnP7w1Zm2T5E8r+s0wRjApqA3yVJTWfI+osgygaG6SataliAEoN7rnnnsHevT9iwIBBmDTpfsVrXq834vsEQYBKpWroxyMiIiIiIiKiRhY82KjM7YRB1CJ33zeKNSV2G9pEGGyU/X0etoab7N7DgnlXWXDmo7HwnP5RnuAuiToYezfuvJRIgo8y1GiMiHNaQwJN0dAKho6jQibG++wlUBnbhD1HFKiqABX1ifA7Lq2B0AxAqcFFOlPzxInjuP32yOeB9ulzDc/jJCIiIiIiImqB5EpPrx8qlQh9/PnBRlfEJeKTzMkxV3quL9qF2V16IbvXMJQ5y5GoN6Hi+LdQVfyC9ndsgU8RdPrg8wkQ7I07L6UmkiTB4/FDjA8djKQytoXPXhoScvodp+A4uhmm3tNCWuYBwNRnOtxO57nPeulgAEqNplWr1nj99bcivm40Gi/i0xARERERERFRQwuu9LS6HTDHG+D0eZATNNhILYhoHXOl5xA8kDEQrh9fQ+muXAhqA0q9DsR3nwhVv0dhLfdAkkKDzmimtTcmSZLCDkaqqdLzbMECtLtjMyCIEVv8m1LQezEwAKVGo9Fo0L17z8Z+DCIiIiIiIiJqQIFqT0EAtMbzlZ7Bg41yC7fL62uv9NyNOVcNw/zemShzO5CoNcDlccNt90LX9R5c3uuBJtfWfiHsLhUS+z0KAHKgCb8XHmtRSDAKAJ6z+1Dx0/tI6DurSbb4NwYGoEREREREREREdMEEQYAoCvL09OrVnka1Fjl7NsuVnkDkwUbZ3+fh6wnTAAAvnwtLA2d6ZmUMgKPcDZvkhFatgs3uhN9fVcXpQtXZmU21rb0uqg9GklxlEHSJ8LjcIcFooNIz/sr7UWbzw+9vWd+LumIASkREREREREREdaZSiTDqfNDqdfA7rRD1ZnjdHvg156s91YKIotsXILewQPHeSION9pWVYkTeKjx33Y1Y2Hs0rG4nErV62F1uOMrdchWj2+0LeZ6m3tZeF4HBSBqPB2Zza1itlfB4JKhU/qCJ8eErPVva96IuxMZ+ACIiIiIiIiIiap5UKhGJCSIce5bhl7d6o+Rv1+OXt3rDJbnkcz2tbgfaGhNQ6qyocbBRdfvKSvHvk0fh9rihdgiwnXXCW+m7JFu4AyRJ+WsgGD1z1o1ylxFnzrphswuX9PcoHFaAEhERERERERFR1IJb3Y06Hyr+70342vRHm35/hNVRDrMhEYKoVpzrGanSE6h5sNFjV2fCWeFhoFeLllj1Wp8YgBIRERERERERUa0Ure4uG0RdAgQA/m7/D8v2/gu5/3oGVrcDg9p0xvoR9yiCztoHG+3CH8IMNnJWeODxhLa5E8WCASgREREREREREdWoqtVdhYqyYxC0nWH1emHW+uHy+fFi4b/w1J6v5LUHyk4iSWsMqfaMPNhoCB7IGAhnhQc2X+hgI6ILxQCUKIIDB37C/fffjRUrVuOaa/o19uMQERERERERXXSiKECtFmHQSnBLPiw7Uozcfe/C6nYgPSEFP9w6F7mF3yjeE6naMzDY6L0Rk7Cw9+iIlZ7hBhsRXQgGoJeQ4DM6JIl/ikJERERERERE4Wk0Kqj0gE6jhdXtgEqtxQv//VpR6WlQa1DisIWc6Qmcr/asfq7n7Z2vRoapFZyVbmglVnrSxcEA9BKgUokQ9AKMOi2sLgfMOgPsLjckp9SiDxF2uZzQ6fSN/RhERERERERETV5w0ZRaLUIfr0HOnq+QW7gdakFE0e0LkFtYoHhPTYON9pWV4ub8tci/firP9aRGJzb2A1DDUqlEGBK0eGnfP9F+/RK037AE7dcvwUv7/glDghYqVcNugYKCbbBY+uHYsaOK6+Xl5Rg1agj+9rcPar2HxdIPb7/9Jlategk33jgaY8YMw5/+9ATs9kp5zc6d38Ni6YdvvinAwoV/xNixw/H4448BAGw2G154IQe33DIOI0cOwuTJ9+C77/4V8nXefPN13HzzOIwZMxTz5z+Ks2fPXuCnJyIiIiIiImraVCoRCUYJyUlamPROJCdpoTYAOXu+wlM/fAmr24G2xgSUOitCQs7gVvdwxl3eDR6PDzarE1q3CjarE06bj+EnXXSsAG1mJEmC3eeJen2CUY9n/7sZT/2QL1+zuh3y76d3s6Cy3B3VvYwqDQRBiOl5Bw0agtat22Djxk/x0EPT5ev5+Z8DAMaMuT6q+3z00QZkZHTHggVP4Pjx41i9eiXcbheWLFmqWPfcc3/C2LHj8cwzt0EURXg8HsyZ8zDOnDmNKVOmoXXrNti0KQ+PPjoLa9e+i/T0LvL9X399NSZOnIR+/frj3//+Fjk5T8X0WYmIiIiIiIiag0C1pyAApvhqg400fmjVWuQWbpfX11Tpmf19HraGaXWf0cOCeb1GwWFzw++XeK4nNSoGoM2IJEm4+Zs38O+zx6Ja30oXF7ZEPSC3sACP9hqJK7c8h1OuyrBrgvVP6oBPBt8fUwiqUqkwYcJN2LjxU0yZ8j9QqVQAgI0bP8Xw4SORkJAQ1X00Gi2WLn1Bfr9Op8Ozzz6NyZOnolOnzvI6i2UYpk2bKf9+48ZPceDAT3jzzfeQmpoGABgwYBCOHTuGN998HU89lQOfz4e3334T48ZNwMMPz5LXnD17Bl98kRf1ZyUiIiIiIiJqylQqEUadD1q9Dn6XDYJaHzLYaFCbztgw4h5F0BlpqBFQ1eq+vmg35lw5DNm9M1HmdiJRq4fd5YbD5m7RR+9R89GkWuCPHDmCRYsW4ZZbbkHPnj1x4403Kl6vqKhAbm4ubrvtNvTr1w+DBw/GQw89hJ9++inkXjabDfPnz0f//v3Rt29fzJw5E6WlpSHrdu7ciTvvvBNXX301Ro4ciVdffTVkQJAkSXj11VcxYsQIXH311bjzzjuxe/fuev3s0Yql/jJSiXqA1e3ASWcF2hqjCyHr6sYbb8Hp06fw7bc7AAAHDx7A/v37cOONt0R9jyFDhsrhJwCMHJkJSZKwd++PinWDBlkUv//uu38hPb0LOnToCK/XK/913XUDsG/fXgDAyZOlOHXqJIYNG6l478iRmTF9TiIiIiIiIqKmRBQFaLUqiKIAlUpEYoIKLsdxePx+nPZ54RDUePbHAjy15ys5OzhQdhJmrRFmrUFxr+zv8zCjpwULeo+WXzNrDXi89xhkZQyAr9IP21kn1A4BtrNOeCt9DD+pyWhSFaAHDhzA1q1b0bt3b/j9/pAg8vjx49iwYQN+97vfYfbs2XC5XFi7di3uvPNOfPTRR0hPT5fXzp49GwcPHsQTTzwBnU6H5cuXY8qUKfjoo4+gVld97CNHjiArKwtDhgzB7Nmz8dNPP+GFF6qqDLOysuR7vfbaa1ixYgXmzp2Lbt264d1338XkyZPxySefoEOHDhfnm4OqEvVPBt8fdQu8KAq4zGgKW6IOVP2gamc04bNBk6OauFaXFngAaNeuPa67bgD+/vdPMHiwBRs3fop27S7HNdf0i/oeSUlJit/HxcVDq9Xh9OlTiuvJycmK35eVWbF//08YMWJgyD0DgeqpU6fCfo2kpJSon4+IiIiIiIioqag+wd0cb4DH54Fb8svVnpEGG0Wq9txXVooReavw3oh7sLD3aFiDKz3Lz1d6+nyc6E5NT5MKQEeNGoXRo0cDAB577DH8+KOyuu+KK65Afn4+DIbzfwoxcOBAjBo1CuvWrcPjjz8OANi1axcKCgqwZs0aWCxVFYGpqamYMGECNm3ahAkTJgAA1qxZg6SkJLz44ovQarUYNGgQzpw5g9WrV2PSpEnQarVwuVx45ZVXMHnyZNx3330AgGuvvRbXX3891qxZgyeeeKKBvytKgiAgTq2Ner3d5caMHhbFGaABM3pYYHe5YRA1DV4LfNNNt2LJkoU4ebIU+fn/wG233RVTmFp9IFFlZQXcbhdSUloprle/p8mUiPT0rsjOfjzivVu1ahX2a5w9ezrq5yMiIiIiIiJqTKIoQK0WIQiA1nh+gnvgTM6vx0/DR4f34Kk9XwEArkpqG7FrNPv7PHwd5lzP2ztfjQxTazgq3FD7BNgqnSHFa0RNUZNqgRfFmh/HaDQqwk8AiIuLQ8eOHRXt7du2bYPJZMKQIeenkKWlpaFHjx7Ytm2bYl1mZia02vOB4oQJE1BeXo5du3YBqGqRr6iowPjx4+U1Wq0WY8aMUdyrqZKcEub1GoXHe48JKVGf12sUJOfF+UE1dOgIJCSYsGTJQpSXl2P8+Btrf1OQ7dv/CZ/v/IHJW7Z8BUEQ0KPHlTW+r1+//jh+/Be0atUa3bv3DPkLAFq3boOUlFbYtm2L4r1btnwV0zMSERERERERXWwajQr6BBUSzHq4tD6IBhVy9myWJ7gDgFoQkZaQoqj2DB5sVN2+slLcnL8Wc3uNwIm7FqPkrsU4cddiPNJzGJwVHrjdVe3tDD+puWhSFaB1UV5ejgMHDmDw4MHytaKiIqSmpoZUA6alpaGoqAgAYLfbceLECaSlpYWsEQQBRUVFGDBggLy++rr09HT89a9/hdPphF6vb4iPVi98Pj8cNjdmdR/aqIcRq9VqjB9/A9atexv9+w/CZZe1jen9Ho8b2dlz8Zvf3IYTJ47jL3/JxYgRmejcObXG911//Q345JO/Yfr0qZg48R506NARFRUVOHDgJ3g8Hjz00HSoVCrcc899eOmlF5CcnILrrhuA7777F3bt+s+FfGQiIiIiIiKieheY4O73S1CrRejjz1d7RmprDzcjpKbBRgAw7vJu8Hr8cDk80KpVsNmdUR2fR9QUNfsA9Pnnn4cgCJg4caJ8rby8POx08cTERLmt3mazAQBMJpNijVarhcFgQFlZmXwvrVYLnU6nWGcymSBJEsrKyi4oAFWrw1e9+v2xn7UZic/nByoBm90JtXhxStQD2bMgAIEvNWzYSKxb9zZuuOHmmO/3u9/dCav1LJ56ahE8Hg+GDRuBP/zhj7W+T6vVYsWKv2Dt2lfx1ltrcfr0KSQmmpGR0Q2/+c3t8rrbbrsTFRU2/O1vH+Djjz9Av379MW/eQjzyyIyon1GlEiL+86SaqVSi4leiSLhXKBbcLxQt7hWKBfcLRYt7hWIRzX4RRQHQCjBoNTjrdiBJa4DT50HOnq/w1LkAM1Jbe3C1Z/BrgVZ3AHg5qF1+Rg8L5l09Cu5Kjxy2imJV8EqNiz9b6qZZB6AfffQR3n//feTk5KBt29gqCpsCURSQlBQX9jWnU4VTp8QGCdVUKgGxzZO/kK91/tm/+24HEhPNGDlyZMyfSatVY86cRzBnziNhX+/fvz/+9a+dYV9LTDRhzpy5mDNnbo1fY8qUqZgyZariWqR7BvP7BYiiiMREY5OuBm4OTKbQ1guicLhXKBbcLxQt7hWKBfcLRYt7hWJR035xej3I2bNZPpMzPSEFP9w6F7mF2+U1kYLO2gcbTcLC3qNR5nEiUaOHx++HQa2BIVHTMB+ULhh/tsSm2QagW7duxaJFizBt2jT85je/UbxmMplQUlIS8p6ysjIkJiYCgFwhGqgEDXC73XA4HPI6k8kEt9sNl8ulqAItLy+HIAjyurrw+yWUl9vDvuZ2u+D3++HzSfB6L06ben0ShKrw0+fz48iRwzh69Ajef389fvvb2yGK6pg/U1P+Pvh8Evx+P8rK7HA4fLW/gUKoVCJMJgPKyx0X7VgGap64VygW3C8ULe4VigX3C0WLe4ViEbxfJEkKqfR0eD1Y9n/bFAOODWoNShy2qNvas7/Pwzc3zggz2Kg3uppawVnphlYSYXe6IEmAG56L9vkpevzZomQyGaKqhm2WAeju3bsxa9Ys3HrrrZg1a1bI62lpadixYwckSVKcA1pcXIyMjAwAVQOV2rVrJ5/xGbxGkiT5zM/Ar8XFxejevbu8rqioCO3bt7/gir9IoZ7P17zP1Qi0vUsS8Nxzz2Dv3h8xYMAgTJp0v2Kd1+uNeA9BEKBSqRryMetVUw5pmwufz8/vIUWFe4Viwf1C0eJeoVhwv1C0uFcoGuejCwlaowbP/jdcpafyXM9Y29pv73w19KIac3oMC50RUn7xZoRQ/eDPltg0uwD04MGDmDp1KgYOHIglS5aEXTNs2DCsWrUKO3bskIcjFRcXY+/evXjggQcU67766is8+uij0Giqyrrz8vJgMpnQt29fAMA111yD+Ph4/OMf/5ADUI/Hg02bNmHYsGEN+VFbjJUrXw17/cSJ47j99sjngfbpcw1WrnwVBQXfN9SjERERERERETUalUqEoBdg1GlR6qiA0VAVftZW6QnE0NbudiBRa4DL44ajwgOPxweP4LtoM0KImoImFYA6HA5s3boVAPDLL7+goqICn3/+OYCqMx4lSUJWVhZ0Oh3uvfdeeaARAMTHx6NLly4AgL59+8JisWD+/PmYN28edDodli1bhm7dumHs2LHye7KysvDZZ5/hkUcewcSJE7F//36sWbMGc+bMgVarBQDodDpMnToVubm5SE5ORkZGBt577z1YrVZkZWVdrG9Ni9SqVWu8/vpbEV83Go0X8WmIiIiIiIiIGlbwBHdRFGBI0MrVnpEmuEeq9ASqqj23TpgWpq39amTIbe2hE9wlSWr2nadEsRCkJhT1//zzz8jMzAz72ltvVQVlv//978O+3r9/f7z99tvy7202G5YuXYr8/Hx4vV5YLBYsXLgQl112meJ9O3fuRE5ODgoLC5GcnIy7774bU6ZMUbTOS5KEV199FevWrcOZM2fQo0cPZGdny1WideXz+XHmTGXY1zweN06fPoGUlHbQaLQX9HUai1otXhLl2C3hn1VjU6tFJCXF4ezZyktiz1Ddca9QLLhfKFrcKxQL7heKFvcKVQ87A5WegZDSWe1cz6uS2uJ/Myejy4fPhNzr48z78P2pn0PO9QSAlwbcjN93uQ56lUZR7elzAh4P51S0NPzZopScHBfVGaBNKgC91EQTgCYnt4VWqwu7pqm7VAJQt9uFM2dKGIBeAP4Ap2hxr1AsuF8oWtwrFAvuF4oW98qlK7it3XpuiJFPkvBsmAnuV2x4Uq7qbKWLQ9HtC9Dx/adCKj27J7bB1gnTsHLvdkWl54zug/DHngOhlYAKtw6CIMDr9SuqPall4c8WpWgD0CbVAk/niWLV8B+/n39a09QF/hkF/pkRERERERHRpSOkrd2kVYSdn43Owrcnj+LpC5jgvq+sFOsP7cTsLr2Q3WsYypzlSNSbYDuyGWf/9ya0u2MLvHY3JImBGFE4DECbKFEUIYoqOJ126PU8C7MpczrtEEUVRLH2P3EgIiIiIiKilkGlEiFo1TDq1bA6PDAbNHB6PXh2z/khRq10cRjeNh2Ttq1TvDfWCe4zeliQ1fVanH5vEMqcp6AytkWJvQR+xymYByyE2+mEJAkgovAYgDZRgiAgPt6M8vLTqKjQQKvVK84lbQ78fqFFH6osSRLcbieczkqYTCnN7p8PERERERER1Y1KJcIQr0POloPILTgMq8OD9BQjfvzjcMUQo7bGBJQ6K+owwf0eLOidiTL7GSTqTag4/i20fjfiMm5D+e6V8Jz+EaLODPOAhTD1exRlNj8AVn8SRcIAtAkzGOLg8bhQUVEGwNrYjxMzURTh97f0H8ACDIZ4GAxxjf0gREREREREFKPg9vVoRqQE1otaNXK2HMRT+Qfk19qb9ChzOxRhZ10nuHcx6HH6g9Hwe2xypad6xHIk9J2FxP6Pwe8sg6hPhNvpRJnND5+vpf+3N9GFYQDahAmCgMTEFCQkmOHzNa+zQFUqAYmJRpSV2Vt0FahKpeLZn0RERERERE1INKFmuPZ1u9MLye2Fz+cPuUfw+jKnB2a9BrkFh0Pua9YaFGFnred6Fu2qdq5nIjx+LzyFf4XnbCH8Lqtc6Rl/5f0os/nh97shikb4He5zbe8MP4lqwwC0Gag6X7J5hWxqtQi9Xg+Hw8epZERERERERNQgqg8giibUFARAH6dsXzcbNJhpScVjI9Ph9Phg0AWd6+nyQatRIWfLAeQWHMYViXp8Ork/rA6P4lkKSyvg9nkwo/tgPLXnK/l64FxPAQJWBk9w7zEYD2QMgOvH11G6KxeC2oBSrwOmvjMQ3/P3SOg1JWKlZ0suNCJqCAxAiYiIiIiIiKhJq6ki0+rwIMmggU8CcjYfRG5BcY2hplGrQs6WQ4r2davDg/d/OI45w9OwrOCw4h5bpw3Gh3tOyOvVooDW8VqYDRpFCHqq0o0fjpzBvF7DAEjI3bcDVrcDJQ4bNhTtxtyrhmF+r+Eoc5YhUZ8IR1kxNJIEIeMeJPR6AJKrDILuXNhZIbLSk6geMQAlIiIiIiIioiYp7KT1ahWZVocHn2X1x7dHz+LpWkJNtSigeEEmcguKQ77W0gk98OevD+HpL8/fQy0KSEsxKtafqnTjy/2nMH1IZ8VaAJjy8X7smjUQczqlIfvqUXLY6bT9DCP8EEQNklUaiKIIyXA5ymxe+HwCNG4PzObWsFor4fGcDztZ6UlUPxiAEhEREREREVGTE27SeriKzFZxWoxIT8GkdbtC7lE91LyqbQJKK9wh7eut4rQYndEK92/YrbjeNkEXdn12XiG2ThsMAFi5/fyz3dG7PSRBA72xPTSieD7s1LVBWQXOVXXq4LcrqzoDR5VGMYeJiOqAASgRERERERERNTlCmEnr4SoyI4WU4ULNEpsLbcK0r0e6R6T1+0orMHzVN3juxp4oGZ0Bq8ODRIMadqcX9goXfD4Bgj182MmqTqKLT2zsByAiIiIiIiIiCiYIAox6dcik9XBBZXBIWdva4Pb1YJHuEWk9UBWCfn/MCrvTA7XHC5vVAa/DLQ8qkiQJPp8/4iR6Irp4GIASERERERER0UUnCELVGZ+CEHJNpRJhdXhqrMgMiDXUzM4rxAxLKhaO7iq/5vVLKDptx0xLashzZucV4pER6Vg0JkNebzZosGhMBuaNTIf/3JR5Bp1ETRdb4ImIiIiIiIjoook02EiCJE9qNxs0MAJhJ62HG0AUOJNTECCfFxocaj6Zv19eG2hfXz/pWiwYnYGyc+3rTpcP80Z2AQCsCJoCf0fv9tCJAmZbOiM7swvKHF653d1R4ZIrPomo6WIASkREREREREQXRbjBRv07mvHFgwOxbGsxcoOCx6+nDQ4JL4GqsHPHTAtEQZCDyhKbCxt2H8fc4emYnxldqNk1xQi7zQG1BNhcnqqWdZWIWUNCg077uaDT6/BALQryeiJqHhiAEhEREREREdFFEW6wUfaoropJ7QBgdXhw19v/wY6ZFgDRV2R67G64/JIipIwUaoar3vT5/IDDDZszfNBZda4ng0+i5oYBKBERERERERE1uHCDjcJNag/YV1qBca/+C/lTByI7s6tc1RlNRWZwSFlbqBkOg06iloUBKBERERERERE1GEEQIIoCBEEIGWwUblJ7sO+OWuFw++H1uhWt6gGxBJUMNYkuXZwCT0RERERERET1TqUSoTZokWA2wKNRwZigg9mgUUxljzSpPcBs0CDRoIbPJ3HSOhHVGQNQIiIiIiIiIqpXgWFHy7cXo92SfPmvn05WYqYlVV4XPNU9nJmWVNidXgafRHRB2AJPRERERERERPUi0O4uhhl2JA82mqEcbLR08wF88eBAxVR3s0GDmZZUzBuZDkeFq7E+DhG1EAxAiYiIiIiIiOiCqFQiBK0aRr0aZU4PzHqNYthRwL7SCox7LXSwkdPlCzvVPdykdiKiWDEAJSIiIiIiIqKYBCo9/X4JoijAEK9DzpaDyC04jCsS9fh0cv86DTaKNNWdiOhCMAAlIiIiIiIioqgEV3oGWtWdHh9ythyS293VooDW5wYbhQtBA4ONbNbQkJOT2omoIXAIEhERERERERFFJAhC1UR3dehgo6ue/xpatQq5BcXyeg42IqKmhhWgRERERERERBSierWnUatSVHoCgEGjQonNFVLpmZ1XiK3TBgMAVm4/zMFGRNSoGIASERERERERkYJKJSrO9VSLAooXZCoqPQGgxOZCmzDt7vtKKzB81Td47saeKBmdAeu5YUccbEREjYEt8ERERERERESkIGjVyNlyEE/lH4DV4UHbBB1KK9whlZ41tbvvK63A98essDs9UHu8sFkd8DrcDD+J6KJjAEpEREREREREMkEQYNSrkVtwWL4WXOlZXXZeIWZaUrFoTIb8utmgwaIxGZg3Mh1+txc+n59nfhJRo2ELPBERERERERFBEASIogBBEGB1eBTVnsGVnk9/eUDxvn2lFVi/+zjmDE1FdmYXlDm8bHcnoiaFASgRERERERHRJaz6sCOzQQMjEHKuZ02DjbL6d4CjwgWb3Q21KMDm8rDik4iaDAagRERERERERJeo6sOOAqHm19MGY6YlFU/m75fXBgYbrZ90LRaMzkBZhMFGPh+DTyJqWhiAEhEREREREV1CAq3ufr+kGHYUYHV4cNfb/8GOmRYAwIqCYjkYvaN3e3RNMcJuc0AtgZWeRNQsMAAlIiIiIiIiugSEa3UHBMWwo4B9pRUY9+q/kD91ILIzu0as9iQiag4YgBIRERERERG1UOcHGwH6OGWr+6DOSdhwz7WKcz6DfXfUCofbD6/XzWpPImrWxMZ+gGBHjhzBokWLcMstt6Bnz5648cYbw6774IMPMG7cOPTq1Qs333wztmzZErLGZrNh/vz56N+/P/r27YuZM2eitLQ0ZN3OnTtx55134uqrr8bIkSPx6quvhvxAlyQJr776KkaMGIGrr74ad955J3bv3l0vn5mIiIiIiIiovqlUItQGLRLMBng0KqiNWuRsOYSn8g/IgeeBk5VIMmrOVYKGMhs0SDSo4fNJ8Pn8DD+JqNlqUgHogQMHsHXrVnTq1Anp6elh12zcuBGPP/44xo8fj9deew19+vTB9OnTQwLJ2bNnY/v27XjiiSfwwgsvoLi4GFOmTIHX65XXHDlyBFlZWWjdujVeeeUV3HvvvVixYgXWrl2ruNdrr72GFStW4L777sMrr7yC1q1bY/LkyTh27Fi9fw+IiIiIiIiIYiUIQlWL+7lfDfE6LN9ejHZL8tHrha0QBQG5BcWK95yqdOPL/acwfUjnsPecaUmF3ell8ElEzV6TaoEfNWoURo8eDQB47LHH8OOPP4asWbFiBW644QbMnj0bADBw4EDs378fL7/8Ml577TUAwK5du1BQUIA1a9bAYqk6tDk1NRUTJkzApk2bMGHCBADAmjVrkJSUhBdffBFarRaDBg3CmTNnsHr1akyaNAlarRYulwuvvPIKJk+ejPvuuw8AcO211+L666/HmjVr8MQTTzTsN4WIiIiIiIgognDnejo9PrnaEwCuapuA0gp32Fb37LxCbJ02GKIgKIYdzbSkYt7IdDgqXBf7IxER1bsmVQEqijU/zrFjx3D48GGMHz9ecX3ChAnYsWMH3G43AGDbtm0wmUwYMmSIvCYtLQ09evTAtm3b5Gvbtm1DZmYmtFqt4l7l5eXYtWsXgKoW+YqKCsXX1Gq1GDNmjOJeRERERERERBdDoMpTrVZWerZbko+rnv8aWrVKUe1ZYnOhTbw2bKv7vtIK3LT2OzwyIg0nFo9FyeKxOLF4DGYN6cxhR0TUYjSpALQ2RUVFAKqqOYOlp6fD4/HILelFRUVITU2FIAiKdWlpafI97HY7Tpw4gbS0tJA1giDI6wK/Vl+Xnp6O48ePw+l01tOnIyIiIiIiIoosmnM9DRoVSmwuRbVnba3u13drA6/HD5vVDrXHC5vVAa/DzfCTiFqMJtUCX5uysjIAgMlkUlwP/D7wenl5ORISEkLen5iYKLfV22y2sPfSarUwGAyKe2m1Wuh0upCvKUkSysrKoNfr6/yZ1OpmlUFHTaUSFb8S1YT7haLFvUKx4H6haHGvUCy4Xyha9b1XRFGA1hCY4l4MtSigeEFmyLmewdWewSFooNUdAFZuP1yt1b0L3A4XoBLOPbMAQFlQRA2LP1soWtwrddOsAtCWRhQFJCXFNfZjNCiTydDYj0DNCPcLRYt7hWLB/ULR4l6hWHC/ULTqa69Uur3I2XIQT+XvBxD5XM/gas+nvzwgX99XWoHhq77B+knXYuHoDJQ5PUjUa+Dx+2HQqmDQGuvlOenC8GcLRYt7JTbNKgBNTEwEUFW92bp1a/l6eXm54nWTyYSSkpKQ95eVlclrAhWigUrQALfbDYfDobiX2+2Gy+VSVIGWl5dDEAR5XV34/RLKy+11fn9TplKJMJkMKC93sG2CasX9QtHiXqFYcL9QtLhXKBbcLxStC9kroigAahX0Og2sDjfMBi00ohjxXM/qIWh2XiG2hRlsdEfv9uiaEgen3QmtBNgrvJAkwF3JQUeNjT9bKFrcK0omkyGqathmFYAGzuEsKipSnMlZVFQEjUaDDh06yOt27NgBSZIU54AWFxcjIyMDAGA0GtGuXTv5jM/gNZIkyfcP/FpcXIzu3bsrvmb79u0vqP0dALzelr1ZfT5/i/+MVH+4Xyha3CsUC+4Xihb3CsWC+4WiFeteUalEaA3ac63uVa3qgzonYcM910Y81zO40hOoqvZcv/s45gxNRXZmF5Q5vEg0qGF3euGocDI0acL4s4Wixb0Sm2Z1YECHDh3QuXNnfP7554rreXl5GDRokDzNfdiwYSgrK8OOHTvkNcXFxdi7dy+GDRsmXxs2bBi++uoreDwexb1MJhP69u0LALjmmmsQHx+Pf/zjH/Iaj8eDTZs2Ke5FREREREREVBeBqe6CIEDQqs+1up8fbHTgZCWSjJqQKe7ZeYWYYUnFwtFd5dfMBg0WjclAVv8O8Dk9sFkdHGxERJe8JlUB6nA4sHXrVgDAL7/8goqKCjns7N+/P5KTkzFjxgzMnTsXHTt2xIABA5CXl4c9e/bgnXfeke/Tt29fWCwWzJ8/H/PmzYNOp8OyZcvQrVs3jB07Vl6XlZWFzz77DI888ggmTpyI/fv3Y82aNZgzZ44cpup0OkydOhW5ublITk5GRkYG3nvvPVitVmRlZV3E7w4RERERERG1JCqVCEGrhlGvltvUAQG5BYcV66I513PB6AyUOTxBlZ4uOez0+aSL+KmIiJqeeglAJUnCmTNnAADJycmKtvNYnD59GrNmzVJcC/z+rbfewoABA3DjjTfC4XDgtddew6uvvorU1FSsXLlSrtgMWL58OZYuXYpFixbB6/XCYrFg4cKFUKvPf+ROnTphzZo1yMnJwYMPPojk5GTMnDkTkydPVtxrypQpkCQJa9euxZkzZ9CjRw+sWbNGbrknIiIiIiIiioYgCBBFAYIA6ON0tba6BwSmuIc/19MIu80BtQTYXB5IEgNPIqJggnQBPxkPHjyIFStW4J///CecTicAQK/XY+jQoZg+fbp83iaF5/P5ceZMZWM/RoNQq0UkJcXh7NlKnklBteJ+oWhxr1AsuF8oWtwrFAvuF4pW9b1SvdrTqFXhha+L5KnuANAqToviBZno8NSXYUPQ/h3NyJ86EFqVSlHtKbm9bG1v5vizhaLFvaKUnBzXsEOQvv/+e0yZMgV+vx+ZmZno3LkzgKqzNjdv3oxt27bh9ddfR79+/er6JYiIiIiIiIiapUBjpCBUtbob4s9Xe6pFAcULMhVT3YGaBxsBwPXd2sDr8cNlc0EtCqz2JCKKUp0D0GeeeQbJycl455130K5dO8VrJ06cwN13342lS5fio48+uuCHJCIiIiIiImoOApWeBr0GpRUuJMYb4PR4kbPlEJ7Krwo1r2qbgNIKd0yt7jMtqZg3Mh2OChckSeK5nkREMahzAHrw4EHMmjUrJPwEgHbt2mHixIlYuXLlBT0cERERERERUVNX07me6SlG7Jk7QlHtWWJzoU28FmaDJiQE3VdagZvWfof8qQORndk14mAjIiKKXu1N8hG0b98ebrc74usejwdt27at6+2JiIiIiIiImjSVSoTaoEWC2QCPRgW1UStXegaCTYNGhRKbSxF0Bre6hxNodbdZ7VB7vLBZHfA63Aw/iYjqqM4B6MMPP4y3334bhYWFIa/t3bsX77zzDmbMmHFBD0dERERERETUFAXO9Vy+vRjtluSj1wtbIQpCyLmewdWewbLzCjHDkoqFo7vKr5kNGiwak4F5I9Mhub3nWt39POeTiOgC1bkF/ocffkBKSgp++9vfom/fvujUqRMA4PDhw9i9eze6du2K3bt3Y/fu3Yr3LVy48IIemIiIiIiIiKixCVo1crYcrPVcz0iDjfaVVmD4qm+wftK1WDA6g63uREQNqM4B6DvvvCP//c6dO7Fz507F6/v378f+/fsV1wRBYABKREREREREzVLgrE9JkmDUq5FbcFh+raZzPbPzCrEtzGCjO3q3R9cUI+w2B9QSONWdiKiB1DkA3bdvX30+BxEREREREVGTFJjsbtSrYXV4kGTQ4KzDG/Fcz+BKT6Cq2nP97uOYMzQV2ZldUObwstqTiOgiqnMASkRERERERNRSRTPZvXq1Z3ZeIbZOGwwAWLn9sFzpOdOSiqz+HeCocMFmd0MtCqz2JCK6iBiAEhERERER0SUrEHT6/RIkSQqp9jRqVfJk94BDp+3Y9NNJzLB0VlwPPtdz4egMlDk9MOk1sDs9ikpPn4/BJxHRxRR1ANq9e3cIghDzFwg3JZ6IiIiIiIioMVUPOs0GDZwuH7QaFXK2HEBuwWGoRQHFCzJDJrsD58/1FBD+XE+n3YnWJiOs1kp4PWxxJyJqTFEHoA8//HBIAJqfn4+DBw/CYrEgNTUVAFBUVITt27eja9euGD16dP0+LREREREREVEtqld1Vr8migIM8cq2drNBg63TBuPDPSdqnewOVFV7Dlv1DbZPH4LszK4hU9wD//nMLnciosYXdQA6Y8YMxe83bNiA06dP47PPPkNaWpritUOHDuHee+9FmzZt6ucpiYiIiIiIiKqprX09UNUpQYJBF3TN4wtpa1eLAtJSjIpqz5omuwdeN2pVqCizQy0oz/VUq8WG/wYQEVFU6vwTec2aNbjnnntCwk8ASE9Px913343XX3/9gh6OiIiIiIiIqDqVSoTaoEWC2QCPRoUEswFaow6GeD2Wby9GuyX5aLckH8NXfQOoBCwrOCxfu+r5r6FVq0La2tsm6EKqPYMnu4cz05IKu9MLv1+Cz+fnUCMioiaqzkOQSkpKoFZHfrtarUZJSUldb09EREREREQkq2kqe7j2dQDIHtUVf/76EJ7+8vw1g0aFEpsrpKIzUrVnTZPd541Mh6PC1cCfnIiILlSdK0C7du2KdevW4ddffw15raSkBO+99x4yMjIu6OGIiIiIiIjo0la92lNt1Mrt64GgMlz7eqs4LUZntMLK7YcV9wsOOoNFqvYMTHa/rXd7nFg8FiWLx+LE4jGYNaSzYrI7ERE1XXWuAM3OzsYDDzyAcePGYfTo0ejUqRMA4PDhw/jqq68gSRKee+65entQIiIiIiIiavlqGlYUaSp7uPb1cNcAZdAZXBkKVFV77phpgSiEn+xutzmglqA465OIiJq+Ogeg/fr1w/vvv4+XXnoJX375JZxOJwBAr9fDYrFgxowZ6NatW709KBEREREREbVcYQcYVRtWFGkqe7j29ZoGGGXnFWLbtMFhg06dKGC2pTOyM7ugzOFVTHZntScRUfNU5wAUADIyMvDyyy/D7/fjzJkzAIDk5GSIIqfdERERERERUc1qOtczPcWIPXNHRDWVPVxVZ02VnvtKK7B+93HMGZoaEnTazwWdXocHalFgtScRUQtQL0mlKIpo1aoVWrVqxfCTiIiIiIiIahTNuZ7hhhXVNJU9O68Qj4xIx6IxGfL5nks3Hwi5ZjZosGhMBrL6d4DP6YHN6oDa44XN6oDX4ZarPCWJk92JiFqKOleArly5ssbXBUGATqdD27Ztcd111+Gyyy6r65ciIiIiIiKiZqwu53rGOpU9Uvu60+WrtaXd52PISUTUkl1QACoIAgCE/IlY9esqlQq33347Fi1axApRIiIiIiKiS8SFnOsZqYU9MJV9/aRrsWB0Bsocnqja19nSTkR06apzALp161ZMnToVPXr0wKRJk9CxY0cAwJEjR/DOO+/gp59+wrJly2C32/HXv/4VGzZsQJs2bTBt2rR6e3giIiIiIiJqmlQqUVHpGeu5nkDNw4pqmspe1b6uDDnDXSMiokuDINXxj76mTZsGvV6PF198Mezrc+bMgc/nw4oVKwAAU6ZMwdGjR/HFF1/U/WlbGJ/PjzNnKhv7MRqEWi0iKSkOZ89WwuvlpESqGfcLRYt7hWLB/ULR4l6hWHC/1Cy41V2l12D59mK50hOoqvb8ZHJ/pD/zleJ9H993Hf7zszVkWBEArLj1Kky65nLotSpFC7vk9jbpqezcKxQL7heKFveKUnJyHFSq2rvN69yP/q9//QvXXXddxNevu+46bN++Xf798OHDcfz48bp+OSIiIiIiImpCBEGoanE/92vwUKMEswFGvQa5BYcV7wmu9gyWnVeIGZZULBzdNeZhRURERLWpcwu8VqvFnj17MHHixLCv//DDD9Bozv+PmtfrhdForOuXIyIiIiIiokYQXNUpSVLIuZ5JBg18EpCz+SByz7WpD+qchA33XFsv53pyWBEREV2oOgegN954I959912YzWZMnDgRV1xxBQDg559/xrp16/Dpp5/i7rvvltd/++236NKly4U/MRERERERETWI6tPaQwYYuXzQalTI2XJAPtfzs6z++PboWTwd1Op+4GQlkoyaej3Xk4iIqK7qHIA++uijOHXqFN544w28+eab8nR3v98PSZIwduxYPProowAAl8uFK6+8Etdcc039PDURERERERHVm2iqOs0GDbZOG4wP95yQz/VsFafFiPQUTFq3S3G/SJWeQFW15/rdxzFnaCqyM7sozvUMrvYkIiKqL3UOQHU6HZYvX469e/fin//8J3755RcAwOWXXw6LxYIrr7xSsXb69OkX/rRERERERER0wapXelaf1h6uqlMtCkhLMSomuLdN0KG0wh1S5QlUVXpuDVPpOdOSiqz+HeCocMFmd0MtCqz2JCKiBlXnADSgZ8+e6NmzZ308CxERERERETWg6pWeZoMGTo8POVsO1VrVGS7sDB5q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Frfddhuee+45iKKIyy67DK+88goSEhJw1113yevuuusuvP3223j44YcxdepU/Prrr3juuedw11134bLLLrvon5+IiIjqR2C6eNWgocNhWtVrHghU11Az8Fqk6sZIlZr1UTkZfkiQGk6XD/NGdgEARTv5Hb3bo2uKEXabA2oJsLk8EEUB80amK9aGqwyN9AyxfC+AqtB2W8RW93Q4KlznJrtzqjsRERERhdfsAlBRFPHqq69i6dKlWLRoETweD/r164d3330XrVu3BgD069cPubm5WL58OT788EO0b98eTz/9NMaPH6+418KFCxEXF4c///nPqKysxDXXXIM33nhDMR0+MTERf/3rX/HUU0/h4YcfRlxcHG677TbMmTPnon5uIiIiql+CVn2urb3mVvX6CPLChZo1DfLJzivEjpkWRejXtXUczto9MVdORhoSZOlorqqadHmqAkSViFlDOiM7swvKHN6gdnKXoqLS55PgqHCFrHV6qipDA4OaIj1D4PoMS2f5e1/b867ffRxzhqbW+mxEREREROE0uwAUAJKTk/H888/XuCYzMxOZmZk1rtFqtZg3bx7mzZtX47r09HS8+eabsT4mERERNVGCIMCoVyM3qH0diG0gUKxBXrhQc+nmA/jiwYEh1Y139G4PnShgtkUZMgJCvVZOKoNNP+Bww+b0QC0KcjAaTri14SpDI32+Y1YHHhvVFQJq/17MtKQiq38HOCpcsNndtT4bEREREVF1gsT/99hofD4/zpypbOzHaBBqtYikpDicPVvJQ3mpVtwvFC3uFYpFTftFpRLh0ajQbkm+4nqrOC2KF2Siw1NfKgLF7m3isXXaYOQWFMsDgYKnwD+7+aAc2gWGEi3bWhQS5D02Mh1Ojw8Gnfp85aTLBwmS4prd6YXk9sLn8ysGNKn0Gry0/bBcZQkAH993Hf7zszUkcAWAFbdehUnXXA69VhX23vUtMDzKqK/98wleHyS1Kqq1DfW8AfzZQrHgfqFoca9QLLhfKFrcK0rJyXFRTYFnANqIGIASVeF+oWhxr1A41Se4B2g0IszmOFitlfB4/Iq1kiQhPtGAdkvyQyonIwWK3dvEY/2ka9Gtdbxi4nhdgrxwzxzpcwQLnFv67JZDUQWugUpPv1+q9d71KZbPV9fvRX3izxaKBfcLRYt7hWLB/ULR4l5RijYAbZYt8ERERETB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n6OEXK1Bfo4SGmUxtNqSf5KXJazHSURERERERERUCZgAJauQyWRwdpRj2cGrkvaHTV4ChpOSxhKVpXdPL89xgfuJzthQT0yPaCpJdJau33l7ZgSyZr6A2zMjMLaDh7jTOpOdRERERERERESPFyZAySpsbGTIUapNbhJkqq10e+nkpY6h2ZfxKZcMzsjU7Z6ua79bWIy96X+ZfdzS9Ttvz3xBkuhUFBRBrSg2ONOTiIiIiIiIiIgeP6wBSlZRUiLAzcnO7E2C4lMuYVdMe0lb6eSlDNL2h9093c1Jji5N6ph93PLU7yQiIiIiIiIiosePTOBa3Uqj1Zbg3r3Cyr4Mq5E72eOT1KuYvfui3mtLI1sgqq07HO1tJclLAQKcHOSSxKNMo4Ugt4Wzo7RdKNZAqy2BTCaDjY0MJSWCmJQ01Fa23cZGBpm93KLjUsWQy21Qs2Y1/P13ITQazqYl4xgrZAnGC5mLsUKWYLyQuRgrZAnGC5mLsSJVq1Y12No+eIE7Z4CS1QjFGkzu7AUAklmWY0I9MTSoIZQFRchXFOvNqNQo1fqzLNVa5KsMtKP8u6drtQKgLLbouERERERERERE9N/GBChZjVZbAmWBbul5U+Sp1HB1tINCpRY3Cbrfz/LkpTUx0UlERERERERE9ORgApSsSqstAZTFUGo0qOtWDTk5hdCoOSWbiIiIiIiIiIgqB3eBp0dCt7KcpTSJiIiIiIiIiKgyMQFKREREREREREREVRYToERERERERERERFRlMQFKREREREREREREVRYToERERERERERERFRlMQFKREREREREREREVRYToERERERERERERFRlyQRBECr7Ip5UgiCgpKTqvv22tjbQaksq+zLoP4LxQuZirJAlGC9kLsYKWYLxQuZirJAlGC9kLsbKv2xsZJDJZA/sxwQoERERERERERERVVlcAk9ERERERERERERVFhOgREREREREREREVGUxAUpERERERERERERVFhOgREREREREREREVGUxAUpERERERERERERVFhOgREREREREREREVGUxAUpERERERERERERVFhOgREREREREREREVGUxAUpERERERERERERVFhOgREREREREREREVGUxAUpERERERERERERVFhOgREREREREREREVGUxAfoEuXbtGmbMmIGePXvCz88PPXr00OtTXFyM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omNl3759uH79Opo0aYLc3Fxs27YNR48exddffy25Lo5ZpGSCoTn2VCXdvHlTLLxd1rp16xAcHIy1a9fiq6++QlZWFtzc3PDCCy9g7NixknoTKSkpSEhIQEZGBgoLC1GzZk2EhYVh3Lhxkro0586dw8yZM8UBXOvWrTF27FjJjqs6KpUKa9asQXJyMm7cuAG1Wg0HBwckJCRIBhAAsHnzZnFWRlkXLlyw+H0hfdaKFZ0vv/wSSUlJyMrKgru7O4YNGyZJlickJGDbtm3IzMyEWq2Gu7s7XnnlFcTExOjN6jI3Vkzdg7u7O1JSUsrz1pAB1o4X3S+M+/fvF+vmWHo+ndzcXKxatQo//fQTsrKyoNFoULt2baxevVryy+Tdu3cxf/58nD59GtnZ2ahevToaN26MQYMGlavwPBlW0bEC3I+BDh06YODAgZg0aZLRazM3Vgx577338PvvvyM5OdlkP7KMNePl7NmzWLJkCc6ePQuVSgUPDw8MHDgQPXv2NHr+o0ePYsCAAdi4caPeChdL4mXZsmVYvny53vH5WWQ91oyVCRMm4MiRI8jNzUWDBg3Qp08fDBgwQG8TpDt37mDu3Lk4ePAg5HI5IiIiEBcXpzdji+OWx09lxItCocDHH3+M7du3o6CgAM2bN8ekSZP0vpjTaDT4+uuvsWnTJly5ckVcIr9w4UK9FXHx8fE4cOAAbt26BblcjgYNGiAyMhL9+vXjZjdW0qVLF2RmZhp87eeff0aDBg0AAN9//z0SExNx69YteHp6Yvz48eLMX538/HzEx8dj9+7d0Gg0CA0NxbRp0yQzBX18fIxeS9nfc7OysrBixQrs27cP2dnZKCkpgYeHBxITE/Hss8+avK+oqCg4OzsjISHBZD8yX0XHSmpqKj744ANcu3YNcrkcQUFBmDBhgt6X9ADHLKUxAUqPpWPHjmHw4MEYOXIkRo8eXdmXQ48xxgpZIjk5GRMnTsSCBQtYWoNMYqyQJRgvZC6OW8gS6enp6N27N7p374558+ZV9uXQYywhIQHLli1DYmKi3gQiotKe5DELa4DSYykwMBBTpkzB0qVLsWXLlsq+HHqMMVbIEj169MDgwYMxbdo0SW0dorIYK2QJxguZi+MWsoSXlxcWLVqETZs24dNPP63sy6HH2PDhw/H8888jNjZWUkKDqKwneczCGaBERERERERERERUZXEGKBEREREREREREVVZTIASERERERERERFRlcUEKBEREREREREREVVZTIASERERERERERFRlcUEKBEREREREREREVVZTIASERERERERERFRlcUEKBEREREREREREVVZTIASERERERERERFRlcUEKBEREREREREREVVZTIASERERERERERFRlfX/DBp2HaBUGpgAAAAASUVORK5CYII=", + "text/plain": [ + "<Figure size 1600x400 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "#direct reduction strategy\n", + "regressor = LinearRegression()\n", + "forecaster = DirectTabularRegressionForecaster(estimator=regressor, window_length=4)\n", + "forecaster.fit(y=y_train, fh=fh_abs)\n", + "y_pred = forecaster.predict()\n", + "\n", + "print(f\"MASE: {round(mean_absolute_scaled_error(y_true=y_test, y_pred=y_pred, y_train=y_train), 3)}\")\n", + "plot_series(y_train, y_test, y_pred, labels=[\"y_train\", \"y_test\", \"y_pred\"]);" + ] + }, + { + "cell_type": "markdown", + "id": "64ad7c5a", + "metadata": { + "id": "64ad7c5a" + }, + "source": [ + "## 3. Evaluation of forecasting models" + ] + }, + { + "cell_type": "markdown", + "id": "718f8427", + "metadata": { + "id": "718f8427" + }, + "source": [ + "### Performance metrics" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "34cb830f", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 346 + }, + "id": "34cb830f", + "outputId": "8a07532e-bf01-4af5-c08b-02476922ec44" + }, + "outputs": [ + { + "data": { + "image/png": "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yauq0jPU1r6ioEh5T+sUQ8zJ7gdOlWHIqq+wfeqgqIONBCG4jkPdiYjqHwNQIiIiIiIiapTCQ005LGmsGHZWVekJACadBsUOjyrsrGyye+h1s16DshIntIIAh0dSnkOr5cxhIqKGgj+RiYiIiIiIqFGJmMpuNUFr0kOn06iuW6wmmFKMWLb9KNosykebRfm45k9fQq/VqCo9AXXYGVLVZPfptgw43T4EAjL8/oAqhCUiooajVipAZVnGuXPnAADNmjWDEKr1JyIiIiIiIqpFGo0Y0b5uNenw5OiumNivg2pae7QBRtEqPQF12Ln484vrQ5PdBQGqrxc+2Z2IiBq2GgWghw8fxvLly/HPf/4TbrcbAGA0GjF48GBMnToVWVlZtfKQREREREREdHkLtbWLei1ytxxWta/bXRLaW01YsvmQEnbGGmBUWVt7aLCRKFwcbFTs8GDD3hOYPTQT87KzIs765GR3IqKGr9oB6K5duzBp0iQEAgFkZ2ejU6dOAICioiJs3rwZ27Ztw6uvvoo+ffrU1rMSERERERFRE1fxXM/wae0lbglWow4rCo6q3tM8SY+RWc3x4Ia9yrVYA4xiVXoCwcFGb+89gVmDM5CTfSVKXD4l7JScXngCMrSi+qxPIiJq+KodgD799NNo1qwZ3nzzTbRp00b12smTJ3HfffdhyZIleP/992v8kERERERERNS0hQedyrAijx96nQa5Ww5hRcFRtEs14uMJfSNCzWhhZ6KVnqG29ol928NV5oHD6Y0advr9DD6JiBqbageghw8fxowZMyLCTwBo06YN7r33XqxcubJGD0dERERERERNX6xzPbdOGYj39p1U2t21ooAWUULNaGFndSs9w9vaGXYSETUN1Z4C37ZtW3i93pivS5KE1q1bV/f2RERERERE1MQJggCNRlSd6xkKMLWigM7pZtW09lhT2UPXp9nU13Py9mOaLQN/GNVFme5uNemwcFQWJvZtD79bgsPuglbywWF3wefy8kxPIqImqNoVoI888giWLFmCYcOGoXv37qrXvvvuO7z55puYN29ejR+QiIiIiIiImpZ4zvWMdYZnaCo7AKzcfrFa9LjdhbkjukBA4gOMWOlJRNS0VTsA/eabb5Ceno7bb78dvXv3RseOHQEAR48exd69e9GlSxfs3bsXe/fuVb1vwYIFNXpgIiIiIiIiarwqtrvHOtcz1hmeB06VYeiqr7D0lqtQPDIL9rBQ01PuwYxBnTjAiIiIVKodgL755pvK3+/evRu7d+9WvX7w4EEcPHhQdU0QBAagREREREREl5nwye5CWLs7EPtcz6rO8Nx13A5bB2uwfT081JT8cLglDjAiIiJFtQPQAwcO1OZzEBERERERURMTbbI7IKja3SsLOnPy9mPHdFvUae1zhmeq2tjDybLMsJOIiBTVDkCJiIiIiIiIYok22X1ApzRs+NX1cZ/reVfPtjCIAmbaItvaY4WfREREFTEAJSIiIiIiolpRWas7ABw6XY40sy6hcz2dF4JOnyt6WzsREVFV4g5Au3XrBkEQEv4C+/fvT/g9RERERERE1LCFh52iKFTZ6g7U4FxPsK2diIiqL+4A9JFHHokIQPPz83H48GHYbDZkZGQAAAoLC7F9+3Z06dIFI0eOrN2nJSIiIiIioksqPOiUZTniXM80kw5+GcjdfBgrLpzTGavVHbjY7p7ouZ5ERETVFXcAOm3aNNXvN2zYgLNnz+KTTz5B586dVa8dOXIE999/P1q2bFk7T0lERERERER1rqqqTrfHD71Og9wth5RzPT+Z2Bc7j53H4jha3YFgpeet675G/uT+yMnugpKwdneGn0REVBfE6r5x7dq1+NWvfhURfgJAZmYm7rvvPrz66qs1ejgiIiIiIiKqexqNCK1JjxSrCZJOA4vVBFOKEcu2H0WbRfnKX8dK3cq5nnaXhOZJegzLTMfKSlrdo7mpa0v4pAAcdmew3d3ugs/lZfhJRER1otpDkIqLi6HVxn67VqtFcXFxdW9PREREREREdaRipWfFae3Rqjq1ooDO6WasKChSrrVOMeBUmbfare4815OIiC6FagegXbp0wfr163HrrbeiVatWqteKi4vxt7/9DVlZWTV+QCIiIiIiIqodFc/vtJp0cEt+5G45okxrD1V1jl+/R/XeaGFnscODlsl6troTEVGDVu0ANCcnB7/5zW8wevRojBw5Eh07dgQAHD16FF988QVkWcbSpUtr7UGJiIiIiIgoMVVVemamm7Fv9rC4qjqjhZ2VTXUHLra6exweaEUhYrI7ERHRpVDtALRPnz5455138OKLL+Lzzz+H2+0GABiNRthsNkybNg1du3attQclIiIiIiKi+MRT6QkAJp0GxQ5PXFWdscLOUKu7IEAJVtnq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fvvteOihh3D+/HkAQKtWrTBgwAAMHDgQv/71r/HWW29h0aJFtfawRERERETUMCVyrmfFoDPWFPdQW/vSW65C8cgs2MPa2p0Xgk6fS4JWFFjtSURERDFVfUpoDGfPnsW1114LADAajQAAl8ulvD569Gjk5+fX8PGIiIiIiKihC53ruWx7Edosylf+OlbqVtrd7S4JxQ6Pcq5nuPB294oOnCrDruN2ON0StJIPDrsLPpdXqfIMnqcZYPhJREREMVU7AG3evLlS+WkymZCamoqiootn9pSVlcHj8dT8CYmIiIiIqMERBCFY9SkIEMLO9QxVcFZ1rmdFOXn78eiwTCwclaUEpFaTDgtHZWHO8EwEvD4GnURERFQt1W6Bv/baa7F7927l98OHD8fatWvRokULBAIBvP766+jVq1dtPCMRERERETUQ0VrdAYHnehIREVGDVe0AdPz48fj000/h9Xqh1+sxY8YM7NmzB7///e8BAB06dMD8+fNr7UGJiIiIiKh+hAYbCQJgTDIgd8thrCgIhpcDOqVhw6+u57meRERE1GBVOwDt06cP+vTpo/y+TZs2+Mc//oGDBw9CFEV07twZWm21b09ERERERPWsYrWnWa9B7pYjeCr/kLLm0OlypJl1EUFneLv74s8Pqe4bOtfT1sEaPNezQtAZPNeTwScRERHVjmqfARr1ZqKIbt26ISsri+EnEREREVEjE36uZ8XBRj2e3QpREFRnegI815OIiIgavhqllGVlZVi/fj127tyJs2fP4sknn8S1114Lu92ODz/8ECNGjEDHjh1r61mJiIiIiChBofb1QEBWBY3h10VRiDjX0y35VdWe17ROiXqmJ3DxXE9RELC8oIjnehIREVGDUu0AtLi4GL/61a9QXFyMjh07orCwEOXl5QAAq9WKt99+Gz/99BMWLFhQaw9LRERERETxiTasyOn2QfD5IWs1yvU0kw5+GcjdfBgrLoSXmelm7Js9TFXtGetMTyDY0n7ruq+RP7k/crK7oITnehIREVEDUu0AdOnSpSgvL8f/+3//D82aNcPAgQNVr48cORJffvllTZ+PiIiIiIjiVNmwIqtJhydHd8XEfh1UYecnE/ti57HzWBx2rqdJp0GxwxP3mZ4AcFPXlvBJAXgcnqhBJ8/1JCIiovpS7TNAt2/fjvHjx+PKK6+EIAgRr7dv3x4nT56s0cMREREREVGk8LM6gWC1p9akR4rVBEmngdasV9rXQyGm3SWhvdWEJZsP4an8g7C7JDRP0mNYZjpWFhxV3T+82jNcTt5+TLNlYMHILlHP9JS9vgtBJ8/1JCIiooaj2hWgbrcbzZo1i/l6qB2eiIiIiIhqR7S2drfHD71Og9wth7Ci4Ci0ooCi+dkRw4qaJ+kxMqs5HtywV7nWOsUQ9VzPWNWeB06VYeiqr/D2+Osxf2SWqtWdZ3oSERFRQ1XtADQzMxP//ve/cc8990R9/fPPP8dVV11V7QcjIiIiIrrcVRxUZEqObGvfOmUg3tt3ssphRdHCzsrO9czJ249tMQYbdUk3w+lwQSuDZ3oSERFRg1ftAPT+++/H3Llz0bVrV4wZMwZA8FyfH374AStXrsTevXuxYsWKWntQIiIiIqKmLNGp7ACgFQV0TjfHNawo2vXKzvU8cKoMb+89gVmDMzjBnYiIiBq1agegv/jFL3DixAm8+OKLWLZsGQDgN7/5DWRZhiiKmDVrFkaOHFlbz0lERERE1CRVbGuPdyo7EL2qM1aoGbo+zdZJFaLm5O3H1ikDIQhQVZZOt2VgYt/2cJV54HB6OcGdiIiIGq1qBaAulwv33Xcf7rzzTuTn52PTpk344YcfEAgE0KFDB9x4441o3759bT8rEREREVGTotGIEW3t8U5lB2JXe4ZCTQBYuf1iqHnc7sLcEV0g4GJbe7HDgw17T2D20EzMy459ricnuBMREVFjVa0A1GQy4ccff4QgCGjbti0eeOCBWn4sIiIiIqKmKbzVXdBrkbvlsFKRGZrKPn79HtV7YgWd1RlW5Cn3YMagThFt7ZLTC09AZqUnERERNTlidd84ePBgFBQU1OazEBERERE1KYIgBFvcL/yqNemRYjVB0mmQYjXBbNRhRcFRZX08U9krysnbj0eHZWLhqCxYTToAiBxWJPngsLvgc3khSX74XF447Orrfn8AsiwrvxIRERE1FdU+A3TKlCmYMWMGHnvsMdx9991o3749DAZDxDqr1VqT5yMiIiIianTiOddzQKc0bPjV9bUyld0gCphpi6zqrGxYUTDsZNBJRERETV+1A9Cbb74ZAHD48GH8/e9/j7lu//791f0SRERERESNQsUJ7vGc63nodDnSzLpamcruvBB0+lwSW9iJiIiIKqh2APrII49AEITafBYiIiIiogYtPOiUZTmi0tNq0sEt+ZG75UiV53rGCjtrMpWdVZ1EREREkaodgE6bNq02n4OIiIiIqMGKGnR6/NDrNMjdckgJKjPTzdg3exhWFBQp7411ridwMewMb2vnVHYiIiKi2lXtAJSIiIiIqCkLVXsKAmBMUre0W006bJ0yEO/tO6lUegKASadBscMT97meB06V4dZ1XyN/cn/kZHdRhZ2cyk5ERERUO6o9BZ6IiIiIqCmqOK1da9YrLe2hAFMrCuicblZVegLqsDOksgnuAHBT15bwSQE47E5OZSciIiKqAwxAiYiIiIgu0GhEmJINWLa9CG0W5aPHs1shCkJE0BmrrT1W2JmTtx/TbBn4w6guSjhqNemwcFQW5gzPhOz1MewkIiIiqiNsgSciIiKiy1porqcgANBpkbvlsNLWfk3rlKhBZ2Vt7Tl5+7Gtmud6EhEREVHtYwBKRERERJel0GAjk1GHU2UepCabAAQnr4fECjpjTXAHgud6vr33BGYNzkBO9pUocfl4ricRERFRPWILPBERERFddtSt7pvQ+olNGLH6K5wu88QMOivKyduPR4dlYuGorIi29ol928PvluCwu3iuJxEREVE9YwUoEREREV02QpPdRb261R0ADp0uR5pZF1HtmZO3H1unDAQArNx+cQr8XT3bwiAKmGnrFFHpGd7W7vcz6CQiIiKqTwxAiYiIiKjJC7W7m41alLglWI06Vas7ELut/cCpMgxd9RXeHn895o9Un9/pvBB0+lwS29qJiIiIGigGoERERETUpIXa3XO3HMaKgqNol2rExxP6RgwvAi5We4YPMApVe3ZJN8PpcEErIyLoDLa1M/gkIiIiaogYgBIRERFRkyZUaHfXigJaxJjgfuBUGW5d9zXyJ/dHTnYXTmsnIiIiagI4BImIiIiImhxBEKDRiBBFAWajVtXuXtlgIwC4qWtL+KQAHHZnxAAjIiIiImp8WAFKRERERE1G+FmfdpeENJMO512+iErPWIONptsyMGd4JlxlHra1ExERETURDECJiIiIqEmoeNan3SUhM92MfbOHRbS7hwYbLb3lKhSPzEKJW4LFqIPTLbHVnYiIiKiJYQs8ERERETVqSrt72FmfobDzyFknNn1/GtNsnSLed+BUGXYdt8PtkdAi2QBXGVvdiYiIiJqiRhuAfvjhhxg3bhx69OiBfv364Te/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IiIiIiIiIqLHhR2gpFVVVdVAeQXKFQp0NmyHwsJSKCr5SDYRERERERERET0Z/zxInqgRlCPWOZUmERERERERERE9SewAJSIiIiIiIiIiomaLHaBERERERERERETUbLEDlIiIiIiIiIiIiJotdoASERERERERERFRs8UOUCIiIiIiIiIiImq22AFKREREREREREREzZaOIAjCk96JZ5UgCKiubr6nv2XLFqiqqn7Su0H/I5gXUhezQppgXkhdzAppgnkhdTErpAnmhdTFrPxXixY60NHR+cdy7AAlIiIiIiIiIiKiZotD4ImIiIiIiIiIiKjZYgcoERERERERERERNVvsACUiIiIiIiIiIqJmix2gRERERERERERE1GyxA5SIiIiIiIiIiIiaLXaAEhERERERERERUbPFDlAiIiIiIiIiIiJqttgBSkRERERERERERM0WO0CJiIiIiIiIiIio2WIHKBERERERERERETVb7AAlIiIiIiIiIiKiZosdoERERERERERERNRssQP0GXL9+nUsWbIEY8eOhbm5OcaMGaNSpqKiAuvXr4ejoyP69euHt99+G2lpaSrlZDKZyp/BgwerlPv111/h5uYGS0tLDB06FJs3b0ZVVZVKOblcjs8//xxvvvkm+vbtC3t7e8ycORPp6ekqZVNTUxEcHIwRI0ZAJpNh+fLljTwjVB9tZgUAsrKyMGvWLNja2sLKygqurq5ITU0V1584caLOTH3wwQcq21I3K1VVVQgPD4eHhwfs7e1hZ2cHT09PnDp16hHPDtWmrbzs27evzhzIZDJMnz5do/qUioqKEBoaihEjRsDS0hKvvvoqgoODkZOTo1I2NDQUo0ePhrW1NQYMGIDx48cjMTHxEc4M1dbUWfH09Ky3XO2frSZZqengwYOQyWQN5pAaR5ufRbm5uQgKCoKjoyOsra0xfvx4/Pjjj/XWXVpaCicnJ8hkMvz+++8q6zXJS1JSEgICAsTtRUREaHgm6J9oMyv5+fkIDAzEwIEDYW1tDX9/f9y8ebPOcgEBAbC2toadnR0WLlyIkpISlXJstzx9nkReAODQoUOYOHEirKysYGtrC09PT+Tl5UnKVFVVITo6Gm5ubujfvz9sbGzg7e2No0ePqmzv+++/h7u7O+zs7NC3b1+MHDkS27ZtQ0VFRSPPDNX2ww8/YObMmXBycoKVlRXG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I0dw+/Zt6Orqonv37nB1dcXkyZP5shstGT58OHJzc+tc98svv6B79+4AgO+++w7h4eG4ffs2TExMEBQUJD75q3T//n2sWbMGP//8MxQKBRwdHbFo0SLJk4Iymazefan9PTcvLw/btm3D4cOHUVBQgOrqahgbGyM8PBz/+te/GjwuT09P6OnpISwsrMFypL6mzkpqairWrVuH69evQ1dXF3Z2dggODla5SQ+wzVITO0DpqXTy5ElMnToVM2fOxKxZs5707tBTjFkhTSQkJGDu3LlYu3Ytp9agBjErpAnmhdTFdgtpIisrC+7u7hg1ahRWrVr1pHeHnmJhYWHYsmULwsPDVR4gIqrpWW6zcA5QeirZ2tpiwYIF2Lx5M/bv3/+kd4eeYswKaWLMmDGYOnUqFi1aJJlbh6g2ZoU0wbyQuthuIU306tUL69evR2xsLD7//PMnvTv0FPPz88Nrr72GgIAAyRQaRLU9y20WPgFKREREREREREREzRafACUiIiIiIiIiIqJmix2gRERERERERERE1GyxA5SIiIiIiIiIiIiaLXaAEhERERERERERUbPFDlAiIiIiIiIiIiJqttgBSkRERERERERERM0WO0CJiIiIiIiIiIio2WIHKBERERERERERETVb7AAlIiIiIiIiIiKiZosdoERERERERERERNRs/T9UjveaATJiZgAAAABJRU5ErkJggg==", + "text/plain": [ + "<Figure size 1600x400 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "forecaster = ThetaForecaster()\n", + "forecaster.fit(y_train)\n", + "y_pred = forecaster.predict(fh=fh_abs)\n", + "plot_series(y_train, y_test, y_pred, labels=[\"y_train\", \"y_test\", \"y_pred\"]);" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "80e7ce1d", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "80e7ce1d", + "outputId": "b392187a-6656-448f-a567-e9b71d33beed" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0.06012960019008075" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#MdAPE function\n", + "median_absolute_percentage_error(y_test, y_pred)" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "73ab70a0", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "73ab70a0", + "outputId": "cb44e270-14d8-46f5-f72b-4405cc7f905c", + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0.06012960019008075" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#MdAPE class\n", + "mdape = MedianAbsolutePercentageError()\n", + "mdape(y_true=y_test, y_pred=y_pred)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "64b12088-669f-44f6-9b16-9d75954e2054", + "metadata": { + "id": "64b12088-669f-44f6-9b16-9d75954e2054" + }, + "outputs": [], + "source": [ + "def custom_mape(y_true: np.array, y_pred: np.array, multioutput: str):\n", + " metrics_dict = {'uniform_average': np.mean(np.abs((y_true - np.ceil(y_pred)) / y_true)),\n", + " 'raw_values': np.abs((y_true - np.ceil(y_pred)) / y_true)}\n", + " try:\n", + " return metrics_dict[multioutput]\n", + " except KeyError:\n", + " print(\"multioutput not specified correctly - pick `raw_values` or `uniform_average`\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "51724bfe", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "51724bfe", + "outputId": "c4df6ca0-e400-4be1-a20a-14b7a140109d", + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0.05751249071487726" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mape_changed = make_forecasting_scorer(func=custom_mape, multioutput = 'uniform_average')\n", + "mape_changed(y_test, y_pred)" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "8108bc34", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "8108bc34", + "outputId": "919734a2-4414-4775-eef0-22b03d64a066" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0.00102004, 0.00391758, 0.002054 , 0.00402024, 0.00977161,\n", + " 0.02408462, 0.03079155, 0.03550762, 0.04034922, 0.04539615,\n", + " 0.05159286, 0.0590479 , 0.06113469, 0.0663205 , 0.06915992,\n", + " 0.07935452, 0.08080733, 0.07912407, 0.08396799, 0.08487858,\n", + " 0.09019835, 0.09639655, 0.09933719, 0.0958987 , 0.09729706,\n", + " 0.08935353, 0.07486882, 0.05743802, 0.05383124, 0.05845428])" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mape_changed = make_forecasting_scorer(func=custom_mape, multioutput = 'raw_values')\n", + "mape_changed(y_test, y_pred)" + ] + }, + { + "cell_type": "markdown", + "id": "3114fb2a", + "metadata": { + "id": "3114fb2a" + }, + "source": [ + "### Time-based cross-validation" + ] + }, + { + "cell_type": "markdown", + "id": "2e5ed2da", + "metadata": { + "id": "2e5ed2da" + }, + "source": [ + "- **Expanding Window**" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "a05ce4c6", + "metadata": { + "id": "a05ce4c6" + }, + "outputs": [], + "source": [ + "forecaster = AutoARIMA(sp=4)\n", + "cv = ExpandingWindowSplitter(step_length=30, fh=list(range(1,31)), initial_window=40)\n", + "cv_df = evaluate(forecaster=forecaster, y=y, cv=cv, strategy=\"update\", return_data=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "02aae2ca", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 307 + }, + "id": "02aae2ca", + "outputId": "85ea11c2-7b68-4daf-e5b2-dc5d86e2634a", + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " <div id=\"df-820beac7-72a3-4b11-b33b-7b9555a3f8fd\" class=\"colab-df-container\">\n", + " <div>\n", + "<style scoped>\n", + " .dataframe tbody tr th:only-of-type {\n", + " vertical-align: middle;\n", + " }\n", + "\n", + " .dataframe tbody tr th {\n", + " vertical-align: top;\n", + " }\n", + "\n", + " .dataframe thead th {\n", + " text-align: right;\n", + " }\n", + "</style>\n", + "<table border=\"1\" class=\"dataframe\">\n", + " <thead>\n", + " <tr style=\"text-align: right;\">\n", + " <th></th>\n", + " <th>test_MeanAbsolutePercentageError</th>\n", + " <th>fit_time</th>\n", + " <th>pred_time</th>\n", + " <th>len_train_window</th>\n", + " <th>cutoff</th>\n", + " <th>y_train</th>\n", + " <th>y_test</th>\n", + " <th>y_pred</th>\n", + " </tr>\n", + " </thead>\n", + " <tbody>\n", + " <tr>\n", + " <th>0</th>\n", + " <td>0.027279</td>\n", + " <td>2.230224</td>\n", + " <td>0.024685</td>\n", + " <td>40</td>\n", + " <td>1968Q4</td>\n", + " <td>date\n", + "1959Q1 2710.349\n", + "1959Q2 2778.801\n", + "195...</td>\n", + " <td>date\n", + "1969Q1 4244.100\n", + "1969Q2 4256.460\n", + "196...</td>\n", + " <td>1969Q1 4211.384583\n", + "1969Q2 4248.007673\n", + "19...</td>\n", + " </tr>\n", + " <tr>\n", + " <th>1</th>\n", + " <td>0.022458</td>\n", + " <td>4.483943</td>\n", + " <td>0.045663</td>\n", + " <td>70</td>\n", + " <td>1976Q2</td>\n", + " <td>date\n", + "1959Q1 2710.349\n", + "1959Q2 2778.801\n", + "195...</td>\n", + " <td>date\n", + "1976Q3 5154.072\n", + "1976Q4 5191.499\n", + "197...</td>\n", + " <td>1976Q3 5183.195992\n", + "1976Q4 5222.693348\n", + "19...</td>\n", + " </tr>\n", + " <tr>\n", + " <th>2</th>\n", + " <td>0.059587</td>\n", + " <td>3.957826</td>\n", + " <td>0.027062</td>\n", + " <td>100</td>\n", + " <td>1983Q4</td>\n", + " <td>date\n", + "1959Q1 2710.349\n", + "1959Q2 2778.801\n", + "195...</td>\n", + " <td>date\n", + "1984Q1 6448.264\n", + "1984Q2 6559.594\n", + "198...</td>\n", + " <td>1984Q1 6385.598862\n", + "1984Q2 6428.366855\n", + "19...</td>\n", + " </tr>\n", + " <tr>\n", + " <th>3</th>\n", + " <td>0.049360</td>\n", + " <td>2.459181</td>\n", + " <td>0.020844</td>\n", + " <td>130</td>\n", + " <td>1991Q2</td>\n", + " <td>date\n", + "1959Q1 2710.349\n", + "1959Q2 2778.801\n", + "195...</td>\n", + " <td>date\n", + "1991Q3 8037.538\n", + "1991Q4 8069.046\n", + "1...</td>\n", + " <td>1991Q3 8048.706257\n", + "1991Q4 8090.890623\n", + "19...</td>\n", + " </tr>\n", + " <tr>\n", + " <th>4</th>\n", + " <td>0.009310</td>\n", + " <td>9.126039</td>\n", + " <td>0.040927</td>\n", + " <td>160</td>\n", + " <td>1998Q4</td>\n", + " <td>date\n", + "1959Q1 2710.349\n", + "1959Q2 2778.801\n", + "1...</td>\n", + " <td>date\n", + "1999Q1 10601.179\n", + "1999Q2 10684.049\n", + "1...</td>\n", + " <td>1999Q1 10623.174768\n", + "1999Q2 10727.402350\n", + "...</td>\n", + " </tr>\n", + " </tbody>\n", + "</table>\n", + "</div>\n", + " <div class=\"colab-df-buttons\">\n", + "\n", + " <div class=\"colab-df-container\">\n", + " <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-820beac7-72a3-4b11-b33b-7b9555a3f8fd')\"\n", + " title=\"Convert this dataframe to an interactive table.\"\n", + " style=\"display:none;\">\n", + "\n", + " <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n", + " <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n", + " </svg>\n", + " </button>\n", + "\n", + " <style>\n", + " .colab-df-container {\n", + " display:flex;\n", + " gap: 12px;\n", + " }\n", + "\n", + " .colab-df-convert {\n", + " background-color: #E8F0FE;\n", + " border: none;\n", + " border-radius: 50%;\n", + " cursor: pointer;\n", + " display: none;\n", + " fill: #1967D2;\n", + " height: 32px;\n", + " padding: 0 0 0 0;\n", + " width: 32px;\n", + " }\n", + "\n", + " .colab-df-convert:hover {\n", + " background-color: #E2EBFA;\n", + " box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n", + " fill: #174EA6;\n", + " }\n", + "\n", + " .colab-df-buttons div {\n", + " margin-bottom: 4px;\n", + " }\n", + "\n", + " [theme=dark] .colab-df-convert {\n", + " background-color: #3B4455;\n", + " fill: #D2E3FC;\n", + " }\n", + "\n", + " [theme=dark] .colab-df-convert:hover {\n", + " background-color: #434B5C;\n", + " box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n", + " filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n", + " fill: #FFFFFF;\n", + " }\n", + " </style>\n", + "\n", + " <script>\n", + " const buttonEl =\n", + " document.querySelector('#df-820beac7-72a3-4b11-b33b-7b9555a3f8fd button.colab-df-convert');\n", + " buttonEl.style.display =\n", + " google.colab.kernel.accessAllowed ? 'block' : 'none';\n", + "\n", + " async function convertToInteractive(key) {\n", + " const element = document.querySelector('#df-820beac7-72a3-4b11-b33b-7b9555a3f8fd');\n", + " const dataTable =\n", + " await google.colab.kernel.invokeFunction('convertToInteractive',\n", + " [key], {});\n", + " if (!dataTable) return;\n", + "\n", + " const docLinkHtml = 'Like what you see? Visit the ' +\n", + " '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n", + " + ' to learn more about interactive tables.';\n", + " element.innerHTML = '';\n", + " dataTable['output_type'] = 'display_data';\n", + " await google.colab.output.renderOutput(dataTable, element);\n", + " const docLink = document.createElement('div');\n", + " docLink.innerHTML = docLinkHtml;\n", + " element.appendChild(docLink);\n", + " }\n", + " </script>\n", + " </div>\n", + "\n", + "\n", + "<div id=\"df-c6f18150-71a1-4246-8b2d-0a9136c354d4\">\n", + " <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-c6f18150-71a1-4246-8b2d-0a9136c354d4')\"\n", + " title=\"Suggest charts\"\n", + " style=\"display:none;\">\n", + "\n", + "<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n", + " width=\"24px\">\n", + " <g>\n", + " <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n", + " </g>\n", + "</svg>\n", + " </button>\n", + "\n", + "<style>\n", + " .colab-df-quickchart {\n", + " --bg-color: #E8F0FE;\n", + " --fill-color: #1967D2;\n", + " --hover-bg-color: #E2EBFA;\n", + " --hover-fill-color: #174EA6;\n", + " --disabled-fill-color: #AAA;\n", + " --disabled-bg-color: #DDD;\n", + " }\n", + "\n", + " [theme=dark] .colab-df-quickchart {\n", + " --bg-color: #3B4455;\n", + " --fill-color: #D2E3FC;\n", + " --hover-bg-color: #434B5C;\n", + " --hover-fill-color: #FFFFFF;\n", + " --disabled-bg-color: #3B4455;\n", + " --disabled-fill-color: #666;\n", + " }\n", + "\n", + " .colab-df-quickchart {\n", + " background-color: var(--bg-color);\n", + " border: none;\n", + " border-radius: 50%;\n", + " cursor: pointer;\n", + " display: none;\n", + " fill: var(--fill-color);\n", + " height: 32px;\n", + " padding: 0;\n", + " width: 32px;\n", + " }\n", + "\n", + " .colab-df-quickchart:hover {\n", + " background-color: var(--hover-bg-color);\n", + " box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n", + " fill: var(--button-hover-fill-color);\n", + " }\n", + "\n", + " .colab-df-quickchart-complete:disabled,\n", + " .colab-df-quickchart-complete:disabled:hover {\n", + " background-color: var(--disabled-bg-color);\n", + " fill: var(--disabled-fill-color);\n", + " box-shadow: none;\n", + " }\n", + "\n", + " .colab-df-spinner {\n", + " border: 2px solid var(--fill-color);\n", + " border-color: transparent;\n", + " border-bottom-color: var(--fill-color);\n", + " animation:\n", + " spin 1s steps(1) infinite;\n", + " }\n", + "\n", + " @keyframes spin {\n", + " 0% {\n", + " border-color: transparent;\n", + " border-bottom-color: var(--fill-color);\n", + " border-left-color: var(--fill-color);\n", + " }\n", + " 20% {\n", + " border-color: transparent;\n", + " border-left-color: var(--fill-color);\n", + " border-top-color: var(--fill-color);\n", + " }\n", + " 30% {\n", + " border-color: transparent;\n", + " border-left-color: var(--fill-color);\n", + " border-top-color: var(--fill-color);\n", + " border-right-color: var(--fill-color);\n", + " }\n", + " 40% {\n", + " border-color: transparent;\n", + " border-right-color: var(--fill-color);\n", + " border-top-color: var(--fill-color);\n", + " }\n", + " 60% {\n", + " border-color: transparent;\n", + " border-right-color: var(--fill-color);\n", + " }\n", + " 80% {\n", + " border-color: transparent;\n", + " border-right-color: var(--fill-color);\n", + " border-bottom-color: var(--fill-color);\n", + " }\n", + " 90% {\n", + " border-color: transparent;\n", + " border-bottom-color: var(--fill-color);\n", + " }\n", + " }\n", + "</style>\n", + "\n", + " <script>\n", + " async function quickchart(key) {\n", + " const quickchartButtonEl =\n", + " document.querySelector('#' + key + ' button');\n", + " quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n", + " quickchartButtonEl.classList.add('colab-df-spinner');\n", + " try {\n", + " const charts = await google.colab.kernel.invokeFunction(\n", + " 'suggestCharts', [key], {});\n", + " } catch (error) {\n", + " console.error('Error during call to suggestCharts:', error);\n", + " }\n", + " quickchartButtonEl.classList.remove('colab-df-spinner');\n", + " quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n", + " }\n", + " (() => {\n", + " let quickchartButtonEl =\n", + " document.querySelector('#df-c6f18150-71a1-4246-8b2d-0a9136c354d4 button');\n", + " quickchartButtonEl.style.display =\n", + " google.colab.kernel.accessAllowed ? 'block' : 'none';\n", + " })();\n", + " </script>\n", + "</div>\n", + " </div>\n", + " </div>\n" + ], + "text/plain": [ + " test_MeanAbsolutePercentageError fit_time pred_time len_train_window \\\n", + "0 0.027279 2.230224 0.024685 40 \n", + "1 0.022458 4.483943 0.045663 70 \n", + "2 0.059587 3.957826 0.027062 100 \n", + "3 0.049360 2.459181 0.020844 130 \n", + "4 0.009310 9.126039 0.040927 160 \n", + "\n", + " cutoff y_train \\\n", + "0 1968Q4 date\n", + "1959Q1 2710.349\n", + "1959Q2 2778.801\n", + "195... \n", + "1 1976Q2 date\n", + "1959Q1 2710.349\n", + "1959Q2 2778.801\n", + "195... \n", + "2 1983Q4 date\n", + "1959Q1 2710.349\n", + "1959Q2 2778.801\n", + "195... \n", + "3 1991Q2 date\n", + "1959Q1 2710.349\n", + "1959Q2 2778.801\n", + "195... \n", + "4 1998Q4 date\n", + "1959Q1 2710.349\n", + "1959Q2 2778.801\n", + "1... \n", + "\n", + " y_test \\\n", + "0 date\n", + "1969Q1 4244.100\n", + "1969Q2 4256.460\n", + "196... \n", + "1 date\n", + "1976Q3 5154.072\n", + "1976Q4 5191.499\n", + "197... \n", + "2 date\n", + "1984Q1 6448.264\n", + "1984Q2 6559.594\n", + "198... \n", + "3 date\n", + "1991Q3 8037.538\n", + "1991Q4 8069.046\n", + "1... \n", + "4 date\n", + "1999Q1 10601.179\n", + "1999Q2 10684.049\n", + "1... \n", + "\n", + " y_pred \n", + "0 1969Q1 4211.384583\n", + "1969Q2 4248.007673\n", + "19... \n", + "1 1976Q3 5183.195992\n", + "1976Q4 5222.693348\n", + "19... \n", + "2 1984Q1 6385.598862\n", + "1984Q2 6428.366855\n", + "19... \n", + "3 1991Q3 8048.706257\n", + "1991Q4 8090.890623\n", + "19... \n", + "4 1999Q1 10623.174768\n", + "1999Q2 10727.402350\n", + "... " + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cv_df" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "9447bd22", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 385 + }, + "id": "9447bd22", + "outputId": "d6cdb1bb-cc22-46de-cafb-edc55b24bcef", + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Average MAPE with Expanding Window: 0.034\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABUAAAAF6CAYAAADYqPLjAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAADotklEQVR4nOzdeVhU5dsH8O+ZDYYd3DdkERDNfUkFTQU0zXJpNXNJM8tcy1LKbFfbS20xtc0lrZ+95ZaKe6BZbplbLoCSiqhsA7PPnPcPnJHDDDKDKIvfz3VxGec855xnhgfMm/u5b0EURRFERERERERERERENZCssidAREREREREREREdKswAEpEREREREREREQ1FgOgREREREREREREVGMxAEpEREREREREREQ1FgOgREREREREREREVGMxAEpEREREREREREQ1FgOgREREREREREREVGMxAEpEREREREREREQ1FgOgREREREREREREVGMxAEpERERUhf3888+IiorCf//9Zz82fPhwDB8+vMxr9+7di6ioKOzdu7dC5xQVFYX58+dX6D1vpd69e2PGjBkujx03btwtnlH1VnL9/ffff4iKisLPP/9cibMqn1sx9+r8fhAREdVUDIASERFRlXHu3DnMmjULcXFxaNWqFdq3b4/HHnsM3333HfR6fWVP746yc+fOahXkdMfp06cxf/58SVC5okRFRZX6MWvWrAp/3p3s8OHDiIqKwrfffutw7tlnn0VUVBRWr17tcG7YsGHo3r37bZghERERVRWKyp4AEREREQDs2LEDkydPhkqlwsCBAxEZGQmTyYT9+/fj/fffx+nTp/HWW29V9jSrhCVLltzyZ+zcuRPLly/HxIkTHc4dPnwYcrn8ls+homzcuBGCINg/P336NBYsWIDOnTujcePGFf68mJgYDBw40OF4aGhohT+rKmjUqBEOHz4MheL2/tOiRYsWUKvV2L9/P0aNGiU5d/DgQSgUChw4cAAPPvig/bjRaMQ///yDXr16Aai8uRMREdHtxb/piYiIqNJlZGRg6tSpaNiwIb777jvUrVvXfm7YsGE4e/YsduzYUer1VqsVJpMJHh4et2G2lU+lUlXq86vb+3y736+QkBCnAdCaShCESlkTCoUCrVu3xoEDByTHU1NTkZOTgwEDBmD//v2Sc0ePHoXBYECHDh0AVN7ciYiI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z5/Hxo0bYbFY0KlTpxvex50GU7fSDz/8gJSUFEydOhVGoxGzZs1yOu7s2bMOX1tb+YZGjRoBKCqzcPfdd2P27Nm47777EBsbi27dupWZVVsaW4Zoyc7wJpNJsg38ZjVs2BCXL1+GTqeTHD937pzL9yjeCOnAgQOSLe716tVDo0aN7MHR6Ohoh2zT8mrUqBEuX77skL1e8nvB9l6W9j0SGBgILy8vAEW/QGndujX27duHffv22dd4hw4dYDQasWbNGly5cqXMNU5ERERSDIASERFRpXvqqafg5eWFmTNn4sqVKw7nz507h+++++6G95DL5YiJicHWrVslAZorV65g3bp16NChg327fU5OjuRab29vBAcHw2g0AgB0Oh0MBoNkTHBwMLy9ve1jmjVrhm7dutk/7rrrLvvYbt26ISAgABs2bMBvv/2G1q1bS4KbpWWXlfUaS9OjRw9kZWVh48aN9mM6nQ4//vijZJwt6694ME0URXz//fcO97QFicoKoLnzvleEDh064I8//sDhw4ftga/o6Gh4e3vjq6++gqenJ1q2bHnDe9hem7ulBipSRkaGvQv8M888g+nTp2Pbtm345ZdfHMZmZWUhKSnJ/nlBQQF++eUXREdH20syyOVyhyDpb7/9hkuXLpVrfnfddReCgoKwcuVK+5oHgP/7v/8rd1DVmdjYWJhMJslatVqtWL58ucv3qFevHho3bow//vgDR44cQbt27STn27Vrh61btyItLa1CMyd79OgBs9mMH374wX7MYrFg2bJlknF169ZFdHQ0fvnlF8l7d/LkSaSkpOCee+6RjO/QoQMOHz6MvXv32ucbFBSE8PBwLFq0CAAkNWqJiIiobKwBSkRERJUuODgYH3zwAaZOnYr+/ftj4MCBiIyMhNFoxMGDB7Fx40YMGTKkzPtMmTIFu3fvxuOPP47HH38ccrkcq1atgtFoxIsvvmgfd99996Fz585o2bIlAgIC8M8//2DTpk325iXp6ekYNWoU7r33XjRr1gxyuRxbtmzBlStXcN9995U5D6VSiYSEBKxfvx46nU6SHQoUbfvv1KkTFi9eDJPJhHr16iElJaXcmXWPPPIIli9fjunTp+Po0aOoU6cOfv31V4cyAWFhYQgODsa7776LS5cuwcfHB5s2bXIa0LIFEd9++23ExsZCLpeX+tpdfd8rQseOHbF27VpJ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PT11b/oSSAKeuy8LBpUlXevpenGdniev5eHLI5cxrm0krszsivSZD+HKzK4YE18TxjwLbEbPXZ1ERERERERERHT3MAClUiEIAgL8VUgssJ0c8Bwy+hJIukzeegKjEyKlbebXDVbsPvc3RiXU9Li24Jb0otYWnMpe+PtHJURietc6si3tM7pGY0hcBBxmW5FBJ7eqExERERERERHdW7gFnkqFQiFAb7IV273pGhJU1OCggoFkwQnugLz70rXNXKdVoVPt8rKJ6kVtSS9qra9T2Qtuaef2dSIiIiIiIiKiex8DUCoVTqcInVbt9dmZ83aewffDWrmdp+kpkNRp1RidEIkhcREw5VmQa7RCpRCQY7FBoRA8TlQ33ggq7SbbLdf6PJWdiIiIiIiIiIjuG4LIVOeucTicyMw03O2HUWpUWg3eTU7D7O2n3b62tGcD9GtWDf4apRQymi0OiBCh9VPJgkfB7oCoUiLAX35dtNqLPFNTEAQoFAKcTvGWQWVRa325DSpdKpUCYWGByMoywG7nualUNNYK+YL1Qt5irZAvWC/kLdYK+YL1Qt5irciVKxcIpfLWJ3yyA5RKjWi1Y1LHKAC4ZfdmwY5KV5emrMvS5kCu2cP1ou7bh4nqRa3lVHYiIiIiIiIiorKHASiVGofDCVOeazt5HeSYbQjxV8NothV7diYDSSIiIiIiIiIiul0YgFKpcjicgMkKk92OCrpA6PUG2G1sySYiIiIiIiIiorvj1pvkiUrAtWOdR2kSEREREREREdHdxACUiIiIiIiIiIiIyiwGoERERERERERERFRmMQAlIiIiIiIiIiKiMosBKBEREREREREREZVZDECJiIiIiIiIiIiozGIASkRERERERERERGWWIIqieLcfxL+VKIpwOsvuy69UKuBwOO/2w6D7BOuFvMVaIV+wXshbrBXyBeuFvMVaIV+wXshbrJWbFAoBgiDcch0DUCIiIiIiIiIiIiqzuAWeiIiIiIiIiIiIyiwGoERERERERERERFRmMQAlIiIiIiIiIiKiMosBKBEREREREREREZVZDECJiIiIiIiIiIiozGIASkRERERERERERGUWA1AiIiIiIiIiIiIqsxiAEhERERERERERUZnFAJSIiIiIiIiIiIjKLAagREREREREREREVGYxACUiIiIiIiIiIqIyiwEoERERERERERER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", + "text/plain": [ + "<Figure size 1600x400 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_series(\n", + " y, *[cv_df[\"y_pred\"].iloc[x] for x in range(5)],\n", + " markers=[\"o\", *[\".\"]*5],\n", + " labels=[\"y_true\"] + [f\"cv: {x}\" for x in range(5)]\n", + ")\n", + "print(f\"Average MAPE with Expanding Window: {round(cv_df['test_MeanAbsolutePercentageError'].mean(), 3)}\")\n", + "plt.title('Cross-validation with Expanding Window');" + ] + }, + { + "cell_type": "markdown", + "id": "4afb8360", + "metadata": { + "id": "4afb8360" + }, + "source": [ + "- **Sliding Window**" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "5c9ed552", + "metadata": { + "id": "5c9ed552" + }, + "outputs": [], + "source": [ + "forecaster = AutoARIMA(sp=4)\n", + "cv = SlidingWindowSplitter(step_length=30, fh=list(range(1,31)), initial_window=40)\n", + "cv_df = evaluate(forecaster=forecaster, y=y, cv=cv, strategy=\"update\", return_data=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "c4b80504", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 400 + }, + "id": "c4b80504", + "outputId": "4f6137a9-6724-428c-c69e-05b40f9c9c52" + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " <div id=\"df-ab05c56f-8a70-4c11-b119-079e5dbb1d8a\" class=\"colab-df-container\">\n", + " <div>\n", + "<style scoped>\n", + " .dataframe tbody tr th:only-of-type {\n", + " vertical-align: middle;\n", + " }\n", + "\n", + " .dataframe tbody tr th {\n", + " vertical-align: top;\n", + " }\n", + "\n", + " .dataframe thead th {\n", + " text-align: right;\n", + " }\n", + "</style>\n", + "<table border=\"1\" class=\"dataframe\">\n", + " <thead>\n", + " <tr style=\"text-align: right;\">\n", + " <th></th>\n", + " <th>test_MeanAbsolutePercentageError</th>\n", + " <th>fit_time</th>\n", + " <th>pred_time</th>\n", + " <th>len_train_window</th>\n", + " <th>cutoff</th>\n", + " <th>y_train</th>\n", + " <th>y_test</th>\n", + " <th>y_pred</th>\n", + " </tr>\n", + " </thead>\n", + " <tbody>\n", + " <tr>\n", + " <th>0</th>\n", + " <td>0.027279</td>\n", + " <td>2.242027</td>\n", + " <td>0.024409</td>\n", + " <td>40</td>\n", + " <td>1968Q4</td>\n", + " <td>1959Q1 2710.349\n", + "1959Q2 2778.801\n", + "1959Q3 ...</td>\n", + " <td>1969Q1 4244.100\n", + "1969Q2 4256.460\n", + "1969Q3 ...</td>\n", + " <td>1969Q1 4211.384583\n", + "1969Q2 4248.007673\n", + "19...</td>\n", + " </tr>\n", + " <tr>\n", + " <th>1</th>\n", + " <td>0.032508</td>\n", + " <td>3.777926</td>\n", + " <td>0.056402</td>\n", + " <td>10</td>\n", + " <td>1976Q2</td>\n", + " <td>1974Q1 4909.617\n", + "1974Q2 4922.188\n", + "1974Q3 ...</td>\n", + " <td>1976Q3 5154.072\n", + "1976Q4 5191.499\n", + "1977Q1 ...</td>\n", + " <td>1976Q3 5178.306143\n", + "1976Q4 5227.665286\n", + "19...</td>\n", + " </tr>\n", + " <tr>\n", + " <th>2</th>\n", + " <td>0.017365</td>\n", + " <td>2.365881</td>\n", + " <td>0.022176</td>\n", + " <td>10</td>\n", + " <td>1983Q4</td>\n", + " <td>1981Q3 6030.184\n", + "1981Q4 5955.062\n", + "1982Q1 ...</td>\n", + " <td>1984Q1 6448.264\n", + "1984Q2 6559.594\n", + "1984Q3 ...</td>\n", + " <td>1984Q1 6386.849\n", + "1984Q2 6448.124\n", + "1984Q3 ...</td>\n", + " </tr>\n", + " <tr>\n", + " <th>3</th>\n", + " <td>0.011343</td>\n", + " <td>1.619386</td>\n", + " <td>0.020145</td>\n", + " <td>10</td>\n", + " <td>1991Q2</td>\n", + " <td>1989Q1 7806.603\n", + "1989Q2 7865.016\n", + "1989Q3 ...</td>\n", + " <td>1991Q3 8037.538\n", + "1991Q4 8069.046\n", + "1992Q1...</td>\n", + " <td>1991Q3 8080.539\n", + "1991Q4 8157.256\n", + "1992Q1...</td>\n", + " </tr>\n", + " <tr>\n", + " <th>4</th>\n", + " <td>0.052317</td>\n", + " <td>13.451261</td>\n", + " <td>0.017559</td>\n", + " <td>10</td>\n", + " <td>1998Q4</td>\n", + " <td>1996Q3 9488.879\n", + "1996Q4 9592.458\n", + "1997Q1...</td>\n", + " <td>1999Q1 10601.179\n", + "1999Q2 10684.049\n", + "1999Q3...</td>\n", + " <td>1999Q1 10749.487249\n", + "1999Q2 10779.693065\n", + "...</td>\n", + " </tr>\n", + " </tbody>\n", + "</table>\n", + "</div>\n", + " <div class=\"colab-df-buttons\">\n", + "\n", + " <div class=\"colab-df-container\">\n", + " <button class=\"colab-df-convert\" onclick=\"convertToInteractive('df-ab05c56f-8a70-4c11-b119-079e5dbb1d8a')\"\n", + " title=\"Convert this dataframe to an interactive table.\"\n", + " style=\"display:none;\">\n", + "\n", + " <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 -960 960 960\">\n", + " <path d=\"M120-120v-720h720v720H120Zm60-500h600v-160H180v160Zm220 220h160v-160H400v160Zm0 220h160v-160H400v160ZM180-400h160v-160H180v160Zm440 0h160v-160H620v160ZM180-180h160v-160H180v160Zm440 0h160v-160H620v160Z\"/>\n", + " </svg>\n", + " </button>\n", + "\n", + " <style>\n", + " .colab-df-container {\n", + " display:flex;\n", + " gap: 12px;\n", + " }\n", + "\n", + " .colab-df-convert {\n", + " background-color: #E8F0FE;\n", + " border: none;\n", + " border-radius: 50%;\n", + " cursor: pointer;\n", + " display: none;\n", + " fill: #1967D2;\n", + " height: 32px;\n", + " padding: 0 0 0 0;\n", + " width: 32px;\n", + " }\n", + "\n", + " .colab-df-convert:hover {\n", + " background-color: #E2EBFA;\n", + " box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15);\n", + " fill: #174EA6;\n", + " }\n", + "\n", + " .colab-df-buttons div {\n", + " margin-bottom: 4px;\n", + " }\n", + "\n", + " [theme=dark] .colab-df-convert {\n", + " background-color: #3B4455;\n", + " fill: #D2E3FC;\n", + " }\n", + "\n", + " [theme=dark] .colab-df-convert:hover {\n", + " background-color: #434B5C;\n", + " box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);\n", + " filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3));\n", + " fill: #FFFFFF;\n", + " }\n", + " </style>\n", + "\n", + " <script>\n", + " const buttonEl =\n", + " document.querySelector('#df-ab05c56f-8a70-4c11-b119-079e5dbb1d8a button.colab-df-convert');\n", + " buttonEl.style.display =\n", + " google.colab.kernel.accessAllowed ? 'block' : 'none';\n", + "\n", + " async function convertToInteractive(key) {\n", + " const element = document.querySelector('#df-ab05c56f-8a70-4c11-b119-079e5dbb1d8a');\n", + " const dataTable =\n", + " await google.colab.kernel.invokeFunction('convertToInteractive',\n", + " [key], {});\n", + " if (!dataTable) return;\n", + "\n", + " const docLinkHtml = 'Like what you see? Visit the ' +\n", + " '<a target=\"_blank\" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>'\n", + " + ' to learn more about interactive tables.';\n", + " element.innerHTML = '';\n", + " dataTable['output_type'] = 'display_data';\n", + " await google.colab.output.renderOutput(dataTable, element);\n", + " const docLink = document.createElement('div');\n", + " docLink.innerHTML = docLinkHtml;\n", + " element.appendChild(docLink);\n", + " }\n", + " </script>\n", + " </div>\n", + "\n", + "\n", + "<div id=\"df-1ed4b4f8-1a2b-466f-8273-ec61ad86e0c8\">\n", + " <button class=\"colab-df-quickchart\" onclick=\"quickchart('df-1ed4b4f8-1a2b-466f-8273-ec61ad86e0c8')\"\n", + " title=\"Suggest charts\"\n", + " style=\"display:none;\">\n", + "\n", + "<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\"viewBox=\"0 0 24 24\"\n", + " width=\"24px\">\n", + " <g>\n", + " <path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z\"/>\n", + " </g>\n", + "</svg>\n", + " </button>\n", + "\n", + "<style>\n", + " .colab-df-quickchart {\n", + " --bg-color: #E8F0FE;\n", + " --fill-color: #1967D2;\n", + " --hover-bg-color: #E2EBFA;\n", + " --hover-fill-color: #174EA6;\n", + " --disabled-fill-color: #AAA;\n", + " --disabled-bg-color: #DDD;\n", + " }\n", + "\n", + " [theme=dark] .colab-df-quickchart {\n", + " --bg-color: #3B4455;\n", + " --fill-color: #D2E3FC;\n", + " --hover-bg-color: #434B5C;\n", + " --hover-fill-color: #FFFFFF;\n", + " --disabled-bg-color: #3B4455;\n", + " --disabled-fill-color: #666;\n", + " }\n", + "\n", + " .colab-df-quickchart {\n", + " background-color: var(--bg-color);\n", + " border: none;\n", + " border-radius: 50%;\n", + " cursor: pointer;\n", + " display: none;\n", + " fill: var(--fill-color);\n", + " height: 32px;\n", + " padding: 0;\n", + " width: 32px;\n", + " }\n", + "\n", + " .colab-df-quickchart:hover {\n", + " background-color: var(--hover-bg-color);\n", + " box-shadow: 0 1px 2px rgba(60, 64, 67, 0.3), 0 1px 3px 1px rgba(60, 64, 67, 0.15);\n", + " fill: var(--button-hover-fill-color);\n", + " }\n", + "\n", + " .colab-df-quickchart-complete:disabled,\n", + " .colab-df-quickchart-complete:disabled:hover {\n", + " background-color: var(--disabled-bg-color);\n", + " fill: var(--disabled-fill-color);\n", + " box-shadow: none;\n", + " }\n", + "\n", + " .colab-df-spinner {\n", + " border: 2px solid var(--fill-color);\n", + " border-color: transparent;\n", + " border-bottom-color: var(--fill-color);\n", + " animation:\n", + " spin 1s steps(1) infinite;\n", + " }\n", + "\n", + " @keyframes spin {\n", + " 0% {\n", + " border-color: transparent;\n", + " border-bottom-color: var(--fill-color);\n", + " border-left-color: var(--fill-color);\n", + " }\n", + " 20% {\n", + " border-color: transparent;\n", + " border-left-color: var(--fill-color);\n", + " border-top-color: var(--fill-color);\n", + " }\n", + " 30% {\n", + " border-color: transparent;\n", + " border-left-color: var(--fill-color);\n", + " border-top-color: var(--fill-color);\n", + " border-right-color: var(--fill-color);\n", + " }\n", + " 40% {\n", + " border-color: transparent;\n", + " border-right-color: var(--fill-color);\n", + " border-top-color: var(--fill-color);\n", + " }\n", + " 60% {\n", + " border-color: transparent;\n", + " border-right-color: var(--fill-color);\n", + " }\n", + " 80% {\n", + " border-color: transparent;\n", + " border-right-color: var(--fill-color);\n", + " border-bottom-color: var(--fill-color);\n", + " }\n", + " 90% {\n", + " border-color: transparent;\n", + " border-bottom-color: var(--fill-color);\n", + " }\n", + " }\n", + "</style>\n", + "\n", + " <script>\n", + " async function quickchart(key) {\n", + " const quickchartButtonEl =\n", + " document.querySelector('#' + key + ' button');\n", + " quickchartButtonEl.disabled = true; // To prevent multiple clicks.\n", + " quickchartButtonEl.classList.add('colab-df-spinner');\n", + " try {\n", + " const charts = await google.colab.kernel.invokeFunction(\n", + " 'suggestCharts', [key], {});\n", + " } catch (error) {\n", + " console.error('Error during call to suggestCharts:', error);\n", + " }\n", + " quickchartButtonEl.classList.remove('colab-df-spinner');\n", + " quickchartButtonEl.classList.add('colab-df-quickchart-complete');\n", + " }\n", + " (() => {\n", + " let quickchartButtonEl =\n", + " document.querySelector('#df-1ed4b4f8-1a2b-466f-8273-ec61ad86e0c8 button');\n", + " quickchartButtonEl.style.display =\n", + " google.colab.kernel.accessAllowed ? 'block' : 'none';\n", + " })();\n", + " </script>\n", + "</div>\n", + " </div>\n", + " </div>\n" + ], + "text/plain": [ + " test_MeanAbsolutePercentageError fit_time pred_time len_train_window \\\n", + "0 0.027279 2.242027 0.024409 40 \n", + "1 0.032508 3.777926 0.056402 10 \n", + "2 0.017365 2.365881 0.022176 10 \n", + "3 0.011343 1.619386 0.020145 10 \n", + "4 0.052317 13.451261 0.017559 10 \n", + "\n", + " cutoff y_train \\\n", + "0 1968Q4 1959Q1 2710.349\n", + "1959Q2 2778.801\n", + "1959Q3 ... \n", + "1 1976Q2 1974Q1 4909.617\n", + "1974Q2 4922.188\n", + "1974Q3 ... \n", + "2 1983Q4 1981Q3 6030.184\n", + "1981Q4 5955.062\n", + "1982Q1 ... \n", + "3 1991Q2 1989Q1 7806.603\n", + "1989Q2 7865.016\n", + "1989Q3 ... \n", + "4 1998Q4 1996Q3 9488.879\n", + "1996Q4 9592.458\n", + "1997Q1... \n", + "\n", + " y_test \\\n", + "0 1969Q1 4244.100\n", + "1969Q2 4256.460\n", + "1969Q3 ... \n", + "1 1976Q3 5154.072\n", + "1976Q4 5191.499\n", + "1977Q1 ... \n", + "2 1984Q1 6448.264\n", + "1984Q2 6559.594\n", + "1984Q3 ... \n", + "3 1991Q3 8037.538\n", + "1991Q4 8069.046\n", + "1992Q1... \n", + "4 1999Q1 10601.179\n", + "1999Q2 10684.049\n", + "1999Q3... \n", + "\n", + " y_pred \n", + "0 1969Q1 4211.384583\n", + "1969Q2 4248.007673\n", + "19... \n", + "1 1976Q3 5178.306143\n", + "1976Q4 5227.665286\n", + "19... \n", + "2 1984Q1 6386.849\n", + "1984Q2 6448.124\n", + "1984Q3 ... \n", + "3 1991Q3 8080.539\n", + "1991Q4 8157.256\n", + "1992Q1... \n", + "4 1999Q1 10749.487249\n", + "1999Q2 10779.693065\n", + "... " + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cv_df" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "beb1d16e", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 385 + }, + "id": "beb1d16e", + "outputId": "93bac828-f0cd-4e16-87a4-456a00178f38", + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Average MAPE with Sliding Window: 0.028\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABUAAAAF6CAYAAADYqPLjAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAADsVElEQVR4nOzdd3hVVdbH8e+5LbnpVOkQQld6FSKCCSCIBbujFEFkBqU4MgOIw+tYgHEcRcCCEAtiwzJjAZEOA1YEZBCQFopID+k3ue28f8Rcc0kCSQgl+Ps8jw/mnH3O2fdkG2Sx9lqGaZomIiIiIiIiIiIiIpcgy4WegIiIiIiIiIiIiMi5ogCoiIiIiIiIiIiIXLIUABUREREREREREZFLlgKgIiIiIiIiIiIicslSAFREREREREREREQuWQqAioiIiIiIiIiIyCVLAVARERERERERERG5ZCkAKiIiIiIiIiIiIpcsBUBFRERERERERETkkqUAqIiIiMgl6qOPPqJp06b8/PPPgWMDBw5k4MCBZ7z2m2++oWnTpnzzzTflOqemTZsyc+bMcr3nuXTNNdcwYcKEEo8dMWLEOZ4RzJw5k6ZNmxZ6dknmeTZr4mJ0LuZekd+HiIiIFE0BUBEREbkk7N+/n8mTJ5OQkEDLli1p164dd955J2+88QY5OTkXenq/K6tXr65QQc7S2LVrFzNnzgwKIJaXrKwsZsyYQf/+/WnTpg2dO3fmxhtv5Mknn+TIkSPl/rwLrV+/ftxwww2Fji9dupSmTZtyzz33FDr3wQcf0LRpU9auXXs+pigiIiKXCNuFnoCIiIjI2Vq1ahVjxozB4XBw44030qRJEzweD99//z3//Oc/2bVrF0888cSFnuZFISkp6Zw/Y/Xq1bz11luMGjWq0LnNmzdjtVrP+RzKy+LFizEMI/D1rl27mDVrFp06daJOnTrl9hyPx8M999zDnj17uOmmm7jnnnvIzs5m586dfPbZZ/Tq1YvLLrusxPMsjfOxJorSvn17PvjgAzIyMoiMjAwc37BhAzabjf/97394PB7sdnvQOavVSps2bYALN3cRERGpWBQAFRERkQrtwIEDPPTQQ9SqVYs33niD6tWrB87dfffd7Nu3j1WrVhV7vd/vx+PxEBISch5me+E5HI4L+vyK9p7P1/tatmwZW7du5ZlnnuH6668POpebm4vH4znt9Wczzwu1Jtq3b8+CBQvYsGEDV199deD4hg0buPbaa/nss8/48ccfA8FOgO+//56mTZsSEREBXPj1LCIiIhWDtsCLiIhIhTZ37lyys7N56qmngoKf+erXr8/gwYMDXzdt2pTHH3+cTz75hOuuu46WLVvy3//+F4CtW7dy33330a5dO9q2bcvgwYPZtGlT0P08Hg+zZs2id+/etGzZks6dO3PXXXexbt26wJhjx44xceJEunfvzhVXXEF8fDx/+tOfTrttevHixTRt2pRvv/220Ll3332Xpk2bsmPHDgC2b9/OhAkTAtv9u3XrxsSJEzl58uQZ31dR9Q0PHz7MyJEjadOmDVdeeSVTpkzB7XYXunb9+vWMHj2aHj16cMUVV3D11VczZcqUoBIDEyZM4K233gLy3nX+P/mKqgFakveeX7vy+++/Z+rUqXTp0oU2bdrwwAMPkJKSctrPvHz5cpo2bcr27dsDx7744guaNm3Kgw8+GDS2b9++jB07NvB1wdqaH330EWPGjAFg0KBBgc92ap3U9evXc+utt9KyZUsSEhL4z3/+c9r5QV4gH6Bdu3aFzoWEhAQCfsUpqgbozp07GTRoEK1ataJ79+68+OKL+P3+Qteeuiby678uWrSIl156ie7du9OyZUsGDx7Mvn37Cl3/1ltvkZCQQKtWrbj11ltZv359iepotm/fHsgLeObLzc3lxx9/pHfv3tStWzfoXEpKCnv37g1cVx5zf++990hMTAyae1FOnDjBI488QteuXWnZsiU33HAD//73v4PGDBgwoNB6uv766wutvUWLFtG0aVN279592vcjIiIi5UcZoCIiIlKhrVy5krp16xYZOCrO119/zeeff87dd99NpUqVqF27Njt37uTuu+8mPDyc++67D5vNxnvvvcfAgQOZP38+rVu3BmDWrFnMnj2b2267jVatWpGZmcmWLVv48ccf6datGwCjRo1i165d3HPPPdSuXZuUlBTWrVvHoUOHit023aNHD8LCwvj888/p1KlT0LlFixbRuHFjmjRpAsCXX37JgQMHuPnmm6lWrRo7d+5kwYIF7Nq1iwULFpRqK3ROTg6DBw/m0KFDDBw4kOrVq/Pxxx/z9ddfFxq7ePFicnJyuOuuu4iJiWHz5s3Mnz+fw4cPM2PGDADuuOMOjh49yrp163j66afP+PySvvd8Tz75JFFRUTz44IMcPHiQN954g8cff5zp06cX+4z27dtjGAbr16+nWbNmQF6Q0mKx8P333wfGpaSksGfPniJrTwJ07NiRgQMH8uabb/LHP/6Rhg0bAhAXFxcYs2/fPsaMGcOtt97KgAED+PDDD5kwYQKXX345jRs3LnaOtWrVAuA///kPI0eOLPN29nzHjh1j0KBB+Hw+7r//fpxOJwsWLChVBu6cOXMwDIOhQ4eSmZnJ3LlzGTduHO+//35gzNtvv83jjz9Ohw4dGDJkCAcPHuSBBx4gKiqKGjVqnPb+devWpXr16kFBzvxt723btqVt27Zs2LCBoUOHAr8FSkvy33pJ5v7+++8zefLkQND9wIED/OlPfyI6OpqaNWsGxuXk5DBw4ED279/P3XffTZ06dVi8eDETJkwgPT098Bcs7du3Z+HChYHrUlNT2blzZ2CdFVx7lStXDlo3IiIicm4pACoiIiIVVmZmJkeOHCEhIaFU1yUnJ/Ppp5/SqFGjwLEHHngAj8fDO++8Q926dQG46aabuPbaa/nnP//J/Pnzgbx6o1dffXWxNUXT09PZuHEjf/3rXxk2bFjg+Jm6g4eGhnLNNdfwxRdf8OijjwbqZB47dozvvvsuKLPsD3/4QyAolK9Nmzb8+c9/5vvvv6dDhw4lfhfvvfcee/fuZfr06fTt2xeA22+/nRtvvLHQ2HHjxhEaGhr4+o477qB+/fo8++yz/PLLL9SqVYu2bdvSoEED1q1bV+Q9TjV9+vQSvfd8MTExvPrqq4EAod/v58033yxUR/LUaxo1asT69esDwc3vv/+e3r17s3jxYnbv3k1cXFwgGFoww7CgunXr0qFDB9588026du1K586dC41JTk7mrbfeCnwP+vbty9VXX81HH33E+PHji30PiYmJxMbGMmPGDD788EM6d+5M+/bt6dmzJ1WqVDndKyzSnDlzSElJ4f3336dVq1ZAXoZi7969S3yP3Nxc/vOf/wS2mUdFRfHUU0+xY8cOmjRpgtvt5vnnn6dly5a88cYb2Gx5f7Ro2rQpEyZMOGMAFPKCmatWrQrU+tywYQN16tShevXqtG3bllmzZgXGnun7U5q5ezwennvuOZo3b868efMC4xo1asTf/va3oADoe++9x+7du/nnP/8ZaNp05513MnDgQKZPn84tt9xCREREYG3kr6cNGzZgt9uJj49n/fr13H333UBeALQkn0FERETKj7bAi4iISIWVmZkJQHh4eKmu69ixY1Dw0+fzsW7dOhITEwNBOIDq1avTv39/vv/++8CzoqKi2LlzJ3v37i3y3qGhodjtdr799lvS0tJKNa++ffty4sSJoG3wX3zxBX6/n379+gU9I19ubi4pKSmBTMkff/yxVM9cs2YN1apV49prrw0cczqd3H777YXGFnxudnY2KSkptG3bFtM02bp1a6meC6V77/luv/32oOzIDh064PP5OHjw4Gmf1b59+8D25szMTLZv384dd9xBpUqVAoG19evXExUVFci0LYtGjRoFBaArV65MbGxsYIt7cUJDQ3n//fcDQfOPPvqISZMmER8fzxNPPFFkSYLTWb16NW3atAkEP/Pncmp90dO5+eabg2ps5n+u/M+yZcsWUlNTuf322wPBT8jb9h0dHV2iZ7Rv356cnJzAut2wYQNt27YF8oKjJ06cCPy3tnHjRurUqXPaZlClmfuJEye48847g8YNGDCgUCA9/7+R/v37B47Z7XYGDhxIdnY23333XdAz8r9ev359oERF/tpLT09n586dpfpLChERETl7CoCKiIhIhZVfFzErK6tU1526DT0lJQWXy0VsbGyhsXFxcfj9fg4dOgTA6NGjycjIoE+fPlx//fX84x//CKrv53A4GDduHGvWrKFbt27cfffdzJkzh2PHjgXGZGRkcOzYscA/qampAHTv3p3IyEgWLVoUGLto0SKaN28eNLfU1FSefPJJunbtSqtWrbjyyisDWbAZGRmlehcHDx6kfv36hbZcF/UufvnlFyZMmECnTp1o27YtV155ZSCj8tRAZUmU5r3ny98qni8qKgrICyydTocOHTh27Bj79u1j48aNGIZBmzZt6NChQyA4tX79etq1a4fFUvb/RS6YOZgvOjq6RMHwyMhI/vrXv7JixQpWrFjBU089RWxsLPPnz+eFF14o1Tx++eUX6tevX+h4Ue+6OGd617/88gsA9erVCxpns9moXbt2iZ5RsA6oaZps3LgxsMW9SZMmREREsGHDBnJzc9myZUuJMydLOvdT35Hdbg8KxsNv/42cui7yt7Dn36tq1ao0aNAgsJ7ys7E7dOjA0aNHOXDgABs2bMDv9ysDVERE5DxTAFREREQqrIiICKpXr87OnTtLdV3BTMbS6tixI0uXLmXKlCk0btyYDz74gJtvvjmotuCQIUP44osv+POf/0xISAjPP/88/fr1C2RJPvXUU8THxwf+GTVqFJAXPE1MTGTp0qV4vV6OHDnChg0bgrI/AcaOHcv777/PnXfeyaxZs3j11VeZO3cuAKZplvmznY7P5+Pee+9l1apV3Hfffbzwwgu89tprTJs2DaDI5jrnQnHByTN97vyA03fffcf69etp0aIFYWFhgQBoVlYW27ZtO+vAVH7pgrNVu3Ztbr31Vt555x2ioqL49NNPy+W+pVHWd10azZo1Izw8nO+//549e/aQmpoaCIBaLBZat27N999/H6gNWtLvz/mYe1HatWvH999/H8hqbd++PU2aNCEqKor169ezfv16wsLCaNGixTmdh4iIiARTAFREREQqtJ49e7J//342btxY5ntUrlwZp9NJcnJyoXN79uzBYrEEZfbFxMRwyy238Oyzz7Jq1aoiO5vXq1ePoUOH8uqrr/LZZ5/h8Xh49dVXAbjvvvt47bXXAv8UrA3Zt29fTp48yVdffcXnn3+OaZqB2pwAaWlpfPXVVwwfPpzRo0fTq1cvunXrVihrraRq167N/v37CwWGTn0XO3bsYO/evUyYMIH777+fxMREunbtSvXq1Qvds6QNfEr73s9GrVq1qFWrFt9//31QndQOHTpw8OBBFi9ejM/no2PHjqe9z9k2Jyqt6Oho6tatG5RBXBK1atUqsut5Ue+6rPKzLPfv3x903Ov1nrEkQT6r1UqbNm3YsGED33//PREREUElCPIbIeU3QCqvzMn8uZ/6jjweDz///HPQsdq1a7Nv375CQf49e/YE3Qvy1tMvv/zCwoUL8fl8gYzi/BIM+VnG5RUoFxERkZJRAFREREQqtPvuu4+wsDAeffRRjh8/Xuj8/v37eeONN057D6vVSrdu3Vi+fHlQ8OP48eN89tlntG/fPrDd/uTJk0HXhoeHU69evUCNRpfLRW5ubtCYevXqER4eHhjTqFEjunbtGvjniiuuCIzt2rUrMTExLFq0iM8//5xWrVoFBTeLC5yc6TMWp3v37hw9epTFixcHjrlcLhYsWBA0Lj+jrmCg1DRN5s2bV+ieTqcTOPO29NK89/LQvn17vv76azZv3hwIpDVv3pzw8HBeeeUVQkNDufzyy097j/zPVtpSA2eyfft2UlJSCh0/ePAgu3fvLtXWdYCrr76aTZs2sXnz5sCxlJSUcs0kveKKK4iJiWHBggV4vd7A8U8//bRU9W/btWtHSkoKH330Ea1btw7K3mzbti3JycksX76cmJiYcuucfsUVV1C5cmXefffdoPqq//73vwut2+7du3Ps2LGg0hRer5c333yTsLCwoKB5fmB9zpw5NG3aNFBPtH379nz11Vel2sYvIiIi5Udd4EVERKRCq1evHs888wwPPfQQ/fr148Ybbwx0qN64cSOLFy/m5ptvPuN9xo4dy5dffskf/vAH/vCHP2C1Wnnvvfdwu9385S9/CYy77rrr6NSpE5dffjkxMTH873//44svvgjUwty7dy9Dhgzh2muvpVGjRlitVpYtW8bx48e57rrrzjgPu91Or169WLhwIS6Xq1Dn8IiICDp27MjcuXPxeDxcdtllrFu3rlDWWkndfvvtvPXWW4wfP54ff/yRatWq8fHHHxcqE9CwYUPq1avHP/7xD44cOUJERARffPFFkUHO/CDik08+SXx8PFartdjPXtL3Xh46dOjAp59+imEYgSCU1Wqlbdu2rF27lk6dOgU1xClK8+bNsVqtzJkzh4yMDBwOB126dClTp/aC1q1bx8yZM7nmmmto3bo1YWFh/Pzzz3z44Ye43e5AmYSSuu+++/j444+57777GDRoEE6nkwULFlCrVi1++umns5prPofDwahRo3jiiScYPHgwffv25eDBg3z00UeF6oKeTv73YuPGjYU+Z5s2bTAMg02bNtGzZ89yy8C12+2MHTuWyZMnM3jwYPr168fPP//MRx99VCib+o477uC9995jwoQJ/Pjjj9SuXZsvvviCDRs28MgjjwQF6evXr0+1atVITk5m4MCBgeMdO3bkmWeeAVADJBERkQtAAVARERGp8BISEvjkk09ISkpi+fLlvPPOOzgcDpo2bcqECROK7Gh+qsaNG/PWW2/xr3/9i9mzZ2OaJq1ateKf//xnoMM6wMCBA1mxYgXr1q3D7XZTq1Ytxo4dG+jeXaNGDa677jq++uorPvnkE6xWKw0bNmT69On06dOnRJ+nX79+vP/++xiGEbT9Pd+//vUvnnjiCd5++21M06Rbt27MmTOHq666qoRv7DdOp5PXX3+dJ554gvnz5xMaGsr1119P9+7due+++wLj7HY7L7/8Mk8++SSzZ88mJCSEXr16cffdd3PjjTcG3bN3794M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w2xDXrYJKpsdedkm2E1WOBzOq0Gn87pT6ImIiIiIiIiIqPQxAKVSIQgCdIEqzN95WnbcW8joT3jpMm7DUQxPipXCxysGK7al/IvkpGqy81wBpvvxoq5bVNg5bsNRJCfF4vWONWVBp/v+nRcnd0T65E64OLkjXk6sBtPVtnaGnUREREREREREtxe2wFOpUCgEZJtsPg0JKqqd3D28dN8vFPDeZq7XqtCuRhQEXNt7U69V41y2Ca+1qykddw9LC1/X36ns19u/k4iIiIiIiIiIbi8MQKlUOJ0i9Fq1z0OCZmw5iR8HN5cd8xZeuo4PT4rFgKYxMOVbkGe0QqUQkGuxQaEQ8HKi50R1i8EiO15UWFqiqezg/p1ERERERERERHcKQWT52i3jcDiRmWm41Q+j1Ki0Gry/6zSmbjrhcdu8bnXRq1FlBGqUUshotjggQoQ2QCULHgW7A6JKCV2g/LhotcPhcHq9b0EQoFAIcDpFWVDpflyhECBoVEVet6hr0I2nUikQHh6ErCwD7Hbvf8ZEANcK+YfrhXzFtUL+4HohX3GtkD+4XshXXCtyERFBUCqvv8MnK0Cp1IhWO8a2jQOA61ZvuldUem0ntzmQZ/a9zbyoikz34w6HCJisRV6XVZ1ERERERERERGUPA1AqNQ6HE6Z8V+t5TeSabQgNVMNotklDggrOk4eMvoSXpYlBJxERERERERHR3YMBKJUqh8MJmKww2e2I1gchO9sAu40l2UREREREREREdGtcv0meqARcneXcSpOIiIiIiIiIiG4lBqBERERERERERERUZjEAJSIiIiIiIiIiojKLASgRERERERERERGVWQxAiYiIiIiIiIiIqMxiAEpERERERERERERlFgNQIiIiIiIiIiIiKrMEURTFW/0g7laiKMLpLLsvv1KpgMPhvNUPg+4QXC/kK64V8gfXC/mKa4X8wfVCvuJaIX9wvZCvuFauUSgECIJw3fMYgBIREREREREREVGZxRZ4IiIiIiIiIiIiKrMYgBIREREREREREVGZxQCUiIiIiIiIiIiIyiwGoERERERERERERFRmMQAlIiIiIiIiIiKiMosBKBEREREREREREZVZDECJiIiIiIiIiIiozGIASkRERERERERERGUWA1AiIiIiIiIiIiIqsxiAEhERERERERERUZnFAJSIiIiIiIiIiIjKLAagREREREREREREVGYxACUiIiIiIiIiIqIyiwHoXeTMmTOYNGkSHnvsMdSuXRsPP/ywxzlWqxVvv/02kpKScN999+HJJ5/Enj17PM5LSEjw+C8xMdHjvK1bt6J79+6oW7cuHnjgAcybNw8Oh8PjPLPZjA8//BBdu3ZFvXr10KxZM7z44os4fPiwx7m7du3C6NGj0aFDByQkJGDq1KklfEWoKKW5VgAgJSUFw4YNQ5MmTdCgQQN069YNu3btkm7fu3ev1zU1cuRIj2v5ulYcDgeWLFmC5557Ds2aNUPTpk3Rq1cv7Nu37z++OlRYaa2X1atXe10HCQkJGDBggF/355KTk4NZs2ahQ4cOqFu3Llq2bInRo0cjLS3N49xZs2bhoYceQsOGDdGoUSM88cQTWL9+/X94Zaiwm71WevXqVeR5hf9s/Vkr7jZv3oyEhIRi1yGVTGl+Lzp//jxGjRqFpKQkNGzYEE888QR+/PHHIu/bYDCgdevWSEhIwJ9//ulxuz/rZcOGDUhOTpaut2zZMj9fCbqe0lwrly5dwogRI3D//fejYcOGeOGFF3Du3Dmv5yUnJ6Nhw4Zo2rQpJkyYgPz8fI/z+Lnl9nMr1gsAbNu2DT179kSDBg3QpEkT9OrVC+np6bJzHA4HPvvsM3Tv3h3169dH48aN0bdvX+zcudPjet999x169OiBpk2bol69eujcuTM++OADWK3WEr4yVNgPP/yAF198Ea1bt0aDBg3w2GOPYdWqVRBFUXbeN998g86dO6NevXp49NFHsXXrVo9r5eXlYfz48WjatCkaNmyI4cOH4/Lly7JzvvzyS/Tv3x+JiYlo1KgRevTogc2bN3t9bJcuXcKkSZPwwAMPSP/WnjRpEi5dulTsc/rkk0+QkJCAIUOG+PlqUHFu9loBgG+//RZdunRB3bp10bFjR3z66adeHxs/s1yjutUPgG6ekydPYvv27ahfvz6cTqfHX0YAeOutt7BmzRqMGDECsbGxWL16NQYNGoSvvvoKderUkZ3bq1cv2QcGtVotu/3gwYMYOnQoHnroIYwaNQqnTp3C3LlzYTKZMHbsWOk8o9GIvn374uTJkxg4cCAaN26M7OxsfPbZZ3j22WcxZ84cdOzYUTr/l19+wbFjx9CkSRPk5OSU1stDbkpzrZw8eRLPPPMMkpKS8Pbbb0OtVuPIkSMwmUwe15wxYwaqV68u/T48PFx2uz9rxWw2Y/HixejevTsGDRoEhUKBr7/+Gr1798ayZcvQokWL0nq57nqltV7atGmDr776SvZ1p0+fxtixY9G6dWu/7g8AMjIy8PzzzyMnJwcvvPACateujfT0dCxfvhxPPPEEli1bhoYNG0rnGwwGPPXUU6hevToEQcCPP/6IUaNGwel04pFHHimNl+qud7PXyuTJkz0CiRUrVuCnn36SvQf4u1ZczGYz3nrrLURFRf2n14W8K631YrVaMXDgQADA+PHjERYWhjVr1uDll1/GkiVL0KpVK4/rfvjhh15/YAv4v142btyIc+fOeV23VDpKa604HA4MHDgQJpMJ06ZNg0ajwYIFC9CnTx+sXbsWQUFBAACbzSatqXfffRdmsxmzZs3C6NGjsWjRIuk++bnl9nSz1wsArFmzBhMmTED//v0xYsQIGAwG7Nu3DxaLRTrH6XQiOTkZO3bsQK9evfDqq6/CZDLhu+++w4ABA/D666/j+eefl87PyclBq1atMHjwYAQHB+Pw4cNYsGAB0tPTMW3atBv4Ct49PvnkE1SuXBmvvfYawsPDsXv3brz++utIT0/HSy+9BABYv349Xn/9dbzwwgto3rw5NmzYgJdeegmff/45GjRoIF1rxIgROHXqFN544w0EBARg7ty5GDRoEL799luoVAWxzMKFC5GUlIRnnnkGOp0OGzduxLBhwzBz5kx0795dulZKSgp69eqFwMBADBs2DNWqVcOZM2ewcOFCbNmyBZ999hmqVavm8XwyMjLwwQcfIDIy8oa+bnejm71WNmzYgPHjx6N3795o06YN9u3bhxkzZkAQBNn7BD+zFCLSXcPhcEj/P3bsWPGhhx6S3Z6eni7WqlVLXLlypXTM6XSKDz/8sPjCCy/Izo2PjxeXLl1a7P31799f7N69u+zYsmXLxDp16ogZGRnSsbfeekuMj48X9+zZIzvXbreLvXv3Fu+//37xypUrXp9H27ZtxSlTphT7OMh/pblWnnnmGfHll18u9v5+/fVXMT4+Xjx8+HCx5/mzVux2u5idne1xXpcuXcQhQ4YUez/kn9JcL4XNmzdPrFWrlnj58mWf789l2LBhYt26dcVTp07JjhsMBvHBBx8U27ZtK1oslmLv/+mnnxb79etX7Dnku5u9Vrxp166dOGjQINmxkq6VuXPnis8991yx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", + "text/plain": [ + "<Figure size 1600x400 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_series(\n", + " y, *[cv_df[\"y_pred\"].iloc[x] for x in range(5)],\n", + " markers=[\"o\", *[\".\"]*5],\n", + " labels=[\"y_true\"] + [f\"cv: {x}\" for x in range(5)],\n", + ")\n", + "print(f\"Average MAPE with Sliding Window: {round(cv_df['test_MeanAbsolutePercentageError'].mean(), 3)}\")\n", + "plt.title('Cross-validation with Sliding Window');" + ] + }, + { + "cell_type": "markdown", + "id": "126aa812", + "metadata": { + "id": "126aa812" + }, + "source": [ + "### Tuning" + ] + }, + { + "cell_type": "markdown", + "id": "78da0181", + "metadata": { + "id": "78da0181" + }, + "source": [ + "- **Grid Search with a statistical model**" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "9165746c", + "metadata": { + "id": "9165746c" + }, + "outputs": [], + "source": [ + "forecaster = AutoETS(sp=4, allow_multiplicative_trend=True)\n", + "params = {\"trend\": [\"add\", \"mul\"],\n", + " \"damped_trend\": [True, False]}" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "dc753968", + "metadata": { + "id": "dc753968" + }, + "outputs": [], + "source": [ + "cv = SlidingWindowSplitter(initial_window=60, window_length=30)\n", + "fgs = ForecastingGridSearchCV(forecaster, strategy=\"refit\", cv=cv, param_grid=params)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "123a1fea", + "metadata": { + "id": "123a1fea" + }, + "outputs": [], + "source": [ + "fgs.fit(y_train)\n", + "y_pred = fgs.predict(fh_abs)" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "0f5023e0", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "0f5023e0", + "outputId": "67db60f5-1665-4a16-d457-e26061d0511d" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'damped_trend': False, 'trend': 'add'}" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fgs.best_params_" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "9108e55a", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "9108e55a", + "outputId": "c6a611bd-44c4-44c9-fb3d-7ddc83f5eec1" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0.00674066038278309" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fgs.best_score_" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "id": "dea23dd5", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 346 + }, + "id": "dea23dd5", + "outputId": "af52c734-2a7b-4b56-d34c-cfe78e52733a" + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABUAAAAFkCAYAAADhdJEIAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAACpJ0lEQVR4nOzdeXhU5dk/8O85s0+2CQkIKEuIBFAQUGQd1oAILqXW9bVUhaJ9kbViMYAoSiVSV4IURdBWRVDRn1pSJQpCg4ilgNRXkCVBUIgBYZJJZjszc35/DHOYk5lJZrKQhe/nuryQM8+cnIlPU/1y388tyLIsg4iIiIiIiIiIiKgFEhv7AYiIiIiIiIiIiIgaCgNQIiIiIiIiIiIiarEYgBIREREREREREVGLxQCUiIiIiIiIiIiIWiwGoERERERERERERNRiMQAlIiIiIiIiIiKiFosBKBEREREREREREbVYDECJiIiIiIiIiIioxWIASkRERERERERERC2WtrEf4GImyzL8frmxH6PBiKLQoj8f1S/uF4oV9wrFg/uFYsW9QvHgfqFYca9QPLhfKFbcK+eJogBBEGpcxwC0Efn9Ms6cqWzsx2gQWq2I1NQElJc74PX6G/txqInjfqFYca9QPLhfKFbcKxQP7heKFfcKxYP7hWLFvaLWqlUCNJqaA1C2wBMREREREREREVGLxQCUiIiIiIiIiIiIWiwGoERERERERERERNRiMQAlIiIiIiIiIiKiFotDkJoBv98Hn8/X2I8RF79fgMulgcfjhs/XcieTaTQaiKKmsR+DiIiIiIiIiIiiYADahMmyjPLyM3A6KwE0vxDx9GkRfn9Ln0gmwGRKQHJyKwhCzVPHiIiIiIiIiIjowmIA2oQ5nZVwOiuQmGiBwWAE0LwCNo1GaNHVn4AMt9uFigobdDoDzObExn4gIiIiIiIiIiKqggFoEyXLMioqbDAaE5CYmNLYj1MrWq0Ir7dlV4DqdAZ4vRIqKmwwmRJYBUpERERERER0EREEAaIowO+XIcs1F4HFu57qBwPQJsrv98Pv98FoNDf2o1ANjEYzXK5K+P1+aDQ8D5SIiIiIiIiopdNoRJgNPuiNBvhdNohGCzwuFxxuDXw+f1jQWdN6algMQJsovz8w9IgDdpq+4D8jv9/HAJSIiIiIiIiohQqGmoIAJCeKKN/1DH7e+xL8bhtEgwXJfaYhpd+f4JX80Bn0StApuT3Q6USURVz/MMorAFkGq0IbkNjYD0DVY0t108d/RkREREREREQtl0YjIskso1WqHsmGSiQnyCjftRS2nX+G320DAPjdNlQefA+C3w3HN8/h+CuX4fiqy3D8lcuAymKURVnvtR2GJVmHZEMlWqXqkWQOVItS/WIFKBERERERERERUQQajYiUpPPVnhC16DDpEMr3vhS2NtX6Z5T953nYvn7q/EVRC52lS9h6XWp3tLvtc5TvfQkl36wIqwots4Ot8fWIkTI1eatXv4z//veber3n7t27YLX2w4ED39XrfYmIiIiIiIioeRMEARqNCEEQYDb4VNWeGnNb+BylSiVnkGhKh6njKJR/s0J1Pdr6VOufUb73Jdi+fkpVFWrbuRjlu/4Cs8HXgJ/w4sMA9CIS+j/g5uS111bhv//dV6/37NatO1aufA2dOmXU632JiIiIiIiIqHmq2ureKlUPg9Goqt70OUqgMbeBaLCo3xsl6Iy0PlpYGlS+dzn0RmOzy2+aMgagFwGNRoTWpEeSxQRJp0GSxQStSd/izpRwu10xr01ISETPnr1gMpka8ImIiIiIiIiIqDkItro79z2vnN9Z8t4Y+JynVKGm33kazmObkdx7qur90YLRSOujhaXKe9w2+F1l0GjqXsjWXIvh6lvLSsAojEYjwpRowAvbi9FuUYHy14vbj8KUaGjwELSwcBus1n44fvyY6np5eTlGjRqC999/t9r3W639AAArVrwIq7UfrNZ+2L17l/LaG2+8jhUrluHmm8fixhuvAwB8++0+zJ07G7/61fUYPdqKe+/9H3zyyUbVfSO1wFut/fDWW3/D6tUv46abrsMNN2TjqacWwel01vn7QERERERERERNTzAgTDD6wgYbSbZDEA2WsFDzbOF8JPd5EJb+886/5vdCshUhuc+0sK9xtnA+Uq6ZDcuABRANlqhhaZD+kmsh6ExIiWM4UtWgU6MRoU3QICnVCMnoR1KqEdoETYsrhosVhyA1M7IswyHFfghuUrIOuVsO48mCQ8o1m1PCEwUHAQDTBnVCpVOK6V5mXfx/YjBo0BC0bt0GGzd+hD/84fwPgYKCTwAAY8ZcX+37V658DX/4w3249dY7MHp0YG1Gxvm29ffeextXXNELjzzyKHw+LwCgpOQkevXqjQkTfgO93oD//vcb5OY+CVmWMW7cjdV+vQ0b3kHv3n0xf/7jOH78GFaseBGpqa3wv/87Pa7PTURERERERERNhyAIEEUBfr8MWQ6EiWaDD3qjIVBtaUhBSZVBRaHVm6GDjaSzB3Dy3Wy0Hv8WLAPmwecqg2hMgeT2IKXfwwACbezBwUYJWbdCFg0w956FlP6PwO8qgyzLSO4zDbadi1VfU5faHe1uyUfZf55F+d6XwoYjVThk1XqNRoRgFGA26GFzO2ExmODySNDrtHh632bk7S+EzeOERW/C9B5WzO01Ck6756IbsMQAtBmRZRk3vbUH//6pPKb16Ql6FM/PRl7h0YivLyssxsMjM3HFsztxutJT4/36X5qMj+7uG1cIqtFoMH78Tdi48SNMmfK/0Gg0AICNGz/C8OEjkZSUVO37e/bsBQBo06at8vehkpJS8NRTf1E90+jRY5W/l2UZvXv3RWnpz/jww/drDEDT0tLx2GOBHz4DBw7GwYMH8MUXnzMAJSIiIiIiImqG1EGnDaLRAsntgU4nouzcZHdN4mW45Ob3I7akny2cj3a3fQ4IYlioqbVcDlu5BFk2w+/0nAtW/TBfdT7oFI0p8LhcKLP74PMJEBweiKIZggdIjhCWth7/Fsp2vwDbzj8rzxAcjgQA5t6zAQCCcK7rN0mPp/+rDjq/GDcVG/bvw5PfFCj3sHmcyu9ndh8KVDbUd7xpYgDazMRTf9k2yYDSCg9sUSo8bU4Jpyo8aJtkiCkAra0bb/wV/v73Ndi5cwcGD7bi8OFDOHjwAB58cGad7z1w4OCwQLa8vBxr1ryMf/1rK06fPgWfLzA5LSUlpcb7XXvtANXvO3fOwOefb6rzcxIRERERERHRhRU817P8XNAZDBnb3vo5yg6/fz5kFLXQmFtDNFjCQlDp7AGUfDgBbX/zaYRQ0x9WSenz+WF3CBCcgaAzEIwKAALrZFmGzxeo4iyzIywsFQClElU0pZ87L7QEGmM6/G0HQTCYUOqsgCXJCKdXwtP/3awKOrWCiC5JacjbXxjxe5K3vxA5vbNhd7ggy3LENS0RA9BmRBAEfHR335hb4EVRwCXJBlhMuoghqMWkQ7tkA/5xd1/4/TVv+tq0wANAu3btce21A/CPf3yIwYOt2LjxI7Rrdymuvrpf3PeqqlWrVmHXnnrqcXz77T7ce+/vkZGRiYSEBHzwwXvYvLkgwh3UEhPVFak6nQ4eT8OFw0RERERERERUO1Xb2qteD5zr+YyqmhKiFjpLF9Vk92it7kHmzmMhSX5UlEcONSMJDTqjqRqWCh4vkvQV0JjbIuG6vyGp4wjYnOVoY0qBDzKe/u8XyPtyEWweJzKT0vDNhDlhQWdbcxJKXRWweSLPM7F5nCjzuKAVhRqfryVhANrMCIKABL0m5vUOlxczrBnKmZ+hZlgz4HB5YdI2/AG4N900AYsWLcCpU6UoKPgnbr31znqaQKa+h9vtxpdfFmLatNm49dY7lesX059qEBEREREREbUk1Z/fGWhr97hccElaGHXeas/1jDaBXWl1B1D+zQrV2ZvJ/R5Gmd0PWfY3aGjo9/shGi1odftWLP3uK+R99RRsHic+Hj0ZO08dw+JvPlfWmrQ6lDjtYUFnicOONsZEWPSmiCGoRW9Cit4Ie6WrwT5HU8QAtIWTPV7MHZkJIHDmp80pwWLSYYY1A3NHZsJZ4b4gzzF06AgkJSVj0aIFKC8vr/EszlBarRYeT2zPKUkS/H4/dDqdcs3hqERh4ba4n5mIiIiIiIiIGk8s53cGg0rLoMeR3PM+lP37+WrP9QydwB76WnCwUauhueg4YB587jKIhuit7rUVGuaKohA2wKjCK+G5/Tvx5L5A2JluSMDwtpmYuG2t6j7Rgs7T7kp8fvIgHuwxBH/+5rOwrz+9xxB4JM9FVyjGALSF8/n8cFa4MXNIZ+RkX44ypxcpJi0cLi+cFe4LNvVLq9Vi3LgbsHbtG+jffxAuuaRtzO/t1CkDhYXb0Lt3X5hMJnTs2Almc0LEtYmJiejR4wq8+ebrsFgs0Gi0ePPN15GQkAib7Ux9fRwiIiIiIiIiakAxn9+JwJAgbVIHlH399PkW9ijnelbX7i6dPQD3z7sgXjIUDrcZfkfNre7xfJ7QsDPVYIJPllWT2s+3tW9X3hetpb26oDNnVz6+vHE6RAjqKfDdB+FPPQbAqNPCLfgvqhC04XufqdH5fH54nR7YbU5oJS/sNie8Ts8FCz+Dhg0bCQC44Yab43rfH/84F36/H3PmzMDvf/87HDiwv9r1jz32Z1x2WQf8+c+P44UX/oIRI7Jx/fXja/3cRERERERERHRhmQ0+lO9aCtvOP58PMCOc3wkEhgWZOo5C+TcrlGuhQWdVZwvnI+Wa2bAMWADRYAncw2CBZcACJPd7GA63CJ+vbgGhIAiB0PPcr6YkPV488C+0X7cI7dcvwmcnDiF3X2CAUTDcjNTWHlrpWVXOrnzMuMKKR3uPUV636E24rXNv6P1uTE834sTt83Dy1odx4vZ5mJYi48w7wwMDl8T6OJaw+WAF6EUklgN4G9JXX32JlJQUDB06PK739e7dB2vWvBl2vbBwV8T1l13WAS+++New65MnP6D8/dVX9wt7f6T73X77/+D22/8nruclIiIiIiIiotoJBIYC9EYdfo7x/M54z/VMyLoVsmiAufesmCa71/S8Vc8nrdrW7qoyrT2etvbqKj0PlJVi3ZHdmHV5L+T0GoYyVzlSjCmQZBlnNoyG5+d/o+LcJPkSRwn8ztMQDRaIxhT4nRfXwGcGoNTgjh07imPHfsB7763HLbfcBr1e39iPRERERERERERNiOq8T7cdsrsy5vM7a3eupw8+nwDBEftk96rPGxZ0eiToddoobe3np7XH29aesysfX4yfCgECloe2tPewYlKXnjjzzgiUuU4rQWf66Jdh7jQGnp//Db/zNPzO08q9kvtMg8flOvdZLx4MQKnBLV36FL777lsMGDAIEyfep3rN6/VGfV/gT31in3hPRERERERERM1D1WFAoed9QtSiw6RDMZ/fqVzv86DqbFCg5nM94+mWDT6zIADGRD2e/u9m1RmbX4ybig379ymVnkDNbe1VQ9CcXfnYOn6q6vzOEqcd64/sxkNXWjGv13CUucqUSs+zG0ZDOntA+T4A5ypfb98MCCLK9y6PONG+Ps41bU4YgFKDW778lYjXT548gdtui34eaJ8+V0d9LxERERERERE1P5Emu/slF8p3PaMKL6MNKjpbOB/t7/xXWLjntR9HyrV/AiBEDf1ibW2vqa3drNOrWtoBQCuI6JKUpqr0BGrZ1l60F7OvHIac3tko87hg0RvhOHsI5esGwVe10rPzdfD8/G/VPaSzB1Dx/TtI6juzzi3+LQUDUGo06emt8eqrf4/6utlsvoBPQ0REREREREQNIbRyMjlRPdldm5KJSyfuDhtsVJvzO8srZJiuqv25nrG0tWsFEUW3zQ8LOuuzrX1y1wFw2j2w+13QigIqXW4kp3SGnHUryvcuh/TLtzWGvolX3ocyux9+f+1a/FsaBqDUaHQ6Hbp3v6KxH4OIiIiIiIiIGkDVak9BZ1YmuwcJWhN8lSVh530Gz+9MtS5Gx/uPw+cuj+H8Th8kSYDgjD30i7etvWdq24hBZ63a2ov2Yk7P4Zh3rtIzRW+Ew+2B0+5RAttge36ZHTCfC3dldxkEQ+yhb2MOxG4qGIASEREREREREVGdxXKuZ9VKz2gDjIBACHp60+/R4f4fYXcnwBfj+Z2RrtdXW3u0oDPetvZg2ClV+OD2e6EVBdgrXZDlyGGlz+eH3SFAJ0mwWFrDZquEJNUu9L0YiY39AERERERERERE1HxpNCKSzDJapeqRbKgM/Gr2KdWefrcNGnNb+BylYSFn6GCjSIJTy71eX9RwsKrAUGVR+VWboEFSqhGS0Y+kVCP0iVqYkvV48cC/0H7dIlz1/55RqjNDRWprDw06q8rZlY+Heo7Ao73HwKI3AQAsehMe7T0Gk7sOgK/SD/tZF7ROAfazLngrffD5/OcCW39Mny+4pOrSeO5xMWIFKBERERERERER1YpGI6oqPaOd61ldpWd9TS2vWtWZajDBJ8vK+Z311dYePL8TAF7av125722de8MgaDCre3ilZ6S2drpwGIASEREREREREVHMQtvJzQZf2AT3SOd6hlZ6Vp3sXtup5VVb7k1J6jM8Px49GTtPHcPiem5rP1BWihH5K/D2iIlY0Hs0bCFBp+Nc0Ol1+Gpsa6cLhy3wRERERERERERUo0it7gajsdpzPUOdLZyP5D4PwtJ/nvKaaLDAMmABEq+8D+UOLc6c9aDcbcaZsx7YHQJ8Pr+qpT34HFXb2jUJonKGp83jRLohAcPbZmJ5A7W139a5N7ompaOy3B3W0g6wJb2pYQUoERERERERERFVK1Kru6HdILS5YW2153qGVnsGJ7u3Hv8WLAPmwVfD1PKqLe0WgwkujwS9Tqtqa89MSsM3E+aoqjojBZ1Aw7W1U9PGAJSavNWrX0b//gPRq1fver/37t278O23+/C7302q93sTERERERERNXfBNvMEY3iru2Q7BNFgietcz4SsW6G1XA5buQRZDp9aHvx6ggAYE9Ut7ZHO7wQAk1aHEqddFWiyrZ1CsQX+IlK1ZLy5eO21Vfjvf/c1yL337PkP3njjtQa5NxEREREREVFzpW53d0BvCG91r26Ce+i5nh3u/xEdpvyEDvf/CNNVs85Ve6oDxKpt7dpEraqlHYh8fiegDjuD2NZOoVgBehHQaESYDT7ojQb4XTaIRgs8Lhccbg1LtYmIiIiIiIgobKBQaLu7JvEyXHLz+2FVnsC5Ss/bPo84wT3xyvtQZvfD7/dAFAPVnqKogWAUkGQwRG1r1woiim6bHxZ0Rmtrj1bVGWxrFyBgeUgVKdvaLz4MQFu4SGd0BH8QpfR7GGV2NOj/sAsLt+GRR/6It99+Hx06dFSul5eXY8KEcZg2bRZuueW2qO+3WvsBAFaseBErVrwIAFi2bCWuvrofZFnG22+/iY8++gA//3wS6eltcOutt+OOO+5W3l9a+jPy8p7H3r27UVlZgbS0dAwdOhwzZjyE1atfxmuvrVJ9nT59rsby5a/U+/eBiIiIiIiIqCmKVDTll1zqdndRC425dcRWd+nsAZR8OAFtf/Np1Anu54cXCTG1tfdMbRvX+Z1AIOzcOn4qRAjKvUucdqwv2os5PYdjXpWgk23tFxcGoM2MLMuAzxHzerPJgPJdy1RndPjdNth2Lg683ms6yu3u2G6mMcfdPj9o0BC0bt0GGzd+hD/8YZpyvaDgEwDAmDHXV/v+lStfwx/+cB9uvfUOjB4dWJuRkQEAePHFZ/Dxx/8Pv/vdJFxxRU98++0+/PWveTAYDJgw4VYAwOLFj+H06VOYNWsOUlNb4eefS/D99/sBADfdNAGnTpWioOATvPjiSgBAQkJCXJ+PiIiIiIiIqLkJPWczOVFdNKVNycSlE3er2t2jDTUKMnceC0nyo9LugVabAK/NA79fgEYDaBM0yhAjs06vtLUHRWprj/f8TiBwhue6or2YfWV4VadU4YPb740YdAba2hl8tnQMQJsRWZbh3DQe/tNfx7ReNKUjfdIh/FzljI6g8r3LkdLvITjfuhJ+5+ma79d6AExjNsYVgmo0GowffxM2bvwIU6b8LzQaDQBg48aPMHz4SCQlJVX7/p49ewEA2rRpq/w9APz004/YsOEdzJmTg1/96hYAwLXXDoDL5cJrr63CzTffAlEUsX///+GBBx5EdvZ1ynvHjbvx3D0vQevWbSCKoureRERERERERC1R1WpPQWdG+a6lqqIpQWuCr7Ik8lCj2z4HAJR/s0LVYZrc70+we2UkWnSBtvbEurW1Vxd05uzKx5c3zlBVelr0JkzvYcXkrgPgtHtg97sihp0MOi9eDECbm3jCR3Nb+BylEc/oAAKVoD7nKWjMbWMKQGvrxht/hb//fQ127tyBwYOtOHz4EA4ePIAHH5xZ63v++987AQAjRoyC1+tVrvfr1x9vvfU3lJb+jLZt2yErqzvefvtNaDRaXHvtAFx2WYc6fx4iIiIiIiKi5qbqEXkQtegw6VDYYCOfowQac5uwdnfp7AGcfDcbrYbmouOAefB5KiDqEyG5PfAIGrywv37b2oPndwLAS/u3x31+J8NOCtWkAtAffvgBq1evxjfffINDhw6hS5cu+Mc//qG8XlFRgddeew1bt27F0aNHodfrcdVVV2H27Nno1q2b6l52ux1LlizBZ599BkmSMHToUCxYsABt2rRRrdu9ezeefvpp7N+/H2lpabjrrrswZcoUVZWjLMtYtWoV1q5dizNnzqBHjx7IyclBnz59GvT7UZUgCDCN2RhzC7wgCtAkWCKe0QEAosECjbkdDNf9E3p/DD8YatECDwDt2rXHtdcOwD/+8SEGD7Zi48aP0K7dpbj66n5x3yuorMwGWZZxww2jI77+88+BAHTRoiV45ZWX8MorK/Dss7no2LETHnjgQQwfPqrWX5uIiIiIiIioOQgdbGQ2+FTneurSekYsmqra7i6a0s8VWJUAAKTkLtBCxFnoYIEIl0aD5/fVf1v7gbJSjMhfgbdHTMSC3qNh4/mdVAdNKgA9dOgQtm7dit69e8Pv94dt3hMnTmD9+vX4zW9+g1mzZsHtdmPNmjW44447sGHDBmRmZiprZ82ahcOHD+Pxxx+HwWDACy+8gClTpmDDhg3QagMf+4cffsDkyZMxZMgQzJo1C99//z2eeeYZaDQaTJ48WbnXqlWrsGzZMsyZMwfdunXDW2+9hUmTJuHDDz9Ehw4XtqJQEARAG/s5lR63G8l9pilnfoZK7jMNHrcbEM0QxPp8ynA33TQBixYtOHfm5j9x66131ipMDUpOToEgCFix4lXodLqw1zt27AQASE9Px7x5j8Hv9+P77/fjb39bjYULc7B27QZceulltf76RERERERERE1VpMFGAqA6Iq9qpWdo0Hm2cD7a3bEVYtadMKZ0hs1ZhjYmC3wAnv7vF8j79C3YPE5kJqXhmwlzGqyt/bbOvdE1KR2V5W5oZZ7fSbXXpALQUaNGYfToQEXfI488gm+//Vb1+mWXXYaCggKYTCbl2sCBAzFq1CisXbsWjz76KABgz549KCwsxOrVq2G1WgEEBueMHz8emzZtwvjx4wEAq1evRmpqKp577jno9XoMGjQIZ86cwcqVKzFx4kTo9Xq43W68/PLLmDRpEu69914AwDXXXIPrr78eq1evxuOPP97A35W6cbg1SOn3MIDAmZ/qMzoeRpndD6DhpsAHDR06AklJyVi0aAHKy8uVczhjodVq4fGoBzVdc821AICysjJYrcNqvIcoiujR40pMmTIVhYXb8NNPP+LSSy+DTqeDx+OJ78MQERERERERNVFVW939bhsM7QahzQ1rVdWewUpPy8CFkJIzkdRxBGzOcrQ2JcNx8mt4RCOeP/YD8vYHws6PR0/GzlPHsDik0tOk1aHEab9gbe1EtdWkAlBRrL4M0Ww2h11LSEhAx44dUVpaqlzbtm0bkpOTMWTIEOValy5d0KNHD2zbtk0JQLdt24YxY8ZAr9cr68aPH4+XX34Ze/bswYABA7B7925UVFRg3Lhxyhq9Xo8xY8agoOD8/+ibKp/PjzI7YL5qFlL6PwK/qwyiMQUelwtldv8F+yGi1WoxbtwNWLv2DfTvPwiXXNI25vd26pSBwsJt6N27L0wmEzp27ISOHTvhlltuw+LFC3HXXRNxxRU94fV6cfz4MezZswtLljyLiooK/PGP0zB27Hh07NgJXq+E9957B4mJScjK6q7c2+fz4Z133kavXled20+dG+i7QERERERERNQwgu3uCUZ1qzsASLZDEA2WsGrPyu/fRfJ1r+L5fZuR985T6vM7v92mtLWnGxIwvG0mJm5bq/qabGun5qJJBaC1UV5ejkOHDmHw4MHKtaKiImRkZIS1WHfp0gVFRUUAAIfDgZMnT6JLly5hawRBQFFREQYMGKCsr7ouMzMTf/vb3+ByuWA0Ghvio9Ubn88Pu0OA4PRAFM3wOz2QZQEXovIz1LBhI7F27Ru44Yab43rfH/84Fy+++AzmzJkBt9uNZctW4uqr+2HWrIfRsWMnfPjh+3j99VdhMpnRsWMnjByZDSAQVGdmXo4NG9bj559LYDAY0b17Dzz//HJYLBYAwJAhQ/HrX9+GN998HWfPnkHv3n2xfPkr9f3RiYiIiIiIiBqEut29DBpDCkrOtbqHtrVHqvY0GZORu28LngwJKSOd3xmppR1gWzs1H80+AP3LX/4CQRBw1113KdfKy8uRlJQUtjYlJUVpq7fb7QCA5ORk1Rq9Xg+TyYSysjLlXnq9HgaDQbUuOTkZsiyjrKysTgGoVhu56tXvr/35mNFcyB8iwexZEIDgz7GvvvoSKSkpGDp0eFz36t27D9aseTPC1xDwm9/cgd/85o6I79Pr9Zg7d0G199ZqtXjoobl46KG5cT1TJBqNEPWfJ1VPoxFVvxJFw71C8eB+oVhxr1A8uF8oVtwrFI/a7hdRFJBkFlB2rt1dk3gZLrn5fWjMbZFw3d9Ube3OU9/C2GmsUu2pFUQU3TY/pvM7o1V6AoGgc+v4qRGDToOowewewzCvdzZsHhcseiMcHgkehwQgkBloNAKA+s9AWir+bKmdZh2AbtiwAe+88w5yc3PRtm3sLdVNhSgKSE2NPNDI5dLg9Gmx2YdqGo2IH344ih9++AEbNqzHb35zO8zmpl0xGy+/X4AoikhJMTf5auCmLjnZVPMiInCvUHy4XyhW3CsUD+4XihX3CsUj3v3ilypRtusvsO38M0RTOkSjBRpzG7S6fSuWfvcV8r4KbWv/X2wIqfbsmdo2YlVnpLCzukrPA2WlWFe0F3/sORzzemejTHIhRWeE5PfDqNXBqA0MLm5jSgQA6E1agP+zqDP+bIlPsw1At27dioULF2Lq1Kn49a9/rXotOTkZJSUlYe8pKytDSkoKACgVosFK0CCPxwOn06msS05OhsfjgdvtVlWBlpeXQxAEZV1t+P0yyssdEV/zeNzw+/3w+WR4vc3vsN/An+KI8Pn8WLJkMb777lsMGDAId999r+rzeL3eau4hQKPRXIjHrROfT4bf70dZmQNOp6+xH6dZ0mhEJCebUF7u5OHWVC3uFYoH9wvFinuF4sH9QrHiXqF4xLNfBAHnjvyTkZSog+PoJiTd9KFS7emAiGf2f40n932uvCfQ1p6uqvaM9/zO4AAjAQKWh1R6Tu9hxeSsAfBUSnDIbugFEQ6XG7IMeCDV3zeJAPBnS1XJyaaYqmGbZQC6d+9ezJw5ExMmTMDMmTPDXu/SpQt27NgBWZZV54AWFxcjKysLQGCgUrt27ZQzPkPXyLKsnPkZ/LW4uBjdu3dX1hUVFaF9+/Z1rviLFm429/Mugm3vsoyoZ2qePHkCt90W/TzQPn2ublbncTbXsLop8fn8/B5STLhXKB7cLxQr7hWKB/cLxYp7heJR3X7RaEQIRgEmgx42jxOpehOcXjdSf70RS/9vB/K+iq+tPd7zO0ucdqwv2os5wUrP0Ent5ZzUfqHxZ0t8ml0AevjwYTzwwAMYOHAgFi1aFHHNsGHDsGLFCuzYsUMZjlRcXIzvvvsOv//971XrPv/8czz88MPQ6QIl2fn5+UhOTkbfvn0BAFdffTUSExPxz3/+UwlAJUnCpk2bMGzYsIb8qC1eenprvPrq36O+bjabL+DTEBERERERETUdwanufr8MURRgStbj6X2bVedsfjFuKjYc3adUe8bT1g6cr+oEgJf2b1ef3yloMKv7MORUCTulCh/cfi8ntVOz0qQCUKfTia1btwIAfvrpJ1RUVOCTTz4BAPTv3x+yLGPy5MkwGAy45557lIFGAJCYmIjLL78cANC3b19YrVbMmzcPc+fOhcFgwPPPP49u3brhuuuuU94zefJkfPzxx3jooYdw11134eDBg1i9ejVmz54NvV4PADAYDHjggQeQl5eHVq1aISsrC2+//TZsNhsmT558ob41LZJOp0P37lc09mMQERERERERNarQQcLBSk/zuUpPi94El1fC0/s248lvCpT3RJrWHm9b+4GyUozIX4G3R0zEgt6jYQsJOh32QFWn1+GLGHY2985Vurg0qQD0l19+CWtpD/7+738PVAoGz/a89957Vev69++PN954Q/n9Cy+8gCVLlmDhwoXwer2wWq1YsGABtNrzH7lTp05YvXo1cnNzcf/996NVq1aYMWMGJk2apLr3lClTIMsy1qxZgzNnzqBHjx5YvXo1OnToUG+fnYiIiIiIiIhattCqTlmWVWFnqbMCliQjfLKsqvTMTErDNxPmNEhbe7Das2tSOirL3dDK4UGnLMsMO6nZE2TWKjcan8+PM2cqI74mSR788stJpKW1g06nv8BPVj+0WvGiOI+iJfyzamxarYjU1AScPVt5UewZqj3uFYoH9wvFinuF4sH9QrHiXqFQGo0Is8EHvdEIv9sO0ZAEye2BX29QhZ0fj56MnaeOYXFIpWfP1Lb4f9mTcPl7T6numW5IQNFt89HxnSdVIWj3lDb4YvxU5H1XqGprn97Dikd6jYJL8sJk0Kna2mWXzDM8mwn+bFFr1Sqh5Q5BIiIiIiIiIiJqykRRgFYrQpZlJCVoUFF2HIK+M2xeLyw6P1yCF8/v2660tacbEjC8bSYmblurus+FbGsnaqlqjkiJiIiIiIiIiCgiQRACreznDvLU6TQwJmmQZDHCrffBnGSABwKeP1aM9u/8Ge03/AW9Pnweel2Cqq09Uks7oA46q8rZlY+Heg7Ho73HwKI3AUB4W7tTgP2sC95Kn1LlGWhr9zP8pIsGK0CJiIiIiIiIiOKk0YgQ9FqYjVrYnBIsJh08Hh90egG5+z5H3rn28/Nt7Z8r7zVpdShx2lVhZ7RKTyAQdG4dPzX8/M5OPWGAjIeuHBo2rd15rtqTiBiAEhERERERERHFRaMRYUo0IHfLYeQVHlUC0O8fseLZfYV48lxLejxt7dUNMDpQVop1RXsxu3t/5PQajjJXGVKMKXCWFUMniHBU+OD2u9jWThQFW+CJojh06HtYrf2we/euxn4UIiIiIiIiagBV29djXS/qtcjdchhPFhyCzSkBAC5J1CPFaETe/u3K+njb2nN25WP6FVYsqNLS/uhVozD58quRoNFCJ4popdFBJ4owmi5Fmd2ntLOzrZ0oMlaAXkQEQYAoCvD7Zf5AJCIiIiIiohYplv/2jdS+7nB5IXu88Pn8YfcIXV/mkmAx6pBXeFR1zysuSYLN46xTW3uJ0471RXsxp+cwzKtS6akXRJRVyPD7PRBFA/wOD2RZAMA2d6KaMAC9CGg0IgSjALNBD5vbCYvBBIfbA9klt+jzQNxuFwwGY2M/BhEREREREV0AsYaaggAYE8Lb12dYM/DIyEy4JB9MhvP3cLl90Os0yN1yCHmFR3FZihEfTeqvVH4GffezHRa9qc5t7S77jzDDD0HUoZVGB1EUIYdUegKAz8eiJqJ4sAW+hdNoRJiS9HjxwL/Qft0itF+/CO3XLcKLB/4FU5IeGk3DboHCwm2wWvvh+PFjquvl5eUYNWoI3n//3RrvYbX2wxtvvI4VK17EjTeOxpgxw/DnPz8Oh6NSWbN79y5Yrf3w5ZeFWLDgT7juuuF49NFHAAB2ux3PPJOLX/1qLEaOHIRJk36Lr7/+KuzrvP76q7j55rEYM2Yo5s17GGfPnq3jpyciIiIiIqL6EK1VPXhdqw2cyfnC9mK0W1Sg/PXi9qMwJxqgM+uRZDFB0mmgNeuRu+WIqn3d5pTwzjcn4PbLeL7wqOoex8pdqnb3ErsbrRP1sJh0qmf5/lQlfrZXYnqsbe29x2By1gAYEWhnT9MGfjUY2qCsAjhz1oNylwFnznpgdwgtuoCJqKGxArSZkWUZDp9U88JzksxGPP3fzXjymwLlms3jVH4/rZsVleWemO5l1uhiPhclaNCgIWjdug02bvwIf/jDNOV6QcEnAIAxY66P6T4bNqxHVlZ3zJ//OE6cOIGVK5fD43Fj0aIlqnVLl/4Z1103Dk89dStEUYQkSZg9+0GcOfMLpkyZitat22DTpnw8/PBMrFnzFjIzL1fu/+qrK3HXXRPRr19//PvfO5Gb+2Rcn5WIiIiIiIjqV7SqTsHrg6zVKNfNeo0SagYFQ83Zw7vg+cKjyCsshlYUUDw/G3mFxWFfa8n4Hnj2iyNY/Nn5e2hFAV3SzKr1pys9+OzgaUwb0lm1FgD+970DePfebABQpsAH2tr3YE7P4ZjfOxu20Ent5R74fDJ0HgkWSyvYbJWQpPNt7az0JKofDECbEVmWcfOXr+HfZ4/HtD7dkICi2+Yjb39hxNfz9hfi4V4jceWWpTjtroy4JlT/1A74cPB9cYWgGo0G48ffhI0bP8KUKf8LjUYDANi48SMMHz4SSUlJMd1Hp9NjyZJnlPcbDAY8/fRiTJr0ADp16qyss1qHYerUGcrvN278CIcOfY/XX38bGRldAAADBgzC8ePH8frrr+LJJ3Ph8/nwxhuvY+zY8XjwwZnKmrNnz+DTT/Nj/qxERERERERUf6JNWn9ibDdMHtARuZsPxx1q9mybhNIKT1j7enqCHqOz0nHf+r2q622TDBHX5+Tvx9apgwEAy7eff7Z+HSwQ/QIeunIY5vUejTKPEyl6E9ySBz6HH+XeyJPag3/LcR1EDYMt8M1MPPWX0abNBdk8TpxyVaCtObYQsrZuvPFX+OWX09i5cwcA4PDhQzh48ABuvPFXMd9jyJChSvgJACNHZkOWZXz33beqdYMGWVW///rrr5CZeTk6dOgIr9er/HXttQNw4MB3AIBTp0px+vQpDBs2UvXekSOz4/qcREREREREVH+ECJPWbU4JHSwmLNl8CE8WHITNKUUNKYOh5vLtR5VrJXY32kRoX492j2jrD5RWYPiKL9G/YypKHrsOJY9dh5OPjcHMIZ1RWeGGq9wHu80FvUcDu80Fl90HSfJxUjtRI2EFaDMiCAI+HHxfzC3woijgEnNyxGlzQODMkXbmZHw8aBL8/pp/+NamBR4A2rVrj2uvHYB//ONDDB5sxcaNH6Fdu0tx9dX9Yr5Hamqq6vcJCYnQ6w345ZfTquutWrVS/b6szIaDB7/HiBEDw+4ZDFRPnz4d8WukpqbF/HxERERERERUfwRBgNmoDZu0HqlSMzSkDA0wI4Wa0drXo92junb3A6UV2HXcBmtHC7SSF3a3pAo2/X4ZHo+vrt8KIqoHDECbGUEQkKDVx7ze4fZgeg+r6gzQoOk9rHC4PTCJugavBb7ppglYtGgBTp0qRUHBP3HrrXfGFaZWHUhUWVkBj8eNtLR01fWq90xOTkFmZlfk5Dwa9d7p6ekRv8bZs7/E/HxERERERERUf0RRgM0phVVk1keoGal93euXUfSLAzOsGXii4KDqa+bk78eOGVaIgoBlhcWqqfFzR2bCWeHmgCKiJo4BaAsnu2TM7TUKQODMT5vHCYvehOk9rJjbaxSc9tgGINXV0KEjkJSUjEWLFqC8vBzjxt0Y1/u3b/8Xpk+frVRtbtnyOQRBQI8eV1b7vn79+mPHju1IT2+N9PTWEde0bt0GaWnp2LZtC4YPP98Gv2XL53E9IxEREREREdWNIAgQRQGyLMNi0oWFl/URagbb19dNvAbzR2ehzCkhxaSFy+3D3JGBQbmhQeftvdvDIAqYZe2MnOzLUeb0IsWkhcPlZfhJ1EwwAG3hfD4/nHYPZnYfipze2SgLnTZn91ywH9RarRbjxt2AtWvfQP/+g3DJJW3jer8keZCTMwe//vWtOHnyBP761zyMGJGNzp0zqn3f9dffgA8/fB/Tpj2Au+76LTp06IiKigocOvQ9JEnCH/4wDRqNBr/97b148cVn0KpVGq69dgC+/vor7Nnzn7p8ZCIiIiIiIqpGMOz0+2WIohA27f10pSesqjNY7Tnd2lk18b02oWbXNDMcdie0MpT2dZ9GxMwh4UGn41zQ6XVKgSFGVdrdiahpYwB6EfD5/EAlYHdEnjZ3oQwbNhJr176BG264Oe73/uY3d8BmO4snn1wISZIwbNgI/PGPf6rxfXq9HsuW/RVr1ryCv/99DX755TRSUizIyuqGX//6NmXdrbfegYoKO95//1188MG76NevP+bOXYCHHpoe97MSERERERFRdBqNqAo7U006+GQoU92DIeXj12UhJ7srBAGqKfDHbU48MqorBAh1CjUjVW/6fH7A6YHdFTnoDAwxYvBJ1NwIMv/IotH4fH6cOVMZ8TVJ8uCXX04iLa0ddLrYz/xsSrRaEV7v+f8zefXVlfjgg3fxwQf/hF4f+2eyWvth6tSZ+J//mdgQj1lnLeGfVWPTakWkpibg7NlK1Z4hqop7heLB/UKx4l6heHC/UKy4VyLTaESYEg3I3XJYCTU/ntwfO4+dxeKCQ2HrX5xwJX539WUw6jWq8FLw+iBrNTAbtarrsscbtdMxtOK0qUUh3C8UK+4VtVatEqDR1DzYhhWg1OCOHTuKY8d+wHvvrcctt9wWV/hJRERERERELYeg1yJ3y2GlfT09QY8RmWmYuHZPxPWPfXoQ9w/shIoyJ7RClYpMyRe1UjMSVm8SXbwYgFKDW7r0KXz33bcYMGAQJk68T/Wa1+uN+j5BEJShR0RERERERNS8CYIAs1GLvMKjyrVIU91D2ZwSypxeaAUhYmUnQ00iigUDUGpwy5e/EvH6yZMncNtt0c8D7dPnaixf/goKC3c11KMRERERERFRAwu2nguCAJtTimmqe5DFpEOKSQu7O3JASkQUCwag1GjS01vj1Vf/HvV1s9l8AZ+GiIiIiIiI6lPVYUcWkw5mQBV2Bqe6V532HjTDmhE427OJndlJRM0LA1BqNDqdDt27X9HYj0FERERERET1LNKwI4tJhy+mDsYMawaeKDiorM3J34+tUweHTXufYc3A3JGZcFa4G/GTEFFLwAC0ieOfcjV9/GdEREREREQUEGx3F6sMOwIC53ne+cZ/sGOGFQCwrLAYNqeEErsb6/eewJzhmZiXnYUyp6RMdXdWuKNOdSciihUD0CZKFAPDf/x+XyM/CdUk+M8o+M+MiIiIiIjoYhPa7l7mkmAx6lTDjoIOlFZg7CtfoeCBgcjJ7qoKOyWHB26/HPNUdyKiWDEAbaJEUYQoauByOWA08izMpszlckAUNRBFsbEfhYiIiIiI6IIIVnr6/TJEUVC1u1+WYsRHk/pHnez+9TEbnB4/vF4PtDLCwk5OdSei+sYAtIkSBAGJiRaUl/+Cigod9HojBEFo7MeKi98vtOj/45JlGR6PCy5XJZKT05rdPx8iIiIiIqJ4RRps5JJ8yN1yRGl314oCWscy2d3GKk8iujAYgDZhJlMCJMmNiooyALbGfpy4iaIIv7+ln9UiwGRKhMmU0NgPQkRERERE1KAiDTbKTDNj35wRyCssVtZxsjsRNTUMQJswQRCQkpKGpCQLfL7mdRaoRiMgJcWMsjJHi64C1Wg0PPuTiIiIiIhatOoGG5l0GpTY3WGVnsHJ7gCwfDsnuxNR42IA2gwEzpdsXiGbVivCaDTC6fTB623pVaBEREREREQtTyyDjUrsbrSJ0O5+oLQCw1d8iaU3XoGS0VmwcbI7ETUiTm0hIiIiIiIiIpVgu/sL24vRblEBRq/8CifKXWGVnqHt7lUdKK3AruM2OFwStJIXdpsTXqeH4ScRXXCsACUiIiIiIiIiFaFKu3t1g41y8vdj29TBEAUBywqLI7a7M/QkosbEAJSIiIiIiIiIFIIgwGzUqtrdqxtsdKC0Auv2nsDsoRnIyb4cZU4v292JqElhAEpEREREREREyrAjQRBw1iHFNdhocv8OcFa4YXd4oBUF2N0Sp7wTUZPBAJSIiIiIiIjoIhY67MjmDAw7Mgmo9WAjn4/BJxE1LRyCRERERERERHSRqjrsqN2iArR7ogAHT1VihjUjbD0HGxFRc8QKUCIiIiIiIqKLSLDV3e+Xw4YdAYDNKeHON/6DHTOsAMDBRkTU7DEAJSIiIiIiIroIhLW6m3QABNWwo6ADpRUY+8pXKHhgIHKyu6IsSrs7EVFzwACUiIiIiIiIqIU6P9gIMCYYkLvlMPIKAwOMBnVOxfrfXhM27Cjo62M2OD1+eL0eaGVwsBERNVs8A5SIiIiIiIiohdFoRGhNeiRZTJB0GmjNeuRuOYInCw4pgeehU5VINevOVYKGs5h0SDFp4fPJ8Pn8DD+JqNlqUgHoDz/8gIULF+JXv/oVrrjiCtx4440R17377rsYO3YsevXqhZtvvhlbtmwJW2O32zFv3jz0798fffv2xYwZM1BaWhq2bvfu3bjjjjtw1VVXYeTIkXjllVfCfqjLsoxXXnkFI0aMwFVXXYU77rgDe/furZfPTERERERERFSfqg426vXMVoiCgLzCYtW605UefHbwNKYN6RzxPjOsGXC4vAw+iajZa1IB6KFDh7B161Z06tQJmZmZEdds3LgRjz76KMaNG4dVq1ahT58+mDZtWlggOWvWLGzfvh2PP/44nnnmGRQXF2PKlCnwer3Kmh9++AGTJ09G69at8fLLL+Oee+7BsmXLsGbNGtW9Vq1ahWXLluHee+/Fyy+/jNatW2PSpEk4fvx4vX8PiIiIiIiIiOIlCELgjE9BUA02sjkltE0yoLTCE7HVPSd/P6ZbM7BwTJZSCWox6bBwTBbmjsyE7PGGvYeIqLlpUmeAjho1CqNHjwYAPPLII/j222/D1ixbtgw33HADZs2aBQAYOHAgDh48iJdeegmrVq0CAOzZsweFhYVYvXo1rNbA1LqMjAyMHz8emzZtwvjx4wEAq1evRmpqKp577jno9XoMGjQIZ86cwcqVKzFx4kTo9Xq43W68/PLLmDRpEu69914AwDXXXIPrr78eq1evxuOPP96w3xQiIiIiIiKiKGIZbFRid6NNoh4Wky4sBD1QWoGb1nzNYUdE1KI1qQpQUaz+cY4fP46jR49i3Lhxquvjx4/Hjh074PF4AADbtm1DcnIyhgwZoqzp0qULevTogW3btinXtm3bhuzsbOj1etW9ysvLsWfPHgCBFvmKigrV19Tr9RgzZozqXkREREREREQXQrDaU6tVt7q3W1SAUSt34FSFWxV01tTqfn23NvBKfthtDmglL+w2J7xOD8NPImoxmlQAWpOioiIAgWrOUJmZmZAkSWlJLyoqQkZGBgRBUK3r0qWLcg+Hw4GTJ0+iS5cuYWsEQVDWBX+tui4zMxMnTpyAy+Wqp09HREREREREFF1dBhsFW90XjO4atdVdljnsiIhapibVAl+TsrIyAEBycrLqevD3wdfLy8uRlJQU9v6UlBSlrd5ut0e8l16vh8lkUt1Lr9fDYDCEfU1ZllFWVgaj0Vjrz6TVNqsMOmYajaj6lag63C8UK+4Vigf3C8WKe4Xiwf1CsarvvSKKAvQmA3K3HEZeYTG0ooDi+dnVDjZa/Nkh5fqB0goMX/El1k28BgtGZ8HmlJBi0sHpluBxeiAILfe/T5sD/myhWHGv1E6zCkBbGlEUkJqa0NiP0aCSk02N/QjUjHC/UKy4Vyge3C8UK+4Vigf3C8WqvvZKpcd7brDRQQBAz7ZJ1Q422jp1MERBwLLCYuVs0Nt7t0dWegL0WhFtkgJFPgatIez91Hj4s4Vixb0Sn2YVgKakpAAIVG+2bt1auV5eXq56PTk5GSUlJWHvLysrU9YEK0SDlaBBHo8HTqdTdS+PxwO3262qAi0vL4cgCMq62vD7ZZSXO2r9/qZMoxGRnGxCebmT58ZQjbhfKFbcKxQP7heKFfcKxYP7hWJVl70iigKg1cBo0MHm9MBi0kMniqpqz9gGGw3CvOyuqmpPt8MNp58t7k0Nf7ZQrLhX1JKTTTFVwzarADR4DmdRUZHqTM6ioiLodDp06NBBWbdjxw7Isqw6B7S4uBhZWVkAALPZjHbt2ilnfIaukWVZuX/w1+LiYnTv3l31Ndu3b1+n9ncA8Hpb9mb1+fwt/jNS/eF+oVhxr1A8uF8oVtwrFA/uF4pVvHtFoxGhN+nPtbofhc0pYVDnVKz/7TVRBxuFtroHBQYb+eC2u6AVBdjdEs/2bAb4s4Vixb0Sn2Z1YECHDh3QuXNnfPLJJ6rr+fn5GDRokDLNfdiwYSgrK8OOHTuUNcXFxfjuu+8wbNgw5dqwYcPw+eefQ5Ik1b2Sk5PRt29fAMDVV1+NxMRE/POf/1TWSJKETZs2qe5FREREREREVFeCXnuu1Z2DjYiI6kuTqgB1Op3YunUrAOCnn35CRUWFEnb2798frVq1wvTp0zFnzhx07NgRAwYMQH5+Pvbt24c333xTuU/fvn1htVoxb948zJ07FwaDAc8//zy6deuG6667Tlk3efJkfPzxx3jooYdw11134eDBg1i9ejVmz56thKkGgwEPPPAA8vLy0KpVK2RlZeHtt9+GzWbD5MmTL+B3h4iIiIiIiFoiQRAgigJkWYbZqEVe4VHV67EMNpo/OgtlTgkpJi0cLi+cFW62xxIRndOkAtBffvkFM2fOVF0L/v7vf/87BgwYgBtvvBFOpxOrVq3CK6+8goyMDCxfvlyp2Ax64YUXsGTJEixcuBBerxdWqxULFiyAVnv+I3fq1AmrV69Gbm4u7r//frRq1QozZszApEmTVPeaMmUKZFnGmjVrcObMGfTo0QOrV69WWu6JiIiIiIiI4qXRiBD0WpiNWticElJNOpx1euMebNQ1zQyH3QmtDLa6ExFFIMj8ydhofD4/zpypbOzHaBBarYjU1AScPVvJMymoRtwvFCvuFYoH9wvFinuF4sH9QrGKtleC1Z6CABgTDKqzPjPTzNg3ZwQufaIgYgjav6MFBQ8MhF6jUVV7yh4vqz2bOf5soVhxr6i1apUQ0xCkZnUGKBEREREREVFzpNGI0Jr0SLKYIOk00Jr1yN1yRHXW55FfHNj0/SlMt3aOeI/AYCM/7DYHtJIXdpsTXqeH4ScRUQ2aVAs8ERERERERUUuj0YgwJZ6v9tSKAornZyOvsDhsbU7+fmybOhgC1K3uM6wZmDsyE84K97nBRmzmJCKKFQNQIiIiIiIionomCCG/6s5PdgeAnm2TUFrhidjmfqC0AsNWfInt04YgJ7srBxsREdUDBqBERERERERE9SQ42Mhk1KG0wo2URBMAqCa7l9jdaJOoh8WkixiCltjdMOs1qChzQCsIHGxERFRHPAOUiIiIiIiIqA4EQQic8akNtLq/sL0Y7RZtQtvHN2HUyi9xqsKtCjpPV3rw2cHTmDakc8T7zbBmwOHywu+X4fP5GX4SEdURK0CJiIiIiIiIaiFY7Wk2amFzSjDrNcpgo6BDpyqRataFVXvm5O/H1qmDAQDLtx+NeNYnERHVDwagRERERERERHGKdbBRaLXn4s/OB6MHSiswfMWXWDfxGswfncWzPomIGhADUCIiIiIiIqI4CfrYBxsFqz1FQT3Z/fbe7dE1zQyH3QmtDJ71SUTUQBiAEhEREREREcVAEASIogBZlmE2amMebHSgtAI3rfkaBQ8M5GR3IqJGwCFIRERERERERFUEBxspA45MeiRZTJB0GiSlmGBzSnENNrq+Wxt4JT/sNge0khd2mxNep4fhJxHRBcAKUCIiIiIiIqJzqg42SjXp4JOB3M2HkXeufT0zzYx9c0bUarCRLMvw+djmTkR0ITEAJSIiIiIiootWsK3d75chioJqsJHNKeHjyf2x89hZLA6Z7H7kFwc2fX8K062dVRPfQwcbLRidhTKXhGSjDg6XxFZ3IqJGxACUiIiIiIiILjpVKz0tJh1ckg+5W44ooWZ6gh4jMtMwce2esPfn5O/HtqmDISDyYCOXw4XWyWbYbJXwSgw+iYgaEwNQIiIiIiIiavFqqvQMtrXnFRYr72mbZIg62f1AaQWGrfgS26cNiTjYSBAC6zjUnYio8TEAJSIiIiIiomYpNNSUQ5LGqmFnTZWeAGDSaVBid6vCzuomuwdfN+s1qChzQCsIsLsl5Tm0Ws4cJiJqKvgTmYiIiIiIiJqVsKnsFhO0Jj10Oo3qerLFBFOSES9sP4p2iwrQblEBev7lC+i1GlWlJ6AOO4Nqmuw+w5oBh8sLv1+Gz+dXhbBERNR01EsFqCzLOHPmDACgVatWEIK1/kRERERERET1SKMRw9rXLSYdnhjbDZMHdFRNa480wChSpSegDjsXf3Z+fXCyuyBA9fVCJ7sTEVHTVqcA9PDhw1i2bBn+9a9/weVyAQCMRiOGDh2KadOmISsrq14ekoiIiIiIiC5uwbZ2Ua9F7pbDqvZ1m1NCB4sJSzYfUsLOaAOMqmtrDw42EoXzg41K7G6s33sCc4ZnYl52VthZn5zsTkTU9NU6AN21axemTJkCv9+P7OxsdO7cGQBQXFyMzZs3Y9u2bXj11VfRr1+/+npWIiIiIiIiauGqnusZOq29zCXBYtQhr/Co6j3pCXqMzkrHfev3KteiDTCKVukJBAYbrdt7ArOHZiAn+3KUOb1K2Ck5PHD7ZWhF9VmfRETU9NU6AH3qqafQqlUrvPnmm2jXrp3qtZMnT+Luu+/GkiVLsGHDhjo/JBEREREREbVsoUGnMqzI7YNep0HulkPIKzyKy1KM+GhS/7BQM1LYGW+lZ7CtfXL/DnBWuGF3eCKGnT4fg08iouam1gHo4cOHMXPmzLDwEwDatWuHu+66C8uXL6/TwxEREREREVHLF+1cz61TB+O9fSeVdnetKKB1hFAzUthZ20rP0LZ2hp1ERC1DrafAt2/fHh6PJ+rrkiShbdu2tb09ERERERERtXCCIECjEVXnegYDTK0ooEuaWTWtPdpU9uD16Vb19Zz8/ZhuzcCjY7oq090tJh0WjsnC5P4d4HNJsNuc0Epe2G1OeJ0enulJRNQC1boC9MEHH8SSJUswYsQI9OjRQ/Xad999hzfffBPz5s2r8wMSERERERFRyxLLuZ7RzvAMTmUHgOXbz1eLHrc58ciorhAQ/wAjVnoSEbVstQ5Av/nmG6SlpeGWW25B37590alTJwDA0aNHsXfvXnTt2hV79+7F3r17Ve9bsGBBnR6YiIiIiIiImq+q7e7RzvWMdobngdIKDF/xJZbeeAVKRmfBFhJquivdmDmkMwcYERGRSq0D0DfffFP5+927d2P37t2q1w8ePIiDBw+qrgmCwACUiIiIiIjoIhM62V0IaXcHop/rWdMZnruO22DtaAm0r4eGmpIPdpfEAUZERKSodQB64MCB+nwOIiIiIiIiamEiTXYHBFW7e3VBZ07+fuyYYY04rX3uyExVG3soWZYZdhIRkaLWASgRERERERFRNJEmuw/qnIr1v70m5nM9b+/dHgZRwCxreFt7tPCTiIioKgagREREREREVC+qa3UHgEOnKpFq1sV1rqfjXNDpdUZuayciIqpJzAFo9+7dIQhC3F9g//79cb+HiIiIiIiImrbQsFMUhRpb3YE6nOsJtrUTEVHtxRyAPvjgg2EBaEFBAQ4fPgyr1YqMjAwAQFFREbZv346uXbti9OjR9fu0REREREREdEGFBp2yLIed65lq0sEnA7mbDyPv3Dmd0VrdgfPt7vGe60lERFRbMQeg06dPV/1+/fr1+OWXX/Dxxx+jS5cuqteOHDmCe+65B23atKmfpyQiIiIiIqIGV1NVp8vtg16nQe6WQ8q5nh9P7o+dx85icQyt7kCg0vOmNV+j4IGByMnuirKQdneGn0RE1BDE2r5x9erV+O1vfxsWfgJAZmYm7r77brz66qt1ejgiIiIiIiJqeBqNCK1JjySLCZJOg2SLCaYkI17YfhTtFhUofx0rdynnetqcEtIT9BiRmYbl1bS6R3J9tzbwSn7YbY5Au7vNCa/Tw/CTiIgaRK2HIJWUlECrjf52rVaLkpKS2t6eiIiIiIiIGkjVSs+q09ojVXVqRQFd0szIKyxWrrVNMqC0wlPrVnee60lERBdCrQPQrl27Yu3atbjppptwySWXqF4rKSnB22+/jaysrDo/IBEREREREdWPqud3Wkw6uCQfcrccUaa1B6s6J67do3pvpLCzxO5Gm0Q9W92JiKhJq3UAmpOTg9///vcYO3YsRo8ejU6dOgEAjh49is8//xyyLGPp0qX19qBEREREREQUn5oqPTPTzNg3Z0RMVZ2Rws7qproD51vd3XY3tKIQNtmdiIjoQqh1ANqvXz+88847ePHFF/HZZ5/B5XIBAIxGI6xWK6ZPn45u3brV24MSERERERFRbGKp9AQAk06DErs7pqrOaGFnsNVdEKAEq2x1JyKipqTWASgAZGVl4aWXXoLf78eZM2cAAK1atYIo1nq2EhEREREREdVCsNpTEABjQs2VnkD8VZ05+fuxY4ZVda5nid2N9XtPYM7wTMzLzmKrOxERNTl1CkCDRFFEenp6fdyKiIiIiIiI4lC12tOs18RU6QnEX9V5e+/2MIgCZlk7Iyf7cpQ5vUrYKTk8cPtltroTEVGTU+sAdPny5dW+LggCDAYD2rZti2uvvTZsUBIRERERERHVjUYjqs711IoCiudnx1TpGZSTvx/bqkxrr66q03GuqtPrlCKGnWx1JyKipqZOAaggCAAQ9id7Va9rNBrcdtttWLhwIdvjiYiIiIio2Tr3nzrKr4G/Pz9oqL6rHiPdO/SaoNcid8thpdqzZ9ukiAOMqmtrP1BagXV7T2D20Iy4qjp5ricRETUXtU4jt27dim7dumHChAl4//33sWvXLuzatQsbNmzAhAkT0KNHD3z66af44IMPcNNNN2H9+vVYuXJlvTz0559/jttuuw19+/aF1WrFzJkzcfz48bB17777LsaOHYtevXrh5ptvxpYtW8LW2O12zJs3D/3790ffvn0xY8YMlJaWhq3bvXs37rjjDlx11VUYOXIkXnnlFbZ0EBERERG1UIIgBFrLzyWdGo0IrUkPU6IJpRVumBJN0JsN0Jn1SLKYIOk0SLKYoDXpodHE/59Z0b5e6L0jfT2zUYe8wqPKfUIrPavKyd+PGdYMLByTpbxuMemwcEwWJvfvAJ9Lgt3mhFbywm5zwuv0wOfznws6/fzvHyIiarYEuZb/LzZ16lQYjUY899xzEV+fPXs2fD4fli1bBgCYMmUKjh07hk8//bT2Twtg586duPfeezFhwgTcdNNNsNlsePHFF+H3+/Hxxx/DaDQCADZu3IiHHnoIf/jDHzBw4EDk5+djw4YNeOutt9CnTx/lfpMnT8bhw4cxd+5cGAwGvPDCCxBFERs2bIBWGyiQ/eGHHzBhwgQMGTIEd999N77//ns888wzmD17NiZPnlzrz+Lz+XHmTGWdvh9NlVYrIjU1AWfPVsLr5aHnVD3uF4oV9wrFg/uFYsW9QqEiTk93+6DXaZC75ZByHmb/jhZ8ev9APLe1CHnn2sarTj73++UaK0Pr8vUGdU7F+t9eg46LP1Pd84N7r8V/frSFVXoCwLIJPTHx6kth1GtUlZ6yx8thRfWMP1soHtwvFCvuFbVWrRJi+oPHWrfAf/XVV3j44Yejvn7ttdfi2WefVX4/fPhwPP3007X9coqNGzeiffv2eOqpp5Q/HW3VqhXuuecefPvtt+jXrx8AYNmyZbjhhhswa9YsAMDAgQNx8OBBvPTSS1i1ahUAYM+ePSgsLMTq1athtVoBABkZGRg/fjw2bdqE8ePHAwBWr16N1NRUPPfcc9Dr9Rg0aBDOnDmDlStXYuLEidDr9XX+XERERERE1LCitapXNz3dYtJh69TBeG/fSdVQoZxRXfHsF0dUIaPNKeGJgoNIT9Bj4jWXIkGnUe4RGjLW19c7dKoSqWZd2LmewQFGALB8+1FVODu5fwc4K9ywOzwcVkRERBeNWrfA6/V67Nu3L+rr33zzDXS6820XXq8XZrO5tl9OdZ+EhAQl/ASApKQkAOfPHD1+/DiOHj2KcePGqd47fvx47NixAx6PBwCwbds2JCcnY8iQIcqaLl26oEePHti2bZtybdu2bcjOzlYFnePHj0d5eTn27NlT589EREREREQNJ1I7udakh06nUV3XmvXK9PRgoKgVBXRJM6uGCqUn6DE6Kx3Ltx8N+1rd2yTizj7t8dy2YrRbVKD89eL2ozAnqlvY6/r1Qs/1DHWgtALDV3yJW3u3x8nHrkPJY9fh5GNjMHNIZzjPDTBiWzsREV1Mal0BeuONN+Ktt96CxWLBXXfdhcsuuwwA8OOPP2Lt2rX46KOPcPfddyvrd+7cicsvv7zOD3zLLbfgww8/xFtvvYWbb74ZNpsNzz33HK644gpcffXVAICioiIAgWrOUJmZmZAkCcePH0dmZiaKioqQkZGhClOBQAgavIfD4cDJkyfRpUuXsDWCIKCoqAgDBgyo9efRalvmUKhg+XFtzj+iiw/3C8WKe4Xiwf1CseJeaXkEIVDVKcsyBEGA3hSssjzfqv7E2G6YPKAjcjcHrkebnt42yRA2VCjStaAl43tgWWFxWGXoO9+cwOzhXfB84dF6/XrBas/QCe4Wkw63926PrmkJcDtcMMiAs8ILyIHvTUv9b5Cmhj9bKB7cLxQr7pXaqXUA+vDDD+P06dN47bXX8PrrryvT3f3+wJ8iXnfddUqLvNvtxpVXXqkElHXRr18/LF++HA899BCeeOIJAECPHj3w6quvQqPRAADKysoAAMnJyar3Bn8ffL28vFypHg2VkpKCb7/9FkBgSFKke+n1ephMJuVetSGKAlJTE2r9/uYgOdnU2I9AzQj3C8WKe4Xiwf1CseJeaRkqPV7oRBE2lwSLUQeX13duSvpBZY3NKaGDxYQlmw9hcQ3T00OHCgVfi3QNOF+ped/6vWHPtWR8D1ULe318PSBQ7XnTmq9R8MAgzMvuijKXhBSjDpLfD5NeA5O+7l14VDf82ULx4H6hWHGvxKfWAWhwYNB3332Hf/3rX/jpp58AAJdeeimsViuuvPJK1dpp06bV/WkRmMb+pz/9CbfffjtGjBgBm82GFStW4P7778fatWuVIUjNgd8vo7zc0diP0SA0GhHJySaUlzt5mDrViPuFYsW9QvHgfqFYca80b8FqT0EAdEYDlm45olR6ZqaZsW/OiLAqy0hBZbSQMbTNPBheRroGRK/UbKivF3R9tzbwe31wON3QCwIcFV7IMuCpdMf/DaV6w58tFA/uF4oV94pacrKpYYcgBV1xxRW44oor6nqbmC1evBgDBw7EI488olzr06cPRowYgQ8//BB33HEHUlJSAASqN1u3bq2sKy8vBwDl9eTkZJSUlIR9jbKyMmVNsEI0WAka5PF44HQ6lXW11dIndvl8/hb/Gan+cL9QrLhXKB7cLxQr7pWmreoAo+D0dNO56elmvSas0tOk06DE7g4LJCMFldWFjDn5+7FjhlXVZr5k8yF8ev9A1TWn5EPbJENYqNlQX6/q1Hn+h3DTxJ8tFA/uF4oV90p86hyAXmhHjhxBdna26lrbtm2RmpqKY8eOAYByXmdRUZHq7M6ioiLodDp06NBBWbdjxw7lbKCg4uJiZGVlAQDMZjPatWunnAkaukaW5bCzQYmIiIiIqP4Eg07zuaDTYtLB5fZBr9Mgd8sh5BUejXqeZrQqy2jXo01Pv713exhEAbOsnZGT3RXlLgnJRh1cbu+5a5ejzOlFikkLl+TDDGsGnggJYuv29ULu7faFXXO4vAw/iYiIahBzANq9e/ewYUE1EQQB3333XdwPVZ327duH3fOnn37C2bNncemllwIAOnTogM6dO+OTTz7B6NGjlXX5+fkYNGiQMs192LBhWLFiBXbs2IHBgwP/4lFcXIzvvvsOv//975X3DRs2DJ9//jkefvhhZbJ9fn4+kpOT0bdv33r9fEREREREFKDRiDAlBgcYnQ8It04djPf2ncSTNZzfGa3KMnh9urWzcg/g/PT0dROvwfzRWShzSkrI6AiGjJIXrS0JsNkqIUmB0NHrlKAVBdjdEkRRwNyRmQCgVGp6/TKKfnGEBaOxfL3Qewcntke6RkRERNHFHIA++OCDcQegDeHOO+/EU089hcWLF2PUqFGw2Wz461//irS0NIwbN05ZN336dMyZMwcdO3bEgAEDkJ+fj3379uHNN99U1vTt2xdWqxXz5s3D3LlzYTAY8Pzzz6Nbt2647rrrlHWTJ0/Gxx9/jIceegh33XUXDh48iNWrV2P27NlKmEpERERERPUj2O4u6rXn2trPh5RaUUCXNLOq2rO6IUE5+fuxLcKU9OM2Jx4Z1RUCIk1PN8Nhd0IrIyxkDP5taO4oyzJ8vsAFn0+Gs8KNmUPCqzfnjrwcAOL8eufvXd01IiIiik6Qm9kfGcqyjHXr1uHtt9/G8ePHkZCQgD59+mD27NnIzMxUrX333XexatUqnDhxAhkZGfjjH/+IkSNHqtbY7XYsWbIEBQUF8Hq9sFqtWLBgAS655BLVut27dyM3Nxf79+9Hq1atcPfdd2PKlCl1CoV9Pj/OnKms9fubMq1WRGpqAs6ereSZFFQj7heKFfcKxYP7hWLFvdJ4op3raTZqUeaSYDHq0XbRJlWo2bNtEj6c1B+ZT32uutcH916L//xoizgkaNmEnph49aUw6jWq1nHB64Os1QS+Xsh12eON2lIez36p9vPF+PWo+eLPFooH9wvFintFrVWrhJiGIDW7ALQlYQBKFMD9QrHiXqF4cL9QrLhXLrxYzvW8LMWIjyb1R5cqQWd6gh7F87PR4cnPVMFo9zaJ2Dp1MPIKi1XnaYYOCfL7ZVUgGVQ1qKxOfeyXeL4eNV/82ULx4H6hWHGvqMUagNZ5CFJJSQm+++472O32iP/nPWHChLp+CSIiIiIiaiFiPddTKwpoHaGtPdq5ntWdpxk6JChS6/iFbilnCzsREdGFVesA1O12Y+7cudi0aRP8fj8EQVAC0NC2cAagREREREQU77me0YJOIHCu544Z1rBzPWs6T5OIiIguTrUOQJ977jkUFBRg1qxZ6Nu3LyZOnIjc3Fy0adMGf/vb31BaWoqnn366Pp+ViIiIiIiauJrP9dQhr/Co6j1tkwwRp7jn5O/H1qmDAUDV1n577/YwiAJmWdWDhqpWexIREREBdQhAP/30U9xyyy24//77cfbsWQDAJZdcgkGDBmHw4MH43e9+h7feeguLFi2qt4clIiIiIqKmKZ5zPasGndGmuAfb2pfeeAVKRmfBFtLW7jgXdHqdErSiwGpPIiIiiqrmU0Kj+OWXX3DVVVcBAIxGIwDA6XQqr48dOxYFBQV1fDwiIiIiImrqgud6vrC9GO0WFSh/HSt3Ke3uNqeEErtbOdczVGi7e1UHSiuw67gNDpcEreSF3eaE1+lRqjwD52n6GX4SERFRVLUOQNPT05XKT5PJhJSUFBQXnz+zp6KiAm63u+5PSERERERETY4gCIGqT0GAEHKuZ7CCs6ZzPavKyd+Ph0ZkYuGYLCUgtZh0WDgmC3NHZsLv8TLoJCIiolqpdQv8VVddhd27dyu/HzlyJFavXo3WrVvD7/fj9ddfR58+ferjGYmIiIiIqImI1OoOCDzXk4iIiJqsWgegEydOxCeffAKPxwO9Xo+ZM2diz549+NOf/gQA6NixI+bPn19vD0pERERERI0jONhIEABjggG5Ww4jrzAQXg7qnIr1v72G53oSERFRk1XrALRfv37o16+f8vt27drhn//8Jw4ePAhRFNGlSxdotbW+PRERERERNbKq1Z5mvQa5W47gyYJDyppDpyqRataFBZ2h7e6LPzukum/wXE9rR0vgXM8qQWfgXE8Gn0RERFQ/an0GaMSbiSK6d++OrKwshp9ERERERM1M6LmeVQcb9XpmK0RBUJ3pCfBcTyIiImr66pRSVlRUYO3atdi5cyd++eUXPPHEE7jqqqtgs9nwwQcfYNSoUejUqVN9PSsREREREcUp2L7u98uqoDH0uigKYed6uiSfqtqzZ9ukiGd6AufP9RQFAcsKi3muJxERETUptQ5AS0pK8Nvf/hYlJSXo1KkTioqKUFlZCQCwWCxYt24dfvrpJyxYsKDeHpaIiIiIiGITaViRw+WF4PVB1mqU66kmHXwykLv5MPLOhZeZaWbsmzNCVe0Z7UxPINDSftOar1HwwEDkZHdFGc/1JCIioiak1gHo0qVLUVlZif/3//4fWrVqhcGDB6teHz16NL744ou6Ph8REREREcWoumFFFpMOT4zthskDOqrCzo8n98fOY2exOORcT5NOgxK7O+YzPQHg+m5t4JX8cNvdEYNOnutJREREjaXWZ4Bu374dEydOxOWXXw5BEMJe79ChA06ePFmnhyMiIiIionChZ3UCgWpPrUmPJIsJkk4DrVmvtK8HQ0ybU0IHiwlLNh/CkwUHYXNKSE/QY0RmGpYXHlXdP7TaM1RO/n5Mt2ZgweiuEc/0lD3ec0Enz/UkIiKipqPWFaAulwutWrWK+nqwHZ6IiIiIiOpHpLZ2l9sHvU6D3C2HkFd4FFpRQPH87LBhRekJeozOSsd96/cq19omGSKe6xmt2vNAaQWGr/gS6yZeg/mjs1St7jzTk4iIiJqqWgegmZmZ+Pe//40777wz4uufffYZrrjiilo/GBERERHRxa7qoCJTYnhb+9apg/HevpM1DiuKFHZWd65nTv5+bIsy2KhrmhkOuxNaGTzTk4iIiJq8Wgeg99xzDx555BF069YN48aNAxA41+eHH37A8uXLsXfvXuTl5dXbgxIRERERtWTxTmUHAK0ooEuaOaZhRZGuV3eu54HSCqzbewKzh2ZwgjsRERE1a7UOQH/1q1/hxIkTePHFF/HCCy8AAH7/+99DlmWIoojZs2dj9OjR9fWcREREREQtUtW29linsgORqzqjhZrB69OtnVUhak7+fmydOhiCAFVl6QxrBib37wBnhRt2h4cT3ImIiKjZqlUA6nQ6cffdd+O2225DQUEBNm3ahB9++AF+vx8dO3bEddddhw4dOtT3sxIRERERtSgajRjW1h7rVHYgerVnMNQEgOXbz4eax21OPDKqKwScb2svsbuxfu8JzBmeiXnZ0c/15AR3IiIiaq5qFYCaTCb8+OOPEAQB7du3x7333lvPj0VERERE1DKFtroLei1ytxxWKjKDU9knrt2jek+0oLM2w4rclW7MHNI5rK1dcnjg9sus9CQiIqIWR6ztG4cOHYrCwsL6fBYiIiIiohZFEIRAi/u5X7UmPZIsJkg6DZIsJpiNOuQVHlXWxzKVvaqc/P14aEQmFo7JgsWkA4DwYUWSF3abE16nB5Lkg9fpgd2mvu7z+SHLsvIrERERUUtR6zNAp06dipkzZ+Lhhx/GHXfcgQ4dOsBgMISts1gsdXk+IiIiIqJmJ5ZzPQd1TsX6315TL1PZDaKAWdbwqs7qhhUFwk4GnURERNTy1ToAveGGGwAAhw8fxj/+8Y+o6/bv31/bL0FERERE1CxUneAey7meh05VItWsq5ep7I5zQafXKbGFnYiIiKiKWgegDz74IARBqM9nISIiIiJq0kKDTlmWwyo9LSYdXJIPuVuO1HiuZ7Swsy5T2VnVSURERBSu1gHo9OnT6/M5iIiIiIiarIhBp9sHvU6D3C2HlKAyM82MfXNGIK+wWHlvtHM9gfNhZ2hbO6eyExEREdWvWgegREREREQtWbDaUxAAY4K6pd1i0mHr1MF4b99JpdITAEw6DUrs7pjP9TxQWoGb1nyNggcGIie7qyrs5FR2IiIiovpR6ynwREREREQtUdVp7VqzXmlpDwaYWlFAlzSzqtITUIedQdVNcAeA67u1gVfyw25zcCo7ERERUQNgAEpEREREdI5GI8KUaMAL24vRblEBej2zFaIghAWd0drao4WdOfn7Md2agUfHdFXCUYtJh4VjsjB3ZCZkj5dhJxEREVEDYQs8EREREV3UgnM9BQGATovcLYeVtvaebZMiBp3VtbXn5O/Htlqe60lERERE9Y8BKBERERFdlIKDjUxGHUor3EhJNAEITF4PihZ0RpvgDgTO9Vy39wRmD81ATvblKHN6ea4nERERUSNiCzwRERERXXTUre6b0PbxTRi18kucqnBHDTqrysnfj4dGZGLhmKywtvbJ/TvA55Jgtzl5ricRERFRI2MFKBERERFdNIKT3UW9utUdAA6dqkSqWRdW7ZmTvx9bpw4GACzffn4K/O2928MgCphl7RxW6Rna1u7zMegkIiIiakwMQImIiIioxQu2u5uNWpS5JFiMOlWrOxC9rf1AaQWGr/gS6yZeg/mj1ed3Os4FnV6nxLZ2IiIioiaKASgRERERtWjBdvfcLYeRV3gUl6UY8dGk/mHDi4Dz1Z6hA4yC1Z5d08xw2J3QyggLOgNt7Qw+iYiIiJoiBqBERERE1KIJVdrdtaKA1lEmuB8orcBNa75GwQMDkZPdldPaiYiIiFoADkEiIiIiohZHEARoNCJEUYDZqFW1u1c32AgAru/WBl7JD7vNETbAiIiIiIiaH1aAEhEREVGLEXrWp80pIdWkw1mnN6zSM9pgoxnWDMwdmQlnhZtt7UREREQtBANQIiIiImoRqp71aXNKyEwzY9+cEWHt7sHBRktvvAIlo7NQ5pKQbNTB4ZLY6k5ERETUwrAFnoiIiIiaNaXdPeSsz2DYeeQXBzZ9fwrTrZ3D3negtAK7jtvgcktonWiAs4Kt7kREREQtUbMNQD/44ANMmDABvXr1woABA/D73/8eLpdLeX3z5s24+eab0atXL4wdOxYbNmwIu4fH48HTTz+NIUOGoE+fPrjvvvtQVFQUtu7IkSO477770KdPHwwZMgRLly6Fx+Np0M9HRERE1FQEA0ZBEBr7UVQ0GhFakx5JFhO8eg3MRp3qrM+gnPz9mD4kAwvHZMFi0gEALCYdFo7JwtyRmZC9PgCAzG53IiIiohapWbbA//Wvf8WqVavwhz/8AX369MHZs2exY8cO+HyBf3ndtWsXpk2bhltvvRXz5s3DV199hfnz5yMhIQHXX3+9cp/FixcjPz8fjzzyCC655BKsXLkS9957LzZu3IikpCQAQFlZGe655x507twZeXl5+Pnnn5GbmwuXy4WFCxc2yucnIiIiqitBECCKAvx+GXKU5K/qeZoWkw4Olxeyx9voVZJV290vSzHio0n9w876BAKVnsNWfInt04ZEnOzexHJdIiIiIqpnzS4ALSoqwvLly7FixQoMHz5cuT527Fjl7//617/iqquuwhNPPAEAGDhwII4fP45ly5YpAWhJSQnee+89PPbYY7j11lsBAL169cLIkSOxbt06TJkyBQCwbt06VFZWYvny5bBYLAAAn8+HRYsW4YEHHsAll1xyIT42ERERUb2oKdQMBqOCABgT1OdpVh0S5PfLNYao9Sk0tBVC2t0BQCsKaJ2oDzvrM6jE7oZZr0FFmQNaQYDdLSnPrNU226YoIiIiIopBs/u3vffffx+XXXaZKvwM5fF4sHPnTlWlJwCMHz8eR44cwY8//ggAKCwshN/vV62zWCwYMmQItm3bplzbtm0bBg0apISfADBu3Dj4/X5s3769Hj8ZERERUbj6bD8PVk2+sL0Y7RYVKH+9uP0ozIkG6MyBdnJJp4HWrEfuliOq8zRtTglPFBzE6q+PQ2PSKWuTLCZoTXpoNA3zr5ahre7Br1e13f10pQefHTyNaUM6R7zHDGsGHC4v/H4ZPp//ggS2RERERNQ0NLsA9JtvvkFWVhZWrFiBQYMGoWfPnrjzzjvxzTffAACOHTsGSZLQpUsX1fsyMzMBQDnjs6ioCGlpaUhJSQlbF3oOaFFRUdi9kpOT0bp164jnhRIRERHVJFKoWfVapNCvtiFjdUOCbE4J73xzAm6/jOcLj6LdogL0emYrREFAXmFx2L26t0nEnX3a47lt4SGqKdGgfIaaPl+s34tIoe2olTtwqsIdVumZk78f060ZWDC6a+SzPj3euL93RERERNT8NbsW+FOnTuHbb7/FwYMH8dhjj8FkMmHlypWYNGkSNm3ahLKyMgCBkDJU8PfB18vLy5VzPquuC64Jrqt6LwBISUlRrautltpyFfyPs4aqBKGWhfuFYsW9QvG40PtFEALBnSzLyjCdqtdEUQC0GhgNOticHlhMeng8XvgBGPVa1TWtVnOu/by4Svv55fA4A+3nNQn9emUuDyxRhgQtGd8Dz35xBIs/C7ST92ybhNIKT8RW8iXje2BZYbGyFjhfGZqeoMfEay5Fgk5b7edzuSWIfj/8oljj98IleZVK1KBDpyqRataFtbsfKK3A8BVfYumNV6BkdBZsTgkpJh2cbgkepweCEPnfvfizheLB/UKx4l6heHC/UKy4V2qn2QWgsizD4XDgxRdfRPfu3QEAvXv3xqhRo/Dmm2/CarU28hPGThQFpKYmNPZjNKjkZFNjPwI1I9wvFCvuFYrHhdgvlR4vdKIIm0uCxaiD1++HDIRdEwUBSzafDzX7d7Tg0/sH4rmtRaqgc+vUwXhv30k8WXBQ+RrBkBEAHh6ZiQR9zf8a55J8yteLNiQoPUGP0VnpuG/9XuVaid2NNhHO04y0Nii0MrSmz/fE2G6YPKAjcmv4XmSmmbFvzoiwStTQdvfQIBYIhKC7jtsw8vI0tEkyAAAMWkON3yuAP1soPtwvFCvuFYoH9wvFinslPs0uAE1OTobFYlHCTyBwducVV1yBw4cP44YbbgAA2O121fvKy8sBQGl5T05ORkVFRdj9y8vLVW3xycnJYfcCApWkVdvn4+X3yygvd9TpHk2VRiMiOdmE8nJno0+JpaaP+4Vixb1C8ajv/RKtelOr1WDpliO1CjVzRnVVVV4CgWE+XdLMEdvPAeCT70vx0IhMeLx+nA2pqITXB1mWlYpTQafFc4VHla8XbUhQ2yRDWLVntIAx0tqgSJWhkT6fzSmhg8WEJZsPYXFB9WtNOg1K7OGt7kCg3X3r1MEQBQHLolTJnq10R/weVsWfLRQP7heKFfcKxYP7hWLFvaKWnGyKqRq22QWgl19+OY4dOxbxNbfbjY4dO0Kn06GoqAhDhw5VXgue1xk8z7NLly44ffp0WJBZ9czPLl26hJ31abfbcerUqbCzQWvD623Zm9Xn87f4z0j1h/uFYsW9QvGoy34JnYiuN+nDJqLXJdSMVk1ZXcjYvU0iPp7UH898cSSsovKefpdBr9WcC2d1ANRneEYLNaNVewYDRgBYvj3wmZ2SD22TDDFVhkb7fPGsjfZsQKDS86Y1X6PggYHIye6KMqeEFJMWDpcXzgpXrf6DgD9bKB7cLxQr7hWKB/cLxYp7JT7N7sCAkSNHwmazYf/+/cq1s2fP4v/+7/9w5ZVXQq/XY8CAAfj0009V78vPz0dmZiYuu+wyAIDVaoUoiti0aZOypqysDIWFhRg2bJhybdiwYfjyyy+VClIA+OSTTyCKIoYMGdJQH5OIiIguoJoGEEWaiF5dqLl8+1HV/SOFmtGCztDQr6ol43sgr7AYTxYcVN7XNsmAO/q0x1+2HkG7RZviHhLk9cso+sWBGdYM1drgeZq39m6Pk49dh5LHrsO3D4+Ax+sLWxvP54tnbU2T3a/v1gZeyQ+7zQGt5IXd5oTX6WE1BBERERGpNLsK0NGjR6NXr16YMWMGZs+eDYPBgFdeeQV6vR7/8z//AwD43//9X/zud7/D448/jnHjxmHnzp34xz/+geeff165T9u2bXHrrbdi6dKlEEURl1xyCV5++WUkJSXhzjvvVNbdeeedeOONN/Dggw/igQcewM8//4ylS5fizjvvxCWXXHLBPz8RERHVH41GhKDXwmzUKtWULrcPep0GuVsOIa/wKLSigOL52WEt6bUNNYOvRatujFapGa1KMhiKhq6Nb0iQFi63D3NHXg4Aqnby23u3R9c0Mxx2J7QyYHdLEEUBc0dmqtZGqgyN9vni+V4AgdB2W9RW90w4K9yQZRk+X81DoYiIiIjo4tTsAlBRFPHKK69gyZIlWLhwISRJQr9+/fDWW2+hdevWAIB+/fohLy8PL7zwAt577z20b98eixcvxrhx41T3WrBgARISEvDss8+isrISV199NV577TXVdPiUlBT87W9/w5NPPokHH3wQCQkJuPXWWzF79uwL+rmJiIiofmk0IkyJhmra2qufiF7XULO6QT45+fuxY4ZVFfp1bZ2Asw4ppqFEsQwJsna0BKom3VIgQNSImDmkM3KyL0eZ0xvSTu5WVVT6fDKcFe6wtS4pUBkaHNQU7RmC16dbOyvf45qed93eE5g9NKPGZyMiIiIiiqTZBaAA0KpVK/zlL3+pdk12djays7OrXaPX6zF37lzMnTu32nWZmZl4/fXX431MIiIiasIEvRa5Ww4rIRwQua29IUPNJZsP4dP7B4ZVN97euz0MooBZVnXICAiq56juvNDqhwRlRgg2/YDTA7tLglYUlGA0kkhrI1WGRvt8x21OPDKqKwTU/L2YYc3A5P4d4Kxww+7w1PhsRERERERVCTL/7bHR+Hx+nDlT2diP0SC0WhGpqQk4e7aSh/JSjbhfKFbcKxSP6vaLIAhIspjQblGBKjzs2TYJH07qj8ynPlet/+Dea/GfH21hoWb3NonYMcOK57cWKaFdcAp86LVgkPfIyEy4JB9MBu35ykm3DzJk1TWHywvZ44XP51cGMfn9MjRGHV7cflSpskxP0KN4fjY6PPlZxBC0f0cLCh4YCL1GoxoSFLx3fQs9UqCmzyd4fZC1mpjWNtTzBvFnC8WD+4Vixb1C8eB+oVhxr6i1apXQMqfAExEREdWVKAqwOaWY2tqByBPRq6vUdLl9YdccLi8c56ouvc7wKstI1wCozreUPV5VleXpSg++OPKLqp08VHBIkNvuviCVk9VVkUb8fJIv9rVERERERLXEAJSIiIiatdAKydCw7NxAd+XX0LWyLMNiCh8SFK2FPTg8aN3EazB/dJaqmrKuoWZ116ry+fxh529aTFqMujxd1U7e2EOC4vl8tf1eEBERERHFigEoERERNUuRJriHtlabjDqUVriRkmiC4PYqrdXBtT/b3TGf1RltInp9hJrxqlplWX7u/M1YBhgREREREV2MGIASERFRsxNtgvsTY7th8oCOyN18GHlhZ3IWK9csJh0evy4LOdldYx5A1NQCxdBw1eeTYx5gRERERER0sWEASkRERM1GsIVdjDDB3eaU0MFiwpLNh7A45HrOqK549osjqkpPm1PCrA//D6IgYPbQjLjO6mzK2DpORERERBSu5jFJRERERI1MoxGhNemRZDHBq9fAbNQhr/Coak16gh6js9KxPOS6cm27em3Qwk+/h1GvQUWZE1rJC7vNCa/To1R5BgJFf7MIP4mIiIiIKDJWgBIREVGTEzrYSBQFVbv7ZSlGfDSpf9gE97ZJBpRWeFTXI10LZXNKKHN6oRWEJtPaTkRERERE9YsVoERERNRkhFZ6SjoNkiwmaEw65G45gicLDsHmlFBid6N1oh4Wk0713hK7G22qXI90LZTFpEOKSQu/nxWeREREREQtFQNQIiIiajSCIASmuZ/71ZRowAvbi9FuUQHaLSpAz798Ab1Wg7zCYuU9pys9+OzgaUwb0ll1r+D16dbONa4NmmHNgMPlZYs7EREREVELxhZ4IiIiuiCqtrULei3MRq0yfd0l+ZRKzyCTToMSuzushT0nfz+2Th0MAFi+/fwU+OM2Jx4Z1RUCzk92X7L5ED69f2DYtPcZ1gzMHZkJZ4X7gn4fiIiIiIjowmIASkRERPUqNOiUZTlQ4RkSdqaadPDJQO7mw8g7F0hmppmxb84IVaUnoG5hDw1BD5RWYPiKL7H0xitQMjoLNqekTHB3V7oxc0hn5GR3RblLQrJRB5fbi1nWzmHT3p3npr0TEREREVHLxQCUiIiIaq3Gqk63D3qdBrlbDiGvMFCp+fHk/th57CwWx1DpGdrCvvizQ6rXDpRWYNdxG6wdLYEJ7m7pfCu75IPT60VrSwJstkpIUiDk9DolaEVBvZaIiIiIiFo0BqBEREQUt1iqOi0mHbZOHYz39p1U2trTE/QYkZmGiWv3qO4XrdITCLS7b5s6uNoW9khVnMF8MzTnlGUZPh+DTyIiIiKiiwkDUCIiIopLcFhR7pbD1VZ1akUBXdLMqrb2tkkGlFZ44q70XLf3BGYPzWALOxERERERxY0BKBER0QVW9YzM5iD0mQW9FrlbDtdY1Rkp7Kxtpefk/h3grHDD7vCwhZ2IiIiIiOLCAJSIiKgeRAs1azoj0+HyQvZ44fP5Y7rHhQj9anpmQEBe4VFlfbSqzkhhZ31UerKFnYiIiIiI4sEAlIiIKE6xhJqC1wdZq6nxjMwZ1gw8MjITLskHk6H6e4QGpsGvXZ+haCzneg7qnIr1v70mpqrOaGFnTv5+bJ06GIIApYWelZ5ERERERNRQGIASERHFKNbBP0+M7YbJAzqqrkc6I9PmlPDONycwe3gXPF94tMZ7BK/f0+8y6LUa2JyemKtII6ka5MZyruehU5VINetirurMyd+PHTOsqrb2Ersb6/eewJzhmZiXnYUyp8RKTyIiIiIiajAMQImIiGIQ6+Afm1NCB4sJSzYfUq5HOyMTAJaM74FnvziiCg4j3QMItJrf0ac9/rL1CJZXqZyMVkUaqVq0apBrMengknzI3XKkxnM9463qvL13exhEAbOsncPa2iWHB26/zEpPIiIiIiJqUAxAiYiIoqjN4J/0BD1GZ6XjvvV7lWvRzsiMtLa660vG90BeYXFYWFpdFWnValGX2we9ToPcLYeUoDIzzYx9c0bENK0dOB92xlrV6ThX1el1ShHDTlZ6EhERERFRQ2IASkREVEWkCslYB//EM/k8nntEC0WByFWk0apFt04djPf2nVSCXAAw6TQosbtjntZ+oLQCN635GgUPDEROdldV2FldVacsyww7iYiIiIjoghMb+wGIiIiaAkEQoNGI0GoDre4vbC9Gu0UFaLeoAKNW7sCpiugBYahI10PbxmtaG+16TVWky7cfVV1XqkULDinv0YoCuqSZVZWe8T5z0PXd2sAr+WG3OaCVvLDbnPA6PfD5/OeCTj9b2omIiIiIqElgAEpERBc1jUaE1qRHksUESaeB1qxXzsIMBoehg3+CogWEwevTrerrOfn7Md2agUfHdFXu4/XLKPrFgRnWjBrvES0sra5atGooGi1EjfZZIj2zxaTDwjFZmDsyE7LHy7CTiIiIiIiaPLbAExHRRaW6yedaUUDx/OywCsl4B/8ctznxyKiuEFDzGZkutw9zR14OAMraSPc4XenBF0d+wXRrZ1X7eqRW9WhBZ3Vt7Tn5+7EtjnM9Q6e1ExERERERNWUMQImI6KIQy+Tznm2T6m3wj7vSjZlDYpt87tOIEddWvYfFpMWoy9NVwWpoFekTBQcBRA86owW5QOBcz3V7T2D20AxOayciIiIiohaFASgREbVI1VV6Rpt8Xu+DfyQf7K6aJ5/7fH7A6Ym8NuQe5W4JoiiEhaVVq0ijVYsCgSB3xwyrKsi1mHSYYc3A5P4d4Kxww+7wcFo7ERERERG1GAxAiYioRYml0hOIPPm8ugpJ4PzgH7fdHXNAGM/k82hrQ6/7fHLEsLRqFWmkalGLSYfbe7eHQRQwyxpecRra1s6wk4iIiIiIWgoGoERE1OwFqz0FATAm1FzpCUSv9gy2ugPA8u1HVRWSc0dmwlnhjivUbChVn6FqFWm0alGHywvHuaDT64xcnUpERERERNSSMAAlIqJmQxDUv1at9jTrNTFVegLRqz0PlFZg+IovsW7iNZg/uvkN/omlWjTSWiIiIiIiopaKASgRETWq0LM6Q8O5qmd4CnotTEYdSivcSEk0QXB7oddpkLvlULUT3OOdfB5sE++aZobD7oRWRrOvkGTQSUREREREFzMGoERE1CgindXpcHkheH2QtRrleqpJB58M5G4+jLyQkHLr1MF4b9/JGie413byeXOo9iQiIiIiIqKaMQAlIqJ6F62qM0ijEcOmsltMOjwxthsmD+ioCjs/ntwfO4+dxeKQtnatKKBLmjnmCe7RKj1jmXxOREREREREzRsDUCKii0AsbebB63VZG62qU/Z44fP5lfWiXovcLYdVZ3XanBI6WExYsvmQEnamJ+gxIjMNE9fuUX2etkmGsGrP+qj0ZJs4ERERERFRy8MAlIioBYk1kKzaZm4x6eBy+yBDhslQu7Uut091JmdoleUjIzPhknwwGbQoc0mwGHXIKzyqevb0BD1GZ6XjvvV7lWuRgk6gdhPcWelJRERERER0cWIASkTUTEUaElQ1pIwUSEZqM+/f0YJP7x+I57cWq87ZjGdt1TM5gUBV5zvfnMDs4V3wfOFR5BUW47IUIz6a1D8s1IwUdkYLOus6wZ2VnkRERERERBcPBqBERE1cTVWdsQ4JAiK3mQNAzqiuePaLI6owMZ61kc7kDFoyvodqvVYU0DpCqBkp7KyurT0nfz92zLC2+AnuREREREREVDcMQImImpDaVHXGOiQIiNxmHulavGujtapHWh8t1Axen27trAptg23tggBVJevtvdvDIAqYZe3MCe5EREREREQUFQNQIqJGUF9VnfEMCYp2vT7WRmtVj7Y+2lmdx21OPDKqKwScr+ossbuxfu8JzBmeifnZWShzSUg26uBwSXCcCzq9TonnehIREREREVFEzT4AraysxLhx4/Dzzz/jvffeQ69evZTX3n33Xbz66qs4ceIEMjIyMHv2bIwcOVL1frvdjiVLluCzzz6DJEkYOnQoFixYgDZt2qjW7d69G08//TT279+PtLQ03HXXXZgyZQoEQbggn5OIWoZIQ4nqUtUZbyAZ6Xp9rI1W1RltffCszqU3XoGS0VmwhZzV6a50Y+aQ8KpOyeGBTwRaWxJgs1XCK52v8JRlmed6EhERERERUURiYz9AXa1YsQI+ny/s+saNG/Hoo49i3LhxWLVqFfr06YNp06Zh7969qnWzZs3C9u3b8fjjj+OZZ55BcXExpkyZAq/Xq6z54YcfMHnyZLRu3Rovv/wy7rnnHixbtgxr1qxp6I9HRC2IRiPClGjAC9uL0W5RgfLXsXIXcrccxpMFh2BzSkpV5/IqU9JrGhIUKjSQjHR9urVzva4FAlWdD43IxMIxWcrzeP0yin5xYIY1I2z9gdIK7Dpug8MlQSt5Ybc54XV6IEk+eJ0e2G1O1XWfz49gcSeLPImIiIiIiChWzboC9MiRI1i7di3mzp2Lxx57TPXasmXLcMMNN2DWrFkAgIEDB+LgwYN46aWXsGrVKgDAnj17UFhYiNWrV8NqtQIAMjIyMH78eGzatAnjx48HAKxevRqpqal47rnnoNfrMWjQIJw5cwYrV67ExIkTodfrL9yHJqImq2pbe9Xrol6rBJ1Bda3qrM2QoEht5ks2H8Kn9w+s09poZ3K63D7MHXk5AKjWz7BmYO7IzKjndbKqk4iIiIiIiOpDsw5AFy9ejDvvvBMZGerKouPHj+Po0aN4+OGHVdfHjx+PpUuXwuPxQK/XY9u2bUhOTsaQIUOUNV26dEGPHj2wbds2JQDdtm0bxowZowo6x48fj5dffhl79uzBgAEDGvBTElFjihRq1nR+p8Wkg8PlheD1QdZqYDZqUeaSYDHqkBdnVWcsbea1GRIUqc3c5fbVeW20Mzl9GjFiWzuHFREREREREVFDa7YB6CeffIKDBw8iLy8P//d//6d6raioCADCgtHMzExIkoTjx48jMzMTRUVFyMjICDvHs0uXLso9HA4HTp48iS5duoStEQQBRUVFDECJWoBYQk2X2wcZMkyG6s/vtJh0eGJsN0we0FEZYnRZihEfTerfIFWdoUOC5mVnoSzkPM1qhwRJPthd4dfrvBbh1Zs+nx9weiLeg4iIiIiIiKghNcsA1Ol0Ijc3F7Nnz0ZiYmLY62VlZQCA5ORk1fXg74Ovl5eXIykpKez9KSkp+PbbbwEEhiRFupder4fJZFLuVVtabbM/hjUijUZU/UpUnQu9XwQhEHjKshz4AxCtBkaDDjanBxaTHh6PF1qtBrlbzk9g79/Rgk/vH4jntxZXO5UdAGxOCR0sJizZfEgZYqQVBbSut6pOEbOHZiAnu+u5sFMHp1uC3y3B6fLAIAhwVngBOfBZQ3/OaDQCgPDhbZGu18faaOJdf/59/NlCseN+oVhxr1A8uF8oVtwrFA/uF4oV90rtNMsA9K9//SvS0tLwm9/8prEfpU5EUUBqakJjP0aDSk42NfYjUDNyIfZLpccLnSjCdq4l3SfLSpVmeKh5UHlfzqiuePaLI6qQMtL5nQCQnqDH6Kx03Ld+r3KtLlWd87OzUOaSkGLUQfL7YdRrYNRrAABtkgwAAIPWUN/fqiaNP1soHtwvFCvuFYoH9wvFinuF4sH9QrHiXolPswtAf/rpJ6xZswYvvfSSUp3pcDiUXysrK5GSkgIgUL3ZunVr5b3l5eUAoLyenJyMkpKSsK9RVlamrAlWiAa/VpDH44HT6VTW1YbfL6O83FHr9zdlGo2I5GQTysudPN+PalTb/SKK4dWbLrcE0e+HXxQjVnUu3XJECTs/ntwfO4+dVao0gcihZqRAE4g+rCja9WBVJwAs3x57VafD5YFeEOCo8EKWAU+lO+bvUUvDny0UD+4XihX3CsWD+4Vixb1C8eB+oVhxr6glJ5tiqoZtdgHojz/+CEmScP/994e99rvf/Q69e/fGs88+CyBwFmjo2Z1FRUXQ6XTo0KEDgMA5njt27DjfBntOcXExsrKyAABmsxnt2rVTzgQNXSPLctjZoPHyelv2ZvX5/C3+M1L9iWW/BM/qFARAb9Kfa1OPfvZmtKrO9AQ9RmSmYeLaPar7Rwov45nKXt31A6UVGL7iSyy98QqUjM6CTXVWpws+nx+Sw8MzMmPAny0UD+4XihX3CsWD+4Vixb1C8eB+oVhxr8Sn2R0Y0KNHD/z9739X/ZWTkwMAWLRoER577DF06NABnTt3xieffKJ6b35+PgYNGqRMcx82bBjKysqwY8cOZU1xcTG+++47DBs2TLk2bNgwfP7555AkSXWv5ORk9O3btyE/LhGdo9GI0Jr0SLKYIOk00Jr1yN1yBE8WHFJCxtCzN58sOKhcj1TVGUuoWd01QN3WHun6dKv6OhAIQXcdt8HhkqCVvLDbnPA6Pcqf3AWGB/kZfhIRERERERHVk2ZXAZqcnBx16vqVV16JK6+8EgAwffp0zJkzBx07dsSAAQOQn5+Pffv24c0331TW9+3bF1arFfPmzcPcuXNhMBjw/PPPo1u3brjuuuuUdZMnT8bHH3+Mhx56CHfddRcOHjyI1atXY/bs2UqYSkQNR6MRYUo0KNWeWlFA8fzsmM7eBCKHndGqNCOd1Rnv+Z0Wkw7HbU48MqorBKivz7BmYO7ITDjPTWcnIiIiIiIioobV7ALQWN14441wOp1YtWoVXnnlFWRkZGD58uVhFZsvvPAClixZgoULF8Lr9cJqtWLBggXQas9/azp16oTVq1cjNzcX999/P1q1aoUZM2Zg0qRJF/pjEV00gq3ufr8MQa9F7pbDyqT1nm2T4jp7M1LYGW+ouWTzIXx6/8CwoDNwfqeAWdbOyMm+HGVOr9LW7q50Y+aQ8OsMP4mIiIiIiIguHEFmn2Wj8fn8OHOmsrEfo0FotSJSUxNw9mwlz6SgGul0IiyWBNhslfD7AUGvhdmoVUJGQEC7RZuU8DI9QY/i+dno8ORnqrAz2nUA+ODea/GfH22qsLN7m0RsnToYy7cXq84RnWHNwCMjM+GSfDAZtEp46XL7IENWXXO4vJA9Xvh8flVoG/qjNdp1ih9/tlA8uF8oVtwrFA/uF4oV9wrFg/uFYsW9otaqVULLHIJERC2HRiNC0GthMupQWuGGJdEEnyyrBhgN6pyK9b+9psY29dDr062dlWrRoEhVnSV2N9bvPYE5wzMxLzvr3PT14FCiQJWm1ymFDSWKdA0Int8ZHnBGu05EREREREREDY8BKBFdMKGVkKIoqM71tDklfDy5P3YeO4vFIeHloVOVSDXrws7qzMnfj61TBwMAlm8/WuPZm9W1qksOD9x+OeZQk4EmERERERERUfPBAJSIGlyw0jO0rd0l+ZQp7kCgfX1EZhomrt2jem+0as8DpRUYvuJLrJt4DeaPVldvRjt7s7qqTgAMNYmIiIiIiIhaIAagRFQnNZ17KQiAMUFd6ZmZZsa+OSNUU9yjDTACzld7RhpA1DXNDIfdCa0MdaAp+WB3xdeqTkREREREREQtDwNQIopJ1aAzUlWnw+WF4PVB1mqU62a9RlXpCQAmnQYldrcq7Iw0qT3oQGkFblrzNQoeGIic7K6qas/qJqoz6CQiIiIiIiKimsckEdFFRxCEQMB57letSY8kiwmSToMkiwl6swGmRCNe2F6MdosKlL/e2nsChgQDXth+FO0WFaDXM1shCoKq0hNQh51Boa3ukVzfrQ28kh92mwNayQu7zQmv0xM1/CQiIiIiIiIiAlgBSkQhqlZ1ppp08MlQTWW3mHTYOnUw3tt3UlXVaXNK6GAxYcnmQ8oQo55tkyK2tUc71zPY6i4IUNrlLSYdZlgzMHdkJpwVblZ1EhEREREREVFcGIASXcRqM5VdKwrokmYOq+pMT9BjdFY67lu/V7lWXVt7Tv5+bKtyrmeJ3Y31e09gzvBMzMvOirnVnYiIiIiIiIgoGgagRBeJqmFnbaeyRxtWFOl6tEpPIHCu57q9JzB7aAZysrui3CUh2aiDwyVBcnjg9ssRBxgREREREREREcWDAShRCxdLW3s8U9mjVXVGux5saweA5dvVbe2T+3eAs8INp0dCa0sCbLZKeKXzVZ5sdSciIiIiIiKiumIAStTC1KatPZ6p7NGqOoPXp1s7q84GPVBageErvsS6iddg/ujIbe2CEJjHxkJPIiIiIiIiIqpvnAJP1IzVNK1dY9Ipbe02p6S0tS8vPKq6T7xT2XPy9+OhEZlYOCZLeY/FpMNxmxOPjOoadv323u3RNc0Mh93JCe5EREREREREdEGxApSoCQmt3gw997Lq9fpua493KvvtvdvDIAqYZe2MnOzLUeb0KlWd7ko3Zg4Jv84hRkRERERERETUGBiAEjWwWELNSEOJHC4vBK8PslajHlbk9kGv0yB3y6F6a2sH4p/K7jgXaHqdUviwIskHuyvCdSIiIiIiIiKiC4wBKFEDqVqlGS3UjFS9aTHp8MTYbpg8oGPY9a1TB+O9fSdrnNYeKeyMfSq7unqzuqnssixHHFYU7ToRERERERER0YXEAJSoHgWrOgUBMCaohw9FCzUjVW/anBI6WExYsvmQ6rpWFNAlzdwgbe2hU9ntDk/EsJOBJhERERERERE1NwxAiWqhpjM5zXqNMnwoKFKoGa16Mz1Bj9FZ6bhv/V7V9UhhZ322tYee08mwk4iIiIiIiIhaAgagRHGI1NZe9UxOrSigeH62qkoTiBxqRqvejHb9QrW1ExERERERERG1FAxAqdmJNlSormtrer8oCjAlhre1Vz2Ts2fbpJhDzWjVm9Gus62diIiIiIiIiCg+DECp2Yg2VEj2eJWAMlpLenVrg2qayu6SfGFt7ZHO5Iwn1IwWaAavT7d2Vn09IBB27phhZVs7EREREREREVEMGIDSBRWpIjNalWYs1ZdPjO2Ge/pdBr1WA5vTE7Elvbq1sU5lz0wzY9+cEWFt7ZGqOuMNNaNVbx63OfHIqK4QcD7otJh0uL13exhEAbOsndnWTkRERERERERUAwagdEFEOztThgyTQV2lWTWQjFZ92TbJgDv6tMdfth7B8mpa0qtbG+tUdpNOgxK7O6YzOYHzoSYALN9efahZXfWmu/L/t3fnYVGV/RvAbzYXJETNTNECTUYWFZRFEhFN0tJeQcs1cAU1Qw00E7fcRUvNJSVEw6XeSk1/AmkaKYpL7qS5sbihIGaAwAzMwPn94Tvn5TADzuAIvnh/rqsrOfNwzpnh5szDd57nOUWY3FWz0Fn4n1GdKrmS09qJiIiIiIiIiCrBAig9E0ZG//2/iYmxxuhN99essD+4C1YeThcLjxUVJCsafbnkXXusOZouGWWpbUp6RW31uSu7vmtyXrmfj+5fH8O/AzpjZi/dipoVjt5UluCRQnuhUxAEFjuJiIiIiIiIiCphXNMnQLWLiYkxTOvXQX2L+rifX4T6FvVhUt9MHL2pLh7O6NkWXx5KxYID18RtZQuSZbdrG32pvqP62qQbkuNrm5JeUVtx+9EblX4/IC10ljcj/jLCfNpgjq8drOqbAYA4Vb1tE3MUPpLDVKnCoxw5VPJiKJUlUMmL8ShHur2kpPQ/Bc1SjanrFW0nIiIiIiIiIqLKcQQoGYy2kZ7aRm+qC4+jfjgv+f6KtmsbfVlRoVKftvrclR14XOhM/OhNyc2HnrQmZ9kbEJXH0ZtERERERERERM8eR4CSwRjVMcXS31MkIz21jd7UpyAJaB99WbZQWdW22rZXNtLzyv18/Pv8XXzSzRb35voic+7buDfXF5O72qAwvwjKQu2jOomIiIiIiIiIqOawAEoGYWRkBPN6plhTZjo5oL3IqE9BUm1G/GVM8rIVp5k/KCjGodS/EeJlo7Vt2SnpFbUte1f28t8f4mWL2b5tJVPa5/jaYYx7K5QolBUWOjlVnYiIiIiIiIjo+cIp8GQQxsZGyJErKx29qb5JUEU3DipbkCx7B3dAOvpSPc3cqr4per7xsuSO6hVNSa+orb53ZS87pZ3T14mIiIiIiIiInn8sgJJBlJYKsKpvpvPamUsSrmN/cBeN9TS1FSSt6pthkpctxri3gjy/CI8Ki2FqbIS8IiWMjY203lG98D+FSpVc+cS2et+VnYiIiIiIiIiI/mcYCazq1JiSklI8fFhQ06dhMKb16+CrpBuYf+CaxmOr/ZwQ0Mka9eqYiEVGRVEJBAioX9dUUng0UpVAMDWBeT3pdqFYVeGamkZGRjA2NkJpqfDEQmVFbfXZBxmWqakxGjVqgH/+KYBKxXVTqWLMCumDeSFdMSukD+aFdMWskD6YF9IVsyLVuHEDmJg8eYVPjgAlgxGKVZjeow0APHH0ZtkRlepRmpJRlsoSPFJo2V7RsfW4o3pFbXlXdiIiIiIiIiKi2ocFUDKYkpJSyPPV08nbIk+hhGU9MxQqlJWuncmCJBERERERERERPSssgJJBlZSUAvJiyFUqNLVqgJycAqiUHJJNREREREREREQ148mT5ImqQD1jnUtpEhERERERERFRTWIBlIiIiIiIiIiIiGotFkCJiIiIiIiIiIio1mIBlIiIiIiIiIiIiGotFkCJiIiIiIiIiIio1mIBlIiIiIiIiIiIiGotFkCJiIiIiIiIiIio1jISBEGo6ZN4UQmCgNLS2vvym5gYo6SktKZPg/5HMC+kK2aF9MG8kK6YFdIH80K6YlZIH8wL6YpZ+S9jYyMYGRk9sR0LoERERERERERERFRrcQo8ERERERERERER1VosgBIREREREREREVGtxQIoERERERERERER1VosgBIREREREREREVGtxQIoERERERERERER1VosgBIREREREREREVGtxQIoERERERERERER1VosgBIREREREREREVGtxQIoERERERERERER1VosgBIREREREREREVGtxQIoERERERERERER1VosgBIREREREREREVGtxQLoC+TmzZuYM2cO+vfvDwcHB/Tr10+jTXFxMZYvXw4vLy906NAB77//Po4fP67RTiaTafzXtWtXjXa///47/P394eTkhO7du2P16tUoKSnRaKdQKPD111/j3XffRfv27eHh4YEJEyYgOTlZo21SUhLCwsLQq1cvyGQyzJ8/v4qvCFXEkFkBgNTUVEycOBFubm5wdnaGn58fkpKSxMdPnjypNVOffPKJxr50zUpJSQmioqIwfPhweHh4wN3dHQEBATh9+vRTvjpUnqHysmvXLq05kMlkGDNmjF7HU8vNzUVERAR69eoFJycnvPnmmwgLC0N6erpG24iICPTt2xcuLi7o1KkTBg4ciLi4uKd4Zai86s5KQEBAhe3K/2z1yUpZBw8ehEwmqzSHVDWGfC/KyMhAaGgovLy84OLigoEDB2L//v0VHrugoADe3t6QyWT4888/NR7XJy/x8fEICQkR9xcdHa3nK0FPYsisZGVlYcqUKejcuTNcXFwwfvx43L59W2u7kJAQuLi4wN3dHTNnzkR+fr5GO/Zbnj81kRcAOHToEIYMGQJnZ2e4ubkhICAAmZmZkjYlJSXYtm0b/P390bFjR7i6umLkyJE4evSoxv5+/vlnDBo0CO7u7mjfvj169+6NdevWobi4uIqvDJX3yy+/YMKECfD29oazszP69++PHTt2QBAESbuffvoJvXv3Rvv27fGvf/0Lv//+u8a+Hj16hPDwcLi7u8PFxQWTJk3C/fv3JW3+/e9/Y/To0ejatSs6deqEQYMG4eDBg1rPLSsrC3PmzEH37t3Fv7XnzJmDrKysSp/Tt99+C5lMhnHjxun5alBlqjsrALBz50706dMHTk5O8PX1xdatW7WeG/ss/2Va0ydA1ef69es4fPgwOnbsiNLSUo1fRgBYvHgx9uzZgylTpsDW1ha7du1CUFAQfvjhBzg6OkraBgQESDoMZmZmksfPnz+Pjz76CH379kVoaChSUlKwatUqyOVyTJ8+XWxXWFiIkSNH4vr16xg7dixcXV2Rk5ODbdu2YdiwYVi5ciV8fX3F9keOHMGVK1fg5uaG3Nxc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Ly+Eh4dj+vTpqFu3LlauXAmZTCa5gWNISAiuXLmCRYsW4e7du5Kpy2VHFS9fvhwBAQEYNGgQxo0bBxsbG9y8eRORkZEoLCzE5s2bxbb29vYaz8vS0hLm5ubstxhQdWfl8OHDuHXrFt544w3k5uZi7969OHnyJL7//nvJebHPImUkaBtjT7XSnTt3xIW3y9uyZQs8PDywadMmfPfdd8jMzISVlRXefvttTJ48WbLeREJCAiIjI5Geno6CggI0atQI3t7emDJlimRdmsuXL2Pu3LliB65jx46YPHmy5I6ragqFAtHR0YiNjcXt27ehVCpRt25dREZGSjoQALBr1y5xVEZ5V69e1ft1IU2Gyora1q1bERMTg8zMTFhbW2Ps2LGSYnlkZCT27t2LjIwMKJVKWFtb47333kNwcLDGqC5ds1LZc7C2tkZCQkJVXhrSwtB5Uf/BmJiYKK6bo+/x1HJzc7Fhwwb8+uuvyMzMhEqlQpMmTbBx40bJH5MPHjzA4sWLcf78eWRnZ+Oll15C69atMXLkyCotPE/aVXdWgMcZ6Nq1K0aMGIFp06ZVeG66ZkWbzz77DBcvXkRsbGyl7Ug/hszLpUuXsGrVKly6dAkKhQI2NjYYMWIE+vfvX+HxT548icDAQOzYsUNjhos+eVmzZg3Wrl2rsX++FxmOIbMSFhaGEydOIDc3Fy1btsTgwYMRGBiocROkrKwsLFy4EEePHoWpqSl8fX0RHh6uMWKL/ZbnT03kpbCwECtWrEBcXBzy8/Ph6OiIadOmaXwwp1Kp8P3332Pnzp1IS0sTp8hHRERozIhbsmQJjhw5grt378LU1BQtW7aEn58fhg0bxpvdGEjPnj2RkZGh9bHffvsNLVu2BAD89NNPiIqKwt27d2Fra4vQ0FBx5K/ao0ePsGTJEhw4cAAqlQpeXl6YNWuWZKSgTCar8FzK/52bmZmJdevW4fDhw8jOzkZpaSlsbGwQFRWF1157rdLnFRAQAHNzc0RGRlbajnRX3VlJSkrCsmXLcPPmTZiamsLd3R1hYWEaH9ID7LOUxQIoPZdOnTqFUaNGYcKECZg4cWJNnw49x5gV0kdsbCymTp2KpUuXcmkNqhSzQvpgXkhX7LeQPlJTUzFo0CD06dMHixYtqunToedYZGQk1qxZg6ioKI0BRERlvch9Fq4BSs8lNzc3zJgxA6tXr8bu3btr+nToOcaskD769euHUaNGYdasWZK1dYjKY1ZIH8wL6Yr9FtJHmzZtsHz5cuzcuRNff/11TZ8OPcfGjRuHt956CyEhIZIlNIjKe5H7LBwBSkRERERERERERLUWR4ASERERERERERFRrcUCKBEREREREREREdVaLIASERERERERERFRrcUCKBEREREREREREdVaLIASERERERERERFRrcUCKBEREREREREREdVaLIASERERERERERFRrcUCKBEREREREREREdVaLIASERERERERERFRrcUCKBEREREREREREdVa/w+nteD3sWVhtQAAAABJRU5ErkJggg==", + "text/plain": [ + "<Figure size 1600x400 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_series(y_train, y_test, y_pred, labels=[\"y_train\", \"y_test\", \"y_pred\"]);" + ] + }, + { + "cell_type": "markdown", + "id": "85dcd148", + "metadata": { + "id": "85dcd148" + }, + "source": [ + "- **Randomized Search with a scikit-learn estimator**" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "4ed06658", + "metadata": { + "id": "4ed06658" + }, + "outputs": [], + "source": [ + "regressor = LinearRegression()\n", + "forecaster = make_reduction(regressor, strategy=\"recursive\")\n", + "params = {\"window_length\": list(range(2, 21))}" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "87b8df0e", + "metadata": { + "id": "87b8df0e" + }, + "outputs": [], + "source": [ + "cv = SlidingWindowSplitter(initial_window=60, window_length=30)\n", + "frs = ForecastingRandomizedSearchCV(forecaster, strategy=\"refit\", cv=cv,\n", + " param_distributions=params, n_iter=5, random_state=42)" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "34cfb79f", + "metadata": { + "id": "34cfb79f" + }, + "outputs": [], + "source": [ + "frs.fit(y_train)\n", + "y_pred = frs.predict(fh_abs)" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "id": "cf7a209d", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "cf7a209d", + "outputId": "03d364a3-46de-4193-b81f-6298c3b53e34" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'window_length': 2}" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "frs.best_params_" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "id": "32cb3203", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "32cb3203", + "outputId": "6509ceed-5f58-4934-87c1-af3d52e38e91" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0.006820844800594237" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "frs.best_score_" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "a662382e", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 346 + }, + "id": "a662382e", + "outputId": "ac982554-f149-455b-bf3e-df7ec13fd8fc", + "scrolled": true + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABUAAAAFkCAYAAADhdJEIAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAACtd0lEQVR4nOzdeXxTZb4G8Oec7GmbpkARUJa2UBZlU2QNSymLoKNeR0VGuSKIepFVcaCAKG5UxxWQYbG4jCK4jFcdGIcKCBYZZxxA9AKytCwKtbIkTZs9OfePkkNOk7RJKXTh+X4+frAn7zk5p7xEefp7358gSZIEIiIiIiIiIiIiokZIrOsbICIiIiIiIiIiIrpYGIASERERERERERFRo8UAlIiIiIiIiIiIiBotBqBERERERERERETUaDEAJSIiIiIiIiIiokaLASgRERERERERERE1WgxAiYiIiIiIiIiIqNFiAEpERERERERERESNFgNQIiIiIiIiIiIiarTUdX0DlzNJkhAISHV9GxeNKAqN+vmodnG+UKw4VygenC8UK84VigfnC8WKc4XiwflCseJcOU8UBQiCUO04BqB1KBCQcOZMeV3fxkWhVotISUlAaakDPl+grm+H6jnOF4oV5wrFg/OFYsW5QvHgfKFYca5QPDhfKFacK0pNmiRApao+AOUSeCIiIiIiIiIiImq0GIASERERERERERFRo8UAlIiIiIiIiIiIiBotBqBERERERERERETUaLEJUgMQCPjh9/vr+jbiEggIcLlU8Hjc8Psbb2cylUoFUVTV9W0QEREREREREVEUDEDrMUmSUFp6Bk5nOYCGFyKeOiUiEGjsHckEGAwJMJmaQBCq7zpGRERERERERESXFgPQeszpLIfTWYbERDN0Oj2AhhWwqVRCo67+BCS43S6UlVmh0ehgNCbW9Q0REREREREREVElDEDrKUmSUFZmhV6fgMTE5Lq+nRpRq0X4fI27AlSj0cHn86KszAqDIYFVoERERERERERUbwiCAFEUEAhIkKTGXKRWNTZBqqcCgQACAT/0emNd3wpVQ683IhDwXwbL/YmIiIiIiIioIVCpRKgTVEhK0cOrDyApRQ91ggoq1eUZBbICtJ4KBCqaHrHBTv0X/D0KBPxQqfj7RURERERERESXVmilpygKMCRp8fwPm7FkXwGsHifMWgOmdrZg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HXNAGE/n82hjQ4/7/VJMYanPB8zOygCAsIpVnShghiU8RA0NctmtnYiIiIiIGgsGoEREVC9VXsIuaNUw6DUoKXMjOdEAyeWF4PNDUqvkak+jVhVTpScQPewMLnUXBMgharBCcnZWBpxl7rhCzYsllrDUWeaOWC3qOBd0+pyRq1OJiIiIiIgaEwagRERUp0KDTkmSwpawpxg08EtA7uZDWBJSyfjUyI6Y2KeNfFwtCiialx1TpWdQpMY/0ZoVNcS9MKtbhl8fglwiIiIiIqKLjQEoERHVusqhZiQR9+p0+6HVqJC75aBcffn5xN749thZPBNS1Wl1etHabMCizQfl49e0SIrYwKimjX8iNStqqBh0EhERERHR5YwBKBHRZSxSUBlLeBnt/EihpsPlg+TxKSonVSoxrCu72aDB1sn98dGek/IS9mYJWgzJaIpxa3Yp3rdZghbDMpvhvnW75WPxVnrG2viHwSEREREREVHDxgCUiKgRiRZexhJUutx+SJBg0EUOLyPtyVld9WblvTOD54paNXK3HFLs1akWBaQ3NSqWsLdI0kWs6ox0vKaVnmz8Q0RERERE1LgxACUiaqCqCyQdLl9Yk6BoQWXvNmb844G+eGVrkWKfzWmWNMzJyoDL65eD0Wh7clau3gQqlqo/lX8AzRK0GHfdlUjQqGBzeWHWa7Ck4IjieSKFmtGqOqMdDzYwAoCl24/EVelJREREREREjRMDUCKieq62mgRVFVTmDO2Al746rKictDq9+OD7E5g5OB2vFByRrxFpT85I1ZtBnZon4q4erfDytopw9apkPT6b0DusqjNSqBmtqjN4fKqlneI59peUYfCyb7B23HWYNyx6AyNWehIREREREV0+GIASEdUjNVlmHmuTICByUBlpP82gRaM7K4LRaHtyRluqHrzG4oIi+RpqUUBqhOrNaGFnsKpTEKBYWn/c6sScoR0gQLmv553dW6FDUyMcdifUEljpSUREREREdJljAEpEVAdqWtV5IU2CgMhBZbTwMtI1oo2NtiQ90jWq2qszZ8M+7JhmUTQrKra7sW73CcwanIF52Zmwubww6TVwuLxwl7sxfUC7Kvf1JCIiIiIiosubWNc3cKHKy8sxaNAgdOzYET/88IPitQ8//BAjR45E165dcfPNN2PLli1h59vtdsydOxe9e/dGz549MW3aNJSUlISN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BmLq1KmSSkF3d3e911Lyc25aWhpWrVqFQ4cOISMjA4WFhXB2dkZMTAxef/31Uu8rNDQUdnZ2iI6OLrUdGa6sY+XYsWNYtGgRbt++DSsrK/j5+WHcuHFaX9ID7LMUxwQovZBOnz6NQYMGYcSIERg5cmR5Xw69wBgrZIy4uDiMHz8eCxYs4NQaVCrGChmD8UKGYr+FjJGUlIRevXqhc+fOmDt3bnlfDr3AoqOjsWLFCsTExGgVEBEV9zL3WTgHKL2QfH19MXnyZCxfvhw7duwo78uhFxhjhYzRtWtXDBo0CFOnTpXMrUNUEmOFjMF4IUOx30LGcHV1xeLFi7Ft2zZ8/fXX5X059AIbNmwY3n77bURGRkqm0CAq6WXus7AClIiIiIiIiIiIiCosVoASERERERERERFRhcUEKBEREREREREREVVYTIASERERERERERFRhcUEKBEREREREREREVVYTIASERERERERERFRhcUEKBEREREREREREVVYTIASERERERERERFRhcUEKBEREREREREREVVYTIASERERERERERFRhcUEKBEREREREREREVVY/w9GCDYcMbowzgAAAABJRU5ErkJggg==", + "text/plain": [ + "<Figure size 1600x400 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_series(y_train, y_test, y_pred, labels=[\"y_train\", \"y_test\", \"y_pred\"]);" + ] + }, + { + "cell_type": "markdown", + "id": "de0b8af4", + "metadata": { + "id": "de0b8af4" + }, + "source": [ + "- **Tuning nested parameters**\n", + "\n", + "Random Forest Regressor" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "id": "fc74f40f", + "metadata": { + "id": "fc74f40f" + }, + "outputs": [], + "source": [ + "regressor = RandomForestRegressor(n_estimators=20)\n", + "forecaster = make_reduction(regressor)" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "id": "266739e0", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "266739e0", + "outputId": "fd7f9966-1055-4487-fc06-0981446719af" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'estimator': RandomForestRegressor(n_estimators=20),\n", + " 'pooling': 'local',\n", + " 'transformers': None,\n", + " 'window_length': 10,\n", + " 'estimator__bootstrap': True,\n", + " 'estimator__ccp_alpha': 0.0,\n", + " 'estimator__criterion': 'squared_error',\n", + " 'estimator__max_depth': None,\n", + " 'estimator__max_features': 1.0,\n", + " 'estimator__max_leaf_nodes': None,\n", + " 'estimator__max_samples': None,\n", + " 'estimator__min_impurity_decrease': 0.0,\n", + " 'estimator__min_samples_leaf': 1,\n", + " 'estimator__min_samples_split': 2,\n", + " 'estimator__min_weight_fraction_leaf': 0.0,\n", + " 'estimator__n_estimators': 20,\n", + " 'estimator__n_jobs': None,\n", + " 'estimator__oob_score': False,\n", + " 'estimator__random_state': None,\n", + " 'estimator__verbose': 0,\n", + " 'estimator__warm_start': False}" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "forecaster.get_params()" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "id": "b98459bb", + "metadata": { + "id": "b98459bb" + }, + "outputs": [], + "source": [ + "nested_params = {\"window_length\": list(range(2,21)),\n", + " \"estimator__max_depth\": list(range(5,16))}" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "id": "8f5abf2b", + "metadata": { + "id": "8f5abf2b" + }, + "outputs": [], + "source": [ + "cv = SlidingWindowSplitter(initial_window=60, window_length=30)\n", + "nrcv = ForecastingRandomizedSearchCV(forecaster, strategy=\"refit\", cv=cv,\n", + " param_distributions=nested_params,\n", + " n_iter = 5, random_state=42)" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "id": "7f6653a1", + "metadata": { + "id": "7f6653a1" + }, + "outputs": [], + "source": [ + "nrcv.fit(y_train)\n", + "y_pred = nrcv.predict(fh_abs)" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "id": "b8822ac3", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "b8822ac3", + "outputId": "186ef5d8-03b0-4177-f336-64df3e6b1d42" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'window_length': 5, 'estimator__max_depth': 8}" + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "nrcv.best_params_" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "id": "9125c788", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "9125c788", + "outputId": "da1e94f8-f8bb-4f30-b70c-db62fc086120" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0.01392739416525403" + ] + }, + "execution_count": 61, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "nrcv.best_score_" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "id": "1adc9ae3", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 346 + }, + "id": "1adc9ae3", + "outputId": "3df3413f-592a-40e1-9a8d-312c2e831182" + }, + "outputs": [ + { + "data": { + "image/png": "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eVzvvJQDjBpra9+yp1rPbPxS804pzKqqk3M9AQAdRbPTyLVr12rw4ME699xz9ec//1nvvfee3nvvPT3//PM699xzNWTIEL322mt64YUXdPbZZ+vZZ5/Vww8/3CIP/eabb+r888/X8OHDVVJSouuuu067du1KWvenP/1J06ZN0/HHH69zzjlHa9asSVpTVVWlm2++WSNHjtTw4cM1Z84c7dmzJ2nd+++/rwsvvFAnnHCCJk6cqEcffZSWDgAAAKCTMgyjrrV8f9JptVpkcznk6uLSnuqAXF1ccridsrsdyvO4FLJbledxyeZyyGrN/j+z0r1f/Xunej93jl3LSncm7lO/0rOhBas2a05JoRZOLU583eOya+HUYs0c2U8Rf0hVXp9sobCqvD6FfUFFItH9QWeU//4BAHRYRqyZ/y82a9Ys5eTk6P7770/59Xnz5ikSiWjp0qWSpCuvvFKfffaZXnvtteY/raR33nlHl112mc4991ydffbZ8nq9euihhxSNRvXyyy8rJydHkvTKK6/o+uuv109+8hONHj1aq1at0vPPP6+nnnpKw4YNS9xv5syZ2r59u+bPny+n06kHH3xQFotFzz//vGy2ugLZTz/9VOeee67GjRunSy65RP/+97913333ad68eZo5c2azP0skEtXevTUH9f1or2w2i7p2zdW+fTUKhzn0HI1jvyBT7BVkg/2CTLFXUF/K6emBiBx2q5as2ZY4D3Nkf49eu2q07l+7Q8v2t403nHwejcaarAw9mPcbM6Crnv3hSep/1xume75w2cn638+9SZWekrT03OM048TvKMdhNVV6xoJhhhW1MH62IBvsF2SKvWLWrVtuRn/w2OwW+H/84x+68cYb03795JNP1i9+8YvE70899VTdc889zX27hFdeeUV9+/bV3XffnfjT0W7duunSSy/VRx99pBEjRkiSli5dqjPPPFNz586VJI0ePVpbt27VL3/5Sz322GOSpA8++EClpaVauXKlSkpKJEmFhYWaPn26Xn/9dU2fPl2StHLlSnXt2lX333+/HA6HxowZo7179+rhhx/WjBkz5HA4DvpzAQAAAGhd6VrVG5ue7nHZtXbWWD23abdpqNCCSYP0i799YgoZvb6Q7li9VT1yHZpx0neUa7cm7lE/ZGyp99v2dY26uu1J53rGBxhJ0vL1O03h7MyR/eSrDqiq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+jW0ePoQLSst052rtyZe1zvPqQuH9dXP136iPotez3pIUDga045vazWnpNC0Nn6e5nlD+2r3baep/LbT9NGNExQMR5LWZvP5slnb1GT30wf3UjgUVZW3VrZQWFVen8K+INUQAAAAMOlwFaBTpkzR8ccfrzlz5mjevHlyOp169NFH5XA49J//+Z+SpP/6r//Sj370I91+++0644wz9M477+gvf/mLHnjggcR9evfurfPOO0/33nuvLBaLjjjiCD3yyCPKy8vTRRddlFh30UUX6fe//72uueYaXX311frqq69077336qKLLtIRRxxxyD8/AABoOVarRYbDJneOLVFN6Q9E5LBbtWTNNi0r3SmbxVDZLZOTWtKbG2rGv5auujFdpWa6Ksl4KFp/bXZDgmzyByKaP/FoSTK1k18wtK8GdXertsonW0yqCoRksRiaP7HItDZVZWi6z5fN90KqC23XpW11L5KvOqBYLKZIpOmhUAAAADg8dbgA1GKx6NFHH9XixYu1cOFChUIhjRgxQk899ZR69uwpSRoxYoSWLVumBx98UM8995z69u2ru+66S2eccYbpXrfeeqtyc3P1i1/8QjU1NTrxxBP161//2jQdvqCgQL/97W9155136pprrlFubq7OO+88zZs375B+bgAA0LKsVotcXZyNtLU3PhH9YEPNxgb5LFi1WRvmlJhCv0E9c7WvNpTRUKJMhgSV9PfUVU0GQnUBotWi68YN0ILJR6vCF67XTh4wVVRGIjH5qgNJa/2husrQ+KCmdM8Qvz67ZEDie9zU8z6z8UvNO6WwyWcDAAAAUulwAagkdevWTT//+c8bXTN58mRNnjy50TUOh0Pz58/X/PnzG11XVFSk3/zmN9k+JgAAaMcMh01L1mxPhHBS6rb21gw1F7+1Ta9dNTqpuvGCoX3ltBiaW2IOGSXD9ByNnRfa+JCgohTBZlTyBVXlD8lmMRLBaCqp1qaqDE33+XZ5fbpp0iAZavp7MaekUDNH9pOvOqCq2mCTzwYAAAA0ZMT4t8c2E4lEtXdvTVs/Rquw2Szq2jVX+/bVcCgvmsR+QabYK8hGY/vFMAzleVzqs2i1KTw8rneeXrxipIruftO0/oXLTtb/fu5NCjWP6dVFG+aU6IG1OxKhXXwKfP1r8SDvpolF8ocicjltByonAxHFFDNdq/WHFQuGFYlEE4OY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", + "text/plain": [ + "<Figure size 1600x400 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_series(y_train, y_test, y_pred, labels=[\"y_train\", \"y_test\", \"y_pred\"]);" + ] + }, + { + "cell_type": "markdown", + "id": "d145a0d6", + "metadata": { + "id": "d145a0d6" + }, + "source": [ + "## 4. New forecasting functionalities" + ] + }, + { + "cell_type": "markdown", + "id": "ca9f4d37", + "metadata": { + "id": "ca9f4d37" + }, + "source": [ + "### Transformers" + ] + }, + { + "cell_type": "markdown", + "id": "39f1096f", + "metadata": { + "id": "39f1096f" + }, + "source": [ + "**`Deseasonalizer`**" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "id": "29b339f5", + "metadata": { + "id": "29b339f5" + }, + "outputs": [], + "source": [ + "transformer = Deseasonalizer(sp=4) #removing seasonality\n", + "y_train_transformed = transformer.fit_transform(y_train)" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "id": "c1e883b4", + "metadata": { + "id": "c1e883b4" + }, + "outputs": [], + "source": [ + "y_train_inversed = transformer.inverse_transform(y_train_transformed) #inversing the seasonality removal" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "id": "35ccf61b", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "35ccf61b", + "outputId": "e614eadc-8549-4377-e5b3-59a9e79a2f4d", + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 65, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#after inversing the transformation, values are again on the same scale as they were before\n", + "(np.round(y_train.values, 3) == np.round(y_train_inversed.values, 3)).all()" + ] + }, + { + "cell_type": "markdown", + "id": "206c9fe5", + "metadata": { + "id": "206c9fe5" + }, + "source": [ + "**`BoxCoxTransformer`**" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "id": "3e14f992", + "metadata": { + "id": "3e14f992" + }, + "outputs": [], + "source": [ + "forecaster = ThetaForecaster(sp=4)\n", + "transformer = BoxCoxTransformer(sp=4) #Box-Cox power transformation\n", + "y_train_transformed = transformer.fit_transform(y_train)" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "id": "2aca2946", + "metadata": { + "id": "2aca2946" + }, + "outputs": [], + "source": [ + "forecaster.fit(y_train_transformed)\n", + "y_pred = forecaster.predict(fh=fh_abs)\n", + "y_pred_inversed = transformer.inverse_transform(y_pred)" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "id": "a22cbb57", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 350 + }, + "id": "a22cbb57", + "outputId": "8c3dd787-a46f-4761-a080-2e86e7b53634" + }, + "outputs": [ + { + "data": { + "image/png": "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N0VEREREVFMqlrtflRSHjydlXnT/zju6t4ROFDDT3DYk05Nl7URERET1R9QB0AceeCDmACgRERERUV0IlLr7/RKECuXualFAsxrq32k/H+j0OjwsayciIiKqp6IOgE6bNq0274OIiIiI6KIFJrsb4tRypiYgKMrda6N/Z3lZOwOfRERERPXRRQ9BIiIiIiKqS4FsT0EA4uKVk937t03Gpj/2CpvpuWPKAADAql0Xytqnm9OQndkKjlIXbHZ32GAnA51EREREDctFB0CLiorwww8/wGazhS33ueWWWy72JcL68MMP8dprr+HYsWMwGAzo2rUrVq1ahbi4OADAtm3bsHz5chQWFqJly5a499578Yc//EFxDbfbjWXLluHjjz9GWVkZevbsiUcffRTt2rVT7Dt27BiWLFmCffv2IT4+HjfffDNmzpwJrVZbK++NiIiIqD4JLievT+XdFbM9DVoVcrcfU0x2P/JrGZINmpBy90NnSzF49dd4auzVKBqegRKnB8Y4DexOD/t3EhERETUy1Q6AulwuzJ49G1u3boXf74cgCPL/EAf3Cq2NAOjf/vY3vPjii7j//vvRo0cPFBcXY/fu3fD5fACAb7/9FlOnTsVtt92GuXPn4p///CfmzZuH+Ph4XH/99fJ1lixZgi1btmDOnDm44oorsGbNGkycOBGbN29GYmIiAKCkpAR333032rZti5UrV+KXX35Bbm4unE4nFixYUOPvjYiIiOhSiCaoGa6c3O70QnJ75QBhXak42EgtCiicl4WV+YWKfVWVu397yoJBbUxolqCDxVIGr6du3xcRERER1bxqB0Cfe+455OXlYebMmejZsycmTJiA3NxcNG/eHK+99hrOnj2L//u//6vJewUAFBQUYNWqVVi9ejUGDx4sr48aNUr+97/97W/o1q0bHnvsMQBAv379cOrUKaxYsUIOgBYVFeG9997DwoULcdtttwEAunbtiqFDh2Ljxo2YPHkyAGDjxo0oKyvDqlWrYDKZAAA+nw+LFy/GfffdhyuuuKLG3yMRERFRbakqqFlZOXmgRHz20HQ4Sl3w+6VLmhla2WCjLi0ScbbUHVLqDlwodw8ebBT8XtwONwCgHiW3EhEREVENEqv7xM8//xy33nor7r33XrRv3x4AcMUVV2DAgAFYu3YtEhMT8dZbb9XYjQZ88MEHuOqqqxTBz2Bu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EREREREZLRZAiYiIiIiIiIiIyGixAEpERERERERERERGiwVQIiIiIiIiIiIiMlosgBIREREREREREZHRYgGUiIiIiIiIiIiIjBYLoERERERERERERGS0WAAlIiIiIiIiIiIio8UCKBERERERERERERktFkCJiIiIiIiIiIjIaLEASkREREREREREREaLBVAiIiIiIiIiIiIyWiyAEhERERERERERkdFiAZSIiIiIiIiIiIiMFgugREREREREREREZLRYAJUpJSUFo0aNgoeHBzp37owlS5aguLi4todFRERERERERHWQQqGAqakJFApFlW2P2qX/Vt1Xfntd6Gvs66v5sUn/re446huz2h7A8yAnJwcjRoyAg4MDVq1ahczMTCxatAhqtRqzZs2q7eERERERERERUR1hamoCRQMFrCwtkF1UCFvLhlAXl0AA0NDCXGwrKCqGohgQLAArSwv8WZgH28YNUCij75Pa5azvWfc19vXV1tisLMzFrOTrub6ComIIagGlpWW188tRi1gAleHf//438vPzsXr1atja2gIASktLMWfOHISGhqJZs2a1O0AiIiIiIiIiqnWmpiZo2NgCi38/iFWXjyK7uBA+L76Kvb3GYsXFw2KbrUVDzPHshdEuvlicXL2+hliGsYyN++LJ67O1aIgwN39Etu2GwtzielcEVQiCINT2IOq6wMBA2NjY4KuvvhLbVCoVfHx8sGDBAgwaNKhayy0tLcPDh/mGGmadYmZmAju7Rvjrr3xoNPXrl4r0x7yQXMwK6YN5IbmYFdIH80JyMSv1k1kjU3x55QjmXtgntv3UfSROP7iL+Rf2S/r+1H0kzjxIx7xq9jXEMoxlbNwXT16f1sz2PTGp1ZvQ5JfqvPY8atKkEUxNnzzDJ68AlSE1NRWDBw+WtCmVSjRt2hSpqalPtWwzM+OchlUbPjkhJGJeSC5mhfTBvJBczArpg3khuZiV+keheHS78arLR8W2Fy0boXtzF4w68oOkb0Xt+vQ1xDKMZWzcF/LatVZdPoqo9t1RUFyE+nRJJAugMqhUKiiVSp12Gxsb5OTkVHu5JiYK2Nk1epqh1XlKZcPaHgI9R5gXkotZIX0wLyQXs0L6YF5ILmalfvmzMA/ZxYXi1y9bNcafamlbZe369DXEMoxlbNwX8tq1sosLkVOiRlNb6wpfN1YsgNaisjIB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", + "text/plain": [ + "<Figure size 1600x400 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_series(y_train, y_test, y_pred, labels=[\"y_train\", \"y_test\", \"y_pred_transformed\"]);" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "id": "470037d2", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 346 + }, + "id": "470037d2", + "outputId": "6922ba2a-6eaf-4813-ba7c-5478fd1f4821" + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABUAAAAFkCAYAAADhdJEIAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAC2OklEQVR4nOzdeXwTdf4/8NdMria90oNTrrZQDkFAuQlnQQSPZV28vi6rgqiLnIILBUQRlIKKSJHlEHRXRVHRnwdVqYJgEXFZQGQFuYqgUMuVNm1zZ35/lAyZJmmT0tKD1/Px4FE6+WQyEz9EePd9CJIkSSAiIiIiIiIiIiKqh8SavgAiIiIiIiIiIiKi6sIAKBEREREREREREdVbDIASERERERERERFRvcUAKBEREREREREREdVbDIASERERERERERFRvcUAKBEREREREREREdVbDIASERERERERERFRvcUAKBEREREREREREdVbDIASERERERERERFRvaWu6Qu4lkmSBI9HqunLqDaiKNTr+6Oqxf1CoeJeoXBwv1CouFcoHNwvFCruFQoH9wuFinvlMlEUIAhChesYAK1BHo+ECxeKa/oyqoVaLSIuLhKFhSVwuTw1fTlUy3G/UKi4Vygc3C8UKu4VCgf3C4WKe4XCwf1CoeJeUYqPj4RKVXEAlCXwREREREREREREVG8xAEpERERERERERET1FgOgREREREREREREVG8xAEpERERERERERET1Focg1QEejxtut7umLyMsHo8Am00Fh8MOt5uTyah83C91m0qlgiiqavoyiIiIiIiIiAJiALQWkyQJhYUXYLUWA6h7QaFz50R4PJxIRqHhfqnLBOj1kYiJiYcgVDx9j4iIiIiIiOhqYgC0FrNai2G1FiEqygidLgJA3QosqFQCs/koZNwvdZUEu92GoiIzNBodDIaomr4gIiIiIiIiIgUGQGspSZJQVGRGREQkoqJia/pyKkWtFuFyMaOPQsP9UndpNDq4XE4UFZmh10cyC5SIiIiIiK4ZgiBAFAV4PBIkqeKknnDXU9VgALSW8ng88HjciIgw1PSlEBFVKCLCAJutGB6PByoV+4ESEREREVH9plKJMOjc0Ebo4LGZIUYY4bDZUGJXwe32+AU6K1pP1YsB0FrK4ykdesTBIkRUF3g/qzweNwOgRERERERUL3mDmoIAxESJ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EREREREREdGTjwlQsgu9XoCnq6PVc2fO2X0JP8U1N5pP01RC0tPVESMivTEwrB5UeQXIVRZCIZchp0ADuVxmckV15d+JSq1K89C+Nq/KTkRERERERERETw2ZwKzOY6PT6fHgQf7jPg27Ubg64ZOUK5ix86LRtsVdGiKmaR24ODmISUZ1gQ4CBLg6KySJR5lWB0HhADcXabtQqDU7p6ZMJoNcLoNeLzw0UWmury37IPtSKOSoWrUS/vorH1ot500l8xgrZAvGC1mLsUK2YLyQtRgrZAvGC1mLsSJVrVolODg8fIZPVoCS3QiFWkxo4wMAD63eLF5RaajSlFRZanTIVZtoN3dsG1ZUN9eXq7ITEREREREREVU8TICS3eh0eqjyDMPJGyBHrYGHiyOUao3FuTOZkCQiIiIiIiIiorLCBCjZlU6nB1SFUGm1qOlZCVlZ+dBqWJJNRERERERERESPx8MHyROVgmHEOqfSJCIiIiIiIiKix4kJUCIiIiIiIiIiIqqwmAAlIiIiIiIiIiKiCosJUCIiIiIiIiIiIqqwmAAlIiIiIiIiIiKiCosJUCIiIiIiIiIiIqqwmAAlIiIiIiIiIiKiCksmCILwuE/iWSUIAvT6ivv2OzjIodPpH/dp0FOC8ULWYqyQLRgvZC3GCtmC8ULWYqyQLRgvZC3Gyj/kchlkMtlD+zEBSkRERERERERERBUWh8ATERERERERERFRhcUEKBEREREREREREVVYTIASERERERERERFRhcUEKBEREREREREREVVYTIASERERERERERFRhcUEKBEREREREREREVVYTIASERERERERERFRhcUEKBEREREREREREVVYTIASERERERERERFRhcUEKBEREREREREREVVYTIASERERERERERFRhcUEKBEREREREREREVVYTIA+Q65evYqpU6eic+fOCAgIQKdOnYz6FBYWYsGCBYiMjETjxo3x73//G4cPHzbq5+fnZ/SnRYsWRv327NmDrl27omHDhmjVqhUWL14MnU5n1E+tVuPTTz/F66+/jkaNGiE8PBxDhw5FamqqUd+UlBSMHTsW7du3h5+fH2bMmFHKd4TMsWesAEBaWhqGDx+O0NBQBAUFoUuXLkhJSRG3Hz161GRMjR492mhf1saKTqdDUlISevfujfDwcISFhSEmJgbHjx9/xHeHSrJX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XLD5fSFj9ooVgy+//BJr1qxBZmYm6tSpg0GDBkmS5YmJidi6dStu3rwJjUaDOnXq4M0330RcXJxRVZe1sWLpGurUqYPdu3eX5q0hE+wdL4ZfGPfv3y/Om2Pr8Qyys7OxYsUK/Pzzz8jMzIRWq0X16tWxcuVKyS+T9+/fx+zZs3Hq1Cncu3cPlStXRv369dGvX79STTxPppV3rABFMdCiRQv07dsX48ePN3tu1saKKe+//z7OnDmDbdu2WexHtrFnvJw9exaLFi3C2bNnoVar4eXlhb59+6Jz585mj3/06FH06dMHGzZsMBrhYku8LFmyBEuXLjXaPz+L7MeesTJ27FgcOXIE2dnZqFu3Lt5++2306dPHaBGkO3fu4IMPPsDBgwehUCgQHR2NhIQEo4otPrc8eR5HvCiVSnz88cfYvn078vLyEBgYiPHjxxt9MafVavH1119j48aNSE9PF4fIz5s3z2hE3Jw5c3DgwAHcunULCoUCdevWRZcuXdCrVy8udmMnbdu2xc2bN01u++WXX1C3bl0AwPfff4+kpCTcunUL3t7eGDNmjFj5a5Cbm4s5c+Zg586d0Gq1iIyMxOTJkyWVgn5+fmbPpeTvuZmZmVi2bBn27duHe/fuQa/Xw8vLC0lJSXjxxRctXldMTAzc3NyQmJhosR9Zr7xjJSUlBfPnz8fVq1ehUCgQFhaGsWPHGn1JD/CZpTgmQOmJdOzYMfTv3x9Dhw7F8OHDH/fp0BOMsUK22LZtG8aNG4e5c+dyag2yiLFCtmC8kLX43EK2SEtLQ/fu3dGxY0fMmjXrcZ8OPcESExOxZMkSJCUlGRUQERX3LD+zcA5QeiKFhoZi4sSJWLx4MTZv3vy4T4eeYIwVskWnTp3Qv39/TJ48WTK3DlFJjBWyBeOFrMXnFrKFj48PFixYgI0bN+LTTz993KdDT7DBgwejXbt2iI+Pl0yhQVTSs/zMwgpQIiIiIiIiIiIiqrBYAUpEREREREREREQVFhOgREREREREREREVGExAUpEREREREREREQVFhOgREREREREREREVGExAUpEREREREREREQVFhOgREREREREREREVGExAUpEREREREREREQVFhOgREREREREREREVGExAUpEREREREREREQVFhOgREREREREREREVGH9Pxq/Ao8rYwEXAAAAAElFTkSuQmCC", + "text/plain": [ + "<Figure size 1600x400 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_series(y_train, y_test, y_pred_inversed, labels=[\"y_train\", \"y_test\", \"y_pred_inversed_transformation\"]);" + ] + }, + { + "cell_type": "markdown", + "id": "90d4d899", + "metadata": { + "id": "90d4d899" + }, + "source": [ + "### Pipelines" + ] + }, + { + "cell_type": "markdown", + "id": "4affacfa", + "metadata": { + "id": "4affacfa" + }, + "source": [ + "- **`TransformedTargetForecaster` - simple pipeline**" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "id": "02dc7cdd", + "metadata": { + "id": "02dc7cdd" + }, + "outputs": [], + "source": [ + "#two transformers and a forecaster\n", + "forecaster = TransformedTargetForecaster(\n", + " [(\"deseasonalize\", Deseasonalizer(sp=4)),\n", + " (\"box_cox\", BoxCoxTransformer(sp=4)),\n", + " (\"forecast\", ThetaForecaster(sp=4))]\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "id": "db4c544e", + "metadata": { + "id": "db4c544e" + }, + "outputs": [], + "source": [ + "forecaster.fit(y_train)\n", + "y_pred = forecaster.predict(fh_abs)" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "id": "244d1c58", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 346 + }, + "id": "244d1c58", + "outputId": "b04b9da7-de05-4942-b49a-e6d5644d7843" + }, + "outputs": [ + { + "data": { + "image/png": "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xKZKw8kB9Z2M2nRIKs1LuITprhbiMPP7haU4lPY3glzN1ZatPCS9urKV38pe9eeDXC2w0KOLZEj7Ig9LTHbqiHJ5WbUdnRyqTkRERERERET0bOEQeNIJfX095BaX1fj0pvIlQdW9OKhyh2TlN7gD0qcvlcPMTZsZYsBrL0reqF7dkPTqymr7VvbKQ9o5fJ2IiIiIiIiI6NnHDlDSiYoKAabNGmk8d+aqxGv4yb+3ynya6jokTZs1wnRXC0x26ojighI8LCqFob4e8kvKoK+vp/aN6kX/31GpKC57bFmt38pORERERERERET/M/QE9urUm/LyCjx4UFjfu6Ezhs0a4/PkG1j6y1WVdRs9beHd0wxNGxuInYzyknIIENCsiaGk41FPUQ7B0ABGTaXLhVJFtXNq6unpQV9fDxUVwmM7Kqsrq802SLcMDfXRsmVz/PNPIRQKzptK1WNWSBvMC2mKWSFtMC+kKWaFtMG8kKaYFalWrZrDwODxM3zyCVDSGaFUgbn9OwPAY5/erPxEpfIpTclTlmXleChXs7y6urV4o3p1ZflWdiIiIiIiIiKihocdoKQz5eUVKC5QDifvgnx5GUyaNkKRvKzGuTPZIUlERERERERERE8LO0BJp8rLK4DiUhQrFGhj2hy5uYVQlPGRbCIiIiIiIiIiqh+PHyRPVAvKEeucSpOIiIiIiIiIiOoTO0CJiIiIiIiIiIiowWIHKBERERERERERETVY7AAlIiIiIiIiIiKiBosdoERERERERERERNRgsQOUiIiIiIiIiIiIGix2gBIREREREREREVGDpScIglDfO/G8EgQBFRUN9/QbGOijvLyivneD/kcwL6QpZoW0wbyQppgV0gbzQppiVkgbzAtpiln5L319Pejp6T22HDtAiYiIiIiIiIiIqMHiEHgiIiIiIiIiIiJqsNgBSkRERERERERERA0WO0CJiIiIiIiIiIiowWIHKBERERERERERETVY7AAlIiIiIiIiIiKiBosdoERERERERERERNRgsQOUiIiIiIiIiIiIGix2gBIREREREREREVGDxQ5QIiIiIiIiIiIiarDYAUpEREREREREREQNFjtAiYiIiIiIiIiIqMFiBygRERERERERERE1WOwAfY7cvHkTixYtwvDhw2FtbY1hw4aplCktLcXatWvh6uqK7t2745133kFKSopK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", + "text/plain": [ + "<Figure size 1600x400 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_series(y_train, y_test, y_pred, labels=[\"y_train\", \"y_test\", \"y_pred\"]);" + ] + }, + { + "cell_type": "markdown", + "id": "ee3b3b82", + "metadata": { + "id": "ee3b3b82" + }, + "source": [ + "- **ForecastingPipeline - pipeline with exogenous variables**" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "id": "084fc9ad", + "metadata": { + "id": "084fc9ad" + }, + "outputs": [], + "source": [ + "forecaster = ForecastingPipeline(\n", + " [(\"hampel\", HampelFilter()),\n", + " (\"log\", LogTransformer()),\n", + " (\"forecaster\", ThetaForecaster(sp=4))])" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "id": "44be0974", + "metadata": { + "id": "44be0974" + }, + "outputs": [], + "source": [ + "forecaster.fit(y_train, X_train)\n", + "y_pred = forecaster.predict(fh=fh_abs, X=X_test)" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "id": "fc1cd3f2", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 346 + }, + "id": "fc1cd3f2", + "outputId": "967df069-c71f-4095-85a5-03a6e13305b7", + "scrolled": true + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABUAAAAFkCAYAAADhdJEIAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAACnFElEQVR4nOzdeXhU5dk/8O85s2UmyWRC2GULkQAqAoqswxoQwaW81vW1VIUivshasRCgKEolUhcEpCiCtioV159aUiUKQoMUSwGpFSSQICjEsE0yyWxnZs7vj2EOczIzyUwWsvD9XJcXcuaZkzPxaapf7vu5BVmWZRARERERERERERE1Q2JDPwARERERERERERFRfWEASkRERERERERERM0WA1AiIiIiIiIiIiJqthiAEhERERERERERUbPFAJSIiIiIiIiIiIiaLQagRERERERERERE1GwxACUiIiIiIiIiIqJmiwEoERERERERERERNVsMQImIiIiIiIiIiKjZ0jb0A1zOZFmG3y839GPUG1EUmvXno7rF/UKx4l6heHC/UKy4Vyge3C8UK+4Vigf3C8WKe+UiURQgCEK16xiANiC/X8a5cxUN/Rj1QqsVkZqaiLIyB7xef0M/DjVy3C8UK+4Vigf3C8WKe4Xiwf1CseJeoXhwv1CsuFfUWrRIhEZTfQDKFngiIiIiIiIiIiJqthiAEhERERERERERUbPFAJSIiIiIiIiIiIiaLQagRERERERERERE1GxxCFIT4Pf74PP5Gvox4uL3C3C5NPB43PD5mu9kMo1GA1HUNPRjEBERERERERFRFAxAGzFZllFWdg5OZwWAphcinjkjwu9v7hPJBBiNiTCbW0AQqp86RkRERERERERElxYD0EbM6ayA01mOpCQLDIYEAE0rYNNohGZd/QnIcLtdKC+3QaczwGRKaugHIiIiIiIiIiKiShiANlKyLKO83IaEhEQkJaU09OPUiFYrwutt3hWgOp0BXq+E8nIbjMZEVoESERERERERXUYEQYAoCvD7Zchy9UVg8a6nusEAtJHy+/3w+31ISDA19KNQNRISTHC5KuD3+6HR8DxQIiIiIiIiouZOoxFhMvigTzDA77JBTLDA43LB4dbA5/OHBZ3Vraf6xQC0kfL7A0OPOGCn8Qv+M/L7fQxAiYiIiIiIiJqpYKgpCIA5SUTZnmfx8/6X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qewAsHrnxWrREzYn5o/qBgHxDzBipScRUfNW4wD0m2++QVpaGm6//Xb07dsXnTt3BgAcO3YM+/fvR7du3bB//37s379f9b5FixbV6oGJiIiIiIio6arc7h7tXM9oZ3geKinH8DVfYfktV6F4dCZsIaGmu8KNWUO6cIARERGp1DgAffPNN5W/37t3L/bu3at6/fDhwzh8+LDqmiAIDECJiIiIiIguM6GT3YWQdncg+rme1Z3hueeEDdZOlkD7emioKflgd0kcYERERIoaB6CHDh2qy+cgIiIiIiKiZibSZHdAULW7VxV0ZucexK6Z1ojT2ueNzFC1sYeSZZlhJxERKWocgBIRERERERFFE2my+6Auqdj0q+tjPtfzrt7tYRAFzLaGt7VHCz+JiIgqYwBKREREREREdaKqVncAKDhdgVSTLq5zPR0Xgk6vM3JbOxERUXViDkB79OgBQRDi/gIHDx6M+z1ERERERETUuIWGnaIoVNvqDtTiXE+wrZ2IiGou5gD0kUceCQtA8/LycOTIEVitVqSnpwMACgsLsXPnTnTr1g2jR4+u26clIiIiIiKiSyo06JRlOexcz1SjDj4ZyNl6BKsunNMZrdUduNjuHu+5nkRERDUVcwA6Y8YM1e83bdqEs2fP4pNPPkHXrl1Vrx09ehT3338/WrduXTdPSURERERERPWuuqpOl9sHvU6DnG0Fyrmen0zuj93Hz2NpDK3uQKDS89YNXyNv6kBkZ3VDaUi7O8NPIiKqD2JN37h+/Xr86le/Cgs/ASAjIwP33XcfXn311Vo9HBEREREREdU/jUaE1qhHssUISaeB2WKEMTkBK3YeQ7slecpfx8tcyrmeNqeElol6jMhIw+oqWt0jual7a3glP+w2R6Dd3eaE1+lh+ElERPWixkOQiouLodVGf7tWq0VxcXFNb09ERERERET1pHKlZ+Vp7ZGqOrWigK5pJqzKL1KutU02oKTcU+NWd57rSUREl0KNA9Bu3bph48aNuPXWW9GmTRvVa8XFxfjrX/+KzMzMWj8gERERERER1Y3K53dajDq4JB9yth1VprUHqzonbtynem+ksLPY7kbrJD1b3YmIqFGrcQCanZ2N3/zmNxg7dixGjx6Nzp07AwCOHTuGL774ArIsY/ny5XX2oERERERERBSf6io9M9JMODB3RExVnZHCzqqmugMXW93d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ormT5MbihkKYAbJc4cL8/vC58zJcoHvxir74/TyPz6Mzxzkzw5e5556Zc4aIiIiIiIiIqPlhByhpTVVVNcpLlMPJe6NYXgmDtq1QJq9scO5MdkgSEREREREREdHjwg5Q0qqqqmqgvALlCgU6G7ZDYWEpFJV8JJuIiIiIiIiIiJ6Mfx4kT9QIyhHrnEqTiIiIiIiIiIieJHaAEhERERERERERUbPFDlAiIiIiIiIiIiJqttgBSkRERERERERERM0WO0CJiIiIiIiIiIio2WIHKBERERERERERETVb7AAlIiIiIiIiIiKiZktHEAThSe/Es0oQBFRXN9/T37JlC1RVVT/p3aD/EcwLqYtZIU0wL6QuZoU0wbyQupgV0gTzQupiVv6rRQsd6Ojo/GM5doASERERERERERFRs8Uh8ERERERERERERNRssQOUiIiIiIiIiIiImi12gBIREREREREREVGzxQ5QIiIiIiIiIiIiarbYAUpERERERERERETNFjtAiYiIiIiIiIiIqNliBygRERERERERERE1W+wAJSIiIiIiIiIiomaLHaBERERERERERETUbLEDlIiIiIiIiIiIiJotdoASERERERERERFRs8UOUCIiIiIiIiIiImq22AH6DLl+/TqWLFmCsWPHwtzcHGPGjFEpU1FRgfXr18PR0RH9+vXD22+/jbS0NJVyMplM5c/gwYNVyv36669wc3ODpaUlhg4dis2bN6OqqkqlnFwux+eff44333wTffv2hb29PWbOnIn09HSVsqmpqQgODsaIESMgk8mwfPnyRp4Rqo82swIAWVlZmDVrFmxtbWFlZQVXV1ekpqaK60+cOFFnpj744AOVbamblaqqKoSHh8PDwwP29vaws7ODp6cnTp069Yhnh2rTVl727dtXZw5kMhmmT5+uUX1KRUVFCA0NxYgRI2BpaYlXX30VwcHByMnJUSkbGhqK0aNHw9raGgMGDMD48eORmJj4CGeGamvqrHh6etZbrvbPVpOs1HTw4EHIZLIGc0iNo83PotzcXAQFBcHR0RHW1tYYP348fvzxx3rrLi0thZOTE2QyGX7//XeV9ZrkJSkpCQEBAeL2IiIiNDwT9E+0mZX8/HwEBgZi4MCBsLa2hr+/P27evFlnuYCAAFhbW8POzg4LFy5ESUmJSjm2W54+TyIvAHDo0CFMnDgRVlZW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", + "text/plain": [ + "<Figure size 1600x400 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_series(y_train, y_test, y_pred, labels=[\"y_train\", \"y_test\", \"y_pred\"]);" + ] + }, + { + "cell_type": "markdown", + "id": "72ff0f21", + "metadata": { + "id": "72ff0f21" + }, + "source": [ + "### Automated model selection" + ] + }, + { + "cell_type": "markdown", + "id": "d4d6422c", + "metadata": { + "id": "d4d6422c" + }, + "source": [ + "- **`MultiplexForecaster` - finding the best forecaster**" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "id": "f6e4a51f", + "metadata": { + "id": "f6e4a51f" + }, + "outputs": [], + "source": [ + "forecaster = MultiplexForecaster(\n", + " forecasters=[\n", + " (\"theta\", ThetaForecaster(sp=4)),\n", + " (\"ets\", ExponentialSmoothing(trend=\"add\", sp=4)),\n", + " (\"autoarima\", AutoARIMA(sp=4)),\n", + " ],\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "id": "688b8fd9", + "metadata": { + "id": "688b8fd9" + }, + "outputs": [], + "source": [ + "cv = SlidingWindowSplitter(initial_window=60, window_length=30)\n", + "forecaster_param_grid = {\"selected_forecaster\": [\"theta\", \"ets\", \"autoarima\"]}\n", + "gscv = ForecastingGridSearchCV(forecaster, cv=cv, param_grid=forecaster_param_grid)" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "id": "010e1f5c", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 109 + }, + "id": "010e1f5c", + "outputId": "16d55de5-07e2-4136-a0b2-a3adfa4d4dc9" + }, + "outputs": [ + { + "data": { + "text/html": [ + "<style>#sk-e74645bf-5326-44da-8525-5bcee84bf3fb {color: black;background-color: white;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb pre{padding: 0;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-toggleable {background-color: white;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb label.sk-toggleable__label-arrow:before {content: \"βΈ\";float: left;margin-right: 0.25em;color: #696969;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"βΎ\";}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-estimator:hover {background-color: #d4ebff;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 2em;bottom: 0;left: 50%;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-item {z-index: 1;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-parallel::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 2em;bottom: 0;left: 50%;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-parallel-item {display: flex;flex-direction: column;position: relative;background-color: white;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-parallel-item:only-child::after {width: 0;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;position: relative;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-label label {font-family: monospace;font-weight: bold;background-color: white;display: inline-block;line-height: 1.2em;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-label-container {position: relative;z-index: 2;text-align: center;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-e74645bf-5326-44da-8525-5bcee84bf3fb div.sk-text-repr-fallback {display: none;}</style><div id='sk-e74645bf-5326-44da-8525-5bcee84bf3fb' class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>ForecastingGridSearchCV(cv=SlidingWindowSplitter(initial_window=60,\n", + " window_length=30),\n", + " forecaster=MultiplexForecaster(forecasters=[('theta',\n", + " ThetaForecaster(sp=4)),\n", + " ('ets',\n", + " ExponentialSmoothing(sp=4,\n", + " trend='add')),\n", + " ('autoarima',\n", + " AutoARIMA(sp=4))]),\n", + " param_grid={'selected_forecaster': ['theta', 'ets',\n", + " 'autoarima']})</pre><b>Please rerun this cell to show the HTML repr or trust the notebook.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item sk-dashed-wrapped\"><div class='sk-label-container'><div class=\"sk-label sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('79a611c5-a2d7-439b-8146-8e7d5fba8d02') type=\"checkbox\" ><label for=UUID('79a611c5-a2d7-439b-8146-8e7d5fba8d02') class='sk-toggleable__label sk-toggleable__label-arrow'>ForecastingGridSearchCV</label><div class=\"sk-toggleable__content\"><pre>ForecastingGridSearchCV(cv=SlidingWindowSplitter(initial_window=60,\n", + " window_length=30),\n", + " forecaster=MultiplexForecaster(forecasters=[('theta',\n", + " ThetaForecaster(sp=4)),\n", + " ('ets',\n", + " ExponentialSmoothing(sp=4,\n", + " trend='add')),\n", + " ('autoarima',\n", + " AutoARIMA(sp=4))]),\n", + " param_grid={'selected_forecaster': ['theta', 'ets',\n", + " 'autoarima']})</pre></div></div></div><div class=\"sk-parallel\"><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-serial\"><div class='sk-item'><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('23b5532d-08fe-4e23-a723-d54c83f0985d') type=\"checkbox\" ><label for=UUID('23b5532d-08fe-4e23-a723-d54c83f0985d') class='sk-toggleable__label sk-toggleable__label-arrow'>SlidingWindowSplitter</label><div class=\"sk-toggleable__content\"><pre>SlidingWindowSplitter(initial_window=60, window_length=30)</pre></div></div></div></div></div></div><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-serial\"><div class=\"sk-item sk-dashed-wrapped\"><div class=\"sk-parallel\"><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-serial\"><div class='sk-item'><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('1f0258b3-6771-4626-b5a3-b68b294da6d4') type=\"checkbox\" ><label for=UUID('1f0258b3-6771-4626-b5a3-b68b294da6d4') class='sk-toggleable__label sk-toggleable__label-arrow'>ThetaForecaster</label><div class=\"sk-toggleable__content\"><pre>ThetaForecaster(sp=4)</pre></div></div></div></div></div></div><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-serial\"><div class='sk-item'><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('b6334082-f211-4343-ab1a-1c994183edf6') type=\"checkbox\" ><label for=UUID('b6334082-f211-4343-ab1a-1c994183edf6') class='sk-toggleable__label sk-toggleable__label-arrow'>ExponentialSmoothing</label><div class=\"sk-toggleable__content\"><pre>ExponentialSmoothing(sp=4, trend='add')</pre></div></div></div></div></div></div><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-serial\"><div class='sk-item'><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('eb63c10a-471f-40e3-9a55-b4322a91b6b9') type=\"checkbox\" ><label for=UUID('eb63c10a-471f-40e3-9a55-b4322a91b6b9') class='sk-toggleable__label sk-toggleable__label-arrow'>AutoARIMA</label><div class=\"sk-toggleable__content\"><pre>AutoARIMA(sp=4)</pre></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div>" + ], + "text/plain": [ + "ForecastingGridSearchCV(cv=SlidingWindowSplitter(initial_window=60,\n", + " window_length=30),\n", + " forecaster=MultiplexForecaster(forecasters=[('theta',\n", + " ThetaForecaster(sp=4)),\n", + " ('ets',\n", + " ExponentialSmoothing(sp=4,\n", + " trend='add')),\n", + " ('autoarima',\n", + " AutoARIMA(sp=4))]),\n", + " param_grid={'selected_forecaster': ['theta', 'ets',\n", + " 'autoarima']})" + ] + }, + "execution_count": 78, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gscv.fit(y_train)" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "id": "c2839de5", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "c2839de5", + "outputId": "02387375-cf9e-4eb7-d022-d7ad434bbb0e" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'selected_forecaster': 'ets'}" + ] + }, + "execution_count": 79, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gscv.best_params_" + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "id": "4f1d6928", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 94 + }, + "id": "4f1d6928", + "outputId": "4d970c4d-f7ac-46a3-c258-460d92f3fa48" + }, + "outputs": [ + { + "data": { + "text/html": [ + "<style>#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 {color: black;background-color: white;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 pre{padding: 0;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-toggleable {background-color: white;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 label.sk-toggleable__label-arrow:before {content: \"βΈ\";float: left;margin-right: 0.25em;color: #696969;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"βΎ\";}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-estimator:hover {background-color: #d4ebff;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 2em;bottom: 0;left: 50%;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-item {z-index: 1;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-parallel::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 2em;bottom: 0;left: 50%;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-parallel-item {display: flex;flex-direction: column;position: relative;background-color: white;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-parallel-item:only-child::after {width: 0;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;position: relative;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-label label {font-family: monospace;font-weight: bold;background-color: white;display: inline-block;line-height: 1.2em;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-label-container {position: relative;z-index: 2;text-align: center;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-2c671cf3-e0c0-47fa-8287-d8e10422d592 div.sk-text-repr-fallback {display: none;}</style><div id='sk-2c671cf3-e0c0-47fa-8287-d8e10422d592' class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>MultiplexForecaster(forecasters=[('theta', ThetaForecaster(sp=4)),\n", + " ('ets',\n", + " ExponentialSmoothing(sp=4, trend='add')),\n", + " ('autoarima', AutoARIMA(sp=4))],\n", + " selected_forecaster='ets')</pre><b>Please rerun this cell to show the HTML repr or trust the notebook.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item sk-dashed-wrapped\"><div class='sk-label-container'><div class=\"sk-label sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('cf93a545-84b5-4df2-8433-9e8e7e8d432a') type=\"checkbox\" ><label for=UUID('cf93a545-84b5-4df2-8433-9e8e7e8d432a') class='sk-toggleable__label sk-toggleable__label-arrow'>MultiplexForecaster</label><div class=\"sk-toggleable__content\"><pre>MultiplexForecaster(forecasters=[('theta', ThetaForecaster(sp=4)),\n", + " ('ets',\n", + " ExponentialSmoothing(sp=4, trend='add')),\n", + " ('autoarima', AutoARIMA(sp=4))],\n", + " selected_forecaster='ets')</pre></div></div></div><div class=\"sk-parallel\"><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-serial\"><div class='sk-item'><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('cd38cb2a-45a2-49f6-8d78-9a9eb88487b8') type=\"checkbox\" ><label for=UUID('cd38cb2a-45a2-49f6-8d78-9a9eb88487b8') class='sk-toggleable__label sk-toggleable__label-arrow'>ThetaForecaster</label><div class=\"sk-toggleable__content\"><pre>ThetaForecaster(sp=4)</pre></div></div></div></div></div></div><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-serial\"><div class='sk-item'><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('a1c840ac-5601-46aa-8b32-f3b4ccca1706') type=\"checkbox\" ><label for=UUID('a1c840ac-5601-46aa-8b32-f3b4ccca1706') class='sk-toggleable__label sk-toggleable__label-arrow'>ExponentialSmoothing</label><div class=\"sk-toggleable__content\"><pre>ExponentialSmoothing(sp=4, trend='add')</pre></div></div></div></div></div></div><div class=\"sk-parallel-item\"><div class=\"sk-item\"><div class=\"sk-serial\"><div class='sk-item'><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=UUID('68576ee3-7378-4704-b31b-0c3798129e47') type=\"checkbox\" ><label for=UUID('68576ee3-7378-4704-b31b-0c3798129e47') class='sk-toggleable__label sk-toggleable__label-arrow'>AutoARIMA</label><div class=\"sk-toggleable__content\"><pre>AutoARIMA(sp=4)</pre></div></div></div></div></div></div></div></div></div></div>" + ], + "text/plain": [ + "MultiplexForecaster(forecasters=[('theta', ThetaForecaster(sp=4)),\n", + " ('ets',\n", + " ExponentialSmoothing(sp=4, trend='add')),\n", + " ('autoarima', AutoARIMA(sp=4))],\n", + " selected_forecaster='ets')" + ] + }, + "execution_count": 80, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gscv.best_forecaster_" + ] + }, + { + "cell_type": "markdown", + "id": "1f853084", + "metadata": { + "id": "1f853084" + }, + "source": [ + "- **`OptionalPassthrough` - finding the best transformations**" + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "id": "c638819e", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "c638819e", + "outputId": "37b97487-c5e2-43a9-9c89-92db3c0e8f6f" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'steps': [('deseasonalizer',\n", + " OptionalPassthrough(transformer=Deseasonalizer())),\n", + " ('forecaster', ExponentialSmoothing())],\n", + " 'deseasonalizer': OptionalPassthrough(transformer=Deseasonalizer()),\n", + " 'forecaster': ExponentialSmoothing(),\n", + " 'deseasonalizer__passthrough': False,\n", + " 'deseasonalizer__transformer': Deseasonalizer(),\n", + " 'deseasonalizer__transformer__model': 'additive',\n", + " 'deseasonalizer__transformer__sp': 1,\n", + " 'forecaster__damped_trend': False,\n", + " 'forecaster__damping_trend': None,\n", + " 'forecaster__initial_level': None,\n", + " 'forecaster__initial_seasonal': None,\n", + " 'forecaster__initial_trend': None,\n", + " 'forecaster__initialization_method': 'estimated',\n", + " 'forecaster__method': None,\n", + " 'forecaster__minimize_kwargs': None,\n", + " 'forecaster__optimized': True,\n", + " 'forecaster__random_state': None,\n", + " 'forecaster__remove_bias': False,\n", + " 'forecaster__seasonal': None,\n", + " 'forecaster__smoothing_level': None,\n", + " 'forecaster__smoothing_seasonal': None,\n", + " 'forecaster__smoothing_trend': None,\n", + " 'forecaster__sp': None,\n", + " 'forecaster__start_params': None,\n", + " 'forecaster__trend': None,\n", + " 'forecaster__use_boxcox': None,\n", + " 'forecaster__use_brute': True}" + ] + }, + "execution_count": 81, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "forecaster = TransformedTargetForecaster([(\"deseasonalizer\", OptionalPassthrough(Deseasonalizer())),\n", + " (\"forecaster\", ExponentialSmoothing())])\n", + "forecaster.get_params()" + ] + }, + { + "cell_type": "code", + "execution_count": 82, + "id": "b99feefe", + "metadata": { + "id": "b99feefe" + }, + "outputs": [], + "source": [ + "cv = SlidingWindowSplitter(initial_window=60, window_length=30)\n", + "params = {\"deseasonalizer__passthrough\": [True, False],\n", + " \"deseasonalizer__transformer__model\": [\"additive\", \"multiplicative\"]}\n", + "\n", + "gscv = ForecastingGridSearchCV(forecaster=forecaster,\n", + " param_grid=params,\n", + " cv=cv)" + ] + }, + { + "cell_type": "code", + "execution_count": 83, + "id": "bad88162", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "bad88162", + "outputId": "31628311-7aa2-42a2-a188-c6cbf00439cf", + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'deseasonalizer__passthrough': True,\n", + " 'deseasonalizer__transformer__model': 'additive'}" + ] + }, + "execution_count": 83, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "gscv.fit(y_train)\n", + "gscv.best_params_ #model performs better with the transformation" + ] + }, + { + "cell_type": "markdown", + "id": "7a1eea65", + "metadata": { + "id": "7a1eea65" + }, + "source": [ + "### Ensemble forecasting" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "id": "afb59acb", + "metadata": { + "id": "afb59acb" + }, + "outputs": [], + "source": [ + "ensemble = EnsembleForecaster(forecasters = [(\"tbats\", TBATS()),\n", + " (\"autoarima\", AutoARIMA())],\n", + " aggfunc = \"min\")" + ] + }, + { + "cell_type": "code", + "execution_count": 85, + "id": "b0d6b016", + "metadata": { + "id": "b0d6b016" + }, + "outputs": [], + "source": [ + "ensemble.fit(y_train)\n", + "y_pred = ensemble.predict(fh_abs) #averaged predictions of both models" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "id": "cecb99be", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "cecb99be", + "outputId": "162bbee6-b205-40eb-9249-cadb95d6193c" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[TBATS(), AutoARIMA()]" + ] + }, + "execution_count": 86, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ensemble.forecasters_" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "id": "85b0566e", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 348 + }, + "id": "85b0566e", + "outputId": "0681c436-6388-49ca-fda9-a0d2bcd51a6a", + "scrolled": true + }, + "outputs": [ + { + "data": { + "image/png": "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STKB45YXU2XHi6urK7p164YZM2YgMzMTDRo0wLfffotHjx5h+PDhYr+BAwfi5MmTmD59Oq5fvw4/Pz8UFBRgx44d2L9/P8LDwyXxNXDgQAQEBKBZs2YwMjLCpUuXsGHDBnTs2JFJLQOZPXs2Dh06hE8//RS5ubniJjPAkz0MzMzMEB4ejkmTJuG1116Dt7c39u7di8TERGzZskXs6+7uDl9fX0RGRmLKlCkwNzfHsmXL4OTkJNnAMTw8HNeuXcP8+fNx//59ydTlklXFS5YsQUhICIKDgzFy5EjY2dnh9u3biI6ORn5+PjZu3Cj2dXZ21nhe1tbWsLS05LjFgCo7Vo4cOYI7d+7gjTfeQFZWFnbv3o3Tp0/ju+++k1wXxyxSMkFbjT1VS/fu3RMX3i5t06ZN8Pb2xoYNG/Dtt98iPT0dNjY2ePvttzF+/HjJehPx8fGIjo5Gamoq8vLyUKdOHfj5+WHChAmSdWmuXr2KWbNmiQO4Nm3aYPz48ZIdV9UUCgXWr1+PuLg43L17F0qlEubm5oiOjpYMIABgx44dYlVGadevX9f7dSFNhooVtc2bNyM2Nhbp6emwtbXFiBEjJMny6Oho7N69G2lpaVAqlbC1tcV7772HsLAwjaouXWOlvOdga2uL+Pj4irw0pIWh40X9C2NCQoK4bo6+51PLysrC2rVr8euvvyI9PR0qlQr16tXDunXrJL9MPnr0CAsWLMDFixeRkZGBWrVqoVmzZhgyZEiFFp4n7So7VoAnMdChQwcMHjwYkydPLvPadI0VbT799FNcvnwZcXFx5fYj/RgyXq5cuYLly5fjypUrUCgUsLOzw+DBg9GrV68yz3/69GkMGjQI27Zt05jhok+8rFy5EqtWrdI4Pt+LDMeQsTJx4kScOnUKWVlZaNKkCfr27YtBgwZpbIL08OFDzJs3D8eOHYOJiQkCAgIQGRmpUbHFccuLpyriJT8/H0uXLsWePXuQm5sLV1dXTJ48WeODOZVKhe+++w7bt29HSkqKOEU+KipKY0bcwoULcfToUdy/fx8mJiZo0qQJAgMDMWDAAG52YyBdunRBWlqa1sd+++03NGnSBADw008/ISYmBvfv34e9vT0iIiLEyl+1nJwcLFy4EAcOHIBKpYKvry+mT58uqRR0cnIq81pK/56bnp6O1atX48iRI8jIyEBxcTHs7OwQExOD1157rdznFRISAktLS0RHR5fbj3RX2bFy/PhxLF68GLdv34aJiQm8vLwwceJEjQ/pAY5ZSmIClF5IZ86cwdChQzF69GiMHTu2qi+HXmCMFdJHXFwcJk2ahEWLFnFpDSoXY4X0wXghXXHcQvpITk5GcHAwunfvjvnz51f15dALLDo6GitXrkRMTIxGARFRSS/zmIVrgNILydPTE1OnTsWKFSuwc+fOqr4ceoExVkgfPXv2xNChQzF9+nTJ2jpEpTFWSB+MF9IVxy2kDwcHByxZsgTbt2/HV199VdWXQy+wkSNH4q233kJ4eLhkCQ2i0l7mMQsrQImIiIiIiIiIiKjaYgUoERERERERERERVVtMgBIREREREREREVG1xQQoERERERERERERVVtMgBIREREREREREVG1xQQoERERERERERERVVtMgBIREREREREREVG1xQQoERERERERERERVVtMgBIREREREREREVG1xQQoERERERERERERVVtMgBIREREREREREVG19f/O0xoudhgQJQAAAABJRU5ErkJggg==", + "text/plain": [ + "<Figure size 1600x400 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_series(y_train, y_test, y_pred, labels=[\"y_train\", \"y_test\", \"y_pred\"]);" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.17" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/blog_posts/README.md b/examples/blog_posts/README.md new file mode 100644 index 00000000000..f52d1cc7d87 --- /dev/null +++ b/examples/blog_posts/README.md @@ -0,0 +1,10 @@ +### Notebooks from blog posts and tutorials + +This folder contains notebooks and tutorials from past blog posts and past tutorials. + +Notebooks in this folder are included in `sktime` continuous integration, +so we can check whether new releases break past code. + +#### Contents + +* Joanna Lenczuk - Why start using `sktime` for forecasting diff --git a/examples/interpolation.ipynb b/examples/interpolation.ipynb index d55caa3f570..eeb36d28b82 100644 --- a/examples/interpolation.ipynb +++ b/examples/interpolation.ipynb @@ -124,6 +124,8 @@ ], "source": [ "# randomly cut the data series in-place\n", + "\n", + "\n", "def random_cut(df):\n", " for row_i in range(df.shape[0]):\n", " for dim_i in range(df.shape[1]):\n", diff --git a/examples/interval_based_classification.ipynb b/examples/interval_based_classification.ipynb index 2f28b2494cf..45cb61fed14 100644 --- a/examples/interval_based_classification.ipynb +++ b/examples/interval_based_classification.ipynb @@ -27,25 +27,22 @@ }, { "cell_type": "markdown", - "metadata": {}, "source": [ "## 1. Imports" - ] + ], + "metadata": { + "collapsed": false + } }, { "cell_type": "code", - "execution_count": 1, - "metadata": { - "execution": { - "iopub.execute_input": "2020-12-19T14:32:05.163967Z", - "iopub.status.busy": "2020-12-19T14:32:05.163440Z", - "iopub.status.idle": "2020-12-19T14:32:05.914752Z", - "shell.execute_reply": "2020-12-19T14:32:05.915264Z" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ + "import numpy as np\n", "from sklearn import metrics\n", + "from sklearn.pipeline import Pipeline\n", "\n", "from sktime.classification.interval_based import (\n", " CanonicalIntervalForest,\n", @@ -54,7 +51,8 @@ " SupervisedTimeSeriesForest,\n", " TimeSeriesForestClassifier,\n", ")\n", - "from sktime.datasets import load_basic_motions, load_italy_power_demand" + "from sktime.datasets import load_basic_motions, load_italy_power_demand\n", + "from sktime.transformations.panel.compose import ColumnConcatenator" ] }, { @@ -66,25 +64,9 @@ }, { "cell_type": "code", - "execution_count": 2, - "metadata": { - "execution": { - "iopub.execute_input": "2020-12-19T14:32:05.919120Z", - "iopub.status.busy": "2020-12-19T14:32:05.918629Z", - "iopub.status.idle": "2020-12-19T14:32:06.041420Z", - "shell.execute_reply": "2020-12-19T14:32:06.040742Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(67, 1) (67,) (50, 1) (50,)\n", - "(40, 6) (40,) (40, 6) (40,)\n" - ] - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "X_train, y_train = load_italy_power_demand(split=\"train\", return_X_y=True)\n", "X_test, y_test = load_italy_power_demand(split=\"test\", return_X_y=True)\n", @@ -118,24 +100,9 @@ }, { "cell_type": "code", - "execution_count": 3, - "metadata": { - "execution": { - "iopub.execute_input": "2020-12-19T14:32:06.045197Z", - "iopub.status.busy": "2020-12-19T14:32:06.044696Z", - "iopub.status.idle": "2020-12-19T14:32:06.460714Z", - "shell.execute_reply": "2020-12-19T14:32:06.461260Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "TSF Accuracy: 0.98\n" - ] - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "tsf = TimeSeriesForestClassifier(n_estimators=50, random_state=47)\n", "tsf.fit(X_train, y_train)\n", @@ -144,6 +111,230 @@ "print(\"TSF Accuracy: \" + str(metrics.accuracy_score(y_test, tsf_preds)))" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "tsf = Pipeline(\n", + " [\n", + " (\"column_concatenar\", ColumnConcatenator()),\n", + " (\"classify\", TimeSeriesForestClassifier(n_estimators=50, random_state=47)),\n", + " ]\n", + ")\n", + "tsf.fit(X_train_mv, y_train_mv)\n", + "\n", + "tsf_preds = tsf.predict(X_test_mv)\n", + "print(\"TSF Accuracy: \" + str(metrics.accuracy_score(y_test_mv, tsf_preds)))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "temporal_feature_importance = tsf[\"classify\"].feature_importances_\n", + "separators = range(0, tsf[\"classify\"].series_length, len(X_train_mv.iloc[0, 0]))\n", + "\n", + "ax = temporal_feature_importance.plot(figsize=(20, 10))\n", + "for index, separator in enumerate(separators):\n", + " ax.vlines(\n", + " separator,\n", + " temporal_feature_importance.min().min(),\n", + " temporal_feature_importance.max().max(),\n", + " color=\"r\",\n", + " alpha=0.3,\n", + " )\n", + " ax.text(\n", + " separator, temporal_feature_importance.max().max(), X_train_mv.columns[index]\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "X_train_mv_columns = list(X_train_mv.columns)\n", + "np.random.shuffle(X_train_mv_columns)\n", + "\n", + "X_train_shuffled = X_train_mv[X_train_mv_columns]\n", + "X_train_shuffled.columns = X_train_mv.columns\n", + "\n", + "X_test_shuffled = X_test_mv[X_train_mv_columns]\n", + "X_test_shuffled.columns = X_test_mv.columns\n", + "\n", + "tsf = Pipeline(\n", + " [\n", + " (\"column_concatenator\", ColumnConcatenator()),\n", + " (\"classify\", TimeSeriesForestClassifier(n_estimators=50, random_state=47)),\n", + " ]\n", + ")\n", + "tsf.fit(X_train_shuffled, y_train_mv)\n", + "\n", + "tsf_preds = tsf.predict(X_test_shuffled)\n", + "print(\"TSF Accuracy: \" + str(metrics.accuracy_score(y_test_mv, tsf_preds)))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "temporal_feature_importance = tsf[\"classify\"].feature_importances_\n", + "separators = range(0, tsf[\"classify\"].series_length, len(X_train_mv.iloc[0, 0]))\n", + "\n", + "ax = temporal_feature_importance.plot(figsize=(20, 10))\n", + "for index, separator in enumerate(separators):\n", + " ax.vlines(\n", + " separator,\n", + " temporal_feature_importance.min().min(),\n", + " temporal_feature_importance.max().max(),\n", + " color=\"r\",\n", + " alpha=0.3,\n", + " )\n", + " ax.text(\n", + " separator, temporal_feature_importance.max().max(), X_train_mv_columns[index]\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "tsf = Pipeline(\n", + " [\n", + " (\"column_concatenator\", ColumnConcatenator()),\n", + " (\n", + " \"classify\",\n", + " TimeSeriesForestClassifier(\n", + " n_estimators=50, random_state=47, inner_series_length=100\n", + " ),\n", + " ),\n", + " ]\n", + ")\n", + "tsf.fit(X_train_mv, y_train_mv)\n", + "\n", + "tsf_preds = tsf.predict(X_test_mv)\n", + "print(\"TSF Accuracy: \" + str(metrics.accuracy_score(y_test_mv, tsf_preds)))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "temporal_feature_importance = tsf[\"classify\"].feature_importances_\n", + "separators = range(0, tsf[\"classify\"].series_length, len(X_train_mv.iloc[0, 0]))\n", + "\n", + "ax = temporal_feature_importance.plot(figsize=(20, 10))\n", + "for index, separator in enumerate(separators):\n", + " ax.vlines(\n", + " separator,\n", + " temporal_feature_importance.min().min(),\n", + " temporal_feature_importance.max().max(),\n", + " color=\"r\",\n", + " alpha=0.3,\n", + " )\n", + " ax.text(\n", + " separator, temporal_feature_importance.max().max(), X_train_mv.columns[index]\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "X_train_mv_columns = list(X_train_mv.columns)\n", + "np.random.shuffle(X_train_mv_columns)\n", + "\n", + "X_train_shuffled = X_train_mv[X_train_mv_columns]\n", + "X_train_shuffled.columns = X_train_mv.columns\n", + "\n", + "X_test_shuffled = X_test_mv[X_train_mv_columns]\n", + "X_test_shuffled.columns = X_test_mv.columns\n", + "\n", + "tsf = Pipeline(\n", + " [\n", + " (\"column_concatenator\", ColumnConcatenator()),\n", + " (\n", + " \"classify\",\n", + " TimeSeriesForestClassifier(\n", + " n_estimators=50, random_state=47, inner_series_length=100\n", + " ),\n", + " ),\n", + " ]\n", + ")\n", + "tsf.fit(X_train_shuffled, y_train_mv)\n", + "\n", + "tsf_preds = tsf.predict(X_test_shuffled)\n", + "print(\"TSF Accuracy: \" + str(metrics.accuracy_score(y_test_mv, tsf_preds)))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "temporal_feature_importance = tsf[\"classify\"].feature_importances_\n", + "separators = range(0, tsf[\"classify\"].series_length, len(X_train_mv.iloc[0, 0]))\n", + "\n", + "ax = temporal_feature_importance.plot(figsize=(20, 10))\n", + "for index, separator in enumerate(separators):\n", + " ax.vlines(\n", + " separator,\n", + " temporal_feature_importance.min().min(),\n", + " temporal_feature_importance.max().max(),\n", + " color=\"r\",\n", + " alpha=0.3,\n", + " )\n", + " ax.text(\n", + " separator, temporal_feature_importance.max().max(), X_train_mv_columns[index]\n", + " )" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -155,21 +346,13 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": { "pycharm": { "name": "#%%\n" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "RISE Accuracy: 1.0\n" - ] - } - ], + "outputs": [], "source": [ "rise = RandomIntervalSpectralEnsemble(n_estimators=50, random_state=47)\n", "rise.fit(X_train, y_train)\n", @@ -189,21 +372,13 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": { "pycharm": { "name": "#%%\n" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "STSF Accuracy: 0.96\n" - ] - } - ], + "outputs": [], "source": [ "stsf = SupervisedTimeSeriesForest(n_estimators=50, random_state=47)\n", "stsf.fit(X_train, y_train)\n", @@ -226,7 +401,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": { "execution": { "iopub.execute_input": "2020-12-19T14:32:06.471294Z", @@ -238,15 +413,7 @@ "name": "#%%\n" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CIF Accuracy: 0.98\n" - ] - } - ], + "outputs": [], "source": [ "cif = CanonicalIntervalForest(n_estimators=50, att_subsample_size=8, random_state=47)\n", "cif.fit(X_train, y_train)\n", @@ -264,21 +431,13 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": { "pycharm": { "name": "#%%\n" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CIF Accuracy: 1.0\n" - ] - } - ], + "outputs": [], "source": [ "cif_m = CanonicalIntervalForest(n_estimators=50, att_subsample_size=8, random_state=47)\n", "cif_m.fit(X_train_mv, y_train_mv)\n", @@ -300,21 +459,13 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": { "pycharm": { "name": "#%%\n" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DrCIF Accuracy: 0.98\n" - ] - } - ], + "outputs": [], "source": [ "drcif = DrCIF(n_estimators=5, att_subsample_size=10, random_state=47)\n", "drcif.fit(X_train, y_train)\n", @@ -336,21 +487,13 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": { "pycharm": { "name": "#%%\n" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DrCIF Accuracy: 1.0\n" - ] - } - ], + "outputs": [], "source": [ "drcif_m = DrCIF(n_estimators=5, att_subsample_size=10, random_state=47)\n", "drcif_m.fit(X_train_mv, y_train_mv)\n", diff --git a/examples/mlflow.ipynb b/examples/mlflow.ipynb index 79189d2029f..fd91ca73aa1 100644 --- a/examples/mlflow.ipynb +++ b/examples/mlflow.ipynb @@ -133,7 +133,6 @@ ], "source": [ "with mlflow.start_run():\n", - "\n", " forecaster = NaiveForecaster()\n", " forecaster.fit(\n", " y_train,\n", @@ -691,7 +690,6 @@ "mlflow.set_experiment(\"Test Sktime\")\n", "\n", "with mlflow.start_run() as run:\n", - "\n", " forecaster = NaiveForecaster()\n", " forecaster.fit(y_train, X=X_train, fh=[1, 2, 3])\n", " forecaster.pyfunc_predict_conf = pyfunc_predict_conf\n", diff --git a/examples/partition_based_clustering.ipynb b/examples/partition_based_clustering.ipynb index 4b802232f44..4aea2cbfc47 100644 --- a/examples/partition_based_clustering.ipynb +++ b/examples/partition_based_clustering.ipynb @@ -134,7 +134,7 @@ " <br>\n", " These three cluster initialisation algorithms have been implemented and can\n", " be chosen to use when constructing either k-means or k-medoids partitioning\n", - " algorithms by parsing the string values 'random' for random iniitialisation,\n", + " algorithms by parsing the string values 'random' for random initialisation,\n", " 'forgy' for forgy and 'k-means++' for k-means++.\n", "\n", "### Assignment (distance measure)\n", diff --git a/extension_templates/alignment.py b/extension_templates/alignment.py index e50caa38429..3fbe2c8ddba 100644 --- a/extension_templates/alignment.py +++ b/extension_templates/alignment.py @@ -69,10 +69,25 @@ class MyAligner(BaseAligner): # optional todo: override base class estimator default tags here if necessary # these are the default values, only add if different to these. _tags = { + # packaging info + # -------------- + "authors": ["author1", "author2"], # authors, GitHub handles + "maintainers": ["maintainer1", "maintainer2"], # maintainers, GitHub handles + # author = significant contribution to code at some point + # maintainer = algorithm maintainer role, "owner" + # specify one or multiple authors and maintainers, only for sktime contribution + # remove maintainer tag if maintained by sktime core team + # + "python_version": None, # PEP 440 python version specifier to limit versions + "python_dependencies": None, # PEP 440 python dependencies specifier, + # e.g., "numba>0.53", or a list, e.g., ["numba>0.53", "numpy>=1.19.0"] + # delete if no python dependencies or version limitations + # + # estimator tags + # -------------- "capability:multiple-alignment": False, # can align more than two sequences? "capability:distance": False, # does compute/return overall distance? "capability:distance-matrix": False, # does compute/return distance matrix? - "python_version": None, # PEP 440 python version specifier to limit versions } # todo: add any hyper-parameters and components to constructor diff --git a/extension_templates/classification.py b/extension_templates/classification.py index 532743cd52b..2a8cbdc9a3e 100644 --- a/extension_templates/classification.py +++ b/extension_templates/classification.py @@ -70,16 +70,33 @@ class MyTimeSeriesClassifier(BaseClassifier): # optional todo: override base class estimator default tags here if necessary # these are the default values, only add if different to these. _tags = { + # packaging info + # -------------- + "authors": ["author1", "author2"], # authors, GitHub handles + "maintainers": ["maintainer1", "maintainer2"], # maintainers, GitHub handles + # author = significant contribution to code at some point + # maintainer = algorithm maintainer role, "owner" + # specify one or multiple authors and maintainers, only for sktime contribution + # remove maintainer tag if maintained by sktime core team + # + "python_version": None, # PEP 440 python version specifier to limit versions + "python_dependencies": None, # PEP 440 python dependencies specifier, + # e.g., "numba>0.53", or a list, e.g., ["numba>0.53", "numpy>=1.19.0"] + # delete if no python dependencies or version limitations + # + # estimator tags + # -------------- "X_inner_mtype": "numpy3D", # which type do _fit/_predict accept, usually - # this is either "numpy3D" or "nested_univ" (nested pd.DataFrame). Other + "y_inner_mtype": "numpy1D", # which type do _fit/_predict return, usually + # this is either "numpy3D", "pd-multiindex" or "nested_univ" (nested df). Other # types are allowable, see datatypes/panel/_registry.py for options. - "capability:multivariate": False, + "capability:multivariate": False, # ability to handle multivariate X + "capability:multioutput": False, # ability to predict multiple columns in y "capability:unequal_length": False, "capability:missing_values": False, "capability:train_estimate": False, "capability:contractable": False, "capability:multithreading": False, - "python_version": None, # PEP 440 python version specifier to limit versions } # todo: add any hyper-parameters and components to constructor @@ -129,13 +146,19 @@ def _fit(self, X, y): ---------- X : guaranteed to be of a type in self.get_tag("X_inner_mtype") if self.get_tag("X_inner_mtype") = "numpy3D": - 3D np.ndarray of shape = [n_instances, n_dimensions, series_length] - if self.get_tag("X_inner_mtype") = "nested_univ": - pd.DataFrame with each column a dimension, each cell a pd.Series + 3D np.ndarray of shape = [n_instances, n_dimensions, series_length] + if self.get_tag("X_inner_mtype") = "pd-multiindex:": + pd.DataFrame with columns = variables, + index = pd.MultiIndex with first level = instance indices, + second level = time indices for list of other mtypes, see datatypes.SCITYPE_REGISTER for specifications, see examples/AA_datatypes_and_datasets.ipynb - y : 1D np.array of int, of shape [n_instances] - class labels for fitting - indices correspond to instance indices in X + y : guaranteed to be of a type in self.get_tag("y_inner_mtype") + 1D iterable, of shape [n_instances] + or 2D iterable, of shape [n_instances, n_dimensions] + class labels for fitting + if self.get_tag("capaility:multioutput") = False, guaranteed to be 1D + if self.get_tag("capaility:multioutput") = True, guaranteed to be 2D Returns ------- @@ -152,31 +175,32 @@ def _fit(self, X, y): # 3. read from self in _fit, 4. pass to interfaced_model.fit in _fit # todo: implement this, mandatory - def _predict(self, X) -> np.ndarray: + def _predict(self, X): """Predict labels for sequences in X. private _predict containing the core logic, called from predict - State required: - Requires state to be "fitted". - - Accesses in self: - Fitted model attributes ending in "_" - Parameters ---------- X : guaranteed to be of a type in self.get_tag("X_inner_mtype") if self.get_tag("X_inner_mtype") = "numpy3D": - 3D np.ndarray of shape = [n_instances, n_dimensions, series_length] - if self.get_tag("X_inner_mtype") = "nested_univ": - pd.DataFrame with each column a dimension, each cell a pd.Series + 3D np.ndarray of shape = [n_instances, n_dimensions, series_length] + if self.get_tag("X_inner_mtype") = "pd-multiindex:": + pd.DataFrame with columns = variables, + index = pd.MultiIndex with first level = instance indices, + second level = time indices for list of other mtypes, see datatypes.SCITYPE_REGISTER for specifications, see examples/AA_datatypes_and_datasets.ipynb Returns ------- - y : 1D np.array of int, of shape [n_instances] - predicted class labels + y : should be of mtype in self.get_tag("y_inner_mtype") + 1D iterable, of shape [n_instances] + or 2D iterable, of shape [n_instances, n_dimensions] + predicted class labels indices correspond to instance indices in X + if self.get_tag("capaility:multioutput") = False, should be 1D + if self.get_tag("capaility:multioutput") = True, should be 2D """ # implement here @@ -200,9 +224,11 @@ def _predict_proba(self, X) -> np.ndarray: ---------- X : guaranteed to be of a type in self.get_tag("X_inner_mtype") if self.get_tag("X_inner_mtype") = "numpy3D": - 3D np.ndarray of shape = [n_instances, n_dimensions, series_length] - if self.get_tag("X_inner_mtype") = "nested_univ": - pd.DataFrame with each column a dimension, each cell a pd.Series + 3D np.ndarray of shape = [n_instances, n_dimensions, series_length] + if self.get_tag("X_inner_mtype") = "pd-multiindex:": + pd.DataFrame with columns = variables, + index = pd.MultiIndex with first level = instance indices, + second level = time indices for list of other mtypes, see datatypes.SCITYPE_REGISTER for specifications, see examples/AA_datatypes_and_datasets.ipynb diff --git a/extension_templates/clustering.py b/extension_templates/clustering.py index 7c3cc2966cd..4e9936de1b3 100644 --- a/extension_templates/clustering.py +++ b/extension_templates/clustering.py @@ -65,6 +65,22 @@ class MyClusterer(BaseClusterer): # optional todo: override base class estimator default tags here if necessary # these are the default values, only add if different to these. _tags = { + # packaging info + # -------------- + "authors": ["author1", "author2"], # authors, GitHub handles + "maintainers": ["maintainer1", "maintainer2"], # maintainers, GitHub handles + # author = significant contribution to code at some point + # maintainer = algorithm maintainer role, "owner" + # specify one or multiple authors and maintainers, only for sktime contribution + # remove maintainer tag if maintained by sktime core team + # + "python_version": None, # PEP 440 python version specifier to limit versions + "python_dependencies": None, # PEP 440 python dependencies specifier, + # e.g., "numba>0.53", or a list, e.g., ["numba>0.53", "numpy>=1.19.0"] + # delete if no python dependencies or version limitations + # + # estimator tags + # -------------- "X_inner_mtype": "numpy3D", # which type do _fit/_predict accept, usually # this is either "numpy3D" or "nested_univ" (nested pd.DataFrame). Other # types are allowable, see datatypes/panel/_registry.py for options. diff --git a/extension_templates/dist_kern_panel.py b/extension_templates/dist_kern_panel.py index 5bd714daa18..4586d798618 100644 --- a/extension_templates/dist_kern_panel.py +++ b/extension_templates/dist_kern_panel.py @@ -57,9 +57,14 @@ class MyTrafoPwPanel(BasePairwiseTransformerPanel): # todo: fill out transformer tags here # delete the tags that you *didn't* change - these defaults are inherited - # _tags = { - # currently there are no tags for pairwise transformers - # } + _tags = { + # specify one or multiple authors and maintainers, only for sktime contribution + "authors": ["author1", "author2"], # authors, GitHub handles + "maintainers": ["maintainer1", "maintainer2"], # maintainers, GitHub handles + # author = significant contribution to code at some point + # maintainer = algorithm maintainer role, "owner" + # remove maintainer tag if maintained by sktime core team + } # in case of inheritance, concrete class should typically set tags # alternatively, descendants can set tags in __init__ (avoid this if possible) diff --git a/extension_templates/dist_kern_tab.py b/extension_templates/dist_kern_tab.py index 926449789fd..7c5cbc3e657 100644 --- a/extension_templates/dist_kern_tab.py +++ b/extension_templates/dist_kern_tab.py @@ -57,9 +57,14 @@ class MyTrafoPw(BasePairwiseTransformer): # todo: fill out transformer tags here # delete the tags that you *didn't* change - these defaults are inherited - # _tags = { - # currently there are no tags for pairwise transformers - # } + _tags = { + # specify one or multiple authors and maintainers, only for sktime contribution + "authors": ["author1", "author2"], # authors, GitHub handles + "maintainers": ["maintainer1", "maintainer2"], # maintainers, GitHub handles + # author = significant contribution to code at some point + # maintainer = algorithm maintainer role, "owner" + # remove maintainer tag if maintained by sktime core team + } # in case of inheritance, concrete class should typically set tags # alternatively, descendants can set tags in __init__ (avoid this if possible) diff --git a/extension_templates/forecasting.py b/extension_templates/forecasting.py index 525499c4b10..532210ac275 100644 --- a/extension_templates/forecasting.py +++ b/extension_templates/forecasting.py @@ -152,6 +152,27 @@ class MyForecaster(BaseForecaster): # only needs to be set if capability:pred_int is True # if False, exception raised if proba methods are called with in-sample fh # + # ---------------------------------------------------------------------------- + # packaging info - only required for sktime contribution or 3rd party packages + # ---------------------------------------------------------------------------- + # + # ownership and contribution tags + # ------------------------------- + # + # author = author(s) of th estimator + # an author is anyone with significant contribution to the code at some point + "authors": ["author1", "author2"], + # valid values: str or list of str, should be GitHub handles + # this should follow best scientific contribution practices + # scope is the code, not the methodology (method is per paper citation) + # + # maintainer = current maintainer(s) of the estimator + # per algorithm maintainer role, see governance document + # this is an "owner" type role, with rights and maintenance duties + "maintainers": ["maintainer1", "maintainer2"], + # valid values: str or list of str, should be GitHub handles + # remove tag if maintained by sktime core team + # # dependency tags: python version and soft dependencies # ----------------------------------------------------- # @@ -161,8 +182,8 @@ class MyForecaster(BaseForecaster): # raises exception at construction if local python version is incompatible # # soft dependency requirement - "python_dependencies": None - # valid values: str or list of str + "python_dependencies": None, + # valid values: str or list of str, PEP 440 valid package version specifiers # raises exception at construction if modules at strings cannot be imported } # in case of inheritance, concrete class should typically set tags diff --git a/extension_templates/forecasting_simple.py b/extension_templates/forecasting_simple.py index 54ecbd9ea78..7fe6210ca34 100644 --- a/extension_templates/forecasting_simple.py +++ b/extension_templates/forecasting_simple.py @@ -107,6 +107,23 @@ class MyForecaster(BaseForecaster): "requires-fh-in-fit": True, # valid values: boolean True (yes), False (no) # if True, raises exception in fit if fh has not been passed + # + # ownership and contribution tags + # ------------------------------- + # + # author = author(s) of th estimator + # an author is anyone with significant contribution to the code at some point + "authors": ["author1", "author2"], + # valid values: str or list of str, should be GitHub handles + # this should follow best scientific contribution practices + # scope is the code, not the methodology (method is per paper citation) + # + # maintainer = current maintainer(s) of the estimator + # per algorithm maintainer role, see governance document + # this is an "owner" type role, with rights and maintenance duties + "maintainers": ["maintainer1", "maintainer2"], + # valid values: str or list of str, should be GitHub handles + # remove tag if maintained by sktime core team } # todo: add any hyper-parameters and components to constructor diff --git a/extension_templates/forecasting_supersimple.py b/extension_templates/forecasting_supersimple.py index 83c6c2ad736..d944cc30595 100644 --- a/extension_templates/forecasting_supersimple.py +++ b/extension_templates/forecasting_supersimple.py @@ -72,6 +72,13 @@ class MyForecaster(BaseForecaster): # "univariate": inner _fit, _predict, receives only single-column DataFrame # "both": inner _predict gets pd.DataFrame series with any number of columns # + # specify one or multiple authors and maintainers, only for sktime contribution + "authors": ["author1", "author2"], # authors, GitHub handles + "maintainers": ["maintainer1", "maintainer2"], # maintainers, GitHub handles + # author = significant contribution to code at some point + # maintainer = algorithm maintainer role, "owner" + # remove maintainer tag if maintained by sktime core team + # # do not change these: # (look at advanced templates if you think these should change) "y_inner_mtype": "pd.DataFrame", diff --git a/extension_templates/param_est.py b/extension_templates/param_est.py index a8dffbd923f..975a87e9cac 100644 --- a/extension_templates/param_est.py +++ b/extension_templates/param_est.py @@ -102,6 +102,26 @@ class MyTimeSeriesParamFitter(BaseParamFitter): # valid values: boolean True (yes), False (no) # if False, raises exception if X passed has more than one variable # + # ---------------------------------------------------------------------------- + # packaging info - only required for sktime contribution or 3rd party packages + # ---------------------------------------------------------------------------- + # + # ownership and contribution tags + # ------------------------------- + # + # author = author(s) of th estimator + # an author is anyone with significant contribution to the code at some point + "authors": ["author1", "author2"], + # valid values: str or list of str, should be GitHub handles + # this should follow best scientific contribution practices + # scope is the code, not the methodology (method is per paper citation) + # + # maintainer = current maintainer(s) of the estimator + # per algorithm maintainer role, see governance document + # this is an "owner" type role, with rights and maintenance duties + "maintainers": ["maintainer1", "maintainer2"], + # valid values: str or list of str, should be GitHub handles + # remove tag if maintained by sktime core team # # dependency tags: python version and soft dependencies # ----------------------------------------------------- @@ -112,8 +132,8 @@ class MyTimeSeriesParamFitter(BaseParamFitter): # raises exception at construction if local python version is incompatible # # soft dependency requirement - "python_dependencies": None - # valid values: str or list of str + "python_dependencies": None, + # valid values: str or list of str, PEP 440 valid package version specifiers # raises exception at construction if modules at strings cannot be imported } # in case of inheritance, concrete class should typically set tags diff --git a/extension_templates/split.py b/extension_templates/split.py new file mode 100644 index 00000000000..a3679c8062a --- /dev/null +++ b/extension_templates/split.py @@ -0,0 +1,290 @@ +"""Extension template for parameter estimators. + +Purpose of this implementation template: + quick implementation of new estimators following the template + NOT a concrete class to import! This is NOT a base class or concrete class! + This is to be used as a "fill-in" coding template. + +How to use this implementation template to implement a new estimator: +- make a copy of the template in a suitable location, give it a descriptive name. +- work through all the "todo" comments below +- fill in code for mandatory methods, and optionally for optional methods +- do not write to reserved variables: _tags, _tags_dynamic +- you can add more private methods, but do not override BaseEstimator's private methods + an easy way to be safe is to prefix your methods with "_custom" +- change docstrings for functions and the file +- ensure interface compatibility by sktime.utils.estimator_checks.check_estimator +- once complete: use as a local library, or contribute to sktime via PR +- more details: + https://www.sktime.net/en/stable/developer_guide/add_estimators.html + +Mandatory implements: + splitting (iloc reference) - _split(self, y) + +Optional implements: + splitting (loc reference) - _split_loc(self, y) + get number of splits - get_n_splits(self, y) + +Testing - required for sktime test framework and check_estimator usage: + get default parameters for test instance(s) - get_test_params(cls) + +copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +""" +# todo: write an informative docstring for the file or module, remove the above +# todo: add an appropriate copyright notice for your estimator +# estimators contributed to sktime should have the copyright notice at the top +# estimators of your own do not need to have permissive or BSD-3 copyright + +# todo: uncomment the following line, enter authors' GitHub IDs +# __author__ = [authorGitHubID, anotherAuthorGitHubID] + + +from sktime.split.base import BaseSplitter + +# todo: add any necessary imports here + +# todo: if any imports are sktime soft dependencies: +# make sure to fill in the "python_dependencies" tag with the package import name + + +class MySplitter(BaseSplitter): + """Custom splitter. todo: write docstring. + + todo: describe your custom splitter here + + Parameters + ---------- + parama : int + descriptive explanation of parama + paramb : string, optional (default='default') + descriptive explanation of paramb + paramc : boolean, optional (default= whether paramb is not the default) + descriptive explanation of paramc + and so on + est : sktime.estimator, BaseEstimator descendant + descriptive explanation of est + est2: another estimator + descriptive explanation of est2 + and so on + """ + + # todo: fill out estimator tags here + # tags are inherited from parent class if they are not set + _tags = { + # + # behavioural tags + # ---------------- + # + # internal support for hierarchical and panel data + "split_hierarchical": False, + # valid values: True, False + # if False, splitter broadcasts over instances for hierarchical data + # if True, internal _split must support pd.MultiIndex + # + # which of _split and _split_loc is called in split_series by default + "split_series_uses": "iloc", + # valid values: "iloc" or "loc" + # determines whether split_series under the hood + # calls split ("iloc") or split_loc ("loc"). Setting this can give + # performance advantages, e.g., if "loc" is faster to obtain. + # + # ---------------------------------------------------------------------------- + # packaging info - only required for sktime contribution or 3rd party packages + # ---------------------------------------------------------------------------- + # + # ownership and contribution tags + # ------------------------------- + # + # author = author(s) of th estimator + # an author is anyone with significant contribution to the code at some point + "authors": ["author1", "author2"], + # valid values: str or list of str, should be GitHub handles + # this should follow best scientific contribution practices + # scope is the code, not the methodology (method is per paper citation) + # + # maintainer = current maintainer(s) of the estimator + # per algorithm maintainer role, see governance document + # this is an "owner" type role, with rights and maintenance duties + "maintainers": ["maintainer1", "maintainer2"], + # valid values: str or list of str, should be GitHub handles + # remove tag if maintained by sktime core team + # + # dependency tags: python version and soft dependencies + # ----------------------------------------------------- + # + # python version requirement + "python_version": None, + # valid values: str, PEP 440 valid python version specifiers + # raises exception at construction if local python version is incompatible + # + # soft dependency requirement + "python_dependencies": None, + # valid values: str or list of str, PEP 440 valid package version specifiers + # raises exception at construction if modules at strings cannot be imported + } + + # todo: add any hyper-parameters and components to constructor + def __init__(self, est, parama, est2=None, paramb="default", paramc=None): + # estimators should precede parameters + # if estimators have default values, set None and initialize below + + # todo: write any hyper-parameters and components to self + self.est = est + self.parama = parama + self.paramb = paramb + self.paramc = paramc + + # leave this as is + super().__init__() + + # todo: optional, parameter checking logic (if applicable) should happen here + # if writes derived values to self, should *not* overwrite self.parama etc + # instead, write to self._parama, self._newparam (starting with _) + + # todo: default estimators should have None arg defaults + # and be initialized here + # do this only with default estimators, not with parameters + # if est2 is None: + # self.estimator = MyDefaultEstimator() + + # todo: if tags of estimator depend on component tags, set these here + # only needed if estimator is a composite + # tags set in the constructor apply to the object and override the class + # + # example 1: conditional setting of a tag + # if est.foo == 42: + # self.set_tags(handles-missing-data=True) + # example 2: cloning tags from component + # self.clone_tags(est2, ["enforce_index_type", "handles-missing-data"]) + + # todo: implement this, mandatory + def _split(self, y): + """Get iloc references to train/test splits of `y`. + + private _split containing the core logic, called from split + + Parameters + ---------- + y : pd.Index + Index of time series to split + + Yields + ------ + train : 1D np.ndarray of dtype int + Training window indices, iloc references to training indices in y + test : 1D np.ndarray of dtype int + Test window indices, iloc references to test indices in y + """ + # todo: implement the core logic of your splitter here + # ensure to avoid side effects to self or y + # + # example: + # for train, test in some_logic(y): + # yield train, test + + # todo: consider implementing this, optional + # if not implementing, delete this - default is as below and present in base class + def _split_loc(self, y): + """Get loc references to train/test splits of `y`. + + private _split containing the core logic, called from split_loc + + Default implements using split and y.index to look up the loc indices. + Can be overridden for faster implementation. + + Parameters + ---------- + y : pd.Index + index of time series to split + + Yields + ------ + train : pd.Index + Training window indices, loc references to training indices in y + test : pd.Index + Test window indices, loc references to test indices in y + """ + for train, test in self.split(y): + # default gets loc index from iloc index + yield y[train], y[test] + + # todo: consider implementing this, optional + # only implement if the result does not depend on y + # if not implementing, delete this - default is as below and present in base class + def get_n_splits(self, y) -> int: + """Return the number of splits. + + Parameters + ---------- + y : pd.Series or pd.Index, optional (default=None) + Time series to split + + Returns + ------- + n_splits : int + The number of splits. + """ + return len(list(self.split(y))) + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the splitter. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + + Returns + ------- + params : dict or list of dict, default = {} + Parameters to create testing instances of the class + Each dict are parameters to construct an "interesting" test instance, i.e., + `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. + `create_test_instance` uses the first (or only) dictionary in `params` + """ + + # todo: set the testing parameters for the object + # Testing parameters can be dictionary or list of dictionaries + # Testing parameter choice should cover internal cases well. + # + # this method can, if required, use: + # class properties (e.g., inherited); parent class test case + # imported objects such as estimators from sktime or sklearn + # important: all such imports should be *inside get_test_params*, not at the top + # since imports are used only at testing time + # + # The parameter_set argument is not used for automated, module level tests. + # It can be used in custom, estimator specific tests, for "special" settings. + # A parameter dictionary must be returned *for all values* of parameter_set, + # i.e., "parameter_set not available" errors should never be raised. + # + # A good parameter set should primarily satisfy two criteria, + # 1. Chosen set of parameters should have a low testing time, + # ideally in the magnitude of few seconds for the entire test suite. + # This is vital for the cases where default values result in + # "big" models which not only increases test time but also + # run into the risk of test workers crashing. + # 2. There should be a minimum two such parameter sets with different + # sets of values to ensure a wide range of code coverage is provided. + # + # example 1: specify params as dictionary + # any number of params can be specified + # params = {"est": value0, "parama": value1, "paramb": value2} + # + # example 2: specify params as list of dictionary + # note: Only first dictionary will be used by create_test_instance + # params = [{"est": value1, "parama": value2}, + # {"est": value3, "parama": value4}] + # return params + # + # example 3: parameter set depending on param_set value + # note: only needed if a separate parameter set is needed in tests + # if parameter_set == "special_param_set": + # params = {"est": value1, "parama": value2} + # return params + # + # # "default" params - always returned except for "special_param_set" value + # params = {"est": value3, "parama": value4} + # return params diff --git a/extension_templates/transformer.py b/extension_templates/transformer.py index f330db6dee8..5fccc728890 100644 --- a/extension_templates/transformer.py +++ b/extension_templates/transformer.py @@ -239,6 +239,26 @@ class MyTransformer(BaseTransformer): # valid values: boolean True (yes), False (no) # used for search index and validity checking, does not raise direct exception # + # ---------------------------------------------------------------------------- + # packaging info - only required for sktime contribution or 3rd party packages + # ---------------------------------------------------------------------------- + # + # ownership and contribution tags + # ------------------------------- + # + # author = author(s) of th estimator + # an author is anyone with significant contribution to the code at some point + "authors": ["author1", "author2"], + # valid values: str or list of str, should be GitHub handles + # this should follow best scientific contribution practices + # scope is the code, not the methodology (method is per paper citation) + # + # maintainer = current maintainer(s) of the estimator + # per algorithm maintainer role, see governance document + # this is an "owner" type role, with rights and maintenance duties + "maintainers": ["maintainer1", "maintainer2"], + # valid values: str or list of str, should be GitHub handles + # remove tag if maintained by sktime core team # # dependency tags: python version and soft dependencies # ----------------------------------------------------- @@ -249,8 +269,8 @@ class MyTransformer(BaseTransformer): # raises exception at construction if local python version is incompatible # # soft dependency requirement - "python_dependencies": None - # valid values: str or list of str + "python_dependencies": None, + # valid values: str or list of str, PEP 440 valid package version specifiers # raises exception at construction if modules at strings cannot be imported } # in case of inheritance, concrete class should typically set tags diff --git a/extension_templates/transformer_simple.py b/extension_templates/transformer_simple.py index b1e37755320..e5b29d76dae 100644 --- a/extension_templates/transformer_simple.py +++ b/extension_templates/transformer_simple.py @@ -172,6 +172,23 @@ class MyTransformer(BaseTransformer): "handles-missing-data": False, # can estimator handle missing data? # valid values: boolean True (yes), False (no) # if False, may raise exception when passed time series with missing values + # + # ownership and contribution tags + # ------------------------------- + # + # author = author(s) of th estimator + # an author is anyone with significant contribution to the code at some point + "authors": ["author1", "author2"], + # valid values: str or list of str, should be GitHub handles + # this should follow best scientific contribution practices + # scope is the code, not the methodology (method is per paper citation) + # + # maintainer = current maintainer(s) of the estimator + # per algorithm maintainer role, see governance document + # this is an "owner" type role, with rights and maintenance duties + "maintainers": ["maintainer1", "maintainer2"], + # valid values: str or list of str, should be GitHub handles + # remove tag if maintained by sktime core team } # todo: add any hyper-parameters and components to constructor diff --git a/extension_templates/transformer_supersimple.py b/extension_templates/transformer_supersimple.py index 405f8beabb9..a321336506f 100644 --- a/extension_templates/transformer_supersimple.py +++ b/extension_templates/transformer_supersimple.py @@ -75,6 +75,13 @@ class MyTransformer(BaseTransformer): # True: inner _fit, _predict, receives only single-column DataFrame # False: inner _predict gets pd.DataFrame series with any number of columns # + # specify one or multiple authors and maintainers, only for sktime contribution + "authors": ["author1", "author2"], # authors, GitHub handles + "maintainers": ["maintainer1", "maintainer2"], # maintainers, GitHub handles + # author = significant contribution to code at some point + # maintainer = algorithm maintainer role, "owner" + # remove maintainer tag if maintained by sktime core team + # # do not change these: # (look at advanced templates if you think these should change) "scitype:transform-input": "Series", diff --git a/pyproject.toml b/pyproject.toml index c0a5dbd9124..c1b5c1683b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "sktime" -version = "0.24.0" +version = "0.26.0" description = "A unified framework for machine learning with time series" readme = "README.md" keywords = [ @@ -56,8 +56,8 @@ dependencies = [ "numpy<1.27,>=1.21", # required for framework layer and base class logic "packaging", # for estimator specific dependency parsing "pandas<2.2.0,>=1.1", # pandas is the main in-memory data container - "scikit-base<0.7.0", # base module for sklearn compatible base API - "scikit-learn<1.4.0,>=0.24", # required for estimators and framework layer + "scikit-base<0.8.0", # base module for sklearn compatible base API + "scikit-learn>=0.24,<1.5.0", # required for estimators and framework layer "scipy<2.0.0,>=1.2", # required for estimators and framework layer ] @@ -77,10 +77,10 @@ dependencies = [ # or "pip install sktime[all_extras_pandas2]", to install only pandas 2 compatible deps # all_extras = [ - "arch<6.3.0,>=5.6", + "arch>=5.6,<6.4.0", "cloudpickle", "dash!=2.9.0", - "dask", + "dask<2024.1.1", "dtw-python", 'esig==0.9.7; python_version < "3.10"', 'filterpy>=1.4.5; python_version < "3.11"', @@ -107,16 +107,16 @@ all_extras = [ "statsmodels>=0.12.1", 'stumpy>=1.5.1; python_version < "3.11"', 'tbats>=1.1; python_version < "3.12"', - 'tensorflow; python_version < "3.11"', + 'tensorflow; python_version < "3.12"', 'tsfresh>=0.17; python_version < "3.12"', - 'tslearn<0.6.0,>=0.5.2; python_version < "3.11"', + 'tslearn<0.7.0,!=0.6.0,>=0.5.2; python_version < "3.11"', "xarray", ] all_extras_pandas2 = [ - "arch<6.3.0,>=5.6", + "arch>=5.6,<6.4.0", "cloudpickle", "dash!=2.9.0", - "dask<2023.7.1", + "dask<2024.1.1", "dtw-python", 'esig==0.9.7; python_version < "3.10"', 'filterpy>=1.4.5; python_version < "3.11"', @@ -142,14 +142,14 @@ all_extras_pandas2 = [ "statsmodels>=0.12.1", 'stumpy>=1.5.1; python_version < "3.11"', 'tbats>=1.1; python_version < "3.12"', - 'tensorflow; python_version < "3.11"', + 'tensorflow; python_version < "3.12"', 'tsfresh>=0.17; python_version < "3.12"', - 'tslearn<0.6.0,>=0.5.2; python_version < "3.11"', + 'tslearn<0.7.0,!=0.6.0,>=0.5.2; python_version < "3.11"', "xarray", ] # single-task dependencies, e.g., forecasting, classification, etc. -# manually curated and intentionally smaller to avoid dependeny conflicts +# manually curated and intentionally smaller to avoid dependency conflicts # names are identical with the names of the modules and estimator type strings # dependency sets are selected to cover the most popular estimators in each module # (this is a subjective choice, and may change over time as the ecosystem evolves, @@ -174,10 +174,10 @@ classification = [ ] clustering = [ 'numba<0.59,>=0.53; python_version < "3.12"', - 'tslearn<0.6.3,>=0.5.2; python_version < "3.12"', + 'tslearn<0.7.0,!=0.6.0,>=0.5.2; python_version < "3.12"', ] forecasting = [ - "arch<6.3,>=5.6", + "arch>=5.6,<6.4", 'pmdarima!=1.8.1,<2.1,>=1.8; python_version < "3.12"', "prophet<1.2,>=1.1", "skpro<2.2,>=2", @@ -200,10 +200,10 @@ regression = [ transformations = [ 'esig<0.10,>=0.9.7; python_version < "3.11"', "filterpy<1.5,>=1.4.5", - "holidays<0.35,>=0.29", - "mne<1.6,>=1.5", + "holidays>=0.29,<0.43", + "mne>=1.5,<1.7", 'numba<0.59,>=0.53; python_version < "3.12"', - "pycatch22<0.4.4,>=0.4", + "pycatch22>=0.4,<0.4.4", "pykalman-bardo<0.10,>=0.9.7", "statsmodels<0.15,>=0.12.1", 'stumpy<1.13,>=1.5.1; python_version < "3.12"', @@ -236,16 +236,16 @@ docs = [ "Sphinx!=7.2.0,<8.0.0", "sphinx-copybutton", "sphinx-design<0.6.0", - "sphinx-gallery<0.15.0", - "sphinx-issues<4.0.0", + "sphinx-gallery<0.16.0", + "sphinx-issues<5.0.0", "tabulate", ] tests = [ - "pytest<7.5,>=7.4", + "pytest>=7.4,<8.1", "pytest-cov<4.2,>=4.1", "pytest-randomly<3.16,>=3.15", "pytest-timeout>=2.1,<2.3", - "pytest-xdist<3.4,>=3.3", + "pytest-xdist>=3.3,<3.6", ] # CI related soft dependency sets - not for users of sktime, only for developers @@ -260,7 +260,8 @@ cython_extras = [ "numba<0.59", ] dl = [ - "tensorflow", + 'tensorflow<=2.14,>=2; python_version < "3.12"', + 'torch; python_version < "3.12"', ] mlflow = [ "mlflow", diff --git a/sktime/__init__.py b/sktime/__init__.py index c30032c0c59..0e1131d015a 100644 --- a/sktime/__init__.py +++ b/sktime/__init__.py @@ -1,6 +1,6 @@ """sktime.""" -__version__ = "0.24.0" +__version__ = "0.26.0" __all__ = ["show_versions"] diff --git a/sktime/_contrib/notebooks/windows_installation.ipynb b/sktime/_contrib/notebooks/windows_installation.ipynb index fc31c29689d..53f743b917c 100644 --- a/sktime/_contrib/notebooks/windows_installation.ipynb +++ b/sktime/_contrib/notebooks/windows_installation.ipynb @@ -340,7 +340,7 @@ "source": [ "# Section 4: Configuring `pre-commit` with PyCharm\n", "\n", - "`pre-commit` is a very useful package for checking your code for simple stye errors at the commit stage. This is very useful when working on large collaborative projects as it allows code reviewers to focus on the function of new code rather than conformity to style. For example, consider the following code: \n", + "`pre-commit` is a very useful package for checking your code for simple style errors at the commit stage. This is very useful when working on large collaborative projects as it allows code reviewers to focus on the function of new code rather than conformity to style. For example, consider the following code: \n", "\n", "![21_pre-commit_examples.png](img/windows_installation/21_pre-commit_examples.png)\n", "\n", diff --git a/sktime/alignment/dtw_numba.py b/sktime/alignment/dtw_numba.py index b466cec72e0..bf806b6538b 100644 --- a/sktime/alignment/dtw_numba.py +++ b/sktime/alignment/dtw_numba.py @@ -117,11 +117,16 @@ class AlignerDtwNumba(BaseAligner): """ _tags = { + # packaging info + # -------------- + "authors": ["chrisholder", "TonyBagnall", "fkiraly"], + "python_dependencies": "numba", + # estimator type + # -------------- "capability:multiple-alignment": False, # can align more than two sequences? "capability:distance": True, # does compute/return overall distance? "capability:distance-matrix": True, # does compute/return distance matrix? "X_inner_mtype": "numpy3D", - "python_dependencies": "numba", } def __init__( diff --git a/sktime/alignment/dtw_python.py b/sktime/alignment/dtw_python.py index 7334c2b73de..fbd211f858d 100644 --- a/sktime/alignment/dtw_python.py +++ b/sktime/alignment/dtw_python.py @@ -47,12 +47,17 @@ class AlignerDTW(BaseAligner): """ _tags = { + # packaging info + # -------------- + "authors": ["fkiraly"], + "python_dependencies": "dtw-python", + "python_dependencies_alias": {"dtw-python": "dtw"}, + # estimator type + # -------------- "capability:multiple-alignment": False, # can align more than two sequences? "capability:distance": True, # does compute/return overall distance? "capability:distance-matrix": True, # does compute/return distance matrix? "alignment_type": "partial", - "python_dependencies": "dtw-python", - "python_dependencies_alias": {"dtw-python": "dtw"}, } def __init__( diff --git a/sktime/alignment/edit_numba.py b/sktime/alignment/edit_numba.py index 5af0c3a39f2..6b012872e87 100644 --- a/sktime/alignment/edit_numba.py +++ b/sktime/alignment/edit_numba.py @@ -112,13 +112,18 @@ class AlignerEditNumba(BaseAligner): """ _tags = { + # packaging info + # -------------- + "authors": ["chrisholder", "TonyBagnall", "fkiraly"], + "python_dependencies": "numba", + # estimator type + # -------------- "symmetric": True, # all the distances are symmetric "capability:multiple-alignment": False, # can align more than two sequences? "capability:distance": True, # does compute/return overall distance? "capability:distance-matrix": True, # does compute/return distance matrix? "alignment_type": "partial", "X_inner_mtype": "numpy3D", - "python_dependencies": "numba", } ALLOWED_DISTANCE_STR = ["lcss", "edr", "erp", "twe"] diff --git a/sktime/alignment/lucky.py b/sktime/alignment/lucky.py index 5fb25afcd14..ddba6d70704 100644 --- a/sktime/alignment/lucky.py +++ b/sktime/alignment/lucky.py @@ -30,6 +30,11 @@ class AlignerLuckyDtw(BaseAligner): """ _tags = { + # packaging info + # -------------- + "authors": ["fkiraly", "Krisztian A Buza"], + # estimator type + # -------------- "capability:multiple-alignment": False, # can align more than two sequences? "capability:distance": True, # does compute/return overall distance? "capability:distance-matrix": True, # does compute/return distance matrix? diff --git a/sktime/alignment/naive.py b/sktime/alignment/naive.py index d78f5f6caca..9a04f59a7f1 100644 --- a/sktime/alignment/naive.py +++ b/sktime/alignment/naive.py @@ -25,6 +25,11 @@ class AlignerNaive(BaseAligner): """ _tags = { + # packaging info + # -------------- + "authors": ["fkiraly"], + # estimator type + # -------------- "capability:multiple-alignment": True, # can align more than two sequences? } diff --git a/sktime/alignment/utils/utils_align.py b/sktime/alignment/utils/utils_align.py index e88848830fa..a0db08d78ec 100644 --- a/sktime/alignment/utils/utils_align.py +++ b/sktime/alignment/utils/utils_align.py @@ -67,7 +67,13 @@ def convert_align_to_align_loc(align, X, align_name="align", df_name="X", copy=T """ from sktime.datatypes import check_is_mtype - check_is_mtype(align, "alignment", scitype="Alignment", var_name=align_name) + check_is_mtype( + align, + "alignment", + scitype="Alignment", + var_name=align_name, + msg_return_dict="list", + ) if not isinstance(X, list): raise ValueError(f"{df_name} must be a list of pandas.DataFrame") diff --git a/sktime/annotation/clasp.py b/sktime/annotation/clasp.py index c49306062a6..0e07ab0677f 100644 --- a/sktime/annotation/clasp.py +++ b/sktime/annotation/clasp.py @@ -191,7 +191,7 @@ class ClaSPSegmentation(BaseSeriesAnnotator): fmt : str {"dense", "sparse"}, optional (default="sparse") Annotation output format: * If "sparse", a pd.Series of the found Change Points is returned - * If "dense", a pd.IndexSeries with the Segmenation of X is returned + * If "dense", a pd.IndexSeries with the Segmentation of X is returned exclusion_radius : int Exclusion Radius for change points to be non-trivial matches diff --git a/sktime/annotation/ggs.py b/sktime/annotation/ggs.py index 29ec206a8c8..2b8262061a2 100644 --- a/sktime/annotation/ggs.py +++ b/sktime/annotation/ggs.py @@ -34,14 +34,15 @@ import logging import math -from dataclasses import asdict, dataclass, field -from typing import Dict, List, Tuple +from dataclasses import dataclass, field +from typing import List, Tuple import numpy as np import numpy.typing as npt +import pandas as pd from sklearn.utils.validation import check_random_state -from sktime.base import BaseEstimator +from sktime.annotation.base._base import BaseSeriesAnnotator from sktime.utils.validation._dependencies import _check_estimator_deps logger = logging.getLogger(__name__) @@ -367,7 +368,7 @@ def find_change_points(self, data: npt.ArrayLike) -> List[int]: return change_points -class GreedyGaussianSegmentation(BaseEstimator): +class GreedyGaussianSegmentation(BaseSeriesAnnotator): """Greedy Gaussian Segmentation Estimator. The method approximates solutions for the problem of breaking a @@ -408,10 +409,6 @@ class GreedyGaussianSegmentation(BaseEstimator): change_points_: array_like, default=[] Locations of change points as integer indexes. By convention change points include the identity segmentation, i.e. first and last index + 1 values. - _intermediate_change_points: List[List[int]], default=[] - Intermediate values of change points for each value of k = 1...k_max - _intermediate_ll: List[float], default=[] - Intermediate values for log-likelihood for each value of k = 1...k_max Notes ----- @@ -428,6 +425,8 @@ class GreedyGaussianSegmentation(BaseEstimator): https://doi.org/10.1007/s11634-018-0335-0 """ + _tags = {"fit_is_empty": True} + def __init__( self, k_max: int = 10, @@ -444,7 +443,7 @@ def __init__( self.random_state = random_state _check_estimator_deps(self) - super().__init__() + super().__init__(fmt="dense", labels="int_label") self._adaptee = GGS( k_max=k_max, @@ -454,33 +453,47 @@ def __init__( random_state=random_state, ) - def fit(self, X: npt.ArrayLike, y: npt.ArrayLike = None): - """Fit method for compatibility with sklearn-type estimator interface. + @property + def _intermediate_change_points(self) -> List[List[int]]: + """Intermediate values of change points for each value of k = 1...k_max. + + Default value is an empty list. + """ + return self._adaptee._intermediate_change_points - It sets the internal state of the estimator and returns the initialized - instance. + @property + def _intermediate_ll(self) -> List[float]: + """Intermediate values for log-likelihood for each value of k = 1...k_max. + + Default value is an empty list. + """ + return self._adaptee._intermediate_ll + + def _fit(self, X, Y=None): + """Fit method for compatibility with sklearn-type estimator interface. Parameters ---------- - X: array_like - 2D `array_like` representing time series with sequence index along - the first dimension and value series as columns. + X: array_like (1D or 2D), pd.Series, or pd.DataFrame + 1D array of timeseries values, or 2D array with index along the first + dimension and columns representing features of the timeseries. If pd.Series, + the values of the timeseries are the values of the series. If pd.DataFrame, + each column represents a feature of the timeseries. y: array_like Placeholder for compatibility with sklearn-api, not used, default=None. """ - self._adaptee.initialize_intermediates() return self - def predict(self, X: npt.ArrayLike, y: npt.ArrayLike = None) -> npt.ArrayLike: + def _predict(self, X) -> npt.ArrayLike: """Perform segmentation. Parameters ---------- - X: array_like - 2D `array_like` representing time series with sequence index along - the first dimension and value series as columns. - y: array_like - Placeholder for compatibility with sklearn-api, not used, default=None. + X: array_like (1D or 2D), pd.Series, or pd.DataFrame + 1D array of timeseries values, or 2D array with index along the first + dimension and columns representing features of the timeseries. If pd.Series, + the values of the timeseries are the values of the series. If pd.DataFrame, + each column represents a feature of the timeseries. Returns ------- @@ -489,6 +502,15 @@ def predict(self, X: npt.ArrayLike, y: npt.ArrayLike = None) -> npt.ArrayLike: dimension of X. The numerical values represent distinct segments labels for each of the data points. """ + if isinstance(X, pd.Series): + X = X.values[:, np.newaxis] + elif isinstance(X, pd.DataFrame): + X = X.values + elif len(X.shape) == 1: + X = X[:, np.newaxis] + elif len(X.shape) > 2: + raise ValueError("X must not have more than two dimensions.") + self._adaptee.initialize_intermediates() self.change_points_ = self._adaptee.find_change_points(X) labels = np.zeros(X.shape[0], dtype=np.int32) @@ -498,16 +520,16 @@ def predict(self, X: npt.ArrayLike, y: npt.ArrayLike = None) -> npt.ArrayLike: labels[start:stop] = i return labels - def fit_predict(self, X: npt.ArrayLike, y: npt.ArrayLike = None) -> npt.ArrayLike: + def fit_predict(self, X) -> npt.ArrayLike: """Perform segmentation. Parameters ---------- - X: array_like - 2D `array_like` representing time series with sequence index along - the first dimension and value series as columns. - y: array_like - Placeholder for compatibility with sklearn-api, not used, default=None. + X: array_like (1D or 2D), pd.Series, or pd.DataFrame + 1D array of timeseries values, or 2D array with index along the first + dimension and columns representing features of the timeseries. If pd.Series, + the values of the timeseries are the values of the series. If pd.DataFrame, + each column represents a feature of the timeseries. Returns ------- @@ -516,49 +538,21 @@ def fit_predict(self, X: npt.ArrayLike, y: npt.ArrayLike = None) -> npt.ArrayLik dimension of X. The numerical values represent distinct segments labels for each of the data points. """ - return self.fit(X, y).predict(X, y) + return self.fit(X, None).predict(X) - def get_params(self, deep: bool = True) -> Dict: - """Return initialization parameters. + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. Parameters ---------- - deep: bool - Dummy argument for compatibility with sklearn-api, not used. + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. Returns ------- - params: dict - Dictionary with the estimator's initialization parameters, with - keys being argument names and values being argument values. + params : dict or list of dict """ - attrs_to_ignore = [ - "change_points_", - "_intermediate_change_points", - "_intermediate_ll", - ] - params = asdict(self._adaptee) - params = { - key: value for key, value in params.items() if key not in attrs_to_ignore - } + params = {"k_max": 10, "lamb": 1.0} return params - - def set_params(self, **parameters): - """Set the parameters of this object. - - Parameters - ---------- - parameters : dict - Initialization parameters for th estimator. - - Returns - ------- - self : reference to self (after parameters have been set) - """ - for key, value in parameters.items(): - setattr(self._adaptee, key, value) - return self - - def __repr__(self) -> str: - """Return a string representation of the estimator.""" - return self._adaptee.__repr__() diff --git a/sktime/annotation/tests/test_plotting.py b/sktime/annotation/tests/test_plotting.py new file mode 100644 index 00000000000..6474229d392 --- /dev/null +++ b/sktime/annotation/tests/test_plotting.py @@ -0,0 +1,75 @@ +import numpy as np +import pandas as pd +import pytest + +from sktime.annotation.plotting.utils import ( + plot_time_series_with_change_points, + plot_time_series_with_profiles, +) +from sktime.utils.validation._dependencies import _check_soft_dependencies + + +@pytest.fixture +def time_series_data(): + ts_data = np.random.rand(100) + ts = pd.DataFrame({"Data": ts_data}) + true_cps = [4, 8] + font_size = 12 + ts_name = "Test Time Series" + profiles = np.array([np.random.rand(100) for _ in range(20)]) + found_cps = [35, 65] + score_name = "Custom Score" + return { + "ts_name": ts_name, + "ts": ts, + "true_cps": true_cps, + "font_size": font_size, + "profiles": profiles, + "found_cps": found_cps, + "score_name": score_name, + } + + +@pytest.mark.skipif( + not _check_soft_dependencies("matplotlib", "seaborn", severity="none"), + reason="Seaborn is required as a dependency for this plot.", +) +def test_plot_time_series_with_change_points(time_series_data): + import matplotlib.pyplot as plt + + # Access data from the fixture + ts_name = time_series_data["ts_name"] + ts = time_series_data["ts"] + true_cps = time_series_data["true_cps"] + font_size = time_series_data["font_size"] + + fig, ax = plot_time_series_with_change_points(ts_name, ts, true_cps, font_size) + + assert isinstance(fig, plt.Figure) + assert isinstance(ax, plt.Axes) + assert ax.get_title() == ts_name + + +@pytest.mark.skipif( + not _check_soft_dependencies("seaborn", "matplotlib", severity="none"), + reason="Seaborn is required as a dependency for this plot.", +) +def test_plot_time_series_with_profiles(time_series_data): + import matplotlib.pyplot as plt + + # Access data from the fixture + ts_name = time_series_data["ts_name"] + ts = time_series_data["ts"] + true_cps = time_series_data["true_cps"] + font_size = time_series_data["font_size"] + profiles = time_series_data["profiles"] + found_cps = time_series_data["found_cps"] + score_name = time_series_data["score_name"] + + fig, ax = plot_time_series_with_profiles( + ts_name, ts, profiles, true_cps, found_cps, score_name, font_size + ) + + assert isinstance(fig, plt.Figure) + assert isinstance(ax, np.ndarray) + assert ax[0].get_title() == ts_name diff --git a/sktime/base/__init__.py b/sktime/base/__init__.py index 4a30db2d045..6cf431c8361 100644 --- a/sktime/base/__init__.py +++ b/sktime/base/__init__.py @@ -6,10 +6,12 @@ __all__ = [ "BaseObject", "BaseEstimator", + "BasePanelMixin", "_HeterogenousMetaEstimator", "load", ] from sktime.base._base import BaseEstimator, BaseObject +from sktime.base._base_panel import BasePanelMixin from sktime.base._meta import _HeterogenousMetaEstimator from sktime.base._serialize import load diff --git a/sktime/base/_base.py b/sktime/base/_base.py index 6c89b5ed34e..bac9533a719 100644 --- a/sktime/base/_base.py +++ b/sktime/base/_base.py @@ -66,6 +66,11 @@ class name: BaseEstimator from sktime.exceptions import NotFittedError from sktime.utils.random_state import set_random_state +SERIALIZATION_FORMATS = { + "pickle", + "cloudpickle", +} + class BaseObject(_BaseObject): """Base class for parametric objects with tags in sktime. @@ -73,7 +78,15 @@ class BaseObject(_BaseObject): Extends skbase BaseObject with additional features. """ - _config = {"warnings": "on"} + _config = { + "warnings": "on", + "backend:parallel": None, # parallelization backend for broadcasting + # {None, "dask", "loky", "multiprocessing", "threading"} + # None: no parallelization + # "loky", "multiprocessing" and "threading": uses `joblib` Parallel loops + # "dask": uses `dask`, requires `dask` package in environment + "backend:parallel:params": None, # params for parallelization backend, + } _config_doc = { "display": """ @@ -86,8 +99,8 @@ class BaseObject(_BaseObject): "print_changed_only": """ print_changed_only : bool, default=True whether printing of self lists only self-parameters that differ - from defaults (False), or all parameter names and values (False) - does not nest, i.e., only affects self and not component estimators + from defaults (False), or all parameter names and values (False). + Does not nest, i.e., only affects self and not component estimators. """, "warnings": """ warnings : str, "on" (default), or "off" @@ -96,12 +109,38 @@ class BaseObject(_BaseObject): * "on" = will raise warnings from sktime * "off" = will not raise warnings from sktime """, + "backend:parallel": """ + backend:parallel : str, optional, default="None" + backend to use for parallelization when broadcasting/vectorizing, one of + + - "None": executes loop sequentally, simple list comprehension + - "loky", "multiprocessing" and "threading": uses ``joblib.Parallel`` + - "joblib": custom and 3rd party ``joblib`` backends, e.g., ``spark`` + - "dask": uses ``dask``, requires ``dask`` package in environment + """, + "backend:parallel:params": """ + backend:parallel:params : dict, optional, default={} (no parameters passed) + additional parameters passed to the parallelization backend as config. + Valid keys depend on the value of ``backend:parallel``: + + - "None": no additional parameters, ``backend_params`` is ignored + - "loky", "multiprocessing" and "threading": default ``joblib`` backends + any valid keys for ``joblib.Parallel`` can be passed here, e.g., + ``n_jobs``, with the exception of ``backend`` which is directly + controlled by ``backend``. + If ``n_jobs`` is not passed, it will default to ``-1``, other parameters + will default to ``joblib`` defaults. + - "joblib": custom and 3rd party ``joblib`` backends, + e.g., ``spark``. Any valid keys for ``joblib.Parallel`` + can be passed here, e.g., ``n_jobs``, + ``backend`` must be passed as a key of ``backend_params`` in this case. + If ``n_jobs`` is not passed, it will default to ``-1``, other parameters + will default to ``joblib`` defaults. + - "dask": any valid keys for ``dask.compute`` can be passed, + e.g., ``scheduler`` + """, } - def __init__(self): - super().__init__() - self.__class__.set_config.__doc__ = self._get_set_config_doc() - def __eq__(self, other): """Equality dunder. Checks equal class and parameters. @@ -110,7 +149,7 @@ def __eq__(self, other): Nested BaseObject descendants from get_params are compared via __eq__ as well. """ - from sktime.utils._testing.deep_equals import deep_equals + from sktime.utils.deep_equals import deep_equals if not isinstance(other, BaseObject): return False @@ -157,7 +196,16 @@ def _get_set_config_doc(cls): doc += doc_end return doc - def save(self, path=None): + @classmethod + def _init_dynamic_doc(cls): + """Set docstring for set_config from self._config_doc.""" + try: # try/except to avoid unexpected failures + cls.set_config = deepcopy_func(cls.set_config) + cls.set_config.__doc__ = cls._get_set_config_doc() + except Exception: + pass + + def save(self, path=None, serialization_format="pickle"): """Save serialized self to bytes-like object or to (.zip) file. Behaviour: @@ -177,6 +225,12 @@ def save(self, path=None): path="/home/stored/estimator" then a zip file `estimator.zip` will be stored in `/home/stored/`. + serialization_format: str, default = "pickle" + Module to use for serialization. + The available options are "pickle" and "cloudpickle". + Note that non-default formats might require + installation of other soft dependencies. + Returns ------- if `path` is None - in-memory serialized self @@ -187,21 +241,44 @@ def save(self, path=None): from pathlib import Path from zipfile import ZipFile - if path is None: - return (type(self), pickle.dumps(self)) - if not isinstance(path, (str, Path)): + from sktime.utils.validation._dependencies import _check_soft_dependencies + + if serialization_format not in SERIALIZATION_FORMATS: + raise ValueError( + f"The provided `serialization_format`='{serialization_format}' " + "is not yet supported. The possible formats are: " + f"{SERIALIZATION_FORMATS}." + ) + + if path is not None and not isinstance(path, (str, Path)): raise TypeError( "`path` is expected to either be a string or a Path object " f"but found of type:{type(path)}." ) + if path is not None: + path = Path(path) if isinstance(path, str) else path + path.mkdir() + + if serialization_format == "cloudpickle": + _check_soft_dependencies("cloudpickle", severity="error") + import cloudpickle + + if path is None: + return (type(self), cloudpickle.dumps(self)) - path = Path(path) if isinstance(path, str) else path - path.mkdir() + with open(path / "_metadata", "wb") as file: + cloudpickle.dump(type(self), file) + with open(path / "_obj", "wb") as file: + cloudpickle.dump(self, file) - with open(path / "_metadata", "wb") as file: - pickle.dump(type(self), file) - with open(path / "_obj", "wb") as file: - pickle.dump(self, file) + elif serialization_format == "pickle": + if path is None: + return (type(self), pickle.dumps(self)) + + with open(path / "_metadata", "wb") as file: + pickle.dump(type(self), file) + with open(path / "_obj", "wb") as file: + pickle.dump(self, file) shutil.make_archive(base_name=path, format="zip", root_dir=path) shutil.rmtree(path) @@ -550,12 +627,12 @@ def _get_fitted_params_default(self, obj=None): # default retrieves all self attributes ending in "_" # and returns them with keys that have the "_" removed - fitted_params = [attr for attr in dir(obj) if attr.endswith("_")] - fitted_params = [x for x in fitted_params if not x.startswith("_")] - fitted_params = [x for x in fitted_params if hasattr(obj, x)] - fitted_param_dict = {p[:-1]: getattr(obj, p) for p in fitted_params} - - return fitted_param_dict + fitted_params = { + attr[:-1]: getattr(obj, attr) + for attr in dir(obj) + if attr.endswith("_") and not attr.startswith("_") and hasattr(obj, attr) + } + return fitted_params def _get_fitted_params(self): """Get fitted parameters. @@ -580,3 +657,20 @@ def _clone_estimator(base_estimator, random_state=None): set_random_state(estimator, random_state) return estimator + + +def deepcopy_func(f, name=None): + """Deepcopy of a function.""" + import types + + return types.FunctionType( + f.__code__, + f.__globals__, + name or f.__name__, + f.__defaults__, + f.__closure__, + ) + + +# initialize dynamic docstrings +BaseObject._init_dynamic_doc() diff --git a/sktime/base/_base_panel.py b/sktime/base/_base_panel.py new file mode 100644 index 00000000000..c6c9008a2c4 --- /dev/null +++ b/sktime/base/_base_panel.py @@ -0,0 +1,485 @@ +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +"""Intermediate base class mixin with common functionality for panel tasks. + +Inherits from BaseEstimator, descendents are: + +BaseClassifier +BaseRegressor +""" + +__author__ = ["fkiraly"] +__all__ = ["BasePanelMixin"] + + +import numpy as np +import pandas as pd + +from sktime.base import BaseEstimator +from sktime.datatypes import ( + MTYPE_LIST_PANEL, + MTYPE_LIST_TABLE, + VectorizedDF, + check_is_error_msg, + check_is_scitype, + convert, +) +from sktime.utils.warnings import warn + + +class BasePanelMixin(BaseEstimator): + """Abstract base class for time series panel tasks, e.g., classifiers, regressors. + + The class contains boilerplate for checks and data conversions, + which are common to multiple descendants, most importantly, + BaseClassifier and BaseRegressor. + """ + + # convenience constant to control which metadata of input data + # are regularly retrieved in input checks + METADATA_REQ_IN_CHECKS = [ + "n_instances", + "has_nans", + "is_univariate", + "is_equal_length", + ] + + # attribute name where vectorized estimators are stored + VECTORIZATION_ATTR = "estimators_" # e.g., classifiers_, regressors_ + + # used in error messages + TASK = "panel data tasks" # e.g., classification, regression + EST_TYPE = "estimator" # e.g., classifier, regressor + EST_TYPE_PLURAL = "estimators" # e.g., classifiers, regressors + + def _vectorize(self, methodname, **kwargs): + """Vectorized/iterated loop over methods of BaseClassifier, BaseRegressor. + + Stores one estimator per loop index. + """ + # retrieve data arguments + X = kwargs.pop("X", None) + y = kwargs.pop("y", None) + + # add some common arguments to kwargs + kwargs["rowname_default"] = self.EST_TYPE_PLURAL + kwargs["colname_default"] = self.EST_TYPE_PLURAL + kwargs["backend"] = self.get_config()["backend:parallel"] + kwargs["backend_params"] = self.get_config()["backend:parallel:params"] + + if methodname == "fit": + self._yvec = y + + ests_ = self._yvec.vectorize_est(self, method="clone", **kwargs) + ests_fit = self._yvec.vectorize_est( + ests_, + method=methodname, + args={"y": y}, + X=X, + **kwargs, + ) + setattr(self, self.VECTORIZATION_ATTR, ests_fit) + return self + else: # methodname == "predict" or methodname == "predict_proba": + ests_ = getattr(self, self.VECTORIZATION_ATTR) + y_pred = self._yvec.vectorize_est( + ests_, + method=methodname, + X=X, + **kwargs, + ) + y_pred = pd.DataFrame( + {str(i): y_pred[col].values[0] for i, col in enumerate(y_pred.columns)} + ) + return y_pred + + def _fit_predict_boilerplate(self, X, y, cv, change_state, method): + """Boilerplate logic for fit_predict and fit_predict_proba.""" + from sklearn.model_selection import KFold + + if isinstance(cv, int): + random_state = getattr(self, "random_state", None) + cv = KFold(cv, random_state=random_state, shuffle=True) + + if change_state: + self.reset() + est = self + else: + est = self.clone() + + if cv is None: + return getattr(est.fit(X, y), method)(X) + elif change_state: + self.fit(X, y) + + # we now know that cv is an sklearn splitter + X, y = self._internal_convert(X, y) + X_metadata = self._check_input( + X, y, return_metadata=self.METADATA_REQ_IN_CHECKS + ) + X_mtype = X_metadata["mtype"] + # Check this estimator can handle characteristics + self._check_capabilities(X_metadata) + + # handle single class case + if len(self._class_dictionary) == 1: + return self._single_class_y_pred(X) + + # Convert data to format easily usable for applying cv + if isinstance(X, np.ndarray): + X = convert( + X, + from_type=X_mtype, + to_type="numpy3D", + as_scitype="Panel", + store_behaviour="freeze", + ) + else: + X = convert( + X, + from_type=X_mtype, + to_type="nested_univ", + as_scitype="Panel", + store_behaviour="freeze", + ) + + if method == "predict_proba": + y_pred = np.empty([len(y), len(np.unique(y))]) + else: + y_pred = np.empty_like(y) + y_pred[:] = -1 + if isinstance(X, np.ndarray): + for tr_idx, tt_idx in cv.split(X): + X_train = X[tr_idx] + X_test = X[tt_idx] + y_train = y[tr_idx] + fitted_est = self.clone().fit(X_train, y_train) + y_pred[tt_idx] = getattr(fitted_est, method)(X_test) + else: + for tr_idx, tt_idx in cv.split(X): + X_train = X.iloc[tr_idx] + X_test = X.iloc[tt_idx] + y_train = y[tr_idx] + fitted_est = self.clone().fit(X_train, y_train) + y_pred[tt_idx] = getattr(fitted_est, method)(X_test) + + return y_pred + + def _check_convert_X_for_predict(self, X): + """Input checks, capability checks, repeated in all predict/score methods. + + Parameters + ---------- + X : any object (to check/convert) + should be of a supported Panel mtype or 2D numpy.ndarray + + Returns + ------- + X: an object of a supported Panel mtype, numpy3D if X was a 2D numpy.ndarray + + Raises + ------ + ValueError if X is of invalid input data type, or there is not enough data + ValueError if the capabilities in self._tags do not handle the data. + """ + X = self._internal_convert(X) + X_metadata = self._check_input(X, return_metadata=self.METADATA_REQ_IN_CHECKS) + X_mtype = X_metadata["mtype"] + # Check that estimator can handle characteristics + self._check_capabilities(X_metadata) + # Convert data as dictated by the estimator tags + X = self._convert_X(X, X_mtype=X_mtype) + + return X + + def _check_capabilities(self, X_metadata): + """Check whether this estimator can handle the data characteristics. + + Parameters + ---------- + missing : boolean, does the data passed to fit contain missing values? + multivariate : boolean, does the data passed to fit contain missing values? + unequal : boolea, do the time series passed to fit have variable lengths? + + Raises + ------ + ValueError if the capabilities in self._tags do not handle the data. + """ + missing = X_metadata["has_nans"] + multivariate = not X_metadata["is_univariate"] + unequal = not X_metadata["is_equal_length"] + + allow_multivariate = self.get_tag("capability:multivariate") + allow_missing = self.get_tag("capability:missing_values") + allow_unequal = self.get_tag("capability:unequal_length") + + self_name = type(self).__name__ + + # identify problems, mismatch of capability and inputs + problems = [] + if missing and not allow_missing: + problems += ["missing values"] + if multivariate and not allow_multivariate: + problems += ["multivariate series"] + if unequal and not allow_unequal: + problems += ["unequal length series"] + + # construct error message + problems_and = " and ".join(problems) + problems_or = " or ".join(problems) + msg = ( + f"Data seen by {self_name} instance has {problems_and}, " + f"but this {self_name} instance cannot handle {problems_or}. " + f"Calls with {problems_or} may result in error or unreliable results." + ) + + # raise exception or warning with message + # if self is composite, raise a warning, since passing could be fine + # see discussion in PR 2366 why + if len(problems) > 0: + if self.is_composite(): + warn(msg, obj=self) + else: + raise ValueError(msg) + + def _convert_X(self, X, X_mtype): + """Convert equal length series from DataFrame to numpy array or vice versa. + + Parameters + ---------- + X : input data for the estimator, any Panel mtype + X_mtype : str, a Panel mtype string, e.g., "pd_multiindex", "numpy3D" + + Returns + ------- + X : input X converted to type in "X_inner_mtype" tag + usually a pd.DataFrame (nested) or 3D np.ndarray + Checked and possibly converted input data + """ + inner_type = self.get_tag("X_inner_mtype") + # convert pd.DataFrame + X = convert( + X, + from_type=X_mtype, + to_type=inner_type, + as_scitype="Panel", + ) + return X + + def _check_y(self, y=None, return_to_mtype=False): + """Check and coerce X/y for fit/transform functions. + + Parameters + ---------- + y : pd.DataFrame, pd.Series or np.ndarray + return_to_mtype : bool + whether to return the mtype of y output + + Returns + ------- + y_inner : object of sktime compatible time series type + can be Series, Panel, Hierarchical + y_metadata : dict + metadata of y, returned by check_is_scitype + y_mtype : str, only returned if return_to_mtype=True + mtype of y_inner, after convert + """ + if y is None: + if return_to_mtype: + return None, None, None + else: + return None, None + + capa_multioutput = self.get_tag("capability:multioutput") + y_inner_mtype = self.get_tag("y_inner_mtype") + + y_valid, y_msg, y_metadata = check_is_scitype( + y, "Table", return_metadata=["is_univariate"] + ) + + if not y_valid: + allowed_msg = ( + f"In {self.TASK}, y must be of a supported type, " + f"for instance 1D or 2D numpy arrays, pd.DataFrame, or pd.Series. " + f"Allowed compatible mtype format specifications are:" + f" {MTYPE_LIST_TABLE} ." + ) + check_is_error_msg( + y_msg, var_name="y", allowed_msg=allowed_msg, raise_exception=True + ) + + y_uni = y_metadata["is_univariate"] + y_mtype = y_metadata["mtype"] + + requires_vectorization = not capa_multioutput and not y_uni + + if requires_vectorization: + y_df = convert( + y, + from_type=y_mtype, + to_type="pd_DataFrame_Table", + as_scitype="Table", + store=self._converter_store_y, + ) + y_vec = VectorizedDF([y_df], iterate_cols=True) + if return_to_mtype: + return y_vec, y_metadata, "pd_DataFrame_Table" + else: + return y_vec, y_metadata + + y_inner, y_inner_mtype = convert( + y, + from_type=y_mtype, + to_type=y_inner_mtype, + as_scitype="Table", + store=self._converter_store_y, + return_to_mtype=True, + ) + + if return_to_mtype: + return y_inner, y_metadata, y_inner_mtype + else: + return y_inner, y_metadata + + def _convert_output_y(self, y): + """Convert output y to original format. + + Parameters + ---------- + y : np.ndarray or pd.DataFrame + output to convert + + Returns + ------- + y : np.ndarray or pd.DataFrame + """ + # for consistency with legacy behaviour: + # output is coerced to numpy1D in case of univariate output + if not self._y_metadata["is_univariate"]: + output_mtype = self._y_metadata["mtype"] + converter_store = self._converter_store_y + else: + output_mtype = "numpy1D" + converter_store = None + + # inner return mtype is what we convert from + # special treatment for 1D numpy array + # this can be returned in composites due to + # current downwards compatible choice "1D return is always numpy" + if isinstance(y, np.ndarray) and y.ndim == 1: + inner_return_mtype = "numpy1D" + else: + inner_return_mtype = self._y_inner_mtype + + y = convert( + y, + from_type=inner_return_mtype, + to_type=output_mtype, + as_scitype="Table", + store=converter_store, + store_behaviour="freeze", + ) + return y + + def _check_input(self, X, y=None, enforce_min_instances=1, return_metadata=True): + """Check whether input X and y are valid formats with minimum data. + + Raises a ValueError if the input is not valid. + + Parameters + ---------- + X : check whether conformant with any sktime Panel mtype specification + y : check whether a pd.Series or np.array + enforce_min_instances : int, optional (default=1) + check there are a minimum number of instances. + return_metadata : bool, str, or list of str + metadata fields to return with X_metadata, input to check_is_scitype + + Returns + ------- + metadata : dict with metadata for X returned by datatypes.check_is_scitype + + Raises + ------ + ValueError + If y or X is invalid input data type, or there is not enough data + """ + # Check X is valid input type and recover the data characteristics + X_valid, msg, X_metadata = check_is_scitype( + X, scitype="Panel", return_metadata=return_metadata + ) + # raise informative error message if X is in wrong format + allowed_msg = ( + f"Allowed scitypes for {self.EST_TYPE_PLURAL} are Panel mtypes, " + f"for instance a pandas.DataFrame with MultiIndex and last(-1) " + f"level an sktime compatible time index. " + f"Allowed compatible mtype format specifications are: {MTYPE_LIST_PANEL} ." + ) + if not X_valid: + check_is_error_msg( + msg, var_name="X", allowed_msg=allowed_msg, raise_exception=True + ) + + n_cases = X_metadata["n_instances"] + if n_cases < enforce_min_instances: + raise ValueError( + f"Minimum number of cases required is {enforce_min_instances} but X " + f"has : {n_cases}" + ) + + # Check y if passed + if y is not None: + # Check y valid input + if not isinstance(y, (pd.Series, pd.DataFrame, np.ndarray)): + raise ValueError( + "y must be a np.array or a pd.Series or pd.DataFrame, but found ", + f"type: {type(y)}", + ) + # Check matching number of labels + n_labels = y.shape[0] + if n_cases != n_labels: + raise ValueError( + f"Mismatch in number of cases. Number in X = {n_cases} nos in y = " + f"{n_labels}" + ) + if isinstance(y, np.ndarray): + if y.ndim > 2: + raise ValueError( + f"np.ndarray y must be 1-dimensional or 2-dimensional, " + f"but found {y.ndim} dimensions" + ) + # warn if only a single class label is seen + # this should not raise exception since this can occur by train subsampling + if len(np.unique(y)) == 1: + warn( + "only single label seen in y passed to " + f"fit of {self.EST_TYPE} {type(self).__name__}", + obj=self, + ) + + return X_metadata + + def _internal_convert(self, X, y=None): + """Convert X and y if necessary as a user convenience. + + Convert X to a 3D numpy array if already a 2D and convert y into an 1D numpy + array if passed as a Series. + + Parameters + ---------- + X : an object of a supported Panel mtype, or 2D numpy.ndarray + y : np.ndarray or pd.Series + + Returns + ------- + X: an object of a supported Panel mtype, numpy3D if X was a 2D numpy.ndarray + y: np.ndarray + """ + if isinstance(X, np.ndarray): + # Temporary fix to insist on 3D numpy. For univariate problems, + # most panel estimators simply convert back to 2D. This squeezing should be + # done here, but touches a lot of files, so will get this to work first. + if X.ndim == 2: + X = X.reshape(X.shape[0], 1, X.shape[1]) + if y is None: + return X + return X, y diff --git a/sktime/base/_meta.py b/sktime/base/_meta.py index 78901df761d..6e49c88e68a 100644 --- a/sktime/base/_meta.py +++ b/sktime/base/_meta.py @@ -97,29 +97,31 @@ def is_composite(self): def _get_params(self, attr, deep=True, fitted=False): if fitted: - method = "_get_fitted_params" - methodd = "get_fitted_params" + private_method = "_get_fitted_params" + public_method = "get_fitted_params" deepkw = {} else: - method = "get_params" - methodd = "get_params" + private_method = "get_params" + public_method = "get_params" deepkw = {"deep": deep} - out = getattr(super(), method)(**deepkw) + out = getattr(super(), private_method)(**deepkw) if deep and hasattr(self, attr): estimators = getattr(self, attr) estimators = [(x[0], x[1]) for x in estimators] out.update(estimators) for name, estimator in estimators: # checks estimator has the method we want to call - cond1 = hasattr(estimator, methodd) + cond1 = hasattr(estimator, public_method) # checks estimator is fitted if calling get_fitted_params is_fitted = hasattr(estimator, "is_fitted") and estimator.is_fitted # if we call get_params and not get_fitted_params, this is True cond2 = not fitted or is_fitted # check both conditions together if cond1 and cond2: - for key, value in getattr(estimator, methodd)(**deepkw).items(): + for key, value in getattr(estimator, public_method)( + **deepkw + ).items(): out[f"{name}__{key}"] = value return out diff --git a/sktime/base/_panel/__init__.py b/sktime/base/_panel/__init__.py new file mode 100644 index 00000000000..a4a06b1b7fa --- /dev/null +++ b/sktime/base/_panel/__init__.py @@ -0,0 +1,2 @@ +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +"""Base classes for specific panel estimators, e.g., classifier and regressor.""" diff --git a/sktime/base/_panel/forest/__init__.py b/sktime/base/_panel/forest/__init__.py new file mode 100644 index 00000000000..73964dae484 --- /dev/null +++ b/sktime/base/_panel/forest/__init__.py @@ -0,0 +1,2 @@ +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +"""Base classes for time series forests.""" diff --git a/sktime/series_as_features/base/estimators/_ensemble.py b/sktime/base/_panel/forest/_composable.py similarity index 99% rename from sktime/series_as_features/base/estimators/_ensemble.py rename to sktime/base/_panel/forest/_composable.py index 4ebce281df0..232b9270a7e 100644 --- a/sktime/series_as_features/base/estimators/_ensemble.py +++ b/sktime/base/_panel/forest/_composable.py @@ -22,7 +22,6 @@ from sklearn.exceptions import DataConversionWarning from sklearn.utils import check_array, check_random_state, compute_sample_weight -from sktime.transformations.panel.summarize import RandomIntervalFeatureExtractor from sktime.utils.random_state import set_random_state from sktime.utils.warnings import warn @@ -292,6 +291,9 @@ def feature_importances_(self, normalise_time_points=False): # assumes particular structure of clf, # with each tree consisting of a particular pipeline, # as in modular tsf + from sktime.transformations.panel.summarize import ( + RandomIntervalFeatureExtractor, + ) if not isinstance( self.estimators_[0].steps[0][1], RandomIntervalFeatureExtractor diff --git a/sktime/series_as_features/base/estimators/interval_based/_tsf.py b/sktime/base/_panel/forest/_tsf.py similarity index 53% rename from sktime/series_as_features/base/estimators/interval_based/_tsf.py rename to sktime/base/_panel/forest/_tsf.py index c7892df8bcc..cb2ed3c59d2 100644 --- a/sktime/series_as_features/base/estimators/interval_based/_tsf.py +++ b/sktime/base/_panel/forest/_tsf.py @@ -1,4 +1,4 @@ -"""Time Series Forest (TSF) Classifier.""" +"""Time Series Forest (TSF) classifier base class.""" __author__ = [ "TonyBagnall", @@ -16,13 +16,14 @@ ] import math +from typing import Optional import numpy as np from joblib import Parallel, delayed +from numpy.random import RandomState from sklearn.utils.multiclass import class_distribution from sklearn.utils.validation import check_random_state -from sktime.base._base import _clone_estimator from sktime.utils.slope_and_trend import _slope from sktime.utils.validation import check_n_jobs @@ -35,6 +36,7 @@ def __init__( min_interval=3, n_estimators=200, n_jobs=1, + inner_series_length: Optional[int] = None, random_state=None, ): super().__init__( @@ -46,6 +48,7 @@ def __init__( self.n_estimators = n_estimators self.min_interval = min_interval self.n_jobs = n_jobs + self.inner_series_length = inner_series_length # The following set in method fit self.n_classes = 0 self.series_length = 0 @@ -88,6 +91,8 @@ def _fit(self, X, y): self : object An fitted instance of the classifier """ + from sktime.base._base import _clone_estimator + X = X.squeeze(1) n_instances, self.series_length = X.shape @@ -105,7 +110,13 @@ def _fit(self, X, y): self.min_interval = self.series_length self.intervals_ = [ - _get_intervals(self.n_intervals, self.min_interval, self.series_length, rng) + _get_intervals( + self.n_intervals, + self.min_interval, + self.series_length, + rng, + self.inner_series_length, + ) for _ in range(self.n_estimators) ] @@ -127,6 +138,102 @@ def _get_fitted_params(self): } +def _get_intervals( + n_intervals: int, + min_interval: int, + series_length: int, + rng: RandomState, + inner_series_length: Optional[int] = None, +) -> np.ndarray: + """Generate random intervals for given parameters. + + Parameters + ---------- + n_intervals : int + Number of intervals to generate. + min_interval : int + Minimum length of an interval. + series_length : int + Length of the series. + rng : RandomState + Random number generator. + inner_series_length : int, optional (default=None) + Length of the inner series, define the maximum of an interval + and forces intervals to be contained in disjoint segments of + length inner_series_length. If None, defaults to series_length. + + Returns + ------- + intervals_starts_and_end_matrix : np.ndarray + Matrix of shape (n_intervals, 2) where each row represents an + interval and contains its start and end. + """ + interval_max_length = ( + series_length if inner_series_length is None else inner_series_length + ) + capped_min_interval = ( + interval_max_length if min_interval >= interval_max_length else min_interval + ) + number_of_inner_intervals = series_length // interval_max_length + intervals_starts_and_end_matrix = np.zeros((n_intervals, 2), dtype=int) + for interval_index in range(n_intervals): + inner_intervals_step = rng.randint(number_of_inner_intervals) + current_interval_start = ( + inner_intervals_step * interval_max_length + + rng.randint(max(1, interval_max_length - capped_min_interval)) + ) + current_interval_length = compute_interval_length( + capped_min_interval, + current_interval_start, + inner_intervals_step, + interval_max_length, + rng, + ) + current_interval_end = current_interval_start + current_interval_length + intervals_starts_and_end_matrix[interval_index, :] = [ + current_interval_start, + current_interval_end, + ] + return intervals_starts_and_end_matrix + + +def compute_interval_length( + capped_min_interval: int, + current_interval_start: int, + inner_intervals_step: int, + interval_max_length: int, + rng: RandomState, +) -> int: + if ( + capped_min_interval + < interval_max_length * (inner_intervals_step + 1) - current_interval_start + ): + current_interval_length = max( + capped_min_interval, + rng.randint( + interval_max_length * (inner_intervals_step + 1) + - current_interval_start + - 1, + ), + ) + elif ( + capped_min_interval + == interval_max_length * (inner_intervals_step + 1) - current_interval_start + ): + current_interval_length = capped_min_interval + else: + highest_possible_interval_length = ( + interval_max_length * (inner_intervals_step + 1) - current_interval_start + ) + raise ValueError( + f"low({capped_min_interval}) > " + f"high({highest_possible_interval_length}): " + f"Decrease capped_min_interval({capped_min_interval}) " + f"or increase interval_max_length({interval_max_length})" + ) + return current_interval_length + + def _transform(X, intervals): """Transform X for given intervals. @@ -159,18 +266,6 @@ def _transform(X, intervals): return transformed_x.T -def _get_intervals(n_intervals, min_interval, series_length, rng): - """Generate random intervals for given parameters.""" - intervals = np.zeros((n_intervals, 2), dtype=int) - for j in range(n_intervals): - intervals[j][0] = rng.randint(series_length - min_interval) - length = rng.randint(series_length - intervals[j][0] - 1) - if length < min_interval: - length = min_interval - intervals[j][1] = intervals[j][0] + length - return intervals - - def _fit_estimator(estimator, X, y, intervals): """Fit an estimator on input data (X, y).""" transformed_x = _transform(X, intervals) diff --git a/sktime/base/_panel/forest/tests/__init__.py b/sktime/base/_panel/forest/tests/__init__.py new file mode 100644 index 00000000000..cd2e2f3c149 --- /dev/null +++ b/sktime/base/_panel/forest/tests/__init__.py @@ -0,0 +1 @@ +"""Tests for time series forests.""" diff --git a/sktime/series_as_features/base/estimators/tests/test_feature_importances_.py b/sktime/base/_panel/forest/tests/test_feature_importances_.py similarity index 98% rename from sktime/series_as_features/base/estimators/tests/test_feature_importances_.py rename to sktime/base/_panel/forest/tests/test_feature_importances_.py index 8ec6c26f094..2983c6249c9 100644 --- a/sktime/series_as_features/base/estimators/tests/test_feature_importances_.py +++ b/sktime/base/_panel/forest/tests/test_feature_importances_.py @@ -14,8 +14,6 @@ from sktime.transformations.series.adapt import TabularToSeriesAdaptor from sktime.utils._testing.panel import make_classification_problem -X_train, y_train = make_classification_problem() - @pytest.mark.xfail(reason="array dimension mismatch since 1.2.0, see #3930") def test_feature_importances_single_feature_interval_and_estimator(): @@ -41,6 +39,8 @@ def test_feature_importances_single_feature_interval_and_estimator(): clf1 = ComposableTimeSeriesForestClassifier( estimator=base_estimator, random_state=random_state, n_estimators=1 ) + + X_train, y_train = make_classification_problem() clf1.fit(X_train, y_train) # Extract the interval and the estimator, and compute using pipelines @@ -100,6 +100,8 @@ def test_feature_importances_multi_intervals_estimators(n_intervals, n_estimator clf1 = ComposableTimeSeriesForestClassifier( estimator=base_estimator, random_state=random_state, n_estimators=n_estimators ) + + X_train, y_train = make_classification_problem() clf1.fit(X_train, y_train) fi_expected = np.zeros([n_estimators, n_intervals * n_features]) diff --git a/sktime/base/_panel/forest/tests/test_tsf.py b/sktime/base/_panel/forest/tests/test_tsf.py new file mode 100644 index 00000000000..6620120c42d --- /dev/null +++ b/sktime/base/_panel/forest/tests/test_tsf.py @@ -0,0 +1,199 @@ +"""Tests for get intervals in time series forests.""" +from typing import Optional + +import numpy as np +import pytest +from numpy.random import RandomState + +from sktime.base._panel.forest._tsf import _get_intervals + + +@pytest.mark.parametrize( + "number_of_intervals, min_interval, " + "number_of_series, inner_series_length, expected_intervals", + [(4, 3, 4, 6, np.array([[12, 17], [0, 3], [3, 10], [9, 12]]))], +) +def test_get_intervals( + number_of_intervals: int, + min_interval: int, + number_of_series: int, + inner_series_length: int, + expected_intervals: np.ndarray, +): + """Test get intervals.""" + # given + given_n_intervals = number_of_intervals + given_min_interval = min_interval + given_series_length = inner_series_length * number_of_series + given_rng: RandomState = RandomState(0) + + # When + intervals = _get_intervals( + n_intervals=given_n_intervals, + min_interval=given_min_interval, + series_length=given_series_length, + rng=given_rng, + ) + + # Then + assert np.array_equal(intervals, expected_intervals) + + +@pytest.mark.parametrize("number_of_intervals", [2, 5]) +@pytest.mark.parametrize("min_interval", [3, 10, 30]) +@pytest.mark.parametrize("inner_series_length", [10, 30, 100]) +@pytest.mark.parametrize("number_of_series", [3, 4, 10]) +def test_get_intervals_should_produce_as_much_interval_as_given( + number_of_intervals: int, + min_interval: int, + inner_series_length: int, + number_of_series: int, +): + """Test get_intervals should produce as much interval as given.""" + # given + given_n_intervals = number_of_intervals + given_min_interval = min_interval + given_series_length = inner_series_length * number_of_series + given_rng: RandomState = RandomState(42) + given_inner_series_length: Optional[int] = inner_series_length + + # When + intervals = _get_intervals( + n_intervals=given_n_intervals, + min_interval=given_min_interval, + series_length=given_series_length, + rng=given_rng, + inner_series_length=given_inner_series_length, + ) + + # Then + assert len(intervals) == given_n_intervals + + +@pytest.mark.parametrize("number_of_intervals", [2, 5]) +@pytest.mark.parametrize("min_interval", [3, 10, 30]) +@pytest.mark.parametrize("inner_series_length", [100]) +@pytest.mark.parametrize("number_of_series", [3, 4, 10]) +def test_get_intervals_at_least_greater_than_min_interval_given( + number_of_intervals: int, + min_interval: int, + inner_series_length: int, + number_of_series: int, +): + """Test get_intervals should at least greater than min interval given.""" + # given + given_n_intervals = number_of_intervals + given_min_interval = min_interval + given_series_length = inner_series_length * number_of_series + given_rng: RandomState = RandomState(42) + given_inner_series_length: Optional[int] = inner_series_length + + # When + intervals = _get_intervals( + n_intervals=given_n_intervals, + min_interval=given_min_interval, + series_length=given_series_length, + rng=given_rng, + inner_series_length=given_inner_series_length, + ) + + # Then + assert all((intervals[:, 1] - intervals[:, 0]) >= given_min_interval) + + +@pytest.mark.parametrize("number_of_intervals", [2, 5]) +@pytest.mark.parametrize("min_interval", [30, 50]) +@pytest.mark.parametrize("inner_series_length", [10, 20]) +@pytest.mark.parametrize("number_of_series", [3, 4, 10]) +def test_get_intervals_equals_to_inner_series_length_given_too_high_min_interval( + number_of_intervals: int, + min_interval: int, + inner_series_length: int, + number_of_series: int, +): + """Test get_intervals equals to inner series length given.""" + # given + given_n_intervals = number_of_intervals + given_min_interval = min_interval + given_series_length = inner_series_length * number_of_series + given_rng: RandomState = RandomState(42) + given_inner_series_length: Optional[int] = inner_series_length + + # When + intervals = _get_intervals( + n_intervals=given_n_intervals, + min_interval=given_min_interval, + series_length=given_series_length, + rng=given_rng, + inner_series_length=given_inner_series_length, + ) + + # Then + assert all((intervals[:, 1] - intervals[:, 0]) == given_inner_series_length) + + +@pytest.mark.parametrize("number_of_intervals", [2, 5]) +@pytest.mark.parametrize("min_interval", [3, 10, 30]) +@pytest.mark.parametrize("inner_series_length", [10, 30, 100]) +@pytest.mark.parametrize("number_of_series", [3, 4, 10]) +def test_get_intervals_should_produce_valid_intervals( + number_of_intervals: int, + min_interval: int, + inner_series_length: int, + number_of_series: int, +): + """Tests get_intervals should produce valid intervals.""" + # given + given_n_intervals = number_of_intervals + given_min_interval = min_interval + given_series_length = inner_series_length * number_of_series + given_rng: RandomState = RandomState(42) + given_inner_series_length: Optional[int] = inner_series_length + + # When + intervals = _get_intervals( + n_intervals=given_n_intervals, + min_interval=given_min_interval, + series_length=given_series_length, + rng=given_rng, + inner_series_length=given_inner_series_length, + ) + + # Then + assert np.min(intervals) >= 0 + assert np.max(intervals) <= given_series_length + + +@pytest.mark.parametrize("number_of_intervals", [2, 5]) +@pytest.mark.parametrize("min_interval", [3, 10, 30]) +@pytest.mark.parametrize("inner_series_length", [10, 30, 100]) +@pytest.mark.parametrize("number_of_series", [3, 4, 10]) +def test_get_intervals_should_produce_intervals_contained_in_inner_series_bins( + number_of_intervals: int, + min_interval: int, + inner_series_length: int, + number_of_series: int, +): + """Tests get_intervals should produce intervals contained in inner series bins.""" + # given + given_n_intervals = number_of_intervals + given_min_interval = min_interval + given_series_length = inner_series_length * number_of_series + given_rng: RandomState = RandomState(42) + given_inner_series_length: Optional[int] = inner_series_length + + # When + intervals = _get_intervals( + n_intervals=given_n_intervals, + min_interval=given_min_interval, + series_length=given_series_length, + rng=given_rng, + inner_series_length=given_inner_series_length, + ) + + # Then + assert all( + intervals[:, 0] + <= (intervals[:, 0] // given_inner_series_length + 1) + * given_inner_series_length + ) diff --git a/sktime/base/_serialize.py b/sktime/base/_serialize.py index 5f2da84c4f4..b0aee1cd5d8 100644 --- a/sktime/base/_serialize.py +++ b/sktime/base/_serialize.py @@ -34,7 +34,7 @@ def load(serial): Examples -------- - Example 1: saving an estimator as pickle and loading + Example 1: saving an estimator in-memory and loading it back >>> from sktime.datasets import load_airline >>> from sktime.forecasting.naive import NaiveForecaster @@ -79,6 +79,30 @@ def load(serial): >>> # 4. continue using the loaded estimator >>> pred = cnn.predict(X=sample_test_X) # doctest: +SKIP >>> loaded_pred = loaded_cnn.predict(X=sample_test_X) # doctest: +SKIP + + Example 3: saving an estimator using cloudpickle's serialization functionality + and loading it back + Note: `cloudpickle` is a soft dependency and is not present + with the base-installation. + + >>> from sktime.classification.feature_based import Catch22Classifier + >>> from sktime.datasets import load_basic_motions # doctest: +SKIP + >>> + >>> # 1. Fit the estimator + >>> X_train, y_train = load_basic_motions(split="TRAIN") # doctest: +SKIP + >>> X_test, y_test = load_basic_motions(split="TEST") # doctest: +SKIP + >>> est = Catch22Classifier().fit(X_train, y_train) # doctest: +SKIP + >>> + >>> # 2. save the fitted estimator + >>> cpkl_serialized = est.save(serialization_format="cloudpickle") # doctest: +SKIP + >>> + >>> # 3. load the saved estimator (possibly after sending it across a stream) + >>> from sktime.base import load # doctest: +SKIP + >>> loaded_est = load(cpkl_serialized) # doctest: +SKIP + >>> + >>> # 4. continue using the estimator as normal + >>> pred = loaded_est.predict(X_test) # doctest: +SKIP + >>> loaded_pred = loaded_est.predict(X_test) # doctest: +SKIP """ import pickle from pathlib import Path diff --git a/sktime/base/tests/test_base.py b/sktime/base/tests/test_base.py index 487d9d2663e..ca27a92327d 100644 --- a/sktime/base/tests/test_base.py +++ b/sktime/base/tests/test_base.py @@ -29,6 +29,8 @@ "test_reset", "test_reset_composite", "test_components", + "test_param_alias", + "test_nested_set_params_and_alias", "test_get_fitted_params", "test_eq_dunder", ] @@ -38,6 +40,7 @@ import pytest from sktime.base import BaseEstimator, BaseObject +from sktime.utils.validation._dependencies import _check_soft_dependencies # Fixture class for testing tag system @@ -280,6 +283,109 @@ def test_components(): assert comp_comps["foo_"] is not composite.foo +class AliasTester(BaseObject): + def __init__(self, a, bar=42): + self.a = a + self.bar = bar + + +@pytest.mark.skipif( + _check_soft_dependencies("skbase<0.6.1", severity="none"), + reason="aliasing was introduced in skbase 0.6.1", +) +def test_param_alias(): + """Tests parameter aliasing with parameter string shorthands. + + Raises + ------ + AssertionError if parameters that should be set via __ are not set + AssertionError if error that should be raised is not raised + """ + non_composite = AliasTester(a=42, bar=4242) + composite = CompositionDummy(foo=non_composite) + + # this should write to a of foo, because there is only one suffix called a + composite.set_params(**{"a": 424242}) + assert composite.get_params()["foo__a"] == 424242 + + # this should write to bar of composite, because "bar" is a full parameter string + # there is a suffix in foo, but if the full string is there, it writes to that + composite.set_params(**{"bar": 424243}) + assert composite.get_params()["bar"] == 424243 + + # trying to write to bad_param should raise an exception + # since bad_param is neither a suffix nor a full parameter string + with pytest.raises(ValueError, match=r"Invalid parameter keys provided to"): + composite.set_params(**{"bad_param": 424242}) + + # new example: highly nested composite with identical suffixes + non_composite1 = composite + non_composite2 = AliasTester(a=42, bar=4242) + uber_composite = CompositionDummy(foo=non_composite1, bar=non_composite2) + + # trying to write to a should raise an exception + # since there are two suffix a, and a is not a full parameter string + with pytest.raises(ValueError, match=r"does not uniquely determine parameter key"): + uber_composite.set_params(**{"a": 424242}) + + # same as above, should overwrite "bar" of uber_composite + uber_composite.set_params(**{"bar": 424243}) + assert uber_composite.get_params()["bar"] == 424243 + + +@pytest.mark.skipif( + _check_soft_dependencies("skbase<0.6.1", severity="none"), + reason="aliasing was introduced in skbase 0.6.1", +) +def test_nested_set_params_and_alias(): + """Tests that nested param setting works correctly. + + This specifically tests that parameters of components can be provided, + even if that component is not present in the object that set_params is called on, + but is also being set in the same set_params call. + + Also tests alias resolution, using recursive end state after set_params. + + Raises + ------ + AssertionError if parameters that should be set via __ are not set + AssertionError if error that should be raised is not raised + """ + non_composite = AliasTester(a=42, bar=4242) + composite = CompositionDummy(foo=0) + + # this should write to a of foo + # potential error here is that composite does not have foo__a to start with + # so error catching or writing foo__a to early could cause an exception + composite.set_params(**{"foo": non_composite, "foo__a": 424242}) + assert composite.get_params()["foo__a"] == 424242 + + non_composite = AliasTester(a=42, bar=4242) + composite = CompositionDummy(foo=0) + + # same, and recognizing that foo__a is the only matching suffix in the end state + composite.set_params(**{"foo": non_composite, "a": 424242}) + assert composite.get_params()["foo__a"] == 424242 + + # new example: highly nested composite with identical suffixes + non_composite1 = composite + non_composite2 = AliasTester(a=42, bar=4242) + uber_composite = CompositionDummy(foo=42, bar=42) + + # trying to write to a should raise an exception + # since there are two suffix a, and a is not a full parameter string + with pytest.raises(ValueError, match=r"does not uniquely determine parameter key"): + uber_composite.set_params( + **{"a": 424242, "foo": non_composite1, "bar": non_composite2} + ) + + uber_composite = CompositionDummy(foo=non_composite1, bar=42) + + # same as above, should overwrite "bar" of uber_composite + uber_composite.set_params(**{"bar": 424243}) + assert uber_composite.get_params()["bar"] == 424243 + + class FittableCompositionDummy(BaseEstimator): """Potentially composite object, for testing.""" diff --git a/sktime/benchmarking/evaluation.py b/sktime/benchmarking/evaluation.py index 60e5f6cf87e..30dac6b1776 100644 --- a/sktime/benchmarking/evaluation.py +++ b/sktime/benchmarking/evaluation.py @@ -111,7 +111,7 @@ def evaluate(self, metric, train_or_test="test", cv_fold="all"): # aggregate over cv folds metrics_by_strategy_dataset = ( self._metrics.groupby(["dataset", "strategy"], as_index=False) - .agg(np.mean) + .agg("mean") .drop(columns="cv_fold") ) self._metrics_by_strategy_dataset = self._metrics_by_strategy_dataset.merge( @@ -123,7 +123,7 @@ def evaluate(self, metric, train_or_test="test", cv_fold="all"): ) metrics_by_strategy = metrics_by_strategy_dataset_wo_ds.groupby( ["strategy"], as_index=False - ).agg(np.mean) + ).agg("mean") self._metrics_by_strategy = self._metrics_by_strategy.merge( metrics_by_strategy, how="outer" ) @@ -452,15 +452,7 @@ def fit_runtime(self, unit="s", train_or_test="test", cv_fold="all"): ) # load all predictions - run_times = pd.DataFrame( - columns=[ - "strategy_name", - "dataset_name", - "fit_estimator_start_time", - "fit_estimator_end_time", - "cv_fold", - ] - ) + run_times_frames = [] for cv_fold in cv_folds: for result in self.results.load_predictions( cv_fold=cv_fold, train_or_test=train_or_test @@ -483,7 +475,8 @@ def fit_runtime(self, unit="s", train_or_test="test", cv_fold="all"): "cv_fold": [cv_fold], } ) - run_times = pd.concat([run_times, unwrapped], ignore_index=True) + run_times_frames.append(unwrapped) + run_times = pd.concat(run_times_frames, ignore_index=True) # calculate run time difference run_times["fit_runtime"] = ( @@ -521,7 +514,7 @@ def fit_runtime(self, unit="s", train_or_test="test", cv_fold="all"): # # aggregate over cv folds # metrics_by_strategy_dataset = ( # self._metrics.groupby(["dataset", "strategy"], as_index=False) - # .agg(np.mean) + # .agg("mean") # .drop(columns="cv_fold") # ) # self._metrics_by_strategy_dataset = self._metrics_by_strategy_dataset.merge( @@ -530,7 +523,7 @@ def fit_runtime(self, unit="s", train_or_test="test", cv_fold="all"): # # aggregate over cv folds and datasets # metrics_by_strategy = metrics_by_strategy_dataset.groupby( # ["strategy"], as_index=False - # ).agg(np.mean) + # ).agg("mean") # self._metrics_by_strategy = self._metrics_by_strategy.merge( # metrics_by_strategy, how="outer" # ) diff --git a/sktime/benchmarking/tests/test_orchestration.py b/sktime/benchmarking/tests/test_orchestration.py index e091273c229..02f75331975 100644 --- a/sktime/benchmarking/tests/test_orchestration.py +++ b/sktime/benchmarking/tests/test_orchestration.py @@ -81,6 +81,7 @@ def test_automated_orchestration_vs_manual(data_loader): # extensive tests of orchestration and metric evaluation against sklearn +@pytest.mark.skip(reason="failures since sklearn 1.4.0, see #5797") @pytest.mark.parametrize( "dataset", [ @@ -193,8 +194,8 @@ def test_stat(): _, sign_test_df = analyse.sign_test() sign_array = [ - [sign_test_df["pf"][0], sign_test_df["pf"][1]], - [sign_test_df["tsf"][0], sign_test_df["tsf"][1]], + [sign_test_df["pf"].iloc[0], sign_test_df["pf"].iloc[1]], + [sign_test_df["tsf"].iloc[0], sign_test_df["tsf"].iloc[1]], ] sign_array_test = [[1, 1], [1, 1]] np.testing.assert_equal( diff --git a/sktime/classification/base.py b/sktime/classification/base.py index b5167b993e9..f853a7c4c4a 100644 --- a/sktime/classification/base.py +++ b/sktime/classification/base.py @@ -23,20 +23,17 @@ class name: BaseClassifier __author__ = ["mloning", "fkiraly", "TonyBagnall", "MatthewMiddlehurst"] import time -from abc import ABC, abstractmethod import numpy as np -import pandas as pd -from sktime.base import BaseEstimator -from sktime.datatypes import check_is_scitype, convert_to +from sktime.base import BasePanelMixin +from sktime.datatypes import VectorizedDF, check_is_scitype, convert from sktime.utils.sklearn import is_sklearn_transformer from sktime.utils.validation import check_n_jobs from sktime.utils.validation._dependencies import _check_estimator_deps -from sktime.utils.warnings import warn -class BaseClassifier(BaseEstimator, ABC): +class BaseClassifier(BasePanelMixin): """Abstract base class for time series classifiers. The base classifier specifies the methods and method signatures that all @@ -55,7 +52,9 @@ class BaseClassifier(BaseEstimator, ABC): _tags = { "object_type": "classifier", # type of object "X_inner_mtype": "numpy3D", # which type do _fit/_predict, support for X? + "y_inner_mtype": "numpy1D", # which type do _fit/_predict, support for y? # it should be either "numpy3D" or "nested_univ" (nested pd.DataFrame) + "capability:multioutput": False, # whether classifier supports multioutput "capability:multivariate": False, "capability:unequal_length": False, "capability:missing_values": False, @@ -65,6 +64,8 @@ class BaseClassifier(BaseEstimator, ABC): "capability:predict_proba": False, "python_version": None, # PEP 440 python version specifier to limit versions "requires_cython": False, # whether C compiler is required in env, e.g., gcc + "authors": "sktime developers", # author(s) of the object + "maintainers": "sktime developers", # current maintainer(s) of the object } # convenience constant to control which metadata of input data @@ -76,6 +77,14 @@ class BaseClassifier(BaseEstimator, ABC): "is_equal_length", ] + # attribute name where vectorized estimators are stored + VECTORIZATION_ATTR = "classifiers_" # e.g., classifiers_, regressors_ + + # used in error messages + TASK = "classification" # e.g., classification, regression + EST_TYPE = "classifier" # e.g., classifier, regressor + EST_TYPE_PLURAL = "classifiers" # e.g., classifiers, regressors + def __init__(self): # reserved attributes written to in fit self.classes_ = [] # classes seen in y, unique labels @@ -88,6 +97,8 @@ def __init__(self): # required for compatibility with some sklearn interfaces # i.e. CalibratedClassifierCV self._estimator_type = "classifier" + self._is_vectorized = False + self._converter_store_y = {} super().__init__() _check_estimator_deps(self) @@ -131,48 +142,72 @@ def __rmul__(self, other): return NotImplemented def fit(self, X, y): - """Fit time series classifier to training data. + """ + Fit time series classifier to training data. + + State change: + Changes state to "fitted". + + Writes to self: + Sets self.is_fitted to True. + Sets fitted model attributes ending in "_". Parameters ---------- - X : 3D np.array (any number of dimensions, equal length series) - of shape [n_instances, n_dimensions, series_length] - or 2D np.array (univariate, equal length series) - of shape [n_instances, series_length] - or pd.DataFrame with each column a dimension, each cell a pd.Series - (any number of dimensions, equal or unequal length series) + X : sktime compatible time series panel data container, Panel scitype, e.g., + pd-multiindex: pd.DataFrame with columns = variables, + index = pd.MultiIndex with first level = instance indices, + second level = time indices + numpy3D: 3D np.array (any number of dimensions, equal length series) + of shape [n_instances, n_dimensions, series_length] or of any other supported Panel mtype - for list of mtypes, see datatypes.SCITYPE_REGISTER - for specifications, see examples/AA_datatypes_and_datasets.ipynb - y : 1D np.array of int, of shape [n_instances] - class labels for fitting - indices correspond to instance indices in X + for list of mtypes, see datatypes.SCITYPE_REGISTER + for specifications, see examples/AA_datatypes_and_datasets.ipynb + y : sktime compatible tabular data container, Table scitype + 1D iterable, of shape [n_instances] + or 2D iterable, of shape [n_instances, n_dimensions] + class labels for fitting + 0-th indices correspond to instance indices in X + 1-st indices (if applicable) correspond to multioutput vector indices in X + supported sktime types: np.ndarray (1D, 2D), pd.Series, pd.DataFrame Returns ------- self : Reference to self. - - Notes - ----- - Changes state by creating a fitted model that updates attributes - ending in "_" and sets is_fitted flag to True. """ # reset estimator at the start of fit self.reset() + # fit timer start start = int(round(time.time() * 1000)) + + # check and convert y for multioutput vectorization + y, y_metadata, y_inner_mtype = self._check_y(y, return_to_mtype=True) + self._y_metadata = y_metadata + self._y_inner_mtype = y_inner_mtype + self._is_vectorized = isinstance(y, VectorizedDF) + + if self._is_vectorized: + self._vectorize("fit", X=X, y=y) + # fit timer end + self.fit_time_ = int(round(time.time() * 1000)) - start + # this should happen last: fitted state is set to True + self._is_fitted = True + return self + + # no vectorization needed, proceed with normal fit + # convenience conversions to allow user flexibility: # if X is 2D array, convert to 3D, if y is Series, convert to numpy X, y = self._internal_convert(X, y) - X_metadata = self._check_classifier_input( + X_metadata = self._check_input( X, y, return_metadata=self.METADATA_REQ_IN_CHECKS ) - missing = X_metadata["has_nans"] - multivariate = not X_metadata["is_univariate"] - unequal = not X_metadata["is_equal_length"] + X_mtype = X_metadata["mtype"] self._X_metadata = X_metadata # Check this classifier can handle characteristics - self._check_capabilities(missing, multivariate, unequal) + self._check_capabilities(X_metadata) # remember class labels self.classes_ = np.unique(y) @@ -189,7 +224,7 @@ def fit(self, X, y): return self # Convert data as dictated by the classifier tags - X = self._convert_X(X) + X = self._convert_X(X, X_mtype) multithread = self.get_tag("capability:multithreading") if multithread: try: @@ -203,32 +238,42 @@ def fit(self, X, y): self._fit(X, y) self.fit_time_ = int(round(time.time() * 1000)) - start - # this should happen last + # this should happen last: fitted state is set to True self._is_fitted = True return self - def predict(self, X) -> np.ndarray: + def predict(self, X): """Predicts labels for sequences in X. Parameters ---------- - X : 3D np.array (any number of dimensions, equal length series) - of shape [n_instances, n_dimensions, series_length] - or 2D np.array (univariate, equal length series) - of shape [n_instances, series_length] - or pd.DataFrame with each column a dimension, each cell a pd.Series - (any number of dimensions, equal or unequal length series) + X : sktime compatible time series panel data container, Panel scitype, e.g., + pd-multiindex: pd.DataFrame with columns = variables, + index = pd.MultiIndex with first level = instance indices, + second level = time indices + numpy3D: 3D np.array (any number of dimensions, equal length series) + of shape [n_instances, n_dimensions, series_length] or of any other supported Panel mtype - for list of mtypes, see datatypes.SCITYPE_REGISTER - for specifications, see examples/AA_datatypes_and_datasets.ipynb + for list of mtypes, see datatypes.SCITYPE_REGISTER + for specifications, see examples/AA_datatypes_and_datasets.ipynb Returns ------- - y : 1D np.array of int, of shape [n_instances] - predicted class labels - indices correspond to instance indices in X + y_pred : sktime compatible tabular data container, Table scitype + 1D iterable, of shape [n_instances] + or 2D iterable, of shape [n_instances, n_dimensions] + predicted class labels + 0-th indices correspond to instance indices in X + 1-st indices (if applicable) correspond to multioutput vector indices in X + 1D np.npdarray, if y univariate (one dimension) + otherwise, same type as y passed in fit """ self.check_is_fitted() + # enter vectorized mode if needed + if self._is_vectorized: + return self._vectorize("predict", X=X) + # boilerplate input checks for predict-like methods X = self._check_convert_X_for_predict(X) @@ -236,33 +281,42 @@ def predict(self, X) -> np.ndarray: if len(self._class_dictionary) == 1: return self._single_class_y_pred(X, method="predict") - # call internal _predict_proba - return self._predict(X) + # call internal _predict, convert output + y_pred_inner = self._predict(X) + y_pred = self._convert_output_y(y_pred_inner) + return y_pred - def predict_proba(self, X) -> np.ndarray: + def predict_proba(self, X): """Predicts labels probabilities for sequences in X. Parameters ---------- - X : 3D np.array (any number of dimensions, equal length series) - of shape [n_instances, n_dimensions, series_length] - or 2D np.array (univariate, equal length series) - of shape [n_instances, series_length] - or pd.DataFrame with each column a dimension, each cell a pd.Series - (any number of dimensions, equal or unequal length series) + X : sktime compatible time series panel data container, Panel scitype, e.g., + pd-multiindex: pd.DataFrame with columns = variables, + index = pd.MultiIndex with first level = instance indices, + second level = time indices + numpy3D: 3D np.array (any number of dimensions, equal length series) + of shape [n_instances, n_dimensions, series_length] or of any other supported Panel mtype - for list of mtypes, see datatypes.SCITYPE_REGISTER - for specifications, see examples/AA_datatypes_and_datasets.ipynb + for list of mtypes, see datatypes.SCITYPE_REGISTER + for specifications, see examples/AA_datatypes_and_datasets.ipynb Returns ------- - y : 2D array of shape [n_instances, n_classes] - predicted class probabilities - 1st dimension indices correspond to instance indices in X - 2nd dimension indices correspond to possible labels (integers) - (i, j)-th entry is predictive probability that i-th instance is of class j + y_pred : 2D np.array of int, of shape [n_instances, n_classes] + predicted class label probabilities + 0-th indices correspond to instance indices in X + 1-st indices correspond to class index, in same order as in self.classes_ + entries are predictive class probabilities, summing to 1 """ self.check_is_fitted() + # enter vectorized mode if needed + if self._is_vectorized: + return self._vectorize("predict_proba", X=X) + + self.check_is_fitted() + # boilerplate input checks for predict-like methods X = self._check_convert_X_for_predict(X) @@ -273,7 +327,7 @@ def predict_proba(self, X) -> np.ndarray: # call internal _predict_proba return self._predict_proba(X) - def fit_predict(self, X, y, cv=None, change_state=True) -> np.ndarray: + def fit_predict(self, X, y, cv=None, change_state=True): """Fit and predict labels for sequences in X. Convenience method to produce in-sample predictions and @@ -287,17 +341,22 @@ def fit_predict(self, X, y, cv=None, change_state=True) -> np.ndarray: Parameters ---------- - X : 3D np.array (any number of dimensions, equal length series) - of shape [n_instances, n_dimensions, series_length] - or 2D np.array (univariate, equal length series) - of shape [n_instances, series_length] - or pd.DataFrame with each column a dimension, each cell a pd.Series - (any number of dimensions, equal or unequal length series) + X : sktime compatible time series panel data container, Panel scitype, e.g., + pd-multiindex: pd.DataFrame with columns = variables, + index = pd.MultiIndex with first level = instance indices, + second level = time indices + numpy3D: 3D np.array (any number of dimensions, equal length series) + of shape [n_instances, n_dimensions, series_length] or of any other supported Panel mtype - for list of mtypes, see datatypes.SCITYPE_REGISTER - for specifications, see examples/AA_datatypes_and_datasets.ipynb - y : 1D np.array of int, of shape [n_instances] - class labels for fitting - indices correspond to instance indices in X + for list of mtypes, see datatypes.SCITYPE_REGISTER + for specifications, see examples/AA_datatypes_and_datasets.ipynb + y : sktime compatible tabular data container, Table scitype + 1D iterable, of shape [n_instances] + or 2D iterable, of shape [n_instances, n_dimensions] + class labels for fitting + 0-th indices correspond to instance indices in X + 1-st indices (if applicable) correspond to multioutput vector indices in X + supported sktime types: np.ndarray (1D, 2D), pd.Series, pd.DataFrame cv : None, int, or sklearn cross-validation object, optional, default=None None : predictions are in-sample, equivalent to fit(X, y).predict(X) cv : predictions are equivalent to fit(X_train, y_train).predict(X_test) @@ -315,9 +374,14 @@ def fit_predict(self, X, y, cv=None, change_state=True) -> np.ndarray: Returns ------- - y : 1D np.array of int, of shape [n_instances] - predicted class labels - indices correspond to instance indices in X - if cv is passed, -1 indicates entries not seen in union of test sets + y_pred : sktime compatible tabular data container, Table scitype + 1D iterable, of shape [n_instances] + or 2D iterable, of shape [n_instances, n_dimensions] + predicted class labels + 0-th indices correspond to instance indices in X + 1-st indices (if applicable) correspond to multioutput vector indices in X + 1D np.npdarray, if y univariate (one dimension) + otherwise, same type as y passed in fit """ return self._fit_predict_boilerplate( X=X, y=y, cv=cv, change_state=change_state, method="predict" @@ -344,14 +408,12 @@ def _fit_predict_boilerplate(self, X, y, cv, change_state, method): # we now know that cv is an sklearn splitter X, y = self._internal_convert(X, y) - X_metadata = self._check_classifier_input( + X_metadata = self._check_input( X, y, return_metadata=self.METADATA_REQ_IN_CHECKS ) - missing = X_metadata["has_nans"] - multivariate = not X_metadata["is_univariate"] - unequal = not X_metadata["is_equal_length"] + X_mtype = X_metadata["mtype"] # Check this classifier can handle characteristics - self._check_capabilities(missing, multivariate, unequal) + self._check_capabilities(X_metadata) # handle single class case if len(self._class_dictionary) == 1: @@ -359,15 +421,17 @@ def _fit_predict_boilerplate(self, X, y, cv, change_state, method): # Convert data to format easily usable for applying cv if isinstance(X, np.ndarray): - X = convert_to( + X = convert( X, + from_type=X_mtype, to_type="numpy3D", as_scitype="Panel", store_behaviour="freeze", ) else: - X = convert_to( + X = convert( X, + from_type=X_mtype, to_type="nested_univ", as_scitype="Panel", store_behaviour="freeze", @@ -395,25 +459,36 @@ def _fit_predict_boilerplate(self, X, y, cv, change_state, method): return y_pred - def fit_predict_proba(self, X, y, cv=None, change_state=True) -> np.ndarray: + def fit_predict_proba(self, X, y, cv=None, change_state=True): """Fit and predict labels probabilities for sequences in X. Convenience method to produce in-sample predictions and cross-validated out-of-sample predictions. + Writes to self, if change_state=True: + Sets self.is_fitted to True. + Sets fitted model attributes ending in "_". + + Does not update state if change_state=False. + Parameters ---------- - X : 3D np.array (any number of dimensions, equal length series) - of shape [n_instances, n_dimensions, series_length] - or 2D np.array (univariate, equal length series) - of shape [n_instances, series_length] - or pd.DataFrame with each column a dimension, each cell a pd.Series - (any number of dimensions, equal or unequal length series) + X : sktime compatible time series panel data container, Panel scitype, e.g., + pd-multiindex: pd.DataFrame with columns = variables, + index = pd.MultiIndex with first level = instance indices, + second level = time indices + numpy3D: 3D np.array (any number of dimensions, equal length series) + of shape [n_instances, n_dimensions, series_length] or of any other supported Panel mtype - for list of mtypes, see datatypes.SCITYPE_REGISTER - for specifications, see examples/AA_datatypes_and_datasets.ipynb - y : 1D np.array of int, of shape [n_instances] - class labels for fitting - indices correspond to instance indices in X + for list of mtypes, see datatypes.SCITYPE_REGISTER + for specifications, see examples/AA_datatypes_and_datasets.ipynb + y : sktime compatible tabular data container, Table scitype + 1D iterable, of shape [n_instances] + or 2D iterable, of shape [n_instances, n_dimensions] + class labels for fitting + 0-th indices correspond to instance indices in X + 1-st indices (if applicable) correspond to multioutput vector indices in X + supported sktime types: np.ndarray (1D, 2D), pd.Series, pd.DataFrame cv : None, int, or sklearn cross-validation object, optional, default=None None : predictions are in-sample, equivalent to fit(X, y).predict(X) cv : predictions are equivalent to fit(X_train, y_train).predict(X_test) @@ -429,10 +504,11 @@ def fit_predict_proba(self, X, y, cv=None, change_state=True) -> np.ndarray: Returns ------- - y : 2D array of shape [n_instances, n_classes] - predicted class probabilities - 1st dimension indices correspond to instance indices in X - 2nd dimension indices correspond to possible labels (integers) - (i, j)-th entry is predictive probability that i-th instance is of class j + y_pred : 2D np.array of int, of shape [n_instances, n_classes] + predicted class label probabilities + 0-th indices correspond to instance indices in X + 1-st indices correspond to class index, in same order as in self.classes_ + entries are predictive class probabilities, summing to 1 """ return self._fit_predict_boilerplate( X=X, y=y, cv=cv, change_state=change_state, method="predict_proba" @@ -455,17 +531,22 @@ def score(self, X, y) -> float: Parameters ---------- - X : 3D np.array (any number of dimensions, equal length series) - of shape [n_instances, n_dimensions, series_length] - or 2D np.array (univariate, equal length series) - of shape [n_instances, series_length] - or pd.DataFrame with each column a dimension, each cell a pd.Series - (any number of dimensions, equal or unequal length series) + X : sktime compatible time series panel data container, e.g., + pd-multiindex: pd.DataFrame with columns = variables, + index = pd.MultiIndex with first level = instance indices, + second level = time indices + numpy3D: 3D np.array (any number of dimensions, equal length series) + of shape [n_instances, n_dimensions, series_length] or of any other supported Panel mtype - for list of mtypes, see datatypes.SCITYPE_REGISTER - for specifications, see examples/AA_datatypes_and_datasets.ipynb - y : 1D np.ndarray of int, of shape [n_instances] - class labels (ground truth) - indices correspond to instance indices in X + for list of mtypes, see datatypes.SCITYPE_REGISTER + for specifications, see examples/AA_datatypes_and_datasets.ipynb + y : sktime compatible tabular data container, Table scitype + 1D iterable, of shape [n_instances] + or 2D iterable, of shape [n_instances, n_dimensions] + class labels for fitting + 0-th indices correspond to instance indices in X + 1-st indices (if applicable) correspond to multioutput vector indices in X + supported sktime types: np.ndarray (1D, 2D), pd.Series, pd.DataFrame Returns ------- @@ -501,35 +582,37 @@ def get_test_params(cls, parameter_set="default"): """ return super().get_test_params(parameter_set=parameter_set) - @abstractmethod def _fit(self, X, y): """Fit time series classifier to training data. Abstract method, must be implemented. + Writes to self: + Sets fitted model attributes ending in "_". + Parameters ---------- X : guaranteed to be of a type in self.get_tag("X_inner_mtype") if self.get_tag("X_inner_mtype") = "numpy3D": - 3D np.ndarray of shape = [n_instances, n_dimensions, series_length] - if self.get_tag("X_inner_mtype") = "nested_univ": - pd.DataFrame with each column a dimension, each cell a pd.Series + 3D np.ndarray of shape = [n_instances, n_dimensions, series_length] + if self.get_tag("X_inner_mtype") = "pd-multiindex:": + pd.DataFrame with columns = variables, + index = pd.MultiIndex with first level = instance indices, + second level = time indices for list of other mtypes, see datatypes.SCITYPE_REGISTER for specifications, see examples/AA_datatypes_and_datasets.ipynb - y : 1D np.array of int, of shape [n_instances] - class labels for fitting - indices correspond to instance indices in X + y : guaranteed to be of a type in self.get_tag("y_inner_mtype") + 1D iterable, of shape [n_instances] + or 2D iterable, of shape [n_instances, n_dimensions] + class labels for fitting + if self.get_tag("capaility:multioutput") = False, guaranteed to be 1D + if self.get_tag("capaility:multioutput") = True, guaranteed to be 2D Returns ------- - self : - Reference to self. - - Notes - ----- - Changes state by creating a fitted model that updates attributes - ending in "_" and sets is_fitted flag to True. + self : Reference to self. """ - ... + raise NotImplementedError("abstract method") def _predict(self, X) -> np.ndarray: """Predicts labels for sequences in X. @@ -540,16 +623,23 @@ def _predict(self, X) -> np.ndarray: ---------- X : guaranteed to be of a type in self.get_tag("X_inner_mtype") if self.get_tag("X_inner_mtype") = "numpy3D": - 3D np.ndarray of shape = [n_instances, n_dimensions, series_length] - if self.get_tag("X_inner_mtype") = "nested_univ": - pd.DataFrame with each column a dimension, each cell a pd.Series + 3D np.ndarray of shape = [n_instances, n_dimensions, series_length] + if self.get_tag("X_inner_mtype") = "pd-multiindex:": + pd.DataFrame with columns = variables, + index = pd.MultiIndex with first level = instance indices, + second level = time indices for list of other mtypes, see datatypes.SCITYPE_REGISTER for specifications, see examples/AA_datatypes_and_datasets.ipynb Returns ------- - y : 1D np.array of int, of shape [n_instances] - predicted class labels + y : should be of mtype in self.get_tag("y_inner_mtype") + 1D iterable, of shape [n_instances] + or 2D iterable, of shape [n_instances, n_dimensions] + predicted class labels indices correspond to instance indices in X + if self.get_tag("capaility:multioutput") = False, should be 1D + if self.get_tag("capaility:multioutput") = True, should be 2D """ y_proba = self._predict_proba(X) y_pred = y_proba.argmax(axis=1) @@ -567,9 +657,11 @@ def _predict_proba(self, X) -> np.ndarray: ---------- X : guaranteed to be of a type in self.get_tag("X_inner_mtype") if self.get_tag("X_inner_mtype") = "numpy3D": - 3D np.ndarray of shape = [n_instances, n_dimensions, series_length] - if self.get_tag("X_inner_mtype") = "nested_univ": - pd.DataFrame with each column a dimension, each cell a pd.Series + 3D np.ndarray of shape = [n_instances, n_dimensions, series_length] + if self.get_tag("X_inner_mtype") = "pd-multiindex:": + pd.DataFrame with columns = variables, + index = pd.MultiIndex with first level = instance indices, + second level = time indices for list of other mtypes, see datatypes.SCITYPE_REGISTER for specifications, see examples/AA_datatypes_and_datasets.ipynb @@ -587,206 +679,3 @@ def _predict_proba(self, X) -> np.ndarray: dists[i, self._class_dictionary[preds[i]]] = 1 return dists - - def _check_convert_X_for_predict(self, X): - """Input checks, capability checks, repeated in all predict/score methods. - - Parameters - ---------- - X : any object (to check/convert) - should be of a supported Panel mtype or 2D numpy.ndarray - - Returns - ------- - X: an object of a supported Panel mtype, numpy3D if X was a 2D numpy.ndarray - - Raises - ------ - ValueError if X is of invalid input data type, or there is not enough data - ValueError if the capabilities in self._tags do not handle the data. - """ - X = self._internal_convert(X) - X_metadata = self._check_classifier_input( - X, return_metadata=self.METADATA_REQ_IN_CHECKS - ) - missing = X_metadata["has_nans"] - multivariate = not X_metadata["is_univariate"] - unequal = not X_metadata["is_equal_length"] - # Check this classifier can handle characteristics - self._check_capabilities(missing, multivariate, unequal) - # Convert data as dictated by the classifier tags - X = self._convert_X(X) - - return X - - def _check_capabilities(self, missing, multivariate, unequal): - """Check whether this classifier can handle the data characteristics. - - Parameters - ---------- - missing : boolean, does the data passed to fit contain missing values? - multivariate : boolean, does the data passed to fit contain missing values? - unequal : boolea, do the time series passed to fit have variable lengths? - - Raises - ------ - ValueError if the capabilities in self._tags do not handle the data. - """ - allow_multivariate = self.get_tag("capability:multivariate") - allow_missing = self.get_tag("capability:missing_values") - allow_unequal = self.get_tag("capability:unequal_length") - - self_name = type(self).__name__ - - # identify problems, mismatch of capability and inputs - problems = [] - if missing and not allow_missing: - problems += ["missing values"] - if multivariate and not allow_multivariate: - problems += ["multivariate series"] - if unequal and not allow_unequal: - problems += ["unequal length series"] - - # construct error message - problems_and = " and ".join(problems) - problems_or = " or ".join(problems) - msg = ( - f"Data seen by {self_name} instance has {problems_and}, " - f"but this {self_name} instance cannot handle {problems_or}. " - f"Calls with {problems_or} may result in error or unreliable results." - ) - - # raise exception or warning with message - # if self is composite, raise a warning, since passing could be fine - # see discussion in PR 2366 why - if len(problems) > 0: - if self.is_composite(): - warn(msg, obj=self) - else: - raise ValueError(msg) - - def _convert_X(self, X): - """Convert equal length series from DataFrame to numpy array or vice versa. - - Parameters - ---------- - self : this classifier - X : pd.DataFrame or np.ndarray. Input attribute data - - Returns - ------- - X : input X converted to type in "X_inner_mtype" tag - usually a pd.DataFrame (nested) or 3D np.ndarray - Checked and possibly converted input data - """ - inner_type = self.get_tag("X_inner_mtype") - # convert pd.DataFrame - X = convert_to( - X, - to_type=inner_type, - as_scitype="Panel", - ) - return X - - def _check_classifier_input( - self, X, y=None, enforce_min_instances=1, return_metadata=True - ): - """Check whether input X and y are valid formats with minimum data. - - Raises a ValueError if the input is not valid. - - Parameters - ---------- - X : check whether conformant with any sktime Panel mtype specification - y : check whether a pd.Series or np.array - enforce_min_instances : int, optional (default=1) - check there are a minimum number of instances. - return_metadata : bool, str, or list of str - metadata fields to return with X_metadata, input to check_is_scitype - - Returns - ------- - metadata : dict with metadata for X returned by datatypes.check_is_scitype - - Raises - ------ - ValueError - If y or X is invalid input data type, or there is not enough data - """ - # Check X is valid input type and recover the data characteristics - X_valid, _, X_metadata = check_is_scitype( - X, scitype="Panel", return_metadata=return_metadata - ) - if not X_valid: - raise TypeError( - f"X is not of a supported input data type." - f"X must be in a supported mtype format for Panel, found {type(X)}" - f"Use datatypes.check_is_mtype to check conformance " - "with specifications." - ) - n_cases = X_metadata["n_instances"] - if n_cases < enforce_min_instances: - raise ValueError( - f"Minimum number of cases required is {enforce_min_instances} but X " - f"has : {n_cases}" - ) - - # Check y if passed - if y is not None: - # Check y valid input - if not isinstance(y, (pd.Series, np.ndarray)): - raise ValueError( - f"y must be a np.array or a pd.Series, but found type: {type(y)}" - ) - # Check matching number of labels - n_labels = y.shape[0] - if n_cases != n_labels: - raise ValueError( - f"Mismatch in number of cases. Number in X = {n_cases} nos in y = " - f"{n_labels}" - ) - if isinstance(y, np.ndarray): - if y.ndim > 1: - raise ValueError( - f"np.ndarray y must be 1-dimensional, " - f"but found {y.ndim} dimensions" - ) - # warn if only a single class label is seen - # this should not raise exception since this can occur by train subsampling - if len(np.unique(y)) == 1: - warn( - "only single class label seen in y passed to " - f"fit of classifier {type(self).__name__}", - obj=self, - ) - - return X_metadata - - def _internal_convert(self, X, y=None): - """Convert X and y if necessary as a user convenience. - - Convert X to a 3D numpy array if already a 2D and convert y into an 1D numpy - array if passed as a Series. - - Parameters - ---------- - X : an object of a supported Panel mtype, or 2D numpy.ndarray - y : np.ndarray or pd.Series - - Returns - ------- - X: an object of a supported Panel mtype, numpy3D if X was a 2D numpy.ndarray - y: np.ndarray - """ - if isinstance(X, np.ndarray): - # Temporary fix to insist on 3D numpy. For univariate problems, - # most classifiers simply convert back to 2D. This squeezing should be - # done here, but touches a lot of files, so will get this to work first. - if X.ndim == 2: - X = X.reshape(X.shape[0], 1, X.shape[1]) - if y is not None and isinstance(y, pd.Series): - # y should be a numpy array, although we allow Series for user convenience - y = pd.Series.to_numpy(y) - if y is None: - return X - return X, y diff --git a/sktime/classification/compose/__init__.py b/sktime/classification/compose/__init__.py index a42414b175a..3d6b35065e0 100644 --- a/sktime/classification/compose/__init__.py +++ b/sktime/classification/compose/__init__.py @@ -6,11 +6,13 @@ "ClassifierPipeline", "ComposableTimeSeriesForestClassifier", "ColumnEnsembleClassifier", + "MultiplexClassifier", "SklearnClassifierPipeline", "WeightedEnsembleClassifier", ] from sktime.classification.compose._column_ensemble import ColumnEnsembleClassifier +from sktime.classification.compose._multiplexer import MultiplexClassifier from sktime.classification.compose._pipeline import ( ClassifierPipeline, SklearnClassifierPipeline, diff --git a/sktime/classification/compose/_column_ensemble.py b/sktime/classification/compose/_column_ensemble.py index bcebc4812bc..abe211eaf41 100644 --- a/sktime/classification/compose/_column_ensemble.py +++ b/sktime/classification/compose/_column_ensemble.py @@ -20,6 +20,7 @@ class BaseColumnEnsembleClassifier(_HeterogenousMetaEstimator, BaseClassifier): """Base Class for column ensemble.""" _tags = { + "authors": ["abostrom"], "capability:multivariate": True, "capability:predict_proba": True, "X_inner_mtype": ["nested_univ", "pd-multiindex"], diff --git a/sktime/classification/compose/_multiplexer.py b/sktime/classification/compose/_multiplexer.py new file mode 100644 index 00000000000..4d4b718cfdb --- /dev/null +++ b/sktime/classification/compose/_multiplexer.py @@ -0,0 +1,219 @@ +#!/usr/bin/env python3 -u +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +"""Implements classifier for selecting among different model classes.""" +# based on MultiplexForecaster + +from sktime.base import _HeterogenousMetaEstimator +from sktime.classification._delegate import _DelegatedClassifier +from sktime.classification.base import BaseClassifier +from sktime.datatypes import MTYPE_LIST_PANEL, MTYPE_LIST_TABLE + +__author__ = ["fkiraly"] +__all__ = ["MultiplexClassifier"] + + +class MultiplexClassifier(_HeterogenousMetaEstimator, _DelegatedClassifier): + """MultiplexClassifier for selecting among different models. + + MultiplexClassifier facilitates a framework for performing + model selection process over different model classes. + It should be used in conjunction with GridSearchCV to get full utilization. + It can be used with univariate and multivariate classifiers, + single-output and multi-output classifiers. + + MultiplexClassifier is specified with a (named) list of classifiers + and a selected_classifier hyper-parameter, which is one of the classifier names. + The MultiplexClassifier then behaves precisely as the classifier with + name selected_classifier, ignoring functionality in the other classifiers. + + When used with GridSearchCV, MultiplexClassifier + provides an ability to tune across multiple estimators, i.e., to perform AutoML, + by tuning the selected_classifier hyper-parameter. This combination will then + select one of the passed classifiers via the tuning algorithm. + + Parameters + ---------- + classifiers : list of sktime classifiers, or + list of tuples (str, estimator) of sktime classifiers + MultiplexClassifier can switch ("multiplex") between these classifiers. + These are "blueprint" classifiers, states do not change when `fit` is called. + selected_classifier: str or None, optional, Default=None. + If str, must be one of the classifier names. + If no names are provided, must coincide with auto-generated name strings. + To inspect auto-generated name strings, call get_params. + If None, behaves as if the first classifier in the list is selected. + Selects the classifier as which MultiplexClassifier behaves. + + Attributes + ---------- + classifier_ : sktime classifier + clone of the selected classifier used for fitting and classification. + _classifiers : list of (str, classifier) tuples + str are identical to those passed, if passed strings are unique + otherwise unique strings are generated from class name; if not unique, + the string `_[i]` is appended where `[i]` is count of occurrence up until then + """ + + _tags = { + "authors": ["fkiraly"], + "capability:multioutput": True, + "capability:multivariate": True, + "capability:unequal_length": True, + "capability:missing_values": True, + "capability:predict_proba": True, + "X_inner_mtype": MTYPE_LIST_PANEL, + "y_inner_mtype": MTYPE_LIST_TABLE, + "fit_is_empty": False, + } + + # attribute for _DelegatedClassifier, which then delegates + # all non-overridden methods to those of same name in self.classifier_ + # see further details in _DelegatedClassifier docstring + _delegate_name = "classifier_" + + # for default get_params/set_params from _HeterogenousMetaEstimator + # _steps_attr points to the attribute of self + # which contains the heterogeneous set of estimators + # this must be an iterable of (name: str, estimator, ...) tuples for the default + _steps_attr = "_classifiers" + # if the estimator is fittable, _HeterogenousMetaEstimator also + # provides an override for get_fitted_params for params from the fitted estimators + # the fitted estimators should be in a different attribute, _steps_fitted_attr + # this must be an iterable of (name: str, estimator, ...) tuples for the default + _steps_fitted_attr = "classifiers_" + + def __init__( + self, + classifiers: list, + selected_classifier=None, + ): + super().__init__() + self.selected_classifier = selected_classifier + + self.classifiers = classifiers + self._check_estimators( + classifiers, + attr_name="classifiers", + cls_type=BaseClassifier, + clone_ests=False, + ) + self._set_classifier() + + self.clone_tags(self.classifier_) + self.set_tags(**{"fit_is_empty": False}) + # this ensures that we convert in the inner estimator, not in the multiplexer + self.set_tags(**{"X_inner_mtype": MTYPE_LIST_PANEL}) + self.set_tags(**{"y_inner_mtype": MTYPE_LIST_TABLE}) + + @property + def _classifiers(self): + """Classifiers turned into name/est tuples.""" + return self._get_estimator_tuples(self.classifiers, clone_ests=False) + + @_classifiers.setter + def _classifiers(self, value): + self.classifiers = value + + def _check_selected_classifier(self): + component_names = self._get_estimator_names(self._classifiers, make_unique=True) + selected = self.selected_classifier + if selected is not None and selected not in component_names: + raise Exception( + f"Invalid selected_classifier parameter value provided, " + f" found: {self.selected_classifier}. Must be one of these" + f" valid selected_classifier parameter values: {component_names}." + ) + + def __or__(self, other): + """Magic | (or) method, return (right) concatenated MultiplexClassifier. + + Implemented for `other` being a classifier, otherwise returns `NotImplemented`. + + Parameters + ---------- + other: `sktime` classifier, must inherit from BaseClassifier + otherwise, `NotImplemented` is returned + + Returns + ------- + MultiplexClassifier object, concatenation of `self` (first) with `other` (last). + not nested, contains only non-MultiplexClassifier `sktime` classifiers + + Raises + ------ + ValueError if other is not of type MultiplexClassifier or BaseClassifier. + """ + return self._dunder_concat( + other=other, + base_class=BaseClassifier, + composite_class=MultiplexClassifier, + attr_name="classifiers", + concat_order="left", + ) + + def __ror__(self, other): + """Magic | (or) method, return (left) concatenated MultiplexClassifier. + + Implemented for `other` being a classifier, otherwise returns `NotImplemented`. + + Parameters + ---------- + other: `sktime` classifier, must inherit from BaseClassifier + otherwise, `NotImplemented` is returned + + Returns + ------- + MultiplexClassifier object, concatenation of `self` (last) with `other` (first). + not nested, contains only non-MultiplexClassifier `sktime` classifiers + """ + return self._dunder_concat( + other=other, + base_class=BaseClassifier, + composite_class=MultiplexClassifier, + attr_name="classifiers", + concat_order="right", + ) + + def _set_classifier(self): + self._check_selected_classifier() + # clone the selected classifier to self.classifier_ + if self.selected_classifier is not None: + for name, classifier in self._get_estimator_tuples(self.classifiers): + if self.selected_classifier == name: + self.classifier_ = classifier.clone() + else: + # if None, simply clone the first classifier to self.classifier_ + self.classifier_ = self._get_estimator_list(self.classifiers)[0].clone() + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + + Returns + ------- + params : dict or list of dict + """ + from sktime.classification.dummy import DummyClassifier + + params1 = { + "classifiers": [ + ("Naive_maj", DummyClassifier(strategy="most_frequent")), + ("Naive_pri", DummyClassifier(strategy="prior")), + ("Naive_uni", DummyClassifier(strategy="uniform")), + ], + "selected_classifier": "Naive_maj", + } + params2 = { + "classifiers": [ + DummyClassifier(strategy="most_frequent"), + DummyClassifier(strategy="prior"), + DummyClassifier(strategy="uniform"), + ], + } + return [params1, params2] diff --git a/sktime/classification/compose/_pipeline.py b/sktime/classification/compose/_pipeline.py index a7ae2e0f180..8c89d2609fa 100644 --- a/sktime/classification/compose/_pipeline.py +++ b/sktime/classification/compose/_pipeline.py @@ -92,6 +92,7 @@ class ClassifierPipeline(_HeterogenousMetaEstimator, BaseClassifier): """ _tags = { + "authors": ["fkiraly"], "X_inner_mtype": "pd-multiindex", # which type do _fit/_predict accept "capability:multivariate": False, "capability:unequal_length": False, diff --git a/sktime/classification/deep_learning/__init__.py b/sktime/classification/deep_learning/__init__.py index 092c206f51c..7215a2bcd06 100644 --- a/sktime/classification/deep_learning/__init__.py +++ b/sktime/classification/deep_learning/__init__.py @@ -1,16 +1,26 @@ """Deep learning based classifiers.""" __all__ = [ "CNNClassifier", + "CNTCClassifier", "FCNClassifier", "InceptionTimeClassifier", "LSTMFCNClassifier", + "MACNNClassifier", + "MCDCNNClassifier", "MLPClassifier", + "ResNetClassifier", + "SimpleRNNClassifier", "TapNetClassifier", ] from sktime.classification.deep_learning.cnn import CNNClassifier +from sktime.classification.deep_learning.cntc import CNTCClassifier from sktime.classification.deep_learning.fcn import FCNClassifier from sktime.classification.deep_learning.inceptiontime import InceptionTimeClassifier from sktime.classification.deep_learning.lstmfcn import LSTMFCNClassifier +from sktime.classification.deep_learning.macnn import MACNNClassifier +from sktime.classification.deep_learning.mcdcnn import MCDCNNClassifier from sktime.classification.deep_learning.mlp import MLPClassifier +from sktime.classification.deep_learning.resnet import ResNetClassifier +from sktime.classification.deep_learning.rnn import SimpleRNNClassifier from sktime.classification.deep_learning.tapnet import TapNetClassifier diff --git a/sktime/classification/deep_learning/base.py b/sktime/classification/deep_learning/base.py index 1dda1707b0c..76ca992efac 100644 --- a/sktime/classification/deep_learning/base.py +++ b/sktime/classification/deep_learning/base.py @@ -12,6 +12,7 @@ from sklearn.preprocessing import LabelEncoder, OneHotEncoder from sklearn.utils import check_random_state +from sktime.base._base import SERIALIZATION_FORMATS from sktime.classification.base import BaseClassifier from sktime.utils.validation._dependencies import _check_soft_dependencies @@ -115,7 +116,14 @@ def convert_y_to_keras(self, y): self.classes_ = self.label_encoder.classes_ self.n_classes_ = len(self.classes_) y = y.reshape(len(y), 1) - self.onehot_encoder = OneHotEncoder(sparse=False, categories="auto") + + # in sklearn 1.2, sparse was renamed to sparse_output + if _check_soft_dependencies("sklearn>=1.2", severity="none"): + sparse_kw = {"sparse_output": False} + else: + sparse_kw = {"sparse": False} + + self.onehot_encoder = OneHotEncoder(categories="auto", **sparse_kw) # categories='auto' to get rid of FutureWarning y = self.onehot_encoder.fit_transform(y) return y @@ -203,7 +211,7 @@ def __setstate__(self, state): if hasattr(self, "history"): self.__dict__["history"] = self.history - def save(self, path=None): + def save(self, path=None, serialization_format="pickle"): """Save serialized self to bytes-like object or to (.zip) file. Behaviour: @@ -225,18 +233,62 @@ def save(self, path=None): path="/home/stored/estimator" then a zip file `estimator.zip` will be stored in `/home/stored/`. + serialization_format: str, default = "pickle" + Module to use for serialization. + The available options are present under + `sktime.base._base.SERIALIZATION_FORMATS`. Note that non-default formats + might require installation of other soft dependencies. + Returns ------- if `path` is None - in-memory serialized self if `path` is file location - ZipFile with reference to the file """ import pickle - import shutil from pathlib import Path + + if serialization_format not in SERIALIZATION_FORMATS: + raise ValueError( + f"The provided `serialization_format`='{serialization_format}' " + "is not yet supported. The possible formats are: " + f"{SERIALIZATION_FORMATS}." + ) + + if path is not None and not isinstance(path, (str, Path)): + raise TypeError( + "`path` is expected to either be a string or a Path object " + f"but found of type:{type(path)}." + ) + + if path is not None: + path = Path(path) if isinstance(path, str) else path + path.mkdir() + + if serialization_format == "cloudpickle": + _check_soft_dependencies("cloudpickle", severity="error") + import cloudpickle + + return self._serialize_using_dump_func( + path=path, + dump=cloudpickle.dump, + dumps=cloudpickle.dumps, + ) + + elif serialization_format == "pickle": + return self._serialize_using_dump_func( + path=path, + dump=pickle.dump, + dumps=pickle.dumps, + ) + + def _serialize_using_dump_func(self, path, dump, dumps): + """Serialize & return DL Estimator using `dump` and `dumps` functions.""" + import shutil from zipfile import ZipFile + history = self.history.history if self.history is not None else None if path is None: - _check_soft_dependencies("h5py") + _check_soft_dependencies("h5py", severity="error") import h5py in_memory_model = None @@ -248,34 +300,25 @@ def save(self, path=None): h5file.flush() in_memory_model = h5file.id.get_file_image() - in_memory_history = pickle.dumps(self.history.history) - + in_memory_history = dumps(history) return ( type(self), ( - pickle.dumps(self), + dumps(self), in_memory_model, in_memory_history, ), ) - if not isinstance(path, (str, Path)): - raise TypeError( - "`path` is expected to either be a string or a Path object " - f"but found of type:{type(path)}." - ) - - path = Path(path) if isinstance(path, str) else path - path.mkdir() - if self.model_ is not None: self.model_.save(path / "keras/") with open(path / "history", "wb") as history_writer: - pickle.dump(self.history.history, history_writer) - - pickle.dump(type(self), open(path / "_metadata", "wb")) - pickle.dump(self, open(path / "_obj", "wb")) + dump(history, history_writer) + with open(path / "_metadata", "wb") as file: + dump(type(self), file) + with open(path / "_obj", "wb") as file: + dump(self, file) shutil.make_archive(base_name=path, format="zip", root_dir=path) shutil.rmtree(path) diff --git a/sktime/classification/deep_learning/cnn.py b/sktime/classification/deep_learning/cnn.py index 45d78cae6e3..899d8a3d756 100644 --- a/sktime/classification/deep_learning/cnn.py +++ b/sktime/classification/deep_learning/cnn.py @@ -17,7 +17,6 @@ class CNNClassifier(BaseDeepClassifier): Parameters ---------- - should inherited fields be listed here? n_epochs : int, default = 2000 the number of epochs to train the model batch_size : int, default = 16 @@ -35,7 +34,6 @@ class CNNClassifier(BaseDeepClassifier): whether to output extra information loss : string, default="mean_squared_error" fit parameter for the keras model - optimizer : keras.optimizer, default=keras.optimizers.Adam(), metrics : list of strings, default=["accuracy"], activation : string or a tf callable, default="sigmoid" Activation function used in the output linear layer. @@ -67,7 +65,14 @@ class CNNClassifier(BaseDeepClassifier): CNNClassifier(...) """ - _tags = {"python_dependencies": "tensorflow"} + _tags = { + # packaging info + # -------------- + "authors": ["James-Large", "TonyBagnall"], + "maintainers": ["James-Large"], + "python_dependencies": "tensorflow", + # estimator type handled by parent class + } def __init__( self, diff --git a/sktime/classification/deep_learning/cntc.py b/sktime/classification/deep_learning/cntc.py new file mode 100644 index 00000000000..900e9861318 --- /dev/null +++ b/sktime/classification/deep_learning/cntc.py @@ -0,0 +1,287 @@ +"""Contextual Time-series Neural Classifier for TSC.""" + +__author__ = ["James-Large", "TonyBagnall", "AurumnPegasus"] +__all__ = ["CNTCClassifier"] +from sklearn.utils import check_random_state + +from sktime.classification.deep_learning.base import BaseDeepClassifier +from sktime.networks.cntc import CNTCNetwork +from sktime.utils.validation._dependencies import _check_dl_dependencies + + +class CNTCClassifier(BaseDeepClassifier): + """Contextual Time-series Neural Classifier (CNTC), as described in [1]. + + Parameters + ---------- + n_epochs : int, default = 2000 + the number of epochs to train the model + batch_size : int, default = 16 + the number of samples per gradient update. + filter_sizes : tuple of shape (2), default = (16, 8) + filter sizes for CNNs in CCNN arm. + kernel_sizes : two-tuple, default = (1, 1) + the length of the 1D convolution window for + CNNs in CCNN arm. + rnn_size : int, default = 64 + number of rnn units in the CCNN arm. + lstm_size : int, default = 8 + number of lstm units in the CLSTM arm. + dense_size : int, default = 64 + dimension of dense layer in CNTC. + random_state : int or None, default=None + Seed for random number generation. + verbose : boolean, default = False + whether to output extra information + loss : string, default="mean_squared_error" + fit parameter for the keras model + optimizer : keras.optimizer, default=keras.optimizers.Adam(), + metrics : list of strings, default=["accuracy"], + + Notes + ----- + Adapted from the implementation from Fullah et. al + https://github.com/AmaduFullah/CNTC_MODEL/blob/master/cntc.ipynb + + References + ---------- + .. [1] Network originally defined in: + @article{FULLAHKAMARA202057, + title = {Combining contextual neural networks for time series classification}, + journal = {Neurocomputing}, + volume = {384}, + pages = {57-66}, + year = {2020}, + issn = {0925-2312}, + doi = {https://doi.org/10.1016/j.neucom.2019.10.113}, + url = {https://www.sciencedirect.com/science/article/pii/S0925231219316364}, + author = {Amadu {Fullah Kamara} and Enhong Chen and Qi Liu and Zhen Pan}, + keywords = {Time series classification, Contextual convolutional neural + networks, Contextual long short-term memory, Attention, Multilayer + perceptron}, + } + + Examples + -------- + >>> from sktime.classification.deep_learning.cntc import CNTCClassifier + >>> from sktime.datasets import load_unit_test + >>> X_train, y_train = load_unit_test(split="train", return_X_y=True) + >>> X_test, y_test = load_unit_test(split="test", return_X_y=True) + >>> cntc = CNTCClassifier() # doctest: +SKIP + >>> cntc.fit(X_train, y_train) # doctest: +SKIP + CNTCClassifier(...) # doctest: +SKIP + """ + + _tags = { + "authors": ["James-Large", "Withington", "TonyBagnall", "AurumnPegasus"], + "maintainers": ["James-Large", "Withington", "AurumnPegasus"], + "python_dependencies": ["tensorflow", "keras-self-attention"], + } + + def __init__( + self, + n_epochs=2000, + batch_size=16, + filter_sizes=(16, 8), + kernel_sizes=(1, 1), + rnn_size=64, + lstm_size=8, + dense_size=64, + callbacks=None, + verbose=False, + loss="categorical_crossentropy", + metrics=None, + random_state=0, + ): + _check_dl_dependencies(severity="error") + + self.kernel_sizes = kernel_sizes # used plural + self.filter_sizes = filter_sizes # used plural + self.rnn_size = rnn_size + self.lstm_size = lstm_size + self.dense_size = dense_size + self.callbacks = callbacks + self.n_epochs = n_epochs + self.batch_size = batch_size + self.verbose = verbose + self.loss = loss + self.metrics = metrics + self.random_state = random_state + self._network = CNTCNetwork() + + super().__init__(batch_size=batch_size, random_state=random_state) + + def build_model(self, input_shape, n_classes, **kwargs): + """Construct a compiled, un-trained, keras model that is ready for training. + + In sktime, time series are stored in numpy arrays of shape (d,m), where d + is the number of dimensions, m is the series length. Keras/tensorflow assume + data is in shape (m,d). This method also assumes (m,d). Transpose should + happen in fit. + + Parameters + ---------- + input_shape : tuple + The shape of the data fed into the input layer, should be (m,d) + n_classes: int + The number of classes, which becomes the size of the output layer + + Returns + ------- + output : a compiled Keras Model + """ + from tensorflow import keras + + metrics = ["accuracy"] if self.metrics is None else self.metrics + input_layer, output_layer = self._network.build_network(input_shape, **kwargs) + + output_layer = keras.layers.Dense(units=n_classes, activation="softmax")( + output_layer + ) + + model = keras.models.Model(inputs=input_layer, outputs=output_layer) + model.compile( + loss=self.loss, + optimizer=keras.optimizers.Adam(), + metrics=metrics, + ) + return model + + def prepare_input(self, X): + """ + Prepare input for the CLSTM arm of the model. + + According to the paper: + " + Time series data is fed into a CLSTM and CCNN networks simultaneously + and is perceived differently. In the CLSTM block, the input data is + viewed as a multivariate time series with a single time stamp. In + contrast, the CCNN block receives univariate data with numerous time + stamps + " + + Arguments + --------- + X: tuple of shape = (series_length (m), n_dimensions (d)) + The shape of the data fed into the model. + + Returns + ------- + trainX: tuple, + The input to be fed to the two arms of CNTC. + """ + import numpy as np + import pandas as pd + from tensorflow import keras + + if X.shape[2] == 1: + # Converting data to pandas + trainX1 = X.reshape([X.shape[0], X.shape[1]]) + pd_trainX = pd.DataFrame(trainX1) + + # Taking rolling window + window = pd_trainX.rolling(window=3).mean() + window = window.fillna(0) + + trainX2 = np.concatenate((trainX1, window), axis=1) + trainX2 = keras.backend.variable(trainX2) + trainX2 = keras.layers.Dense( + trainX1.shape[1], input_shape=(trainX2.shape[1:]) + )(trainX2) + trainX2 = keras.backend.eval(trainX2) + trainX = trainX2.reshape((trainX2.shape[0], trainX2.shape[1], 1)) + else: + trainXs = [] + for i in range(X.shape[2]): + trainX1 = X[:, :, i] + pd_trainX = pd.DataFrame(trainX1) + + window = pd_trainX.rolling(window=3).mean() + window = window.fillna(0) + + trainX2 = np.concatenate((trainX1, window), axis=1) + trainX2 = keras.backend.variable(trainX2) + trainX2 = keras.layers.Dense( + trainX1.shape[1], input_shape=(trainX2.shape[1:]) + )(trainX2) + trainX2 = keras.backend.eval(trainX2) + + trainX = trainX2.reshape((trainX2.shape[0], trainX2.shape[1], 1)) + trainXs.append(trainX) + + trainX = np.concatenate(trainXs, axis=2) + return trainX + + def _fit(self, X, y): + """Fit the classifier on the training set (X, y). + + Parameters + ---------- + X : np.ndarray of shape = (n_instances (n), n_dimensions (d), series_length (m)) + The training input samples. + y : np.ndarray of shape n + The training data class labels. + + Returns + ------- + self : object + """ + if self.callbacks is None: + self._callbacks = [] + y_onehot = self.convert_y_to_keras(y) + # Transpose to conform to Keras input style. + X = X.transpose(0, 2, 1) + + check_random_state(self.random_state) + self.input_shape = X.shape[1:] + self.model_ = self.build_model(self.input_shape, self.n_classes_) + X2 = self.prepare_input(X) + if self.verbose: + self.model_.summary() + self.history = self.model_.fit( + [X2, X, X], + y_onehot, + batch_size=self.batch_size, + epochs=self.n_epochs, + verbose=self.verbose, + callbacks=self._callbacks, + ) + return self + + def _predict(self, X, **kwargs): + import numpy as np + + probs = self._predict_proba(X, **kwargs) + rng = check_random_state(self.random_state) + return np.array( + [ + self.classes_[int(rng.choice(np.flatnonzero(prob == prob.max())))] + for prob in probs + ] + ) + + def _predict_proba(self, X, **kwargs): + """Find probability estimates for each class for all cases in X. + + Parameters + ---------- + X : an np.ndarray of shape = (n_instances, n_dimensions, series_length) + The training input samples. + + Returns + ------- + output : array of shape = [n_instances, n_classes] of probabilities + """ + import numpy as np + + # Transpose to work correctly with keras + X = X.transpose((0, 2, 1)) + X2 = self.prepare_input(X) + probs = self.model_.predict([X2, X, X], self.batch_size, **kwargs) + + # check if binary classification + if probs.shape[1] == 1: + # first column is probability of class 0 and second is of class 1 + probs = np.hstack([1 - probs, probs]) + probs = probs / probs.sum(axis=1, keepdims=1) + return probs diff --git a/sktime/classification/deep_learning/fcn.py b/sktime/classification/deep_learning/fcn.py index 3f86beef848..cece17d47e6 100644 --- a/sktime/classification/deep_learning/fcn.py +++ b/sktime/classification/deep_learning/fcn.py @@ -60,6 +60,14 @@ class FCNClassifier(BaseDeepClassifier): FCNClassifier(...) """ + _tags = { + # packaging info + # -------------- + "authors": ["James-Large", "AurumnPegasus"], + "maintainers": ["James-Large", "AurumnPegasus"], + # estimator type handled by parent class + } + def __init__( self, n_epochs=2000, diff --git a/sktime/classification/deep_learning/inceptiontime.py b/sktime/classification/deep_learning/inceptiontime.py index 041b196f142..e4b1d4636ed 100644 --- a/sktime/classification/deep_learning/inceptiontime.py +++ b/sktime/classification/deep_learning/inceptiontime.py @@ -43,6 +43,14 @@ class InceptionTimeClassifier(BaseDeepClassifier): https://github.com/hfawaz/InceptionTime/blob/master/classifiers/inception.py """ + _tags = { + # packaging info + # -------------- + "authors": ["james-large"], + "maintainers": ["james-large"], + # estimator type handled by parent class + } + def __init__( self, n_epochs=1500, diff --git a/sktime/classification/deep_learning/lstmfcn.py b/sktime/classification/deep_learning/lstmfcn.py index 4b73575cc25..ddabf816429 100644 --- a/sktime/classification/deep_learning/lstmfcn.py +++ b/sktime/classification/deep_learning/lstmfcn.py @@ -19,7 +19,6 @@ class LSTMFCNClassifier(BaseDeepClassifier): Combines an LSTM arm with a CNN arm. Optionally uses an attention mechanism in the LSTM which the author indicates provides improved performance. - Parameters ---------- n_epochs: int, default=2000 @@ -49,19 +48,20 @@ class LSTMFCNClassifier(BaseDeepClassifier): random_state : int or None, default=None Seed for random, integer. - - Notes - ----- - Ported from sktime-dl source code - https://github.com/sktime/sktime-dl/blob/master/sktime_dl/classification/_lstmfcn.py - References ---------- .. [1] Karim et al. Multivariate LSTM-FCNs for Time Series Classification, 2019 https://arxiv.org/pdf/1801.04503.pdf """ - _tags = {"python_dependencies": "tensorflow"} + _tags = { + # packaging info + # -------------- + "authors": ["jnrusson1", "solen0id"], + "maintainers": ["jnrusson1", "solen0id"], + "python_dependencies": "tensorflow", + # estimator type handled by parent class + } def __init__( self, diff --git a/sktime/classification/deep_learning/macnn.py b/sktime/classification/deep_learning/macnn.py index daf513c7358..ba504fd55ee 100644 --- a/sktime/classification/deep_learning/macnn.py +++ b/sktime/classification/deep_learning/macnn.py @@ -77,7 +77,14 @@ class MACNNClassifier(BaseDeepClassifier): MACNNClassifier(...) """ - _tags = {"python_dependencies": "tensorflow"} + _tags = { + # packaging info + # -------------- + "authors": ["jnrusson1"], + "maintainers": "jnrusson1", + "python_dependencies": "tensorflow", + # estimator type handled by parent class + } def __init__( self, diff --git a/sktime/classification/deep_learning/mcdcnn.py b/sktime/classification/deep_learning/mcdcnn.py index 1a9f024a20c..2c614814671 100644 --- a/sktime/classification/deep_learning/mcdcnn.py +++ b/sktime/classification/deep_learning/mcdcnn.py @@ -1,8 +1,6 @@ """Multi Channel Deep Convolutional Neural Classifier (MCDCNN).""" -__author__ = [ - "JamesLarge", -] +__author__ = ["James-Large"] from copy import deepcopy @@ -80,7 +78,14 @@ class MCDCNNClassifier(BaseDeepClassifier): MCDCNNClassifier(...) """ - _tags = {"python_dependencies": "tensorflow"} + _tags = { + # packaging info + # -------------- + "authors": ["james-large"], + "maintainers": ["james-large"], + "python_dependencies": "tensorflow", + # estimator type handled by parent class + } def __init__( self, diff --git a/sktime/classification/deep_learning/mlp.py b/sktime/classification/deep_learning/mlp.py index 0bf71a5bd1c..18adefe4dc0 100644 --- a/sktime/classification/deep_learning/mlp.py +++ b/sktime/classification/deep_learning/mlp.py @@ -60,6 +60,14 @@ class MLPClassifier(BaseDeepClassifier): MLPClassifier(...) """ + _tags = { + # packaging info + # -------------- + "authors": ["James-Large", "AurumnPegasus"], + "maintainers": ["James-Large", "AurumnPegasus"], + # estimator type handled by parent class + } + def __init__( self, n_epochs=2000, diff --git a/sktime/classification/deep_learning/resnet.py b/sktime/classification/deep_learning/resnet.py index 870da4eff9e..b5b292fa5fb 100644 --- a/sktime/classification/deep_learning/resnet.py +++ b/sktime/classification/deep_learning/resnet.py @@ -60,7 +60,14 @@ class ResNetClassifier(BaseDeepClassifier): ResNetClassifier(...) """ - _tags = {"python_dependencies": ["tensorflow"]} + _tags = { + # packaging info + # -------------- + "authors": ["James-Large", "AurumnPegasus", "nilesh05apr"], + "maintainers": ["James-Large", "AurumnPegasus", "nilesh05apr"], + "python_dependencies": ["tensorflow"], + # estimator type handled by parent class + } def __init__( self, diff --git a/sktime/classification/deep_learning/rnn.py b/sktime/classification/deep_learning/rnn.py index cbac0badb9d..41ec273aa41 100644 --- a/sktime/classification/deep_learning/rnn.py +++ b/sktime/classification/deep_learning/rnn.py @@ -49,9 +49,16 @@ class SimpleRNNClassifier(BaseDeepClassifier): https://github.com/Mcompetitions/M4-methods """ + _tags = { + # packaging info + # -------------- + "authors": ["mloning"], + # estimator type handled by parent class + } + def __init__( self, - num_epochs=100, + n_epochs=100, batch_size=1, units=6, callbacks=None, @@ -65,8 +72,9 @@ def __init__( optimizer=None, ): _check_dl_dependencies(severity="error") + super().__init__() - self.num_epochs = num_epochs + self.batch_size = batch_size self.verbose = verbose self.units = units @@ -80,6 +88,7 @@ def __init__( self.optimizer = optimizer self.history = None self._network = RNNNetwork(random_state=random_state, units=units) + self.n_epochs = n_epochs def build_model(self, input_shape, n_classes, **kwargs): """Construct a compiled, un-trained, keras model that is ready for training. @@ -189,7 +198,7 @@ def _fit(self, X, y): X, y_onehot, batch_size=self.batch_size, - epochs=self.num_epochs, + epochs=self.n_epochs, verbose=self.verbose, callbacks=self.callbacks_, ) @@ -218,7 +227,7 @@ def get_test_params(cls, parameter_set="default"): """ params1 = {} params2 = { - "num_epochs": 50, + "n_epochs": 50, "batch_size": 2, "units": 5, "use_bias": False, diff --git a/sktime/classification/deep_learning/tapnet.py b/sktime/classification/deep_learning/tapnet.py index 11f396d7412..267783999a2 100644 --- a/sktime/classification/deep_learning/tapnet.py +++ b/sktime/classification/deep_learning/tapnet.py @@ -1,7 +1,7 @@ """Time Convolutional Neural Network (CNN) for classification.""" __author__ = [ - "Jack Russon", + "jnrusson1", "TonyBagnall", "achieveordie", ] @@ -85,7 +85,14 @@ class TapNetClassifier(BaseDeepClassifier): TapNetClassifier(...) """ - _tags = {"python_dependencies": "tensorflow"} + _tags = { + # packaging info + # -------------- + "authors": ["jnrusson1", "TonyBagnall", "achieveordie"], + "maintainers": ["jnrusson1", "achieveordie"], + "python_dependencies": "tensorflow", + # estimator type handled by parent class + } def __init__( self, diff --git a/sktime/classification/dictionary_based/_boss.py b/sktime/classification/dictionary_based/_boss.py index cfcfb6ca9fc..747636923a0 100644 --- a/sktime/classification/dictionary_based/_boss.py +++ b/sktime/classification/dictionary_based/_boss.py @@ -7,6 +7,7 @@ __author__ = ["MatthewMiddlehurst", "patrickzib"] __all__ = ["BOSSEnsemble", "IndividualBOSS", "pairwise_distances"] +from copy import copy from itertools import compress import numpy as np @@ -125,11 +126,16 @@ class BOSSEnsemble(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": ["MatthewMiddlehurst", "patrickzib"], + "python_dependencies": "numba", + # estimator type + # -------------- "capability:train_estimate": True, "capability:multithreading": True, "classifier_type": "dictionary", "capability:predict_proba": True, - "python_dependencies": "numba", } def __init__( @@ -528,8 +534,13 @@ class IndividualBOSS(BaseClassifier): """ _tags = { - "capability:multithreading": True, + # packaging info + # -------------- + "authors": ["MatthewMiddlehurst", "patrickzib"], "python_dependencies": "numba", + # estimator type + # -------------- + "capability:multithreading": True, } def __init__( @@ -648,25 +659,22 @@ def _train_predict(self, train_num, distance_matrix): return self._class_vals[min_pos] def _shorten_bags(self, word_len, y): - new_boss = IndividualBOSS( - self.window_size, - word_len, - self.norm, - self.alphabet_size, - save_words=self.save_words, - use_boss_distance=self.use_boss_distance, - feature_selection=self.feature_selection, - n_jobs=self.n_jobs, - random_state=self.random_state, - ) + new_boss = copy(self) + + # change word length parameter + new_boss.word_length = word_len + + # reset internal variables + new_boss._accuracy = 0 + new_boss._subsample = [] + new_boss._train_predictions = [] + + # copy fitted transformer as reference new_boss._transformer = self._transformer + + # update shortened bags new_bag = new_boss._transformer._shorten_bags(word_len, y) new_boss._transformed_data = new_bag - new_boss._class_vals = self._class_vals - new_boss.n_classes_ = self.n_classes_ - new_boss.classes_ = self.classes_ - new_boss._class_dictionary = self._class_dictionary - new_boss._is_fitted = True return new_boss diff --git a/sktime/classification/dictionary_based/_cboss.py b/sktime/classification/dictionary_based/_cboss.py index e8d3df20d09..412c2d32372 100644 --- a/sktime/classification/dictionary_based/_cboss.py +++ b/sktime/classification/dictionary_based/_cboss.py @@ -130,12 +130,18 @@ class ContractableBOSS(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": ["MatthewMiddlehurst", "BINAYKUMAR943"], + "maintainers": "BINAYKUMAR943", + "python_dependencies": "numba", + # estimator type + # -------------- "capability:train_estimate": True, "capability:contractable": True, "capability:multithreading": True, "classifier_type": "dictionary", "capability:predict_proba": True, - "python_dependencies": "numba", } def __init__( diff --git a/sktime/classification/dictionary_based/_muse.py b/sktime/classification/dictionary_based/_muse.py index 46f37252d46..0789552f5c1 100644 --- a/sktime/classification/dictionary_based/_muse.py +++ b/sktime/classification/dictionary_based/_muse.py @@ -119,12 +119,18 @@ class MUSE(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": ["patrickzib", "BINAYKUMAR943"], + "maintainers": "BINAYKUMAR943", + "python_dependencies": "numba", + # estimator type + # -------------- "capability:multivariate": True, "capability:multithreading": True, "capability:predict_proba": True, "X_inner_mtype": "numpy3D", # which mtypes do _fit/_predict support for X? "classifier_type": "dictionary", - "python_dependencies": "numba", } def __init__( diff --git a/sktime/classification/dictionary_based/_tde.py b/sktime/classification/dictionary_based/_tde.py index 636649fded8..87266a6d0c8 100644 --- a/sktime/classification/dictionary_based/_tde.py +++ b/sktime/classification/dictionary_based/_tde.py @@ -146,13 +146,18 @@ class TemporalDictionaryEnsemble(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": ["MatthewMiddlehurst"], + "python_dependencies": "numba", + # estimator type + # -------------- "capability:multivariate": True, "capability:train_estimate": True, "capability:contractable": True, "capability:multithreading": True, "capability:predict_proba": True, "classifier_type": "dictionary", - "python_dependencies": "numba", } def __init__( @@ -671,9 +676,14 @@ class IndividualTDE(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": ["MatthewMiddlehurst"], + "python_dependencies": "numba", + # estimator type + # -------------- "capability:multivariate": True, "capability:multithreading": True, - "python_dependencies": "numba", } def __init__( diff --git a/sktime/classification/dictionary_based/_weasel.py b/sktime/classification/dictionary_based/_weasel.py index d6fd806ed04..047c6d09753 100644 --- a/sktime/classification/dictionary_based/_weasel.py +++ b/sktime/classification/dictionary_based/_weasel.py @@ -3,7 +3,7 @@ Dictionary based classifier based on SFA transform, BOSS and linear regression. """ -__author__ = ["patrickzib", "Arik Ermshaus"] +__author__ = ["patrickzib", "ermshaua"] __all__ = ["WEASEL"] import math @@ -120,10 +120,16 @@ class WEASEL(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": ["patrickzib", "ermshaua"], + "maintainers": ["ermshaua"], + "python_dependencies": "numba", + # estimator type + # -------------- "capability:multithreading": True, "capability:predict_proba": True, "classifier_type": "dictionary", - "python_dependencies": "numba", } def __init__( diff --git a/sktime/classification/distance_based/_elastic_ensemble.py b/sktime/classification/distance_based/_elastic_ensemble.py index 6c96ac28d80..0032f01d884 100644 --- a/sktime/classification/distance_based/_elastic_ensemble.py +++ b/sktime/classification/distance_based/_elastic_ensemble.py @@ -89,6 +89,11 @@ class ElasticEnsemble(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": ["jasonlines", "TonyBagnall"], + # estimator type + # -------------- "capability:multithreading": True, "capability:predict_proba": True, "classifier_type": "distance", diff --git a/sktime/classification/distance_based/_proximity_forest.py b/sktime/classification/distance_based/_proximity_forest.py index f235a3c30dc..ae135102eac 100644 --- a/sktime/classification/distance_based/_proximity_forest.py +++ b/sktime/classification/distance_based/_proximity_forest.py @@ -790,6 +790,12 @@ class ProximityStump(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": ["goastler", "moradabaz"], + "maintainers": ["goastler", "moradabaz"], + # estimator type + # -------------- "capability:multithreading": True, "X_inner_mtype": "nested_univ", # input in nested dataframe } @@ -1061,10 +1067,16 @@ class ProximityTree(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": ["goastler", "moradabaz"], + "maintainers": ["goastler", "moradabaz"], + "python_dependencies": "numba", + # estimator type + # -------------- "capability:multithreading": True, "capability:predict_proba": True, "X_inner_mtype": "nested_univ", - "python_dependencies": "numba", } def __init__( @@ -1315,11 +1327,17 @@ class ProximityForest(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": ["goastler", "moradabaz"], + "maintainers": ["goastler", "moradabaz"], + "python_dependencies": "numba", + # estimator type + # -------------- "X_inner_mtype": "nested_univ", "capability:multithreading": True, "capability:predict_proba": True, "classifier_type": "distance", - "python_dependencies": "numba", } def __init__( diff --git a/sktime/classification/distance_based/_shape_dtw.py b/sktime/classification/distance_based/_shape_dtw.py index ea4b9b3ad86..180b5ad9cac 100644 --- a/sktime/classification/distance_based/_shape_dtw.py +++ b/sktime/classification/distance_based/_shape_dtw.py @@ -15,7 +15,7 @@ KNeighborsTimeSeriesClassifier, ) from sktime.datatypes import convert -from sktime.transformations.panel.dictionary_based._paa import PAA +from sktime.transformations.panel.dictionary_based._paa import PAAlegacy as PAA from sktime.transformations.panel.dwt import DWTTransformer from sktime.transformations.panel.hog1d import HOG1DTransformer @@ -111,6 +111,12 @@ class ShapeDTW(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": ["vincent-nich12"], + "maintainers": ["vincent-nich12"], + # estimator type + # -------------- "capability:predict_proba": True, "classifier_type": "distance", } @@ -443,7 +449,7 @@ def _check_metric_params(self, parameters): names = list(parameters.keys()) for x in names: - if not (x in valid_metric_params): + if x not in valid_metric_params: raise ValueError( x + " is not a valid metric parameter." diff --git a/sktime/classification/distance_based/_time_series_neighbors.py b/sktime/classification/distance_based/_time_series_neighbors.py index 452de04b409..cfe56392384 100644 --- a/sktime/classification/distance_based/_time_series_neighbors.py +++ b/sktime/classification/distance_based/_time_series_neighbors.py @@ -116,6 +116,11 @@ class KNeighborsTimeSeriesClassifier(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": ["jasonlines", "TonyBagnall", "chrisholder", "fkiraly"], + # estimator type + # -------------- "capability:multivariate": True, "capability:unequal_length": True, "capability:missing_values": True, @@ -229,7 +234,9 @@ def _fit(self, X, y): # "X may be a sparse graph, in which case only "nonzero" elements # may be considered neighbors." X_inner_mtype = self.get_tag("X_inner_mtype") - _, _, X_meta = check_is_mtype(X, X_inner_mtype, return_metadata=True) + _, _, X_meta = check_is_mtype( + X, X_inner_mtype, return_metadata=True, msg_return_dict="list" + ) n = X_meta["n_instances"] dist_mat = np.zeros([n, n], dtype="float") diff --git a/sktime/classification/dummy/_dummy.py b/sktime/classification/dummy/_dummy.py index 215c8a0c0f1..66a10adf683 100644 --- a/sktime/classification/dummy/_dummy.py +++ b/sktime/classification/dummy/_dummy.py @@ -60,6 +60,12 @@ class prior probabilities. """ _tags = { + # packaging info + # -------------- + "authors": ["ZiyaoWei"], + "maintainers": ["ZiyaoWei"], + # estimator type + # -------------- "X_inner_mtype": "nested_univ", "capability:missing_values": True, "capability:unequal_length": True, diff --git a/sktime/classification/early_classification/_probability_threshold.py b/sktime/classification/early_classification/_probability_threshold.py index 0464bfd3e7b..18bc3a48522 100644 --- a/sktime/classification/early_classification/_probability_threshold.py +++ b/sktime/classification/early_classification/_probability_threshold.py @@ -20,7 +20,7 @@ from sktime.utils.validation.panel import check_X -# TODO: fix this in 0.25.0 +# TODO: fix this in 0.27.0 # base class should have been changed to BaseEarlyClassifier class ProbabilityThresholdEarlyClassifier(BaseClassifier): """Probability Threshold Early Classifier. diff --git a/sktime/classification/early_classification/base.py b/sktime/classification/early_classification/base.py index 335cb38b77b..d780e26570a 100644 --- a/sktime/classification/early_classification/base.py +++ b/sktime/classification/early_classification/base.py @@ -55,7 +55,9 @@ class BaseEarlyClassifier(BaseEstimator, ABC): _tags = { "object_type": "early_classifier", # type of object "X_inner_mtype": "numpy3D", # which type do _fit/_predict, support for X? + "y_inner_mtype": "numpy1D", # which type do _fit/_predict, support for y? # it should be either "numpy3D" or "nested_univ" (nested pd.DataFrame) + "capability:multioutput": False, # whether classifier supports multioutput "capability:multivariate": False, "capability:unequal_length": False, "capability:missing_values": False, @@ -71,6 +73,14 @@ class BaseEarlyClassifier(BaseEstimator, ABC): "is_equal_length", ] + # attribute name where vectorized estimators are stored + VECTORIZATION_ATTR = "classifiers_" # e.g., classifiers_, regressors_ + + # used in error messages + TASK = "early classification" # e.g., classification, regression + EST_TYPE = "early classifier" # e.g., classifier, regressor + EST_TYPE_PLURAL = "early classifiers" # e.g., classifiers, regressors + def __init__(self): self.classes_ = [] self.n_classes_ = 0 @@ -89,6 +99,8 @@ def __init__(self): """ self.state_info = None + self._converter_store_y = {} + super().__init__() def fit(self, X, y): @@ -587,42 +599,59 @@ def _check_convert_X_for_predict(self, X): _check_convert_X_for_predict = BaseClassifier._check_convert_X_for_predict return _check_convert_X_for_predict(self, X) - def _check_capabilities(self, missing, multivariate, unequal): + def _check_capabilities(self, X_metadata): """Check whether this classifier can handle the data characteristics. Parameters ---------- - missing : boolean, does the data passed to fit contain missing values? - multivariate : boolean, does the data passed to fit contain missing values? - unequal : boolea, do the time series passed to fit have variable lengths? + X_metadata : dict with metadata for X returned by datatypes.check_is_scitype Raises ------ ValueError if the capabilities in self._tags do not handle the data. """ _check_capabilities = BaseClassifier._check_capabilities - return _check_capabilities(self, missing, multivariate, unequal) + return _check_capabilities(self, X_metadata) - def _convert_X(self, X): + def _convert_X(self, X, X_mtype): """Convert equal length series from DataFrame to numpy array or vice versa. Parameters ---------- - self : this classifier - X : pd.DataFrame or np.ndarray. Input attribute data + X : input data for the classifier + X_mtype : str, a Panel mtype string, e.g., "pd_multiindex", "numpy3D" Returns ------- X : input X converted to type in "X_inner_mtype" tag - usually a pd.DataFrame (nested) or 3D np.ndarray + usually a pd.DataFrame (nested) or 3D np.ndarray Checked and possibly converted input data """ _convert_X = BaseClassifier._convert_X - return _convert_X(self, X) + return _convert_X(self, X, X_mtype) + + def _check_y(self, y=None, return_to_mtype=False): + """Check and coerce X/y for fit/transform functions. + + Parameters + ---------- + y : pd.DataFrame, pd.Series or np.ndarray + return_to_mtype : bool + whether to return the mtype of y output + + Returns + ------- + y_inner : object of sktime compatible time series type + can be Series, Panel, Hierarchical + y_metadata : dict + metadata of y, returned by check_is_scitype + y_mtype : str, only returned if return_to_mtype=True + mtype of y_inner, after convert + """ + _check_y = BaseClassifier._check_y + return _check_y(self, y, return_to_mtype=return_to_mtype) - def _check_classifier_input( - self, X, y=None, enforce_min_instances=1, return_metadata=True - ): + def _check_input(self, X, y=None, enforce_min_instances=1, return_metadata=True): """Check whether input X and y are valid formats with minimum data. Raises a ValueError if the input is not valid. @@ -645,10 +674,8 @@ def _check_classifier_input( ValueError If y or X is invalid input data type, or there is not enough data """ - _check_classifier_input = BaseClassifier._check_classifier_input - return _check_classifier_input( - self, X, y, enforce_min_instances, return_metadata - ) + _check_input = BaseClassifier._check_input + return _check_input(self, X, y, enforce_min_instances, return_metadata) def _internal_convert(self, X, y=None): """Convert X and y if necessary as a user convenience. diff --git a/sktime/classification/ensemble/_bagging.py b/sktime/classification/ensemble/_bagging.py index 621ccbe6492..04a39d7c0fe 100644 --- a/sktime/classification/ensemble/_bagging.py +++ b/sktime/classification/ensemble/_bagging.py @@ -20,14 +20,15 @@ class BaggingClassifier(BaseClassifier): On ``predict_proba``, the mean average of probabilistic predictions is returned. For a deterministic classifier, this results in majority vote for ``predict``. - The estimator allows to choose sample sizes fir instances, variables, + The estimator allows to choose sample sizes for instances, variables, and whether sampling is with or without replacement. Direct generalization of ``sklearn``'s ``BaggingClassifier`` to the time series classification task. - Note: if n_features=1, BaggingClassifier turns a univariate classifier into - a multivariate classifier (as slices seen by ``estimator`` are all univariate). + Note: if ``n_features=1``, ``BaggingClassifier`` turns a univariate classifier into + a multivariate classifier, because slices seen by ``estimator`` are all univariate. + This can be used to give a univariate classifier multivariate capabilities. Parameters ---------- @@ -77,6 +78,11 @@ class BaggingClassifier(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": ["fkiraly"], + # estimator type + # -------------- "capability:multivariate": True, "capability:missing_values": True, "capability:predict_proba": True, diff --git a/sktime/classification/ensemble/_ctsf.py b/sktime/classification/ensemble/_ctsf.py index 325f88a5bb0..773507f3b3f 100644 --- a/sktime/classification/ensemble/_ctsf.py +++ b/sktime/classification/ensemble/_ctsf.py @@ -17,8 +17,8 @@ from sklearn.utils import compute_sample_weight from sklearn.utils.multiclass import check_classification_targets +from sktime.base._panel.forest._composable import BaseTimeSeriesForest from sktime.classification.base import BaseClassifier -from sktime.series_as_features.base.estimators._ensemble import BaseTimeSeriesForest from sktime.transformations.panel.summarize import RandomIntervalFeatureExtractor from sktime.utils.slope_and_trend import _slope from sktime.utils.validation.panel import check_X, check_X_y @@ -174,6 +174,12 @@ class labels (multi-output problem). """ _tags = { + # packaging info + # -------------- + "authors": ["mloning", "AyushmaanSeth"], + "maintainers": ["AyushmaanSeth"], + # estimator type + # -------------- "X_inner_mtype": "nested_univ", # nested pd.DataFrame } diff --git a/sktime/classification/ensemble/_weighted.py b/sktime/classification/ensemble/_weighted.py index 89d5d321439..0a658449d86 100644 --- a/sktime/classification/ensemble/_weighted.py +++ b/sktime/classification/ensemble/_weighted.py @@ -85,6 +85,11 @@ class WeightedEnsembleClassifier(_HeterogenousMetaEstimator, BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": "fkiraly", + # estimator type + # -------------- "capability:multivariate": True, "capability:missing_values": True, "capability:predict_proba": True, diff --git a/sktime/classification/feature_based/_catch22_classifier.py b/sktime/classification/feature_based/_catch22_classifier.py index 0aed52be99c..7814c0475db 100644 --- a/sktime/classification/feature_based/_catch22_classifier.py +++ b/sktime/classification/feature_based/_catch22_classifier.py @@ -81,11 +81,17 @@ class Catch22Classifier(_DelegatedClassifier): """ _tags = { + # packaging info + # -------------- + "authors": ["MatthewMiddlehurst", "RavenRudi", "fkiraly"], + "maintainers": ["RavenRudi"], + "python_dependencies": "numba", + # estimator type + # -------------- "capability:multivariate": True, "capability:multithreading": True, "capability:predict_proba": True, "classifier_type": "feature", - "python_dependencies": "numba", } def __init__( diff --git a/sktime/classification/feature_based/_fresh_prince.py b/sktime/classification/feature_based/_fresh_prince.py index 4f34c1aaf8c..719e37866ac 100644 --- a/sktime/classification/feature_based/_fresh_prince.py +++ b/sktime/classification/feature_based/_fresh_prince.py @@ -60,13 +60,18 @@ class FreshPRINCE(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": ["MatthewMiddlehurst"], + "python_version": "<3.10", + "python_dependencies": "tsfresh", + # estimator type + # -------------- "capability:multivariate": True, "capability:multithreading": True, "capability:train_estimate": True, "capability:predict_proba": True, "classifier_type": "feature", - "python_version": "<3.10", - "python_dependencies": "tsfresh", } def __init__( diff --git a/sktime/classification/feature_based/_matrix_profile_classifier.py b/sktime/classification/feature_based/_matrix_profile_classifier.py index 448720cd470..8180ddd05ee 100644 --- a/sktime/classification/feature_based/_matrix_profile_classifier.py +++ b/sktime/classification/feature_based/_matrix_profile_classifier.py @@ -65,12 +65,17 @@ class MatrixProfileClassifier(BaseClassifier): """ _tags = { - "capability:multithreading": True, - "capability:predict_proba": True, - "classifier_type": "distance", + # packaging info + # -------------- + "authors": ["MatthewMiddlehurst"], # sklearn 1.3.0 has a bug which causes predict_proba to fail # see scikit-learn#26768 and sktime#4778 "python_dependencies": "scikit-learn!=1.3.0", + # estimator type + # -------------- + "capability:multithreading": True, + "capability:predict_proba": True, + "classifier_type": "distance", } def __init__( diff --git a/sktime/classification/feature_based/_random_interval_classifier.py b/sktime/classification/feature_based/_random_interval_classifier.py index b10afc80703..278b0a68659 100644 --- a/sktime/classification/feature_based/_random_interval_classifier.py +++ b/sktime/classification/feature_based/_random_interval_classifier.py @@ -52,6 +52,11 @@ class RandomIntervalClassifier(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": ["MatthewMiddlehurst"], + # estimator type + # -------------- "capability:multivariate": True, "capability:multithreading": True, "capability:predict_proba": True, diff --git a/sktime/classification/feature_based/_signature_classifier.py b/sktime/classification/feature_based/_signature_classifier.py index 5ceac9a0a18..56b7b1320db 100644 --- a/sktime/classification/feature_based/_signature_classifier.py +++ b/sktime/classification/feature_based/_signature_classifier.py @@ -90,11 +90,17 @@ class SignatureClassifier(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": "jambo6", + "maintainers": "jambo6", + "python_dependencies": "esig", + "python_version": "<3.10", + # estimator type + # -------------- "capability:multivariate": True, "capability:predict_proba": True, "classifier_type": "feature", - "python_dependencies": "esig", - "python_version": "<3.10", } def __init__( diff --git a/sktime/classification/feature_based/_summary_classifier.py b/sktime/classification/feature_based/_summary_classifier.py index fe7e92a1d6e..992fd38eb63 100644 --- a/sktime/classification/feature_based/_summary_classifier.py +++ b/sktime/classification/feature_based/_summary_classifier.py @@ -64,6 +64,11 @@ class SummaryClassifier(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": ["MatthewMiddlehurst"], + # estimator type + # -------------- "capability:multivariate": True, "capability:multithreading": True, "capability:predict_proba": True, diff --git a/sktime/classification/feature_based/_tsfresh_classifier.py b/sktime/classification/feature_based/_tsfresh_classifier.py index 50216d7bd2c..d648d9a3826 100644 --- a/sktime/classification/feature_based/_tsfresh_classifier.py +++ b/sktime/classification/feature_based/_tsfresh_classifier.py @@ -65,12 +65,17 @@ class TSFreshClassifier(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": ["MatthewMiddlehurst"], + "python_version": "<3.10", + "python_dependencies": "tsfresh", + # estimator type + # -------------- "capability:multivariate": True, "capability:multithreading": True, "capability:predict_proba": True, "classifier_type": "feature", - "python_version": "<3.10", - "python_dependencies": "tsfresh", } def __init__( @@ -149,6 +154,7 @@ def _fit(self, X, y): self._estimator.n_jobs = self._threads_to_use X_t = self._transformer.fit_transform(X, y) + self._Xt_colnames = X_t.columns if X_t.shape[1] == 0: warn( @@ -182,7 +188,9 @@ def _predict(self, X) -> np.ndarray: if self._return_majority_class: return np.full(X.shape[0], self.classes_[self._majority_class]) - return self._estimator.predict(self._transformer.transform(X)) + X_t = self._transformer.transform(X) + X_t = X_t.reindex(self._Xt_colnames, axis=1, fill_value=0) + return self._estimator.predict(X_t) def _predict_proba(self, X) -> np.ndarray: """Predict class probabilities for n instances in X. @@ -207,7 +215,9 @@ def _predict_proba(self, X) -> np.ndarray: return self._estimator.predict_proba(self._transformer.transform(X)) else: dists = np.zeros((X.shape[0], self.n_classes_)) - preds = self._estimator.predict(self._transformer.transform(X)) + X_t = self._transformer.transform(X) + X_t = X_t.reindex(self._Xt_colnames, axis=1, fill_value=0) + preds = self._estimator.predict(X_t) for i in range(0, X.shape[0]): dists[i, self._class_dictionary[preds[i]]] = 1 return dists diff --git a/sktime/classification/hybrid/_hivecote_v1.py b/sktime/classification/hybrid/_hivecote_v1.py index 62ef0e02c4d..2e3d8d01967 100644 --- a/sktime/classification/hybrid/_hivecote_v1.py +++ b/sktime/classification/hybrid/_hivecote_v1.py @@ -94,10 +94,15 @@ class HIVECOTEV1(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": "MatthewMiddlehurst", + "python_dependencies": "numba", + # estimator type + # -------------- "capability:multithreading": True, "capability:predict_proba": True, "classifier_type": "hybrid", - "python_dependencies": "numba", } def __init__( diff --git a/sktime/classification/hybrid/_hivecote_v2.py b/sktime/classification/hybrid/_hivecote_v2.py index 9ac2e493575..4f96717fe72 100644 --- a/sktime/classification/hybrid/_hivecote_v2.py +++ b/sktime/classification/hybrid/_hivecote_v2.py @@ -90,12 +90,17 @@ class HIVECOTEV2(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": "MatthewMiddlehurst", + "python_dependencies": "numba", + # estimator type + # -------------- "capability:multivariate": True, "capability:contractable": True, "capability:multithreading": True, "capability:predict_proba": True, "classifier_type": "hybrid", - "python_dependencies": "numba", } def __init__( diff --git a/sktime/classification/interval_based/_cif.py b/sktime/classification/interval_based/_cif.py index 53f7c59b402..956e448832b 100644 --- a/sktime/classification/interval_based/_cif.py +++ b/sktime/classification/interval_based/_cif.py @@ -117,11 +117,16 @@ class CanonicalIntervalForest(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": "MatthewMiddlehurst", + "python_dependencies": "numba", + # estimator type + # -------------- "capability:multivariate": True, "capability:multithreading": True, "capability:predict_proba": True, "classifier_type": "interval", - "python_dependencies": "numba", } def __init__( diff --git a/sktime/classification/interval_based/_drcif.py b/sktime/classification/interval_based/_drcif.py index 1e39cd14720..b6afdd16184 100644 --- a/sktime/classification/interval_based/_drcif.py +++ b/sktime/classification/interval_based/_drcif.py @@ -141,13 +141,18 @@ class DrCIF(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": "MatthewMiddlehurst", + "python_dependencies": "numba", + # estimator type + # -------------- "capability:multivariate": True, "capability:train_estimate": True, "capability:contractable": True, "capability:multithreading": True, "capability:predict_proba": True, "classifier_type": "interval", - "python_dependencies": "numba", } def __init__( diff --git a/sktime/classification/interval_based/_rise.py b/sktime/classification/interval_based/_rise.py index 197dd986401..6eb3891eaed 100644 --- a/sktime/classification/interval_based/_rise.py +++ b/sktime/classification/interval_based/_rise.py @@ -177,10 +177,15 @@ class RandomIntervalSpectralEnsemble(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": "TonyBagnall", + "python_dependencies": "numba", + # estimator type + # -------------- "capability:multithreading": True, "capability:predict_proba": True, "classifier_type": "interval", - "python_dependencies": "numba", } def __init__( diff --git a/sktime/classification/interval_based/_stsf.py b/sktime/classification/interval_based/_stsf.py index f2e08709ce6..406511ea57c 100644 --- a/sktime/classification/interval_based/_stsf.py +++ b/sktime/classification/interval_based/_stsf.py @@ -86,6 +86,11 @@ class SupervisedTimeSeriesForest(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": "MatthewMiddlehurst", + # estimator type + # -------------- "capability:multithreading": True, "capability:predict_proba": True, "classifier_type": "interval", @@ -205,7 +210,7 @@ def _predict_proba(self, X) -> np.ndarray: Returns ------- - output : nd.array of shape = (n_instances, n_classes) + output : np.ndarray of shape = (n_instances, n_classes) Predicted probabilities """ X = X.squeeze(1) diff --git a/sktime/classification/interval_based/_tsf.py b/sktime/classification/interval_based/_tsf.py index b5a474a5005..d8706c30331 100644 --- a/sktime/classification/interval_based/_tsf.py +++ b/sktime/classification/interval_based/_tsf.py @@ -6,16 +6,16 @@ __author__ = ["kkoziara", "luiszugasti", "kanand77"] __all__ = ["TimeSeriesForestClassifier"] +from typing import Optional + import numpy as np +import pandas as pd from joblib import Parallel, delayed from sklearn.ensemble._forest import ForestClassifier from sklearn.tree import DecisionTreeClassifier +from sktime.base._panel.forest._tsf import BaseTimeSeriesForest, _transform from sktime.classification.base import BaseClassifier -from sktime.series_as_features.base.estimators.interval_based import ( - BaseTimeSeriesForest, -) -from sktime.series_as_features.base.estimators.interval_based._tsf import _transform class TimeSeriesForestClassifier( @@ -26,19 +26,30 @@ class TimeSeriesForestClassifier( A time series forest is an ensemble of decision trees built on random intervals. Overview: Input n series length m. For each tree - - sample sqrt(m) intervals, - - find mean, std and slope for each interval, concatenate to form new - data set, - - build decision tree on new data set. + + - sample sqrt(m) intervals, + - find mean, std and slope for each interval, concatenate to form new + data set, if inner series length is set, then intervals are sampled + within bins of length inner_series_length. + - build decision tree on new data set. + Ensemble the trees with averaged probability estimates. This implementation deviates from the original in minor ways. It samples intervals with replacement and does not use the splitting criteria tiny refinement described in [1]. - This is an intentionally stripped down, non - configurable version for use as a hive-cote component. For a configurable - tree based ensemble, see sktime.classifiers.ensemble.TimeSeriesForestClassifier + This classifier is intentionally written with low configurability, + for performace reasons. + + * for a more configurable tree based ensemble, + use ``sktime.classication.ensemble.ComposableTimeSeriesForestClassifier``, + which also allows switching the base estimator. + * to build a a time series forest with configurable ensembling, base estimator, + and/or feature extraction, fully from composable blocks, + combine ``sktime.classication.ensemble.BaggingClassifier`` with + any classifier pipeline, e.g., pipelining any ``sklearn`` classifier + with any time series feature extraction, e.g., ``Summarizer`` Parameters ---------- @@ -49,6 +60,10 @@ class TimeSeriesForestClassifier( n_jobs : int, default=1 The number of jobs to run in parallel for both `fit` and `predict`. ``-1`` means using all processors. + inner_series_length: int, default=None + The maximum length of unique segments within X from which we extract + intervals is determined. This helps prevent the extraction of + intervals that span across distinct inner series. random_state : int or None, default=None Seed for random number generation. @@ -58,6 +73,10 @@ class TimeSeriesForestClassifier( The number of classes. classes_ : list The classes labels. + feature_importances_ : pandas Dataframe of shape (series_length, 3) + The feature temporal importances for each feature type (mean, std, slope). + It shows how much each time point of your input dataset, through the + feature types extracted (mean, std, slope), contributed to the predictions. Notes ----- @@ -82,22 +101,36 @@ class TimeSeriesForestClassifier( >>> y_pred = clf.predict(X_test) """ + _feature_types = ["mean", "std", "slope"] _base_estimator = DecisionTreeClassifier(criterion="entropy") - _tags = {"capability:predict_proba": True} + _tags = { + # packaging info + # -------------- + "authors": ["kkoziara", "luiszugasti", "kanand77"], + "maintainers": ["kkoziara", "luiszugasti", "kanand77"], + # estimator type + # -------------- + "capability:predict_proba": True, + } def __init__( self, min_interval=3, n_estimators=200, + inner_series_length: Optional[int] = None, n_jobs=1, random_state=None, ): + self.criterion = "gini" # needed for BaseForest in sklearn > 1.4.0, + # because sklearn tag logic looks at this attribute + super().__init__( min_interval=min_interval, n_estimators=n_estimators, n_jobs=n_jobs, random_state=random_state, + inner_series_length=inner_series_length, ) BaseClassifier.__init__(self) @@ -155,7 +188,7 @@ def _predict_proba(self, X) -> np.ndarray: Returns ------- - output : nd.array of shape = (n_instances, n_classes) + output : np.ndarray of shape = (n_instances, n_classes) Predicted probabilities """ X = X.squeeze(1) @@ -203,6 +236,91 @@ def get_test_params(cls, parameter_set="default"): else: return {"n_estimators": 2} + def _extract_feature_importance_by_feature_type_per_tree( + self, tree_feature_importance: np.array, feature_type: str + ) -> np.array: + """Return feature importance. + + Extracting the feature importance corresponding from a feature type + (eg. "mean", "std", "slope") from tree feature importance + + Parameters + ---------- + tree_feature_importance : array-like of shape (n_features_in,) + The feature importance per feature in an estimator, n_intervals x number + of feature types + feature_type : str + feature type belonging to self.feature_types + + Returns + ------- + self : array-like of shape (n_intervals,) + Feature importance corresponding from a feature type. + """ + feature_index = np.argwhere( + [ + feature_type == feature_type_recorded + for feature_type_recorded in self._feature_types + ] + )[0, 0] + + feature_type_feature_importance = tree_feature_importance[ + [ + interval_index + feature_index + for interval_index in range( + 0, len(tree_feature_importance), len(self._feature_types) + ) + ] + ] + + return feature_type_feature_importance + + @property + def feature_importances_(self, **kwargs) -> pd.DataFrame: + """Return the temporal feature importances. + + There is an implementation of temporal feature importance in + BaseTimeSeriesForest in sktime.base._panel.forest._composable + but TimeseriesForestClassifier is inheriting from + sktime.base._panel.forest._tsf.py + which does not have feature_importance_. + + Other feature importance methods implementation: + >>> from sktime.base._panel.forest._composable import BaseTimeSeriesForest + + Returns + ------- + feature_importances_ : pandas Dataframe of shape (series_length, 3) + The feature importances for each feature type (mean, std, slope). + """ + all_importances_per_feature = { + _feature_type: np.zeros(self.series_length) + for _feature_type in self._feature_types + } + + for tree_index in range(self.n_estimators): + tree = self.estimators_[tree_index] + tree_importances = tree.feature_importances_ + tree_intervals = self.intervals_[tree_index] + for feature_type in self._feature_types: + feature_type_importances = ( + self._extract_feature_importance_by_feature_type_per_tree( + tree_importances, feature_type + ) + ) + for interval_index in range(self.n_intervals): + interval = tree_intervals[interval_index] + all_importances_per_feature[feature_type][ + interval[0] : interval[1] + ] += feature_type_importances[interval_index] + + temporal_feature_importance = ( + pd.DataFrame(all_importances_per_feature) + / self.n_estimators + / self.n_intervals + ) + return temporal_feature_importance + def _predict_single_classifier_proba(X, estimator, intervals): """Find probability estimates for each class for all cases in X.""" diff --git a/sktime/classification/interval_based/tests/test_tsf.py b/sktime/classification/interval_based/tests/test_tsf.py new file mode 100644 index 00000000000..8d390f394d9 --- /dev/null +++ b/sktime/classification/interval_based/tests/test_tsf.py @@ -0,0 +1,151 @@ +"""Tests for feature importance in time series forests.""" +from unittest.mock import MagicMock, patch + +import numpy as np +import pandas as pd +import pytest + +from sktime.classification.interval_based import TimeSeriesForestClassifier +from sktime.utils._testing.panel import make_classification_problem + +TESTED_MODULE = "sktime.classification.interval_based._tsf" + +X_train, y_train = make_classification_problem() + + +@patch( + f"{TESTED_MODULE}.TimeSeriesForestClassifier." + f"_extract_feature_importance_by_feature_type_per_tree" +) +@pytest.mark.parametrize("n_estimators", [2, 5]) +def test_time_series_forest_classifier_feature_importance( + extract_feature_importance_of_feature_mock: MagicMock, + n_estimators: int, +): + """Test TimeSeriesForestClassifier feature importance.""" + # Given + given_n_intervals = 2 + given_n_estimators = n_estimators + given_time_series_forest_classifier = TimeSeriesForestClassifier( + n_estimators=given_n_estimators + ) + + given_time_series_forest_classifier.series_length = 20 + given_time_series_forest_classifier.estimators_ = MagicMock() + given_time_series_forest_classifier.intervals_ = np.array( + [[[0, 9], [15, 20]]] * given_n_estimators + ) + given_time_series_forest_classifier.n_intervals = given_n_intervals + + extract_feature_importance_of_feature_mock.return_value = np.ones( + given_time_series_forest_classifier.n_intervals + ) + + # When + fi = given_time_series_forest_classifier.feature_importances_ + + # Then + expected_fi = pd.DataFrame( + { + "mean": [ + 0.5, + 0.5, + 0.5, + 0.5, + 0.5, + 0.5, + 0.5, + 0.5, + 0.5, + 0, + 0, + 0, + 0, + 0, + 0, + 0.5, + 0.5, + 0.5, + 0.5, + 0.5, + ], + "std": [ + 0.5, + 0.5, + 0.5, + 0.5, + 0.5, + 0.5, + 0.5, + 0.5, + 0.5, + 0, + 0, + 0, + 0, + 0, + 0, + 0.5, + 0.5, + 0.5, + 0.5, + 0.5, + ], + "slope": [ + 0.5, + 0.5, + 0.5, + 0.5, + 0.5, + 0.5, + 0.5, + 0.5, + 0.5, + 0, + 0, + 0, + 0, + 0, + 0, + 0.5, + 0.5, + 0.5, + 0.5, + 0.5, + ], + } + ) + pd.testing.assert_frame_equal(expected_fi, fi) + + +@pytest.mark.parametrize("number_of_intervals", [2, 5]) +@pytest.mark.parametrize("feature_type", ["mean", "std", "slope"]) +def test__extract_feature_importance_by_feature_type_per_tree( + number_of_intervals: int, feature_type: str +): + """Test TimeSeriesForestClassifier feature type feature importance.""" + # given + given_number_of_intervals = number_of_intervals + given_tree_feature_importance = np.array([1, 2, 3] * given_number_of_intervals) + given_feature_type = feature_type + given_tsf_classifier = TimeSeriesForestClassifier() + + # When + feature_importance_of_feature_type_from_tree_feature_importance = ( + given_tsf_classifier._extract_feature_importance_by_feature_type_per_tree( + given_tree_feature_importance, given_feature_type + ) + ) + + # Then + expected_feature_importance_of_feature_type_from_tree_feature_importance = { + "mean": np.ones(given_number_of_intervals) * 1, + "std": np.ones(given_number_of_intervals) * 2, + "slope": np.ones(given_number_of_intervals) * 3, + } + np.testing.assert_array_equal( + expected_feature_importance_of_feature_type_from_tree_feature_importance[ + given_feature_type + ], + feature_importance_of_feature_type_from_tree_feature_importance, + ) diff --git a/sktime/classification/kernel_based/_arsenal.py b/sktime/classification/kernel_based/_arsenal.py index 8cb144db01b..3d1d1e6c38f 100644 --- a/sktime/classification/kernel_based/_arsenal.py +++ b/sktime/classification/kernel_based/_arsenal.py @@ -111,13 +111,19 @@ class Arsenal(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": ["MatthewMiddlehurst", "kachayev"], + "maintainers": ["kachayev"], + "python_dependencies": "numba", + # estimator type + # -------------- "capability:multivariate": True, "capability:train_estimate": True, "capability:contractable": True, "capability:multithreading": True, "capability:predict_proba": True, "classifier_type": "kernel", - "python_dependencies": "numba", } def __init__( diff --git a/sktime/classification/kernel_based/_rocket_classifier.py b/sktime/classification/kernel_based/_rocket_classifier.py index fb5a265de82..bc53983317d 100644 --- a/sktime/classification/kernel_based/_rocket_classifier.py +++ b/sktime/classification/kernel_based/_rocket_classifier.py @@ -30,15 +30,17 @@ class RocketClassifier(_DelegatedClassifier): Shorthand for the pipeline `rocket * StandardScaler(with_mean=False) * RidgeClassifierCV(alphas)` where `alphas = np.logspace(-3, 3, 10)`, and - where `rocket` depends on params `rocket_transform`, `use_multivariate` as follows: - - | rocket_transform | `use_multivariate` | rocket (class) | - |------------------|--------------------|-------------------------| - | "rocket" | any | Rocket | - | "minirocket" | "yes | MiniRocketMultivariate | - | "minirocket" | "no" | MiniRocket | - | "multirocket" | "yes" | MultiRocketMultivariate | - | "multirocket" | "no" | MultiRocket | + where `rocket` depends on params `rocket_transform`, `use_multivariate` as follows + + ================ ================== ======================= + rocket_transform `use_multivariate` rocket (class) + ================ ================== ======================= + "rocket" any Rocket + "minirocket" "yes" MiniRocketMultivariate + "minirocket" "no" MiniRocket + "multirocket" "yes" MultiRocketMultivariate + "multirocket" "no" MultiRocket + ================ ================== ======================= classes are sktime classes, other parameters are passed on to the rocket class. @@ -105,10 +107,16 @@ class RocketClassifier(_DelegatedClassifier): """ _tags = { + # packaging info + # -------------- + "authors": ["MatthewMiddlehurst", "victordremov", "fkiraly"], + "maintainers": ["victordremov"], + "python_dependencies": "numba", + # estimator type + # -------------- "capability:multivariate": True, "capability:multithreading": True, "classifier_type": "kernel", - "python_dependencies": "numba", } # valid rocket strings for input validity checking diff --git a/sktime/classification/kernel_based/_svc.py b/sktime/classification/kernel_based/_svc.py index 13ca6268c7b..3b2ff31ed13 100644 --- a/sktime/classification/kernel_based/_svc.py +++ b/sktime/classification/kernel_based/_svc.py @@ -104,6 +104,11 @@ class TimeSeriesSVC(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": "fkiraly", + # estimator type + # -------------- "capability:multivariate": True, "capability:unequal_length": True, "capability:missing_values": True, diff --git a/sktime/classification/kernel_based/tests/test_arsenal.py b/sktime/classification/kernel_based/tests/test_arsenal.py index 2017cf556f1..0281a9a6341 100644 --- a/sktime/classification/kernel_based/tests/test_arsenal.py +++ b/sktime/classification/kernel_based/tests/test_arsenal.py @@ -24,4 +24,4 @@ def test_contracted_arsenal(): ) arsenal.fit(X_train, y_train) - assert len(arsenal.estimators_) > 1 + assert len(arsenal.estimators_) >= 1 diff --git a/sktime/classification/model_selection/__init__.py b/sktime/classification/model_selection/__init__.py new file mode 100644 index 00000000000..72343b457b4 --- /dev/null +++ b/sktime/classification/model_selection/__init__.py @@ -0,0 +1,6 @@ +"""Tuning of time series classifiers.""" +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) + +from sktime.classification.model_selection._tune import TSCGridSearchCV + +__all__ = ["TSCGridSearchCV"] diff --git a/sktime/classification/model_selection/_tune.py b/sktime/classification/model_selection/_tune.py new file mode 100644 index 00000000000..bd723bd064e --- /dev/null +++ b/sktime/classification/model_selection/_tune.py @@ -0,0 +1,447 @@ +"""Tuning for time series classifiers.""" + +__author__ = ["fkiraly", "achieveordie"] + +import numpy as np +from sklearn.model_selection import GridSearchCV + +from sktime.classification._delegate import _DelegatedClassifier + + +class TSCGridSearchCV(_DelegatedClassifier): + """Exhaustive search over specified parameter values for an estimator. + + Adapts sklearn GridSearchCV for sktime time series classifiers + + Optimizes hyper-parameters of `estimators` by exhaustive grid search. + + Parameters + ---------- + estimator : estimator object + This is assumed to implement the scikit-learn estimator interface. + Either estimator needs to provide a ``score`` function, + or ``scoring`` must be passed. + + param_grid : dict or list of dictionaries + Dictionary with parameters names (`str`) as keys and lists of + parameter settings to try as values, or a list of such + dictionaries, in which case the grids spanned by each dictionary + in the list are explored. This enables searching over any sequence + of parameter settings. + + scoring : str, callable, list, tuple or dict, default=None + Strategy to evaluate the performance of the cross-validated model on + the test set. + + If `scoring` represents a single score, one can use: + + - a single string (see :ref:`scoring_parameter`); + - a callable (see :ref:`scoring`) that returns a single value. + + If `scoring` represents multiple scores, one can use: + + - a list or tuple of unique strings; + - a callable returning a dictionary where the keys are the metric + names and the values are the metric scores; + - a dictionary with metric names as keys and callables a values. + + n_jobs : int, default=None + Number of jobs to run in parallel. + ``None`` means 1 unless in a :obj:`joblib.parallel_backend` context. + ``-1`` means using all processors. See :term:`Glossary <n_jobs>` + for more details. + + refit : bool, str, or callable, default=True + Refit an estimator using the best found parameters on the whole + dataset. If ``False``, the ``predict`` and ``predict_probab`` will not work. + + For multiple metric evaluation, this needs to be a `str` denoting the + scorer that would be used to find the best parameters for refitting + the estimator at the end. + + Where there are considerations other than maximum score in + choosing a best estimator, ``refit`` can be set to a function which + returns the selected ``best_index_`` given ``cv_results_``. In that + case, the ``best_estimator_`` and ``best_params_`` will be set + according to the returned ``best_index_`` while the ``best_score_`` + attribute will not be available. + + The refitted estimator is made available at the ``best_estimator_`` + attribute and permits using ``predict`` directly on this + ``GridSearchCV`` instance. + + Also for multiple metric evaluation, the attributes ``best_index_``, + ``best_score_`` and ``best_params_`` will only be available if + ``refit`` is set and all of them will be determined w.r.t this specific + scorer. + + See ``scoring`` parameter to know more about multiple metric + evaluation. + + cv : int, cross-validation generator or an iterable, default=None + Determines the cross-validation splitting strategy. + Possible inputs for cv are: + + - None, to use the default 5-fold cross validation, + - integer, to specify the number of folds in a `(Stratified)KFold`, + - :term:`CV splitter`, + - An iterable yielding (train, test) splits as arrays of indices. + + For integer/None inputs, if the estimator is a classifier and ``y`` is + either binary or multiclass, :class:`StratifiedKFold` is used. In all + other cases, :class:`KFold` is used. These splitters are instantiated + with `shuffle=False` so the splits will be the same across calls. + + Refer :ref:`User Guide <cross_validation>` for the various + cross-validation strategies that can be used here. + + verbose : int + Controls the verbosity: the higher, the more messages. + + - >1 : the computation time for each fold and parameter candidate is + displayed; + - >2 : the score is also displayed; + - >3 : the fold and candidate parameter indexes are also displayed + together with the starting time of the computation. + + pre_dispatch : int, or str, default='2*n_jobs' + Controls the number of jobs that get dispatched during parallel + execution. Reducing this number can be useful to avoid an + explosion of memory consumption when more jobs get dispatched + than CPUs can process. This parameter can be: + + - None, in which case all the jobs are immediately + created and spawned. Use this for lightweight and + fast-running jobs, to avoid delays due to on-demand + spawning of the jobs + + - An int, giving the exact number of total jobs that are + spawned + + - A str, giving an expression as a function of n_jobs, + as in '2*n_jobs' + + error_score : 'raise' or numeric, default=np.nan + Value to assign to the score if an error occurs in estimator fitting. + If set to 'raise', the error is raised. If a numeric value is given, + FitFailedWarning is raised. This parameter does not affect the refit + step, which will always raise the error. + + return_train_score : bool, default=False + If ``False``, the ``cv_results_`` attribute will not include training + scores. + Computing training scores is used to get insights on how different + parameter settings impact the overfitting/underfitting trade-off. + However computing the scores on the training set can be computationally + expensive and is not strictly required to select the parameters that + yield the best generalization performance. + + tune_by_variable : bool, optional (default=False) + Whether to tune parameter by each time series variable separately, + in case of multivariate data passed to the tuning estimator. + Only applies if time series passed are strictly multivariate. + If True, clones of the estimator will be fit to each variable separately, + and are available in fields of the classifiers_ attribute. + Has the same effect as applying ColumnEnsembleClassifier wrapper to self. + If False, the same best parameter is selected for all variables. + + Attributes + ---------- + cv_results_ : dict of numpy (masked) ndarrays + A dict with keys as column headers and values as columns, that can be + imported into a pandas ``DataFrame``. + + For multi-metric evaluation, the scores for all the scorers are + available in the ``cv_results_`` dict at the keys ending with that + scorer's name (``'_<scorer_name>'``) instead of ``'_score'`` shown + above. ('split0_test_precision', 'mean_train_precision' etc.) + + best_estimator_ : estimator + Estimator that was chosen by the search, i.e. estimator + which gave highest score (or smallest loss if specified) + on the left out data. Not available if ``refit=False``. + + See ``refit`` parameter for more information on allowed values. + + best_score_ : float + Mean cross-validated score of the best_estimator + + For multi-metric evaluation, this is present only if ``refit`` is + specified. + + This attribute is not available if ``refit`` is a function. + + best_params_ : dict + Parameter setting that gave the best results on the hold out data. + + For multi-metric evaluation, this is present only if ``refit`` is + specified. + + best_index_ : int + The index (of the ``cv_results_`` arrays) which corresponds to the best + candidate parameter setting. + + The dict at ``search.cv_results_['params'][search.best_index_]`` gives + the parameter setting for the best model, that gives the highest + mean score (``search.best_score_``). + + For multi-metric evaluation, this is present only if ``refit`` is + specified. + + scorer_ : function or a dict + Scorer function used on the held out data to choose the best + parameters for the model. + + For multi-metric evaluation, this attribute holds the validated + ``scoring`` dict which maps the scorer key to the scorer callable. + + n_splits_ : int + The number of cross-validation splits (folds/iterations). + + refit_time_ : float + Seconds used for refitting the best model on the whole dataset. + + This is present only if ``refit`` is not False. + + multimetric_ : bool + Whether or not the scorers compute several metrics. + + classes_ : ndarray of shape (n_classes,) + The classes labels. This is present only if ``refit`` is specified and + the underlying estimator is a classifier. + + n_features_in_ : int + Number of features seen during :term:`fit`. Only defined if + `best_estimator_` is defined (see the documentation for the `refit` + parameter for more details) and that `best_estimator_` exposes + `n_features_in_` when fit. + + feature_names_in_ : ndarray of shape (`n_features_in_`,) + Names of features seen during :term:`fit`. Only defined if + `best_estimator_` is defined (see the documentation for the `refit` + parameter for more details) and that `best_estimator_` exposes + `feature_names_in_` when fit. + + See Also + -------- + ParameterGrid : Generates all the combinations of a hyperparameter grid. + train_test_split : Utility function to split the data into a development + set usable for fitting a GridSearchCV instance and an evaluation set + for its final evaluation. + sklearn.metrics.make_scorer : Make a scorer from a performance metric or + loss function. + """ + + _tags = { + # packaging info + # -------------- + "authors": ["fkiraly", "achieveordie"], + # estimator type + # -------------- + "X_inner_mtype": ["nested_univ", "numpy3D"], + "y_inner_mtype": ["numpy2D"], + "capability:multivariate": True, + "capability:multioutput": True, + "capability:unequal_length": True, + "capability:missing_values": True, + "capability:multithreading": True, + "capability:predict_proba": True, + } + + def __init__( + self, + estimator, + param_grid, + scoring=None, + n_jobs=None, + refit=True, + cv=None, + verbose=0, + pre_dispatch="2*n_jobs", + error_score=np.nan, + return_train_score=False, + tune_by_variable=False, + ): + self.estimator = estimator + self.param_grid = param_grid + self.scoring = scoring + self.n_jobs = n_jobs + self.refit = refit + self.cv = cv + self.verbose = verbose + self.pre_dispatch = pre_dispatch + self.error_score = error_score + self.return_train_score = return_train_score + self.tune_by_variable = tune_by_variable + + super().__init__() + + DELEGATED_PARAMS = [ + "estimator", + "param_grid", + "scoring", + "n_jobs", + "refit", + "cv", + "verbose", + "pre_dispatch", + "error_score", + "return_train_score", + ] + + gcsvargs = {k: getattr(self, k) for k in DELEGATED_PARAMS} + + self.estimator_ = GridSearchCV(**gcsvargs) + + if self.tune_by_variable: + self.set_tags(**{"capability:multioutput": False}) + + def _fit(self, X, y): + """Fit time series classifier to training data. + + private _fit containing the core logic, called from fit + + Writes to self: + Sets fitted model attributes ending in "_". + + Parameters + ---------- + X : guaranteed to be of a type in self.get_tag("X_inner_mtype") + if self.get_tag("X_inner_mtype") = "numpy3D": + 3D np.ndarray of shape = [n_instances, n_dimensions, series_length] + if self.get_tag("X_inner_mtype") = "pd-multiindex:": + pd.DataFrame with columns = variables, + index = pd.MultiIndex with first level = instance indices, + second level = time indices + for list of other mtypes, see datatypes.SCITYPE_REGISTER + for specifications, see examples/AA_datatypes_and_datasets.ipynb + y : guaranteed to be of a type in self.get_tag("y_inner_mtype") + 1D iterable, of shape [n_instances] + or 2D iterable, of shape [n_instances, n_dimensions] + class labels for fitting + if self.get_tag("capaility:multioutput") = False, guaranteed to be 1D + if self.get_tag("capaility:multioutput") = True, guaranteed to be 2D + + Returns + ------- + self : Reference to self. + """ + if y.shape[1] == 1: + y = y.flatten() + + estimator = self._get_delegate() + estimator.fit(X=X, y=y) + + fitted_param_names = [ + "cv_results_", + "best_estimator_", + "best_score_", + "best_params_", + "best_index_", + "scorer_", + "n_splits_", + "refit_time_", + "multimetric_", + "classes_", + ] + + for p in fitted_param_names: + if hasattr(estimator, p): + val = getattr(estimator, p) + setattr(self, p, val) + + return self + + def _predict(self, X): + """Predict labels for sequences in X. + + private _predict containing the core logic, called from predict + + State required: + Requires state to be "fitted". + + Accesses in self: + Fitted model attributes ending in "_" + + Parameters + ---------- + X : guaranteed to be of a type in self.get_tag("X_inner_mtype") + if self.get_tag("X_inner_mtype") = "numpy3D": + 3D np.ndarray of shape = [n_instances, n_dimensions, series_length] + if self.get_tag("X_inner_mtype") = "nested_univ": + pd.DataFrame with each column a dimension, each cell a pd.Series + for list of other mtypes, see datatypes.SCITYPE_REGISTER + for specifications, see examples/AA_datatypes_and_datasets.ipynb + + Returns + ------- + y : 1D np.array of int, of shape [n_instances] - predicted class labels + indices correspond to instance indices in X + """ + estimator = self._get_delegate() + y_pred = estimator.predict(X=X) + if y_pred.ndim == 1: + y_pred = y_pred.reshape(-1, 1) + return y_pred + + # the delegate is an sklearn estimator and it does not have get_fitted_params + # therefore we have to override _get_fitted_params from the delegator, + # which would otherwise call it + def _get_fitted_params(self): + """Get fitted parameters. + + private _get_fitted_params, called from get_fitted_params + + State required: + Requires state to be "fitted". + + Returns + ------- + fitted_params : dict with str keys + fitted parameters, keyed by names of fitted parameter + """ + return {} + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + For classifiers, a "default" set of parameters should be provided for + general testing, and a "results_comparison" set for comparing against + previously recorded results if the general set does not produce suitable + probabilities to compare against. + + Returns + ------- + params : dict or list of dict, default={} + Parameters to create testing instances of the class. + Each dict are parameters to construct an "interesting" test instance, i.e., + `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. + `create_test_instance` uses the first (or only) dictionary in `params`. + """ + from sklearn.gaussian_process.kernels import RBF, DotProduct + from sklearn.metrics import accuracy_score + + from sktime.classification.kernel_based import TimeSeriesSVC + from sktime.dists_kernels import AggrDist + + mean_eucl_tskernel = AggrDist(DotProduct()) + mean_rbf_tskernel = AggrDist(RBF()) + + param1 = { + "estimator": TimeSeriesSVC(kernel=mean_rbf_tskernel, probability=True), + "param_grid": {"C": [0.1, 1]}, + } + + param2 = { + "estimator": TimeSeriesSVC(kernel=mean_eucl_tskernel, probability=True), + "param_grid": {"kernel__transformer": [DotProduct(), RBF()]}, + "scoring": accuracy_score, + } + + return [param1, param2] diff --git a/sktime/classification/shapelet_based/_mrseql.py b/sktime/classification/shapelet_based/_mrseql.py index 4c93c309d56..9fa11e70cdf 100644 --- a/sktime/classification/shapelet_based/_mrseql.py +++ b/sktime/classification/shapelet_based/_mrseql.py @@ -38,9 +38,15 @@ class MrSEQL(_DelegatedClassifier): """ _tags = { - "X_inner_mtype": "nested_univ", + # packaging info + # -------------- + "authors": ["lnthach", "heerme", "fkiraly"], + "maintainers": ["lnthach", "heerme", "fkiraly"], "python_dependencies": "mrseql", "requires_cython": True, + # estimator type + # -------------- + "X_inner_mtype": "nested_univ", } def __init__( diff --git a/sktime/classification/shapelet_based/_mrsqm.py b/sktime/classification/shapelet_based/_mrsqm.py index e9b8f17f722..038a4aaef2d 100644 --- a/sktime/classification/shapelet_based/_mrsqm.py +++ b/sktime/classification/shapelet_based/_mrsqm.py @@ -30,8 +30,6 @@ class MrSQM(_DelegatedClassifier): number of representations produced by sax transformation. nsfa : int, default=0 number of representations produced by sfa transformation. - WARNING: setting this to 1 or larger will break estimator persistence (save), - known bug, see https://github.com/mlgig/mrsqm/issues/7 custom_config : dict, default=None customized parameters for the symbolic transformation. random_state : int, default=None. @@ -50,9 +48,15 @@ class MrSQM(_DelegatedClassifier): """ _tags = { - "X_inner_mtype": "nested_univ", + # packaging info + # -------------- + "authors": ["lnthach", "heerme", "fkiraly"], + "maintainers": ["lnthach", "heerme", "fkiraly"], "python_dependencies": "mrsqm", "requires_cython": True, + # estimator type + # -------------- + "X_inner_mtype": "nested_univ", } def __init__( @@ -124,15 +128,12 @@ def get_test_params(cls, parameter_set="default"): """ params1 = {} - # known problem: nsfa > 0 causes estimator to be non-pickleable - # see https://github.com/mlgig/mrsqm/issues/7 - # fix this problem once the pickling issue is resolved params2 = { "strat": "SR", "features_per_rep": 200, "selection_per_rep": 1000, "nsax": 2, - "nsfa": 0, + "nsfa": 1, "sfa_norm": False, } diff --git a/sktime/classification/shapelet_based/_stc.py b/sktime/classification/shapelet_based/_stc.py index c1bfa8a9007..af6b3306a8a 100644 --- a/sktime/classification/shapelet_based/_stc.py +++ b/sktime/classification/shapelet_based/_stc.py @@ -127,13 +127,18 @@ class ShapeletTransformClassifier(BaseClassifier): """ _tags = { + # packaging info + # -------------- + "authors": ["TonyBagnall", "MatthewMiddlehurst"], + "python_dependencies": "numba", + # estimator type + # -------------- "capability:multivariate": True, "capability:train_estimate": True, "capability:contractable": True, "capability:multithreading": True, "capability:predict_proba": True, "classifier_type": "shapelet", - "python_dependencies": "numba", } def __init__( diff --git a/sktime/classification/tests/_classification_test_reproduction.py b/sktime/classification/tests/_classification_test_reproduction.py index a552b7df614..be3bb3e64b4 100644 --- a/sktime/classification/tests/_classification_test_reproduction.py +++ b/sktime/classification/tests/_classification_test_reproduction.py @@ -14,10 +14,7 @@ ProximityForest, ShapeDTW, ) -from sktime.classification.early_classification import ( - TEASER, - ProbabilityThresholdEarlyClassifier, -) +from sktime.classification.early_classification import TEASER from sktime.classification.feature_based import ( Catch22Classifier, MatrixProfileClassifier, diff --git a/sktime/classification/tests/test_all_classifiers.py b/sktime/classification/tests/test_all_classifiers.py index d84533eace4..173edc08ac2 100644 --- a/sktime/classification/tests/test_all_classifiers.py +++ b/sktime/classification/tests/test_all_classifiers.py @@ -4,6 +4,7 @@ import numpy as np +import pandas as pd import pytest from sktime.classification.tests._expected_outputs import ( @@ -207,7 +208,30 @@ def test_handles_single_class(self, estimator_instance): X, y = make_classification_problem() y[:] = 42 - error_msg = "single class label" + error_msg = "single label" with pytest.warns(UserWarning, match=error_msg): estimator_instance.fit(X, y) + + def test_multioutput(self, estimator_instance): + """Test multioutput classification for all classifiers. + + All classifiers should follow the same interface, + those that do not genuinely should vectorize/broadcast over y. + """ + n_instances = 20 + X, y = make_classification_problem(n_instances=n_instances) + y_mult = pd.DataFrame({"a": y, "b": y}) + + estimator_instance.fit(X, y_mult) + y_pred = estimator_instance.predict(X) + + assert isinstance(y_pred, pd.DataFrame) + assert y_pred.shape == y_mult.shape + + # the estimator vectorizes iff it does not have the multioutput capability + vectorized = not estimator_instance.get_tag("capability:multioutput") + if vectorized: + assert hasattr(estimator_instance, "classifiers_") + assert isinstance(estimator_instance.classifiers_, pd.DataFrame) + assert estimator_instance.classifiers_.shape == (1, 2) diff --git a/sktime/classification/tests/test_base.py b/sktime/classification/tests/test_base.py index caf5b1b5fbf..33d0409f1e6 100644 --- a/sktime/classification/tests/test_base.py +++ b/sktime/classification/tests/test_base.py @@ -120,8 +120,6 @@ def _predict_proba(self, X): multivariate_message = r"multivariate series" missing_message = r"missing values" unequal_message = r"unequal length series" -incorrect_X_data_structure = r"must be a np.array or a pd.Series" -incorrect_y_data_structure = r"must be 1-dimensional" def test_base_classifier_fit(): @@ -144,8 +142,11 @@ def test_base_classifier_fit(): test_X3 = _create_example_dataframe(cases=cases, dimensions=1, length=length) test_X4 = _create_example_dataframe(cases=cases, dimensions=3, length=length) test_y1 = np.random.randint(0, 2, size=(cases)) + test_y2 = pd.DataFrame({"0": [1] * cases, "1": [0] * cases}) result = dummy.fit(test_X1, test_y1) assert result is dummy + result = dummy.fit(test_X3, test_y2) + assert result is dummy with pytest.raises(ValueError, match=multivariate_message): result = dummy.fit(test_X2, test_y1) assert result is dummy @@ -154,15 +155,6 @@ def test_base_classifier_fit(): with pytest.raises(ValueError, match=multivariate_message): result = dummy.fit(test_X4, test_y1) assert result is dummy - # Raise a specific error if y is in a 2D matrix (1,cases) - test_y2 = np.array([test_y1]) - # What if y is in a 2D matrix (cases,1)? - test_y2 = np.array([test_y1]).transpose() - with pytest.raises(ValueError, match=incorrect_y_data_structure): - result = dummy.fit(test_X1, test_y2) - # Pass a data fram - with pytest.raises(ValueError, match=incorrect_X_data_structure): - result = dummy.fit(test_X1, test_X3) TF = [True, False] @@ -178,36 +170,41 @@ def test_check_capabilities(missing, multivariate, unequal): handle it and that cannot. Obvs could loop, but I think its clearer to just explicitly test; """ + X_metadata = { + "has_nans": missing, + "is_univariate": not multivariate, + "is_equal_length": not unequal, + } handles_none = _DummyClassifier() handles_none_composite = _DummyComposite(_DummyClassifier()) # checks that errors are raised if missing: with pytest.raises(ValueError, match=missing_message): - handles_none._check_capabilities(missing, multivariate, unequal) + handles_none._check_capabilities(X_metadata) if multivariate: with pytest.raises(ValueError, match=multivariate_message): - handles_none._check_capabilities(missing, multivariate, unequal) + handles_none._check_capabilities(X_metadata) if unequal: with pytest.raises(ValueError, match=unequal_message): - handles_none._check_capabilities(missing, multivariate, unequal) + handles_none._check_capabilities(X_metadata) if not missing and not multivariate and not unequal: - handles_none._check_capabilities(missing, multivariate, unequal) + handles_none._check_capabilities(X_metadata) if missing: with pytest.warns(UserWarning, match=missing_message): - handles_none_composite._check_capabilities(missing, multivariate, unequal) + handles_none_composite._check_capabilities(X_metadata) if multivariate: with pytest.warns(UserWarning, match=multivariate_message): - handles_none_composite._check_capabilities(missing, multivariate, unequal) + handles_none_composite._check_capabilities(X_metadata) if unequal: with pytest.warns(UserWarning, match=unequal_message): - handles_none_composite._check_capabilities(missing, multivariate, unequal) + handles_none_composite._check_capabilities(X_metadata) if not missing and not multivariate and not unequal: - handles_none_composite._check_capabilities(missing, multivariate, unequal) + handles_none_composite._check_capabilities(X_metadata) handles_all = _DummyHandlesAllInput() - handles_all._check_capabilities(missing, multivariate, unequal) + handles_all._check_capabilities(X_metadata) def test_convert_input(): @@ -228,26 +225,26 @@ def _internal_convert(X, y=None): test_X1 = np.random.uniform(-1, 1, size=(cases, length)) test_X2 = np.random.uniform(-1, 1, size=(cases, 2, length)) tester = _DummyClassifier() - tempX = tester._convert_X(test_X2) + tempX = tester._convert_X(test_X2, "numpy3D") assert tempX.shape[0] == cases and tempX.shape[1] == 2 and tempX.shape[2] == length instance_list = [] for _ in range(0, cases): instance_list.append(pd.Series(np.random.randn(10))) test_X3 = _create_example_dataframe(cases=cases, dimensions=1, length=length) test_X4 = _create_example_dataframe(cases=cases, dimensions=3, length=length) - tempX = tester._convert_X(test_X3) + tempX = tester._convert_X(test_X3, "nested_univ") assert tempX.shape[0] == cases and tempX.shape[1] == 1 and tempX.shape[2] == length - tempX = tester._convert_X(test_X4) + tempX = tester._convert_X(test_X4, "nested_univ") assert tempX.shape[0] == cases and tempX.shape[1] == 3 and tempX.shape[2] == length tester = _DummyConvertPandas() - tempX = tester._convert_X(test_X2) + tempX = tester._convert_X(test_X2, "numpy3D") assert isinstance(tempX, pd.DataFrame) assert tempX.shape[0] == cases assert tempX.shape[1] == 2 test_y1 = np.random.randint(0, 1, size=(cases)) test_y1 = pd.Series(test_y1) tempX, tempY = _internal_convert(test_X1, test_y1) - assert isinstance(tempY, np.ndarray) + assert isinstance(tempY, pd.Series) assert isinstance(tempX, np.ndarray) assert tempX.ndim == 3 @@ -261,9 +258,10 @@ def test__check_classifier_input(): 4. Test incorrect: y as a list 5. Test incorrect: too few cases or too short a series """ + clf = _DummyClassifier() def _check_classifier_input(X, y=None, enforce_min_instances=1): - return BaseClassifier._check_classifier_input(None, X, y, enforce_min_instances) + return clf._check_input(X, y, enforce_min_instances) # 1. Test correct: X: np.array of 2 and 3 dimensions vs y:np.array and np.Series test_X1 = np.random.uniform(-1, 1, size=(5, 10)) @@ -287,9 +285,7 @@ def _check_classifier_input(X, y=None, enforce_min_instances=1): _check_classifier_input(test_X5, test_y1) # 4. Test incorrect data type: y is a List test_y3 = [1, 2, 3, 4, 5] - with pytest.raises( - TypeError, match=r".*X is not of a supported input data " r"type.*" - ): + with pytest.raises(TypeError, match="must be in an sktime compatible format"): _check_classifier_input(test_X1, test_y3) # 5. Test incorrect: too few cases or too short a series with pytest.raises(ValueError, match=r".*Minimum number of cases required*."): @@ -508,3 +504,26 @@ def test_deep_estimator_full(optimizer): # check if components are same assert full_dummy.__dict__ == deserialized_full.__dict__ + + +DUMMY_EST_PARAMETERS_FOO = [None, 10.3, "string", {"key": "value"}, lambda x: x**2] + + +@pytest.mark.skipif( + not _check_soft_dependencies("cloudpickle", severity="none"), + reason="skip test if required soft dependency not available", +) +@pytest.mark.parametrize("foo", DUMMY_EST_PARAMETERS_FOO) +def test_save_estimator_using_cloudpickle(foo): + """Check if serialization works with cloudpickle.""" + from sktime.base._serialize import load + + est = _DummyComposite(foo) + + serialized = est.save(serialization_format="cloudpickle") + loaded_est = load(serialized) + + if callable(foo): + assert est.foo(2) == loaded_est.foo(2) + else: + assert est.foo == loaded_est.foo diff --git a/sktime/classification/tests/test_sklearn_compatibility.py b/sktime/classification/tests/test_sklearn_compatibility.py index 5c417ff6ca2..00f7f15410e 100644 --- a/sktime/classification/tests/test_sklearn_compatibility.py +++ b/sktime/classification/tests/test_sklearn_compatibility.py @@ -82,7 +82,7 @@ ] ), CalibratedClassifierCV( - base_estimator=CanonicalIntervalForest.create_test_instance(), + estimator=CanonicalIntervalForest.create_test_instance(), cv=3, ), ] diff --git a/sktime/clustering/base.py b/sktime/clustering/base.py index b56b228e49f..d2408ef740d 100644 --- a/sktime/clustering/base.py +++ b/sktime/clustering/base.py @@ -36,6 +36,8 @@ class BaseClusterer(BaseEstimator): "capability:unequal_length": False, "capability:missing_values": False, "capability:multithreading": False, + "authors": "sktime developers", # author(s) of the object + "maintainers": "sktime developers", # current maintainer(s) of the object } def __init__(self, n_clusters: int = None): diff --git a/sktime/clustering/compose/_pipeline.py b/sktime/clustering/compose/_pipeline.py index a4be371ad6a..5ed27a3aafa 100644 --- a/sktime/clustering/compose/_pipeline.py +++ b/sktime/clustering/compose/_pipeline.py @@ -92,6 +92,11 @@ class ClustererPipeline(_HeterogenousMetaEstimator, BaseClusterer): """ _tags = { + # packaging info + # -------------- + "authors": "fkiraly", + # estimator type + # -------------- "X_inner_mtype": "pd-multiindex", # which type do _fit/_predict accept "capability:multivariate": False, "capability:unequal_length": False, diff --git a/sktime/clustering/dbscan.py b/sktime/clustering/dbscan.py index 46e824b1961..bd531cc34c1 100644 --- a/sktime/clustering/dbscan.py +++ b/sktime/clustering/dbscan.py @@ -62,6 +62,11 @@ class TimeSeriesDBSCAN(BaseClusterer): """ _tags = { + # packaging info + # -------------- + "authors": "fkiraly", + # estimator type + # -------------- "capability:multivariate": True, "capability:unequal_length": True, "capability:missing_values": True, diff --git a/sktime/clustering/k_means/_k_means.py b/sktime/clustering/k_means/_k_means.py index 48b7ef0046c..ed3770cde0c 100644 --- a/sktime/clustering/k_means/_k_means.py +++ b/sktime/clustering/k_means/_k_means.py @@ -82,7 +82,12 @@ class TimeSeriesKMeans(TimeSeriesLloyds): >>> y_pred = clusterer.predict(X_test) # doctest: +SKIP """ - _tags = {"python_dependencies": "numba"} + _tags = { + # packaging info + # -------------- + "authors": ["chrisholder", "TonyBagnall"], + "python_dependencies": "numba", + } def __init__( self, diff --git a/sktime/clustering/k_means/_k_means_tslearn.py b/sktime/clustering/k_means/_k_means_tslearn.py index 943be254f6e..796d95933a3 100644 --- a/sktime/clustering/k_means/_k_means_tslearn.py +++ b/sktime/clustering/k_means/_k_means_tslearn.py @@ -100,9 +100,14 @@ class TimeSeriesKMeansTslearn(_TslearnAdapter, BaseClusterer): """ _tags = { + # packaging info + # -------------- + "authors": "fkiraly", + "python_dependencies": "tslearn", + # estimator type + # -------------- "capability:multivariate": True, "capability:unequal_length": True, - "python_dependencies": "tslearn", } # defines the name of the attribute containing the tslearn estimator diff --git a/sktime/clustering/k_medoids.py b/sktime/clustering/k_medoids.py index 12b0d0fc3db..777dfa14a37 100755 --- a/sktime/clustering/k_medoids.py +++ b/sktime/clustering/k_medoids.py @@ -76,7 +76,12 @@ class TimeSeriesKMedoids(TimeSeriesLloyds): >>> y_pred = clusterer.predict(X_test) # doctest: +SKIP """ - _tags = {"python_dependencies": "numba"} + _tags = { + # packaging info + # -------------- + "authors": ["chrisholder", "TonyBagnall"], + "python_dependencies": "numba", + } def __init__( self, diff --git a/sktime/clustering/k_shapes.py b/sktime/clustering/k_shapes.py index 8156915220f..6d7d809265c 100755 --- a/sktime/clustering/k_shapes.py +++ b/sktime/clustering/k_shapes.py @@ -50,9 +50,14 @@ class TimeSeriesKShapes(_TslearnAdapter, BaseClusterer): """ _tags = { + # packaging info + # -------------- + "authors": "fkiraly", + "python_dependencies": "tslearn", + # estimator type + # -------------- "capability:multivariate": True, "capability:unequal_length": True, - "python_dependencies": "tslearn", } # defines the name of the attribute containing the tslearn estimator diff --git a/sktime/clustering/kernel_k_means.py b/sktime/clustering/kernel_k_means.py index dca518e56f6..4f0fd58c0c5 100755 --- a/sktime/clustering/kernel_k_means.py +++ b/sktime/clustering/kernel_k_means.py @@ -65,8 +65,13 @@ class TimeSeriesKernelKMeans(_TslearnAdapter, BaseClusterer): """ _tags = { - "capability:multivariate": True, + # packaging info + # -------------- + "authors": "fkiraly", "python_dependencies": "tslearn", + # estimator type + # -------------- + "capability:multivariate": True, } # defines the name of the attribute containing the tslearn estimator diff --git a/sktime/datasets/_data_io.py b/sktime/datasets/_data_io.py index cf954961213..e5e11b8279e 100644 --- a/sktime/datasets/_data_io.py +++ b/sktime/datasets/_data_io.py @@ -241,6 +241,8 @@ def _load_dataset(name, split, return_X_y, return_type=None, extract_path=None): if extract_path is None: # default for first check is sktime/datasets/data check_path = os.path.join(MODULE, "data") + else: + check_path = extract_path def _get_data_from(path): return _load_provided_dataset(name, split, return_X_y, return_type, path) diff --git a/sktime/datasets/_readers_writers/arff.py b/sktime/datasets/_readers_writers/arff.py index c18a0a1c0de..505008ac67f 100644 --- a/sktime/datasets/_readers_writers/arff.py +++ b/sktime/datasets/_readers_writers/arff.py @@ -17,7 +17,7 @@ # ================================================================================================== -# TODO: original author didnt add test for this function +# TODO: original author didn't add test for this function # Refactor the nested loops def load_from_arff_to_dataframe( full_file_path_and_name, @@ -202,7 +202,7 @@ def write_tabular_transformation_to_arff( dirt = f"{str(path)}/{str(problem_name)}-{type(transformation).__name__}/" try: os.makedirs(dirt) - except os.error: + except OSError: pass # raises os.error if path already exists # create arff file in the path file = open( diff --git a/sktime/datasets/_readers_writers/long.py b/sktime/datasets/_readers_writers/long.py index 6f7ae217f8d..3072cbd6493 100644 --- a/sktime/datasets/_readers_writers/long.py +++ b/sktime/datasets/_readers_writers/long.py @@ -8,7 +8,7 @@ from sktime.datatypes._panel._convert import from_long_to_nested -# TODO: original author didnt add test for this function, for research purposes? +# TODO: original author didn't add test for this function, for research purposes? def load_from_long_to_dataframe(full_file_path_and_name, separator=","): """Load data from a long format file into a Pandas DataFrame. diff --git a/sktime/datasets/_readers_writers/tsf.py b/sktime/datasets/_readers_writers/tsf.py index 42fdb6fa817..99b5b448442 100644 --- a/sktime/datasets/_readers_writers/tsf.py +++ b/sktime/datasets/_readers_writers/tsf.py @@ -29,7 +29,7 @@ def _convert_tsf_to_hierarchical( tsf file metadata freq : str, optional pandas compatible time frequency, by default None - if not speciffied it's automatically mapped from the tsf frequency to a pandas + if not specified it's automatically mapped from the tsf frequency to a pandas frequency value_column_name: str, optional The name of the column that contains the values, by default "series_value" diff --git a/sktime/datasets/_readers_writers/tsv.py b/sktime/datasets/_readers_writers/tsv.py index 52d1e58098e..77ea75d86bb 100644 --- a/sktime/datasets/_readers_writers/tsv.py +++ b/sktime/datasets/_readers_writers/tsv.py @@ -6,7 +6,7 @@ import pandas as pd -# TODO: original author didnt add test for this function +# TODO: original author didn't add test for this function def load_from_ucr_tsv_to_dataframe( full_file_path_and_name, return_separate_X_and_y=True ): diff --git a/sktime/datasets/_readers_writers/utils.py b/sktime/datasets/_readers_writers/utils.py index 751985b9f1d..f96055ce6ef 100644 --- a/sktime/datasets/_readers_writers/utils.py +++ b/sktime/datasets/_readers_writers/utils.py @@ -124,7 +124,7 @@ def _write_header( dirt = f"{str(path)}/{str(problem_name)}/" try: os.makedirs(dirt) - except os.error: + except OSError: pass # raises os.error if path already exists # create ts file in the path file = open(f"{dirt}{str(problem_name)}{fold}.ts", "w") @@ -210,7 +210,7 @@ def write_results_to_uea_format( output_path = f"{output_path}/{estimator_name}/Predictions/{dataset_name}/" try: os.makedirs(output_path) - except os.error: + except OSError: pass # raises os.error if path already exists, so just ignore this if split == "TRAIN" or split == "train": diff --git a/sktime/datasets/_single_problem_loaders.py b/sktime/datasets/_single_problem_loaders.py index 8785d650fe2..b49c5844ae4 100644 --- a/sktime/datasets/_single_problem_loaders.py +++ b/sktime/datasets/_single_problem_loaders.py @@ -1213,6 +1213,11 @@ def load_solar( api_version : string or None, default="v4" API version to call. If None then a stored sample of the data is loaded. + Returns + ------- + y : pd.Series + The solar generation time-series, as requested by parameters, see above + References ---------- .. [1] https://www.solar.sheffield.ac.uk/pvlive/ diff --git a/sktime/datasets/tests/test_data_io.py b/sktime/datasets/tests/test_data_io.py index 1ae45305481..9e612626828 100644 --- a/sktime/datasets/tests/test_data_io.py +++ b/sktime/datasets/tests/test_data_io.py @@ -36,7 +36,9 @@ def test_load_provided_dataset(return_X_y, return_type): X = _load_provided_dataset("UnitTest", "TRAIN", return_X_y, return_type) # Check whether object is same mtype or not, via bool - valid, check_msg, _ = check_is_mtype(X, return_type, return_metadata=True) + valid, check_msg, _ = check_is_mtype( + X, return_type, return_metadata=True, msg_return_dict="list" + ) msg = ( "load_basic_motions return has unexpected type on " f"return_X_y = {return_X_y}, return_type = {return_type}. " @@ -60,7 +62,9 @@ def test_load_basic_motions(return_X_y, return_type): X = load_basic_motions("TRAIN", return_X_y, return_type) # Check whether object is same mtype or not, via bool - valid, check_msg, _ = check_is_mtype(X, return_type, return_metadata=True) + valid, check_msg, _ = check_is_mtype( + X, return_type, return_metadata=True, msg_return_dict="list" + ) msg = ( "load_basic_motions return has unexpected type on " f"return_X_y = {return_X_y}, return_type = {return_type}. " @@ -80,6 +84,16 @@ def test_load_UCR_UEA_dataset(): assert X.shape == (42, 1) and y.shape == (42,) +def test_load_UCR_UEA_local(): + """Tests load_UCR_UEA_dataset looks for local file if extract_path is set. + + A FileNotFoundError indicates the function looked for the file and everything up + to that point went fine. + """ + with pytest.raises(FileNotFoundError): + load_UCR_UEA_dataset(name="UnitTest", extract_path=" ") + + _CHECKS = { "uschange": { "columns": ["Income", "Production", "Savings", "Unemployment"], diff --git a/sktime/datasets/tests/test_datadownload.py b/sktime/datasets/tests/test_datadownload.py new file mode 100644 index 00000000000..352244f33c1 --- /dev/null +++ b/sktime/datasets/tests/test_datadownload.py @@ -0,0 +1,82 @@ +"""Test data loaders that download from external sources.""" +from urllib.request import Request, urlopen + +import numpy as np +import pandas as pd +import pytest + +from sktime.datasets import load_forecastingdata, load_solar, load_UCR_UEA_dataset +from sktime.datasets.tsf_dataset_names import tsf_all, tsf_all_datasets + +# test tsf download only on a random uniform subsample of datasets +N_TSF_SUBSAMPLE = 3 +TSF_SUBSAMPLE = np.random.choice(tsf_all_datasets, N_TSF_SUBSAMPLE) + + +@pytest.mark.datadownload +def test_load_solar(): + """Test whether solar dataset can be downloaded.""" + solar = load_solar() + + assert isinstance(solar, pd.Series) + assert len(solar) == 5905 + + +@pytest.mark.xfail(reason="known sporadic failure of unknown cause, see #5460") +@pytest.mark.datadownload +def test_load_UEA(): + """Test loading of a random subset of the UEA data, to check API.""" + from sktime.datasets.tsc_dataset_names import multivariate, univariate + + TOO_LARGE_DATA = ["InsectWingbeat"] + + univariate = list(set(univariate).difference(TOO_LARGE_DATA)) + multivariate = list(set(multivariate).difference(TOO_LARGE_DATA)) + + n_univariate = 3 + n_multivariate = 2 + + univ_names = np.random.choice(univariate, n_univariate) + mult_names = np.random.choice(multivariate, n_multivariate) + + for univ_name in univ_names: + load_UCR_UEA_dataset(univ_name) + + for mult_name in mult_names: + load_UCR_UEA_dataset(mult_name) + + +@pytest.mark.datadownload +def test_load_forecastingdata(): + """Test loading downloaded dataset from forecasting.org.""" + file = "UnitTest" + loaded_datasets, metadata = load_forecastingdata(name=file) + assert len(loaded_datasets) == 1 + assert metadata["frequency"] == "yearly" + assert metadata["forecast_horizon"] == 4 + assert metadata["contain_missing_values"] is False + assert metadata["contain_equal_length"] is False + + +@pytest.mark.xfail(reason="known sporadic failure of unknown cause, see #5462") +@pytest.mark.datadownload +@pytest.mark.parametrize("name", TSF_SUBSAMPLE) +def test_check_link_downloadable(name): + """Test dataset URL from forecasting.org is downloadable and exits.""" + url = f"https://zenodo.org/record/{tsf_all[name]}/files/{name}.zip" + + # Send a GET request to check if the link exists without downloading the file + req = Request(url, method="HEAD") + response = urlopen(req) + + # Check if the response status code is 200 (OK) + assert ( + response.status == 200 + ), f"URL is not valid or does not exist. Error code {response.status}." + + # Check if the response headers indicate that the content is downloadable + content_type = response.headers.get("Content-Type") + content_disposition = response.headers.get("Content-Disposition") + + assert "application/octet-stream" in content_type, "URL is not downloadable." + assert "attachment" in content_disposition, "URL is not downloadable." diff --git a/sktime/datasets/tests/test_readers_writers.py b/sktime/datasets/tests/test_readers_writers.py index 022bc39efb1..bedfe87a5e6 100644 --- a/sktime/datasets/tests/test_readers_writers.py +++ b/sktime/datasets/tests/test_readers_writers.py @@ -1186,7 +1186,7 @@ def test_load_tsf_to_dataframe(input_path, return_type, output_df): assert_frame_equal(df, output_df, check_dtype=False) assert metadata == expected_metadata if return_type != "default_tsf": - assert check_is_mtype(obj=df, mtype=return_type) + assert check_is_mtype(obj=df, mtype=return_type, msg_return_dict="list") @pytest.mark.parametrize("freq", [None, "YS"]) diff --git a/sktime/datasets/tests/test_single_problem_loaders.py b/sktime/datasets/tests/test_single_problem_loaders.py index cf142e3b031..999ee4ffd26 100644 --- a/sktime/datasets/tests/test_single_problem_loaders.py +++ b/sktime/datasets/tests/test_single_problem_loaders.py @@ -1,24 +1,19 @@ -"""Test single problem loaders with varying return types.""" -from urllib.request import Request, urlopen - +"""Test single problem loaders using data shipping with sktime.""" import numpy as np import pandas as pd import pytest -from sktime.datasets import ( # Univariate; Unequal length; Multivariate +from sktime.datasets import ( load_acsf1, load_arrow_head, load_basic_motions, - load_forecastingdata, load_italy_power_demand, load_japanese_vowels, load_osuleaf, load_plaid, load_tecator, - load_UCR_UEA_dataset, load_unit_test, ) -from sktime.datasets.tsf_dataset_names import tsf_all, tsf_all_datasets UNIVARIATE_PROBLEMS = [ load_acsf1, @@ -36,10 +31,6 @@ load_japanese_vowels, ] -# test tsf download only on a random uniform subsample of datasets -N_TSF_SUBSAMPLE = 3 -TSF_SUBSAMPLE = np.random.choice(tsf_all_datasets, N_TSF_SUBSAMPLE) - @pytest.mark.parametrize( "loader", UNIVARIATE_PROBLEMS + MULTIVARIATE_PROBLEMS + UNEQUAL_LENGTH_PROBLEMS @@ -81,60 +72,3 @@ def test_load_numpy2d_multivariate_raises(loader): """Test that multivariate and/or unequal length raise the correct error.""" with pytest.raises(ValueError, match="attempting to load into a numpy2d"): X, y = loader(return_type="numpy2d") - - -@pytest.mark.xfail(reason="known sporadic failure of unknown cause, see #5460") -def test_load_UEA(): - """Test loading of a random subset of the UEA data, to check API.""" - from sktime.datasets.tsc_dataset_names import multivariate, univariate - - TOO_LARGE_DATA = ["InsectWingbeat"] - - univariate = list(set(univariate).difference(TOO_LARGE_DATA)) - multivariate = list(set(multivariate).difference(TOO_LARGE_DATA)) - - n_univariate = 3 - n_multivariate = 2 - - univ_names = np.random.choice(univariate, n_univariate) - mult_names = np.random.choice(multivariate, n_multivariate) - - for univ_name in univ_names: - load_UCR_UEA_dataset(univ_name) - - for mult_name in mult_names: - load_UCR_UEA_dataset(mult_name) - - -def test_load_forecastingdata(): - """Test loading downloaded dataset from forecasting.org.""" - file = "UnitTest" - loaded_datasets, metadata = load_forecastingdata(name=file) - assert len(loaded_datasets) == 1 - assert metadata["frequency"] == "yearly" - assert metadata["forecast_horizon"] == 4 - assert metadata["contain_missing_values"] is False - assert metadata["contain_equal_length"] is False - - -@pytest.mark.xfail(reason="known sporadic failure of unknown cause, see #5462") -@pytest.mark.parametrize("name", TSF_SUBSAMPLE) -def test_check_link_downloadable(name): - """Test dataset URL from forecasting.org is downloadable and exits.""" - url = f"https://zenodo.org/record/{tsf_all[name]}/files/{name}.zip" - - # Send a GET request to check if the link exists without downloading the file - req = Request(url, method="HEAD") - response = urlopen(req) - - # Check if the response status code is 200 (OK) - assert ( - response.status == 200 - ), f"URL is not valid or does not exist. Error code {response.status}." - - # Check if the response headers indicate that the content is downloadable - content_type = response.headers.get("Content-Type") - content_disposition = response.headers.get("Content-Disposition") - - assert "application/octet-stream" in content_type, "URL is not downloadable." - assert "attachment" in content_disposition, "URL is not downloadable." diff --git a/sktime/datatypes/__init__.py b/sktime/datatypes/__init__.py index 1c90739d014..a866eb0ea0b 100644 --- a/sktime/datatypes/__init__.py +++ b/sktime/datatypes/__init__.py @@ -3,6 +3,7 @@ __author__ = ["fkiraly"] from sktime.datatypes._check import ( + check_is_error_msg, check_is_mtype, check_is_scitype, check_raise, @@ -31,6 +32,7 @@ "ALL_TIME_SERIES_MTYPES", "check_is_mtype", "check_is_scitype", + "check_is_error_msg", "check_raise", "convert", "convert_to", diff --git a/sktime/datatypes/_adapter/dask_to_pd.py b/sktime/datatypes/_adapter/dask_to_pd.py index 627428c0b84..7e07fa45873 100644 --- a/sktime/datatypes/_adapter/dask_to_pd.py +++ b/sktime/datatypes/_adapter/dask_to_pd.py @@ -175,6 +175,10 @@ def check_dask_frame( metadata["is_empty"] = len(obj.index) < 1 or len(obj.columns) < 1 if _req("is_univariate", return_metadata): metadata["is_univariate"] = len(obj.columns) == 1 + if _req("n_features", return_metadata): + metadata["n_features"] = len(obj.columns) + if _req("feature_names", return_metadata): + metadata["feature_names"] = obj.columns.to_list() # check that columns are unique if not obj.columns.is_unique: diff --git a/sktime/datatypes/_check.py b/sktime/datatypes/_check.py index 90d9ffb5c44..192b4b57a1c 100644 --- a/sktime/datatypes/_check.py +++ b/sktime/datatypes/_check.py @@ -92,6 +92,7 @@ def check_is_mtype( scitype: str = None, return_metadata=False, var_name="obj", + msg_return_dict="dict", ): """Check object for compliance with mtype specification, return metadata. @@ -107,14 +108,23 @@ def check_is_mtype( if False, returns only "valid" return if True, returns all three return objects if str, list of str, metadata return dict is subset to keys in return_metadata - var_name: str, optional, default="obj" - name of input in error messages + var_name: str, optional, default="obj" + name of input in error messages + msg_return_dict: str, "list" or "dict", optional, default="dict" + whether returned msg, if returned is a str, dict or list + if "list", msg is str if mtype is str, list of str if mtype is list + if "dict", msg is str if mtype is str, dict of str if mtype is list, + if dict, has with mtype as key and error message for mtype as value Returns ------- valid: bool - whether obj is a valid object of mtype/scitype - msg: str or list of str - error messages if object is not valid, otherwise None - str if mtype is str; list of len(mtype) with message per mtype if list - returned only if return_metadata is True or str, list of str + msg: str or list/dict of str - error messages if object is not valid, otherwise None + list or dict type is controlled via msg_return_dict + if str: error message for tested mtype + it list: list of len(mtype) with message per mtype if list, same order as mtype + if dict: dict with mtype as key and error message for mtype as value + returned only if return_metadata is True or str, list of str metadata: dict - metadata about obj if valid, otherwise None returned only if return_metadata is True or str, list of str Keys populated depend on (assumed, otherwise identified) scitype of obj. @@ -153,7 +163,16 @@ def check_is_mtype( # we loop through individual mtypes in mtype and see whether they pass the check # for each check we remember whether it passed and what it returned - msg = [] + + # initialize loop variables + if msg_return_dict is None: + msg_return_dict = "dict" + msg = dict() + elif msg_return_dict == "list": + msg = [] + elif msg_return_dict == "dict": + msg = dict() + found_mtype = [] found_scitype = [] @@ -179,7 +198,10 @@ def check_is_mtype( found_scitype.append(scitype_of_m) final_result = res elif _metadata_requested(return_metadata): - msg.append(res[1]) + if msg_return_dict == "list": + msg.append(res[1]) + else: + msg[m] = res[1] # there are three options on the result of check_is_mtype: # a. two or more mtypes are found - this is unexpected and an error with checks @@ -200,7 +222,10 @@ def check_is_mtype( # c. no mtype is found - then return False and all error messages if requested else: if len(msg) == 1: - msg = msg[0] + if msg_return_dict == "list": + msg = msg[0] + else: + msg = list(msg.values())[0] return _ret(False, msg, None, return_metadata) @@ -237,6 +262,7 @@ def check_raise(obj, mtype: str, scitype: str = None, var_name: str = "input"): scitype=scitype, return_metadata=[], var_name=var_name, + msg_return_dict="list", ) if valid: @@ -301,6 +327,7 @@ def mtype( mtype=m_plus_scitype[0], scitype=m_plus_scitype[1], return_metadata=[], + msg_return_dict="list", ) if valid: mtypes_positive += [m_plus_scitype[0]] @@ -437,6 +464,46 @@ def check_is_scitype( return _ret(False, msg, None, return_metadata) +def check_is_error_msg(msg, var_name="obj", allowed_msg=None, raise_exception=False): + """Format and possibly raise error message from check_is_mtype or check_is_scitype. + + Parameters + ---------- + msg: dict[str, str] + error message from check_is_scitype, or from check_is_mtype with dict return + var_name: str, optional, default="obj" + name of input in error messages + allowed_msg: str, optional, default=None + message component detailing allowed mtypes or scitype combinations + raise_exception: bool or Exception, optional, default=False + whether to raise exception or return error message + if False, returns formatted error message + if True, raises TypeError with formatted error message + if Exception, raises that Exception with formatted error message + + Returns + ------- + str - formatted error message + """ + msg_invalid_input = ( + f"{var_name} must be in an sktime compatible format. {allowed_msg}" + f" See the data format tutorial examples/AA_datatypes_and_datasets.ipynb. " + f"If you think the data is already in an sktime supported input format, " + f"run sktime.datatypes.check_raise(data, mtype) to diagnose the error, " + f"where mtype is the string of the type specification you want. " + f"Error message for checked mtypes, in format [mtype: message], as follows:" + ) + for mtype, err in msg.items(): + msg_invalid_input += f" [{mtype}: {err}] " + + if raise_exception is True: + raise TypeError(msg_invalid_input) + elif raise_exception is False: + return msg_invalid_input + else: + raise raise_exception(msg_invalid_input) + + def scitype(obj, candidate_scitypes=SCITYPE_LIST, exclude_mtypes=AMBIGUOUS_MTYPES): """Infer the scitype of an object. diff --git a/sktime/datatypes/_convert.py b/sktime/datatypes/_convert.py index fcc46c2f7f6..eac9d2fe840 100644 --- a/sktime/datatypes/_convert.py +++ b/sktime/datatypes/_convert.py @@ -301,8 +301,8 @@ def _get_first_mtype_of_same_scitype(from_mtype, to_mtypes, varname="to_mtypes") ] if len(same_scitype_mtypes) == 0: raise TypeError( - f"{varname} contains no mtype compatible with the scitype of obj," - f"which is {scitype}" + f"{varname} contains no mtype compatible with the scitype of obj, " + f"which is {scitype}. Value of {varname} is: {to_mtypes}" ) to_type = same_scitype_mtypes[0] return to_type diff --git a/sktime/datatypes/_examples.py b/sktime/datatypes/_examples.py index 1ea554ede3b..f1555c7e21b 100644 --- a/sktime/datatypes/_examples.py +++ b/sktime/datatypes/_examples.py @@ -97,9 +97,9 @@ def get_examples( fixtures: dict with integer keys, elements being fixture - example for mtype `mtype`, scitype `as_scitype` if return_lossy=True, elements are pairs with fixture and - lossy: bool - whether the example is a lossy representation + lossy: bool - whether the example is a lossy representation if return_metadata=True, elements are triples with fixture, lossy, and - metadata: dict - metadata dict that would be returned by check_is_mtype + metadata: dict - metadata dict that would be returned by check_is_mtype """ # if as_scitype is None, infer from mtype if as_scitype is None: diff --git a/sktime/datatypes/_hierarchical/_check.py b/sktime/datatypes/_hierarchical/_check.py index efe1adb048b..6511f385437 100644 --- a/sktime/datatypes/_hierarchical/_check.py +++ b/sktime/datatypes/_hierarchical/_check.py @@ -36,6 +36,8 @@ "has_nans": bool, True iff the panel contains NaN values "n_instances": int, number of instances in the hierarchical panel "n_panels": int, number of flat panels in the hierarchical panel + "n_features": int, number of variables in series + "feature_names": list of int or object, names of variables in series """ __author__ = ["fkiraly"] diff --git a/sktime/datatypes/_hierarchical/_examples.py b/sktime/datatypes/_hierarchical/_examples.py index 3833a662ce1..18b798b06f7 100644 --- a/sktime/datatypes/_hierarchical/_examples.py +++ b/sktime/datatypes/_hierarchical/_examples.py @@ -114,6 +114,8 @@ "has_nans": False, "n_instances": 6, "n_panels": 2, + "n_features": 2, + "feature_names": ["var_0", "var_1"], } @@ -156,4 +158,6 @@ "has_nans": False, "n_instances": 6, "n_panels": 2, + "n_features": 1, + "feature_names": ["var_0"], } diff --git a/sktime/datatypes/_panel/_check.py b/sktime/datatypes/_panel/_check.py index 8203aadcfc3..b00f811c7d7 100644 --- a/sktime/datatypes/_panel/_check.py +++ b/sktime/datatypes/_panel/_check.py @@ -34,6 +34,8 @@ "is_one_series": bool, True iff there is only one series in the panel "has_nans": bool, True iff the panel contains NaN values "n_instances": int, number of instances in the panel + "n_features": int, number of variables in series + "feature_names": list of int or object, names of variables in series """ __author__ = ["fkiraly", "TonyBagnall"] @@ -124,6 +126,10 @@ def check_dflist_panel(obj, return_metadata=False, var_name="obj"): metadata["is_one_panel"] = True if _req("n_instances", return_metadata): metadata["n_instances"] = n + if _req("n_features", return_metadata): + metadata["n_features"] = len(obj[0].columns) + if _req("feature_names", return_metadata): + metadata["feature_names"] = obj[0].columns.to_list() return _ret(True, None, metadata, return_metadata) @@ -160,6 +166,10 @@ def check_numpy3d_panel(obj, return_metadata=False, var_name="obj"): metadata["n_panels"] = 1 if _req("is_one_panel", return_metadata): metadata["is_one_panel"] = True + if _req("n_features", return_metadata): + metadata["n_features"] = obj.shape[1] + if _req("feature_names", return_metadata): + metadata["feature_names"] = list(range(obj.shape[1])) # check whether there any nans; only if requested if _req("has_nans", return_metadata): @@ -233,7 +243,8 @@ def check_pdmultiindex_panel(obj, return_metadata=False, var_name="obj", panel=T ): msg = ( f"The (time) index of {var_name} must be sorted monotonically " - f"increasing, but found: {index}" + f"increasing. Use {var_name}.sort_index() to sort the index, or " + f"{var_name}.duplicated() to find duplicates." ) return _ret(False, msg, None, return_metadata) @@ -245,6 +256,10 @@ def check_pdmultiindex_panel(obj, return_metadata=False, var_name="obj", panel=T metadata["is_empty"] = len(index) < 1 or len(obj.columns) < 1 if _req("has_nans", return_metadata): metadata["has_nans"] = obj.isna().values.any() + if _req("n_features", return_metadata): + metadata["n_features"] = len(obj.columns) + if _req("feature_names", return_metadata): + metadata["feature_names"] = obj.columns.to_list() # check whether index is equally spaced or if there are any nans # compute only if needed @@ -396,10 +411,10 @@ def is_nested_dataframe(obj, return_metadata=False, var_name="obj"): # Check instance index is unique if not obj.index.is_unique: - duplicates = obj.index[obj.index.duplicated()].unique().to_list() msg = ( f"The instance index of {var_name} must be unique, " - f"but found duplicates: {duplicates}" + f"but found duplicates. Use {var_name}.duplicated() " + f"to find the duplicates." ) return _ret(False, msg, None, return_metadata) @@ -418,6 +433,10 @@ def is_nested_dataframe(obj, return_metadata=False, var_name="obj"): metadata["has_nans"] = _nested_dataframe_has_nans(obj) if _req("is_equal_length", return_metadata): metadata["is_equal_length"] = not _nested_dataframe_has_unequal(obj) + if _req("n_features", return_metadata): + metadata["n_features"] = len(obj.columns) + if _req("feature_names", return_metadata): + metadata["feature_names"] = obj.columns.to_list() # todo: this is temporary override, proper is_empty logic needs to be added if _req("is_empty", return_metadata): @@ -447,6 +466,10 @@ def check_numpyflat_Panel(obj, return_metadata=False, var_name="obj"): metadata["is_empty"] = len(obj) < 1 or obj.shape[1] < 1 if _req("is_univariate", return_metadata): metadata["is_univariate"] = True + if _req("n_features", return_metadata): + metadata["n_features"] = 1 + if _req("feature_names", return_metadata): + metadata["feature_names"] = [0] # np.arrays are considered equally spaced, equal length, by assumption if _req("is_equally_spaced", return_metadata): metadata["is_equally_spaced"] = True diff --git a/sktime/datatypes/_panel/_convert.py b/sktime/datatypes/_panel/_convert.py index f7655c29874..0b3c2165984 100644 --- a/sktime/datatypes/_panel/_convert.py +++ b/sktime/datatypes/_panel/_convert.py @@ -36,6 +36,7 @@ from sktime.datatypes._convert_utils._coerce import _coerce_df_dtypes from sktime.datatypes._convert_utils._convert import _extend_conversions from sktime.datatypes._panel._registry import MTYPE_LIST_PANEL +from sktime.utils.pandas import df_map from sktime.utils.validation._dependencies import _check_soft_dependencies # dictionary indexed by triples of types @@ -71,7 +72,7 @@ def _cell_is_series_or_array(cell): def _nested_cell_mask(X): - return X.applymap(_cell_is_series_or_array) + return df_map(X)(_cell_is_series_or_array) def are_columns_nested(X): @@ -820,7 +821,7 @@ def from_nested_to_multi_index(X, instance_index=None, time_index=None): X_col = X_col.infer_objects() # create the right MultiIndex and assign to X_mi - idx_df = X[[c]].applymap(lambda x: x.index).explode(c) + idx_df = df_map(X[[c]])(lambda x: x.index).explode(c) index = pd.MultiIndex.from_arrays([idx_df.index, idx_df[c].values]) index = index.set_names([instance_index, time_index]) X_col.index = index @@ -886,7 +887,7 @@ def from_nested_to_3d_numpy(X): # If all the columns are nested in structure if nested_col_mask.count(True) == len(nested_col_mask): X_3d = np.stack( - X.applymap(_convert_series_cell_to_numpy) + df_map(X)(_convert_series_cell_to_numpy) .apply(lambda row: np.stack(row), axis=1) .to_numpy() ) diff --git a/sktime/datatypes/_panel/_examples.py b/sktime/datatypes/_panel/_examples.py index e7c1503cc7a..d0b0998e3de 100644 --- a/sktime/datatypes/_panel/_examples.py +++ b/sktime/datatypes/_panel/_examples.py @@ -39,10 +39,10 @@ ) example_dict[("numpy3D", "Panel", 0)] = X -example_dict_lossy[("numpy3D", "Panel", 0)] = False +example_dict_lossy[("numpy3D", "Panel", 0)] = True example_dict[("numpyflat", "Panel", 0)] = None -example_dict_lossy[("numpyflat", "Panel", 0)] = None +example_dict_lossy[("numpyflat", "Panel", 0)] = True cols = [f"var_{i}" for i in range(2)] Xlist = [ @@ -68,7 +68,7 @@ example_dict_lossy[("pd-multiindex", "Panel", 0)] = False cols = [f"var_{i}" for i in range(2)] -X = pd.DataFrame(columns=cols, index=[0, 1, 2]) +X = pd.DataFrame(columns=cols, index=pd.RangeIndex(3)) X["var_0"] = pd.Series( [pd.Series([1, 2, 3]), pd.Series([1, 2, 3]), pd.Series([1, 2, 3])] ) @@ -101,6 +101,8 @@ "is_empty": False, "has_nans": False, "n_instances": 3, + "n_features": 2, + "feature_names": ["var_0", "var_1"], } ### @@ -112,12 +114,12 @@ ) example_dict[("numpy3D", "Panel", 1)] = X -example_dict_lossy[("numpy3D", "Panel", 1)] = False +example_dict_lossy[("numpy3D", "Panel", 1)] = True X = np.array([[4, 5, 6], [4, 55, 6], [42, 5, 6]], dtype=np.int64) example_dict[("numpyflat", "Panel", 1)] = X -example_dict_lossy[("numpyflat", "Panel", 1)] = False +example_dict_lossy[("numpyflat", "Panel", 1)] = True cols = [f"var_{i}" for i in range(1)] Xlist = [ @@ -143,7 +145,7 @@ example_dict_lossy[("pd-multiindex", "Panel", 1)] = False cols = [f"var_{i}" for i in range(1)] -X = pd.DataFrame(columns=cols, index=[0, 1, 2]) +X = pd.DataFrame(columns=cols, index=pd.RangeIndex(3)) X["var_0"] = pd.Series( [pd.Series([4, 5, 6]), pd.Series([4, 55, 6]), pd.Series([42, 5, 6])] ) @@ -173,6 +175,8 @@ "is_empty": False, "has_nans": False, "n_instances": 3, + "n_features": 1, + "feature_names": ["var_0"], } ### @@ -184,12 +188,12 @@ ) example_dict[("numpy3D", "Panel", 2)] = X -example_dict_lossy[("numpy3D", "Panel", 2)] = False +example_dict_lossy[("numpy3D", "Panel", 2)] = True X = np.array([[4, 5, 6]], dtype=np.int64) example_dict[("numpyflat", "Panel", 2)] = X -example_dict_lossy[("numpyflat", "Panel", 2)] = False +example_dict_lossy[("numpyflat", "Panel", 2)] = True cols = [f"var_{i}" for i in range(1)] Xlist = [ @@ -211,7 +215,7 @@ example_dict_lossy[("pd-multiindex", "Panel", 2)] = False cols = [f"var_{i}" for i in range(1)] -X = pd.DataFrame(columns=cols, index=[0]) +X = pd.DataFrame(columns=cols, index=pd.RangeIndex(1)) X["var_0"] = pd.Series([pd.Series([4, 5, 6])]) example_dict[("nested_univ", "Panel", 2)] = X @@ -238,6 +242,8 @@ "is_empty": False, "has_nans": False, "n_instances": 1, + "n_features": 1, + "feature_names": ["var_0"], } ### @@ -266,4 +272,6 @@ "is_empty": False, "has_nans": False, "n_instances": 3, + "n_features": 1, + "feature_names": ["var_0"], } diff --git a/sktime/datatypes/_series/_check.py b/sktime/datatypes/_series/_check.py index 9110c7d5800..fe3a47b6e8e 100644 --- a/sktime/datatypes/_series/_check.py +++ b/sktime/datatypes/_series/_check.py @@ -31,6 +31,8 @@ "is_equally_spaced": bool, True iff series index is equally spaced "is_empty": bool, True iff series has no variables or no instances "has_nans": bool, True iff the series contains NaN values + "n_features": int, number of variables in series + "feature_names": list of int or object, names of variables in series """ __author__ = ["fkiraly"] @@ -67,6 +69,10 @@ def check_pddataframe_series(obj, return_metadata=False, var_name="obj"): metadata["is_empty"] = len(index) < 1 or len(obj.columns) < 1 if _req("is_univariate", return_metadata): metadata["is_univariate"] = len(obj.columns) < 2 + if _req("n_features", return_metadata): + metadata["n_features"] = len(obj.columns) + if _req("feature_names", return_metadata): + metadata["feature_names"] = obj.columns.to_list() # check that columns are unique if not obj.columns.is_unique: @@ -125,6 +131,13 @@ def check_pdseries_series(obj, return_metadata=False, var_name="obj"): metadata["is_empty"] = len(index) < 1 if _req("is_univariate", return_metadata): metadata["is_univariate"] = True + if _req("n_features", return_metadata): + metadata["n_features"] = 1 + if _req("feature_names", return_metadata): + if not hasattr(obj, "name") or obj.name is None: + metadata["feature_names"] = [0] + else: + metadata["feature_names"] = [obj.name] # check that dtype is not object if "object" == obj.dtypes: @@ -178,12 +191,20 @@ def check_numpy_series(obj, return_metadata=False, var_name="obj"): metadata["is_empty"] = len(obj) < 1 or obj.shape[1] < 1 if _req("is_univariate", return_metadata): metadata["is_univariate"] = obj.shape[1] < 2 + if _req("n_features", return_metadata): + metadata["n_features"] = obj.shape[1] + if _req("feature_names", return_metadata): + metadata["feature_names"] = list(range(obj.shape[1])) elif len(obj.shape) == 1: # we now know obj is a 1D np.ndarray if _req("is_empty", return_metadata): metadata["is_empty"] = len(obj) < 1 if _req("is_univariate", return_metadata): metadata["is_univariate"] = True + if _req("n_features", return_metadata): + metadata["n_features"] = 1 + if _req("feature_names", return_metadata): + metadata["feature_names"] = [0] else: msg = f"{var_name} must be 1D or 2D numpy.ndarray, but found {len(obj.shape)}D" return ret(False, msg, None, return_metadata) @@ -271,6 +292,16 @@ def check_xrdataarray_series(obj, return_metadata=False, var_name="obj"): # The second dimension is the set of columns if _req("is_univariate", return_metadata): metadata["is_univariate"] = len(obj.dims) == 1 or len(obj[obj.dims[1]]) < 2 + if len(obj.dims) == 1: + if _req("n_features", return_metadata): + metadata["n_features"] = 1 + if _req("feature_names", return_metadata): + metadata["feature_names"] = [0] + else: + if _req("n_features", return_metadata): + metadata["n_features"] = len(obj[obj.dims[1]]) + if _req("feature_names", return_metadata): + metadata["feature_names"] = obj.indexes[obj.dims[1]].to_list() # check that columns are unique if not len(obj.dims) == len(set(obj.dims)): diff --git a/sktime/datatypes/_series/_examples.py b/sktime/datatypes/_series/_examples.py index 9cb5cd8bfab..f0a042bf100 100644 --- a/sktime/datatypes/_series/_examples.py +++ b/sktime/datatypes/_series/_examples.py @@ -80,6 +80,8 @@ "is_equally_spaced": True, "is_empty": False, "has_nans": False, + "n_features": 1, + "feature_names": ["a"], } ### @@ -121,6 +123,8 @@ "is_equally_spaced": True, "is_empty": False, "has_nans": False, + "n_features": 2, + "feature_names": ["a", "b"], } @@ -165,6 +169,8 @@ "is_equally_spaced": True, "is_empty": False, "has_nans": False, + "n_features": 2, + "feature_names": ["a", "b"], } ### @@ -201,4 +207,6 @@ "is_equally_spaced": True, "is_empty": False, "has_nans": False, + "n_features": 1, + "feature_names": ["a"], } diff --git a/sktime/datatypes/_table/_check.py b/sktime/datatypes/_table/_check.py index 6b25cf3335b..4a1d96d880d 100644 --- a/sktime/datatypes/_table/_check.py +++ b/sktime/datatypes/_table/_check.py @@ -65,11 +65,6 @@ def check_pddataframe_table(obj, return_metadata=False, var_name="obj"): if _req("has_nans", return_metadata): metadata["has_nans"] = obj.isna().values.any() - # check that no dtype is object - if "object" in obj.dtypes.values: - msg = f"{var_name} should not have column of 'object' dtype" - return _ret(False, msg, None, return_metadata) - return _ret(True, None, metadata, return_metadata) @@ -92,11 +87,6 @@ def check_pdseries_table(obj, return_metadata=False, var_name="obj"): if _req("n_instances", return_metadata): metadata["n_instances"] = len(index) - # check that dtype is not object - if "object" == obj.dtypes: - msg = f"{var_name} should not be of 'object' dtype" - return _ret(False, msg, None, return_metadata) - # check whether index is equally spaced or if there are any nans # compute only if needed if _req("has_nans", return_metadata): diff --git a/sktime/datatypes/_utilities.py b/sktime/datatypes/_utilities.py index d0271ca9c87..f588d5b9ad1 100644 --- a/sktime/datatypes/_utilities.py +++ b/sktime/datatypes/_utilities.py @@ -266,9 +266,11 @@ def get_cutoff( if reverse_order: ix = 0 agg = min + agg_str = "min" else: ix = -1 agg = max + agg_str = "max" def sub_idx(idx, ix, return_index=True): """Like sub-setting pd.index, but preserves freq attribute.""" @@ -309,7 +311,7 @@ def sub_idx(idx, ix, return_index=True): .groupby(level=inst_levels, sort=False) .nth(ix) .iloc[:, -1] - .agg(agg) + .agg(agg_str) ) if return_index: cuttoff_idx = ensure_index([cutoff]) diff --git a/sktime/datatypes/_vectorize.py b/sktime/datatypes/_vectorize.py index 5d6d73e3bef..b10b186d16f 100644 --- a/sktime/datatypes/_vectorize.py +++ b/sktime/datatypes/_vectorize.py @@ -61,9 +61,16 @@ class VectorizedDF: SERIES_SCITYPES = ["Series", "Panel", "Hierarchical"] def __init__( - self, X, y=None, iterate_as="Series", is_scitype="Panel", iterate_cols=False + self, + X, + y=None, + iterate_as="Series", + is_scitype="Panel", + iterate_cols=False, + remember_data=True, ): - self.X = X + if remember_data: + self.X = X if is_scitype is None: _, _, metadata = check_is_scitype( @@ -89,9 +96,15 @@ def __init__( self._check_iterate_cols(iterate_cols) self.iterate_cols = iterate_cols + self.remember_data = remember_data + self.converter_store = dict() - self.X_multiindex = self._init_conversion(X) + X_multiindex = self._init_conversion(X) + self.X_mi_columns = X_multiindex.columns + self.X_mi_index = X_multiindex.index + if remember_data: + self.X_multiindex = X_multiindex self.iter_indices = self._init_iter_indices() self.shape = self._iter_shape() @@ -148,14 +161,14 @@ def _init_iter_indices(self): iterate_as = self.iterate_as is_scitype = self.is_scitype iterate_cols = self.iterate_cols - X = self.X_multiindex + X_ix = self.X_mi_index if iterate_as == is_scitype: row_ix = None elif iterate_as == "Series": - row_ix = X.index.droplevel(-1).unique() + row_ix = X_ix.droplevel(-1).unique() elif iterate_as == "Panel": - row_ix = X.index.droplevel([-1, -2]).unique() + row_ix = X_ix.droplevel([-1, -2]).unique() else: raise RuntimeError( f"unexpected value found for attribute self.iterate_as: {iterate_as}" @@ -163,7 +176,7 @@ def _init_iter_indices(self): ) if iterate_cols: - col_ix = X.columns + col_ix = self.X_mi_columns else: col_ix = None @@ -172,7 +185,7 @@ def _init_iter_indices(self): @property def index(self): """Defaults to pandas index of X converted to pandas type.""" - return self.X_multiindex.index + return self.X_mi_index def get_iter_indices(self): """Get indices that are iterated over in vectorization. @@ -257,11 +270,14 @@ def _iter_cols(inst, group_name=None): yield group_name, None, _enforce_index_freq(inst) iter_levels = self._iter_levels(iterate_as) - is_self_iter = len(iter_levels) == self.X_multiindex.index.nlevels + is_self_iter = len(iter_levels) == self.X_mi_index.nlevels if is_self_iter: yield from _iter_cols(self.X_multiindex) else: + if isinstance(iter_levels, (list, tuple)) and len(iter_levels) == 1: + # single level, groupby expects scalar + iter_levels = iter_levels[0] for name, group in self.X_multiindex.groupby(level=iter_levels, sort=False): yield from _iter_cols(group.droplevel(iter_levels), group_name=name) @@ -285,7 +301,7 @@ def _iter_levels(self, iterate_as): iter_levels = 2 elif iterate_as == "Series": iter_levels = 1 - return list(range(self.X_multiindex.index.nlevels - iter_levels)) + return list(range(self.X_mi_index.nlevels - iter_levels)) def _iter_shape(self, iterate_as=None, iterate_cols=None): """Get the number of groups and columns to iterate over. @@ -306,11 +322,11 @@ def _iter_shape(self, iterate_as=None, iterate_cols=None): iterate_cols = self.iterate_cols iter_levels = self._iter_levels(iterate_as) - is_self_iter = len(iter_levels) == self.X_multiindex.index.nlevels + is_self_iter = len(iter_levels) == self.X_mi_index.nlevels return ( 1 if is_self_iter else self.X_multiindex.groupby(level=iter_levels).ngroups, - len(self.X_multiindex.columns) if iterate_cols else 1, + len(self.X_mi_columns) if iterate_cols else 1, ) def as_list(self): @@ -383,7 +399,7 @@ def _force_flat(df_list): row_ix, col_ix = self.get_iter_indices() force_flat = False if row_ix is None and col_ix is None: - X_mi_reconstructed = self.X_multiindex + X_mi_reconstructed = pd.DataFrame(df_list[0]) elif col_ix is None: X_mi_reconstructed = pd.concat(df_list, keys=row_ix, axis=0) elif row_ix is None: @@ -409,7 +425,7 @@ def _force_flat(df_list): X_mi_reconstructed = pd.concat(col_concats, keys=row_ix, axis=0) X_mi_index = X_mi_reconstructed.index - X_orig_row_index = self.X_multiindex.index + X_orig_row_index = self.X_mi_index flatten = col_multiindex == "flat" or (col_multiindex == "none" and force_flat) if flatten and isinstance(X_mi_reconstructed.columns, pd.MultiIndex): @@ -511,6 +527,7 @@ def vectorize_est( - "None": executes loop sequentally, simple list comprehension - "loky", "multiprocessing" and "threading": uses ``joblib.Parallel`` loops + - "joblib": custom and 3rd party ``joblib`` backends, e.g., ``spark`` - "dask": uses ``dask``, requires ``dask`` package in environment - "dask_lazy": same as "dask", but returns delayed object instead diff --git a/sktime/datatypes/tests/test_check.py b/sktime/datatypes/tests/test_check.py index 975fb8e3cc1..85d93be4e2e 100644 --- a/sktime/datatypes/tests/test_check.py +++ b/sktime/datatypes/tests/test_check.py @@ -127,7 +127,9 @@ def test_check_positive(scitype, mtype, fixture_index): # check fixtures that exist against checks that exist, when full metadata is queried if fixture is not None and check_is_defined: - check_result = check_is_mtype(fixture, mtype, scitype, return_metadata=True) + check_result = check_is_mtype( + fixture, mtype, scitype, return_metadata=True, msg_return_dict="list" + ) if not check_result[0]: msg = ( f"check_is_mtype returns False on scitype {scitype}, mtype {mtype} " @@ -138,7 +140,9 @@ def test_check_positive(scitype, mtype, fixture_index): # check fixtures that exist against checks that exist, when no metadata is queried if fixture is not None and check_is_defined: - check_result = check_is_mtype(fixture, mtype, scitype, return_metadata=[]) + check_result = check_is_mtype( + fixture, mtype, scitype, return_metadata=[], msg_return_dict="list" + ) if not check_result[0]: msg = ( f"check_is_mtype returns False on scitype {scitype}, mtype {mtype} " @@ -213,7 +217,7 @@ def test_check_metadata_inference(scitype, mtype, fixture_index): error if check itself raises an error """ # retrieve fixture for checking - fixture, _, expected_metadata = get_examples( + fixture, lossy, expected_metadata = get_examples( mtype=mtype, as_scitype=scitype, return_metadata=True ).get(fixture_index) @@ -226,6 +230,15 @@ def test_check_metadata_inference(scitype, mtype, fixture_index): # is_equal_index is not fully supported yet in inference EXCLUDE_KEYS = ["is_equal_index"] + # metadata keys to ignore if mtype is lossy + EXCLUDE_IF_LOSSY = [ + "feature_names", # lossy mtypes do not have feature names + ] + + # if mtype is in the list, add mtype specific keys to exclude + if lossy: + EXCLUDE_KEYS += EXCLUDE_IF_LOSSY + if metadata_provided: expected_metadata = expected_metadata.copy() subset_keys = set(expected_metadata.keys()).difference(EXCLUDE_KEYS) @@ -233,7 +246,9 @@ def test_check_metadata_inference(scitype, mtype, fixture_index): # check fixtures that exist against checks that exist, full metadata query if fixture is not None and check_is_defined and metadata_provided: - check_result = check_is_mtype(fixture, mtype, scitype, return_metadata=True) + check_result = check_is_mtype( + fixture, mtype, scitype, return_metadata=True, msg_return_dict="list" + ) metadata = check_result[2] # remove mtype & scitype key if exists, since comparison is on scitype level @@ -242,6 +257,11 @@ def test_check_metadata_inference(scitype, mtype, fixture_index): if "scitype" in metadata: del metadata["scitype"] + # remove keys that are not checked + for key in EXCLUDE_KEYS: + if key in metadata: + del metadata[key] + # currently we do not check this field in metadata inference msg = ( @@ -256,7 +276,11 @@ def test_check_metadata_inference(scitype, mtype, fixture_index): if fixture is not None and check_is_defined and metadata_provided: for metadata_key in subset_keys: check_result = check_is_mtype( - fixture, mtype, scitype, return_metadata=[metadata_key] + fixture, + mtype, + scitype, + return_metadata=[metadata_key], + msg_return_dict="list", ) metadata = check_result[2] @@ -317,7 +341,9 @@ def test_check_negative(scitype, mtype): # check fixtures that exist against checks that exist if fixture_wrong_type is not None and check_is_defined: - assert not check_is_mtype(fixture_wrong_type, mtype, scitype), ( + assert not check_is_mtype( + fixture_wrong_type, mtype, scitype, msg_return_dict="list" + ), ( f"check_is_mtype {mtype} returns True " f"on {wrong_mtype} fixture {i}" ) @@ -325,7 +351,11 @@ def test_check_negative(scitype, mtype): # check fixtures that exist against checks that exist if fixture_wrong_type is not None and check_is_defined: result = check_is_mtype( - fixture_wrong_type, mtype, scitype, return_metadata=[] + fixture_wrong_type, + mtype, + scitype, + return_metadata=[], + msg_return_dict="list", )[0] assert not result, ( f"check_is_mtype {mtype} returns True " diff --git a/sktime/datatypes/tests/test_convert.py b/sktime/datatypes/tests/test_convert.py index 5bd25f98dc4..dded33480a1 100644 --- a/sktime/datatypes/tests/test_convert.py +++ b/sktime/datatypes/tests/test_convert.py @@ -5,7 +5,7 @@ from sktime.datatypes import SCITYPE_REGISTER, scitype_to_mtype from sktime.datatypes._convert import _conversions_defined, convert from sktime.datatypes._examples import get_examples -from sktime.utils._testing.deep_equals import deep_equals +from sktime.utils.deep_equals import deep_equals SCITYPES = [sci[0] for sci in SCITYPE_REGISTER] diff --git a/sktime/datatypes/tests/test_convert_to.py b/sktime/datatypes/tests/test_convert_to.py index c6facdddc4b..246277b31de 100644 --- a/sktime/datatypes/tests/test_convert_to.py +++ b/sktime/datatypes/tests/test_convert_to.py @@ -4,7 +4,7 @@ from sktime.datatypes._convert import convert_to from sktime.datatypes._examples import get_examples -from sktime.utils._testing.deep_equals import deep_equals +from sktime.utils.deep_equals import deep_equals # hard-coded scitypes/mtypes to use in test_convert_to # easy to change in case the strings change diff --git a/sktime/datatypes/tests/test_panel_converters.py b/sktime/datatypes/tests/test_panel_converters.py index 2e3e4d66314..f7971c08988 100644 --- a/sktime/datatypes/tests/test_panel_converters.py +++ b/sktime/datatypes/tests/test_panel_converters.py @@ -167,7 +167,7 @@ def test_from_nested_to_multi_index(n_instances, n_columns, n_timepoints): nested, instance_index="case_id", time_index="reading_id" ) - # n_timepoints_max = nested.applymap(_nested_cell_timepoints).sum().max() + # n_timepoints_max = nested.map(_nested_cell_timepoints).sum().max() assert isinstance(mi_df, pd.DataFrame) assert mi_df.shape == (n_instances * n_timepoints, n_columns) diff --git a/sktime/datatypes/tests/test_utils.py b/sktime/datatypes/tests/test_utils.py index 0d7ef954a42..cbccfb5f70a 100644 --- a/sktime/datatypes/tests/test_utils.py +++ b/sktime/datatypes/tests/test_utils.py @@ -280,7 +280,9 @@ def test_get_window_output_type(scitype, mtype, window_length, lag): # retrieve example fixture fixture = get_examples(mtype=mtype, as_scitype=scitype, return_lossy=False)[0] X = get_window(fixture, window_length=window_length, lag=lag) - valid, err, _ = check_is_mtype(X, mtype=mtype, return_metadata=True) + valid, err, _ = check_is_mtype( + X, mtype=mtype, return_metadata=True, msg_return_dict="list" + ) msg = ( f"get_window should return an output of mtype {mtype} for that type of input, " @@ -352,7 +354,9 @@ def test_get_slice_output_type(scitype, mtype): # retrieve example fixture fixture = get_examples(mtype=mtype, as_scitype=scitype, return_lossy=False)[0] X = get_slice(fixture) - valid, err, _ = check_is_mtype(X, mtype=mtype, return_metadata=True) + valid, err, _ = check_is_mtype( + X, mtype=mtype, return_metadata=True, msg_return_dict="list" + ) msg = ( f"get_slice should return an output of mtype {mtype} for that type of input, " diff --git a/sktime/datatypes/tests/test_vectorize.py b/sktime/datatypes/tests/test_vectorize.py index 3f5dfe0c3be..c822e9ac805 100644 --- a/sktime/datatypes/tests/test_vectorize.py +++ b/sktime/datatypes/tests/test_vectorize.py @@ -10,11 +10,15 @@ from sktime.datatypes._check import AMBIGUOUS_MTYPES, check_is_mtype from sktime.datatypes._examples import get_examples from sktime.datatypes._vectorize import VectorizedDF, _enforce_index_freq -from sktime.utils._testing.deep_equals import deep_equals -from sktime.utils.validation._dependencies import _check_soft_dependencies +from sktime.utils.deep_equals import deep_equals +from sktime.utils.pandas import df_map +from sktime.utils.parallel import _get_parallel_test_fixtures SCITYPES = ["Panel", "Hierarchical"] +# list of parallelization backends to test +BACKENDS = _get_parallel_test_fixtures("estimator") + def _get_all_mtypes_for_scitype(scitype): """Return list of all mtypes for scitype. @@ -228,12 +232,20 @@ def test_item_len(scitype, mtype, fixture_index, iterate_as, iterate_cols): true_length = 1 elif iterate_as == "Series": _, _, metadata = check_is_mtype( - fixture, mtype=mtype, scitype=scitype, return_metadata=True + fixture, + mtype=mtype, + scitype=scitype, + return_metadata=True, + msg_return_dict="list", ) true_length = metadata["n_instances"] elif iterate_as == "Panel": _, _, metadata = check_is_mtype( - fixture, mtype=mtype, scitype=scitype, return_metadata=True + fixture, + mtype=mtype, + scitype=scitype, + return_metadata=True, + msg_return_dict="list", ) true_length = metadata["n_panels"] @@ -330,7 +342,10 @@ def test_series_item_mtype(scitype, mtype, fixture_index, iterate_as, iterate_co raise RuntimeError(f"found unexpected iterate_as value: {iterate_as}") X_list_valid = [ - check_is_mtype(X, mtype=correct_mtype, scitype=iterate_as) for X in X_list + check_is_mtype( + X, mtype=correct_mtype, scitype=iterate_as, msg_return_dict="list" + ) + for X in X_list ] assert np.all( @@ -421,7 +436,7 @@ def test_enforce_index_freq(item, freq): assert item.index.freq == freq -@pytest.mark.parametrize("backend", [None, "loky", "threading", "dask"]) +@pytest.mark.parametrize("backend", BACKENDS) @pytest.mark.parametrize("varname_used", [True, False]) def test_vectorize_est( scitype, mtype, fixture_index, iterate_as, iterate_cols, varname_used, backend @@ -448,10 +463,6 @@ def test_vectorize_est( if not _is_valid_iterate_as(scitype, iterate_as): return None - # escape test for dask backend if dask is not installed - if backend == "dask" and not _check_soft_dependencies("dask", severity="none"): - return None - # retrieve fixture for checking fixture = get_examples(mtype=mtype, as_scitype=scitype).get(fixture_index) X_vect = VectorizedDF( @@ -465,8 +476,10 @@ def test_vectorize_est( else: kwargs["y"] = X_vect + kwargs.update(backend) + est_clones = X_vect.vectorize_est(NaiveForecaster(), method="clone") - result = X_vect.vectorize_est(est_clones, method="fit", backend=backend, **kwargs) + result = X_vect.vectorize_est(est_clones, method="fit", **kwargs) def _len(x): if x is None: @@ -481,5 +494,5 @@ def _len(x): n_cols = _len(cols) assert isinstance(result, pd.DataFrame) assert result.shape == (n_rows, n_cols) - is_fcst_frame = result.applymap(lambda x: isinstance(x, NaiveForecaster)) + is_fcst_frame = df_map(result)(lambda x: isinstance(x, NaiveForecaster)) assert is_fcst_frame.all().all() diff --git a/sktime/dists_kernels/algebra.py b/sktime/dists_kernels/algebra.py index de1784734cf..6fc6f92d03b 100644 --- a/sktime/dists_kernels/algebra.py +++ b/sktime/dists_kernels/algebra.py @@ -53,6 +53,11 @@ class CombinedDistance(_HeterogenousMetaEstimator, BasePairwiseTransformerPanel) """ _tags = { + # packaging info + # -------------- + "authors": ["fkiraly"], + # estimator type + # -------------- "X_inner_mtype": SUPPORTED_MTYPES, "capability:missing_values": True, # can estimator handle missing data? "capability:multivariate": True, # can estimator handle multivariate data? diff --git a/sktime/dists_kernels/base/_base.py b/sktime/dists_kernels/base/_base.py index ce582a43f55..47af48e74d5 100644 --- a/sktime/dists_kernels/base/_base.py +++ b/sktime/dists_kernels/base/_base.py @@ -55,6 +55,8 @@ class BasePairwiseTransformer(BaseEstimator): "capability:missing_values": True, # can estimator handle missing data? "capability:multivariate": True, # can estimator handle multivariate data? "pwtrafo_type": "distance", # type of pw. transformer, "kernel" or "distance" + "authors": "sktime developers", # author(s) of the object + "maintainers": "sktime developers", # current maintainer(s) of the object } def __init__(self): @@ -191,6 +193,8 @@ class BasePairwiseTransformerPanel(BaseEstimator): "capability:multivariate": True, # can estimator handle multivariate data? "capability:unequal_length": True, # can dist handle unequal length panels? "pwtrafo_type": "distance", # type of pw. transformer, "kernel" or "distance" + "authors": "sktime developers", # author(s) of the object + "maintainers": "sktime developers", # current maintainer(s) of the object } def __init__(self): @@ -467,7 +471,7 @@ def transform_diag(self, X): diag = np.zeros(len(X_spl)) for i, X_instance in enumerate(X_spl): - diag[i] = self.transform(X=X_instance) + diag[i] = self.transform(X=X_instance)[0, 0] return diag diff --git a/sktime/dists_kernels/base/adapters/_tslearn.py b/sktime/dists_kernels/base/adapters/_tslearn.py index 9cbfa0c6608..e373ee65dfc 100644 --- a/sktime/dists_kernels/base/adapters/_tslearn.py +++ b/sktime/dists_kernels/base/adapters/_tslearn.py @@ -28,6 +28,11 @@ class _TslearnPwTrafoAdapter: """Base adapter mixin for tslearn distances and kernels.""" _tags = { + # packaging info + # -------------- + "python_dependencies": ["tslearn"], + # estimator type + # -------------- "symmetric": False, # is the transformer symmetric, i.e., t(x,y)=t(y,x) always? "X_inner_mtype": "df-list", # which mtype is used internally in _transform? @@ -35,7 +40,6 @@ class _TslearnPwTrafoAdapter: "capability:missing_values": True, # can estimator handle missing data? "capability:multivariate": True, # can estimator handle multivariate data? "pwtrafo_type": "distance", # type of pw. transformer, "kernel" or "distance" - "python_dependencies": ["tslearn"], } # parameters to pass to the inner tslearn estimator, list of str diff --git a/sktime/dists_kernels/compose.py b/sktime/dists_kernels/compose.py index a23a5ba35a6..ca64f62c998 100644 --- a/sktime/dists_kernels/compose.py +++ b/sktime/dists_kernels/compose.py @@ -59,6 +59,7 @@ class PwTrafoPanelPipeline(_HeterogenousMetaEstimator, BasePairwiseTransformerPa """ _tags = { + "authors": "fkiraly", "X_inner_mtype": SUPPORTED_MTYPES, "capability:missing_values": True, # can estimator handle missing data? "capability:multivariate": True, # can estimator handle multivariate data? diff --git a/sktime/dists_kernels/compose_from_align.py b/sktime/dists_kernels/compose_from_align.py index d9a7c2edabd..07790ad97d0 100644 --- a/sktime/dists_kernels/compose_from_align.py +++ b/sktime/dists_kernels/compose_from_align.py @@ -19,6 +19,7 @@ class DistFromAligner(BasePairwiseTransformerPanel): """ _tags = { + "authors": ["fkiraly"], "symmetric": True, # all the distances are symmetric "capability:unequal_length": True, # aligners can usually handle unequal length } diff --git a/sktime/dists_kernels/compose_tab_to_panel.py b/sktime/dists_kernels/compose_tab_to_panel.py index 805f030ce2a..4f2f29c2c1f 100644 --- a/sktime/dists_kernels/compose_tab_to_panel.py +++ b/sktime/dists_kernels/compose_tab_to_panel.py @@ -14,7 +14,7 @@ BasePairwiseTransformer, BasePairwiseTransformerPanel, ) -from sktime.utils._testing.deep_equals import deep_equals +from sktime.utils.deep_equals import deep_equals class AggrDist(BasePairwiseTransformerPanel): @@ -64,6 +64,8 @@ class AggrDist(BasePairwiseTransformerPanel): >>> mean_gaussian_tskernel = AggrDist(RBF()) """ + _tags = {"authors": "fkiraly"} + def __init__( self, transformer, @@ -195,6 +197,7 @@ class FlatDist(BasePairwiseTransformerPanel): """ _tags = { + "authors": "fkiraly", "X_inner_mtype": "numpy3D", # which mtype is used internally in _transform? "capability:unequal_length": False, } diff --git a/sktime/dists_kernels/ctw.py b/sktime/dists_kernels/ctw.py index 532810201d7..1b3e62b7316 100644 --- a/sktime/dists_kernels/ctw.py +++ b/sktime/dists_kernels/ctw.py @@ -50,7 +50,16 @@ class CtwDistTslearn(_TslearnPwTrafoAdapter, BasePairwiseTransformerPanel): human behavior". NIPS 2009. """ - _tags = {"symmetric": True, "pwtrafo_type": "distance"} + _tags = { + # packaging info + # -------------- + "authors": ["fkiraly"], + "python_dependencies": ["tslearn"], + # estimator type + # -------------- + "symmetric": True, + "pwtrafo_type": "distance", + } def __init__( self, diff --git a/sktime/dists_kernels/dist_to_kern.py b/sktime/dists_kernels/dist_to_kern.py index a6a0422f40b..ccdc03c735b 100644 --- a/sktime/dists_kernels/dist_to_kern.py +++ b/sktime/dists_kernels/dist_to_kern.py @@ -44,6 +44,7 @@ class KernelFromDist(BasePairwiseTransformerPanel): """ _tags = { + "authors": "fkiraly", "X_inner_mtype": SUPPORTED_MTYPES, "capability:missing_values": True, # can estimator handle missing data? "capability:multivariate": True, # can estimator handle multivariate data? @@ -175,6 +176,7 @@ class DistFromKernel(BasePairwiseTransformerPanel): """ _tags = { + "authors": "fkiraly", "X_inner_mtype": SUPPORTED_MTYPES, "capability:missing_values": True, # can estimator handle missing data? "capability:multivariate": True, # can estimator handle multivariate data? diff --git a/sktime/dists_kernels/dtw/_dtw_python.py b/sktime/dists_kernels/dtw/_dtw_python.py index adc448fe74b..ed67db4c482 100644 --- a/sktime/dists_kernels/dtw/_dtw_python.py +++ b/sktime/dists_kernels/dtw/_dtw_python.py @@ -38,13 +38,18 @@ class DtwPythonDist(_DelegatedPairwiseTransformerPanel): """ _tags = { + # packaging info + # -------------- + "authors": ["fkiraly"], + "python_dependencies": "dtw-python", + "python_dependencies_alias": {"dtw-python": "dtw"}, + # estimator type + # -------------- "pwtrafo_type": "distance", # type of pw. transformer, "kernel" or "distance" "symmetric": True, # all the distances are symmetric "capability:multivariate": True, # can estimator handle multivariate data? "capability:unequal_length": True, # can dist handle unequal length panels? "X_inner_mtype": "df-list", - "python_dependencies": "dtw-python", - "python_dependencies_alias": {"dtw-python": "dtw"}, } def __init__( diff --git a/sktime/dists_kernels/dtw/_dtw_sktime.py b/sktime/dists_kernels/dtw/_dtw_sktime.py index 67d03860286..4370a43e795 100644 --- a/sktime/dists_kernels/dtw/_dtw_sktime.py +++ b/sktime/dists_kernels/dtw/_dtw_sktime.py @@ -123,9 +123,14 @@ class DtwDist(BasePairwiseTransformerPanel): """ _tags = { + # packaging info + # -------------- + "authors": ["chrisholder", "TonyBagnall", "fkiraly"], + "python_dependencies": "numba", + # estimator type + # -------------- "symmetric": True, # all the distances are symmetric "X_inner_mtype": "numpy3D", - "python_dependencies": "numba", } def __init__( diff --git a/sktime/dists_kernels/dtw/_dtw_tslearn.py b/sktime/dists_kernels/dtw/_dtw_tslearn.py index 229228af11d..b004582d163 100644 --- a/sktime/dists_kernels/dtw/_dtw_tslearn.py +++ b/sktime/dists_kernels/dtw/_dtw_tslearn.py @@ -50,7 +50,16 @@ class DtwDistTslearn(_TslearnPwTrafoAdapter, BasePairwiseTransformerPanel): Signal Processing, vol. 26(1), pp. 43--49, 1978. """ - _tags = {"symmetric": True, "pwtrafo_type": "distance"} + _tags = { + # packaging info + # -------------- + "authors": ["fkiraly"], + "python_dependencies": ["tslearn"], + # estimator type + # -------------- + "symmetric": True, + "pwtrafo_type": "distance", + } def __init__( self, diff --git a/sktime/dists_kernels/dummy.py b/sktime/dists_kernels/dummy.py index 9508987ad7f..8044cf32a50 100644 --- a/sktime/dists_kernels/dummy.py +++ b/sktime/dists_kernels/dummy.py @@ -19,6 +19,7 @@ class ConstantPwTrafoPanel(BasePairwiseTransformerPanel): """ _tags = { + "authors": "fkiraly", "X_inner_mtype": SUPPORTED_MTYPES, "capability:missing_values": True, # can estimator handle missing data? "capability:multivariate": True, # can estimator handle multivariate data? diff --git a/sktime/dists_kernels/edit_dist.py b/sktime/dists_kernels/edit_dist.py index 55d9f5d0bd3..96c489a3154 100644 --- a/sktime/dists_kernels/edit_dist.py +++ b/sktime/dists_kernels/edit_dist.py @@ -115,9 +115,14 @@ class EditDist(BasePairwiseTransformerPanel): """ _tags = { + # packaging info + # -------------- + "authors": ["chrisholder", "TonyBagnall", "fkiraly"], + "python_dependencies": "numba", + # estimator type + # -------------- "symmetric": True, # all the distances are symmetric "X_inner_mtype": "numpy3D", - "python_dependencies": "numba", } ALLOWED_DISTANCE_STR = ["lcss", "edr", "erp", "twe"] diff --git a/sktime/dists_kernels/gak.py b/sktime/dists_kernels/gak.py index 84fcbef753a..75f0f1ee6c6 100644 --- a/sktime/dists_kernels/gak.py +++ b/sktime/dists_kernels/gak.py @@ -34,7 +34,16 @@ class GAKernel(_TslearnPwTrafoAdapter, BasePairwiseTransformerPanel): .. [1] M. Cuturi, "Fast global alignment kernels," ICML 2011. """ - _tags = {"symmetric": True, "pwtrafo_type": "kernel"} + _tags = { + # packaging info + # -------------- + "authors": ["fkiraly"], + "python_dependencies": ["tslearn"], + # estimator type + # -------------- + "symmetric": True, + "pwtrafo_type": "kernel", + } def __init__( self, diff --git a/sktime/dists_kernels/indep.py b/sktime/dists_kernels/indep.py index 5440c4a306f..b1db0648d03 100644 --- a/sktime/dists_kernels/indep.py +++ b/sktime/dists_kernels/indep.py @@ -59,6 +59,11 @@ class IndepDist(BasePairwiseTransformerPanel): """ # noqa: E501 _tags = { + # packaging info + # -------------- + "authors": "fkiraly", + # estimator type + # -------------- "X_inner_mtype": SUPPORTED_MTYPES, "capability:missing_values": True, # can estimator handle missing data? "capability:multivariate": True, # can estimator handle multivariate data? diff --git a/sktime/dists_kernels/lcss.py b/sktime/dists_kernels/lcss.py index a505cbd04a6..cf02f71de8b 100644 --- a/sktime/dists_kernels/lcss.py +++ b/sktime/dists_kernels/lcss.py @@ -44,7 +44,16 @@ class LcssTslearn(_TslearnPwTrafoAdapter, BasePairwiseTransformerPanel): IEEE Computer Society, USA, 673. """ - _tags = {"symmetric": True, "pwtrafo_type": "distance"} + _tags = { + # packaging info + # -------------- + "authors": ["fkiraly"], + "python_dependencies": ["tslearn"], + # estimator type + # -------------- + "symmetric": True, + "pwtrafo_type": "distance", + } _is_cdist = False diff --git a/sktime/dists_kernels/lucky.py b/sktime/dists_kernels/lucky.py index 00ed51605f9..ce6bafa6cab 100644 --- a/sktime/dists_kernels/lucky.py +++ b/sktime/dists_kernels/lucky.py @@ -26,6 +26,11 @@ class LuckyDtwDist(_DelegatedPairwiseTransformerPanel): """ _tags = { + # packaging info + # -------------- + "authors": ["fkiraly", "Kristian A Buza"], + # estimator type + # -------------- "symmetric": True, # is the transformer symmetric, i.e., t(x,y)=t(y,x) always? "capability:missing_values": False, # can estimator handle missing data? "capability:multivariate": True, # can estimator handle multivariate data? diff --git a/sktime/dists_kernels/scipy_dist.py b/sktime/dists_kernels/scipy_dist.py index bece6f361c1..bdda0a6da39 100644 --- a/sktime/dists_kernels/scipy_dist.py +++ b/sktime/dists_kernels/scipy_dist.py @@ -52,6 +52,7 @@ class ScipyDist(BasePairwiseTransformer): """ _tags = { + "authors": "fkiraly", "symmetric": True, # all the distances are symmetric } diff --git a/sktime/dists_kernels/signature_kernel.py b/sktime/dists_kernels/signature_kernel.py index 267f4a3f154..1d0d9962222 100644 --- a/sktime/dists_kernels/signature_kernel.py +++ b/sktime/dists_kernels/signature_kernel.py @@ -903,7 +903,11 @@ class SignatureKernel(BasePairwiseTransformerPanel): Journal of Machine Learning Research. """ - _tags = {"X_inner_mtype": "numpy3D", "pwtrafo_type": "kernel"} + _tags = { + "authors": "fkiraly", + "X_inner_mtype": "numpy3D", + "pwtrafo_type": "kernel", + } def __init__( self, diff --git a/sktime/forecasting/adapters/_hcrystalball.py b/sktime/forecasting/adapters/_hcrystalball.py index 248c28aca16..3bd290b792c 100644 --- a/sktime/forecasting/adapters/_hcrystalball.py +++ b/sktime/forecasting/adapters/_hcrystalball.py @@ -106,10 +106,16 @@ class HCrystalBallAdapter(BaseForecaster): """ _tags = { + # packaging info + # -------------- + "authors": "MichalChromcak", + "maintainers": "MichalChromcak", + "python_dependencies": "hcrystalball", + # estimator type + # -------------- "ignores-exogeneous-X": True, "requires-fh-in-fit": False, "handles-missing-data": False, - "python_dependencies": "hcrystalball", } def __init__(self, model): diff --git a/sktime/forecasting/all/__init__.py b/sktime/forecasting/all/__init__.py index 2d72d78b827..7ac4e1a8e9f 100644 --- a/sktime/forecasting/all/__init__.py +++ b/sktime/forecasting/all/__init__.py @@ -11,13 +11,6 @@ from sktime.datasets import load_airline, load_longley, load_lynx, load_shampoo_sales from sktime.forecasting.base import ForecastingHorizon from sktime.forecasting.model_evaluation import evaluate -from sktime.forecasting.model_selection import ( - CutoffSplitter, - ExpandingWindowSplitter, - SingleWindowSplitter, - SlidingWindowSplitter, - temporal_train_test_split, -) from sktime.performance_metrics.forecasting import ( GeometricMeanRelativeAbsoluteError, GeometricMeanRelativeSquaredError, @@ -58,6 +51,13 @@ relative_loss, ) from sktime.registry import all_estimators +from sktime.split import ( + CutoffSplitter, + ExpandingWindowSplitter, + SingleWindowSplitter, + SlidingWindowSplitter, + temporal_train_test_split, +) from sktime.transformations.series.detrend import Deseasonalizer, Detrender from sktime.utils.plotting import plot_series diff --git a/sktime/forecasting/arch/_statsforecast_arch.py b/sktime/forecasting/arch/_statsforecast_arch.py index 9a19f5bb421..e27ca9de3e2 100644 --- a/sktime/forecasting/arch/_statsforecast_arch.py +++ b/sktime/forecasting/arch/_statsforecast_arch.py @@ -33,6 +33,12 @@ class StatsForecastGARCH(_GeneralisedStatsForecastAdapter): """ _tags = { + # packaging info + # -------------- + "authors": ["eyjo"], + "maintainers": ["eyjo"], + # estimator type + # -------------- "ignores-exogeneous-X": False, "capability:pred_int": True, "capability:pred_int:insample": True, diff --git a/sktime/forecasting/arch/_uarch.py b/sktime/forecasting/arch/_uarch.py index c637902150e..f23700a61d4 100644 --- a/sktime/forecasting/arch/_uarch.py +++ b/sktime/forecasting/arch/_uarch.py @@ -152,12 +152,18 @@ class ARCH(BaseForecaster): """ _tags = { + # packaging info + # -------------- + "authors": "Vasudeva-bit", + "maintainers": "Vasudeva-bit", + "python_dependencies": "arch", + # estimator type + # -------------- "scitype:y": "univariate", "y_inner_mtype": "pd.Series", "X_inner_mtype": "pd.DataFrame", "requires-fh-in-fit": False, "handles-missing-data": False, - "python_dependencies": "arch", "capability:pred_int": True, "ignores-exogeneous-X": True, } @@ -251,6 +257,7 @@ def _fit(self, y, X=None, fh=None): if fh: self._horizon = fh + y_name = y.name self._forecaster = _ARCH( y=y, x=X, @@ -277,6 +284,7 @@ def _fit(self, y, X=None, fh=None): options=self.options, backcast=self.backcast, ) + y.name = y_name return self def _get_arch_result_object(self, fh=None, X=None): @@ -344,7 +352,7 @@ def _predict(self, fh, X=None): y_pred = pd.Series( ArchResultObject.mean.values[-1], index=full_range, - name=str(self._y.name), + name=self._y.name, ) y_pred = y_pred.loc[abs_idx.to_pandas()] y_pred.index = self._horizon.to_absolute_index(self.cutoff) @@ -398,11 +406,15 @@ def _predict_interval(self, fh, X, coverage): upper_int = mean_forecast + (z_critical * std_err) lower_df = pd.DataFrame( lower_int, - columns=[y_col_name + " " + str(alpha) + " " + "lower"], + columns=[ + y_col_name if y_col_name else "0" + " " + str(alpha) + " " + "lower" + ], ) upper_df = pd.DataFrame( upper_int, - columns=[y_col_name + " " + str(alpha) + " " + "upper"], + columns=[ + y_col_name if y_col_name else "0" + " " + str(alpha) + " " + "upper" + ], ) df_list.append(pd.concat((lower_df, upper_df), axis=1)) concat_df = pd.concat(df_list, axis=1) @@ -410,7 +422,7 @@ def _predict_interval(self, fh, X, coverage): OrderedDict.fromkeys( [ col_df - for col in y_col_name + for col in (y_col_name if y_col_name else "0") for col_df in concat_df.columns if col in col_df ] @@ -425,7 +437,7 @@ def _predict_interval(self, fh, X, coverage): final_columns = list( itertools.product( *[ - [y_col_name], + [y_col_name if y_col_name else 0], coverage, df.columns.get_level_values(2).unique(), ] diff --git a/sktime/forecasting/ardl.py b/sktime/forecasting/ardl.py index 3f678d706f8..6950f290cdb 100644 --- a/sktime/forecasting/ardl.py +++ b/sktime/forecasting/ardl.py @@ -193,6 +193,13 @@ class ARDL(_StatsModelsAdapter): """ _tags = { + # packaging info + # -------------- + "authors": "kcc-lion", + "maintainers": "kcc-lion", + "python_dependencies": "statsmodels>=0.13.0", + # estimator type + # -------------- "scitype:y": "univariate", # which y are fine? univariate/multivariate/both "ignores-exogeneous-X": False, # does estimator ignore the exogeneous X? "handles-missing-data": False, # can estimator handle missing data? @@ -202,8 +209,6 @@ class ARDL(_StatsModelsAdapter): "X-y-must-have-same-index": True, # can estimator handle different X/y index? "enforce_index_type": None, # index type that needs to be enforced in X/y "capability:pred_int": False, # does forecaster implement proba forecasts? - "python_version": None, # PEP 440 python version specifier to limit versions - "python_dependencies": "statsmodels>=0.13.0", } def __init__( diff --git a/sktime/forecasting/arima/__init__.py b/sktime/forecasting/arima/__init__.py new file mode 100644 index 00000000000..e248ffb30b4 --- /dev/null +++ b/sktime/forecasting/arima/__init__.py @@ -0,0 +1,10 @@ +"""Time series forecasting with ARIMA models.""" + +__all__ = [ + "AutoARIMA", + "ARIMA", + "StatsModelsARIMA", +] + +from sktime.forecasting.arima._pmdarima import ARIMA, AutoARIMA +from sktime.forecasting.arima._statsmodels import StatsModelsARIMA diff --git a/sktime/forecasting/arima.py b/sktime/forecasting/arima/_pmdarima.py similarity index 97% rename from sktime/forecasting/arima.py rename to sktime/forecasting/arima/_pmdarima.py index bb45f9816ca..9b88479a6c7 100644 --- a/sktime/forecasting/arima.py +++ b/sktime/forecasting/arima/_pmdarima.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -u # copyright: sktime developers, BSD-3-Clause License (see LICENSE file) -"""Implements autoregressive integrated moving average (ARIMA) models.""" +"""Interface to ARIMA and AutoARIMA models from pmdarima package.""" __author__ = ["mloning", "hyang1996", "fkiraly", "ilkersigirci"] __all__ = ["AutoARIMA", "ARIMA"] @@ -9,7 +9,7 @@ class AutoARIMA(_PmdArimaAdapter): - """Wrapper of the pmdarima implementation of fitting Auto-(S)ARIMA(X) models. + """Auto-(S)ARIMA(X) forecaster, from pmdarima package. Includes automated fitting of (S)ARIMA(X) hyper-parameters (p, d, q, P, D, Q). @@ -248,6 +248,7 @@ class AutoARIMA(_PmdArimaAdapter): See Also -------- ARIMA + StatsForecastAutoARIMA References ---------- @@ -264,7 +265,16 @@ class AutoARIMA(_PmdArimaAdapter): >>> y_pred = forecaster.predict(fh=[1,2,3]) # doctest: +SKIP """ # noqa: E501 - _tags = {"handles-missing-data": True} + _tags = { + # packaging info + # -------------- + "authors": ["mloning", "hyang1996", "fkiraly", "ilkersigirci"], + "maintainers": ["hyang1996"], + # python_dependencies: "pmdarima" - inherited from _PmdArimaAdapter + # estimator type + # -------------- + "handles-missing-data": True, + } SARIMAX_KWARGS_KEYS = [ "time_varying_regression", @@ -478,7 +488,7 @@ def get_test_params(cls, parameter_set="default"): class ARIMA(_PmdArimaAdapter): - """Wrapper of the pmdarima implementation of fitting (S)ARIMA(X) models. + """(S)ARIMA(X) forecaster, from pmdarima package. Exposes `pmdarima.arima.ARIMA` [1]_ under the `sktime` interface. Seasonal ARIMA models and exogeneous input is supported, hence this estimator is @@ -661,7 +671,11 @@ def foo_loss(y_true, y_pred) >>> y_pred = forecaster.predict(fh=[1,2,3]) # doctest: +SKIP """ # noqa: E501 - _tags = {"handles-missing-data": True} + _tags = { + "authors": ["mloning", "hyang1996", "fkiraly", "ilkersigirci"], + "maintainers": ["hyang1996"], + "handles-missing-data": True, + } SARIMAX_KWARGS_KEYS = [ "time_varying_regression", diff --git a/sktime/forecasting/arima/_statsmodels.py b/sktime/forecasting/arima/_statsmodels.py new file mode 100644 index 00000000000..4325604f8d6 --- /dev/null +++ b/sktime/forecasting/arima/_statsmodels.py @@ -0,0 +1,327 @@ +# !/usr/bin/env python3 -u +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +"""Interface to ARIMA from statsmodels package.""" + +__all__ = ["StatsModelsARIMA"] +__author__ = ["arnaujc91"] + +from typing import Iterable, Optional, Tuple, Union + +import numpy as np +import pandas as pd + +from sktime.forecasting.base.adapters import _StatsModelsAdapter + + +class StatsModelsARIMA(_StatsModelsAdapter): + """ARIMA forecaster, from statsmodels package. + + Direct interface for `statsmodels.tsa.arima.model.ARIMA`. + + Parameters + ---------- + order : tuple, optional + The (p,d,q) order of the model for the autoregressive, differences, and + moving average components. d is always an integer, while p and q may + either be integers or lists of integers. + seasonal_order : tuple, optional + The (P,D,Q,s) order of the seasonal component of the model for the + AR parameters, differences, MA parameters, and periodicity. Default + is (0, 0, 0, 0). D and s are always integers, while P and Q + may either be integers or lists of positive integers. + trend : str{'n','c','t','ct'} or iterable, optional + Parameter controlling the deterministic trend. Can be specified as a + string where 'c' indicates a constant term, 't' indicates a + linear trend in time, and 'ct' includes both. Can also be specified as + an iterable defining a polynomial, as in `numpy.poly1d`, where + `[1,1,0,1]` would denote :math:`a + bt + ct^3`. Default is 'c' for + models without integration, and no trend for models with integration. + Note that all trend terms are included in the model as exogenous + regressors, which differs from how trends are included in ``SARIMAX`` + models. See the Notes section for a precise definition of the + treatment of trend terms. + enforce_stationarity : bool, optional + Whether or not to require the autoregressive parameters to correspond + to a stationarity process. + enforce_invertibility : bool, optional + Whether or not to require the moving average parameters to correspond + to an invertible process. + concentrate_scale : bool, optional + Whether or not to concentrate the scale (variance of the error term) + out of the likelihood. This reduces the number of parameters by one. + This is only applicable when considering estimation by numerical + maximum likelihood. + trend_offset : int, optional + The offset at which to start time trend values. Default is 1, so that + if `trend='t'` the trend is equal to 1, 2, ..., nobs. Typically is only + set when the model created by extending a previous dataset. + dates : array_like of datetime, optional + If no index is given by `endog` or `exog`, an array-like object of + datetime objects can be provided. + freq : str, optional + If no index is given by `endog` or `exog`, the frequency of the + time-series may be specified here as a Pandas offset or offset string. + missing : str + Available options are 'none', 'drop', and 'raise'. If 'none', no nan + checking is done. If 'drop', any observations with nans are dropped. + If 'raise', an error is raised. Default is 'none'. + start_params : array_like, optional + Initial guess of the solution for the loglikelihood maximization. + If None, the default is given by Model.start_params. + transformed : bool, optional + Whether or not `start_params` is already transformed. Default is + True. + includes_fixed : bool, optional + If parameters were previously fixed with the `fix_params` method, + this argument describes whether or not `start_params` also includes + the fixed parameters, in addition to the free parameters. Default + is False. + method : str, optional + The method used for estimating the parameters of the model. Valid + options include 'statespace', 'innovations_mle', 'hannan_rissanen', + 'burg', 'innovations', and 'yule_walker'. Not all options are + available for every specification (for example 'yule_walker' can + only be used with AR(p) models). + method_kwargs : dict, optional + Arguments to pass to the fit function for the parameter estimator + described by the `method` argument. + gls : bool, optional + Whether or not to use generalized least squares (GLS) to estimate + regression effects. The default is False if `method='statespace'` + and is True otherwise. + gls_kwargs : dict, optional + Arguments to pass to the GLS estimation fit method. Only applicable + if GLS estimation is used (see `gls` argument for details). + cov_type : str, optional + The `cov_type` keyword governs the method for calculating the + covariance matrix of parameter estimates. Can be one of: + + - 'opg' for the outer product of gradient estimator + - 'oim' for the observed information matrix estimator, calculated + using the method of Harvey (1989) + - 'approx' for the observed information matrix estimator, + calculated using a numerical approximation of the Hessian matrix. + - 'robust' for an approximate (quasi-maximum likelihood) covariance + matrix that may be valid even in the presence of some + misspecifications. Intermediate calculations use the 'oim' + method. + - 'robust_approx' is the same as 'robust' except that the + intermediate calculations use the 'approx' method. + - 'none' for no covariance matrix calculation. + + Default is 'opg' unless memory conservation is used to avoid + computing the loglikelihood values for each observation, in which + case the default is 'oim'. + cov_kwds : dict or None, optional + A dictionary of arguments affecting covariance matrix computation. + + **opg, oim, approx, robust, robust_approx** + + - 'approx_complex_step' : bool, optional - If True, numerical + approximations are computed using complex-step methods. If False, + numerical approximations are computed using finite difference + methods. Default is True. + - 'approx_centered' : bool, optional - If True, numerical + approximations computed using finite difference methods use a + centered approximation. Default is False. + return_params : bool, optional + Whether or not to return only the array of maximizing parameters. + Default is False. + low_memory : bool, optional + If set to True, techniques are applied to substantially reduce + memory usage. If used, some features of the results object will + not be available (including smoothed results and in-sample + prediction), although out-of-sample forecasting is possible. + Default is False. + + See Also + -------- + ARIMA + SARIMAX + AutoARIMA + StatsForecastAutoARIMA + + Examples + -------- + >>> from sktime.datasets import load_airline + >>> from sktime.forecasting.arima import StatsModelsARIMA + >>> y = load_airline() + >>> forecaster = StatsModelsARIMA(order=(0, 0, 12)) # doctest: +SKIP + >>> forecaster.fit(y) # doctest: +SKIP + >>> y_pred = forecaster.predict(fh=[1,2,3]) # doctest: +SKIP + """ + + _tags = { + # packaging info + # -------------- + "authors": ["arnaujc91"], + "maintainers": ["arnaujc91"], + "ignores-exogeneous-X": False, + "capability:pred_int": True, + "capability:pred_int:insample": True, + "python_dependencies": ["statsmodels"], + } + + def __init__( + self, + order: Tuple[int, int, int] = (0, 0, 0), + seasonal_order: Tuple[int, int, int, int] = (0, 0, 0, 0), + trend: Optional[Union[str, Iterable]] = None, + enforce_stationarity: bool = True, + enforce_invertibility: bool = True, + concentrate_scale: bool = False, + trend_offset: int = 1, + dates: Optional[np.ndarray] = None, + freq: Optional[str] = None, + missing: Optional[str] = None, + validate_specification: bool = True, + start_params: Optional[np.ndarray] = None, + transformed: bool = True, + includes_fixed: bool = False, + method: Optional[str] = None, + method_kwargs: Optional[dict] = None, + gls: bool = False, + gls_kwargs: Optional[dict] = None, + cov_type: str = "opg", + cov_kwds: Optional[dict] = None, + return_params: bool = False, + low_memory: bool = False, + ): + self.order = order + self.seasonal_order = seasonal_order + self.trend = trend + self.enforce_stationarity = enforce_stationarity + self.enforce_invertibility = enforce_invertibility + self.concentrate_scale = concentrate_scale + self.trend_offset = trend_offset + self.dates = dates + self.freq = freq + self.missing = missing + self.validate_specification = validate_specification + + # Fit params + self.start_params = start_params + self.transformed = transformed + self.includes_fixed = includes_fixed + self.method = method + self.method_kwargs = method_kwargs + self.gls = gls + self.gls_kwargs = gls_kwargs + self.cov_type = cov_type + self.cov_kwds = cov_kwds + self.return_params = return_params + self.low_memory = low_memory + + super().__init__() + + def _fit_forecaster(self, y, X=None): + from statsmodels.tsa.arima.model import ARIMA as _ARIMA + + self._forecaster = _ARIMA( + endog=y, + exog=X, + order=self.order, + seasonal_order=self.seasonal_order, + trend=self.trend, + enforce_stationarity=self.enforce_stationarity, + enforce_invertibility=self.enforce_invertibility, + concentrate_scale=self.concentrate_scale, + trend_offset=self.trend_offset, + dates=self.dates, + freq=self.freq, + missing=self.missing, + validate_specification=self.validate_specification, + ) + self._fitted_forecaster = self._forecaster.fit( + start_params=self.start_params, + transformed=self.transformed, + includes_fixed=self.includes_fixed, + method=self.method, + method_kwargs=self.method_kwargs, + gls=self.gls, + gls_kwargs=self.gls_kwargs, + cov_type=self.cov_type, + cov_kwds=self.cov_kwds, + return_params=self.return_params, + low_memory=self.low_memory, + ) + + def summary(self): + """Get a summary of the fitted forecaster. + + This is the same as the implementation in statsmodels: + https://www.statsmodels.org/dev/examples/notebooks/generated/statespace_structural_harvey_jaeger.html + """ + return self._fitted_forecaster.summary() + + @staticmethod + def _extract_conf_int(prediction_results, alpha) -> pd.DataFrame: + """Construct confidence interval at specified `alpha` for each timestep. + + Parameters + ---------- + prediction_results : PredictionResults + results class, as returned by ``self._fitted_forecaster.get_prediction`` + alpha : float + one minus nominal coverage + + Returns + ------- + pd.DataFrame + confidence intervals at each timestep + + The dataframe must have at least two columns ``lower`` and ``upper``, and + the row indices must be integers relative to ``self.cutoff``. Order of + columns do not matter, and row indices must be a superset of relative + integer horizon of ``fh``. + """ + conf_int = prediction_results.conf_int(alpha=alpha) + conf_int.columns = ["lower", "upper"] + + return conf_int + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + There are currently no reserved values for forecasters. + + Returns + ------- + params : list of dict, default = [] + Parameters to create testing instances of the class + Each dict are parameters to construct an "interesting" test instance, i.e., + `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. + `create_test_instance` uses the first (or only) dictionary in `params` + """ + return [ + { + "order": (0, 1, 2), + "trend": "n", + "enforce_stationarity": False, + "enforce_invertibility": False, + "concentrate_scale": True, + "method": "statespace", + }, + { + "order": (1, 1, 2), + "trend": "t", + "enforce_stationarity": False, + "enforce_invertibility": False, + "method": "statespace", + }, + { + "order": (0, 0, 1), + "trend": "ct", + "seasonal_order": (1, 0, 1, 2), + "cov_type": "opg", + "gls": True, + "method": "statespace", + }, + {"cov_type": "robust", "gls": True, "method": "burg"}, + ] diff --git a/sktime/forecasting/auto_reg.py b/sktime/forecasting/auto_reg.py index c27ab585c6c..dd56bfeae64 100644 --- a/sktime/forecasting/auto_reg.py +++ b/sktime/forecasting/auto_reg.py @@ -93,13 +93,18 @@ class AutoREG(_StatsModelsAdapter): """ _tags = { + # packaging info + # -------------- + "authors": ["jonathanbechtel", "mgazian000", "CTFallon"], + "maintainers": ["jonathanbechtel", "mgazian000", "CTFallon"], + "python_dependencies": "statsmodels>=0.13.0", + # estimator type + # -------------- "y_inner_mtype": "pd.Series", "X_inner_mtype": "pd.DataFrame", "scitype:y": "univariate", "ignores-exogeneous-X": False, "requires-fh-in-fit": False, - "python_version": None, - "python_dependencies": "statsmodels>=0.13.0", } def __init__( diff --git a/sktime/forecasting/base/__init__.py b/sktime/forecasting/base/__init__.py index a101e3a62cc..9ab500c8094 100644 --- a/sktime/forecasting/base/__init__.py +++ b/sktime/forecasting/base/__init__.py @@ -1,4 +1,3 @@ -# !/usr/bin/env python3 -u # copyright: sktime developers, BSD-3-Clause License (see LICENSE file) """Implements base classes for forecasting in sktime.""" diff --git a/sktime/forecasting/base/_base.py b/sktime/forecasting/base/_base.py index 46d22661732..acc6e58227d 100644 --- a/sktime/forecasting/base/_base.py +++ b/sktime/forecasting/base/_base.py @@ -45,6 +45,7 @@ class name: BaseForecaster from sktime.base import BaseEstimator from sktime.datatypes import ( VectorizedDF, + check_is_error_msg, check_is_scitype, convert_to, get_cutoff, @@ -82,6 +83,14 @@ class BaseForecaster(BaseEstimator): # default tag values - these typically make the "safest" assumption # for more extensive documentation, see extension_templates/forecasting.py _tags = { + # packaging info + # -------------- + "authors": "sktime developers", # author(s) of the object + "maintainers": "sktime developers", # current maintainer(s) of the object + "python_version": None, # PEP 440 python version specifier to limit versions + "python_dependencies": None, # str or list of str, package soft dependencies + # estimator type + # -------------- "object_type": "forecaster", # type of object "scitype:y": "univariate", # which y are fine? univariate/multivariate/both "ignores-exogeneous-X": False, # does estimator ignore the exogeneous X? @@ -95,41 +104,30 @@ class BaseForecaster(BaseEstimator): "X-y-must-have-same-index": True, # can estimator handle different X/y index? "enforce_index_type": None, # index type that needs to be enforced in X/y "fit_is_empty": False, # is fit empty and can be skipped? - "python_version": None, # PEP 440 python version specifier to limit versions - "python_dependencies": None, # str or list of str, package soft dependencies } # configs and default config values + # see set_config documentation for details _config = { "backend:parallel": None, # parallelization backend for broadcasting # {None, "dask", "loky", "multiprocessing", "threading"} # None: no parallelization # "loky", "multiprocessing" and "threading": uses `joblib` Parallel loops + # "joblib": uses custom joblib backend, set via `joblib_backend` tag # "dask": uses `dask`, requires `dask` package in environment "backend:parallel:params": None, # params for parallelization backend + "remember_data": True, # whether to remember data in fit - self._X, self._y } _config_doc = { - "backend:parallel": """ - backend:parallel : str, optional, default="None" - backend to use for parallelization when broadcasting/vectorizing, one of - - - "None": executes loop sequentally, simple list comprehension - - "loky", "multiprocessing" and "threading": uses ``joblib`` ``Parallel`` - - "dask": uses ``dask``, requires ``dask`` package in environment - """, - "backend:parallel:params": """ - backend:parallel:params : dict, optional, default={} (no parameters passed) - additional parameters passed to the parallelization backend as config. - Valid keys depend on the value of ``backend:parallel``: - - - "None": no additional parameters, ``backend_params`` is ignored - - "loky", "multiprocessing" and "threading": - any valid keys for ``joblib.Parallel`` can be passed here, - e.g., ``n_jobs``, with the exception of ``backend`` which is directly - controlled by ``backend:parallel`` - - "dask": any valid keys for ``dask.compute`` - can be passed, e.g., ``scheduler`` + "remember_data": """ + remember_data : bool, default=True + whether self._X and self._y are stored in fit, and updated + in update. If True, self._X and self._y are stored and updated. + If False, self._X and self._y are not stored and updated. + This reduces serialization size when using save, + but the update will default to "do nothing" rather than + "refit to all data seen". """, } @@ -390,11 +388,7 @@ def fit(self, y, X=None, fh=None): return self - def predict( - self, - fh=None, - X=None, - ): + def predict(self, fh=None, X=None): """Forecast time series at future horizon. State required: @@ -443,16 +437,20 @@ def predict( # convert to output mtype, identical with last y mtype seen y_out = convert_to( y_pred, - self._y_mtype_last_seen, + self._y_metadata["mtype"], store=self._converter_store_y, store_behaviour="freeze", ) return y_out - def fit_predict(self, y, X=None, fh=None): + def fit_predict(self, y, X=None, fh=None, X_pred=None): """Fit and forecast time series at future horizon. + Same as ``fit(y, X, fh).predict(X_pred)``. + If ``X_pred`` is not passed, same as + ``fit(y, fh, X).predict(X)``. + State change: Changes state to "fitted". @@ -466,32 +464,38 @@ def fit_predict(self, y, X=None, fh=None): Parameters ---------- y : time series in sktime compatible data container format - Time series to which to fit the forecaster. + Time series to which to fit the forecaster. y can be in one of the following formats: Series scitype: pd.Series, pd.DataFrame, or np.ndarray (1D or 2D) - for vanilla forecasting, one time series + for vanilla forecasting, one time series Panel scitype: pd.DataFrame with 2-level row MultiIndex, - 3D np.ndarray, list of Series pd.DataFrame, or nested pd.DataFrame - for global or panel forecasting + 3D np.ndarray, list of Series pd.DataFrame, or nested pd.DataFrame + for global or panel forecasting Hierarchical scitype: pd.DataFrame with 3 or more level row MultiIndex - for hierarchical forecasting + for hierarchical forecasting Number of columns admissible depend on the "scitype:y" tag: - if self.get_tag("scitype:y")=="univariate": - y must have a single column/variable - if self.get_tag("scitype:y")=="multivariate": - y must have 2 or more columns - if self.get_tag("scitype:y")=="both": no restrictions on columns apply + if self.get_tag("scitype:y")=="univariate": + y must have a single column/variable + if self.get_tag("scitype:y")=="multivariate": + y must have 2 or more columns + if self.get_tag("scitype:y")=="both": no restrictions on columns apply For further details: - on usage, see forecasting tutorial examples/01_forecasting.ipynb - on specification of formats, examples/AA_datatypes_and_datasets.ipynb + on usage, see forecasting tutorial examples/01_forecasting.ipynb + on specification of formats, examples/AA_datatypes_and_datasets.ipynb fh : int, list, np.array or ForecastingHorizon (not optional) The forecasting horizon encoding the time stamps to forecast at. if has not been passed in fit, must be passed, not optional X : time series in sktime compatible format, optional (default=None) - Exogeneous time series to fit to + Exogeneous time series to fit to Should be of same scitype (Series, Panel, or Hierarchical) as y in fit - if self.get_tag("X-y-must-have-same-index"), - X.index must contain fh.index and y.index both + If ``self.get_tag("X-y-must-have-same-index")`` is True, + X.index must contain y.index. + If, in addition, X_pred is not passed, X must also contain fh.index. + X_pred : time series in sktime compatible format, optional (default=None) + Exogeneous time series to use in predict + If passed, will be used in predict instead of X. + If ``self.get_tag("X-y-must-have-same-index")`` is True, + X_pred.index must contain fh.index. Returns ------- @@ -500,6 +504,12 @@ def fit_predict(self, y, X=None, fh=None): y_pred has same type as the y that has been passed most recently: Series, Panel, Hierarchical scitype, same format (see above) """ + # if X_pred is passed, run fit/predict with different X + if X_pred is not None: + return self.fit(y=y, X=X, fh=fh).predict(X=X_pred) + # otherwise, we use the same X for fit and predict + # below code carries out conversion and checks for X only once + # if fit is called, fitted state is re-set self._is_fitted = False @@ -1091,7 +1101,7 @@ def update_predict_single( # convert to output mtype, identical with last y mtype seen y_pred = convert_to( y_pred, - self._y_mtype_last_seen, + self._y_metadata["mtype"], store=self._converter_store_y, store_behaviour="freeze", ) @@ -1148,7 +1158,7 @@ def predict_residuals(self, y=None, X=None): fh_orig = None # if no y is passed, the so far observed y is used - if y is None: + if y is None and self.get_config()["remember_data"]: y = self._y # we want residuals, so fh must be the index of y @@ -1171,8 +1181,8 @@ def predict_residuals(self, y=None, X=None): y_pred = self.predict(fh=fh, X=X) - if not type(y_pred) is type(y): - y = convert_to(y, self._y_mtype_last_seen) + if type(y_pred) is not type(y): + y = convert_to(y, self._y_metadata["mtype"]) y_res = y - y_pred @@ -1319,7 +1329,7 @@ def _check_X_y(self, X=None, y=None): Writes to self -------------- - _y_mtype_last_seen : str, mtype of y + _y_metadata : dict with str keys, metadata from checking y _converter_store_y : dict, metadata from conversion for back-conversion """ if X is None and y is None: @@ -1334,7 +1344,11 @@ def _most_complex_scitype(scitypes, smaller_equal_than=None): elif "Series" in scitypes: return "Series" else: - raise ValueError("no series scitypes supported, bug in estimator") + raise ValueError( + f"Error in {type(self).__name__}, no series scitypes supported, " + "likely a bug in estimator: scitypes arg passed to " + f"_most_complex_scitype are {scitypes}" + ) def _check_missing(metadata, obj_name): """Check input metadata against self's missing capability tag.""" @@ -1370,34 +1384,40 @@ def _check_missing(metadata, obj_name): # checking y if y is not None: # request only required metadata from checks - y_metadata_required = [] + y_metadata_required = ["n_features", "feature_names"] if self.get_tag("scitype:y") != "both": y_metadata_required += ["is_univariate"] if not self.get_tag("handles-missing-data"): y_metadata_required += ["has_nans"] - y_valid, _, y_metadata = check_is_scitype( + y_valid, y_msg, y_metadata = check_is_scitype( y, scitype=ALLOWED_SCITYPES, return_metadata=y_metadata_required, var_name="y", ) - msg = ( - "y must be in an sktime compatible format, " - f"of scitype {', '.join(ALLOWED_SCITYPES)}, " + + msg_start = ( + f"Unsupported input data type in {self.__class__.__name__}, input y" + ) + allowed_msg = ( + "Allowed scitypes for y in forecasting are " + f"{', '.join(ALLOWED_SCITYPES)}, " "for instance a pandas.DataFrame with sktime compatible time indices, " "or with MultiIndex and last(-1) level an sktime compatible time index." " See the forecasting tutorial examples/01_forecasting.ipynb, or" - " the data format tutorial examples/AA_datatypes_and_datasets.ipynb," - "If you think y is already in an sktime supported input format, " - "run sktime.datatypes.check_raise(y, mtype) to diagnose the error, " - "where mtype is the string of the type specification you want for y. " - "Possible mtype specification strings are as follows: " + " the data format tutorial examples/AA_datatypes_and_datasets.ipynb" ) if not y_valid: - raise TypeError(msg + ", ".join(mtypes_messages)) + check_is_error_msg( + y_msg, + var_name=msg_start, + allowed_msg=allowed_msg, + raise_exception=True, + ) y_scitype = y_metadata["scitype"] + self._y_metadata = y_metadata self._y_mtype_last_seen = y_metadata["mtype"] req_vec_because_rows = y_scitype not in y_inner_scitype @@ -1412,7 +1432,9 @@ def _check_missing(metadata, obj_name): and y_metadata["is_univariate"] ): raise ValueError( - "y must have two or more variables, but found only one" + f"Unsupported input data type in {type(self).__name__}, " + "this forecaster accepts only strictly multivariate data. " + "y must have two or more variables, but found only one." ) _check_missing(y_metadata, "y") @@ -1430,27 +1452,31 @@ def _check_missing(metadata, obj_name): if not self.get_tag("handles-missing-data"): X_metadata_required += ["has_nans"] - X_valid, _, X_metadata = check_is_scitype( + X_valid, X_msg, X_metadata = check_is_scitype( X, scitype=ALLOWED_SCITYPES, return_metadata=X_metadata_required, var_name="X", ) - msg = ( - "X must be either None, or in an sktime compatible format, " - "of scitype Series, Panel or Hierarchical, " + msg_start = ( + f"Unsupported input data type in {self.__class__.__name__}, input X" + ) + allowed_msg = ( + "Allowed scitypes for X in forecasting are None, " + f"{', '.join(ALLOWED_SCITYPES)}, " "for instance a pandas.DataFrame with sktime compatible time indices, " "or with MultiIndex and last(-1) level an sktime compatible time index." " See the forecasting tutorial examples/01_forecasting.ipynb, or" " the data format tutorial examples/AA_datatypes_and_datasets.ipynb" - "If you think X is already in an sktime supported input format, " - "run sktime.datatypes.check_raise(X, mtype) to diagnose the error, " - "where mtype is the string of the type specification you want for X. " - "Possible mtype specification strings are as follows. " ) if not X_valid: - raise TypeError(msg + ", ".join(mtypes_messages)) + check_is_error_msg( + X_msg, + var_name=msg_start, + allowed_msg=allowed_msg, + raise_exception=True, + ) X_scitype = X_metadata["scitype"] X_requires_vectorization = X_scitype not in X_inner_scitype @@ -1533,10 +1559,9 @@ def _check_X(self, X=None): return self._check_X_y(X=X)[0] def _update_X(self, X, enforce_index_type=None): - if X is not None: + if X is not None and self.get_config()["remember_data"]: X = check_X(X, enforce_index_type=enforce_index_type) - if X is len(X) > 0: - self._X = X.combine_first(self._X) + self._X = update_data(self._X, X) def _update_y_X(self, y, X=None, enforce_index_type=None): """Update internal memory of seen training data. @@ -1565,7 +1590,7 @@ def _update_y_X(self, y, X=None, enforce_index_type=None): X : pd.DataFrame or 2D np.ndarray, optional (default=None) Exogeneous time series """ - if y is not None: + if y is not None and self.get_config()["remember_data"]: # unwrap y if VectorizedDF if isinstance(y, VectorizedDF): y = y.X_multiindex @@ -1578,7 +1603,7 @@ def _update_y_X(self, y, X=None, enforce_index_type=None): # set cutoff to the end of the observation horizon self._set_cutoff_from_y(y) - if X is not None: + if X is not None and self.get_config()["remember_data"]: # unwrap X if VectorizedDF if isinstance(X, VectorizedDF): X = X.X_multiindex @@ -1914,7 +1939,7 @@ def _update(self, y, X=None, update_params=True): ------- self : reference to self """ - if update_params: + if update_params and self.get_config()["remember_data"]: # default to re-fitting if update is not implemented warn( f"NotImplementedWarning: {self.__class__.__name__} " @@ -1928,12 +1953,14 @@ def _update(self, y, X=None, update_params=True): # we need to overwrite the mtype last seen and converter store, since the _y # may have been converted mtype_last_seen = self._y_mtype_last_seen + y_metadata = self._y_metadata _converter_store_y = self._converter_store_y # refit with updated data, not only passed data self.fit(y=self._y, X=self._X, fh=self._fh) # todo: should probably be self._fit, not self.fit # but looping to self.fit for now to avoid interface break self._y_mtype_last_seen = mtype_last_seen + self._y_metadata = y_metadata self._converter_store_y = _converter_store_y # if update_params=False, and there are no components, do nothing @@ -2026,14 +2053,9 @@ def _predict_interval(self, fh, X, coverage): # change the column labels (multiindex) to the format for intervals # idx returned by _predict_quantiles is # 2-level MultiIndex with variable names, alpha - idx = pred_int.columns - # variable names (unique, in same order) - var_names = idx.get_level_values(0).unique() - # idx returned by _predict_interval should be # 3-level MultiIndex with variable names, coverage, lower/upper - int_idx = pd.MultiIndex.from_product([var_names, coverage, ["lower", "upper"]]) - + int_idx = self._get_columns(method="predict_interval", coverage=coverage) pred_int.columns = int_idx return pred_int @@ -2099,14 +2121,9 @@ def _predict_quantiles(self, fh, X, alpha): # change the column labels (multiindex) to the format for intervals # idx returned by _predict_interval is # 3-level MultiIndex with variable names, coverage, lower/upper - idx = pred_int.columns - # variable names (unique, in same order) - var_names = idx.get_level_values(0).unique() - # idx returned by _predict_quantiles should be # is 2-level MultiIndex with variable names, alpha - int_idx = pd.MultiIndex.from_product([var_names, alpha]) - + int_idx = self._get_columns(method="predict_quantiles", alpha=alpha) pred_int.columns = int_idx elif implements_proba: @@ -2176,8 +2193,9 @@ def _predict_var(self, fh=None, X=None, cov=False): if fh.is_relative: fh = fh.to_absolute(self.cutoff) pred_var.index = fh.to_pandas() - if isinstance(self._y, pd.DataFrame): - pred_var.columns = self._y.columns + + if isinstance(pred_var, pd.DataFrame): + pred_var.columns = self._get_columns(method="predict_var") return pred_var @@ -2345,29 +2363,78 @@ def _predict_moving_cutoff( for i in range(len(y_preds)): y_preds[i] = convert_to( y_preds[i], - self._y_mtype_last_seen, + self._y_metadata["mtype"], store=self._converter_store_y, store_behaviour="freeze", ) return _format_moving_cutoff_predictions(y_preds, cutoffs) - def _get_varnames(self): + def _get_varnames(self, y=None): """Return variable column for DataFrame-like returns. - Developer note: currently a helper for predict_interval, predict_quantiles, - valid only in the univariate case. Can be extended later. + Primarily used as helper for probabilistic predict-like methods. + Assumes that _check_X_y has been called, and self._y_metadata set. + + Parameter + --------- + y : ignored, present for downwards compatibility + + Returns + ------- + varnames : iterable of integer or str variable names + can be list or pd.Index + variable names for DataFrame-like returns + identical to self._y_varnames if this attribute exists + """ + featnames = self._y_metadata["feature_names"] + return featnames + + def _get_columns(self, method="predict", **kwargs): + """Return column names for DataFrame-like returns. + + Primarily used as helper for probabilistic predict-like methods. + Assumes that _check_X_y has been called, and self._y_metadata set. + + Parameter + --------- + method : str, optional (default="predict") + method for which to return column names + one of "predict", "predict_interval", "predict_quantiles", "predict_var" + kwargs : dict + additional keyword arguments passed to private method + important: args to private method, e.g., _predict, _predict_interval + + Returns + ------- + columns : pd.Index + column names """ - y = self._y - if isinstance(y, pd.Series): - var_name = self._y.name - elif isinstance(y, pd.DataFrame): - return y.columns + featnames = self._get_varnames() + + if method in ["predict", "predict_var"]: + return featnames else: - var_name = 0 - if var_name is None: - var_name = 0 + assert method in ["predict_interval", "predict_quantiles"] + + if method == "predict_interval": + coverage = kwargs.get("coverage", None) + if coverage is None: + raise ValueError( + "coverage must be passed to _get_columns for predict_interval" + ) + return pd.MultiIndex.from_product([featnames, coverage, ["lower", "upper"]]) + + if method == "predict_quantiles": + alpha = kwargs.get("alpha", None) + if alpha is None: + raise ValueError( + "alpha must be passed to _get_columns for predict_quantiles" + ) + return pd.MultiIndex.from_product([featnames, alpha]) + - return [var_name] +# initialize dynamic docstrings +BaseForecaster._init_dynamic_doc() def _format_moving_cutoff_predictions(y_preds, cutoffs): diff --git a/sktime/forecasting/base/_delegate.py b/sktime/forecasting/base/_delegate.py index 1a9a9af3fb0..05d001aed4b 100644 --- a/sktime/forecasting/base/_delegate.py +++ b/sktime/forecasting/base/_delegate.py @@ -38,6 +38,57 @@ class _DelegatedForecaster(BaseForecaster): def _get_delegate(self): return getattr(self, self._delegate_name) + def _set_delegated_tags(self, delegate=None): + """Set delegated tags, only tags for boilerplate control. + + Writes tags to self. + Can be used by descendant classes to set dependent tags. + Makes safe baseline assumptions about tags, which can be overwritten. + + * data mtype tags are set to the most general value. + This is to ensure that conversion is left to the inner estimator. + * packaging tags such as "author" or "python_depedencies" are not cloned. + * other boilerplate tags are cloned. + + Parameters + ---------- + delegate : object, optional (default=None) + object to get tags from, if None, uses self._get_delegate() + + Returns + ------- + self : reference to self + """ + from sktime.datatypes import ALL_TIME_SERIES_MTYPES + + if delegate is None: + delegate = self._get_delegate() + + TAGS_TO_DELEGATE = [ + "requires-fh-in-fit", + "handles-missing-data", + "ignores-exogeneous-X", + "capability:insample", + "capability:pred_int", + "capability:pred_int:insample", + "handles-missing-data", + "requires-fh-in-fit", + "X-y-must-have-same-index", + "enforce_index_type", + "fit_is_empty", + ] + + TAGS_TO_SET = { + "scitype:y": "both", + "y_inner_mtype": ALL_TIME_SERIES_MTYPES, + "X_inner_mtype": ALL_TIME_SERIES_MTYPES, + } + + self.clone_tags(delegate, tag_names=TAGS_TO_DELEGATE) + self.set_tags(**TAGS_TO_SET) + + return self + def _fit(self, y, X, fh): """Fit forecaster to training data. diff --git a/sktime/forecasting/base/_fh.py b/sktime/forecasting/base/_fh.py index 4754cf6d548..d06286d0286 100644 --- a/sktime/forecasting/base/_fh.py +++ b/sktime/forecasting/base/_fh.py @@ -674,6 +674,87 @@ def to_indexer(self, cutoff=None, from_cutoff=True): relative = self.to_relative(cutoff) return relative - relative.to_pandas()[0] + def get_expected_pred_idx(self, y=None, cutoff=None, sort_by_time=False): + """Construct DataFrame Index expected in y_pred, return of _predict. + + Parameters + ---------- + y : pd.DataFrame, pd.Series, pd.Index, or None + data to compute fh relative to, + assumed in sktime pandas based mtype or index thereof + if None, assumes no MultiIndex + cutoff : pd.Period, pd.Timestamp, int, or pd.Index, optional (default=None) + Cutoff value to use in computing resulting index. + If cutoff is not provided, is computed from ``y`` via ``get_cutoff``. + sort_by_time : bool, optional (default=False) + for MultiIndex returns, whether to sort by time index (level -1) + - If True, result Index is sorted by time index (level -1) + - If False, result Index is sorted overall + + Returns + ------- + fh_idx : pd.Index, expected index of y_pred returned by predict + assumes pandas based return mtype + """ + from sktime.datatypes import get_cutoff + + def _make_y_pred(y_single): + """Make y_pred from single instance y, used in list comprehension.""" + cutoff = get_cutoff(y_single) + return pd.Index(self.to_absolute_index(cutoff)) + + if hasattr(y, "index"): + y_index = y.index + elif isinstance(y, pd.Index): + y_index = y + y = pd.DataFrame(index=y_index) + elif cutoff is None: + y_index = pd.Index(y) + y = pd.DataFrame(index=y_index) + else: + y_index = None + + if cutoff is None and not isinstance(y_index, pd.MultiIndex): + _cutoff = get_cutoff(y) + else: + _cutoff = cutoff + + if cutoff is not None or not isinstance(y_index, pd.MultiIndex): + fh_idx = pd.Index(self.to_absolute_index(_cutoff)) + + if cutoff is not None and isinstance(y_index, pd.MultiIndex): + y_inst_idx = y_index.droplevel(-1).unique().sort_values() + if isinstance(y_inst_idx, pd.MultiIndex) and sort_by_time: + fh_list = [x + (y,) for y in fh_idx for x in y_inst_idx] + elif isinstance(y_inst_idx, pd.MultiIndex) and not sort_by_time: + fh_list = [x + (y,) for x in y_inst_idx for y in fh_idx] + elif sort_by_time: # and not isinstance(y_inst_idx, pd.MultiIndex): + fh_list = [(x, y) for y in fh_idx for x in y_inst_idx] + else: # not sort_by_time and not isinstance(y_inst_idx, pd.MultiIndex): + fh_list = [(x, y) for x in y_inst_idx for y in fh_idx] + + fh_idx = pd.Index(fh_list) + + elif isinstance(y_index, pd.MultiIndex): + y_inst_idx = y_index.droplevel(-1).unique() + + if isinstance(y_inst_idx, pd.MultiIndex): + fh_list = [x + (z,) for x in y_inst_idx for z in _make_y_pred(y.loc[x])] + else: + fh_list = [(x, z) for x in y_inst_idx for z in _make_y_pred(y.loc[x])] + + fh_idx = pd.Index(fh_list) + + if sort_by_time: + fh_df = pd.DataFrame(index=fh_idx) + fh_idx = fh_df.sort_index(level=-1).index + + # replicating index names + if hasattr(y_index, "names") and y_index.names is not None: + fh_idx.names = y_index.names + + return fh_idx + def __repr__(self): """Generate repr based on wrapped index repr.""" class_name = self.__class__.__name__ @@ -728,7 +809,7 @@ def _to_relative(fh: ForecastingHorizon, cutoff=None) -> ForecastingHorizon: absolute = _coerce_to_period(absolute, freq=fh.freq) cutoff = _coerce_to_period(cutoff, freq=fh.freq) - # TODO: 0.25.0: + # TODO: 0.27.0: # Check at every minor release whether lower pandas bound >=0.15.0 # if yes, can remove the workaround in the "else" condition and the check # @@ -792,6 +873,12 @@ def _to_absolute(fh: ForecastingHorizon, cutoff) -> ForecastingHorizon: _check_cutoff(cutoff, relative) is_timestamp = isinstance(cutoff, pd.DatetimeIndex) + # remember timezone to restore it later + if hasattr(cutoff, "tz"): + old_tz = cutoff.tz + else: + old_tz = None + if is_timestamp: # coerce to pd.Period for reliable arithmetic operations and # computations of time deltas @@ -806,6 +893,9 @@ def _to_absolute(fh: ForecastingHorizon, cutoff) -> ForecastingHorizon: # coerce back to DatetimeIndex after operation absolute = absolute.to_timestamp(fh.freq) + if old_tz is not None: + absolute = absolute.tz_localize(old_tz) + return fh._new(absolute, is_relative=False, freq=fh.freq) diff --git a/sktime/forecasting/base/_sktime.py b/sktime/forecasting/base/_sktime.py index 681f7b80808..47755bd3d28 100644 --- a/sktime/forecasting/base/_sktime.py +++ b/sktime/forecasting/base/_sktime.py @@ -8,7 +8,7 @@ import numpy as np import pandas as pd -from sktime.forecasting.base._base import DEFAULT_ALPHA, BaseForecaster +from sktime.forecasting.base._base import BaseForecaster from sktime.split import CutoffSplitter from sktime.utils.datetime import _shift @@ -21,41 +21,50 @@ def __init__(self, window_length=None): self.window_length = window_length self.window_length_ = None - def _predict(self, fh, X): - """Predict core logic.""" - kwargs = {"X": X} + def _predict_boilerplate(self, fh, **kwargs): + """Dispatcher to in-sample and out-of-sample logic. + + In-sample logic is implemented in _predict_in_sample. + Out-of-sample logic is implemented in _predict_fixed_cutoff. + """ + cutoff = self._cutoff # all values are out-of-sample - if fh.is_all_out_of_sample(self.cutoff): - y_pred = self._predict_fixed_cutoff( - fh.to_out_of_sample(self.cutoff), **kwargs - ) + if fh.is_all_out_of_sample(cutoff): + y_pred = self._predict_fixed_cutoff(fh.to_out_of_sample(cutoff), **kwargs) # all values are in-sample elif fh.is_all_in_sample(self.cutoff): - y_pred = self._predict_in_sample(fh.to_in_sample(self.cutoff), **kwargs) + y_pred = self._predict_in_sample(fh.to_in_sample(cutoff), **kwargs) # both in-sample and out-of-sample values else: - y_ins = self._predict_in_sample(fh.to_in_sample(self.cutoff), **kwargs) - y_oos = self._predict_fixed_cutoff( - fh.to_out_of_sample(self.cutoff), **kwargs - ) + y_ins = self._predict_in_sample(fh.to_in_sample(cutoff), **kwargs) + y_oos = self._predict_fixed_cutoff(fh.to_out_of_sample(cutoff), **kwargs) if isinstance(y_ins, pd.DataFrame) and isinstance(y_oos, pd.Series): y_oos = y_oos.to_frame(y_ins.columns[0]) y_pred = pd.concat([y_ins, y_oos]) + return y_pred + + def _predict(self, fh, X): + """Predict core logic.""" + kwargs = {"X": X} + + y_pred = self._predict_boilerplate(fh, **kwargs) + # ensure pd.Series name attribute is preserved if isinstance(y_pred, pd.Series) and isinstance(self._y, pd.Series): y_pred.name = self._y.name + if isinstance(y_pred, pd.DataFrame) and isinstance(self._y, pd.Series): + y_pred = y_pred.iloc[:, 0] + y_pred.name = self._y.name return y_pred - def _predict_fixed_cutoff( - self, fh, X=None, return_pred_int=False, alpha=DEFAULT_ALPHA - ): + def _predict_fixed_cutoff(self, fh, X=None, **kwargs): """Make single-step or multi-step fixed cutoff predictions. Parameters @@ -63,26 +72,20 @@ def _predict_fixed_cutoff( fh : np.array all positive (> 0) X : pd.DataFrame - return_pred_int : bool - alpha : float or array-like Returns ------- y_pred = pd.Series or pd.DataFrame """ # assert all(fh > 0) - y_pred = self._predict_last_window( - fh, X, return_pred_int=return_pred_int, alpha=alpha - ) + y_pred = self._predict_last_window(fh, X=X, **kwargs) if isinstance(y_pred, pd.Series) or isinstance(y_pred, pd.DataFrame): return y_pred else: index = fh.to_absolute_index(self.cutoff) return pd.Series(y_pred, index=index) - def _predict_in_sample( - self, fh, X=None, return_pred_int=False, alpha=DEFAULT_ALPHA - ): + def _predict_in_sample(self, fh, X=None, **kwargs): """Make in-sample prediction using single-step moving-cutoff predictions. Parameters @@ -90,16 +93,11 @@ def _predict_in_sample( fh : np.array all non-positive (<= 0) X : pd.DataFrame - return_pred_int : bool - alpha : float or array-like Returns ------- y_pred : pd.DataFrame or pd.Series """ - if return_pred_int: - raise NotImplementedError() - y_train = self._y # generate cutoffs from forecasting horizon, note that cutoffs are @@ -108,17 +106,13 @@ def _predict_in_sample( cv = CutoffSplitter(cutoffs, fh=1, window_length=self.window_length_) return self._predict_moving_cutoff(y_train, cv, X, update_params=False) - def _predict_last_window( - self, fh, X=None, return_pred_int=False, alpha=DEFAULT_ALPHA - ): + def _predict_last_window(self, fh, X=None, **kwargs): """Predict core logic. Parameters ---------- fh : np.array X : pd.DataFrame - return_pred_int : bool - alpha : float or list of floats Returns ------- @@ -141,7 +135,32 @@ def _get_last_window(self): return y, X - @staticmethod - def _predict_nan(fh): - """Predict nan if predictions are not possible.""" - return np.full(len(fh), np.nan) + def _predict_nan(self, fh=None, method="predict", **kwargs): + """Create a return DataFrame for predict-like method, with all np.nan entries. + + Parameters + ---------- + fh : ForecastingHorizon of self, optional (default=None) + retrieved from self.fh if None + method : str, optional (default="predict") + method name to generate return DataFrame for + name of one of the BaseForecaster predict-like methods + **kwargs : optional + further kwargs to predict-like methods, e.g., coverage for predict_interval + passed to self._get_columns + + Returns + ------- + y_pred : pd.DataFrame + return DataFrame + index, columns are as expected + all entries are np.nan + """ + if fh is None: + fh = self.fh + + index = fh.get_expected_pred_idx(y=self._y, cutoff=self.cutoff) + columns = self._get_columns(method=method, **kwargs) + + y_pred = pd.DataFrame(np.nan, index=index, columns=columns) + return y_pred diff --git a/sktime/forecasting/base/adapters/_fbprophet.py b/sktime/forecasting/base/adapters/_fbprophet.py index acfd91f4707..a27bc2cd3f3 100644 --- a/sktime/forecasting/base/adapters/_fbprophet.py +++ b/sktime/forecasting/base/adapters/_fbprophet.py @@ -16,6 +16,7 @@ class _ProphetAdapter(BaseForecaster): """Base class for interfacing prophet and neuralprophet.""" _tags = { + "authors": ["mloning", "aiwalter", "fkiraly"], "ignores-exogeneous-X": False, "capability:pred_int": True, "capability:pred_int:insample": True, @@ -116,11 +117,15 @@ def _fit(self, y, X, fh): df["cap"] = self.growth_cap df["floor"] = self.growth_floor + if hasattr(self, "fit_kwargs") and isinstance(self.fit_kwargs, dict): + fit_kwargs = self.fit_kwargs + else: + fit_kwargs = {} if self.verbose: - self._forecaster.fit(df=df) + self._forecaster.fit(df=df, **fit_kwargs) else: with _suppress_stdout_stderr(): - self._forecaster.fit(df=df) + self._forecaster.fit(df=df, **fit_kwargs) return self diff --git a/sktime/forecasting/base/adapters/_generalised_statsforecast.py b/sktime/forecasting/base/adapters/_generalised_statsforecast.py index 3055b7a0449..21477e3cbea 100644 --- a/sktime/forecasting/base/adapters/_generalised_statsforecast.py +++ b/sktime/forecasting/base/adapters/_generalised_statsforecast.py @@ -16,6 +16,14 @@ class _GeneralisedStatsForecastAdapter(BaseForecaster): """Base adapter class for StatsForecast models.""" _tags = { + # packaging info + # -------------- + "authors": ["yarnabrina"], + "maintainers": ["yarnabrina"], + "python_version": ">=3.8", + "python_dependencies": ["statsforecast"], + # estimator type + # -------------- "y_inner_mtype": "pd.Series", "X_inner_mtype": "pd.DataFrame", "scitype:y": "univariate", @@ -23,8 +31,6 @@ class _GeneralisedStatsForecastAdapter(BaseForecaster): # "X-y-must-have-same-index": True, # TODO: need to check (how?) # "enforce_index_type": None, # TODO: need to check (how?) "handles-missing-data": False, - "python_version": ">=3.8", - "python_dependencies": ["statsforecast"], } def __init__(self): @@ -504,7 +510,7 @@ def predict(self, h, X=None, level=None): self.prediction_intervals = ConformalIntervals(h=h) level = sorted(level) - coverage = [round(1 - (_l / 100), 2) for _l in level] + coverage = [round(_l / 100, 2) for _l in level] pred_int = self.estimator.predict_interval( fh=range(1, h + 1), X=X, coverage=coverage @@ -532,7 +538,7 @@ def predict_in_sample(self, level=None): return {"fitted": fitted} level = sorted(level) - coverage = [round(1 - (_l / 100), 2) for _l in level] + coverage = [round(_l / 100, 2) for _l in level] pred_int = self.estimator.predict_interval( fh=self.estimator._y.index, X=self.estimator._X, coverage=coverage ) diff --git a/sktime/forecasting/base/adapters/_pmdarima.py b/sktime/forecasting/base/adapters/_pmdarima.py index 4ff3d162b2b..0733b1fbfd4 100644 --- a/sktime/forecasting/base/adapters/_pmdarima.py +++ b/sktime/forecasting/base/adapters/_pmdarima.py @@ -16,6 +16,8 @@ class _PmdArimaAdapter(BaseForecaster): """Base class for interfacing pmdarima.""" _tags = { + "authors": ["mloning", "hyang1996", "kejsitake", "fkiraly"], + "maintainers": "hyang1996", "ignores-exogeneous-X": False, "capability:pred_int": True, "capability:pred_int:insample": True, diff --git a/sktime/forecasting/base/adapters/_pytorch.py b/sktime/forecasting/base/adapters/_pytorch.py new file mode 100644 index 00000000000..76b1f7799f7 --- /dev/null +++ b/sktime/forecasting/base/adapters/_pytorch.py @@ -0,0 +1,245 @@ +from abc import ABC + +import numpy as np +import pandas as pd + +from sktime.forecasting.base import BaseForecaster +from sktime.utils.validation._dependencies import _check_soft_dependencies + +if _check_soft_dependencies("torch", severity="none"): + import torch + + +class BaseDeepNetworkPyTorch(BaseForecaster, ABC): + """Abstract base class for deep learning networks using torch.nn.""" + + _tags = { + "python_dependencies": "torch", + "y_inner_mtype": "pd.DataFrame", + "capability:insample": False, + "capability:pred_int:insample": False, + "scitype:y": "both", + "ignores-exogeneous-X": True, + } + + def __init__( + self, + num_epochs=16, + batch_size=8, + in_channels=1, + individual=False, + criterion_kwargs=None, + optimizer=None, + optimizer_kwargs=None, + lr=0.001, + ): + self.num_epochs = num_epochs + self.batch_size = batch_size + self.in_channels = in_channels + self.individual = individual + self.criterion_kwargs = criterion_kwargs + self.optimizer = optimizer + self.optimizer_kwargs = optimizer_kwargs + self.lr = lr + + super().__init__() + + def _fit(self, y, fh, X=None): + """Fit the network. + + Changes to state: + writes to self._network.state_dict + + Parameters + ---------- + X : iterable-style or map-style dataset + see (https://pytorch.org/docs/stable/data.html) for more information + """ + from sktime.forecasting.base import ForecastingHorizon + + fh = fh.to_relative(self.cutoff) + + if type(fh) is ForecastingHorizon: + self.network = self._build_network(fh._values[-1]) + else: + self.network = self._build_network(fh) + + if self.criterion: + if self.criterion in self.criterions.keys(): + if self.criterion_kwargs: + self._criterion = self.criterions[self.criterion]( + **self.criterion_kwargs + ) + else: + self._criterion = self.criterions[self.criterion]() + else: + raise TypeError( + f"Please pass one of {self.criterions.keys()} for `criterion`." + ) + else: + # default criterion + self._criterion = torch.nn.MSELoss() + + if self.optimizer: + if self.optimizer in self.optimizers.keys(): + if self.optimizer_kwargs: + self._optimizer = self.optimizers[self.optimizer]( + self.network.parameters(), lr=self.lr, **self.optimizer_kwargs + ) + else: + self._optimizer = self.optimizers[self.optimizer]( + self.network.parameters(), lr=self.lr + ) + else: + raise TypeError( + f"Please pass one of {self.optimizers.keys()} for `optimizer`." + ) + else: + # default optimizer + self._optimizer = torch.optim.Adam(self.network.parameters(), lr=self.lr) + + dataloader = self.build_pytorch_train_dataloader(y) + self.network.train() + + for _ in range(self.num_epochs): + for x, y in dataloader: + y_pred = self.network(x) + loss = self._criterion(y_pred, y) + self._optimizer.zero_grad() + loss.backward() + self._optimizer.step() + + def _predict(self, X=None, fh=None): + """Predict with fitted model.""" + from torch import cat + + if fh is None: + fh = self._fh + fh = fh.to_relative(self.cutoff) + + if max(fh._values) > self.network.pred_len or min(fh._values) < 0: + raise ValueError( + f"fh of {fh} passed to {self.__class__.__name__} is not " + "within `pred_len`. Please use a fh that aligns with the `pred_len` of " + "the forecaster." + ) + + if X is None: + dataloader = self.build_pytorch_pred_dataloader(self._y, fh) + else: + dataloader = self.build_pytorch_pred_dataloader(X, fh) + + y_pred = [] + for x, _ in dataloader: + y_pred.append(self.network(x).detach()) + y_pred = cat(y_pred, dim=0).view(-1, y_pred[0].shape[-1]).numpy() + y_pred = y_pred[fh._values.values - 1] + y_pred = pd.DataFrame( + y_pred, columns=self._y.columns, index=fh.to_absolute_index(self.cutoff) + ) + + return y_pred + + def build_pytorch_train_dataloader(self, y): + """Build PyTorch DataLoader for training.""" + from torch.utils.data import DataLoader + + if self.custom_dataset_train: + if hasattr(self.custom_dataset_train, "build_dataset") and callable( + self.custom_dataset_train.build_dataset + ): + self.custom_dataset_train.build_dataset(y) + dataset = self.custom_dataset_train + else: + raise NotImplementedError( + "Custom Dataset `build_dataset` method is not available. Please " + f"refer to the {self.__class__.__name__}.build_dataset " + "documentation." + ) + else: + dataset = PyTorchTrainDataset( + y=y, + seq_len=self.network.seq_len, + fh=self._fh.to_relative(self.cutoff)._values[-1], + ) + + return DataLoader( + dataset, + self.batch_size, + ) + + def build_pytorch_pred_dataloader(self, y, fh): + """Build PyTorch DataLoader for prediction.""" + from torch.utils.data import DataLoader + + if self.custom_dataset_pred: + if hasattr(self.custom_dataset_pred, "build_dataset") and callable( + self.custom_dataset_pred.build_dataset + ): + self.custom_dataset_train.build_dataset(y) + dataset = self.custom_dataset_train + else: + raise NotImplementedError( + "Custom Dataset `build_dataset` method is not available. Please" + f"refer to the {self.__class__.__name__}.build_dataset" + "documentation." + ) + else: + dataset = PyTorchPredDataset( + y=y[-self.network.seq_len :], + seq_len=self.network.seq_len, + ) + + return DataLoader( + dataset, + self.batch_size, + ) + + def get_y_true(self, y): + """Get y_true values for validation.""" + dataloader = self.build_pytorch_pred_dataloader(y) + y_true = [y.flatten().numpy() for _, y in dataloader] + return np.concatenate(y_true, axis=0) + + +class PyTorchTrainDataset: + """Dataset for use in sktime deep learning forecasters.""" + + def __init__(self, y, seq_len, fh): + self.y = y.values + self.seq_len = seq_len + self.fh = fh + + def __len__(self): + """Return length of dataset.""" + return len(self.y) - self.seq_len - self.fh + 1 + + def __getitem__(self, i): + """Return data point.""" + from torch import from_numpy, tensor + + return ( + tensor(self.y[i : i + self.seq_len]).float(), + from_numpy(self.y[i + self.seq_len : i + self.seq_len + self.fh]).float(), + ) + + +class PyTorchPredDataset: + """Dataset for use in sktime deep learning forecasters.""" + + def __init__(self, y, seq_len): + self.y = y.values + self.seq_len = seq_len + + def __len__(self): + """Return length of dataset.""" + return 1 + + def __getitem__(self, i): + """Return data point.""" + from torch import from_numpy, tensor + + return ( + tensor(self.y[i : i + self.seq_len]).float(), + from_numpy(self.y[i + self.seq_len : i + self.seq_len]).float(), + ) diff --git a/sktime/forecasting/base/adapters/_statsforecast.py b/sktime/forecasting/base/adapters/_statsforecast.py index 3da1f4e33ac..1c1a87f5e8d 100644 --- a/sktime/forecasting/base/adapters/_statsforecast.py +++ b/sktime/forecasting/base/adapters/_statsforecast.py @@ -15,6 +15,8 @@ class _StatsForecastAdapter(BaseForecaster): """Base class for interfacing StatsForecast.""" _tags = { + "authors": ["FedericoGarza"], + "maintainers": ["FedericoGarza"], "scitype:y": "univariate", # which y are fine? univariate/multivariate/both "ignores-exogeneous-X": False, # does estimator ignore the exogeneous X? "handles-missing-data": False, # can estimator handle missing data? diff --git a/sktime/forecasting/base/adapters/_statsmodels.py b/sktime/forecasting/base/adapters/_statsmodels.py index 0e3d91ecbc6..1f00fe1066f 100644 --- a/sktime/forecasting/base/adapters/_statsmodels.py +++ b/sktime/forecasting/base/adapters/_statsmodels.py @@ -2,7 +2,7 @@ # copyright: sktime developers, BSD-3-Clause License (see LICENSE file) """Implements adapter for statsmodels forecasters to be used in sktime framework.""" -__author__ = ["mloning"] +__author__ = ["mloning", "ciaran-g"] __all__ = ["_StatsModelsAdapter"] import inspect @@ -19,10 +19,16 @@ class _StatsModelsAdapter(BaseForecaster): _fitted_param_names = () _tags = { + # packaging info + # -------------- + "authors": ["mloning", "ciaran-g"], + "maintainers": ["ciaran-g"], + "python_dependencies": "statsmodels", + # estimator type + # -------------- "ignores-exogeneous-X": True, "requires-fh-in-fit": False, "handles-missing-data": False, - "python_dependencies": "statsmodels", } def __init__(self, random_state=None): @@ -99,7 +105,7 @@ def _predict(self, fh, X): # statsmodels requires zero-based indexing starting at the # beginning of the training series when passing integers start, end = fh.to_absolute_int(self._y.index[0], self.cutoff)[[0, -1]] - fh_abs = fh.to_absolute_index(self.cutoff) + fh_int = fh.to_absolute_int(self._y.index[0], self.cutoff) - len(self._y) # bug fix for evaluate function as test_plus_train indices are passed # statsmodels exog must contain test indices only. @@ -108,7 +114,7 @@ def _predict(self, fh, X): ind_drop = self._X.index X = X.loc[~X.index.isin(ind_drop)] # Entire range of the forecast horizon is required - X = X[: fh_abs[-1]] + X = X.iloc[: (fh_int[-1] + 1)] # include end point if "exog" in inspect.signature(self._forecaster.__init__).parameters.keys(): y_pred = self._fitted_forecaster.predict(start=start, end=end, exog=X) @@ -117,7 +123,9 @@ def _predict(self, fh, X): # statsmodels forecasts all periods from start to end of forecasting # horizon, but only return given time points in forecasting horizon - y_pred = y_pred.loc[fh_abs] + # if fh[0] > 1 steps ahead of cutoff then make relative to `start` + fh_int = fh_int - fh_int[0] + y_pred = y_pred.iloc[fh_int] # ensure that name is not added nor removed # otherwise this may upset conversion to pd.DataFrame y_pred.name = self._y.name @@ -186,7 +194,9 @@ def _predict_interval(self, fh, X, coverage): return BaseForecaster._predict_interval(self, fh, X=X, coverage=coverage) start, end = fh.to_absolute_int(self._y.index[0], self.cutoff)[[0, -1]] - valid_indices = fh.to_absolute(self.cutoff).to_pandas() + fh_int = fh.to_absolute_int(self._y.index[0], self.cutoff) - len(self._y) + # if fh > 1 steps ahead of cutoff + fh_int = fh_int - fh_int[0] get_prediction_arguments = {"start": start, "end": end} @@ -205,17 +215,15 @@ def _predict_interval(self, fh, X, coverage): var_names = self._get_varnames() var_name = var_names[0] columns = pd.MultiIndex.from_product([var_names, coverage, ["lower", "upper"]]) - pred_int = pd.DataFrame(index=valid_indices, columns=columns) + preds_index = self._extract_conf_int(prediction_results, (1 - coverage[0])) + preds_index = preds_index.iloc[fh_int].index + pred_int = pd.DataFrame(index=preds_index, columns=columns) for c in coverage: pred_statsmodels = self._extract_conf_int(prediction_results, (1 - c)) - pred_int[(var_name, c, "lower")] = pred_statsmodels.loc[ - valid_indices, "lower" - ] - pred_int[(var_name, c, "upper")] = pred_statsmodels.loc[ - valid_indices, "upper" - ] + pred_int[(var_name, c, "lower")] = pred_statsmodels.iloc[fh_int]["lower"] + pred_int[(var_name, c, "upper")] = pred_statsmodels.iloc[fh_int]["upper"] return pred_int diff --git a/sktime/forecasting/base/adapters/_tbats.py b/sktime/forecasting/base/adapters/_tbats.py index d0043faa3ea..b3dc70ffa7c 100644 --- a/sktime/forecasting/base/adapters/_tbats.py +++ b/sktime/forecasting/base/adapters/_tbats.py @@ -17,6 +17,7 @@ class _TbatsAdapter(BaseForecaster): """Base class for interfacing tbats forecasting algorithms.""" _tags = { + "authors": ["mloning", "aiwalter", "k1m190r", "fkiraly"], "ignores-exogeneous-X": True, "capability:pred_int": True, "capability:pred_int:insample": True, diff --git a/sktime/forecasting/base/tests/test_base.py b/sktime/forecasting/base/tests/test_base.py index b759bcf8a45..17a22bf027d 100644 --- a/sktime/forecasting/base/tests/test_base.py +++ b/sktime/forecasting/base/tests/test_base.py @@ -14,23 +14,28 @@ from sktime.datatypes import check_is_mtype, convert from sktime.datatypes._utilities import get_cutoff, get_window from sktime.forecasting.arima import ARIMA +from sktime.forecasting.compose import YfromX from sktime.forecasting.naive import NaiveForecaster from sktime.forecasting.theta import ThetaForecaster from sktime.forecasting.var import VAR from sktime.utils._testing.hierarchical import _make_hierarchical from sktime.utils._testing.panel import _make_panel from sktime.utils._testing.series import _make_series +from sktime.utils.parallel import _get_parallel_test_fixtures from sktime.utils.validation._dependencies import _check_estimator_deps PANEL_MTYPES = ["pd-multiindex", "nested_univ", "numpy3D"] HIER_MTYPES = ["pd_multiindex_hier"] +# list of parallelization backends to test +BACKENDS = _get_parallel_test_fixtures("config") + @pytest.mark.skipif( not _check_estimator_deps(ARIMA, severity="none"), reason="skip test if required soft dependency for ARIMA not available", ) -@pytest.mark.parametrize("backend", [None, "joblib", "loky", "threading"]) +@pytest.mark.parametrize("backend", BACKENDS) @pytest.mark.parametrize("mtype", PANEL_MTYPES) def test_vectorization_series_to_panel(mtype, backend): """Test that forecaster vectorization works for Panel data. @@ -43,9 +48,11 @@ def test_vectorization_series_to_panel(mtype, backend): y = _make_panel(n_instances=n_instances, random_state=42, return_mtype=mtype) f = ARIMA() - f.set_config(**{"backend:parallel": backend}) + f.set_config(**backend.copy()) y_pred = f.fit(y).predict([1, 2, 3]) - valid, _, metadata = check_is_mtype(y_pred, mtype, return_metadata=True) + valid, _, metadata = check_is_mtype( + y_pred, mtype, return_metadata=True, msg_return_dict="list" + ) msg = ( f"vectorization of forecasters does not work for test example " @@ -81,7 +88,7 @@ def test_vectorization_series_to_panel(mtype, backend): not _check_estimator_deps(ARIMA, severity="none"), reason="skip test if required soft dependency for ARIMA not available", ) -@pytest.mark.parametrize("backend", [None, "joblib", "loky", "threading"]) +@pytest.mark.parametrize("backend", BACKENDS) @pytest.mark.parametrize("mtype", HIER_MTYPES) def test_vectorization_series_to_hier(mtype, backend): """Test that forecaster vectorization works for Hierarchical data. @@ -96,9 +103,11 @@ def test_vectorization_series_to_hier(mtype, backend): y = convert(y, from_type="pd_multiindex_hier", to_type=mtype) f = ARIMA() - f.set_config(**{"backend:parallel": backend}) + f.set_config(**backend.copy()) y_pred = f.fit(y).predict([1, 2, 3]) - valid, _, metadata = check_is_mtype(y_pred, mtype, return_metadata=True) + valid, _, metadata = check_is_mtype( + y_pred, mtype, return_metadata=True, msg_return_dict="list" + ) msg = ( f"vectorization of forecasters does not work for test example " @@ -158,7 +167,9 @@ def test_vectorization_series_to_panel_proba(method, mtype): else: RuntimeError(f"bug in test, unreachable state, method {method} queried") - valid, _, _ = check_is_mtype(y_pred, expected_mtype, return_metadata=True) + valid, _, _ = check_is_mtype( + y_pred, expected_mtype, return_metadata=True, msg_return_dict="list" + ) msg = ( f"vectorization of forecaster method {method} does not work for test example " @@ -194,7 +205,9 @@ def test_vectorization_series_to_hier_proba(method, mtype): else: RuntimeError(f"bug in test, unreachable state, method {method} queried") - valid, _, _ = check_is_mtype(y_pred, expected_mtype, return_metadata=True) + valid, _, _ = check_is_mtype( + y_pred, expected_mtype, return_metadata=True, msg_return_dict="list" + ) msg = ( f"vectorization of forecaster method {method} does not work for test example " @@ -251,7 +264,9 @@ def test_vectorization_multivariate(mtype, exogeneous): est = ARIMA().fit(y=y_fit, X=X_fit, fh=[1, 2, 3]) y_pred = est.predict(X=X_pred) - valid, _, metadata = check_is_mtype(y_pred, mtype, return_metadata=True) + valid, _, metadata = check_is_mtype( + y_pred, mtype, return_metadata=True, msg_return_dict="list" + ) msg = ( f"vectorization of forecasters does not work for test example " @@ -441,3 +456,25 @@ def test_range_fh_in_predict(): assert isinstance(var_predictions, pd.DataFrame) assert var_predictions.shape == (10 * 2, 5) + + +def test_remember_data(): + """Test that the ``remember_data`` flag works as expected.""" + from sktime.datasets import load_airline + + y = load_airline() + X = load_airline() + f = YfromX.create_test_instance() + + # turn off remembering _X, _y by config + f.set_config(**{"remember_data": False}) + f.fit(y, X, fh=[1, 2, 3]) + + assert f._X is None + assert f._y is None + + f.set_config(**{"remember_data": True}) + f.fit(y, X, fh=[1, 2, 3]) + + assert f._X is not None + assert f._y is not None diff --git a/sktime/forecasting/base/tests/test_fh.py b/sktime/forecasting/base/tests/test_fh.py index 873313edaa9..5241634391f 100644 --- a/sktime/forecasting/base/tests/test_fh.py +++ b/sktime/forecasting/base/tests/test_fh.py @@ -319,11 +319,20 @@ def test_get_duration(n_timepoints, index_type): _make_index(n_timepoints, index_type) -FIXED_FREQUENCY_STRINGS = ["10T", "H", "D", "2D"] +FIXED_FREQUENCY_STRINGS = ["10min", "H", "D", "2D"] NON_FIXED_FREQUENCY_STRINGS = ["W-WED", "W-SUN", "W-SAT", "M"] FREQUENCY_STRINGS = [*FIXED_FREQUENCY_STRINGS, *NON_FIXED_FREQUENCY_STRINGS] +def _get_expected_freqstr(freqstr): + # special case for 10min, T is being deprecated and replaced by min + if freqstr == "10min": + fh_freqstr_expected = "10T" + else: + fh_freqstr_expected = freqstr + return fh_freqstr_expected + + @pytest.mark.parametrize("freqstr", FREQUENCY_STRINGS) def test_to_absolute_freq(freqstr): """Test conversion when anchorings included in frequency.""" @@ -332,7 +341,7 @@ def test_to_absolute_freq(freqstr): fh = ForecastingHorizon([1, 2, 3]) abs_fh = fh.to_absolute(cutoff) - assert abs_fh._values.freqstr == freqstr + assert abs_fh._values.freqstr == _get_expected_freqstr(freqstr) @pytest.mark.parametrize("freqstr", FREQUENCY_STRINGS) @@ -346,7 +355,8 @@ def test_absolute_to_absolute_with_integer_horizon(freqstr): converted_abs_fh = abs_fh.to_relative(cutoff).to_absolute(cutoff) assert_array_equal(abs_fh, converted_abs_fh) - assert converted_abs_fh._values.freqstr == freqstr + fh_freqstr = converted_abs_fh._values.freqstr + assert fh_freqstr == _get_expected_freqstr(freqstr) @pytest.mark.parametrize("freqstr", FIXED_FREQUENCY_STRINGS) @@ -363,7 +373,8 @@ def test_absolute_to_absolute_with_timedelta_horizon(freqstr): converted_abs_fh = abs_fh.to_relative(cutoff).to_absolute(cutoff) assert_array_equal(abs_fh, converted_abs_fh) - assert converted_abs_fh._values.freqstr == freqstr + + assert converted_abs_fh._values.freqstr == _get_expected_freqstr(freqstr) @pytest.mark.parametrize("freqstr", FREQUENCY_STRINGS) @@ -728,3 +739,60 @@ def test_empty_range_in_fh(): """Test when ``range`` has zero length.""" empty_range = ForecastingHorizon(values=range(-5)) assert (empty_range == ForecastingHorizon(values=[])).all() + + +def test_fh_expected_pred(): + """Test for expected prediction index method.""" + fh = ForecastingHorizon([1, 2, 3]) + y_pred_idx = fh.get_expected_pred_idx(pd.Index([2, 3, 4])) + + assert y_pred_idx.equals(pd.Index([5, 6, 7])) + + y_df = pd.DataFrame([1, 2, 3], index=[2, 3, 4]) + y_pred_idx = fh.get_expected_pred_idx(y_df) + + assert y_pred_idx.equals(pd.Index([5, 6, 7])) + + # pd.MultiIndex case, 2 levels + idx = pd.MultiIndex.from_tuples([("a", 3), ("a", 5), ("b", 4), ("b", 5), ("b", 6)]) + y_pred_idx = fh.get_expected_pred_idx(idx) + + y_pred_idx_expected = pd.MultiIndex.from_tuples( + [("a", 6), ("a", 7), ("a", 8), ("b", 7), ("b", 8), ("b", 9)] + ) + assert y_pred_idx.equals(y_pred_idx_expected) + + y_pred_idx = fh.get_expected_pred_idx(idx, sort_by_time=True) + y_pred_idx_expected = pd.MultiIndex.from_tuples( + [("a", 6), ("a", 7), ("b", 7), ("a", 8), ("b", 8), ("b", 9)] + ) + assert y_pred_idx.equals(y_pred_idx_expected) + + # pd.MultiIndex case, 3 levels + idx = pd.MultiIndex.from_tuples( + [("a", 3, 4), ("a", 3, 5), ("b", 5, 4), ("b", 5, 5), ("b", 5, 6)] + ) + y_pred_idx = fh.get_expected_pred_idx(idx) + + y_pred_idx_expected = pd.MultiIndex.from_tuples( + [("a", 3, 6), ("a", 3, 7), ("a", 3, 8), ("b", 5, 7), ("b", 5, 8), ("b", 5, 9)] + ) + assert y_pred_idx.equals(y_pred_idx_expected) + + y_pred_idx = fh.get_expected_pred_idx(idx, sort_by_time=True) + + y_pred_idx_expected = pd.MultiIndex.from_tuples( + [("a", 3, 6), ("a", 3, 7), ("b", 5, 7), ("a", 3, 8), ("b", 5, 8), ("b", 5, 9)] + ) + assert y_pred_idx.equals(y_pred_idx_expected) + + +def test_tz_preserved(): + """Test that time zone information is preserved in to_absolute. + + Failure case in issue #5584. + """ + cutoff = pd.Timestamp("2020-01-01", tz="utc") + fh_absolute = ForecastingHorizon(range(100), freq="h").to_absolute(cutoff) + + assert fh_absolute[0].tz == cutoff.tz diff --git a/sktime/forecasting/bats.py b/sktime/forecasting/bats.py index 0f1413fdd9a..5ea5d68b35a 100644 --- a/sktime/forecasting/bats.py +++ b/sktime/forecasting/bats.py @@ -77,6 +77,7 @@ class BATS(_TbatsAdapter): See Also -------- TBATS + StatsForecastAutoTBATS References ---------- diff --git a/sktime/forecasting/compose/__init__.py b/sktime/forecasting/compose/__init__.py index 537afc45512..30b0c1971c3 100644 --- a/sktime/forecasting/compose/__init__.py +++ b/sktime/forecasting/compose/__init__.py @@ -6,6 +6,7 @@ "HierarchyEnsembleForecaster", "ColumnEnsembleForecaster", "EnsembleForecaster", + "FallbackForecaster", "AutoEnsembleForecaster", "TransformedTargetForecaster", "ForecastingPipeline", @@ -18,6 +19,7 @@ "RecursiveTimeSeriesRegressionForecaster", "DirRecTabularRegressionForecaster", "DirRecTimeSeriesRegressionForecaster", + "DirectReductionForecaster", "StackingForecaster", "MultiplexForecaster", "make_reduction", @@ -26,6 +28,7 @@ "ForecastByLevel", "Permute", "YfromX", + "IgnoreX", ] from sktime.forecasting.compose._bagging import BaggingForecaster @@ -34,9 +37,11 @@ AutoEnsembleForecaster, EnsembleForecaster, ) +from sktime.forecasting.compose._fallback import FallbackForecaster from sktime.forecasting.compose._fhplex import FhPlexForecaster from sktime.forecasting.compose._grouped import ForecastByLevel from sktime.forecasting.compose._hierarchy_ensemble import HierarchyEnsembleForecaster +from sktime.forecasting.compose._ignore_x import IgnoreX from sktime.forecasting.compose._multiplexer import MultiplexForecaster from sktime.forecasting.compose._pipeline import ( ForecastingPipeline, @@ -45,6 +50,7 @@ TransformedTargetForecaster, ) from sktime.forecasting.compose._reduce import ( + DirectReductionForecaster, DirectTabularRegressionForecaster, DirectTimeSeriesRegressionForecaster, DirRecTabularRegressionForecaster, diff --git a/sktime/forecasting/compose/_bagging.py b/sktime/forecasting/compose/_bagging.py index 3a257f1564a..72b9d036c92 100644 --- a/sktime/forecasting/compose/_bagging.py +++ b/sktime/forecasting/compose/_bagging.py @@ -8,19 +8,13 @@ import numpy as np import pandas as pd -from sklearn import clone from sklearn.utils import check_random_state from sktime.datatypes._utilities import update_data from sktime.forecasting.base import BaseForecaster from sktime.forecasting.ets import AutoETS from sktime.transformations.base import BaseTransformer -from sktime.transformations.bootstrap import ( - MovingBlockBootstrapTransformer, - STLBootstrapTransformer, -) -from sktime.utils.estimators import MockForecaster -from sktime.utils.random_state import set_random_state +from sktime.transformations.bootstrap import STLBootstrapTransformer class BaggingForecaster(BaseForecaster): @@ -38,15 +32,15 @@ class BaggingForecaster(BaseForecaster): Parameters ---------- - bootstrap_transformer : BaseTransformer - (sktime.transformations.bootstrap.STLBootstrapTransformer) + bootstrap_transformer : sktime transformer BaseTransformer descendant instance + (default = sktime.transformations.bootstrap.STLBootstrapTransformer) Bootstrapping Transformer that takes a series (with tag scitype:transform-input=Series) as input and returns a panel (with tag scitype:transform-input=Panel) of bootstrapped time series if not specified sktime.transformations.bootstrap.STLBootstrapTransformer is used. - forecaster : BaseForecaster (sktime.forecating.ets.AutoETS) - A valid sktime Forecaster. If not specified sktime.forecating.ets.AutoETS is - used. + forecaster : sktime forecaster, BaseForecaster descendant instance, optional + (default = sktime.forecating.ets.AutoETS) + If not specified, sktime.forecating.ets.AutoETS is used. sp: int (default=2) Seasonal period for default Forecaster and Transformer. Must be 2 or greater. Ignored for the bootstrap_transformer and forecaster if they are specified. @@ -88,6 +82,7 @@ class BaggingForecaster(BaseForecaster): """ _tags = { + "authors": ["ltsaprounis"], "scitype:y": "univariate", # which y are fine? univariate/multivariate/both "ignores-exogeneous-X": True, # does estimator ignore the exogeneous X? "handles-missing-data": False, # can estimator handle missing data? @@ -161,13 +156,17 @@ def _fit(self, y, X, fh): """ if self.bootstrap_transformer is None: self.bootstrap_transformer_ = STLBootstrapTransformer(sp=self.sp) + elif hasattr(self.bootstrap_transformer, "clone"): + self.bootstrap_transformer_ = self.bootstrap_transformer.clone() else: + from sklearn import clone + self.bootstrap_transformer_ = clone(self.bootstrap_transformer) if self.forecaster is None: self.forecaster_ = AutoETS(sp=self.sp) else: - self.forecaster_ = clone(self.forecaster) + self.forecaster_ = self.forecaster.clone() if ( self.bootstrap_transformer_.get_tag( @@ -192,8 +191,6 @@ def _fit(self, y, X, fh): # random state handling passed into input estimators self.random_state_ = check_random_state(self.random_state) - set_random_state(self.bootstrap_transformer_, random_state=self.random_state_) - set_random_state(self.forecaster_, random_state=self.random_state_) self.bootstrap_transformer_.fit(X=y) y_bootstraps = self.bootstrap_transformer_.transform(X=y) self.forecaster_.fit(y=y_bootstraps, fh=fh, X=None) @@ -303,6 +300,8 @@ def get_test_params(cls): `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. `create_test_instance` uses the first (or only) dictionary in `params` """ + from sktime.transformations.bootstrap import MovingBlockBootstrapTransformer + from sktime.utils.estimators import MockForecaster from sktime.utils.validation._dependencies import _check_soft_dependencies params = [ diff --git a/sktime/forecasting/compose/_column_ensemble.py b/sktime/forecasting/compose/_column_ensemble.py index a700c64cec7..7a362ee7fe1 100644 --- a/sktime/forecasting/compose/_column_ensemble.py +++ b/sktime/forecasting/compose/_column_ensemble.py @@ -88,6 +88,7 @@ class ColumnEnsembleForecaster(_HeterogenousEnsembleForecaster, _ColumnEstimator """ _tags = { + "authors": ["GuzalBulatova", "mloning", "fkiraly"], "scitype:y": "both", "ignores-exogeneous-X": False, "y_inner_mtype": PANDAS_MTYPES, diff --git a/sktime/forecasting/compose/_ensemble.py b/sktime/forecasting/compose/_ensemble.py index f523479d63f..5f3c46e7d75 100644 --- a/sktime/forecasting/compose/_ensemble.py +++ b/sktime/forecasting/compose/_ensemble.py @@ -104,6 +104,7 @@ class AutoEnsembleForecaster(_HeterogenousEnsembleForecaster): """ _tags = { + "authors": ["mloning", "GuzalBulatova", "aiwalter", "RNKuhns", "AnH0ang"], "ignores-exogeneous-X": False, "requires-fh-in-fit": False, "handles-missing-data": False, @@ -310,6 +311,7 @@ class EnsembleForecaster(_HeterogenousEnsembleForecaster): """ _tags = { + "authors": ["mloning", "GuzalBulatova", "aiwalter", "RNKuhns", "AnH0ang"], "ignores-exogeneous-X": False, "requires-fh-in-fit": False, "handles-missing-data": False, @@ -364,8 +366,14 @@ def _predict(self, fh, X): """ names, _ = self._check_forecasters() y_pred = pd.concat(self._predict_forecasters(fh, X), axis=1, keys=names) - y_pred = y_pred.groupby(level=1, axis=1).agg( - _aggregate, self.aggfunc, self.weights + y_pred = ( + y_pred.T.groupby(level=1) + .agg( + lambda y, aggfunc, weights: _aggregate(y.T, aggfunc, weights), + self.aggfunc, + self.weights, + ) + .T ) return y_pred diff --git a/sktime/forecasting/compose/_fallback.py b/sktime/forecasting/compose/_fallback.py new file mode 100644 index 00000000000..e23f5f5beac --- /dev/null +++ b/sktime/forecasting/compose/_fallback.py @@ -0,0 +1,257 @@ +#!/usr/bin/env python3 -u +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file). +""" +Implements the FallbackForecaster. + +The FallbackForecaster works with a list of forecasters and tries to fit them in order. +If the active forecaster fails during prediction, it proceeds to the next. This ensures +a robust forecasting mechanism by providing fallback options. +""" + +__author__ = ["ninedigits"] +__all__ = ["FallbackForecaster"] + +from sktime.base import _HeterogenousMetaEstimator +from sktime.datatypes import ALL_TIME_SERIES_MTYPES +from sktime.forecasting.base._delegate import _DelegatedForecaster +from sktime.utils.warnings import warn + + +class FallbackForecaster(_HeterogenousMetaEstimator, _DelegatedForecaster): + """Forecaster that sequentially tries a list of forecasting models. + + Attempts to fit the provided forecasters in the order they are given. If a + forecaster fails during fitting or prediction, it proceeds to the next one. This + class is useful in scenarios where the reliability of individual forecasting models + may be in question, and a fallback mechanism is desired. + + Parameters + ---------- + forecasters : list of forecasters, or + list of tuples (str, estimator) of sktime forecasters + Forecasters to be tried sequentially. + These are "blueprint" transformers resp forecasters, + forecaster states do not change when `fit` is called + + verbose : bool, default=False + If True, raises warnings when a forecaster fails to fit or predict. + + Attributes + ---------- + forecasters_ : list of (str, estimator) tuples + The forecasters to be tried sequentially. + Forecasters that have been fitted successfully are stored in this list. + first_nonfailing_forecaster_index_ : int + Index of the first non-failing forecaster in the list of forecasters. + current_forecaster_ : sktime forecaster + pointer to the first forecaster that was successfully fitted + same as ``forecasters_[first_nonfailing_forecaster_index_][1]`` + current_name_ : str + name of the current forecaster + same as ``forecasters_[first_nonfailing_forecaster_index_][0]`` + exceptions_raised_ : dict + dictionary of exceptions raised by forecasters during fitting or prediction + keys are int indices of forecasters in the list of forecasters + values are dicts with keys "failed_at_step", "exception", "forecaster_name" + failed_at_step is either "fit" or "predict" + exception is the exception raised by the forecaster + forecaster_name is the name of the forecaster + + Examples + -------- + >>> from sktime.forecasting.naive import NaiveForecaster + >>> from sktime.forecasting.compose import FallbackForecaster + >>> from sktime.forecasting.compose import EnsembleForecaster + >>> from sktime.forecasting.trend import PolynomialTrendForecaster + >>> from sktime.datasets import load_airline + >>> y = load_airline() + >>> # first fit polyomial trend, if fails make naive forecast + >>> forecasters = [ + ... ("poly", PolynomialTrendForecaster()), + ... ("naive", NaiveForecaster()) + ... ] + >>> forecaster = FallbackForecaster(forecasters=forecasters) + >>> forecaster.fit(y=y, fh=[1, 2, 3]) + FallbackForecaster(...) + >>> y_pred = forecaster.predict() + """ + + _tags = { + "authors": ["ninedigits"], + "maintainers": ["ninedigits"], + "handles-missing-data": True, + "scitype:y": "both", + "y_inner_mtype": ALL_TIME_SERIES_MTYPES, + "X_inner_mtype": ALL_TIME_SERIES_MTYPES, + "fit_is_empty": False, + } + # for default get_params/set_params from _HeterogenousMetaEstimator + # _steps_attr points to the attribute of self + # which contains the heterogeneous set of estimators + # this must be an iterable of (name: str, estimator, ...) tuples for the default + _steps_attr = "_forecasters" + # if the estimator is fittable, _HeterogenousMetaEstimator also + # provides an override for get_fitted_params for params from the fitted estimators + # the fitted estimators should be in a different attribute, _steps_fitted_attr + # this must be an iterable of (name: str, estimator, ...) tuples for the default + _steps_fitted_attr = "forecasters_" + + def __init__(self, forecasters, verbose=False): + super().__init__() + + self.forecasters = forecasters + self.current_forecaster_ = None + self.current_name_ = None + self.verbose = verbose + + self._forecasters = self._check_estimators( + forecasters, "forecasters", clone_ests=False + ) + self.forecasters_ = self._check_estimators(forecasters, "forecasters") + + self._anytagis_then_set("requires-fh-in-fit", True, False, self._forecasters) + self._anytagis_then_set("capability:pred_int", False, True, self._forecasters) + + def _get_delegate(self): + return self.current_forecaster_ + + def _fit(self, y, X=None, fh=None): + """Fit the forecasters in the given order until one succeeds. + + Parameters + ---------- + y : array-like + Target time series to which to fit the forecasters. + X : array-like, optional (default=None) + Exogenous variables. + fh : array-like, optional (default=None) + The forecasting horizon. + + Returns + ------- + self : an instance of self + + Raises + ------ + RuntimeError + If all forecasters fail to fit. + """ + self.first_nonfailing_forecaster_index_ = 0 + self.exceptions_raised_ = dict() + return self._try_fit_forecasters(y=y, X=X, fh=fh) + + def _try_fit_forecasters(self, y, X, fh): + """ + Attempt to fit the forecasters in sequence until one succeeds. + + This method iterates over the forecasters starting from the index + `first_nonfailing_forecaster_index_`. For each forecaster, it tries to fit it + with the current data. If the fit method of a forecaster raises an exception, + it records the exception and proceeds to the next forecaster. If a forecaster + fits successfully, it updates the current forecaster and its name. + + Returns + ------- + self : an instance of self + + Raises + ------ + RuntimeError + If all forecasters fail to fit. + """ + while True: + ix = self.first_nonfailing_forecaster_index_ + if self.first_nonfailing_forecaster_index_ >= len(self.forecasters_): + raise RuntimeError("No remaining forecasters to attempt prediction.") + name, forecaster = self.forecasters_[ix] + try: + self.current_name_ = name + self.current_forecaster_ = forecaster.clone() + self.current_forecaster_.fit(y=y, X=X, fh=fh) + return self + except Exception as e: + self.exceptions_raised_[self.first_nonfailing_forecaster_index_] = { + "failed_at_step": "fit", + "exception": e, + "forecaster_name": name, + } + self.first_nonfailing_forecaster_index_ += 1 + if self.verbose: + warn( + f"Forecaster {name} failed to fit with error: {e}", + stacklevel=2, + obj=self, + ) + + def _predict(self, fh, X=None): + """Predict using the current forecaster. + + If predict fails, fit and predict with the next forecaster. + + Parameters + ---------- + fh : array-like + The forecasting horizon. + X : array-like, optional (default=None) + Exogenous variables. + + Returns + ------- + y_pred : array-like + The predicted values. + + Raises + ------ + RuntimeError + If no forecaster is fitted or all forecasters fail to predict. + """ + if self.current_forecaster_ is None: + raise RuntimeError("No forecaster has been successfully fitted yet.") + + try: + return self.current_forecaster_.predict(fh, X) + except Exception as e: + self.exceptions_raised_[self.first_nonfailing_forecaster_index_] = { + "failed_at_step": "predict", + "exception": e, + "forecaster_name": self.current_name_, + } + if self.verbose: + warn( + f"Current forecaster failed at prediction with error: {e}", + stacklevel=2, + obj=self, + ) + self.first_nonfailing_forecaster_index_ += 1 + + # Fit the next forecaster and retry prediction + self.current_forecaster_ = None + self._try_fit_forecasters(self._y, self._X, self._fh) + return self.predict(fh, X) + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + + Returns + ------- + params : dict or list of dict + """ + from sktime.forecasting.compose._reduce import YfromX + from sktime.forecasting.naive import NaiveForecaster + + # univariate case + FORECASTER = NaiveForecaster() + params = [{"forecasters": [("f1", FORECASTER), ("f2", FORECASTER)]}] + + # test multivariate case, i.e., ensembling multiple variables at same time + FORECASTER2 = YfromX.create_test_instance() + params = params + [{"forecasters": [FORECASTER2, FORECASTER]}] + + return params diff --git a/sktime/forecasting/compose/_fhplex.py b/sktime/forecasting/compose/_fhplex.py index db9b266a2d1..d48acd97d42 100644 --- a/sktime/forecasting/compose/_fhplex.py +++ b/sktime/forecasting/compose/_fhplex.py @@ -81,6 +81,7 @@ class FhPlexForecaster(BaseForecaster): """ _tags = { + "authors": "fkiraly", "requires-fh-in-fit": True, "handles-missing-data": True, "scitype:y": "both", diff --git a/sktime/forecasting/compose/_grouped.py b/sktime/forecasting/compose/_grouped.py index f88a8955570..c2c4e44a4d2 100644 --- a/sktime/forecasting/compose/_grouped.py +++ b/sktime/forecasting/compose/_grouped.py @@ -53,6 +53,7 @@ class ForecastByLevel(_DelegatedForecaster): """ _tags = { + "authors": ["fkiraly"], "requires-fh-in-fit": False, "handles-missing-data": True, "scitype:y": "both", @@ -74,7 +75,7 @@ def __init__(self, forecaster, groupby="local"): super().__init__() - self.clone_tags(self.forecaster_) + self._set_delegated_tags(self.forecaster_) self.set_tags(**{"fit_is_empty": False}) if groupby == "local": diff --git a/sktime/forecasting/compose/_hierarchy_ensemble.py b/sktime/forecasting/compose/_hierarchy_ensemble.py index 1eca3af0351..bcc47d5d262 100644 --- a/sktime/forecasting/compose/_hierarchy_ensemble.py +++ b/sktime/forecasting/compose/_hierarchy_ensemble.py @@ -93,6 +93,8 @@ class HierarchyEnsembleForecaster(_HeterogenousEnsembleForecaster): """ _tags = { + "authors": ["VyomkeshVyas"], + "maintainers": ["VyomkeshVyas"], "scitype:y": "both", "ignores-exogeneous-X": False, "y_inner_mtype": ["pd.DataFrame", "pd-multiindex", "pd_multiindex_hier"], @@ -285,7 +287,8 @@ def _get_node_dict(self, z): if counter == 0: nodes = mi else: - nodes.append(mi) + # For nlevels = 2, 'nodes' is pd.Index object (L286) + nodes = nodes.append(mi) else: node_l = [] for i in range(len(node)): @@ -495,6 +498,7 @@ def _check_forecasters(self, y, z): raise ValueError("Nodes cannot be empty.") if z.index.nlevels == 2: nodes_ix = pd.Index(nodes) + nodes_t += nodes else: nodes_l = [] for i in range(len(nodes)): diff --git a/sktime/forecasting/compose/_ignore_x.py b/sktime/forecasting/compose/_ignore_x.py new file mode 100644 index 00000000000..6ff8e8bdb5f --- /dev/null +++ b/sktime/forecasting/compose/_ignore_x.py @@ -0,0 +1,76 @@ +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +"""Implements compositor for ignoring exogenous data.""" + +__author__ = ["fkiraly"] + +from sktime.forecasting.base._delegate import _DelegatedForecaster + + +class IgnoreX(_DelegatedForecaster): + """Compositor for ignoring exogenous variables. + + Composing with IgnoreX instructs the wrapped forecaster to ignore exogenous + data. This is useful for testing the impact of exogenous data on forecasts, + or for use in tuning hyperparameters of the forecaster. + + Parameters + ---------- + forecaster : sktime forecaster, BaseForecaster descendant instance + The forecaster to wrap. + ignore_x : bool, optional (default=True) + Whether to ignore exogenous data or not, this parameter is useful for tuning. + True: ignore exogenous data, X is not passed on to ``forecaster`` + False: use exogenous data, X is passed on to ``forecaster`` + + Attributes + ---------- + forecaster_ : clone of forecaster + The fitted forecaster. + """ + + # attribute for _DelegatedForecaster, which then delegates + # all non-overridden methods are same as of getattr(self, _delegate_name) + # see further details in _DelegatedForecaster docstring + _delegate_name = "forecaster_" + + _tags = { + "ignores-exogeneous-X": True, + } + + def __init__(self, forecaster, ignore_x=True): + self.forecaster = forecaster + self.ignore_x = ignore_x + + super().__init__() + + self.forecaster_ = forecaster.clone() + + self._set_delegated_tags(self.forecaster_) + self.set_tags(**{"ignores-exogeneous-X": True}) + + if not ignore_x: + self.set_tags(**{"ignores-exogeneous-X": ignore_x}) + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + + + Returns + ------- + params : dict or list of dict + """ + from sktime.forecasting.naive import NaiveForecaster + + f = NaiveForecaster() + + params1 = {"forecaster": f} + params2 = {"forecaster": f, "ignore_x": False} + + return [params1, params2] diff --git a/sktime/forecasting/compose/_multiplexer.py b/sktime/forecasting/compose/_multiplexer.py index 3bd81ee8ba0..4b48bcc2db7 100644 --- a/sktime/forecasting/compose/_multiplexer.py +++ b/sktime/forecasting/compose/_multiplexer.py @@ -77,6 +77,7 @@ class MultiplexForecaster(_HeterogenousMetaEstimator, _DelegatedForecaster): """ _tags = { + "authors": ["kkoralturk", "aiwalter", "fkiraly", "miraep8"], "requires-fh-in-fit": False, "handles-missing-data": False, "scitype:y": "both", @@ -118,7 +119,7 @@ def __init__( ) self._set_forecaster() - self.clone_tags(self.forecaster_) + self._set_delegated_tags() self.set_tags(**{"fit_is_empty": False}) # this ensures that we convert in the inner estimator, not in the multiplexer self.set_tags(**{"y_inner_mtype": ALL_TIME_SERIES_MTYPES}) diff --git a/sktime/forecasting/compose/_pipeline.py b/sktime/forecasting/compose/_pipeline.py index a86242c75f9..7c73f252094 100644 --- a/sktime/forecasting/compose/_pipeline.py +++ b/sktime/forecasting/compose/_pipeline.py @@ -170,7 +170,7 @@ def _get_inverse_transform(self, transformers, y, X=None, mode=None): if len(levels) == 1: levels = levels[0] yt[ix] = y.xs(ix, level=levels, axis=1) - # todo 0.25.0 - check why this cannot be easily removed + # todo 0.27.0 - check why this cannot be easily removed # in theory, we should get rid of the "Coverage" case treatment # (the legacy naming convention was removed in 0.23.0) # deal with the "Coverage" case, we need to get rid of this @@ -391,6 +391,7 @@ class ForecastingPipeline(_Pipeline): """ _tags = { + "authors": ["mloning", "fkiraly", "aiwalter"], "scitype:y": "both", "y_inner_mtype": SUPPORTED_MTYPES, "X_inner_mtype": SUPPORTED_MTYPES, @@ -814,6 +815,7 @@ class TransformedTargetForecaster(_Pipeline): """ _tags = { + "authors": ["mloning", "fkiraly", "aiwalter"], "scitype:y": "both", "y_inner_mtype": SUPPORTED_MTYPES, "X_inner_mtype": SUPPORTED_MTYPES, @@ -843,6 +845,21 @@ def __init__(self, steps): self.clone_tags(self.forecaster_, tags_to_clone) self._anytagis_then_set("fit_is_empty", False, True, self.steps_) + # above, we cloned the ignores-exogeneous-X tag, + # but we also need to check whether X is used as y in some transformer + # in this case X is not ignored by the pipe, even if the forecaster ignores it + # logic below checks whether there is at least one such transformer + # if there is, we override the ignores-exogeneous-X tag to False + # also see discussion in bug issue #5518 + pre_ts = self.transformers_pre_ + post_ts = self.transformers_post_ + pre_use_y = [est.get_tag("y_inner_mtype") != "None" for _, est in pre_ts] + post_use_y = [est.get_tag("y_inner_mtype") != "None" for _, est in post_ts] + any_t_use_y = any(pre_use_y) or any(post_use_y) + + if any_t_use_y: + self.set_tags(**{"ignores-exogeneous-X": False}) + @property def forecaster_(self): """Return reference to the forecaster in the pipeline. @@ -1259,6 +1276,7 @@ class ForecastX(BaseForecaster): """ _tags = { + "authors": ["fkiraly", "benheid", "yarnabrina"], "X_inner_mtype": SUPPORTED_MTYPES, "y_inner_mtype": SUPPORTED_MTYPES, "scitype:y": "both", @@ -1692,6 +1710,7 @@ class Permute(_DelegatedForecaster, BaseForecaster, _HeterogenousMetaEstimator): """ _tags = { + "authors": "aiwalter", "scitype:y": "both", "y_inner_mtype": ALL_TIME_SERIES_MTYPES, "X_inner_mtype": ALL_TIME_SERIES_MTYPES, @@ -1711,17 +1730,8 @@ def __init__(self, estimator, permutation=None, steps_arg="steps"): self.steps_arg = steps_arg super().__init__() - tags_to_clone = [ - "ignores-exogeneous-X", # does estimator ignore the exogeneous X? - "capability:insample", - "capability:pred_int", # can the estimator produce prediction intervals? - "capability:pred_int:insample", - "requires-fh-in-fit", # is forecasting horizon already required in fit? - "enforce_index_type", # index type that needs to be enforced in X/y - "fit_is_empty", - ] - self.clone_tags(self.estimator, tags_to_clone) + self._set_delegated_tags(estimator) self._set_permuted_estimator() diff --git a/sktime/forecasting/compose/_reduce.py b/sktime/forecasting/compose/_reduce.py index 4f92895012c..b383f38fc3b 100644 --- a/sktime/forecasting/compose/_reduce.py +++ b/sktime/forecasting/compose/_reduce.py @@ -5,10 +5,12 @@ __author__ = [ "mloning", "AyushmaanSeth", + "danbartl", "kAnand77", "LuisZugasti", "Lovkush-A", "fkiraly", + "benheid", ] __all__ = [ @@ -32,7 +34,6 @@ from sktime.datatypes._utilities import get_time_index from sktime.forecasting.base import BaseForecaster, ForecastingHorizon -from sktime.forecasting.base._base import DEFAULT_ALPHA from sktime.forecasting.base._fh import _index_range from sktime.forecasting.base._sktime import _BaseWindowForecaster from sktime.regression.base import BaseRegressor @@ -40,7 +41,7 @@ from sktime.transformations.series.summarize import WindowSummarizer from sktime.utils.datetime import _shift from sktime.utils.estimators.dispatch import construct_dispatch -from sktime.utils.sklearn import is_sklearn_regressor +from sktime.utils.sklearn import is_sklearn_regressor, prep_skl_df from sktime.utils.validation import check_window_length from sktime.utils.warnings import warn @@ -184,22 +185,33 @@ def _sliding_window_transform( Xt = Zt[:, :, :window_length] # Pre-allocate array for sliding windows. # If the scitype is tabular regression, we have to convert X into a 2d array. - if scitype == "tabular-regressor": - if transformers is not None: - return yt, Xt - else: - return yt, Xt.reshape(Xt.shape[0], -1) - else: - return yt, Xt + if scitype == "tabular-regressor" and transformers is None: + Xt = Xt.reshape(Xt.shape[0], -1) + + assert Xt.ndim == 2 or Xt.ndim == 3 + assert yt.ndim == 2 + + return yt, Xt class _Reducer(_BaseWindowForecaster): """Base class for reducing forecasting to regression.""" _tags = { + "authors": [ + "mloning", + "AyushmaanSeth", + "danbartl", + "kAnand77", + "LuisZugasti", + "Lovkush-A", + "fkiraly", + "benheid", + ], "ignores-exogeneous-X": False, # reduction uses X in non-trivial way "handles-missing-data": True, "capability:insample": False, + "capability:pred_int": True, } def __init__( @@ -221,6 +233,25 @@ def __init__( # therefore this is commented out until sktime and sklearn are better aligned # self.set_tags(**{"handles-missing-data": estimator._get_tags()["allow_nan"]}) + # for dealing with probabilistic regressors: + # self._est_type encodes information what type of estimator is passed + if hasattr(estimator, "get_tags"): + _est_type = estimator.get_tag("object_type", "regressor", False) + else: + _est_type = "regressor" + + if _est_type not in ["regressor", "regressor_proba"]: + raise TypeError( + f"error in {type(self).__name}, " + "estimator must be either an sklearn compatible " + "regressor, or an skpro probabilistic regressor." + ) + + # has probabilistic mode iff the estimator is of type regressor_proba + self.set_tags(**{"capability:pred_int": _est_type == "regressor_proba"}) + + self._est_type = _est_type + def _is_predictable(self, last_window): """Check if we can make predictions from last window.""" return ( @@ -229,7 +260,26 @@ def _is_predictable(self, last_window): and np.sum(np.isinf(last_window)) == 0 ) - def _predict_in_sample(self, fh, X=None, return_pred_int=False, alpha=None): + def _predict_quantiles(self, fh, X, alpha): + """Compute/return prediction quantiles for a forecast. + + Parameters + ---------- + fh : guaranteed to be ForecastingHorizon + The forecasting horizon with the steps ahead to to predict. + X : sktime time series object, optional (default=None) + guaranteed to be of an mtype in self.get_tag("X_inner_mtype") + Exogeneous time series for the forecast + alpha : list of float (guaranteed not None and floats in [0,1] interval) + A list of probabilities at which quantile forecasts are computed. + """ + kwargs = {"X": X, "alpha": alpha, "method": "predict_quantiles"} + + y_pred = self._predict_boilerplate(fh, **kwargs) + + return y_pred + + def _predict_in_sample(self, fh, X=None, **kwargs): # Note that we currently only support out-of-sample predictions. For the # direct and multioutput strategy, we need to check this already during fit, # as the fh is required for fitting. @@ -260,6 +310,7 @@ def get_test_params(cls, parameter_set="default"): from sklearn.pipeline import make_pipeline from sktime.transformations.panel.reduce import Tabularizer + from sktime.utils.validation._dependencies import _check_soft_dependencies # naming convention is as follows: # reducers with Tabular take an sklearn estimator, e.g., LinearRegressor @@ -270,7 +321,26 @@ def get_test_params(cls, parameter_set="default"): if "TimeSeries" in cls.__name__: est = make_pipeline(Tabularizer(), est) - params = {"estimator": est, "window_length": 3} + params = [{"estimator": est, "window_length": 3}] + + PROBA_IMPLEMENTED = ["DirectTabularRegressionForecaster"] + self_supports_proba = cls.__name__ in PROBA_IMPLEMENTED + + if _check_soft_dependencies("skpro", severity="none") and self_supports_proba: + from skpro.regression.residual import ResidualDouble + + params_proba_local = { + "estimator": ResidualDouble.create_test_instance(), + "pooling": "local", + "window_length": 3, + } + params_proba_global = { + "estimator": ResidualDouble.create_test_instance(), + "pooling": "global", + "window_length": 4, + } + params = params + [params_proba_local, params_proba_global] + return params def _get_shifted_window(self, shift=0, y_update=None, X_update=None): @@ -343,6 +413,9 @@ def _get_shifted_window(self, shift=0, y_update=None, X_update=None): # first observation after the window (this is what the window is summarized to). index_range = _index_range(relative_int, cutoff) + if isinstance(cutoff, pd.DatetimeIndex): + if cutoff.tzinfo is not None: + index_range = index_range.tz_localize(cutoff.tzinfo) # index_range will convert the indices to the date format of cutoff y_raw = _create_fcst_df(index_range, self._y) @@ -508,6 +581,8 @@ def _fit(self, y, X, fh): raise NotImplementedError("In-sample predictions are not implemented.") yt, Xt = self._transform(y, X) + if hasattr(Xt, "columns"): + Xt.columns = Xt.columns.astype(str) # Iterate over forecasting horizon, fitting a separate estimator for each step. self.estimators_ = [] @@ -517,23 +592,26 @@ def _fit(self, y, X, fh): if self.transformers_ is not None: fh_rel = fh.to_relative(self.cutoff) - yt = _cut_df(yt, n_timepoints - fh_rel[i] + 1) - Xt = _cut_df(Xt, n_timepoints - fh_rel[i] + 1, type="head") - estimator.fit(Xt, yt) + Xt_cut = _cut_df(Xt, n_timepoints - fh_rel[i] + 1, type="head") + yt_cut = _cut_df(yt, n_timepoints - fh_rel[i] + 1) + elif self.windows_identical is True or (fh_rel[i] - 1) == 0: + Xt_cut = Xt + yt_cut = yt[:, i] else: - if self.windows_identical is True: - estimator.fit(Xt, yt[:, i]) - else: - if (fh_rel[i] - 1) == 0: - estimator.fit(Xt, yt[:, i]) - else: - estimator.fit(Xt[: -(fh_rel[i] - 1)], yt[: -(fh_rel[i] - 1), i]) + Xt_cut = Xt[: -(fh_rel[i] - 1)] + yt_cut = yt[: -(fh_rel[i] - 1), i] + + # coercion to pandas for skpro proba regressors + if self._est_type != "regressor" and not isinstance(Xt, pd.DataFrame): + Xt_cut = pd.DataFrame(Xt_cut) + if self._est_type != "regressor" and not isinstance(yt, pd.DataFrame): + yt_cut = pd.DataFrame(yt_cut) + + estimator.fit(Xt_cut, yt_cut) self.estimators_.append(estimator) return self - def _predict_last_window( - self, fh, X=None, return_pred_int=False, alpha=DEFAULT_ALPHA - ): + def _predict_last_window(self, fh, X=None, **kwargs): """. In recursive reduction, iteration must be done over the @@ -548,13 +626,20 @@ def _predict_last_window( Forecasting horizon X : pd.DataFrame, optional (default=None) Exogenous time series - return_pred_int : bool - alpha : float or array-like Returns ------- y_return = pd.Series or pd.DataFrame """ + if "method" in kwargs: + method = kwargs.pop("method") + else: + method = "predict" + + # estimator type for case branches + est_type = self._est_type + # "regressor" for sklearn, "regressor_proba" for skpro + if self._X is not None and X is None: raise ValueError( "`X` must be passed to `predict` if `X` is given in `fit`." @@ -564,22 +649,51 @@ def _predict_last_window( y_last, X_last = self._get_shifted_window(X_update=X) ys = np.array(y_last) if not np.sum(np.isnan(ys)) == 0 and np.sum(np.isinf(ys)) == 0: - return self._predict_nan(fh) + return self._predict_nan(fh, method=method, **kwargs) else: y_last, X_last = self._get_last_window() if not self._is_predictable(y_last): - return self._predict_nan(fh) + return self._predict_nan(fh, method=method, **kwargs) # Get last window of available data. # If we cannot generate a prediction from the available data, return nan. + if isinstance(X_last, pd.DataFrame): + X_last = prep_skl_df(X_last) + + def pool_preds(y_preds): + """Pool predictions from different estimators. + + Parameters + ---------- + y_preds : list of pd.DataFrame + List of predictions from different estimators. + """ + y_pred = y_preds.pop(0) + for y_pred_i in y_preds: + y_pred = y_pred.combine_first(y_pred_i) + return y_pred + + def _coerce_to_numpy(y_pred): + """Coerce predictions to numpy array, assumes pd.DataFram or numpy.""" + if isinstance(y_pred, pd.DataFrame): + return y_pred.values + else: + return y_pred + if self.pooling == "global": fh_abs = fh.to_absolute_index(self.cutoff) - y_pred = _create_fcst_df(fh_abs, self._y) + y_preds = [] for i, estimator in enumerate(self.estimators_): - y_pred_short = estimator.predict(X_last) - y_pred_curr = _create_fcst_df([fh_abs[i]], self._y, fill=y_pred_short) - y_pred.update(y_pred_curr) + y_pred_est = getattr(estimator, method)(X_last, **kwargs) + if est_type == "regressor": + y_pred_i = _create_fcst_df([fh_abs[i]], self._y, fill=y_pred_est) + else: # est_type == "regressor_proba" + y_pred_v = _coerce_to_numpy(y_pred_est) + y_pred_i = _create_fcst_df([fh_abs[i]], y_pred_est, fill=y_pred_v) + y_preds.append(y_pred_i) + y_pred = pool_preds(y_preds) + else: # Pre-allocate arrays. if self._X is None: @@ -603,11 +717,33 @@ def _predict_last_window( X_pred = X_pred.reshape(1, -1) # Allocate array for predictions. - y_pred = np.zeros(len(fh)) + if est_type == "regressor": + y_pred = np.zeros(len(fh)) + else: # est_type == "regressor_proba" + y_preds = [] # Iterate over estimators/forecast horizon for i, estimator in enumerate(self.estimators_): - y_pred[i] = estimator.predict(X_pred) + y_pred_est = getattr(estimator, method)(X_pred, **kwargs) + if est_type == "regressor": + y_pred[i] = y_pred_est + else: # est_type == "regressor_proba" + y_pred_v = _coerce_to_numpy(y_pred_est) + y_pred_i = _create_fcst_df([fh[i]], y_pred_est, fill=y_pred_v) + y_preds.append(y_pred_i) + + if est_type != "regressor": + y_pred = pool_preds(y_preds) + + # coerce index and columns to expected + index = fh.get_expected_pred_idx(y=self._y, cutoff=self.cutoff) + columns = self._get_columns(method=method, **kwargs) + if isinstance(y_pred, pd.DataFrame): + y_pred.index = index + y_pred.columns = columns + else: + y_pred = pd.DataFrame(y_pred, index=index, columns=columns) + return y_pred @@ -660,9 +796,7 @@ def _fit(self, y, X, fh): self.estimator_.fit(Xt, yt) return self - def _predict_last_window( - self, fh, X=None, return_pred_int=False, alpha=DEFAULT_ALPHA - ): + def _predict_last_window(self, fh, X=None, **kwargs): """Predict to training data. Parameters @@ -671,8 +805,6 @@ def _predict_last_window( Forecasting horizon X : pd.DataFrame, optional (default=None) Exogenous time series - return_pred_int : bool - alpha : float or array-like Returns ------- @@ -823,9 +955,7 @@ def _fit(self, y, X, fh): self.estimator_.fit(Xt, yt) return self - def _predict_last_window( - self, fh, X=None, return_pred_int=False, alpha=DEFAULT_ALPHA - ): + def _predict_last_window(self, fh, X=None, **kwargs): """. In recursive reduction, iteration must be done over the @@ -869,6 +999,9 @@ def _predict_last_window( fh_max = fh.to_relative(self.cutoff)[-1] relative = pd.Index(list(map(int, range(1, fh_max + 1)))) index_range = _index_range(relative, self.cutoff) + if isinstance(self.cutoff, pd.DatetimeIndex): + if self.cutoff.tzinfo is not None: + index_range = index_range.tz_localize(self.cutoff.tzinfo) y_pred = _create_fcst_df(index_range, self._y) @@ -895,15 +1028,27 @@ def _predict_last_window( fh_max = fh.to_relative(self.cutoff)[-1] y_pred = np.zeros(fh_max) + + # Array with input data for prediction. last = np.zeros((1, n_columns, window_length + fh_max)) # Fill pre-allocated arrays with available data. last[:, 0, :window_length] = y_last if X is not None: - last[:, 1:, :window_length] = X_last.T - last[:, 1:, window_length:] = X.iloc[ - -(last.shape[2] - window_length) :, : - ].T + X_to_use = np.concatenate( + [X_last.T, X.iloc[-(last.shape[2] - window_length) :, :].T], axis=1 + ) + if X_to_use.shape[1] < window_length + fh_max: + X_to_use = np.pad( + X_to_use, + ((0, 0), (0, window_length + fh_max - X_to_use.shape[1])), + "edge", + ) + elif X_to_use.shape[1] > window_length + fh_max: + X_to_use = X_to_use[:, : window_length + fh_max] + # else X_to_use.shape[1] == window_length + fh_max + # and there are no additional steps to take + last[:, 1:] = X_to_use # Recursively generate predictions by iterating over forecasting horizon. for i in range(fh_max): @@ -1016,9 +1161,7 @@ def _fit(self, y, X, fh): self.estimators_.append(estimator) return self - def _predict_last_window( - self, fh, X=None, return_pred_int=False, alpha=DEFAULT_ALPHA - ): + def _predict_last_window(self, fh, X=None, **kwargs): """Fit to training data. Parameters @@ -1027,8 +1170,6 @@ def _predict_last_window( Forecasting horizon X : pd.DataFrame, optional (default=None) Exogenous time series - return_pred_int : bool - alpha : float or array-like Returns ------- @@ -1388,20 +1529,27 @@ def make_reduction( Parameters ---------- - estimator : an estimator instance - Either a tabular regressor from scikit-learn or a time series regressor from - sktime. + estimator : an estimator instance, can be: + + * scikit-learn regressor or interface compatible + * sktime time series regressor + * skpro tabular probabilistic supervised regressor, only for direct reduction + this will result in a probabilistic forecaster + strategy : str, optional (default="recursive") The strategy to generate forecasts. Must be one of "direct", "recursive" or "multioutput". + window_length : int, optional (default=10) Window length used in sliding window transformation. + scitype : str, optional (default="infer") Legacy argument for downwards compatibility, should not be used. `make_reduction` will automatically infer the correct type of `estimator`. This internal inference can be force-overridden by the `scitype` argument. Must be one of "infer", "tabular-regressor" or "time-series-regressor". If the scitype cannot be inferred, this is a bug and should be reported. + transformers: list of transformers (default = None) A suitable list of transformers that allows for using an en-bloc approach with make_reduction. This means that instead of using the raw past observations of @@ -1409,10 +1557,12 @@ def make_reduction( the past raw observations. Currently only supports WindowSummarizer (or a list of WindowSummarizers) to generate features e.g. the mean of the past 7 observations. Currently only works for RecursiveTimeSeriesRegressionForecaster. + pooling: str {"local", "global"}, optional Specifies whether separate models will be fit at the level of each instance (local) of if you wish to fit a single model to all instances ("global"). Currently only works for RecursiveTimeSeriesRegressionForecaster. + windows_identical: bool, (default = True) Direct forecasting only. Specifies whether all direct models use the same X windows from y (True: Number @@ -1423,8 +1573,9 @@ def make_reduction( Returns ------- - estimator : an Estimator instance - A reduction forecaster + forecaster : an sktime forecaster object + the reduction forecaster, wrapping ``estimator`` + class is determined by the ``strategy`` argument and type of ``estimator``. Examples -------- @@ -1527,11 +1678,11 @@ def _cut_df(X, n_obs=1, type="tail"): if n_obs == 0: return X.copy() if isinstance(X.index, pd.MultiIndex): - Xi_grp = X.index.names[0:-1] + levels = list(range(X.index.nlevels - 1)) if type == "tail": - X = X.groupby(Xi_grp, as_index=False).tail(n_obs) + X = X.groupby(level=levels, as_index=False).tail(n_obs) elif type == "head": - X = X.groupby(Xi_grp, as_index=False).head(n_obs) + X = X.groupby(level=levels, as_index=False).head(n_obs) else: if type == "tail": X = X.tail(n_obs) @@ -1566,75 +1717,31 @@ def _create_fcst_df(target_date, origin_df, fill=None): ------- A pandas dataframe or series """ - oi = origin_df.index - if not isinstance(oi, pd.MultiIndex): - if isinstance(origin_df, pd.Series): - if fill is None: - template = pd.Series(np.zeros(len(target_date)), index=target_date) - else: - template = pd.Series(fill, index=target_date) - template.name = origin_df.name - return template - else: - if fill is None: - template = pd.DataFrame( - np.zeros((len(target_date), len(origin_df.columns))), - index=target_date, - columns=origin_df.columns.to_list(), - ) - else: - template = pd.DataFrame( - fill, index=target_date, columns=origin_df.columns.to_list() - ) - return template + if not isinstance(target_date, ForecastingHorizon): + ix = pd.Index(target_date) + fh = ForecastingHorizon(ix, is_relative=False) else: - idx = origin_df.index.to_frame(index=False) - instance_names = idx.columns[0:-1].to_list() - time_names = idx.columns[-1] - idx = idx[instance_names].drop_duplicates() - - timeframe = pd.DataFrame(target_date, columns=[time_names]) - target_frame = idx.merge(timeframe, how="cross") - if hasattr(target_date, "freq"): - freq_inferred = target_date.freq - mi = ( - target_frame.groupby(instance_names, as_index=True) - .apply( - lambda df: df.drop(instance_names, axis=1) - .set_index(time_names) - .asfreq(freq_inferred) - ) - .index - ) - else: - mi = ( - target_frame.groupby(instance_names, as_index=True) - .apply(lambda df: df.drop(instance_names, axis=1).set_index(time_names)) - .index - ) + fh = target_date.to_absolute() - if fill is None: - template = pd.DataFrame( - np.zeros((len(target_date) * idx.shape[0], len(origin_df.columns))), - index=mi, - columns=origin_df.columns.to_list(), - ) - else: - template = pd.DataFrame( - fill, - index=mi, - columns=origin_df.columns.to_list(), - ) + index = fh.get_expected_pred_idx(origin_df) + + if isinstance(origin_df, pd.Series): + columns = [origin_df.name] + else: + columns = origin_df.columns.to_list() - template = template.astype(origin_df.dtypes.to_dict()) - return template + if fill is None: + values = 0 + else: + values = fill + res = pd.DataFrame(values, index=index, columns=columns) -def _coerce_col_str(X): - """Coerce columns to string, to satisfy sklearn convention.""" - X = X.copy() - X.columns = [str(x) for x in X.columns] - return X + if isinstance(origin_df, pd.Series) and not isinstance(index, pd.MultiIndex): + res = res.iloc[:, 0] + res.name = origin_df.name + + return res def slice_at_ix(df, ix): @@ -1744,7 +1851,7 @@ class DirectReductionForecaster(BaseForecaster, _ReducerMixin): to obtain a prediction for `y(c+h)`, for each `h` in the forecasting horizon if `X_treatment = "shifted": applies fitted estimator's predict to - features = `y(c)`, `y(c-1)`, ..., `y(c-window_size)`, if provided: `X(t)` + features = `y(c)`, `y(c-1)`, ..., `y(c-window_size)`, if provided: `X(c)` to obtain prediction for `y(c+h_1)`, ..., `y(c+h_k)` for `h_j` in forec. horizon Parameters @@ -1773,6 +1880,7 @@ class DirectReductionForecaster(BaseForecaster, _ReducerMixin): """ _tags = { + "authors": "fkiraly", "requires-fh-in-fit": True, # is the forecasting horizon required in fit? "ignores-exogeneous-X": False, "X_inner_mtype": ["pd.DataFrame", "pd-multiindex", "pd_multiindex_hier"], @@ -1873,8 +1981,8 @@ def _fit_shifted(self, y, X=None, fh=None): Xt = lagger_y_to_X.fit_transform(X=y, y=X) Xt = Xt.loc[y_notna_idx] - Xt = _coerce_col_str(Xt) - yt = _coerce_col_str(yt) + Xt = prep_skl_df(Xt) + yt = prep_skl_df(yt) estimator = clone(self.estimator) if not estimator._get_tags()["multioutput"]: @@ -1899,7 +2007,7 @@ def _predict_shifted(self, fh=None, X=None): Xt = lagger_y_to_X.transform(X=self._y, y=self._X) Xt_lastrow = slice_at_ix(Xt, self.cutoff) - Xt_lastrow = _coerce_col_str(Xt_lastrow) + Xt_lastrow = prep_skl_df(Xt_lastrow) estimator = self.estimator_ # 2D numpy array with col index = (fh, var) and 1 row @@ -1963,8 +2071,8 @@ def _fit_concurrent(self, y, X=None, fh=None): yt = yt.loc[notna_idx] Xtt = Xtt.loc[notna_idx] - Xtt = _coerce_col_str(Xtt) - yt = _coerce_col_str(yt) + Xtt = prep_skl_df(Xtt) + yt = prep_skl_df(yt) # we now check whether the set of full lags is empty # if yes, we set a flag, since we cannot fit the reducer @@ -2009,7 +2117,7 @@ def _predict_concurrent(self, X=None, fh=None): Xt = lagger_y_to_X[-lag].transform(X=self._y, y=X_pool) Xtt = lag_plus.fit_transform(Xt) Xtt_predrow = slice_at_ix(Xtt, predict_idx) - Xtt_predrow = _coerce_col_str(Xtt_predrow) + Xtt_predrow = prep_skl_df(Xtt_predrow) estimator = self.estimators_[i] @@ -2112,6 +2220,7 @@ class RecursiveReductionForecaster(BaseForecaster, _ReducerMixin): """ _tags = { + "authors": "fkiraly", "requires-fh-in-fit": False, # is the forecasting horizon required in fit? "ignores-exogeneous-X": False, "X_inner_mtype": ["pd.DataFrame", "pd-multiindex", "pd_multiindex_hier"], @@ -2208,8 +2317,8 @@ def _fit(self, y, X, fh): if X is not None: Xtt = pd.concat([X.loc[notna_idx], Xtt], axis=1) - Xtt = _coerce_col_str(Xtt) - yt = _coerce_col_str(yt) + Xtt = prep_skl_df(Xtt) + yt = prep_skl_df(yt) estimator = clone(self.estimator) estimator.fit(Xtt, yt) @@ -2304,7 +2413,7 @@ def _predict_out_of_sample(self, X_pool, fh): [slice_at_ix(X_pool, predict_idx), Xtt_predrow], axis=1 ) - Xtt_predrow = _coerce_col_str(Xtt_predrow) + Xtt_predrow = prep_skl_df(Xtt_predrow) estimator = self.estimator_ @@ -2355,7 +2464,7 @@ def _predict_in_sample(self, X_pool, fh): [slice_at_ix(X_pool, fh_abs), Xtt_predrows], axis=1 ) - Xtt_predrows = _coerce_col_str(Xtt_predrows) + Xtt_predrows = prep_skl_df(Xtt_predrows) estimator = self.estimator_ @@ -2404,32 +2513,38 @@ def get_test_params(cls, parameter_set="default"): class YfromX(BaseForecaster, _ReducerMixin): """Simple reduction predicting endogeneous from concurrent exogeneous variables. - Tabulates all seen `X` and `y` by time index and applies + Tabulates all seen ``X`` and ``y`` by time index and applies tabular supervised regression. - In `fit`, given endogeneous time series `y` and exogeneous `X`: - fits `estimator` to feature-label pairs as defined as follows. + In ``fit``, given endogeneous time series ``y`` and exogeneous ``X``: + fits ``estimator`` to feature-label pairs as defined as follows. + + features = :math:`y(t)`, labels: :math:`X(t)` + ranging over all :math:`t` where the above have been observed (are in the index) - features = :math:`y(t)`, labels: :math:`X(t)` - ranging over all :math:`t` where the above have been observed (are in the index) + In ``predict``, at a time :math:`t` in the forecasting horizon, uses ``estimator`` + to predict :math:`y(t)`, from labels: :math:`X(t)` - In `predict`, at a time :math:`t` in the forecasting horizon, uses `estimator` - to predict :math:`y(t)`, from labels: :math:`X(t)` + If regressor is ``skpro`` probabilistic regressor, and has ``predict_interval`` etc, + uses ``estimator`` to predict :math:`y(t)`, from labels: :math:`X(t)`, + passing on the ``predict_interval`` etc arguments. - If no exogeneous data is provided, will predict the mean of `y` seen in `fit`. + If no exogeneous data is provided, will predict the mean of ``y`` seen in ``fit``. In order to use a fit not on the entire historical data - and update periodically, combine this with `UpdateRefitsEvery`. + and update periodically, combine this with ``UpdateRefitsEvery``. - In order to deal with missing data, combine this with `Imputer`. + In order to deal with missing data, combine this with ``Imputer``. To construct an custom direct reducer, - combine with `YtoX`, `Lag`, or `ReducerTransform`. + combine with ``YtoX``, ``Lag``, or ``ReducerTransform``. Parameters ---------- - estimator : sklearn regressor, must be compatible with sklearn interface + estimator : sklearn regressor or skpro probabilistic regressor, + must be compatible with sklearn or skpro interface tabular regression algorithm used in reduction algorithm + if skpro regressor, resulting forecaster will have probabilistic capability pooling : str, one of ["local", "global", "panel"], optional, default="local" level on which data are pooled to fit the supervised regression model "local" = unit/instance level, one reduced model per lowest hierarchy level @@ -2545,13 +2660,13 @@ def _fit(self, y, X, fh): dummy = DummyRegressor() estimator = ResidualDouble(dummy) - X = _coerce_col_str(y) + X = prep_skl_df(y, copy_df=True) else: - X = _coerce_col_str(X) + X = prep_skl_df(X, copy_df=True) estimator = clone(self.estimator) if _est_type == "regressor": - y = _coerce_col_str(y) + y = prep_skl_df(y, copy_df=True) y = y.values.flatten() estimator.fit(X, y) @@ -2756,7 +2871,7 @@ def _get_pred_X(self, X, fh_idx): else: X_pool = pd.DataFrame(0, index=fh_idx, columns=y_cols) - X_pool = _coerce_col_str(X_pool) + X_pool = prep_skl_df(X_pool, copy_df=True) X_idx = X_pool.loc[fh_idx] return X_idx diff --git a/sktime/forecasting/compose/_stack.py b/sktime/forecasting/compose/_stack.py index 8bcc8e163af..3171bd33a12 100644 --- a/sktime/forecasting/compose/_stack.py +++ b/sktime/forecasting/compose/_stack.py @@ -60,6 +60,7 @@ class StackingForecaster(_HeterogenousEnsembleForecaster): """ _tags = { + "authors": ["mloning", "fkiraly", "indinewton"], "ignores-exogeneous-X": False, "requires-fh-in-fit": True, "handles-missing-data": True, diff --git a/sktime/forecasting/compose/tests/test_fallback.py b/sktime/forecasting/compose/tests/test_fallback.py new file mode 100644 index 00000000000..61c8c7bce61 --- /dev/null +++ b/sktime/forecasting/compose/tests/test_fallback.py @@ -0,0 +1,531 @@ +#!/usr/bin/env python3 -u +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file). +"""Unit tests for the FallbackForecaster functionality. + +Tests cover the basic operations of the FallbackForecaster, ensuring proper +functionality of fitting, predicting, updating, and handling of errors in the +forecasting process. +""" + +__author__ = ["ninedigits"] + +import pandas as pd +import pytest + +from sktime.base import _HeterogenousMetaEstimator +from sktime.forecasting.base._base import BaseForecaster +from sktime.forecasting.compose import EnsembleForecaster, FallbackForecaster +from sktime.forecasting.naive import NaiveForecaster +from sktime.forecasting.trend import PolynomialTrendForecaster +from sktime.utils._testing.forecasting import make_forecasting_problem + + +class ForecastingError(Exception): + """Exception raised for errors in the forecasting process. + + Attributes + ---------- + message : str + Explanation of the error. + + Methods + ------- + __init__(message) + Constructs the ForecastingError with the provided message.""" + + def __init__(self, message): + self.message = message + super().__init__(message) + + +class DummyForecaster(_HeterogenousMetaEstimator, BaseForecaster): + """Dummy forecaster used for testing the FallbackForecaster. + + This forecaster is intentionally designed to fail at specified stages of the + forecasting process (fit, predict, or update) to test the robustness and fallback + mechanisms of the FallbackForecaster. + + Parameters + ---------- + raise_at : str + Stage at which the forecaster should fail. Options are "fit", "predict", + "update". + + Raises + ------ + AttributeError + If `raise_at` is not one of the valid options. + """ + + def __init__(self, raise_at="fit"): + super().__init__() + __valid__ = ["fit", "predict", "update"] + if raise_at not in __valid__: + raise AttributeError(f"`raise_at` must choose from {__valid__}") + self.forecaster = NaiveForecaster() + self.raise_at = raise_at + self._is_fitted = False + + def _fit(self, y, X=None, fh=None): + """Fit to training data. Optionally fail here.""" + if self.raise_at == "fit": + raise ForecastingError("Intentional failure in fit.") + self.forecaster.fit(y, X, fh) + self._is_fitted = True + return self + + def _predict(self, fh, X=None): + """Make predictions. Optionally fail here.""" + if not self._is_fitted: + raise ForecastingError("The forecaster is not fitted yet.") + if self.raise_at == "predict": + raise ForecastingError("Intentional failure in predict.") + return self.forecaster.predict(fh, X) + + def _update(self, y, X=None, update_params=True): + """Update the forecaster. Optionally fail here.""" + if self.raise_at == "update": + raise ForecastingError("Intentional failure in update.") + self.forecaster.update(y, X, update_params) + return self + + +def test_raises_at_fit(): + """Test dummy forecaster raises at fit""" + # Start with negative time series, Theta model will fail here + y = make_forecasting_problem(random_state=42) + forecaster = DummyForecaster(raise_at="fit") + with pytest.raises(ForecastingError): + forecaster.fit(y=y, fh=[1, 2, 3]) + + +def test_raises_at_predict(): + """Test dummy forecaster raises at predict""" + # Start with negative time series, Theta model will fail here + y = make_forecasting_problem(random_state=42) + forecaster = DummyForecaster(raise_at="predict") + forecaster.fit(y=y, fh=[1, 2, 3]) + with pytest.raises(ForecastingError): + forecaster.predict() + + +def test_raises_at_update(): + """Test dummy forecaster raises at update""" + # Start with negative time series, Theta model will fail here + y = make_forecasting_problem(random_state=42) + forecaster = DummyForecaster(raise_at="update") + forecaster.fit(y=y, fh=[1, 2, 3]) + forecaster.predict() + with pytest.raises(ForecastingError): + forecaster.update(y) + + +def test_fallbackforecaster_fails_at_fit(): + """Test FallbackForecaster fails at first fit, second forecaster succeeds""" + y = make_forecasting_problem(random_state=42) + forecaster1 = EnsembleForecaster( + [ + ("trend", PolynomialTrendForecaster()), + ("fail_fit", DummyForecaster(raise_at="fit")), + ] + ) + forecaster2 = EnsembleForecaster( + [ + ("trend", PolynomialTrendForecaster()), + ("naive", NaiveForecaster()), + ] + ) + forecaster = FallbackForecaster( + [ + ( + "ensemble1_fails_at_fit", + forecaster1, + ), + ( + "ensemble2", + forecaster2, + ), + ] + ) + forecaster.fit(y=y, fh=[1, 2, 3]) + y_pred_actual = forecaster.predict() + + forecaster2.fit(y=y, fh=[1, 2, 3]) + y_pred_expected = forecaster2.predict() + + # Assert that the first valid forecaster is trained + name = forecaster.current_name_ + assert name == "ensemble2" + + # Assert that the first valid forecaster produces the same results as it would + # on its own + pd.testing.assert_series_equal(y_pred_expected, y_pred_actual) + + # Count the number of exceptions raised + exceptions_raised = forecaster.exceptions_raised_ + assert len(exceptions_raised) == 1 + + +def test_fallbackforecaster_fails_at_predict(): + """Test FallbackForecaster fails at predict, second forecaster succeeds""" + y = make_forecasting_problem(random_state=42) + forecaster1 = EnsembleForecaster( + [ + ("trend", PolynomialTrendForecaster()), + ("raise_at_predict", DummyForecaster(raise_at="predict")), + ] + ) + forecaster2 = EnsembleForecaster( + [ + ("trend", PolynomialTrendForecaster()), + ("naive", NaiveForecaster()), + ] + ) + + forecaster = FallbackForecaster( + [ + ("forecaster1_fails_predict", forecaster1), + ("forecaster2_succeeded", forecaster2), + ] + ) + forecaster.fit(y=y, fh=[1, 2, 3]) + + # Assert predictions line up with the correct forecaster + y_pred_actual = forecaster.predict() + + forecaster2.fit(y=y, fh=[1, 2, 3]) + y_pred_expected = forecaster2.predict() + + # Assert correct forecaster name + name = forecaster.current_name_ + assert name == "forecaster2_succeeded" + + # Assert correct y_pred + pd.testing.assert_series_equal(y_pred_expected, y_pred_actual) + + +def test_fallbackforecaster_fails_twice(): + """First two FallbackForecasters fail, third succeeds""" + y = make_forecasting_problem(random_state=42) + forecaster1 = EnsembleForecaster( + [ + ("trend", PolynomialTrendForecaster()), + ("fails", DummyForecaster(raise_at="fit")), + ] + ) + forecaster2 = EnsembleForecaster( + [ + ("trend", PolynomialTrendForecaster()), + ("fails", DummyForecaster(raise_at="predict")), + ] + ) + forecaster3 = EnsembleForecaster( + [ + ("trend", PolynomialTrendForecaster()), + ("naive", NaiveForecaster()), + ] + ) + forecaster4 = PolynomialTrendForecaster() + + forecaster = FallbackForecaster( + [ + ("forecaster1_fails_fit", forecaster1), + ("forecaster2_fails_prd", forecaster2), + ("forecaster3_succeeded", forecaster3), + ("forecaster4_notcalled", forecaster4), + ] + ) + forecaster.fit(y=y, fh=[1, 2, 3]) + y_pred_actual = forecaster.predict() + + forecaster3.fit(y=y, fh=[1, 2, 3]) + y_pred_expected = forecaster3.predict() + + # Assert correct forecaster name + name = forecaster.current_name_ + assert name == "forecaster3_succeeded" + + # Assert correct y_pred + pd.testing.assert_series_equal(y_pred_expected, y_pred_actual) + + # Assert correct number of expected exceptions + exceptions_raised = forecaster.exceptions_raised_ + assert len(exceptions_raised) == 2 + + # Assert the correct forecasters failed + names_raised_actual = [ + vals["forecaster_name"] for vals in exceptions_raised.values() + ] + names_raised_expected = ["forecaster1_fails_fit", "forecaster2_fails_prd"] + assert names_raised_actual == names_raised_expected + + +def test_fallbackforecaster_fails_fit_twice(): + """First two FallbackForecasters fail at fit step, third forecaster succeeds""" + y = make_forecasting_problem(random_state=42) + forecaster1 = EnsembleForecaster( + [ + ("trend", PolynomialTrendForecaster()), + ("fails", DummyForecaster(raise_at="fit")), + ] + ) + forecaster2 = EnsembleForecaster( + [ + ("trend", PolynomialTrendForecaster()), + ("fails", DummyForecaster(raise_at="fit")), + ] + ) + forecaster3 = EnsembleForecaster( + [ + ("trend", PolynomialTrendForecaster()), + ("naive", NaiveForecaster()), + ] + ) + forecaster4 = PolynomialTrendForecaster() + + forecaster = FallbackForecaster( + [ + ("forecaster1_fails_fit", forecaster1), + ("forecaster2_fails_fit", forecaster2), + ("forecaster3_succeeded", forecaster3), + ("forecaster4_notcalled", forecaster4), + ] + ) + forecaster.fit(y=y, fh=[1, 2, 3]) + + # Assert predictions line up with the correct forecaster + y_pred_actual = forecaster.predict() + + forecaster3.fit(y=y, fh=[1, 2, 3]) + y_pred_expected = forecaster3.predict() + + # Assert correct forecaster name + name = forecaster.current_name_ + assert name == "forecaster3_succeeded" + + # Assert correct y_pred + pd.testing.assert_series_equal(y_pred_expected, y_pred_actual) + + # Assert correct number of expected exceptions + exceptions_raised = forecaster.exceptions_raised_ + assert len(exceptions_raised) == 2 + + # Assert the correct forecasters failed + names_raised_actual = [ + vals["forecaster_name"] for vals in exceptions_raised.values() + ] + names_raised_expected = ["forecaster1_fails_fit", "forecaster2_fails_fit"] + assert names_raised_actual == names_raised_expected + + +def test_all_forecasters_fail1(): + """All forecasters fail; predict and fit""" + # Start with negative time series, Theta model will fail here + y = make_forecasting_problem(random_state=42) + forecaster1 = ("raise_predict1", DummyForecaster(raise_at="predict")) + forecaster2 = ("raise_fit1", DummyForecaster(raise_at="fit")) + forecaster3 = ("raise_fit2", DummyForecaster(raise_at="fit")) + forecaster = FallbackForecaster([forecaster1, forecaster2, forecaster3]) + with pytest.raises(RuntimeError): + forecaster.fit(y=y, fh=[1, 2, 3]) + forecaster.predict() + + +def test_all_forecasters_fail2(): + """All forecasters fail at fit step""" + # Start with negative time series, Theta model will fail here + y = make_forecasting_problem(random_state=42) + forecaster1 = ("raise_fit1", DummyForecaster(raise_at="fit")) + forecaster2 = ("raise_fit2", DummyForecaster(raise_at="fit")) + forecaster3 = ("raise_fit3", DummyForecaster(raise_at="fit")) + forecaster = FallbackForecaster([forecaster1, forecaster2, forecaster3]) + with pytest.raises(RuntimeError): + forecaster.fit(y=y, fh=[1, 2, 3]) + + +def test_all_forecasters_fail3(): + """All forecasters fail at predict""" + # Start with negative time series, Theta model will fail here + y = make_forecasting_problem(random_state=42) + forecaster1 = ("raise_predict1", DummyForecaster(raise_at="predict")) + forecaster2 = ("raise_predict2", DummyForecaster(raise_at="predict")) + forecaster3 = ("raise_predict3", DummyForecaster(raise_at="predict")) + forecaster = FallbackForecaster([forecaster1, forecaster2, forecaster3]) + with pytest.raises(RuntimeError): + forecaster.fit(y=y, fh=[1, 2, 3]) + forecaster.predict() + + +def test_many_forecasters_fail1(): + """All forecasters fail at predict""" + # Start with negative time series, Theta model will fail here + y = make_forecasting_problem(random_state=42) + forecaster1 = ("raise_predict1", DummyForecaster(raise_at="predict")) + forecaster2 = ("raise_fit2", DummyForecaster(raise_at="fit")) + forecaster3 = ("raise_fit3", DummyForecaster(raise_at="fit")) + forecaster4 = ("raise_predict4", DummyForecaster(raise_at="predict")) + forecaster5 = ("forecaster5", PolynomialTrendForecaster()) + forecaster = FallbackForecaster( + [forecaster1, forecaster2, forecaster3, forecaster4, forecaster5] + ) + forecaster.fit(y, fh=[1, 2, 3]) + y_pred_actual = forecaster.predict() + y_name_actual = forecaster.current_name_ + expected_forecaster = forecaster5[1] + expected_forecaster.fit(y, fh=[1, 2, 3]) + y_pred_expected = expected_forecaster.predict() + y_name_expected = forecaster5[0] + pd.testing.assert_series_equal(y_pred_actual, y_pred_expected) + assert y_name_actual == y_name_expected + + # Assert correct forecaster name + name = forecaster.current_name_ + assert name == "forecaster5" + + # Assert correct y_pred + pd.testing.assert_series_equal(y_pred_expected, y_pred_actual) + + # Assert correct number of expected exceptions + exceptions_raised = forecaster.exceptions_raised_ + assert len(exceptions_raised) == 4 + + # Assert the correct forecasters failed + names_raised_actual = [ + vals["forecaster_name"] for vals in exceptions_raised.values() + ] + names_raised_expected = [ + "raise_predict1", + "raise_fit2", + "raise_fit3", + "raise_predict4", + ] + assert names_raised_actual == names_raised_expected + + +def test_fallbackforecaster_fails_twice_simple(): + """First two FallbackForecasters fail, third succeeds""" + y = make_forecasting_problem(random_state=42) + forecaster1 = DummyForecaster(raise_at="fit") + forecaster2 = DummyForecaster(raise_at="predict") + forecaster3 = PolynomialTrendForecaster() + forecaster4 = NaiveForecaster() + + forecaster = FallbackForecaster( + [ + ("forecaster1_fails_fit", forecaster1), + ("forecaster2_fails_prd", forecaster2), + ("forecaster3_succeeded", forecaster3), + ("forecaster4_notcalled", forecaster4), + ] + ) + forecaster.fit(y=y, fh=[1, 2, 3]) + y_pred_actual = forecaster.predict() + + forecaster3.fit(y=y, fh=[1, 2, 3]) + y_pred_expected = forecaster3.predict() + + # Assert correct forecaster name + name = forecaster.current_name_ + assert name == "forecaster3_succeeded" + + # Assert correct y_pred + pd.testing.assert_series_equal(y_pred_expected, y_pred_actual) + + # Assert correct number of expected exceptions + exceptions_raised = forecaster.exceptions_raised_ + assert len(exceptions_raised) == 2 + + # Assert the correct forecasters failed + names_raised_actual = [ + vals["forecaster_name"] for vals in exceptions_raised.values() + ] + names_raised_expected = ["forecaster1_fails_fit", "forecaster2_fails_prd"] + assert names_raised_actual == names_raised_expected + + +def test_fallbackforecaster_fails_many_simple(): + """First two FallbackForecasters fail, third succeeds""" + y = make_forecasting_problem(random_state=42) + forecaster1 = DummyForecaster(raise_at="predict") + forecaster2 = DummyForecaster(raise_at="predict") + forecaster3 = DummyForecaster(raise_at="fit") + forecaster4 = DummyForecaster(raise_at="fit") + forecaster5 = DummyForecaster(raise_at="fit") + forecaster6 = DummyForecaster(raise_at="predict") + forecaster7 = DummyForecaster(raise_at="fit") + forecaster8 = DummyForecaster(raise_at="predict") + forecaster9 = PolynomialTrendForecaster() + forecaster10 = NaiveForecaster() + + forecaster = FallbackForecaster( + [ + ("f1", forecaster1), + ("f2", forecaster2), + ("f3", forecaster3), + ("f4", forecaster4), + ("f5", forecaster5), + ("f6", forecaster6), + ("f7", forecaster7), + ("f8", forecaster8), + ("target", forecaster9), + ("notcalled", forecaster10), + ] + ) + forecaster.fit(y=y, fh=[1, 2, 3]) + y_pred_actual = forecaster.predict() + + forecaster9.fit(y=y, fh=[1, 2, 3]) + y_pred_expected = forecaster9.predict() + + # Assert correct forecaster name + name = forecaster.current_name_ + assert name == "target" + + # Assert correct y_pred + pd.testing.assert_series_equal(y_pred_expected, y_pred_actual) + + # Assert correct number of expected exceptions + exceptions_raised = forecaster.exceptions_raised_ + assert len(exceptions_raised) == 8 + + # Assert the correct forecasters failed + names_raised_actual = [ + vals["forecaster_name"] for vals in exceptions_raised.values() + ] + names_raised_expected = ["f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8"] + assert names_raised_actual == names_raised_expected + + +def test_fallbackforecaster_pred_int(): + """Predict interval works bc all forecasters have them enabled, first forecaster + expected + """ + y = make_forecasting_problem(random_state=42) + forecaster1 = NaiveForecaster("mean") + forecaster2 = NaiveForecaster("last") + forecaster = FallbackForecaster( + [("naive_mean", forecaster1), ("naive_last", forecaster2)] + ) + fh = [1, 2, 3] + forecaster.fit(y, fh=fh) + pred_int_actual = forecaster.predict_interval() + + forecaster1.fit(y, fh=fh) + pred_int_expected = forecaster1.predict_interval() + pd.testing.assert_frame_equal(pred_int_expected, pred_int_actual) + + +def test_fallbackforecaster_pred_int_raises(): + """Predict int raises because EnsembleForecaster does not have this capability""" + y = make_forecasting_problem(random_state=42) + forecaster1 = NaiveForecaster("mean") + forecaster2 = EnsembleForecaster( + [("naive_last", NaiveForecaster("last")), ("poly", PolynomialTrendForecaster())] + ) + forecaster = FallbackForecaster( + [("naive_mean", forecaster1), ("ensemble", forecaster2)] + ) + fh = [1, 2, 3] + forecaster.fit(y, fh=fh) + with pytest.raises(NotImplementedError): + forecaster.predict_interval() diff --git a/sktime/forecasting/compose/tests/test_hierarchy_ensemble.py b/sktime/forecasting/compose/tests/test_hierarchy_ensemble.py index b3a655fb439..e56194314e1 100644 --- a/sktime/forecasting/compose/tests/test_hierarchy_ensemble.py +++ b/sktime/forecasting/compose/tests/test_hierarchy_ensemble.py @@ -7,10 +7,11 @@ import numpy as np import pytest +from sktime.base._meta import flatten from sktime.datatypes._utilities import get_window from sktime.forecasting.compose import HierarchyEnsembleForecaster from sktime.forecasting.naive import NaiveForecaster -from sktime.forecasting.trend import PolynomialTrendForecaster +from sktime.forecasting.trend import PolynomialTrendForecaster, TrendForecaster from sktime.transformations.hierarchical.aggregate import Aggregator from sktime.utils._testing.hierarchical import _bottom_hier_datagen, _make_hierarchical from sktime.utils.validation._dependencies import _check_soft_dependencies @@ -145,3 +146,57 @@ def test_hierarchy_ensemble_exog(forecasters): estimator_instance.fit(y=y_train, X=X_train, fh=[1, 2, 3]) estimator_instance.predict(X=X_test) estimator_instance.update(y=y_test, X=X_test) + + +@pytest.mark.parametrize( + "forecasters", + [ + [ + ("trend", TrendForecaster(), ["l1_node01"]), + ("polytrend", PolynomialTrendForecaster(), ["l1_node02", "l1_node03"]), + ("naive", NaiveForecaster(), ["__total"]), + ], + [ + ( + "trend", + TrendForecaster(), + [("__total"), ("l1_node01"), ("l1_node02"), ("l1_node03")], + ), + ], + ], +) +@pytest.mark.parametrize("default", [NaiveForecaster(), None]) +def test_level_one_data(forecasters, default): + "Check for data with one level of hierarchy (excluding timepoints level)." + agg = Aggregator() + + y = _bottom_hier_datagen( + no_bottom_nodes=3, + no_levels=1, + random_seed=123, + ) + + forecaster = HierarchyEnsembleForecaster(forecasters, by="node", default=default) + + forecaster.fit(y, fh=[1, 2, 3]) + actual_pred = forecaster.predict() + + y = agg.fit_transform(y) + + for i in range(len(forecasters)): + test_frcstr = forecasters[i][1].clone() + df = y[y.index.droplevel(-1).isin(forecaster.fitted_list[i][1])] + test_frcstr.fit(df, fh=[1, 2, 3]) + test_pred = test_frcstr.predict() + msg = "Node predictions do not match" + assert np.all(actual_pred.loc[test_pred.index] == test_pred), msg + + _, _, nodes = zip(*forecasters) + nodes = set(flatten(nodes)) + if default is not None and len(nodes) != len(y.index.droplevel(-1).unique()): + def_frcstr = default + df = y[y.index.droplevel(-1).isin(forecaster.fitted_list[-1][1])] + def_frcstr.fit(df, fh=[1, 2, 3]) + def_pred = def_frcstr.predict() + msg = "Node default predictions do not match" + assert np.all(actual_pred.loc[def_pred.index] == def_pred), msg diff --git a/sktime/forecasting/compose/tests/test_ignorex.py b/sktime/forecasting/compose/tests/test_ignorex.py new file mode 100644 index 00000000000..814a4e9fa5a --- /dev/null +++ b/sktime/forecasting/compose/tests/test_ignorex.py @@ -0,0 +1,39 @@ +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +"""Tests for IgnoreX.""" + +from unittest.mock import MagicMock + +import pytest + +from sktime.datasets import load_longley +from sktime.forecasting.compose import IgnoreX +from sktime.tests.test_switch import run_test_for_class + + +@pytest.mark.skipif( + not run_test_for_class(IgnoreX), + reason="run test only if softdeps are present and incrementally (if requested)", +) +@pytest.mark.parametrize("ignore_x", [True, False, None]) +def test_ignoreX(ignore_x): + """Test that indeed X=None is passed iff the args of IgnoreX claim to do so.""" + y, X = load_longley() + + fcst = MagicMock() + + if ignore_x is None: + igx = IgnoreX(forecaster=fcst) + else: + igx = IgnoreX(forecaster=fcst, ignore_x=ignore_x) + + igx.fit(y, fh=[1, 2, 3], X=X) + + mock_fitted = igx.forecaster_.fit + call_args_list = mock_fitted.call_args_list + all_calls_X_none = all(call_args[1]["X"] is None for call_args in call_args_list) + any_calls_X_none = any(call_args[1]["X"] is None for call_args in call_args_list) + + if ignore_x in [True, None]: + assert all_calls_X_none + else: + assert not any_calls_X_none diff --git a/sktime/forecasting/compose/tests/test_pipeline.py b/sktime/forecasting/compose/tests/test_pipeline.py index 334c445d7a3..850943f61f2 100644 --- a/sktime/forecasting/compose/tests/test_pipeline.py +++ b/sktime/forecasting/compose/tests/test_pipeline.py @@ -373,7 +373,7 @@ def test_tag_handles_missing_data(): forecaster.set_tags(**{"handles-missing-data": False}) y = _make_series() - y[10] = np.nan + y.iloc[10] = np.nan # test only TransformedTargetForecaster y_pipe = TransformedTargetForecaster( @@ -485,7 +485,7 @@ def test_forecastx_logic(): ) def test_forecastx_fit_behavior(): from sktime.forecasting.compose import ForecastX - from sktime.forecasting.model_selection import temporal_train_test_split + from sktime.split import temporal_train_test_split y, X = load_longley() y_train, y_test, X_train, X_test = temporal_train_test_split(y, X) @@ -705,3 +705,70 @@ def test_featurizer_forecastingpipeline_logic(): forecaster.fit(y_train, X=X_train, fh=[1]) # try to forecast next year forecaster.predict(X=X_test) # dummy X to predict next year + + +def test_exogenousx_ignore_tag_set(): + """Tests that TransformedTargetForecaster sets X tag for feature selection. + + If the forecaster ignores X, but the feature selector does not, then the + ignores-exogeneous-X tag should be correctly set to False, not True. + + This is the failure case in bug report #5518. + + More generally, the tag should be set to True iff all steps in the pipeline + ignore X. + """ + from sktime.forecasting.compose import YfromX + from sktime.transformations.series.feature_selection import FeatureSelection + + fcst_does_not_ignore_x = YfromX.create_test_instance() + fcst_ignores_x = NaiveForecaster() + + trafo_ignores_x = ExponentTransformer() + trafo_does_not_ignore_x = FeatureSelection() + + # check that ignores-exogeneous-X tag is set correctly + pipe1 = trafo_ignores_x * fcst_does_not_ignore_x + pipe2 = trafo_ignores_x * fcst_ignores_x + pipe3 = trafo_does_not_ignore_x * fcst_does_not_ignore_x + pipe4 = trafo_does_not_ignore_x * fcst_ignores_x + pipe5 = trafo_ignores_x * trafo_does_not_ignore_x * fcst_does_not_ignore_x + pipe6 = trafo_ignores_x * trafo_does_not_ignore_x * fcst_ignores_x + pipe7 = trafo_ignores_x * trafo_ignores_x * fcst_does_not_ignore_x + pipe8 = trafo_ignores_x * fcst_ignores_x * trafo_does_not_ignore_x + pipe9 = trafo_does_not_ignore_x * fcst_ignores_x * trafo_ignores_x + pipe10 = trafo_ignores_x * fcst_ignores_x * trafo_ignores_x + + assert not pipe1.get_tag("ignores-exogeneous-X") + assert pipe2.get_tag("ignores-exogeneous-X") + assert not pipe3.get_tag("ignores-exogeneous-X") + assert not pipe4.get_tag("ignores-exogeneous-X") + assert not pipe5.get_tag("ignores-exogeneous-X") + assert not pipe6.get_tag("ignores-exogeneous-X") + assert not pipe7.get_tag("ignores-exogeneous-X") + assert not pipe8.get_tag("ignores-exogeneous-X") + assert not pipe9.get_tag("ignores-exogeneous-X") + assert pipe10.get_tag("ignores-exogeneous-X") + + +@pytest.mark.skipif( + not _check_soft_dependencies("pmdarima", severity="none"), + reason="skip test if required soft dependency is not available", +) +def test_pipeline_exogenous_none(): + """Test ForecastingPipeline works with a transformer returning None.""" + from sktime.transformations.series.feature_selection import FeatureSelection + + y, X = load_longley() + y_train, y_test, X_train, X_test = temporal_train_test_split(y, X, test_size=3) + + pipe = ForecastingPipeline( + [ + ("select_X", FeatureSelection(method="none")), + ("arima", ARIMA()), + ] + ) + + pipe.fit(y_train, X_train, fh=[1, 2, 3]) + y_pred = pipe.predict(X=X_test) + assert np.all(y_pred.index == y_test.index) diff --git a/sktime/forecasting/compose/tests/test_reduce.py b/sktime/forecasting/compose/tests/test_reduce.py index 13758a2e787..26b980e4ff0 100644 --- a/sktime/forecasting/compose/tests/test_reduce.py +++ b/sktime/forecasting/compose/tests/test_reduce.py @@ -588,3 +588,28 @@ def test_direct_vs_recursive(): assert pred_dir_max.head(1).equals(pred_rec_max.head(1)) assert pred_dir_max.head(1).equals(pred_rec_spec.head(1)) assert not pred_dir_max.head(1).equals(pred_dir_spec.head(1)) + + +def test_recursive_reducer_X_not_fit_to_fh(): + """Test recursive reducer with X that do not fit the fh. + + I.e., either X is longer or smaller than max_fh + """ + y = load_airline() + y_train, y_test = temporal_train_test_split(y) + X_train = y_train + X_test = y_test + + forecaster = make_reduction( + LinearRegression(), window_length=2, strategy="recursive" + ) + forecaster.fit(y_train, X_train) + + pred1 = forecaster.predict(X=X_test[:1], fh=[1, 2, 3]) + assert pred1.shape == (3,) + pred2 = forecaster.predict(X=X_test[:2], fh=[1, 2, 3]) + assert pred2.shape == (3,) + pred3 = forecaster.predict(X=X_test[:3], fh=[1, 2, 3]) + assert pred3.shape == (3,) + pred4 = forecaster.predict(X=X_test, fh=[1]) + assert pred4.shape == (1,) diff --git a/sktime/forecasting/compose/tests/test_reduce_global.py b/sktime/forecasting/compose/tests/test_reduce_global.py index 28951c12504..e2a78d278e7 100644 --- a/sktime/forecasting/compose/tests/test_reduce_global.py +++ b/sktime/forecasting/compose/tests/test_reduce_global.py @@ -21,7 +21,7 @@ from sklearn.linear_model import LinearRegression from sklearn.pipeline import make_pipeline -from sktime.datasets import load_airline +from sktime.datasets import load_airline, load_solar from sktime.datatypes import get_examples from sktime.forecasting.base import ForecastingHorizon from sktime.forecasting.compose import make_reduction @@ -106,6 +106,7 @@ def y_dict(): # Create integer index data y_numeric = y_train.copy() y_numeric.index = pd.to_numeric(y_numeric.index) + y_numeric.index.names = [None] # setting None to cover "no index name" case y_dict["y_numeric"] = y_numeric return y_dict @@ -139,7 +140,7 @@ def check_eval(test_input, expected): ), ( "y_train", - [None], + ["Period"], ), ( "y_numeric", @@ -186,7 +187,7 @@ def test_recursive_reduction(y, index_names, y_dict): ), ( "y_train", - [None], + ["Period"], ), ( "y_numeric", @@ -232,7 +233,7 @@ def test_direct_reduction(y, index_names, y_dict): ), ( "y_train", - [None], + ["Period"], ), ( "y_numeric", @@ -358,3 +359,40 @@ def test_nofreq_pass(): np.testing.assert_almost_equal( y_pred_global["c0"].values, y_pred_nofreq["c0"].values ) + + +def test_timezoneaware_index(): + y = load_solar(api_version=None) + y_notz = y.copy().tz_localize(None) + + assert y.index.tz is not None + assert y_notz.index.tz is None + + window_trafo = WindowSummarizer(n_jobs=1, **{"lag_feature": {"lag": [1, 2, 48]}}) + regressor = LinearRegression() + forecaster = make_reduction( + estimator=regressor, + strategy="recursive", + transformers=[window_trafo], + window_length=None, + pooling="global", + ) + + # check coefficients + tzaware = forecaster.clone().fit(y) + tznaive = forecaster.clone().fit(y_notz) + tzaware_coef = tzaware.get_fitted_params()["estimator__coef"] + tznaive_coef = tznaive.get_fitted_params()["estimator__coef"] + + np.testing.assert_almost_equal(tzaware_coef, tznaive_coef) + + fh = np.arange(1, 97) + pred_tzaware = tzaware.predict(fh=fh) + pred_tznaive = tznaive.predict(fh=fh) + + msg = "Time-zone of predictions not consistent with training data." + assert pred_tzaware.index.tz == y.index.tz, msg + assert pred_tznaive.index.tz == y_notz.index.tz, msg + + # These should give us identical predictions + np.testing.assert_almost_equal(pred_tzaware.values, pred_tznaive.values) diff --git a/sktime/forecasting/conformal.py b/sktime/forecasting/conformal.py index 175e7543711..dd45961d47a 100644 --- a/sktime/forecasting/conformal.py +++ b/sktime/forecasting/conformal.py @@ -119,6 +119,11 @@ class ConformalIntervals(BaseForecaster): """ _tags = { + # packaging info + # -------------- + "authors": ["fkiraly", "bethrice44"], + # estimator type + # -------------- "scitype:y": "univariate", "requires-fh-in-fit": False, "handles-missing-data": False, diff --git a/sktime/forecasting/croston.py b/sktime/forecasting/croston.py index 9c2186c782f..59fc284d0cc 100644 --- a/sktime/forecasting/croston.py +++ b/sktime/forecasting/croston.py @@ -70,6 +70,12 @@ class Croston(BaseForecaster): """ _tags = { + # packaging info + # -------------- + "authors": "Riyabelle25", + "maintainers": "Riyabelle25", + # estimator type + # -------------- "requires-fh-in-fit": False, # is forecasting horizon already required in fit? } @@ -171,6 +177,7 @@ def get_test_params(cls, parameter_set="default"): {}, {"smoothing": 0}, {"smoothing": 0.42}, + {"smoothing": 2}, ] return params diff --git a/sktime/forecasting/dummy.py b/sktime/forecasting/dummy.py index ddf9433ed4a..7f72a1cd233 100644 --- a/sktime/forecasting/dummy.py +++ b/sktime/forecasting/dummy.py @@ -56,6 +56,11 @@ class ForecastKnownValues(BaseForecaster): """ _tags = { + # packaging info + # -------------- + "authors": ["fkiraly"], + # estimator type + # -------------- "y_inner_mtype": "pd.DataFrame", "X_inner_mtype": "pd.DataFrame", "scitype:y": "both", diff --git a/sktime/forecasting/dynamic_factor.py b/sktime/forecasting/dynamic_factor.py index 37a00bc1741..4c5e476d160 100644 --- a/sktime/forecasting/dynamic_factor.py +++ b/sktime/forecasting/dynamic_factor.py @@ -121,6 +121,13 @@ class DynamicFactor(_StatsModelsAdapter): """ _tags = { + # packaging info + # -------------- + "authors": ["Ris-Bali", "lbventura"], + "maintainers": ["Ris-Bali", "lbventura"], + # python_dependencies: "statsmodels" - inherited from _StatsModelsAdapter + # estimator type + # -------------- "scitype:y": "multivariate", "ignores-exogeneous-X": False, "handles-missing-data": True, diff --git a/sktime/forecasting/ets.py b/sktime/forecasting/ets.py index 0156dd5f25f..25b13d09e27 100644 --- a/sktime/forecasting/ets.py +++ b/sktime/forecasting/ets.py @@ -2,7 +2,6 @@ # copyright: sktime developers, BSD-3-Clause License (see LICENSE file) """Implements automatic and manually exponential time series smoothing models.""" - __author__ = ["hyang1996"] __all__ = ["AutoETS"] @@ -175,6 +174,13 @@ class AutoETS(_StatsModelsAdapter): _fitted_param_names = ("aic", "aicc", "bic", "hqic") _tags = { + # packaging info + # -------------- + "authors": ["hyang1996"], + "maintainers": ["hyang1996"], + # "python_dependencies": "statmodels" - inherited from _StatsModelsAdapter + # estimator type + # -------------- "ignores-exogeneous-X": True, "capability:pred_int": True, "capability:pred_int:insample": True, diff --git a/sktime/forecasting/exp_smoothing.py b/sktime/forecasting/exp_smoothing.py index 6535dac524e..2ee8e5a65a9 100644 --- a/sktime/forecasting/exp_smoothing.py +++ b/sktime/forecasting/exp_smoothing.py @@ -110,6 +110,14 @@ class ExponentialSmoothing(_StatsModelsAdapter): >>> y_pred = forecaster.predict(fh=[1,2,3]) # doctest: +SKIP """ + _tags = { + # packaging info + # -------------- + "authors": ["mloning", "big-o"], + # "python_dependencies": "statsmodels" - inherited from _StatsModelsAdapter + # estimator type tags inherited from _StatsModelsAdapter + } + _fitted_param_names = ( "initial_level", "initial_slope", @@ -234,7 +242,7 @@ def get_test_params(cls, parameter_set="default"): "damped_trend": False, "seasonal": "add", "sp": 2, - "use_boxcox": True, + "use_boxcox": False, "initialization_method": "estimated", "smoothing_level": 0.3, "smoothing_trend": 0.5, diff --git a/sktime/forecasting/fbprophet.py b/sktime/forecasting/fbprophet.py index e814a8b164f..06cc496b384 100644 --- a/sktime/forecasting/fbprophet.py +++ b/sktime/forecasting/fbprophet.py @@ -2,7 +2,7 @@ # copyright: sktime developers, BSD-3-Clause License (see LICENSE file) """Implements Prophet forecaster by wrapping fbprophet.""" -__author__ = ["aiwalter"] +__author__ = ["mloning", "aiwalter", "fkiraly"] __all__ = ["Prophet"] @@ -46,7 +46,7 @@ class Prophet(_ProphetAdapter): trend. If 'logistic' specified float for 'growth_cap' must be provided. growth_floor: float, default=0 Growth saturation minimum value. - Used only if `growth="logistic"`, has no effect otherwise + Used only if `growth="logistic"`, has no effect otherwise (if `growth` is not `"logistic"`). growth_cap: float, default=None Growth saturation maximum aka carrying capacity. @@ -111,6 +111,10 @@ class Prophet(_ProphetAdapter): stan_backend: str or None, default=None str as defined in StanBackendEnum. If None, will try to iterate over all available backends and find the working one. + fit_kwargs: dict or None, default=None + Dict with args for Prophet.fit(). + These are additional arguments passed to the optimizing or sampling + functions in Stan. References ---------- @@ -158,6 +162,7 @@ def __init__( uncertainty_samples=1000, stan_backend=None, verbose=0, + fit_kwargs=None, ): self.freq = freq self.add_seasonality = add_seasonality @@ -182,6 +187,7 @@ def __init__( self.uncertainty_samples = uncertainty_samples self.stan_backend = stan_backend self.verbose = verbose + self.fit_kwargs = fit_kwargs super().__init__() @@ -233,5 +239,6 @@ def get_test_params(cls, parameter_set="default"): "daily_seasonality": False, "uncertainty_samples": 10, "verbose": False, + "fit_kwargs": {"seed": 12345}, } return params diff --git a/sktime/forecasting/ltsf.py b/sktime/forecasting/ltsf.py new file mode 100644 index 00000000000..6a8248496fb --- /dev/null +++ b/sktime/forecasting/ltsf.py @@ -0,0 +1,501 @@ +"""Deep Learning Forecasters using LTSF-Linear Models.""" + +from sktime.forecasting.base.adapters._pytorch import BaseDeepNetworkPyTorch + + +class LTSFLinearForecaster(BaseDeepNetworkPyTorch): + """LTSF-Linear Forecaster. + + Implementation of the Long-Term Short-Term Feature (LTSF) linear forecaster, + aka LTSF-Linear, by Zeng et al [1]_. + + Core logic is directly copied from the cure-lab LTSF-Linear implementation [2]_, + which is unfortunately not available as a package. + + Parameters + ---------- + seq_len : int + length of input sequence + pred_len : int + length of prediction (forecast horizon) + num_epochs : int, default=16 + number of epochs to train + batch_size : int, default=8 + number of training examples per batch + in_channels : int, default=1 + number of input channels passed to network + individual : bool, default=False + boolean flag that controls whether the network treats each channel individually" + "or applies a single linear layer across all channels. If individual=True, the" + "a separate linear layer is created for each input channel. If" + "individual=False, a single shared linear layer is used for all channels." + criterion : torch.nn Loss Function, default=torch.nn.MSELoss + loss function to be used for training + criterion_kwargs : dict, default=None + keyword arguments to pass to criterion + optimizer : torch.optim.Optimizer, default=torch.optim.Adam + optimizer to be used for training + optimizer_kwargs : dict, default=None + keyword arguments to pass to optimizer + lr : float, default=0.003 + learning rate to train model with + + References + ---------- + .. [1] Zeng A, Chen M, Zhang L, Xu Q. 2023. + Are transformers effective for time series forecasting? + Proceedings of the AAAI conference on artificial intelligence 2023 + (Vol. 37, No. 9, pp. 11121-11128). + .. [2] https://github.com/cure-lab/LTSF-Linear + + Examples + -------- + >>> from sktime.forecasting.ltsf import LTSFLinearForecaster # doctest: +SKIP + >>> from sktime.datasets import load_airline + >>> model = LTSFLinearForecaster(10, 3) # doctest: +SKIP + >>> y = load_airline() + >>> model.fit(y, fh=[1,2,3]) # doctest: +SKIP + LTSFLinearForecaster(pred_len=3, seq_len=10) + >>> y_pred = model.predict() # doctest: +SKIP + >>> y_pred # doctest: +SKIP + 1961-01 515.456726 + 1961-02 576.704712 + 1961-03 559.859680 + Freq: M, Name: Number of airline passengers, dtype: float32 + """ + + _tags = { + # packaging info + # -------------- + "authors": ["luca-miniati"], + "maintainers": ["luca-miniati"], + # "python_dependencis": "pytorch" - inherited from BaseDeepNetworkPyTorch + # estimator type vars inherited from BaseDeepNetworkPyTorch + } + + def __init__( + self, + seq_len, + pred_len, + *, + num_epochs=16, + batch_size=8, + in_channels=1, + individual=False, + criterion=None, + criterion_kwargs=None, + optimizer=None, + optimizer_kwargs=None, + lr=0.001, + custom_dataset_train=None, + custom_dataset_pred=None, + ): + self.seq_len = seq_len + self.pred_len = pred_len + self.individual = individual + self.in_channels = in_channels + self.criterion = criterion + self.optimizer = optimizer + self.criterion_kwargs = criterion_kwargs + self.optimizer_kwargs = optimizer_kwargs + self.lr = lr + self.num_epochs = num_epochs + self.custom_dataset_train = custom_dataset_train + self.custom_dataset_pred = custom_dataset_pred + self.batch_size = batch_size + + super().__init__( + num_epochs=num_epochs, + batch_size=batch_size, + in_channels=in_channels, + individual=individual, + criterion_kwargs=criterion_kwargs, + optimizer=optimizer, + optimizer_kwargs=optimizer_kwargs, + lr=lr, + ) + + from sktime.utils.validation._dependencies import _check_soft_dependencies + + if _check_soft_dependencies("torch"): + import torch + + self.criterions = { + "MSE": torch.nn.MSELoss, + "L1": torch.nn.L1Loss, + "SmoothL1": torch.nn.SmoothL1Loss, + "Huber": torch.nn.HuberLoss, + } + + self.optimizers = { + "Adadelta": torch.optim.Adadelta, + "Adagrad": torch.optim.Adagrad, + "Adam": torch.optim.Adam, + "AdamW": torch.optim.AdamW, + "SGD": torch.optim.SGD, + } + + def _build_network(self, fh): + from sktime.networks.ltsf._ltsf import LTSFLinearNetwork + + return LTSFLinearNetwork( + self.seq_len, + fh, + self.in_channels, + self.individual, + )._build() + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + + + Returns + ------- + params : dict or list of dict + """ + params = [ + { + "seq_len": 2, + "pred_len": 1, + "lr": 0.005, + "optimizer": "Adam", + "batch_size": 1, + "num_epochs": 1, + "individual": True, + } + ] + + return params + + +class LTSFDLinearForecaster(BaseDeepNetworkPyTorch): + """LTSF-DLinear Forecaster. + + Implementation of the Long-Term Short-Term Feature (LTSF) decomposition linear + forecaster, aka LTSF-DLinear, by Zeng et al [1]_. + + Core logic is directly copied from the cure-lab LTSF-Linear implementation [2]_, + which is unfortunately not available as a package. + + Parameters + ---------- + seq_len : int + length of input sequence + pred_len : int + length of prediction (forecast horizon) + num_epochs : int, default=16 + number of epochs to train + batch_size : int, default=8 + number of training examples per batch + in_channels : int, default=1 + number of input channels passed to network + individual : bool, default=False + boolean flag that controls whether the network treats each channel individually" + "or applies a single linear layer across all channels. If individual=True, the" + "a separate linear layer is created for each input channel. If" + "individual=False, a single shared linear layer is used for all channels." + criterion : torch.nn Loss Function, default=torch.nn.MSELoss + loss function to be used for training + criterion_kwargs : dict, default=None + keyword arguments to pass to criterion + optimizer : torch.optim.Optimizer, default=torch.optim.Adam + optimizer to be used for training + optimizer_kwargs : dict, default=None + keyword arguments to pass to optimizer + lr : float, default=0.003 + learning rate to train model with + + References + ---------- + .. [1] Zeng A, Chen M, Zhang L, Xu Q. 2023. + Are transformers effective for time series forecasting? + Proceedings of the AAAI conference on artificial intelligence 2023 + (Vol. 37, No. 9, pp. 11121-11128). + .. [2] https://github.com/cure-lab/LTSF-Linear + + Examples + -------- + >>> from sktime.forecasting.ltsf import LTSFDLinearForecaster # doctest: +SKIP + >>> from sktime.datasets import load_airline + >>> model = LTSFDLinearForecaster(10, 3) # doctest: +SKIP + >>> y = load_airline() + >>> model.fit(y, fh=[1,2,3]) # doctest: +SKIP + LTSFDLinearForecaster(pred_len=3, seq_len=10) + >>> y_pred = model.predict() # doctest: +SKIP + >>> y_pred # doctest: +SKIP + 1961-01 436.494476 + 1961-02 433.659851 + 1961-03 479.309631 + Freq: M, Name: Number of airline passengers, dtype: float32 + """ + + def __init__( + self, + seq_len, + pred_len, + *, + num_epochs=16, + batch_size=8, + in_channels=1, + individual=False, + criterion=None, + criterion_kwargs=None, + optimizer=None, + optimizer_kwargs=None, + lr=0.001, + custom_dataset_train=None, + custom_dataset_pred=None, + ): + self.seq_len = seq_len + self.pred_len = pred_len + self.individual = individual + self.in_channels = in_channels + self.criterion = criterion + self.optimizer = optimizer + self.criterion_kwargs = criterion_kwargs + self.optimizer_kwargs = optimizer_kwargs + self.lr = lr + self.num_epochs = num_epochs + self.custom_dataset_train = custom_dataset_train + self.custom_dataset_pred = custom_dataset_pred + self.batch_size = batch_size + + super().__init__( + num_epochs=num_epochs, + batch_size=batch_size, + in_channels=in_channels, + individual=individual, + criterion_kwargs=criterion_kwargs, + optimizer=optimizer, + optimizer_kwargs=optimizer_kwargs, + lr=lr, + ) + + from sktime.utils.validation._dependencies import _check_soft_dependencies + + if _check_soft_dependencies("torch"): + import torch + + self.criterions = { + "MSE": torch.nn.MSELoss, + "L1": torch.nn.L1Loss, + "SmoothL1": torch.nn.SmoothL1Loss, + "Huber": torch.nn.HuberLoss, + } + + self.optimizers = { + "Adadelta": torch.optim.Adadelta, + "Adagrad": torch.optim.Adagrad, + "Adam": torch.optim.Adam, + "AdamW": torch.optim.AdamW, + "SGD": torch.optim.SGD, + } + + def _build_network(self, fh): + from sktime.networks.ltsf._ltsf import LTSFDLinearNetwork + + return LTSFDLinearNetwork( + self.seq_len, + fh, + self.in_channels, + self.individual, + )._build() + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + + + Returns + ------- + params : dict or list of dict + """ + params = [ + { + "seq_len": 2, + "pred_len": 1, + "lr": 0.005, + "optimizer": "Adam", + "batch_size": 1, + "num_epochs": 1, + "individual": True, + } + ] + + return params + + +class LTSFNLinearForecaster(BaseDeepNetworkPyTorch): + """LTSF-NLinear Forecaster. + + Implementation of the Long-Term Short-Term Feature (LTSF) normalization linear + forecaster, aka LTSF-NLinear, by Zeng et al [1]_. + + Core logic is directly copied from the cure-lab LTSF-Linear implementation [2]_, + which is unfortunately not available as a package. + + Parameters + ---------- + seq_len : int + length of input sequence + pred_len : int + length of prediction (forecast horizon) + num_epochs : int, default=16 + number of epochs to train + batch_size : int, default=8 + number of training examples per batch + in_channels : int, default=1 + number of input channels passed to network + individual : bool, default=False + boolean flag that controls whether the network treats each channel individually" + "or applies a single linear layer across all channels. If individual=True, the" + "a separate linear layer is created for each input channel. If" + "individual=False, a single shared linear layer is used for all channels." + criterion : torch.nn Loss Function, default=torch.nn.MSELoss + loss function to be used for training + criterion_kwargs : dict, default=None + keyword arguments to pass to criterion + optimizer : torch.optim.Optimizer, default=torch.optim.Adam + optimizer to be used for training + optimizer_kwargs : dict, default=None + keyword arguments to pass to optimizer + lr : float, default=0.003 + learning rate to train model with + + References + ---------- + .. [1] Zeng A, Chen M, Zhang L, Xu Q. 2023. + Are transformers effective for time series forecasting? + Proceedings of the AAAI conference on artificial intelligence 2023 + (Vol. 37, No. 9, pp. 11121-11128). + .. [2] https://github.com/cure-lab/LTSF-Linear + + Examples + -------- + >>> from sktime.forecasting.ltsf import LTSFNLinearForecaster # doctest: +SKIP + >>> from sktime.datasets import load_airline + >>> model = LTSFNLinearForecaster(10, 3) # doctest: +SKIP + >>> y = load_airline() + >>> model.fit(y, fh=[1,2,3]) # doctest: +SKIP + LTSFNLinearForecaster(pred_len=3, seq_len=10) + >>> y_pred = model.predict() # doctest: +SKIP + >>> y_pred # doctest: +SKIP + 1961-01 455.628082 + 1961-02 433.349640 + 1961-03 437.045502 + Freq: M, Name: Number of airline passengers, dtype: float32 + """ + + def __init__( + self, + seq_len, + pred_len, + *, + num_epochs=16, + batch_size=8, + in_channels=1, + individual=False, + criterion=None, + criterion_kwargs=None, + optimizer=None, + optimizer_kwargs=None, + lr=0.001, + custom_dataset_train=None, + custom_dataset_pred=None, + ): + self.seq_len = seq_len + self.pred_len = pred_len + self.individual = individual + self.in_channels = in_channels + self.criterion = criterion + self.optimizer = optimizer + self.criterion_kwargs = criterion_kwargs + self.optimizer_kwargs = optimizer_kwargs + self.lr = lr + self.num_epochs = num_epochs + self.custom_dataset_train = custom_dataset_train + self.custom_dataset_pred = custom_dataset_pred + self.batch_size = batch_size + + super().__init__( + num_epochs=num_epochs, + batch_size=batch_size, + in_channels=in_channels, + individual=individual, + criterion_kwargs=criterion_kwargs, + optimizer=optimizer, + optimizer_kwargs=optimizer_kwargs, + lr=lr, + ) + + from sktime.utils.validation._dependencies import _check_soft_dependencies + + if _check_soft_dependencies("torch"): + import torch + + self.criterions = { + "MSE": torch.nn.MSELoss, + "L1": torch.nn.L1Loss, + "SmoothL1": torch.nn.SmoothL1Loss, + "Huber": torch.nn.HuberLoss, + } + + self.optimizers = { + "Adadelta": torch.optim.Adadelta, + "Adagrad": torch.optim.Adagrad, + "Adam": torch.optim.Adam, + "AdamW": torch.optim.AdamW, + "SGD": torch.optim.SGD, + } + + def _build_network(self, fh): + from sktime.networks.ltsf._ltsf import LTSFNLinearNetwork + + return LTSFNLinearNetwork( + self.seq_len, + fh, + self.in_channels, + self.individual, + )._build() + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + + + Returns + ------- + params : dict or list of dict + """ + params = [ + { + "seq_len": 2, + "pred_len": 1, + "lr": 0.005, + "optimizer": "Adam", + "batch_size": 1, + "num_epochs": 1, + "individual": True, + } + ] + + return params diff --git a/sktime/forecasting/model_evaluation/_functions.py b/sktime/forecasting/model_evaluation/_functions.py index 155caabd8b2..9937a9030eb 100644 --- a/sktime/forecasting/model_evaluation/_functions.py +++ b/sktime/forecasting/model_evaluation/_functions.py @@ -318,8 +318,6 @@ def _evaluate_window(x, meta): return result -# todo 0.25.0: remove compute argument and docstring -# todo 0.25.0: remove kwargs and docstring def evaluate( forecaster, cv, @@ -330,10 +328,8 @@ def evaluate( return_data: bool = False, error_score: Union[str, int, float] = np.nan, backend: Optional[str] = None, - compute: bool = None, cv_X=None, backend_params: Optional[dict] = None, - **kwargs, ): r"""Evaluate forecaster using timeseries cross-validation. @@ -348,13 +344,13 @@ def evaluate( the train/test folds produced by the generator ``cv_X.split_series(X)`` (if ``X`` is ``None``, consider these to be ``None`` as well). - 1. Set ``i = 1`` + 1. Initialize the counter to ``i = 1`` 2. Fit the ``forecaster`` to :math:`y_{train, 1}`, :math:`X_{train, 1}`, - with a ``fh`` to forecast :math:`y_{test, 1}` - 3. The ``forecaster`` predict with exogeneous data :math:`X_{test, i}` - ``y_pred = forecaster.predict`` (or ``predict_proba`` or ``predict_quantiles``, - depending on ``scoring``) - 4. Compute ``scoring`` on ``y_pred`` versus :math:`y_{test, 1}` + with ``fh`` set to the absolute indices of :math:`y_{test, 1}`. + 3. Use the ``forecaster`` to make a prediction ``y_pred`` with the exogeneous + data :math:`X_{test, i}`. Predictions are made using either ``predict``, + ``predict_proba`` or ``predict_quantiles``, depending on ``scoring``. + 4. Compute the ``scoring`` function on ``y_pred`` versus :math:`y_{test, i}` 5. If ``i == K``, terminate, otherwise 6. Set ``i = i + 1`` 7. Ingest more data :math:`y_{train, i}`, :math:`X_{train, i}`, @@ -413,6 +409,7 @@ def evaluate( - "None": executes loop sequentally, simple list comprehension - "loky", "multiprocessing" and "threading": uses ``joblib.Parallel`` loops + - "joblib": custom and 3rd party ``joblib`` backends, e.g., ``spark`` - "dask": uses ``dask``, requires ``dask`` package in environment - "dask_lazy": same as "dask", but changes the return to (lazy) ``dask.dataframe.DataFrame``. @@ -421,9 +418,6 @@ def evaluate( "threading" is unlikely to see speed ups due to the GIL and the serialization backend (``cloudpickle``) for "dask" and "loky" is generally more robust than the standard ``pickle`` library used in "multiprocessing". - compute : bool, default=True, deprecated and will be removed in 0.25.0. - If backend="dask", whether returned DataFrame is computed. - If set to True, returns `pd.DataFrame`, otherwise `dask.dataframe.DataFrame`. cv_X : sktime BaseSplitter descendant, optional determines split of ``X`` into test and train folds default is ``X`` being split to identical ``loc`` indices as ``y`` @@ -435,12 +429,18 @@ def evaluate( Valid keys depend on the value of ``backend``: - "None": no additional parameters, ``backend_params`` is ignored - - "loky", "multiprocessing" and "threading": - any valid keys for ``joblib.Parallel`` can be passed here, - e.g., ``n_jobs``, with the exception of ``backend`` - which is directly controlled by ``backend`` + - "loky", "multiprocessing" and "threading": default ``joblib`` backends + any valid keys for ``joblib.Parallel`` can be passed here, e.g., ``n_jobs``, + with the exception of ``backend`` which is directly controlled by ``backend``. + If ``n_jobs`` is not passed, it will default to ``-1``, other parameters + will default to ``joblib`` defaults. + - "joblib": custom and 3rd party ``joblib`` backends, e.g., ``spark``. + any valid keys for ``joblib.Parallel`` can be passed here, e.g., ``n_jobs``, + ``backend`` must be passed as a key of ``backend_params`` in this case. + If ``n_jobs`` is not passed, it will default to ``-1``, other parameters + will default to ``joblib`` defaults. - "dask": any valid keys for ``dask.compute`` can be passed, - e.g., ``scheduler`` + e.g., ``scheduler`` Returns ------- @@ -518,40 +518,8 @@ def evaluate( "installed, but dask is not present in the python environment" ) - # todo 0.25.0: remove kwargs and this warning - if kwargs != {}: - warnings.warn( - "in evaluate, kwargs will no longer be supported from sktime 0.25.0. " - "to pass configuration arguments to the parallelization backend, " - "use backend_params instead. " - f"The following kwargs were found: {kwargs.keys()}, pass these as " - "dict elements to backend_params instead.", - DeprecationWarning, - stacklevel=2, - ) - - # todo 0.25.0: remove compute argument and logic, and remove this warning - if compute is not None: - warnings.warn( - "the compute argument of evaluate is deprecated and will be removed " - "in sktime 0.25.0. For the same behaviour in the future, " - 'use backend="dask_lazy"', - DeprecationWarning, - stacklevel=2, - ) - if compute is None: - compute = True - if backend == "dask" and not compute: - backend = "dask_lazy" - _check_strategy(strategy) cv = check_cv(cv, enforce_start_with_window=True) - # TODO: remove lines(four lines below) and 599-612 in v0.25.0 - if isinstance(scoring, list): - raise_warn, num = True, len(scoring) - else: - raise_warn, num = False, 1 - # removal until here scoring = _check_scores(scoring) ALLOWED_SCITYPES = ["Series", "Panel", "Hierarchical"] @@ -662,21 +630,4 @@ def gen_y_X_train_test(y, X, cv, cv_X): # final formatting of results DataFrame results = results.reset_index(drop=True) - # TODO: remove 16 lines below and 451-455 in v0.25.0 - if raise_warn: - warnings.warn( - "Starting v0.25.0 model_evaluation.evaluate module will rearrange " - "all metric columns to the left of its output result DataFrame. " - "Please use loc references when addressing the columns. You can " - "safely ignore this warning if you don't use evaluate function directly.", - DeprecationWarning, - stacklevel=2, - ) - columns = results.columns.to_list() - non_first_metrics = [] - for _ in range(1, num): - metric = columns.pop(1) - non_first_metrics.append(metric) - results = results.reindex(columns=columns + non_first_metrics) - # removal until here return results diff --git a/sktime/forecasting/model_evaluation/tests/test_evaluate.py b/sktime/forecasting/model_evaluation/tests/test_evaluate.py index 6c312e4dc77..7d3696e841a 100644 --- a/sktime/forecasting/model_evaluation/tests/test_evaluate.py +++ b/sktime/forecasting/model_evaluation/tests/test_evaluate.py @@ -47,11 +47,15 @@ from sktime.utils._testing.forecasting import make_forecasting_problem from sktime.utils._testing.hierarchical import _make_hierarchical from sktime.utils._testing.series import _make_series +from sktime.utils.parallel import _get_parallel_test_fixtures from sktime.utils.validation._dependencies import _check_soft_dependencies METRICS = [MeanAbsolutePercentageError(symmetric=True), MeanAbsoluteScaledError()] PROBA_METRICS = [CRPS(), EmpiricalCoverage(), LogLoss(), PinballLoss()] +# list of parallelization backends to test +BACKENDS = _get_parallel_test_fixtures("estimator") + def _check_evaluate_output(out, cv, y, scoring, return_data): assert isinstance(out, pd.DataFrame) @@ -103,7 +107,7 @@ def _check_evaluate_output(out, cv, y, scoring, return_data): @pytest.mark.parametrize("step_length", TEST_STEP_LENGTHS_INT) @pytest.mark.parametrize("strategy", ["refit", "update", "no-update_params"]) @pytest.mark.parametrize("scoring", METRICS) -@pytest.mark.parametrize("backend", [None, "dask", "loky", "threading"]) +@pytest.mark.parametrize("backend", BACKENDS) def test_evaluate_common_configs( CV, fh, window_length, step_length, strategy, scoring, backend ): @@ -122,7 +126,7 @@ def test_evaluate_common_configs( cv=cv, strategy=strategy, scoring=scoring, - backend=backend, + **backend, ) _check_evaluate_output(out, cv, y, scoring, False) @@ -216,14 +220,10 @@ def test_evaluate_no_exog_against_with_exog(): @pytest.mark.parametrize("error_score", [np.nan, "raise", 1000]) @pytest.mark.parametrize("return_data", [True, False]) @pytest.mark.parametrize("strategy", ["refit", "update", "no-update_params"]) -@pytest.mark.parametrize("backend", [None, "dask", "loky", "threading"]) +@pytest.mark.parametrize("backend", BACKENDS) @pytest.mark.parametrize("scores", [[MeanAbsolutePercentageError()], METRICS]) def test_evaluate_error_score(error_score, return_data, strategy, backend, scores): """Test evaluate to raise warnings and exceptions according to error_score value.""" - # skip test for dask backend if dask is not installed - if backend == "dask" and not _check_soft_dependencies("dask", severity="none"): - return None - forecaster = ExponentialSmoothing(sp=12) y = load_airline() # add NaN to make ExponentialSmoothing fail @@ -240,12 +240,12 @@ def test_evaluate_error_score(error_score, return_data, strategy, backend, score "return_data": return_data, "error_score": error_score, "strategy": strategy, - "backend": backend, } + args.update(backend) if error_score in [np.nan, 1000]: # known bug - loky backend does not pass on warnings, #5307 - if backend != "loky": + if backend["backend"] not in ["loky", "multiprocessing"]: with pytest.warns(FitFailedWarning): results = evaluate(**args) else: @@ -264,7 +264,7 @@ def test_evaluate_error_score(error_score, return_data, strategy, backend, score not run_test_for_class(evaluate), reason="run test only if softdeps are present and incrementally (if requested)", ) -@pytest.mark.parametrize("backend", [None, "dask", "loky", "threading"]) +@pytest.mark.parametrize("backend", BACKENDS) def test_evaluate_hierarchical(backend): """Check that evaluate works with hierarchical data.""" # skip test for dask backend if dask is not installed @@ -284,10 +284,10 @@ def test_evaluate_hierarchical(backend): cv = SlidingWindowSplitter() scoring = MeanAbsolutePercentageError(symmetric=True) out_exog = evaluate( - forecaster, cv, y, X=X, scoring=scoring, error_score="raise", backend=backend + forecaster, cv, y, X=X, scoring=scoring, error_score="raise", **backend ) out_no_exog = evaluate( - forecaster, cv, y, X=None, scoring=scoring, error_score="raise", backend=backend + forecaster, cv, y, X=None, scoring=scoring, error_score="raise", **backend ) scoring_name = f"test_{scoring.name}" diff --git a/sktime/forecasting/model_selection/__init__.py b/sktime/forecasting/model_selection/__init__.py index c55f7396095..8c9ca7712ad 100644 --- a/sktime/forecasting/model_selection/__init__.py +++ b/sktime/forecasting/model_selection/__init__.py @@ -2,33 +2,98 @@ # copyright: sktime developers, BSD-3-Clause License (see LICENSE file) """Implements functionality for selecting forecasting models.""" -__author__ = ["mloning", "kkoralturk"] __all__ = [ - "CutoffSplitter", - "SameLocSplitter", - "SingleWindowSplitter", - "SlidingWindowSplitter", - "temporal_train_test_split", - "ExpandingGreedySplitter", - "ExpandingWindowSplitter", - "TestPlusTrainSplitter", "ForecastingGridSearchCV", "ForecastingRandomizedSearchCV", "ForecastingSkoptSearchCV", + "ExpandingWindowSplitter", + "SlidingWindowSplitter", + "temporal_train_test_split", ] -from sktime.forecasting.model_selection._split import ( - CutoffSplitter, - ExpandingGreedySplitter, - ExpandingWindowSplitter, - SameLocSplitter, - SingleWindowSplitter, - SlidingWindowSplitter, - TestPlusTrainSplitter, - temporal_train_test_split, -) from sktime.forecasting.model_selection._tune import ( ForecastingGridSearchCV, ForecastingRandomizedSearchCV, ForecastingSkoptSearchCV, ) + + +# todo 0.27.0 - check whether we should remove, otherwise bump +# still used in blog posts and old tutorials +def temporal_train_test_split( + y, X=None, test_size=None, train_size=None, fh=None, anchor="start" +): + """Split time series data into temporal train and test sets. + + DEPRECATED - use sktime.split.temporal_train_test_split instead. + """ + from warnings import warn + + from sktime.split import temporal_train_test_split as _tts + + warn( + "WARNING - the old location of temporal_train_test_split in " + "sktime.forecasting.model_selection is deprecated and is scheduled for " + "imminent removal in a MINOR version. " + "Please update any import statements to " + "from sktime.split import temporal_train_test_split.", + DeprecationWarning, + ) + + return _tts( + y=y, X=X, test_size=test_size, train_size=train_size, fh=fh, anchor=anchor + ) + + +# todo 0.27.0 - check whether we should remove, otherwise bump +# still used in blog posts and old tutorials +def ExpandingWindowSplitter(fh=1, initial_window=10, step_length=1): + """Legacy export of Expanding window splitter. + + DEPRECATED - use sktime.split.ExpandingWindowSplitter instead. + """ + from warnings import warn + + from sktime.split import ExpandingWindowSplitter as _EWSplitter + + warn( + "WARNING - the old location of ExpandingWindowSplitter in " + "sktime.forecasting.model_selection is deprecated and is scheduled for " + "imminent removal in a MINOR version. " + "Please update any import statements to " + "from sktime.split import ExpandingWindowSplitter.", + DeprecationWarning, + ) + + return _EWSplitter(fh=fh, initial_window=initial_window, step_length=step_length) + + +# todo 0.27.0 - check whether we should remove, otherwise bump +# still used in blog posts and old tutorials +def SlidingWindowSplitter( + fh=1, window_length=10, step_length=1, initial_window=None, start_with_window=True +): + """Legacy export of Sliding window splitter. + + DEPRECATED - use sktime.split.ExpandingWindowSplitter instead. + """ + from warnings import warn + + from sktime.split import SlidingWindowSplitter as _SWSplitter + + warn( + "WARNING - the old location of SlidingWindowSplitter in " + "sktime.forecasting.model_selection is deprecated and is scheduled for " + "imminent removal in a MINOR version. " + "Please update any import statements to " + "from sktime.split import SlidingWindowSplitter.", + DeprecationWarning, + ) + + return _SWSplitter( + fh=fh, + window_length=window_length, + step_length=step_length, + initial_window=initial_window, + start_with_window=start_with_window, + ) diff --git a/sktime/forecasting/model_selection/_split.py b/sktime/forecasting/model_selection/_split.py deleted file mode 100644 index 3d77d9d77fb..00000000000 --- a/sktime/forecasting/model_selection/_split.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python3 -u -# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) -"""Implement dataset splitting for model evaluation and selection.""" - -# This module is deprecated. Below the deprecation cycle : -# - Until the 0.25.0 release, imports are allowed from this location but raise a -# DeprecationWarning. -# - In the 0.25.0 release, this file (sktime/forecasting/model_selection/_split.py) -# will be removed. -# todo 0.25.0 : Please ensure this file is deleted. - -__all__ = [ - "ExpandingGreedySplitter", - "ExpandingWindowSplitter", - "SlidingWindowSplitter", - "CutoffSplitter", - "SingleWindowSplitter", - "SameLocSplitter", - "temporal_train_test_split", - "TestPlusTrainSplitter", -] - -import warnings - -from sktime.split import ( - CutoffSplitter, - ExpandingGreedySplitter, - ExpandingWindowSplitter, - SameLocSplitter, - SingleWindowSplitter, - SlidingWindowSplitter, - TestPlusTrainSplitter, - temporal_train_test_split, -) - -warnings.warn( - "Please import sktime splitters from `sktime.split`. Importing splitters from " - "`sktime.forecasting.model_selection` is deprecated and will be removed in release " - "0.25.0", - DeprecationWarning, - stacklevel=2, -) diff --git a/sktime/forecasting/model_selection/_tune.py b/sktime/forecasting/model_selection/_tune.py index 7b70b6d1eb0..8c32e28ca08 100644 --- a/sktime/forecasting/model_selection/_tune.py +++ b/sktime/forecasting/model_selection/_tune.py @@ -30,6 +30,7 @@ class BaseGridSearch(_DelegatedForecaster): _tags = { + "authors": ["mloning", "fkiraly", "aiwalter"], "scitype:y": "both", "requires-fh-in-fit": False, "handles-missing-data": False, @@ -38,7 +39,7 @@ class BaseGridSearch(_DelegatedForecaster): "capability:pred_int:insample": True, } - # todo 0.26.0: remove n_jobs, pre_dispatch parameters and all related logic + # todo 0.27.0: remove n_jobs, pre_dispatch parameters and all related logic def __init__( self, forecaster, @@ -75,18 +76,9 @@ def __init__( super().__init__() - tags_to_clone = [ - "requires-fh-in-fit", - "capability:pred_int", - "capability:pred_int:insample", - "capability:insample", - "ignores-exogeneous-X", - "handles-missing-data", - "y_inner_mtype", - "X_inner_mtype", - "X-y-must-have-same-index", - "enforce_index_type", - ] + self._set_delegated_tags(forecaster) + + tags_to_clone = ["y_inner_mtype", "X_inner_mtype"] self.clone_tags(forecaster, tags_to_clone) self._extend_to_all_scitypes("y_inner_mtype") self._extend_to_all_scitypes("X_inner_mtype") @@ -186,54 +178,26 @@ def _fit(self, y, X, fh): scoring = check_scoring(self.scoring, obj=self) scoring_name = f"test_{scoring.name}" - # todo 0.26.0: remove this logic and only use backend_params + # todo 0.27.0: remove this logic and only use backend_params backend = self.backend backend_params = self.backend_params if self.backend_params else {} if backend in ["threading", "multiprocessing", "loky"]: n_jobs = self.n_jobs pre_dispatch = self.pre_dispatch - backend_params["n_jobs"] = n_jobs - backend_params["pre_dispatch"] = pre_dispatch + if n_jobs is not None: + backend_params["n_jobs"] = n_jobs + if pre_dispatch is not None: + backend_params["pre_dispatch"] = pre_dispatch if n_jobs is not None or pre_dispatch is not None: warn( f"in {self.__class__.__name__}, n_jobs and pre_dispatch " - "parameters are deprecated and will be removed in 0.26.0. " + "parameters are deprecated and will be removed in 0.27.0. " "Please use n_jobs and pre_dispatch directly in the backend_params " "argument instead.", obj=self, stacklevel=2, ) - def _fit_and_score(params, meta): - # Clone forecaster. - forecaster = self.forecaster.clone() - - # Set parameters. - forecaster.set_params(**params) - - # Evaluate. - out = evaluate( - forecaster, - cv, - y, - X, - strategy=self.strategy, - scoring=scoring, - error_score=self.error_score, - ) - - # Filter columns. - out = out.filter(items=[scoring_name, "fit_time", "pred_time"], axis=1) - - # Aggregate results. - out = out.mean() - out = out.add_prefix("mean_") - - # Add parameters to output table. - out["params"] = params - - return out - def evaluate_candidates(candidate_params): candidate_params = list(candidate_params) @@ -247,9 +211,21 @@ def evaluate_candidates(candidate_params): ) ) + # Set meta variables for parallelization. + meta = {} + meta["forecaster"] = self.forecaster + meta["y"] = y + meta["X"] = X + meta["cv"] = cv + meta["strategy"] = self.strategy + meta["scoring"] = scoring + meta["error_score"] = self.error_score + meta["scoring_name"] = scoring_name + out = parallelize( fun=_fit_and_score, iter=candidate_params, + meta=meta, backend=backend, backend_params=backend_params, ) @@ -386,6 +362,35 @@ def _update(self, y, X=None, update_params=True): return self +def _fit_and_score(params, meta): + """Fit and score forecaster with given parameters. + + Root level function for parallelization, called from + BaseGridSearchCV._fit, evaluate_candidates, within parallelize. + """ + meta = meta.copy() + scoring_name = meta.pop("scoring_name") + + # Set parameters. + forecaster = meta.pop("forecaster").clone() + forecaster.set_params(**params) + + # Evaluate. + out = evaluate(forecaster, **meta) + + # Filter columns. + out = out.filter(items=[scoring_name, "fit_time", "pred_time"], axis=1) + + # Aggregate results. + out = out.mean() + out = out.add_prefix("mean_") + + # Add parameters to output table. + out["params"] = params + + return out + + class ForecastingGridSearchCV(BaseGridSearch): """Perform grid-search cross-validation to find optimal model parameters. @@ -401,16 +406,16 @@ class ForecastingGridSearchCV(BaseGridSearch): Parameters ---------- - forecaster : estimator object - The estimator should implement the sktime or scikit-learn estimator - interface. Either the estimator must contain a "score" function, - or a scoring function must be passed. + forecaster : sktime forecaster, BaseForecaster instance or interface compatible + The forecaster to tune, must implement the sktime forecaster interface. + sklearn regressors can be used, but must first be converted to forecasters + via one of the reduction compositors, e.g., via ``make_reduction`` cv : cross-validation generator or an iterable e.g. SlidingWindowSplitter() strategy : {"refit", "update", "no-update_params"}, optional, default="refit" data ingestion strategy in fitting cv, passed to `evaluate` internally defines the ingestion mode when the forecaster sees new data when window expands - "refit" = forecaster is refitted to each training window + "refit" = a new copy of the forecaster is fitted to each training window "update" = forecaster is updated with training window data, in sequence provided "no-update_params" = fit to first training window, re-used without fit or update update_behaviour : str, optional, default = "full_refit" @@ -464,6 +469,7 @@ class ForecastingGridSearchCV(BaseGridSearch): - "None": executes loop sequentally, simple list comprehension - "loky", "multiprocessing" and "threading": uses ``joblib.Parallel`` loops + - "joblib": custom and 3rd party ``joblib`` backends, e.g., ``spark`` - "dask": uses ``dask``, requires ``dask`` package in environment Recommendation: Use "dask" or "loky" for parallel evaluate. @@ -498,10 +504,16 @@ class ForecastingGridSearchCV(BaseGridSearch): Valid keys depend on the value of ``backend``: - "None": no additional parameters, ``backend_params`` is ignored - - "loky", "multiprocessing" and "threading": - any valid keys for ``joblib.Parallel`` can be passed here, - e.g., ``n_jobs``, with the exception of ``backend`` - which is directly controlled by ``backend`` + - "loky", "multiprocessing" and "threading": default ``joblib`` backends + any valid keys for ``joblib.Parallel`` can be passed here, e.g., ``n_jobs``, + with the exception of ``backend`` which is directly controlled by ``backend``. + If ``n_jobs`` is not passed, it will default to ``-1``, other parameters + will default to ``joblib`` defaults. + - "joblib": custom and 3rd party ``joblib`` backends, e.g., ``spark``. + any valid keys for ``joblib.Parallel`` can be passed here, e.g., ``n_jobs``, + ``backend`` must be passed as a key of ``backend_params`` in this case. + If ``n_jobs`` is not passed, it will default to ``-1``, other parameters + will default to ``joblib`` defaults. - "dask": any valid keys for ``dask.compute`` can be passed, e.g., ``scheduler`` Attributes @@ -537,9 +549,7 @@ class ForecastingGridSearchCV(BaseGridSearch): -------- >>> from sktime.datasets import load_shampoo_sales >>> from sktime.forecasting.model_selection import ForecastingGridSearchCV - >>> from sktime.split import ( - ... ExpandingWindowSplitter, - ... ExpandingWindowSplitter) + >>> from sktime.split import ExpandingWindowSplitter >>> from sktime.forecasting.naive import NaiveForecaster >>> y = load_shampoo_sales() >>> fh = [1,2,3] @@ -723,16 +733,16 @@ class ForecastingRandomizedSearchCV(BaseGridSearch): Parameters ---------- - forecaster : estimator object - The estimator should implement the sktime or scikit-learn estimator - interface. Either the estimator must contain a "score" function, - or a scoring function must be passed. + forecaster : sktime forecaster, BaseForecaster instance or interface compatible + The forecaster to tune, must implement the sktime forecaster interface. + sklearn regressors can be used, but must first be converted to forecasters + via one of the reduction compositors, e.g., via ``make_reduction`` cv : cross-validation generator or an iterable e.g. SlidingWindowSplitter() strategy : {"refit", "update", "no-update_params"}, optional, default="refit" data ingestion strategy in fitting cv, passed to `evaluate` internally defines the ingestion mode when the forecaster sees new data when window expands - "refit" = forecaster is refitted to each training window + "refit" = a new copy of the forecaster is fitted to each training window "update" = forecaster is updated with training window data, in sequence provided "no-update_params" = fit to first training window, re-used without fit or update update_behaviour: str, optional, default = "full_refit" @@ -796,6 +806,7 @@ class ForecastingRandomizedSearchCV(BaseGridSearch): - "None": executes loop sequentally, simple list comprehension - "loky", "multiprocessing" and "threading": uses ``joblib.Parallel`` loops + - "joblib": custom and 3rd party ``joblib`` backends, e.g., ``spark`` - "dask": uses ``dask``, requires ``dask`` package in environment Recommendation: Use "dask" or "loky" for parallel evaluate. @@ -830,10 +841,16 @@ class ForecastingRandomizedSearchCV(BaseGridSearch): Valid keys depend on the value of ``backend``: - "None": no additional parameters, ``backend_params`` is ignored - - "loky", "multiprocessing" and "threading": - any valid keys for ``joblib.Parallel`` can be passed here, - e.g., ``n_jobs``, with the exception of ``backend`` - which is directly controlled by ``backend`` + - "loky", "multiprocessing" and "threading": default ``joblib`` backends + any valid keys for ``joblib.Parallel`` can be passed here, e.g., ``n_jobs``, + with the exception of ``backend`` which is directly controlled by ``backend``. + If ``n_jobs`` is not passed, it will default to ``-1``, other parameters + will default to ``joblib`` defaults. + - "joblib": custom and 3rd party ``joblib`` backends, e.g., ``spark``. + any valid keys for ``joblib.Parallel`` can be passed here, e.g., ``n_jobs``, + ``backend`` must be passed as a key of ``backend_params`` in this case. + If ``n_jobs`` is not passed, it will default to ``-1``, other parameters + will default to ``joblib`` defaults. - "dask": any valid keys for ``dask.compute`` can be passed, e.g., ``scheduler`` Attributes @@ -961,10 +978,10 @@ class ForecastingSkoptSearchCV(BaseGridSearch): Parameters ---------- - forecaster : estimator object. - The estimator should implement the sktime or scikit-learn estimator interface. - Either the estimator must contain a "score" function, - or a scoring function must be passed. + forecaster : sktime forecaster, BaseForecaster instance or interface compatible + The forecaster to tune, must implement the sktime forecaster interface. + sklearn regressors can be used, but must first be converted to forecasters + via one of the reduction compositors, e.g., via ``make_reduction`` cv : cross-validation generator or an iterable Splitter used for generating validation folds. e.g. SlidingWindowSplitter() @@ -1022,7 +1039,7 @@ class ForecastingSkoptSearchCV(BaseGridSearch): strategy : {"refit", "update", "no-update_params"}, optional, default="refit" data ingestion strategy in fitting cv, passed to `evaluate` internally defines the ingestion mode when the forecaster sees new data when window expands - "refit" = forecaster is refitted to each training window + "refit" = a new copy of the forecaster is fitted to each training window "update" = forecaster is updated with training window data, in sequence provided "no-update_params" = fit to first training window, re-used without fit or update update_behaviour: str, optional, default = "full_refit" @@ -1055,6 +1072,7 @@ class ForecastingSkoptSearchCV(BaseGridSearch): - "None": executes loop sequentally, simple list comprehension - "loky", "multiprocessing" and "threading": uses ``joblib.Parallel`` loops + - "joblib": custom and 3rd party ``joblib`` backends, e.g., ``spark`` - "dask": uses ``dask``, requires ``dask`` package in environment Recommendation: Use "dask" or "loky" for parallel evaluate. @@ -1085,10 +1103,16 @@ class ForecastingSkoptSearchCV(BaseGridSearch): Valid keys depend on the value of ``backend``: - "None": no additional parameters, ``backend_params`` is ignored - - "loky", "multiprocessing" and "threading": - any valid keys for ``joblib.Parallel`` can be passed here, - e.g., ``n_jobs``, with the exception of ``backend`` - which is directly controlled by ``backend`` + - "loky", "multiprocessing" and "threading": default ``joblib`` backends + any valid keys for ``joblib.Parallel`` can be passed here, e.g., ``n_jobs``, + with the exception of ``backend`` which is directly controlled by ``backend``. + If ``n_jobs`` is not passed, it will default to ``-1``, other parameters + will default to ``joblib`` defaults. + - "joblib": custom and 3rd party ``joblib`` backends, e.g., ``spark``. + any valid keys for ``joblib.Parallel`` can be passed here, e.g., ``n_jobs``, + ``backend`` must be passed as a key of ``backend_params`` in this case. + If ``n_jobs`` is not passed, it will default to ``-1``, other parameters + will default to ``joblib`` defaults. - "dask": any valid keys for ``dask.compute`` can be passed, e.g., ``scheduler`` Attributes @@ -1141,6 +1165,8 @@ class ForecastingSkoptSearchCV(BaseGridSearch): """ _tags = { + "authors": ["HazrulAkmal"], + "maintainers": ["HazrulAkmal"], "scitype:y": "both", "requires-fh-in-fit": False, "handles-missing-data": False, diff --git a/sktime/forecasting/model_selection/tests/test_tune.py b/sktime/forecasting/model_selection/tests/test_tune.py index fa52904dfb0..e1cb65dd624 100644 --- a/sktime/forecasting/model_selection/tests/test_tune.py +++ b/sktime/forecasting/model_selection/tests/test_tune.py @@ -325,7 +325,7 @@ def test_skoptcv_multiple_forecaster(): assert len(sscv.cv_results_) == 5 -BACKEND_TEST = _get_parallel_test_fixtures() +BACKEND_TEST = _get_parallel_test_fixtures("estimator") @pytest.mark.skipif( diff --git a/sktime/forecasting/naive.py b/sktime/forecasting/naive.py index cf518b1ba3b..df2ec152d34 100644 --- a/sktime/forecasting/naive.py +++ b/sktime/forecasting/naive.py @@ -108,6 +108,20 @@ class NaiveForecaster(_BaseWindowForecaster): """ _tags = { + # packaging info + # -------------- + "authors": [ + "mloning", + "piyush1729", + "sri1419", + "Flix6x", + "aiwalter", + "IlyasMoutawwakil", + "fkiraly", + "bethrice44", + ], + # estimator type + # -------------- "y_inner_mtype": "pd.Series", "requires-fh-in-fit": False, "handles-missing-data": True, @@ -191,7 +205,7 @@ def _fit(self, y, X, fh): ) # check window length - if self.window_length_ > len(self._y): + if self.window_length_ > len(y): param = "sp" if self.strategy == "last" and sp != 1 else "window_length_" raise ValueError( f"The {param}: {self.window_length_} is larger than " @@ -348,7 +362,7 @@ def _predict_naive(self, fh=None, X=None): y_old = lagger.fit_transform(_y) y_new = pd.DataFrame(index=expected_index, columns=[0], dtype="float64") full_y = pd.concat([y_old, y_new], keys=["a", "b"]).sort_index(level=-1) - y_filled = full_y.fillna(method="ffill").fillna(method="bfill") + y_filled = full_y.ffill().bfill() # subset to rows that contain elements we wanted to fill y_pred = y_filled.loc["b"] # convert to pd.Series from pd.DataFrame @@ -361,7 +375,7 @@ def _predict_naive(self, fh=None, X=None): y_new_mask = pd.Series(index=expected_index, dtype="float64") y_new = _pivot_sp(y_new_mask, sp, anchor=_y, anchor_side="end") full_y = pd.concat([y_old, y_new], keys=["a", "b"]).sort_index(level=-1) - y_filled = full_y.fillna(method="ffill").fillna(method="bfill") + y_filled = full_y.ffill().bfill() # subset to rows that contain elements we wanted to fill y_pred = y_filled.loc["b"] # reformat to wide @@ -550,14 +564,19 @@ def _predict_var(self, fh, X=None, cov=False): se_res = np.sqrt(mse_res) window_length = self.window_length or T + + def sqrt_flr(x): + """Square root of x, floored at 1 - to deal with in-sample predictions.""" + return np.sqrt(np.maximum(x, 1)) + # Formulas from: # https://otexts.com/fpp3/prediction-intervals.html (Table 5.2) partial_se_formulas = { - "last": lambda h: np.sqrt(h) + "last": sqrt_flr if sp == 1 - else np.sqrt(np.floor((h - 1) / sp) + 1), - "mean": lambda h: np.repeat(np.sqrt(1 + (1 / window_length)), len(h)), - "drift": lambda h: np.sqrt(h * (1 + (h / (T - 1)))), + else lambda h: sqrt_flr(np.floor((h - 1) / sp) + 1), + "mean": lambda h: np.repeat(sqrt_flr(1 + (1 / window_length)), len(h)), + "drift": lambda h: sqrt_flr(h * (1 + (h / (T - 1)))), } fh_periods = np.array(fh.to_relative(self.cutoff)) @@ -649,6 +668,11 @@ class NaiveVariance(BaseForecaster): """ _tags = { + # packaging info + # -------------- + "authors": ["fkiraly", "bethrice44"], + # estimator type + # -------------- "scitype:y": "univariate", "requires-fh-in-fit": False, "handles-missing-data": False, diff --git a/sktime/forecasting/online_learning/_online_ensemble.py b/sktime/forecasting/online_learning/_online_ensemble.py index 38a60327e1d..e50b9824a23 100644 --- a/sktime/forecasting/online_learning/_online_ensemble.py +++ b/sktime/forecasting/online_learning/_online_ensemble.py @@ -24,6 +24,12 @@ class OnlineEnsembleForecaster(EnsembleForecaster): """ _tags = { + # packaging info + # -------------- + "authors": ["magittan", "mloning"], + "maintainers": ["magittan"], + # estimator type + # -------------- "ignores-exogeneous-X": True, "requires-fh-in-fit": False, "handles-missing-data": False, diff --git a/sktime/forecasting/online_learning/_prediction_weighted_ensembler.py b/sktime/forecasting/online_learning/_prediction_weighted_ensembler.py index b48690c0e3d..b3ab085e433 100644 --- a/sktime/forecasting/online_learning/_prediction_weighted_ensembler.py +++ b/sktime/forecasting/online_learning/_prediction_weighted_ensembler.py @@ -21,6 +21,12 @@ class _PredictionWeightedEnsembler: """ _tags = { + # packaging info + # -------------- + "authors": ["magittan"], + "maintainers": ["magittan"], + # estimator type + # -------------- "ignores-exogeneous-X": True, "requires-fh-in-fit": False, "handles-missing-data": False, diff --git a/sktime/forecasting/reconcile.py b/sktime/forecasting/reconcile.py index 8a34084ae45..49ad6d186f4 100644 --- a/sktime/forecasting/reconcile.py +++ b/sktime/forecasting/reconcile.py @@ -3,9 +3,7 @@ """Implements reconciled forecasters for hierarchical data.""" __all__ = ["ReconcilerForecaster"] -__author__ = [ - "ciaran-g", -] +__author__ = ["ciaran-g"] # todo: top down historical proportions? -> new _get_g_matrix_prop(self) @@ -82,6 +80,12 @@ class ReconcilerForecaster(BaseForecaster): """ _tags = { + # packaging info + # -------------- + "authors": "ciaran-g", + "maintainers": "ciaran-g", + # estimator type + # -------------- "scitype:y": "univariate", # which y are fine? univariate/multivariate/both "ignores-exogeneous-X": False, # does estimator ignore the exogeneous X? "handles-missing-data": False, # can estimator handle missing data? diff --git a/sktime/forecasting/sarimax.py b/sktime/forecasting/sarimax.py index 0f47b5f1f0a..a74437c086d 100644 --- a/sktime/forecasting/sarimax.py +++ b/sktime/forecasting/sarimax.py @@ -85,11 +85,103 @@ class SARIMAX(_StatsModelsAdapter): Whether or not to use exact diffuse initialization for non-stationary states. Default is False (in which case approximate diffuse initialization is used). - random_state : int, RandomState instance or None, optional , - default=None β If int, random_state is the seed used by the random + disp : bool, optional, default=False + Set to True to print convergence messages. + random_state : int, RandomState instance or None, optional, default=None + default=None - If int, random_state is the seed used by the random number generator; If RandomState instance, random_state is the random number generator; If None, the random number generator is the RandomState instance used by np.random. + start_params : array_like, optional + Initial guess of the solution for the loglikelihood maximization. If None, the + default is given by SARIMAX.start_params. + transformed : bool, optional + Whether or not `start_params` is already transformed. Default is True. + includes_fixed : bool, optional + If parameters were previously fixed with the `fix_params` method, this argument + describes whether or not `start_params` also includes the fixed parameters, in + addition to the free parameters. Default is False. + cov_type : str, optional + The `cov_type` keyword governs the method for calculating the covariance matrix + of parameter estimates. Can be one of: + + - 'opg' for the outer product of gradient estimator + - 'oim' for the observed information matrix estimator, calculated + using the method of Harvey (1989) + - 'approx' for the observed information matrix estimator, calculated using a + numerical approximation of the Hessian matrix. + - 'robust' for an approximate (quasi-maximum likelihood) covariance matrix that + may be valid even in the presence of some misspecifications. Intermediate + calculations use the 'oim' method. + - 'robust_approx' is the same as 'robust' except that the intermediate + calculations use the 'approx' method. + - 'none' for no covariance matrix calculation. + + Default is 'opg' unless memory conservation is used to avoid + computing the loglikelihood values for each observation, in which + case the default is 'approx'. + cov_kwds : dict or None, optional + A dictionary of arguments affecting covariance matrix computation. + + **opg, oim, approx, robust, robust_approx** + + - 'approx_complex_step' : bool, optional - If True, numerical + approximations are computed using complex-step methods. If False, numerical + approximations are computed using finite difference methods. Default is + True. + - 'approx_centered' : bool, optional - If True, numerical + approximations computed using finite difference methods use a centered + approximation. Default is False. + method : str, optional + The `method` determines which solver from `scipy.optimize` is used, and it can + be chosen from among the following strings: + + - 'newton' for Newton-Raphson + - 'nm' for Nelder-Mead + - 'bfgs' for Broyden-Fletcher-Goldfarb-Shanno (BFGS) + - 'lbfgs' for limited-memory BFGS with optional box constraints + - 'powell' for modified Powell's method + - 'cg' for conjugate gradient + - 'ncg' for Newton-conjugate gradient + - 'basinhopping' for global basin-hopping solver + + The explicit arguments in `fit` are passed to the solver, with the exception of + the basin-hopping solver. Each solver has several optional arguments that are + not the same across solvers. See the notes section below (or scipy.optimize) for + the available arguments and for the list of explicit arguments that the + basin-hopping solver supports. + maxiter : int, optional + The maximum number of iterations to perform. + full_output : bool, optional + Set to True to have all available output in the Results object's mle_retvals + attribute. The output is dependent on the solver. See LikelihoodModelResults + notes section for more information. + callback : callable callback(xk), optional + Called after each iteration, as callback(xk), where xk is the current parameter + vector. + return_params : bool, optional + Whether or not to return only the array of maximizing parameters. Default is + False. + optim_score : {'harvey', 'approx'} or None, optional + The method by which the score vector is calculated. 'harvey' uses the method + from Harvey (1989), 'approx' uses either finite difference or complex step + differentiation depending upon the value of `optim_complex_step`, and None uses + the built-in gradient approximation of the optimizer. Default is None. This + keyword is only relevant if the optimization method uses the score. + optim_complex_step : bool, optional + Whether or not to use complex step differentiation when approximating the score; + if False, finite difference approximation is used. Default is True. This keyword + is only relevant if `optim_score` is set to 'harvey' or 'approx'. + optim_hessian : {'opg','oim','approx'}, optional + The method by which the Hessian is numerically approximated. 'opg' uses outer + product of gradients, 'oim' uses the information matrix formula from Harvey + (1989), and 'approx' uses numerical approximation. This keyword is only relevant + if the optimization method uses the Hessian matrix. + low_memory : bool, optional + If set to True, techniques are applied to substantially reduce memory usage. If + used, some features of the results object will not be available (including + smoothed results and in-sample prediction), although out-of-sample forecasting + is possible. Default is False. See Also -------- @@ -116,6 +208,13 @@ class SARIMAX(_StatsModelsAdapter): """ _tags = { + # packaging info + # -------------- + "authors": ["TNTran92", "yarnabrina"], + "maintainers": ["TNTran92", "yarnabrina"], + # "python_dependencnies": "statsmodels" - inherited from _StatsModelsAdapter + # estimator type + # -------------- "ignores-exogeneous-X": False, "capability:pred_int": True, "capability:pred_int:insample": True, @@ -140,7 +239,22 @@ def __init__( freq=None, missing="none", validate_specification=True, + disp=False, random_state=None, + start_params=None, + transformed=True, + includes_fixed=False, + cov_type=None, + cov_kwds=None, + method="lbfgs", + maxiter=50, + full_output=1, + callback=None, + return_params=False, + optim_score=None, + optim_complex_step=None, + optim_hessian=None, + low_memory=False, ): self.order = order self.seasonal_order = seasonal_order @@ -160,6 +274,23 @@ def __init__( self.missing = missing self.validate_specification = validate_specification + # Fit params + self.disp = disp + self.start_params = start_params + self.transformed = transformed + self.includes_fixed = includes_fixed + self.cov_type = cov_type + self.cov_kwds = cov_kwds + self.method = method + self.maxiter = maxiter + self.full_output = full_output + self.callback = callback + self.return_params = return_params + self.optim_score = optim_score + self.optim_complex_step = optim_complex_step + self.optim_hessian = optim_hessian + self.low_memory = low_memory + super().__init__(random_state=random_state) def _fit_forecaster(self, y, X=None): @@ -186,7 +317,23 @@ def _fit_forecaster(self, y, X=None): missing=self.missing, validate_specification=self.validate_specification, ) - self._fitted_forecaster = self._forecaster.fit() + self._fitted_forecaster = self._forecaster.fit( + disp=self.disp, + start_params=self.start_params, + transformed=self.transformed, + includes_fixed=self.includes_fixed, + cov_type=self.cov_type, + cov_kwds=self.cov_kwds, + method=self.method, + maxiter=self.maxiter, + full_output=self.full_output, + callback=self.callback, + return_params=self.return_params, + optim_score=self.optim_score, + optim_complex_step=self.optim_complex_step, + optim_hessian=self.optim_hessian, + low_memory=self.low_memory, + ) def summary(self): """Get a summary of the fitted forecaster. @@ -268,4 +415,5 @@ def get_test_params(cls, parameter_set="default"): "hamilton_representation": True, "simple_differencing": True, }, + {"cov_type": "robust", "method": "bfgs", "maxiter": 5}, ] diff --git a/sktime/forecasting/squaring_residuals.py b/sktime/forecasting/squaring_residuals.py index c9333d22ade..7265b8aad00 100644 --- a/sktime/forecasting/squaring_residuals.py +++ b/sktime/forecasting/squaring_residuals.py @@ -80,6 +80,12 @@ class SquaringResiduals(BaseForecaster): """ _tags = { + # packaging info + # -------------- + "authors": ["kcc-lion", "fkiraly"], + "maintainers": ["kcc-lion"], + # estimator type + # -------------- "scitype:y": "univariate", # which y are fine? univariate/multivariate/both "ignores-exogeneous-X": True, # does estimator ignore the exogeneous X? "handles-missing-data": False, # can estimator handle missing data? @@ -91,7 +97,6 @@ class SquaringResiduals(BaseForecaster): "capability:insample": False, "capability:pred_int": True, # does forecaster implement proba forecasts? "capability:pred_int:insample": False, - "python_version": None, # PEP 440 python version specifier to limit versions } def __init__( diff --git a/sktime/forecasting/statsforecast.py b/sktime/forecasting/statsforecast.py index 21493ab634d..237bbb5c2f5 100644 --- a/sktime/forecasting/statsforecast.py +++ b/sktime/forecasting/statsforecast.py @@ -7,6 +7,7 @@ "StatsForecastAutoARIMA", "StatsForecastAutoCES", "StatsForecastAutoETS", + "StatsForecastAutoTBATS", "StatsForecastAutoTheta", "StatsForecastMSTL", ] @@ -23,8 +24,12 @@ class StatsForecastAutoARIMA(_GeneralisedStatsForecastAdapter): """StatsForecast AutoARIMA estimator. - This implementation is inspired by Hyndman's forecast::auto.arima [1]_ - and based on the Python implementation of statsforecast [2]_ by Nixtla. + Direct interface to ``statsforecast.models.AutoARIMA`` by Nixtla. + + This estimator directly interfaces ``AutoARIMA``, + from ``statsforecast`` [2]_ by Nixtla. + The ``statsforecast`` implementation is inspired + by Hyndman's forecast::auto.arima [1]_. Returns best ARIMA model according to either AIC, AICc or BIC value. The function conducts a search over possible model within @@ -103,10 +108,12 @@ class StatsForecastAutoARIMA(_GeneralisedStatsForecastAdapter): is to use conditional-sum-of-squares to find starting values, then maximum likelihood. Can be abbreviated. It can be chosen from among the following strings: + - 'CSS-ML' for conditional sum-of-squares to find starting values and then maximum likelihood. - 'ML' for maximum likelihood. - 'CSS' for conditional sum-of-squares. + offset_test_args: dict optional (default None) Additional arguments to be passed to the unit root test. seasonal_test_args: dict optional (default None) @@ -170,6 +177,14 @@ class StatsForecastAutoARIMA(_GeneralisedStatsForecastAdapter): """ _tags = { + # packaging info + # -------------- + "authors": ["FedericoGarza", "yarnabrina"], + "maintainers": ["FedericoGarza"], + # "python_dependencies": "statsforecast" + # inherited from _GeneralisedStatsForecastAdapter + # estimator type + # -------------- "ignores-exogeneous-X": False, "capability:pred_int": True, "capability:pred_int:insample": True, @@ -317,9 +332,12 @@ def get_test_params(cls, parameter_set="default"): class StatsForecastAutoTheta(_GeneralisedStatsForecastAdapter): - """StatsForecast AutoTheta estimator. + """Statsforecast AutoTheta estimator. - This implementation is a wrapper over Nixtla implementation in statsforecast [1]_. + Direct interface to ``statsforecast.models.AutoTheta`` by Nixtla. + + This estimator directly interfaces ``AutoTheta``, + from ``statsforecast`` [1]_ by Nixtla. AutoTheta model automatically selects the best Theta (Standard Theta Model ("STM"), Optimized Theta Model ("OTM"), Dynamic Standard Theta Model ("DSTM"), Dynamic @@ -327,18 +345,19 @@ class StatsForecastAutoTheta(_GeneralisedStatsForecastAdapter): Parameters ---------- - season_length : int, optional + season_length : int, optional, default=1 number of observations per unit of time (e.g. 24 for hourly data), by default 1 - decomposition_type : str, optional - type of seasonal decomposition, by default "multiplicative" + decomposition_type : str, optional, default="multipliciative" possible values: "additive", "multiplicative" + type of seasonal decomposition, by default "multiplicative" + model : Optional[str], optional controlling Theta Model, by default searches the best model References ---------- - .. [1] https://nixtla.github.io/statsforecast/models.html#autotheta + .. [1] https://nixtlaverse.nixtla.io/statsforecast/src/core/models.html#autotheta See Also -------- @@ -346,6 +365,14 @@ class StatsForecastAutoTheta(_GeneralisedStatsForecastAdapter): """ _tags = { + # packaging info + # -------------- + # "authors": ["yarnabrina"], + # "maintainers": ["yarnabrina"], + # "python_dependencies": "statsforecast" + # inherited from _GeneralisedStatsForecastAdapter + # estimator type + # -------------- "ignores-exogeneous-X": True, "capability:pred_int": True, "capability:pred_int:insample": True, @@ -405,7 +432,9 @@ def get_test_params(cls, parameter_set="default"): class StatsForecastAutoETS(_GeneralisedStatsForecastAdapter): """StatsForecast Automatic Exponential Smoothing model. - This implementation is a wrapper over Nixtla implementation in statsforecast [1]_. + Direct interface to ``statsforecast.models.AutoETS``, + from ``statsforecast`` [1]_ by Nixtla. + The ``statsforecast`` implementation is a mirror of Hyndman's forecast::ets [2]_. Automatically selects the best ETS (Error, Trend, Seasonality) model using an information criterion. Default is Akaike Information Criterion (AICc), while @@ -429,13 +458,9 @@ class StatsForecastAutoETS(_GeneralisedStatsForecastAdapter): damped : bool A parameter that 'dampens' the trend. - Notes - ----- - This implementation is a mirror of Hyndman's forecast::ets [2]_. - References ---------- - .. [1] https://nixtla.github.io/statsforecast/models.html#autoets + .. [1] https://nixtlaverse.nixtla.io/statsforecast/src/core/models.html#autoets .. [2] https://github.com/robjhyndman/forecast See Also @@ -444,6 +469,14 @@ class StatsForecastAutoETS(_GeneralisedStatsForecastAdapter): """ _tags = { + # packaging info + # -------------- + # "authors": ["yarnabrina"], + # "maintainers": ["yarnabrina"], + # "python_dependencies": "statsforecast" + # inherited from _GeneralisedStatsForecastAdapter + # estimator type + # -------------- "ignores-exogeneous-X": True, "capability:pred_int": True, "capability:pred_int:insample": True, @@ -500,7 +533,8 @@ def get_test_params(cls, parameter_set="default"): class StatsForecastAutoCES(_GeneralisedStatsForecastAdapter): """StatsForecast Complex Exponential Smoothing model. - This implementation is a wrapper over Nixtla implementation in statsforecast [1]_. + Direct interface to ``statsforecast.models.AutoCES``, + from ``statsforecast`` [1]_ by Nixtla. Automatically selects the best Complex Exponential Smoothing model using an information criterion. Default is Akaike Information Criterion (AICc), while @@ -523,10 +557,18 @@ class StatsForecastAutoCES(_GeneralisedStatsForecastAdapter): References ---------- - .. [1] https://nixtla.github.io/statsforecast/models.html#autoces + .. [1] https://nixtlaverse.nixtla.io/statsforecast/src/core/models.html#autoces """ _tags = { + # packaging info + # -------------- + # "authors": ["yarnabrina"], + # "maintainers": ["yarnabrina"], + # "python_dependencies": "statsforecast" + # inherited from _GeneralisedStatsForecastAdapter + # estimator type + # -------------- "ignores-exogeneous-X": True, "capability:pred_int": True, "capability:pred_int:insample": True, @@ -576,11 +618,125 @@ def get_test_params(cls, parameter_set="default"): return params +class StatsForecastAutoTBATS(_GeneralisedStatsForecastAdapter): + """StatsForecast TBATS model. + + Direct interface to `statsforecast.models.AutoTBATS`, + from `statsforecast` [1]_ by Nixtla. + + Automatically selects the best TBATS model from all feasible combinations of the + parameters `use_boxcox`, `use_trend`, `use_damped_trend`, and `use_arma_errors`. + Selection is made using the AIC. + + Default value for `use_arma_errors` is `True` since this enables the evaluation of + models with and without ARMA errors. + + Parameters + ---------- + seasonal_periods : int or list of int. + Number of observations per unit of time. Ex: 24 Hourly data. + use_boxcox : bool (default=None) + Whether or not to use a Box-Cox transformation. By default tries both. + bc_lower_bound : float (default=0.0) + Lower bound for the Box-Cox transformation. + bc_upper_bound : float (default=1.5) + Upper bound for the Box-Cox transformation. + use_trend : bool (default=None) + Whether or not to use a trend component. By default tries both. + use_damped_trend : bool (default=None) + Whether or not to dampen the trend component. By default tries both. + use_arma_errors : bool (default=True) + Whether or not to use a ARMA errors. + Default is True and this evaluates both models. + + See Also + -------- + BATS + TBATS + + References + ---------- + .. [1] https://nixtlaverse.nixtla.io/statsforecast/src/core/models.html#autotbats + """ + + _tags = { + # packaging info + # -------------- + # "authors": ["yarnabrina"], + # "maintainers": ["yarnabrina"], + # "python_dependencies": "statsforecast" + # inherited from _GeneralisedStatsForecastAdapter + # estimator type + # -------------- + "ignores-exogeneous-X": True, + "capability:pred_int": True, + "capability:pred_int:insample": True, + "python_dependencies": ["statsforecast>=1.7.2"], + } + + def __init__( + self, + seasonal_periods: Union[int, List[int]], + use_boxcox: Optional[bool] = None, + use_trend: Optional[bool] = None, + use_damped_trend: Optional[bool] = None, + use_arma_errors: bool = True, + ): + self.seasonal_periods = seasonal_periods + self.use_boxcox = use_boxcox + self.use_trend = use_trend + self.use_damped_trend = use_damped_trend + self.use_arma_errors = use_arma_errors + + super().__init__() + + def _get_statsforecast_class(self): + """Create underlying forecaster instance.""" + from statsforecast.models import AutoTBATS + + return AutoTBATS + + def _get_statsforecast_params(self) -> dict: + return { + "seasonal_periods": self.seasonal_periods, + "use_boxcox": self.use_boxcox, + "use_trend": self.use_trend, + "use_damped_trend": self.use_damped_trend, + "use_arma_errors": self.use_arma_errors, + } + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + There are currently no reserved values for forecasters. + + Returns + ------- + params : dict or list of dict, default = {} + Parameters to create testing instances of the class + Each dict are parameters to construct an "interesting" test instance, i.e., + `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. + `create_test_instance` uses the first (or only) dictionary in `params` + """ + del parameter_set # to avoid being detected as unused by `vulture` etc. + + params = [{"seasonal_periods": 3}, {"seasonal_periods": [3, 12]}] + + return params + + class StatsForecastMSTL(_GeneralisedStatsForecastAdapter): """StatsForecast Multiple Seasonal-Trend decomposition using LOESS model. - This implementation is a wrapper over Nixtla implementation in - statsforecast [1]_. + Direct interface to ``statsforecast.models.MSTL``, + from ``statsforecast`` [1]_ by Nixtla, with a back-adapter that allows + to use ``sktime`` forecasters as trend forecasters. The MSTL (Multiple Seasonal-Trend decomposition using LOESS) decomposes the time series in multiple seasonalities using LOESS. Then forecasts the trend using @@ -619,10 +775,17 @@ class StatsForecastMSTL(_GeneralisedStatsForecastAdapter): """ _tags = { + # packaging info + # -------------- + "authors": "luca-miniati", + "maintainers": "luca-miniati", + # "python_dependencies": "statsforecast" + # inherited from _GeneralisedStatsForecastAdapter + # estimator type + # -------------- "ignores-exogeneous-X": True, "capability:pred_int": True, "capability:pred_int:insample": True, - "python_dependencies": ["statsforecast"], } def __init__( diff --git a/sktime/forecasting/stream/_update.py b/sktime/forecasting/stream/_update.py index 43c4b2eb5a3..23c6f55da9b 100644 --- a/sktime/forecasting/stream/_update.py +++ b/sktime/forecasting/stream/_update.py @@ -9,13 +9,6 @@ from sktime.datatypes._utilities import get_window from sktime.forecasting.base._delegate import _DelegatedForecaster -# prepare tags to clone - exceptions are TAGS_TO_KEEP -TAGS_TO_KEEP = ["fit_is_empty", "X_inner_mtype", "y_inner_mtype"] -# fit must be executed to fit the wrapped estimator and remember the cutoff -# mtype tags are set so X/y is passed through, conversions happen in wrapped estimator -TAGS_TO_CLONE = _DelegatedForecaster().get_tags().keys() -TAGS_TO_CLONE = list(set(TAGS_TO_CLONE).difference(TAGS_TO_KEEP)) - class UpdateRefitsEvery(_DelegatedForecaster): """Refits periodically when update is called. @@ -50,6 +43,7 @@ class UpdateRefitsEvery(_DelegatedForecaster): _delegate_name = "forecaster_" _tags = { + "authors": "fkiraly", "fit_is_empty": False, "requires-fh-in-fit": False, "y_inner_mtype": ALL_TIME_SERIES_MTYPES, @@ -68,7 +62,8 @@ def __init__( super().__init__() - self.clone_tags(forecaster, TAGS_TO_CLONE) + self._set_delegated_tags(self.forecaster_) + self.set_tags(**{"fit_is_empty": False}) def _fit(self, y, X, fh): """Fit forecaster to training data. @@ -235,6 +230,7 @@ class UpdateEvery(_DelegatedForecaster): _delegate_name = "forecaster_" _tags = { + "authors": "fkiraly", "fit_is_empty": False, "requires-fh-in-fit": False, "y_inner_mtype": ALL_TIME_SERIES_MTYPES, @@ -249,7 +245,8 @@ def __init__(self, forecaster, update_interval=None): super().__init__() - self.clone_tags(forecaster, TAGS_TO_KEEP) + self._set_delegated_tags(self.forecaster_) + self.set_tags(**{"fit_is_empty": False}) def _fit(self, y, X, fh): """Fit forecaster to training data. @@ -400,6 +397,7 @@ class DontUpdate(_DelegatedForecaster): _delegate_name = "forecaster_" _tags = { + "authors": "fkiraly", "fit_is_empty": False, "requires-fh-in-fit": False, "y_inner_mtype": ALL_TIME_SERIES_MTYPES, @@ -412,7 +410,8 @@ def __init__(self, forecaster): super().__init__() - self.clone_tags(forecaster, TAGS_TO_CLONE) + self._set_delegated_tags(self.forecaster_) + self.set_tags(**{"fit_is_empty": False}) def _update(self, y, X=None, update_params=True): """Update time series to incremental training data. diff --git a/sktime/forecasting/structural.py b/sktime/forecasting/structural.py index fe57dc545fa..bdf74b3e21f 100644 --- a/sktime/forecasting/structural.py +++ b/sktime/forecasting/structural.py @@ -198,6 +198,13 @@ class UnobservedComponents(_StatsModelsAdapter): """ _tags = { + # packaging info + # -------------- + "authors": ["juanitorduz"], + "maintainers": ["juanitorduz"], + # python_dependencies: "statsmodels" - inherited from _StatsModelsAdapter + # estimator type + # -------------- "capability:pred_int": True, "capability:pred_int:insample": True, "handles-missing-data": False, diff --git a/sktime/forecasting/tbats.py b/sktime/forecasting/tbats.py index 9477bf76b0d..79fbaca851f 100644 --- a/sktime/forecasting/tbats.py +++ b/sktime/forecasting/tbats.py @@ -79,6 +79,7 @@ class TBATS(_TbatsAdapter): See Also -------- BATS + StatsForecastAutoTBATS References ---------- @@ -134,7 +135,7 @@ def get_test_params(cls, parameter_set="default"): ------- params : dict or list of dict """ - params = { + params1 = { "use_box_cox": False, "use_trend": False, "use_damped_trend": False, @@ -142,4 +143,12 @@ def get_test_params(cls, parameter_set="default"): "use_arma_errors": False, "n_jobs": 1, } - return params + params2 = { + "use_box_cox": False, + "use_trend": True, + "use_damped_trend": True, + "sp": [], + "use_arma_errors": True, + "n_jobs": 2, + } + return [params1, params2] diff --git a/sktime/forecasting/tests/test_all_forecasters.py b/sktime/forecasting/tests/test_all_forecasters.py index 8fe750a3f41..6b79d547673 100644 --- a/sktime/forecasting/tests/test_all_forecasters.py +++ b/sktime/forecasting/tests/test_all_forecasters.py @@ -13,6 +13,7 @@ from sktime.datatypes._utilities import get_cutoff from sktime.exceptions import NotFittedError from sktime.forecasting.base._delegate import _DelegatedForecaster +from sktime.forecasting.base._fh import ForecastingHorizon from sktime.forecasting.tests._config import ( TEST_ALPHAS, TEST_FHS, @@ -350,7 +351,11 @@ def _check_predict_intervals(self, pred_ints, y_train, fh, coverage): """Check expected interval prediction output.""" # check expected type valid, msg, _ = check_is_mtype( - pred_ints, mtype="pred_interval", scitype="Proba", return_metadata=True + pred_ints, + mtype="pred_interval", + scitype="Proba", + return_metadata=True, + msg_return_dict="list", ) # type: ignore assert valid, msg @@ -379,7 +384,7 @@ def get_expected_columns(): found = pred_ints.columns.to_flat_index() msg = ( - "columns of returned prediction interval DataFrame do not" + "columns of returned prediction interval DataFrame do not " f"match up with expected columns. Expected: {expected}," f"found: {found}" ) @@ -436,6 +441,7 @@ def _check_predict_quantiles(self, pred_quantiles, y_train, fh, alpha): mtype="pred_quantiles", scitype="Proba", return_metadata=True, + msg_return_dict="list", ) # type: ignore assert valid, msg @@ -830,7 +836,7 @@ def test_hierarchical_with_exogeneous(self, estimator_instance, n_columns): y_pred = estimator_instance.predict(X=X_test) assert isinstance(y_pred, pd.DataFrame) - assert check_is_mtype(y_pred, "pd_multiindex_hier") + assert check_is_mtype(y_pred, "pd_multiindex_hier", msg_return_dict="list") msg = ( "returned columns after predict are not as expected. " f"expected: {y_train.columns}. Found: {y_pred.columns}" @@ -851,7 +857,9 @@ def test_hierarchical_with_exogeneous(self, estimator_instance, n_columns): y_pred_int = estimator_instance.predict_interval(X=X_test) assert isinstance(y_pred_int, pd.DataFrame) - assert check_is_mtype(y_pred_int, "pd_multiindex_hier") + assert check_is_mtype( + y_pred_int, "pd_multiindex_hier", msg_return_dict="list" + ) if len(y_pred_int.index) == len(X_test.index): assert np.all(y_pred_int.index == X_test.index) @@ -861,9 +869,32 @@ def test_hierarchical_with_exogeneous(self, estimator_instance, n_columns): y_pred_q = estimator_instance.predict_quantiles(X=X_test) assert isinstance(y_pred_q, pd.DataFrame) - assert check_is_mtype(y_pred_q, "pd_multiindex_hier") + assert check_is_mtype( + y_pred_q, "pd_multiindex_hier", msg_return_dict="list" + ) if len(y_pred_q.index) == len(X_test.index): assert np.all(y_pred_q.index == X_test.index) else: assert set(X_test.index).issubset(y_pred_q.index) + + def test_fit_predict(self, estimator_instance, n_columns): + """Check fit_predict method against interface expectations. + + Does not check directly against fit and predict, as either may + be stochastic and not return the same result each time. + """ + y = _make_series(n_columns=n_columns) + X = _make_series(n_columns=3) + + fh = ForecastingHorizon([1, 2, 3]) + + y_train, _, X_train, X_test = temporal_train_test_split(y, X, fh=fh) + + y_pred = estimator_instance.fit_predict( + y=y_train, X=X_train, fh=fh, X_pred=X_test + ) + + cutoff = get_cutoff(y_train, return_index=True) + _assert_correct_pred_time_index(y_pred.index, cutoff, fh) + _assert_correct_columns(y_pred, y_train) diff --git a/sktime/forecasting/tests/test_conformal.py b/sktime/forecasting/tests/test_conformal.py index a371cc6d634..dc84aeda778 100644 --- a/sktime/forecasting/tests/test_conformal.py +++ b/sktime/forecasting/tests/test_conformal.py @@ -23,7 +23,7 @@ def test_conformal_standard(): conformal_forecaster.fit(y, fh=[1, 2, 3]) pred_int = conformal_forecaster.predict_interval() - assert check_is_mtype(pred_int, "pred_interval", "Proba") + assert check_is_mtype(pred_int, "pred_interval", "Proba", msg_return_dict="list") @pytest.mark.skipif( @@ -60,7 +60,9 @@ def test_conformal_with_gscv(): y_pred_quantiles = gscv_with_conformal.predict_quantiles() - assert check_is_mtype(y_pred_quantiles, "pred_quantiles", "Proba") + assert check_is_mtype( + y_pred_quantiles, "pred_quantiles", "Proba", msg_return_dict="list" + ) @pytest.mark.skipif( diff --git a/sktime/forecasting/tests/test_exp_smoothing.py b/sktime/forecasting/tests/test_exp_smoothing.py index fe1a2cf21d4..2d2633faac8 100644 --- a/sktime/forecasting/tests/test_exp_smoothing.py +++ b/sktime/forecasting/tests/test_exp_smoothing.py @@ -1,11 +1,13 @@ """Test exponential smoothing forecasters.""" -__author__ = ["mloning", "big-o"] +__author__ = ["mloning", "big-o", "ciaran-g"] __all__ = ["test_set_params"] +import pandas as pd import pytest from numpy.testing import assert_array_equal +from sktime.datasets import load_airline from sktime.forecasting.exp_smoothing import ExponentialSmoothing from sktime.split import temporal_train_test_split from sktime.utils._testing.forecasting import make_forecasting_problem @@ -35,3 +37,23 @@ def test_set_params(): y_pred = f.predict() assert_array_equal(y_pred, expected) + + +@pytest.mark.skipif( + not _check_soft_dependencies("statsmodels", severity="none"), + reason="skip test if required soft dependency not available", +) +def check_panel_expsmooth(): + """Test exponential smoothing on panel data with datetime index.""" + # make panel with hour of day panel and datetime index + y = load_airline() + y.index = pd.date_range(start="1960-01-01", periods=len(y.index), freq="H") + y.index.names = ["datetime"] + y.name = "passengers" + y = y.to_frame() + y["hour_of_day"] = y.index.hour + y = y.reset_index().set_index(["hour_of_day", "datetime"]).sort_index() + + forecaster = ExponentialSmoothing(trend="add", sp=1) + forecaster.fit(y) + forecaster.predict(fh=[1, 3]) diff --git a/sktime/forecasting/tests/test_naive.py b/sktime/forecasting/tests/test_naive.py index ef5f37af02a..c003e18bfb8 100644 --- a/sktime/forecasting/tests/test_naive.py +++ b/sktime/forecasting/tests/test_naive.py @@ -213,7 +213,7 @@ def test_strategy_mean_and_last_seasonal_additional_combinations( # For selected cases, remove a redundant data point by making it NaN if window_length > sp: # create a trailing NaN value in the training set - data[window_length - 1] = np.nan + data.iloc[window_length - 1] = np.nan # Split into train and test data train_data = data[:window_length] diff --git a/sktime/forecasting/tests/test_prophet.py b/sktime/forecasting/tests/test_prophet.py index e1cc1012791..82ca8d25279 100644 --- a/sktime/forecasting/tests/test_prophet.py +++ b/sktime/forecasting/tests/test_prophet.py @@ -3,7 +3,9 @@ # copyright: sktime developers, BSD-3-Clause License (see LICENSE file) """ -__author__ = ["fkiraly"] +__author__ = ["fkiraly", "tpvasconcelos"] + +from unittest import mock import pandas as pd import pytest @@ -77,3 +79,28 @@ def test_prophet_period_fh(convert_to_datetime): else: assert isinstance(y_pred.index, pd.PeriodIndex) assert (y_pred.index == fh_index).all() + + +@pytest.mark.skipif( + not run_test_for_class(Prophet), + reason="run test only if softdeps are present and incrementally (if requested)", +) +@pytest.mark.parametrize( + "fit_kwargs", [None, {"foo": "bar"}, {"foo1": "bar1", "foo2": "bar2"}] +) +def test_prophet_fit_kwargs_are_passed_down(fit_kwargs: dict): + """Test that the `fit_kwargs` hyperparameter is passed down to Prophet.fit().""" + from sktime.datasets import load_airline + from sktime.forecasting.fbprophet import Prophet + + y = load_airline() + with mock.patch("prophet.forecaster.Prophet.fit") as mock_fit: + forecaster = Prophet(fit_kwargs=fit_kwargs) + forecaster.fit(y) + mock_fit.assert_called_once() + assert mock_fit.call_args.args == () + call_kwargs = mock_fit.call_args.kwargs + # `df` should always be one of the arguments but + # we don't care about its actual value here + call_kwargs.pop("df") + assert call_kwargs == (fit_kwargs or {}) diff --git a/sktime/forecasting/tests/test_statsforecast.py b/sktime/forecasting/tests/test_statsforecast.py new file mode 100644 index 00000000000..106230898e9 --- /dev/null +++ b/sktime/forecasting/tests/test_statsforecast.py @@ -0,0 +1,43 @@ +"""Tests for StatsForecast. + +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +""" + +from unittest.mock import patch + +import numpy as np +import pandas as pd +import pytest + +from sktime.forecasting.base import ForecastingHorizon +from sktime.forecasting.statsforecast import StatsForecastMSTL +from sktime.tests.test_switch import run_test_for_class + + +@pytest.mark.skipif( + not run_test_for_class(StatsForecastMSTL), + reason="run test only if softdeps are present and incrementally (if requested)", +) +@patch("statsforecast.models.AutoETS", autospec=True) +def test_statsforecast_mstl(mock_autoets): + """ + Check that StatsForecast MSTL adapter calls trend forecaster with + the correct arguments. + """ + from sktime.datasets import load_airline + + y = load_airline() + + predict = mock_autoets.return_value.predict + predict.return_value = { + "mean": np.arange(36, dtype=np.float64), + "lo-95.0": np.arange(36, dtype=np.float64), + "hi-95.0": np.arange(36, dtype=np.float64), + } + + model = StatsForecastMSTL(season_length=[12]) + model.fit(y) + fh_index = pd.PeriodIndex(pd.date_range("1961-01", periods=36, freq="M")) + fh = ForecastingHorizon(fh_index, is_relative=False) + model.predict_interval(fh, coverage=0.95) + predict.assert_called_with(36, X=None, level=[95.0]) diff --git a/sktime/forecasting/tests/test_theta.py b/sktime/forecasting/tests/test_theta.py index f6b6685b15b..a31a22fd3de 100644 --- a/sktime/forecasting/tests/test_theta.py +++ b/sktime/forecasting/tests/test_theta.py @@ -1,9 +1,10 @@ """Tests for ThetaForecaster.""" # copyright: sktime developers, BSD-3-Clause License (see LICENSE file) -__author__ = ["big-o", "kejsitake"] +__author__ = ["big-o", "kejsitake", "ciaran-g"] import numpy as np +import pandas as pd import pytest from sktime.datasets import load_airline @@ -121,3 +122,24 @@ def test_theta_and_thetamodular(): y_pred_thetamodular = f1.predict(fh=fh) np.testing.assert_allclose(y_pred_theta, y_pred_thetamodular, rtol=0.06) + + +@pytest.mark.skipif( + not _check_soft_dependencies("statsmodels", severity="none"), + reason="skip test if required soft dependency not available", +) +def check_panel_theta_quantiles(): + """Test predict quantiles with theta on panel data with datetime index.""" + # make panel with hour of day panel and datetime index + y = load_airline() + y.index = pd.date_range(start="1960-01-01", periods=len(y.index), freq="H") + y.index.names = ["datetime"] + y.name = "passengers" + y = y.to_frame() + y["hour_of_day"] = y.index.hour + y = y.reset_index().set_index(["hour_of_day", "datetime"]).sort_index() + + forecaster = ThetaForecaster(sp=1) + forecaster.fit(y) + forecaster.predict(fh=[1, 3]) + forecaster.predict_quantiles(fh=[1, 3], alpha=[0.1, 0.5, 0.9]) diff --git a/sktime/forecasting/theta.py b/sktime/forecasting/theta.py index ce00bf451c4..6f7460579b2 100644 --- a/sktime/forecasting/theta.py +++ b/sktime/forecasting/theta.py @@ -89,7 +89,13 @@ class ThetaForecaster(ExponentialSmoothing): _fitted_param_names = ("initial_level", "smoothing_level") _tags = { + # packaging info + # -------------- + "authors": ["big-o", "mloning", "kejsitake", "fkiraly", "GuzalBulatova"], "scitype:y": "univariate", + # "python_dependencies": "statsmodels" - inherited from _StatsModelsAdapter + # estimator type + # -------------- "ignores-exogeneous-X": True, "capability:pred_int": True, "capability:pred_int:insample": True, @@ -411,6 +417,7 @@ class ThetaModularForecaster(BaseForecaster): """ _tags = { + "authors": ["GuzalBulatova", "fkiraly"], "univariate-only": False, "y_inner_mtype": "pd.Series", "requires-fh-in-fit": False, diff --git a/sktime/forecasting/trend/__init__.py b/sktime/forecasting/trend/__init__.py index f1df869127b..70703a83205 100644 --- a/sktime/forecasting/trend/__init__.py +++ b/sktime/forecasting/trend/__init__.py @@ -7,11 +7,15 @@ "PolynomialTrendForecaster", "STLForecaster", "CurveFitForecaster", + "ProphetPiecewiseLinearTrendForecaster", ] from sktime.forecasting.trend._curve_fit_forecaster import CurveFitForecaster from sktime.forecasting.trend._polynomial_trend_forecaster import ( PolynomialTrendForecaster, ) +from sktime.forecasting.trend._pwl_trend_forecaster import ( + ProphetPiecewiseLinearTrendForecaster, +) from sktime.forecasting.trend._stl_forecaster import STLForecaster from sktime.forecasting.trend._trend_forecaster import TrendForecaster diff --git a/sktime/forecasting/trend/_curve_fit_forecaster.py b/sktime/forecasting/trend/_curve_fit_forecaster.py index 741b6d13298..0d7803e9846 100644 --- a/sktime/forecasting/trend/_curve_fit_forecaster.py +++ b/sktime/forecasting/trend/_curve_fit_forecaster.py @@ -74,6 +74,8 @@ class CurveFitForecaster(BaseForecaster): """ _tags = { + "authors": ["benheid"], + "maintainers": ["benheid"], "scitype:y": "univariate", "y_inner_mtype": "pd.Series", "X_inner_mtype": "pd.DataFrame", diff --git a/sktime/forecasting/trend/_polynomial_trend_forecaster.py b/sktime/forecasting/trend/_polynomial_trend_forecaster.py index 2da6bc927de..fcafac102ed 100644 --- a/sktime/forecasting/trend/_polynomial_trend_forecaster.py +++ b/sktime/forecasting/trend/_polynomial_trend_forecaster.py @@ -18,28 +18,30 @@ class PolynomialTrendForecaster(BaseForecaster): r"""Forecast time series data with a polynomial trend. - Uses a `sklearn` regressor specified by the `regressor` parameter + Uses an ``sklearn`` regressor specified by the ``regressor`` parameter to perform regression on time series values against their corresponding indices, after extraction of polynomial features. - Same as `TrendForecaster` where `regressor` is pipelined with transformation step - `PolynomialFeatures(degree, with_intercept)` applied to time index, at the start. + Same as ``TrendForecaster`` where ``regressor`` is pipelined with transformation + step ``PolynomialFeatures(degree, with_intercept)`` applied to time index, + at the start. - In `fit`, for input time series :math:`(v_i, p(t_i)), i = 1, \dots, T`, + In ``fit``, for input time series :math:`(v_i, p(t_i)), i = 1, \dots, T`, where :math:`v_i` are values, :math:`t_i` are time stamps, and :math:`p` is the polynomial feature transform with degree `degree`, and with/without intercept depending on `with_intercept`, - fits an `sklearn` model :math:`v_i = f(p(t_i)) + \epsilon_i`, where `f` is - the model fitted when `regressor.fit` is passed `X` = vector of :math:`p(t_i)`, - and `y` = vector of :math:`v_i`. + fits an `sklearn` model :math:`v_i = f(p(t_i)) + \epsilon_i`, where :math:`f` is + the model fitted when ``regressor.fit`` is passed ``X`` = vector of :math:`p(t_i)`, + and ``y`` = vector of :math:`v_i`. - In `predict`, for a new time point :math:`t_*`, predicts :math:`f(p(t_*))`, - where :math:`f` is the function as fitted above in `fit`, + In ``predict``, for a new time point :math:`t_*`, predicts :math:`f(p(t_*))`, + where :math:`f` is the function as fitted above in ``fit``, and :math:`p` is the same polynomial feature transform as above. - Default for `regressor` is linear regression = `sklearn` `LinearRegression` default. + Default for ``regressor`` is linear regression = ``sklearn`` ``LinearRegression``, + with default parameters. Default for `degree` is 1. If time stamps are `pd.DatetimeIndex`, fitted coefficients are in units - of days since start of 1970. If time stamps are `pd.PeriodIndex`, + of days since start of 1970. If time stamps are ``pd.PeriodIndex``, coefficients are in units of (full) periods since start of 1970. Parameters @@ -54,6 +56,14 @@ class PolynomialTrendForecaster(BaseForecaster): zero. (i.e. a column of ones, acts as an intercept term in a linear model) + Attributes + ---------- + regressor_ : sklearn regressor estimator object + The fitted regressor object. + This is a fitted ``sklearn`` pipeline with steps + ``PolynomialFeatures(degree, with_intercept)``, + followed by a clone of ``regressor``. + Examples -------- >>> from sktime.datasets import load_airline @@ -66,6 +76,8 @@ class PolynomialTrendForecaster(BaseForecaster): """ _tags = { + "authors": ["tensorflow-as-tf", "mloning", "aiwalter", "fkiraly"], + "maintainers": ["tensorflow-as-tf"], "ignores-exogeneous-X": True, "requires-fh-in-fit": False, "handles-missing-data": False, diff --git a/sktime/forecasting/trend/_pwl_trend_forecaster.py b/sktime/forecasting/trend/_pwl_trend_forecaster.py new file mode 100644 index 00000000000..e5620f2747c --- /dev/null +++ b/sktime/forecasting/trend/_pwl_trend_forecaster.py @@ -0,0 +1,209 @@ +#!/usr/bin/env python3 -u +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +"""Implements a piecewise linear trend forecaster by wrapping fbprophet.""" + +__author__ = ["sbuse"] + +import pandas as pd + +from sktime.forecasting.base._base import DEFAULT_ALPHA +from sktime.forecasting.base.adapters import _ProphetAdapter + + +class ProphetPiecewiseLinearTrendForecaster(_ProphetAdapter): + """ + Forecast time series data with a piecewise linear trend, fitted via prophet. + + The forecaster uses Facebook's prophet algorithm [1]_ and extracts the piecewise + linear trend from it. Only hyper-parameters relevant for the trend modelling are + exposed via the constructor. + + Seasonalities are set to additive and "auto" detection in prophet, + which means that yearly, weekly and daily seasonality are automatically detected, + and included in the model if present, using prophet's default settings. + + For more granular control of components or seasonality, use + ``sktime.forecasting.fbprophet.Prophet`` directly. + + Data can be passed in one of the sktime compatible formats, + naming a column `ds` such as in the prophet package is not necessary. + + Unlike vanilla `prophet`, also supports integer/range and period index: + * integer/range index is interpreted as days since Jan 1, 2000 + * `PeriodIndex` is converted using the `pandas` method `to_timestamp` + + Parameters + ---------- + changepoints: list or None, default=None + List of dates at which to include potential changepoints. If + not specified, potential changepoints are selected automatically. + n_changepoints: int, default=25 + Number of potential changepoints to include. Not used + if input `changepoints` is supplied. If `changepoints` is not supplied, + then n_changepoints potential changepoints are selected uniformly from + the first `changepoint_range` proportion of the history. + changepoint_range: float, default=0.8 + Proportion of history in which trend changepoints will + be estimated. Defaults to 0.8 for the first 80%. Not used if + `changepoints` is specified. + changepoint_prior_scale: float, default=0.05 + Parameter modulating the flexibility of the + automatic changepoint selection. Large values will allow many + changepoints, small values will allow few changepoints. + Recommended to take values within [0.001,0.5]. + + References + ---------- + .. [1] https://facebook.github.io/prophet + + Examples + -------- + >>> from sktime.datasets import load_airline + >>> from sktime.forecasting.trend import ProphetPiecewiseLinearTrendForecaster + >>> from sktime.forecasting.base import ForecastingHorizon + >>> from sktime.split import temporal_train_test_split + >>> y =load_airline().to_timestamp(freq='M') + >>> y_train, y_test = temporal_train_test_split(y) + >>> fh = ForecastingHorizon(y.index, is_relative=False) + >>> forecaster = ProphetPiecewiseLinearTrendForecaster() # doctest: +SKIP + >>> forecaster.fit(y_train) # doctest: +SKIP + ProphetPiecewiseLinearTrendForecaster(...) + >>> y_pred = forecaster.predict(fh) # doctest: +SKIP + """ + + _tags = { + "authors": ["sbuse"], + "maintainers": ["sbuse"], + "scitype:y": "univariate", + "y_inner_mtype": "pd.DataFrame", + "X_inner_mtype": "pd.DataFrame", + "ignores-exogeneous-X": True, + "requires-fh-in-fit": False, + "python_dependencies": "prophet", + } + + def __init__( + self, + changepoints=None, + n_changepoints=25, + changepoint_range=0.8, + changepoint_prior_scale=0.05, + verbose=0, + ): + self.freq = None + self.add_seasonality = None + self.add_country_holidays = None + self.growth = "linear" + self.growth_floor = 0.0 + self.growth_cap = None + self.changepoints = changepoints + self.n_changepoints = n_changepoints + self.changepoint_range = changepoint_range + self.yearly_seasonality = "auto" + self.weekly_seasonality = "auto" + self.daily_seasonality = "auto" + self.holidays = None + self.seasonality_mode = "additive" + self.seasonality_prior_scale = 10.0 + self.changepoint_prior_scale = changepoint_prior_scale + self.holidays_prior_scale = 10.0 + self.mcmc_samples = 0 + self.alpha = DEFAULT_ALPHA + self.uncertainty_samples = 1000 + self.stan_backend = None + self.verbose = verbose + + super().__init__() + + # import inside method to avoid hard dependency + from prophet.forecaster import Prophet as _Prophet + + self._ModelClass = _Prophet + + def _instantiate_model(self): + self._forecaster = self._ModelClass( + growth=self.growth, + changepoints=self.changepoints, + n_changepoints=self.n_changepoints, + changepoint_range=self.changepoint_range, + yearly_seasonality=self.yearly_seasonality, + weekly_seasonality=self.weekly_seasonality, + daily_seasonality=self.daily_seasonality, + holidays=self.holidays, + seasonality_mode=self.seasonality_mode, + seasonality_prior_scale=float(self.seasonality_prior_scale), + holidays_prior_scale=float(self.holidays_prior_scale), + changepoint_prior_scale=float(self.changepoint_prior_scale), + mcmc_samples=self.mcmc_samples, + interval_width=1 - self.alpha, + uncertainty_samples=self.uncertainty_samples, + stan_backend=self.stan_backend, + ) + return self + + # _fit is defined in the superclass and is fine as it is. + + def _predict(self, fh, X=None): + """Forecast time series trend at future horizon. + + private _predict containing the core logic, called from predict + + State required: + Requires state to be "fitted". + + Accesses in self: + Fitted model attributes ending in "_" + self.cutoff + + Parameters + ---------- + fh : guaranteed to be ForecastingHorizon or None, optional (default=None) + The forecasting horizon with the steps ahead to to predict. + X : pd.DataFrame, optional (default=None) + Exogenous time series + + Returns + ------- + y_pred : pd.DataFrame + Point predictions + """ + fh = self._get_prophet_fh() + future = pd.DataFrame({"ds": fh}, index=fh) + + out = self._forecaster.setup_dataframe(future.copy()) + out["trend"] = self._forecaster.predict_trend(out) + + y_pred = out.loc[:, "trend"] + y_pred.index = future.index + + if isinstance(self._y.columns[0], str): + y_pred.name = self._y.columns[0] + else: + y_pred.name = None + + if self.y_index_was_int_ or self.y_index_was_period_: + y_pred.index = self.fh.to_absolute_index(cutoff=self.cutoff) + + return y_pred + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + + + Returns + ------- + params : dict or list of dict + """ + params0 = { + "changepoint_range": 0.8, + "changepoint_prior_scale": 0.05, + } + + return params0 diff --git a/sktime/forecasting/trend/_stl_forecaster.py b/sktime/forecasting/trend/_stl_forecaster.py index 41843579626..2b7dc4ad747 100644 --- a/sktime/forecasting/trend/_stl_forecaster.py +++ b/sktime/forecasting/trend/_stl_forecaster.py @@ -134,6 +134,8 @@ class STLForecaster(BaseForecaster): """ _tags = { + "authors": ["tensorflow-as-tf", "mloning", "aiwalter", "fkiraly"], + "maintainers": ["tensorflow-as-tf"], "scitype:y": "univariate", # which y are fine? univariate/multivariate/both "ignores-exogeneous-X": False, # does estimator ignore the exogeneous X? "handles-missing-data": False, # can estimator handle missing data? diff --git a/sktime/forecasting/trend/_trend_forecaster.py b/sktime/forecasting/trend/_trend_forecaster.py index 0377e821b20..c0fe92d8dc6 100644 --- a/sktime/forecasting/trend/_trend_forecaster.py +++ b/sktime/forecasting/trend/_trend_forecaster.py @@ -16,23 +16,24 @@ class TrendForecaster(BaseForecaster): r"""Trend based forecasts of time series data, regressing values on index. - Uses a `sklearn` regressor specified by the `regressor` parameter + Uses an ``sklearn`` regressor specified by the ``regressor`` parameter to perform regression on time series values against their corresponding indices, providing trend-based forecasts: - In `fit`, for input time series :math:`(v_i, t_i), i = 1, \dots, T`, + In ``fit``, for input time series :math:`(v_i, t_i), i = 1, \dots, T`, where :math:`v_i` are values and :math:`t_i` are time stamps, - fits an `sklearn` model :math:`v_i = f(t_i) + \epsilon_i`, where `f` is - the model fitted when `regressor.fit` is passed `X` = vector of :math:`t_i`, - and `y` = vector of :math:`v_i`. + fits an `sklearn` model :math:`v_i = f(t_i) + \epsilon_i`, where :math:`f` is + the model fitted when ``regressor.fit`` is passed ``X`` = vector of :math:`t_i`, + and ``y`` = vector of :math:`v_i`. - In `predict`, for a new time point :math:`t_*`, predicts :math:`f(t_*)`, - where :math:`f` is the function as fitted above in `fit`. + In ``predict``, for a new time point :math:`t_*`, predicts :math:`f(t_*)`, + where :math:`f` is the function as fitted above in ``fit``. - Default for `regressor` is linear regression = `sklearn` `LinearRegression` default. + Default for ``regressor`` is linear regression = ``sklearn`` ``LinearRegression``, + with default parameters. - If time stamps are `pd.DatetimeIndex`, fitted coefficients are in units - of days since start of 1970. If time stamps are `pd.PeriodIndex`, + If time stamps are ``pd.DatetimeIndex``, fitted coefficients are in units + of days since start of 1970. If time stamps are ``pd.PeriodIndex``, coefficients are in units of (full) periods since start of 1970. Parameters @@ -41,6 +42,11 @@ class TrendForecaster(BaseForecaster): Define the regression model type. If not set, will default to sklearn.linear_model.LinearRegression + Attributes + ---------- + regressor_ : sklearn regressor estimator object + The fitted regressor object. Clone of ``regressor``. + Examples -------- >>> from sktime.datasets import load_airline @@ -53,6 +59,8 @@ class TrendForecaster(BaseForecaster): """ _tags = { + "authors": ["tensorflow-as-tf", "mloning", "aiwalter", "fkiraly"], + "maintainers": ["tensorflow-as-tf"], "ignores-exogeneous-X": True, "requires-fh-in-fit": False, "handles-missing-data": False, diff --git a/sktime/forecasting/trend/tests/test_pwl_trend.py b/sktime/forecasting/trend/tests/test_pwl_trend.py new file mode 100644 index 00000000000..01275098c47 --- /dev/null +++ b/sktime/forecasting/trend/tests/test_pwl_trend.py @@ -0,0 +1,130 @@ +"""Test piecewise linear trend forecasters. + +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +""" + +__author__ = ["sbuse"] + +import numpy as np +import pandas as pd +import pytest + +from sktime.datasets import load_airline +from sktime.forecasting.base import ForecastingHorizon +from sktime.forecasting.trend import ( + PolynomialTrendForecaster, + ProphetPiecewiseLinearTrendForecaster, +) +from sktime.split import temporal_train_test_split +from sktime.tests.test_switch import run_test_for_class + + +@pytest.mark.skipif( + not run_test_for_class(ProphetPiecewiseLinearTrendForecaster), + reason="run test only if softdeps are present and incrementally (if requested)", +) +def test_for_changes_in_original(): + """Check if the original prophet implementation returns the same result as the + sktime wrapper for the airline dataset. + + Raises + ------ + AssertionError - if the predictions are not exactly the same + """ + from prophet import Prophet + + from sktime.forecasting.fbprophet import Prophet as skProphet + + y = load_airline().to_timestamp(freq="M") + + # ------original Prophet--------- + prophet = Prophet() + prophet.fit(pd.DataFrame(data={"ds": y.index, "y": y.values})) + future = prophet.make_future_dataframe(periods=12, freq="M", include_history=False) + forecast = prophet.predict(future)[["ds", "yhat"]] + y_pred_original = forecast["yhat"] + y_pred_original.index = forecast["ds"].values + + # ------sktime Prophet----------- + skprophet = skProphet() + y_pred_sktime = skprophet.fit_predict(y, fh=np.arange(1, 13)) + + np.testing.assert_array_equal(y_pred_original.values, y_pred_sktime.values) # exact + + +@pytest.mark.skipif( + not run_test_for_class(ProphetPiecewiseLinearTrendForecaster), + reason="run test only if softdeps are present and incrementally (if requested)", +) +def test_pred_errors_against_linear(): + """Check prediction performance on airline dataset. + + For a small value of changepoint_prior_scale like 0.001 the + ProphetPiecewiseLinearTrendForecaster must return a single straight trendline. + + Raises + ------ + AssertionError - if the trend forecast is not compatible with a linear trend. + """ + y = load_airline().to_timestamp(freq="M") + fh = ForecastingHorizon(y.index, is_relative=False) + + pwl = ProphetPiecewiseLinearTrendForecaster(changepoint_prior_scale=0.001) + y_pred_pwl = pwl.fit(y).predict(fh) + + linear = PolynomialTrendForecaster(degree=1) + y_pred_linear = linear.fit(y).predict(fh) + + np.testing.assert_allclose(y_pred_pwl, y_pred_linear, rtol=0.04) + + +@pytest.mark.skipif( + not run_test_for_class(ProphetPiecewiseLinearTrendForecaster), + reason="run test only if softdeps are present and incrementally (if requested)", +) +def test_pred_with_explicit_changepoints(): + """Check functionality with explicit changepoints. + + When changepoints are passed to the ProphetPiecewiseLinearTrendForecaster + the prediction has to be different then the automatic detection because the + changepoints are forcefully added. + + Raises + ------ + AssertionError - if adding a changepoint has no effect on the trend prediction. + """ + y = load_airline().to_timestamp(freq="M") + y_train, y_test = temporal_train_test_split(y) + + fh = ForecastingHorizon(y_test.index, is_relative=False) + a = ProphetPiecewiseLinearTrendForecaster(changepoints=["1953-05-31"]) + b = ProphetPiecewiseLinearTrendForecaster() + + slope_a = a.fit(y_train).predict(fh).diff().mean() + slope_b = b.fit(y_train).predict(fh).diff().mean() + + assert not np.allclose(slope_a, slope_b, rtol=0.1) + + +@pytest.mark.skipif( + not run_test_for_class(ProphetPiecewiseLinearTrendForecaster), + reason="run test only if softdeps are present and incrementally (if requested)", +) +@pytest.mark.parametrize("indextype", ["range", "period"]) +def test_pwl_trend_nonnative_index(indextype): + """Check pwl detrend with RangeIndex and PeriodIndex.""" + y = pd.DataFrame({"a": [1, 2, 3, 4]}) + + if indextype == "period": + y.index = pd.period_range("2000-01-01", periods=4) + + fh = [1, 2] + + f = ProphetPiecewiseLinearTrendForecaster() + f.fit(y) + y_pred = f.predict(fh=fh) + + if indextype == "range": + assert pd.api.types.is_integer_dtype(y_pred.index) + if indextype == "period": + assert isinstance(y_pred.index, pd.PeriodIndex) diff --git a/sktime/forecasting/var.py b/sktime/forecasting/var.py index dd0dab8dbe3..c370cd6bbfa 100644 --- a/sktime/forecasting/var.py +++ b/sktime/forecasting/var.py @@ -72,6 +72,13 @@ class VAR(_StatsModelsAdapter): _fitted_param_names = ("aic", "fpe", "hqic", "bic") _tags = { + # packaging info + # -------------- + "authors": ["thayeylolu", "aiwalter", "lbventura"], + "maintainers": "lbventura", + # "python_dependencies": "statsmodels" - inherited from _StatsModelsAdapter + # estimator type + # -------------- "scitype:y": "multivariate", "y_inner_mtype": "pd.DataFrame", "requires-fh-in-fit": False, diff --git a/sktime/forecasting/varmax.py b/sktime/forecasting/varmax.py index 91c603cd077..25755f25555 100644 --- a/sktime/forecasting/varmax.py +++ b/sktime/forecasting/varmax.py @@ -206,6 +206,12 @@ class VARMAX(_StatsModelsAdapter): """ _tags = { + # packaging info + # -------------- + "authors": "KatieBuc", + # "python_dependencies": "statsmodels" - inherited from _StatsModelsAdapter + # estimator type + # -------------- "scitype:y": "multivariate", "ignores-exogeneous-X": False, "handles-missing-data": False, diff --git a/sktime/forecasting/vecm.py b/sktime/forecasting/vecm.py index 4b4c55b9ab6..de59d51eb3b 100644 --- a/sktime/forecasting/vecm.py +++ b/sktime/forecasting/vecm.py @@ -77,6 +77,12 @@ class VECM(_StatsModelsAdapter): """ _tags = { + # packaging info + # -------------- + "authors": ["thayeylolu", "AurumnPegasus"], + # "python_dependencies": "statsmodels" - inherited from _StatsModelsAdapter + # estimator type + # -------------- "scitype:y": "multivariate", "y_inner_mtype": "pd.DataFrame", "X_inner_mtype": "pd.DataFrame", diff --git a/sktime/networks/base.py b/sktime/networks/base.py index 4cf14fff7d9..7d04a18fb84 100644 --- a/sktime/networks/base.py +++ b/sktime/networks/base.py @@ -4,7 +4,15 @@ from abc import ABC, abstractmethod +import numpy as np +import pandas as pd + from sktime.base import BaseObject +from sktime.forecasting.base import BaseForecaster +from sktime.utils.validation._dependencies import _check_soft_dependencies + +if _check_soft_dependencies("torch", severity="none"): + import torch class BaseDeepNetwork(BaseObject, ABC): @@ -27,3 +35,244 @@ def build_network(self, input_shape, **kwargs): output_layer : a keras layer """ ... + + +class BaseDeepNetworkPyTorch(BaseForecaster, ABC): + """Abstract base class for deep learning networks using torch.nn.""" + + _tags = { + "python_dependencies": "torch", + "y_inner_mtype": "pd.DataFrame", + "capability:insample": False, + "capability:pred_int:insample": False, + "scitype:y": "both", + "ignores-exogeneous-X": True, + } + + def __init__( + self, + num_epochs=16, + batch_size=8, + in_channels=1, + individual=False, + criterion_kwargs=None, + optimizer=None, + optimizer_kwargs=None, + lr=0.001, + ): + self.num_epochs = num_epochs + self.batch_size = batch_size + self.in_channels = in_channels + self.individual = individual + self.criterion_kwargs = criterion_kwargs + self.optimizer = optimizer + self.optimizer_kwargs = optimizer_kwargs + self.lr = lr + + super().__init__() + + def _fit(self, y, fh, X=None): + """Fit the network. + + Changes to state: + writes to self._network.state_dict + + Parameters + ---------- + X : iterable-style or map-style dataset + see (https://pytorch.org/docs/stable/data.html) for more information + """ + from sktime.forecasting.base import ForecastingHorizon + + # save fh and y for prediction later + if fh.is_relative: + self._fh = fh + else: + fh = fh.to_relative(self.cutoff) + self._fh = fh + + self._y = y + + if type(fh) is ForecastingHorizon: + self.network = self._build_network(fh._values[-1]) + else: + self.network = self._build_network(fh) + + if self.criterion: + if self.criterion in self.criterions.keys(): + if self.criterion_kwargs: + self._criterion = self.criterions[self.criterion]( + **self.criterion_kwargs + ) + else: + self._criterion = self.criterions[self.criterion]() + else: + raise TypeError( + f"Please pass one of {self.criterions.keys()} for `criterion`." + ) + else: + # default criterion + self._criterion = torch.nn.MSELoss() + + if self.optimizer: + if self.optimizer in self.optimizers.keys(): + if self.optimizer_kwargs: + self._optimizer = self.optimizers[self.optimizer]( + self.network.parameters(), lr=self.lr, **self.optimizer_kwargs + ) + else: + self._optimizer = self.optimizers[self.optimizer]( + self.network.parameters(), lr=self.lr + ) + else: + raise TypeError( + f"Please pass one of {self.optimizers.keys()} for `optimizer`." + ) + else: + # default optimizer + self._optimizer = torch.optim.Adam(self.network.parameters(), lr=self.lr) + + dataloader = self.build_pytorch_train_dataloader(y) + self.network.train() + + for _ in range(self.num_epochs): + for x, y in dataloader: + y_pred = self.network(x) + loss = self._criterion(y_pred, y) + self._optimizer.zero_grad() + loss.backward() + self._optimizer.step() + + def _predict(self, X=None, fh=None): + """Predict with fitted model.""" + from torch import cat + + if fh is None: + fh = self._fh + + if max(fh._values) > self.network.pred_len or min(fh._values) < 0: + raise ValueError( + f"fh of {fh} passed to {self.__class__.__name__} is not " + "within `pred_len`. Please use a fh that aligns with the `pred_len` of " + "the forecaster." + ) + + if X is None: + dataloader = self.build_pytorch_pred_dataloader(self._y, fh) + else: + dataloader = self.build_pytorch_pred_dataloader(X, fh) + + y_pred = [] + for x, _ in dataloader: + y_pred.append(self.network(x).detach()) + y_pred = cat(y_pred, dim=0).view(-1, y_pred[0].shape[-1]).numpy() + y_pred = y_pred[fh._values.values - 1] + y_pred = pd.DataFrame( + y_pred, columns=self._y.columns, index=fh.to_absolute_index(self.cutoff) + ) + + return y_pred + + def build_pytorch_train_dataloader(self, y): + """Build PyTorch DataLoader for training.""" + from torch.utils.data import DataLoader + + if self.custom_dataset_train: + if hasattr(self.custom_dataset_train, "build_dataset") and callable( + self.custom_dataset_train.build_dataset + ): + self.custom_dataset_train.build_dataset(y) + dataset = self.custom_dataset_train + else: + raise NotImplementedError( + "Custom Dataset `build_dataset` method is not available. Please " + f"refer to the {self.__class__.__name__}.build_dataset " + "documentation." + ) + else: + dataset = PyTorchTrainDataset( + y=y, + seq_len=self.network.seq_len, + fh=self._fh._values[-1], + ) + + return DataLoader( + dataset, + self.batch_size, + ) + + def build_pytorch_pred_dataloader(self, y, fh): + """Build PyTorch DataLoader for prediction.""" + from torch.utils.data import DataLoader + + if self.custom_dataset_pred: + if hasattr(self.custom_dataset_pred, "build_dataset") and callable( + self.custom_dataset_pred.build_dataset + ): + self.custom_dataset_train.build_dataset(y) + dataset = self.custom_dataset_train + else: + raise NotImplementedError( + "Custom Dataset `build_dataset` method is not available. Please" + f"refer to the {self.__class__.__name__}.build_dataset" + "documentation." + ) + else: + dataset = PyTorchPredDataset( + y=y[-self.network.seq_len :], + seq_len=self.network.seq_len, + ) + + return DataLoader( + dataset, + self.batch_size, + ) + + def get_y_true(self, y): + """Get y_true values for validation.""" + dataloader = self.build_pytorch_pred_dataloader(y) + y_true = [y.flatten().numpy() for _, y in dataloader] + return np.concatenate(y_true, axis=0) + + +class PyTorchTrainDataset: + """Dataset for use in sktime deep learning forecasters.""" + + def __init__(self, y, seq_len, fh): + self.y = y.values + self.seq_len = seq_len + self.fh = fh + + def __len__(self): + """Return length of dataset.""" + return len(self.y) - self.seq_len - self.fh + 1 + + def __getitem__(self, i): + """Return data point.""" + from torch import from_numpy, tensor + + return ( + tensor(self.y[i : i + self.seq_len]).float(), + from_numpy(self.y[i + self.seq_len : i + self.seq_len + self.fh]).float(), + ) + + +class PyTorchPredDataset: + """Dataset for use in sktime deep learning forecasters.""" + + def __init__(self, y, seq_len): + self.y = y.values + self.seq_len = seq_len + + def __len__(self): + """Return length of dataset.""" + return 1 + + def __getitem__(self, i): + """Return data point.""" + from torch import from_numpy, tensor + + return ( + tensor(self.y[i : i + self.seq_len]).float(), + from_numpy(self.y[i + self.seq_len : i + self.seq_len]).float(), + ) diff --git a/sktime/networks/cntc.py b/sktime/networks/cntc.py new file mode 100644 index 00000000000..d94ed71ec58 --- /dev/null +++ b/sktime/networks/cntc.py @@ -0,0 +1,193 @@ +"""a combination of CCNN and CLSTM as feature extractors.""" + +__author__ = ["James-Large", "Withington", "TonyBagnall", "AurumnPegasus"] + +from sktime.networks.base import BaseDeepNetwork +from sktime.utils.validation._dependencies import ( + _check_dl_dependencies, + _check_soft_dependencies, +) + + +class CNTCNetwork(BaseDeepNetwork): + """Combining contextual neural networks for time series classification. + + Adapted from the implementation used in [1] + + Parameters + ---------- + kernel_size : int, default = 7 + specifying the length of the 1D convolution window + avg_pool_size : int, default = 3 + size of the average pooling windows + n_conv_layers : int, default = 2 + the number of convolutional plus average pooling layers + filter_sizes : array of int, shape = (nb_conv_layers) + activation : string, default = sigmoid + keras activation function + random_state : int, default = 0 + seed to any needed random actions + + Notes + ----- + Adapted from the implementation from Fullah et. al + https://github.com/AmaduFullah/CNTC_MODEL/blob/master/cntc.ipynb + + References + ---------- + .. [1] Network originally defined in: + @article{FULLAHKAMARA202057, + title = {Combining contextual neural networks for time series classification}, + journal = {Neurocomputing}, + volume = {384}, + pages = {57-66}, + year = {2020}, + issn = {0925-2312}, + doi = {https://doi.org/10.1016/j.neucom.2019.10.113}, + url = {https://www.sciencedirect.com/science/article/pii/S0925231219316364}, + author = {Amadu {Fullah Kamara} and Enhong Chen and Qi Liu and Zhen Pan}, + keywords = {Time series classification, Contextual convolutional neural + networks, Contextual long short-term memory, Attention, Multilayer + perceptron}, + } + """ + + _tags = { + "authors": ["James-Large", "Withington", "TonyBagnall", "AurumnPegasus"], + "maintainers": ["James-Large", "Withington", "AurumnPegasus"], + "python_dependencies": ["tensorflow", "keras-self-attention"], + } + + def __init__( + self, + random_state=0, + rnn_layer=64, + filter_sizes=(16, 8), + kernel_sizes=(1, 1), + lstm_size=8, + dense_size=64, + ): + _check_soft_dependencies( + "keras-self-attention", + package_import_alias={"keras-self-attention": "keras_self_attention"}, + severity="error", + ) + _check_dl_dependencies(severity="error") + + self.random_state = random_state + self.rnn_layer = rnn_layer + self.filter_sizes = filter_sizes + self.kernel_sizes = kernel_sizes + self.lstm_size = lstm_size + self.dense_size = dense_size + + super().__init__() + + def build_network(self, input_shape, **kwargs): + """Construct a network and return its input and output layers. + + Arguments + --------- + input_shape: tuple + The shape of the data fed into the input layer, should be (m,d) + + Returns + ------- + input_layer: a keras layer + output_layer: a keras layer + """ + from keras_self_attention import SeqSelfAttention + from tensorflow import keras + + input_layers = [] + + # CNN Arm + input_layers.append(keras.layers.Input(input_shape)) + input_layers.append(keras.layers.Input(input_shape)) + self.dropout = 0.2 + + conv1 = keras.layers.Conv1D( + self.filter_sizes[0], + self.kernel_sizes[0], + activation="relu", + use_bias=True, + kernel_initializer="glorot_uniform", + )(input_layers[0]) + conv1 = keras.layers.BatchNormalization()(conv1) + conv1 = keras.layers.Dropout(self.dropout)(conv1) + conv1 = keras.layers.Dense( + input_shape[1], + input_shape=(input_shape[0], keras.backend.int_shape(conv1)[2]), + )(conv1) + + # RNN for CNN Arm (CCNN) + rnn1 = keras.layers.SimpleRNN( + self.rnn_layer * input_shape[1], + activation="relu", + use_bias=True, + kernel_initializer="glorot_uniform", + )(input_layers[1]) + rnn1 = keras.layers.BatchNormalization()(rnn1) + rnn1 = keras.layers.Dropout(self.dropout)(rnn1) + rnn1 = keras.layers.Reshape((64, input_shape[1]))(rnn1) + + # Combining CNN and RNN + conc1 = keras.layers.Concatenate( + axis=-2, name="contextual_convolutional_layer1" + )([conv1, rnn1]) + + # Final CNN for C-CNN (WHY) + conv2 = keras.layers.Conv1D( + self.filter_sizes[1], + self.kernel_sizes[1], + activation="relu", + kernel_initializer="glorot_uniform", + name="standard_cnn_layer", + )(conc1) + conv2 = keras.layers.Dense( + input_shape[1], + input_shape=(input_shape[0], keras.backend.int_shape(conv2)[2]), + )(conv2) + conv2 = keras.layers.BatchNormalization()(conv2) + conv2 = keras.layers.Dropout(0.1)(conv2) + + # CLSTM Arm + input_layers.append(keras.layers.Input(input_shape)) + lstm1 = keras.layers.LSTM( + self.lstm_size * input_shape[1], + return_sequences=False, + kernel_initializer="glorot_uniform", + activation="relu", + )(input_layers[2]) + lstm1 = keras.layers.Reshape((self.lstm_size, input_shape[1]))(lstm1) + lstm1 = keras.layers.Dropout(self.dropout)(lstm1) + merge = keras.layers.Concatenate( + axis=-2, name="contextual_convolutional_layer2" + )([conv2, lstm1]) + + # Output calculation based on combination + avg = keras.layers.MaxPooling1D(pool_size=1, strides=None, padding="valid")( + merge + ) + avg = keras.layers.Dropout(0.1)(avg) + + # Adding self attention + att = SeqSelfAttention( + attention_width=10, + attention_activation="sigmoid", + name="Attention", + attention_type="multiplicative", + )(avg) + att = keras.layers.Dropout(0.1)(att) + + # Adding ouutput MLP Layer + mlp1 = keras.layers.Dense( + self.dense_size, kernel_initializer="glorot_uniform", activation="relu" + )(att) + mlp1 = keras.layers.Dropout(0.1)(mlp1) + mlp2 = keras.layers.Dense( + self.dense_size, kernel_initializer="glorot_uniform", activation="relu" + )(mlp1) + mlp2 = keras.layers.Dropout(0.1)(mlp2) + flat = keras.layers.Flatten()(mlp2) + return input_layers, flat diff --git a/sktime/networks/ltsf/__init__.py b/sktime/networks/ltsf/__init__.py new file mode 100644 index 00000000000..403b83db0df --- /dev/null +++ b/sktime/networks/ltsf/__init__.py @@ -0,0 +1 @@ +"""Init LTSF.""" diff --git a/sktime/networks/ltsf/_ltsf.py b/sktime/networks/ltsf/_ltsf.py new file mode 100644 index 00000000000..43b2a0fb332 --- /dev/null +++ b/sktime/networks/ltsf/_ltsf.py @@ -0,0 +1,316 @@ +"""Deep Learning Forecasters using LTSF-Linear Models.""" +from sktime.utils.validation._dependencies import _check_soft_dependencies + +if _check_soft_dependencies("torch", severity="none"): + import torch.nn as nn + + nn_module = nn.Module +else: + + class nn_module: + """Dummy class if torch is unavailable.""" + + pass + + +class LTSFLinearNetwork: + """LTSF-Linear Forecaster. + + Implementation of the Long-Term Short-Term Feature (LTSF) linear forecaster, + aka LTSF-Linear, by Zeng et al [1]_. + + Core logic is directly copied from the cure-lab LTSF-Linear implementation [2]_, + which is unfortunately not available as a package. + + Parameters + ---------- + seq_len : int + length of input sequence + pred_len : int + length of prediction (forecast horizon) + in_channels : int, default=None + number of input channels passed to network + individual : bool, default=False + boolean flag that controls whether the network treats each channel individually" + "or applies a single linear layer across all channels. If individual=True, the" + "a separate linear layer is created for each input channel. If" + "individual=False, a single shared linear layer is used for all channels." + + References + ---------- + .. [1] Zeng A, Chen M, Zhang L, Xu Q. 2023. + Are transformers effective for time series forecasting? + Proceedings of the AAAI conference on artificial intelligence 2023 + (Vol. 37, No. 9, pp. 11121-11128). + .. [2] https://github.com/cure-lab/LTSF-Linear + """ + + class _LTSFLinearNetwork(nn_module): + def __init__( + self, + seq_len, + pred_len, + in_channels, + individual, + ): + super().__init__() + + self.seq_len = seq_len + self.pred_len = pred_len + self.in_channels = in_channels + self.individual = individual + + if self.individual: + self.Linear = nn.ModuleList() + for _ in range(self.in_channels): + self.Linear.append(nn.Linear(self.seq_len, self.pred_len)) + else: + self.Linear = nn.Linear(self.seq_len, self.pred_len) + + def forward(self, x): + """Forward pass for LSTF-Linear Network. + + Parameters + ---------- + x : torch.Tensor + torch.Tensor of shape [Batch, Input Sequence Length, Channel] + + Returns + ------- + x : torch.Tensor + output of Linear Model. x.shape = [Batch, Output Length, Channel] + """ + from torch import zeros + + if self.individual: + output = zeros([x.size(0), self.pred_len, x.size(2)], dtype=x.dtype).to( + x.device + ) + for i in range(self.in_channels): + output[:, :, i] = self.Linear[i](x[:, :, i]) + x = output + else: + x = self.Linear(x.permute(0, 2, 1)).permute(0, 2, 1) + return x # [Batch, Output Length, Channel] + + def __init__(self, seq_len, pred_len, in_channels=1, individual=False): + self.seq_len = seq_len + self.pred_len = pred_len + self.in_channels = in_channels + self.individual = individual + + def _build(self): + return self._LTSFLinearNetwork( + self.seq_len, self.pred_len, self.in_channels, self.individual + ) + + +class LTSFDLinearNetwork: + """LTSF-DLinear Forecaster. + + Implementation of the Long-Term Short-Term Feature (LTSF) decomposition linear + forecaster, aka LTSF-DLinear, by Zeng et al [1]_. + + Core logic is directly copied from the cure-lab LTSF-Linear implementation [2]_, + which is unfortunately not available as a package. + + Parameters + ---------- + seq_len : int + length of input sequence + pred_len : int + length of prediction (forecast horizon) + in_channels : int, default=None + number of input channels passed to network + individual : bool, default=False + boolean flag that controls whether the network treats each channel individually" + "or applies a single linear layer across all channels. If individual=True, the" + "a separate linear layer is created for each input channel. If" + "individual=False, a single shared linear layer is used for all channels." + + References + ---------- + .. [1] Zeng A, Chen M, Zhang L, Xu Q. 2023. + Are transformers effective for time series forecasting? + Proceedings of the AAAI conference on artificial intelligence 2023 + (Vol. 37, No. 9, pp. 11121-11128). + .. [2] https://github.com/cure-lab/LTSF-Linear + """ + + class _LTSFDLinearNetwork(nn_module): + def __init__( + self, + seq_len, + pred_len, + in_channels, + individual, + ): + from sktime.networks.ltsf.layers import SeriesDecomposer + + super().__init__() + self.seq_len = seq_len + self.pred_len = pred_len + + # Decompsition Kernel Size + kernel_size = 25 + self.decompsition = SeriesDecomposer(kernel_size)._build() + self.individual = individual + self.in_channels = in_channels + + if self.individual: + self.Linear_Seasonal = nn.ModuleList() + self.Linear_Trend = nn.ModuleList() + for _ in range(self.in_channels): + self.Linear_Seasonal.append(nn.Linear(self.seq_len, self.pred_len)) + self.Linear_Trend.append(nn.Linear(self.seq_len, self.pred_len)) + else: + self.Linear_Seasonal = nn.Linear(self.seq_len, self.pred_len) + self.Linear_Trend = nn.Linear(self.seq_len, self.pred_len) + + def forward(self, x): + """Forward pass for LSTF-DLinear Network. + + Parameters + ---------- + x : torch.Tensor + torch.Tensor of shape [Batch, Input Sequence Length, Channel] + + Returns + ------- + x : torch.Tensor + output of Linear Model. x.shape = [Batch, Output Length, Channel] + """ + from torch import zeros + + # x: [Batch, Input length, Channel] + seasonal_init, trend_init = self.decompsition(x) + seasonal_init, trend_init = seasonal_init.permute( + 0, 2, 1 + ), trend_init.permute(0, 2, 1) + if self.individual: + seasonal_output = zeros( + [seasonal_init.size(0), seasonal_init.size(1), self.pred_len], + dtype=seasonal_init.dtype, + ).to(seasonal_init.device) + trend_output = zeros( + [trend_init.size(0), trend_init.size(1), self.pred_len], + dtype=trend_init.dtype, + ).to(trend_init.device) + for i in range(self.in_channels): + seasonal_output[:, i, :] = self.Linear_Seasonal[i]( + seasonal_init[:, i, :] + ) + trend_output[:, i, :] = self.Linear_Trend[i](trend_init[:, i, :]) + else: + seasonal_output = self.Linear_Seasonal(seasonal_init) + trend_output = self.Linear_Trend(trend_init) + + x = seasonal_output + trend_output + return x.permute(0, 2, 1) # to [Batch, Output length, Channel] + + def __init__(self, seq_len, pred_len, in_channels=1, individual=False): + self.seq_len = seq_len + self.pred_len = pred_len + self.in_channels = in_channels + self.individual = individual + + def _build(self): + return self._LTSFDLinearNetwork( + self.seq_len, self.pred_len, self.in_channels, self.individual + ) + + +class LTSFNLinearNetwork: + """LTSF-NLinear Forecaster. + + Implementation of the Long-Term Short-Term Feature (LTSF) normalization linear + forecaster, aka LTSF-NLinear, by Zeng et al [1]_. + + Core logic is directly copied from the cure-lab LTSF-Linear implementation [2]_, + which is unfortunately not available as a package. + + Parameters + ---------- + seq_len : int + length of input sequence + pred_len : int + length of prediction (forecast horizon) + in_channels : int, default=None + number of input channels passed to network + individual : bool, default=False + boolean flag that controls whether the network treats each channel individually" + "or applies a single linear layer across all channels. If individual=True, the" + "a separate linear layer is created for each input channel. If" + "individual=False, a single shared linear layer is used for all channels." + + References + ---------- + .. [1] Zeng A, Chen M, Zhang L, Xu Q. 2023. + Are transformers effective for time series forecasting? + Proceedings of the AAAI conference on artificial intelligence 2023 + (Vol. 37, No. 9, pp. 11121-11128). + .. [2] https://github.com/cure-lab/LTSF-Linear + """ + + class _LTSFNLinearNetwork(nn_module): + def __init__( + self, + seq_len, + pred_len, + in_channels, + individual, + ): + super().__init__() + self.seq_len = seq_len + self.pred_len = pred_len + + self.in_channels = in_channels + self.individual = individual + + if self.individual: + self.Linear = nn.ModuleList() + for _ in range(self.in_channels): + self.Linear.append(nn.Linear(self.seq_len, self.pred_len)) + else: + self.Linear = nn.Linear(self.seq_len, self.pred_len) + + def forward(self, x): + """Forward pass for LSTF-NLinear Network. + + Parameters + ---------- + x : torch.Tensor + torch.Tensor of shape [Batch, Input Sequence Length, Channel] + + Returns + ------- + x : torch.Tensor + output of Linear Model. x.shape = [Batch, Output Length, Channel] + """ + from torch import zeros + + # x: [Batch, Input length, Channel] + seq_last = x[:, -1:, :].detach() + x = x - seq_last + if self.individual: + output = zeros([x.size(0), self.pred_len, x.size(2)], dtype=x.dtype).to( + x.device + ) + for i in range(self.in_channels): + output[:, :, i] = self.Linear[i](x[:, :, i]) + x = output + else: + x = self.Linear(x.permute(0, 2, 1)).permute(0, 2, 1) + x = x + seq_last + return x # [Batch, Output length, Channel] + + def __init__(self, seq_len, pred_len, in_channels=1, individual=False): + self.seq_len = seq_len + self.pred_len = pred_len + self.in_channels = in_channels + self.individual = individual + + def _build(self): + return self._LTSFNLinearNetwork( + self.seq_len, self.pred_len, self.in_channels, self.individual + ) diff --git a/sktime/networks/ltsf/layers.py b/sktime/networks/ltsf/layers.py new file mode 100644 index 00000000000..dd6d87769dd --- /dev/null +++ b/sktime/networks/ltsf/layers.py @@ -0,0 +1,577 @@ +"""Extra LTSF-Linear Model Layers.""" +from sktime.utils.validation._dependencies import _check_soft_dependencies + +if _check_soft_dependencies("torch", severity="none"): + import torch.nn as nn + + nn_module = nn.Module +else: + + class nn_module: + """Dummy class if torch is unavailable.""" + + pass + + +import math + + +class SeriesDecomposer: + """Series decomposition block.""" + + def __init__(self, kernel_size): + self.kernel_size = kernel_size + + def _build(self): + return self._SeriesDecomposer(self.kernel_size) + + class _SeriesDecomposer(nn_module): + """Series decomposition block.""" + + def __init__(self, kernel_size): + super().__init__() + self.moving_avg = MovingAverage(kernel_size, stride=1)._build() + + def forward(self, x): + moving_mean = self.moving_avg(x) + res = x - moving_mean + return res, moving_mean + + +class MovingAverage: + """Moving average block to highlight the trend of time series.""" + + def __init__(self, kernel_size, stride): + self.kernel_size = kernel_size + self.stride = stride + + def _build(self): + return self._MovingAverage(self.kernel_size, self.stride) + + class _MovingAverage(nn_module): + """Moving average block to highlight the trend of time series.""" + + def __init__(self, kernel_size, stride): + super().__init__() + self.kernel_size = kernel_size + self.avg = nn.AvgPool1d(kernel_size=kernel_size, stride=stride, padding=0) + + def forward(self, x): + from torch import cat + + # padding on the both ends of time series + front = x[:, 0:1, :].repeat(1, (self.kernel_size - 1) // 2, 1) + end = x[:, -1:, :].repeat(1, (self.kernel_size - 1) // 2, 1) + x = cat([front, x, end], dim=1) + x = self.avg(x.permute(0, 2, 1)) + x = x.permute(0, 2, 1) + return x + + +class AutoCorrelation: + """AutoCorrelation layer. + + AutoCorrelation Mechanism with the following two phases: + (1) period-based dependencies discovery + (2) time delay aggregation + This block can replace the self-attention family mechanism seamlessly. + """ + + class _AutoCorrelation(nn_module): + def __init__( + self, + mask_flag=True, + factor=1, + scale=None, + attention_dropout=0.1, + output_attention=False, + ): + super().__init__() + self.factor = factor + self.scale = scale + self.mask_flag = mask_flag + self.output_attention = output_attention + self.dropout = nn.Dropout(attention_dropout) + + def time_delay_agg_training(self, values, corr): + """Normalize. + + SpeedUp version of Autocorrelation (a batch-normalization style design) + This is for the training phase. + """ + from torch import mean, roll, softmax, stack, topk, zeros_like + + head = values.shape[1] + channel = values.shape[2] + length = values.shape[3] + # find top k + top_k = int(self.factor * math.log(length)) + mean_value = mean(mean(corr, dim=1), dim=1) + index = topk(mean(mean_value, dim=0), top_k, dim=-1)[1] + weights = stack([mean_value[:, index[i]] for i in range(top_k)], dim=-1) + # update corr + tmp_corr = softmax(weights, dim=-1) + # aggregation + tmp_values = values + delays_agg = zeros_like(values).float() + for i in range(top_k): + pattern = roll(tmp_values, -int(index[i]), -1) + delays_agg = delays_agg + pattern * ( + tmp_corr[:, i] + .unsqueeze(1) + .unsqueeze(1) + .unsqueeze(1) + .repeat(1, head, channel, length) + ) + return delays_agg + + def time_delay_agg_inference(self, values, corr): + """Normalize data. + + SpeedUp version of Autocorrelation (a batch-normalization style design) + This is for the inference phase. + """ + from torch import arange, gather, mean, softmax, topk, zeros_like + + batch = values.shape[0] + head = values.shape[1] + channel = values.shape[2] + length = values.shape[3] + # index init + init_index = ( + arange(length) + .unsqueeze(0) + .unsqueeze(0) + .unsqueeze(0) + .repeat(batch, head, channel, 1) + .cuda() + ) + # find top k + top_k = int(self.factor * math.log(length)) + mean_value = mean(mean(corr, dim=1), dim=1) + weights = topk(mean_value, top_k, dim=-1)[0] + delay = topk(mean_value, top_k, dim=-1)[1] + # update corr + tmp_corr = softmax(weights, dim=-1) + # aggregation + tmp_values = values.repeat(1, 1, 1, 2) + delays_agg = zeros_like(values).float() + for i in range(top_k): + tmp_delay = init_index + ( + delay[:, i] + .unsqueeze(1) + .unsqueeze(1) + .unsqueeze(1) + .repeat(1, head, channel, length) + ) + pattern = gather(tmp_values, dim=-1, index=tmp_delay) + delays_agg = delays_agg + pattern * ( + tmp_corr[:, i] + .unsqueeze(1) + .unsqueeze(1) + .unsqueeze(1) + .repeat(1, head, channel, length) + ) + return delays_agg + + def time_delay_agg_full(self, values, corr): + """Normalize Data. + + Standard version of Autocorrelation + """ + from torch import arange, gather, softmax, topk, zeros_like + + batch = values.shape[0] + head = values.shape[1] + channel = values.shape[2] + length = values.shape[3] + # index init + init_index = ( + arange(length) + .unsqueeze(0) + .unsqueeze(0) + .unsqueeze(0) + .repeat(batch, head, channel, 1) + .cuda() + ) + # find top k + top_k = int(self.factor * math.log(length)) + weights = topk(corr, top_k, dim=-1)[0] + delay = topk(corr, top_k, dim=-1)[1] + # update corr + tmp_corr = softmax(weights, dim=-1) + # aggregation + tmp_values = values.repeat(1, 1, 1, 2) + delays_agg = zeros_like(values).float() + for i in range(top_k): + tmp_delay = init_index + delay[..., i].unsqueeze(-1) + pattern = gather(tmp_values, dim=-1, index=tmp_delay) + delays_agg = delays_agg + pattern * (tmp_corr[..., i].unsqueeze(-1)) + return delays_agg + + def forward(self, queries, keys, values, attn_mask): + """Call model.""" + from torch import cat, conj, fft, zeros_like + + B, L, H, E = queries.shape + _, S, _, D = values.shape + if L > S: + zeros = zeros_like(queries[:, : (L - S), :]).float() + values = cat([values, zeros], dim=1) + keys = cat([keys, zeros], dim=1) + else: + values = values[:, :L, :, :] + keys = keys[:, :L, :, :] + + # period-based dependencies + q_fft = fft.rfft(queries.permute(0, 2, 3, 1).contiguous(), dim=-1) + k_fft = fft.rfft(keys.permute(0, 2, 3, 1).contiguous(), dim=-1) + res = q_fft * conj(k_fft) + corr = fft.irfft(res, dim=-1) + + # time delay agg + if self.training: + V = self.time_delay_agg_training( + values.permute(0, 2, 3, 1).contiguous(), corr + ).permute(0, 3, 1, 2) + else: + V = self.time_delay_agg_inference( + values.permute(0, 2, 3, 1).contiguous(), corr + ).permute(0, 3, 1, 2) + + if self.output_attention: + return (V.contiguous(), corr.permute(0, 3, 1, 2)) + else: + return (V.contiguous(), None) + + def __init__( + self, + mask_flag=True, + factor=1, + scale=None, + attention_dropout=0.1, + output_attention=False, + ): + self.mask_flag = mask_flag + self.factor = factor + self.scale = scale + self.attention_dropout = attention_dropout + self.output_attention = output_attention + + def _build(self): + return self._AutoCorrelation( + self.mask_flag, + self.factor, + self.scale, + self.attention_dropout, + self.output_attention, + ) + + +class AutoCorrelationLayer: + """Layer for AutoCorrelation.""" + + class _AutoCorrelationLayer(nn_module): + def __init__(self, correlation, d_model, n_heads, d_keys=None, d_values=None): + super().__init__() + + d_keys = d_keys or (d_model // n_heads) + d_values = d_values or (d_model // n_heads) + + self.inner_correlation = correlation + self.query_projection = nn.Linear(d_model, d_keys * n_heads) + self.key_projection = nn.Linear(d_model, d_keys * n_heads) + self.value_projection = nn.Linear(d_model, d_values * n_heads) + self.out_projection = nn.Linear(d_values * n_heads, d_model) + self.n_heads = n_heads + + def forward(self, queries, keys, values, attn_mask): + """Call layer.""" + B, L, _ = queries.shape + _, S, _ = keys.shape + H = self.n_heads + + queries = self.query_projection(queries).view(B, L, H, -1) + keys = self.key_projection(keys).view(B, S, H, -1) + values = self.value_projection(values).view(B, S, H, -1) + + out, attn = self.inner_correlation(queries, keys, values, attn_mask) + out = out.view(B, L, -1) + + return self.out_projection(out), attn + + def __init__(self, correlation, d_model, n_heads, d_keys=None, d_values=None): + self.correlation = correlation + self.d_model = d_model + self.n_heads = n_heads + self.d_keys = d_keys + self.d_values = d_values + + def _build(self): + return self._AutoCorrelationLayer( + self.correlation, self.d_model, self.n_heads, self.d_keys, self.d_values + ) + + +class LTSFLayerNorm: + """LayerNorm.""" + + class _LTSFLayernorm(nn_module): + def __init__(self, channels): + super().__init__() + self.layernorm = nn.LayerNorm(channels) + + def forward(self, x): + """Call layer.""" + from torch import mean + + x_hat = self.layernorm(x) + bias = mean(x_hat, dim=1).unsqueeze(1).repeat(1, x.shape[1], 1) + return x_hat - bias + + def __init__(self, channels): + self.channels = channels + + def _build(self): + return self._LTSFLayernorm(self.channels) + + +class EncoderLayer: + """Encoder Layer. + + Autoformer encoder layer with the progressive decomposition architecture + """ + + class _EncoderLayer(nn_module): + def __init__( + self, + attention, + d_model, + d_ff=None, + moving_avg=25, + dropout=0.1, + activation="relu", + ): + super().__init__() + from torch.nn.functional import gelu, relu + + d_ff = d_ff or 4 * d_model + self.attention = attention + self.conv1 = nn.Conv1d( + in_channels=d_model, out_channels=d_ff, kernel_size=1, bias=False + ) + self.conv2 = nn.Conv1d( + in_channels=d_ff, out_channels=d_model, kernel_size=1, bias=False + ) + self.decomp1 = SeriesDecomposer(moving_avg) + self.decomp2 = SeriesDecomposer(moving_avg) + self.dropout = nn.Dropout(dropout) + self.activation = relu if activation == "relu" else gelu + + def forward(self, x, attn_mask=None): + new_x, attn = self.attention(x, x, x, attn_mask=attn_mask) + x = x + self.dropout(new_x) + x, _ = self.decomp1(x) + y = x + y = self.dropout(self.activation(self.conv1(y.transpose(-1, 1)))) + y = self.dropout(self.conv2(y).transpose(-1, 1)) + res, _ = self.decomp2(x + y) + return res, attn + + def __init__( + self, + attention, + d_model, + d_ff=None, + moving_avg=25, + dropout=0.1, + activation="relu", + ): + self.attention = attention + self.d_model = d_model + self.d_ff = d_ff + self.moving_avg = moving_avg + self.dropout = dropout + self.activation = activation + + def _build(self): + return self._EncoderLayer( + self.attention, + self.d_model, + self.d_ff, + self.moving_avg, + self.dropout, + self.activation, + ) + + +class Encoder: + """Autoformer encoder.""" + + class _Encoder(nn_module): + def __init__(self, attn_layers, conv_layers=None, norm_layer=None): + super(Encoder, self).__init__() + self.attn_layers = nn.ModuleList(attn_layers) + self.conv_layers = ( + nn.ModuleList(conv_layers) if conv_layers is not None else None + ) + self.norm = norm_layer + + def forward(self, x, attn_mask=None): + """Call encoder.""" + attns = [] + if self.conv_layers is not None: + for attn_layer, conv_layer in zip(self.attn_layers, self.conv_layers): + x, attn = attn_layer(x, attn_mask=attn_mask) + x = conv_layer(x) + attns.append(attn) + x, attn = self.attn_layers[-1](x) + attns.append(attn) + else: + for attn_layer in self.attn_layers: + x, attn = attn_layer(x, attn_mask=attn_mask) + attns.append(attn) + + if self.norm is not None: + x = self.norm(x) + + return x, attns + + def __init__(self, attn_layers, conv_layers=None, norm_layer=None): + self.attn_layers = attn_layers + self.conv_layers = conv_layers + self.norm_layer = norm_layer + + def _build(self): + return self._Encoder(self.attn_layers, self.conv_layers, self.norm_layer) + + +class DecoderLayer: + """Decoder Layer. + + Autoformer decoder layer with the progressive decomposition architecture + """ + + class _DecoderLayer(nn_module): + def __init__( + self, + self_attention, + cross_attention, + d_model, + c_out, + d_ff=None, + moving_avg=25, + dropout=0.1, + activation="relu", + ): + super().__init__() + from torch.nn.functional import gelu, relu + + d_ff = d_ff or 4 * d_model + self.self_attention = self_attention + self.cross_attention = cross_attention + self.conv1 = nn.Conv1d( + in_channels=d_model, out_channels=d_ff, kernel_size=1, bias=False + ) + self.conv2 = nn.Conv1d( + in_channels=d_ff, out_channels=d_model, kernel_size=1, bias=False + ) + self.decomp1 = SeriesDecomposer(moving_avg) + self.decomp2 = SeriesDecomposer(moving_avg) + self.decomp3 = SeriesDecomposer(moving_avg) + self.dropout = nn.Dropout(dropout) + self.projection = nn.Conv1d( + in_channels=d_model, + out_channels=c_out, + kernel_size=3, + stride=1, + padding=1, + padding_mode="circular", + bias=False, + ) + self.activation = relu if activation == "relu" else gelu + + def forward(self, x, cross, x_mask=None, cross_mask=None): + """Call decoder.""" + x = x + self.dropout(self.self_attention(x, x, x, attn_mask=x_mask)[0]) + x, trend1 = self.decomp1(x) + x = x + self.dropout( + self.cross_attention(x, cross, cross, attn_mask=cross_mask)[0] + ) + x, trend2 = self.decomp2(x) + y = x + y = self.dropout(self.activation(self.conv1(y.transpose(-1, 1)))) + y = self.dropout(self.conv2(y).transpose(-1, 1)) + x, trend3 = self.decomp3(x + y) + + residual_trend = trend1 + trend2 + trend3 + residual_trend = self.projection(residual_trend.permute(0, 2, 1)).transpose( + 1, 2 + ) + return x, residual_trend + + def __init__( + self, + self_attention, + cross_attention, + d_model, + c_out, + d_ff=None, + moving_avg=25, + dropout=0.1, + activation="relu", + ): + self.self_attention = self_attention + self.cross_attention = cross_attention + self.d_model = d_model + self.c_out = c_out + self.d_ff = d_ff + self.moving_avg = moving_avg + self.dropout = dropout + self.activation = activation + + def _build(self): + return self._DecoderLayer( + self.self_attention, + self.cross_attention, + self.d_model, + self.c_out, + self.d_ff, + self.moving_avg, + self.dropout, + self.activation, + ) + + +class Decoder: + """Autoformer decoder.""" + + class _Decoder(nn_module): + def __init__(self, layers, norm_layer=None, projection=None): + super().__init__() + self.layers = nn.ModuleList(layers) + self.norm = norm_layer + self.projection = projection + + def forward(self, x, cross, x_mask=None, cross_mask=None, trend=None): + """Call decoder.""" + for layer in self.layers: + x, residual_trend = layer( + x, cross, x_mask=x_mask, cross_mask=cross_mask + ) + trend = trend + residual_trend + + if self.norm is not None: + x = self.norm(x) + + if self.projection is not None: + x = self.projection(x) + return x, trend + + def __init__(self, layers, norm_layer=None, projection=None): + self.layers = layers + self.norm_layer = norm_layer + self.projection = projection + + def _build(self): + return self._Decoder(self.layers, self.norm_layer, self.projection) diff --git a/sktime/networks/rnn.py b/sktime/networks/rnn.py index 099193e33a5..836bef65072 100644 --- a/sktime/networks/rnn.py +++ b/sktime/networks/rnn.py @@ -1,6 +1,6 @@ """Time Recurrent Neural Network (RNN) (minus the final output layer).""" -__authors__ = ["JamesLarge", "Withington", "TonyBagnall", "achieveordie"] +__authors__ = ["James-Large", "Withington", "TonyBagnall", "achieveordie"] from sktime.networks.base import BaseDeepNetwork diff --git a/sktime/networks/tests/test_all_networks.py b/sktime/networks/tests/test_all_networks.py new file mode 100644 index 00000000000..c11fb889e5c --- /dev/null +++ b/sktime/networks/tests/test_all_networks.py @@ -0,0 +1,33 @@ +"""Unit tests for all neural networks.""" + +from sktime.tests.test_all_estimators import BaseFixtureGenerator, QuickTester + + +class NetworkFixtureGenerator(BaseFixtureGenerator): + """Fixture generator for classifier tests. + + Fixtures parameterized + ---------------------- + estimator_class: estimator inheriting from BaseObject + ranges over estimator classes not excluded by EXCLUDE_ESTIMATORS, EXCLUDED_TESTS + estimator_instance: instance of estimator inheriting from BaseObject + ranges over estimator classes not excluded by EXCLUDE_ESTIMATORS, EXCLUDED_TESTS + instances are generated by create_test_instance class method + scenario: instance of TestScenario + ranges over all scenarios returned by retrieve_scenarios + """ + + # note: this should be separate from TestAllNetworks + # additional fixtures, parameters, etc should be added here + # TestAllNetworks should contain the tests only + + estimator_type_filter = "network" + + +class TestAllNetworks(NetworkFixtureGenerator, QuickTester): + """Module level tests for all sktime neural networks.""" + + def test_dummy(self, estimator_instance): + """Dummy test to act as placeholder.""" + # check if multivariate input raises error for univariate regressors + assert 42 == 42 diff --git a/sktime/param_est/base.py b/sktime/param_est/base.py index d1a430e7603..55a6af4324e 100644 --- a/sktime/param_est/base.py +++ b/sktime/param_est/base.py @@ -60,6 +60,8 @@ class BaseParamFitter(BaseEstimator): "capability:multivariate": False, # can estimator handle multivariate data? "python_version": None, # PEP 440 python version specifier to limit versions "python_dependencies": None, # string or str list of pkg soft dependencies + "authors": "sktime developers", # author(s) of the object + "maintainers": "sktime developers", # current maintainer(s) of the object } def __init__(self): @@ -70,11 +72,46 @@ def __init__(self): super().__init__() _check_estimator_deps(self) + def __mul__(self, other): + """Magic * method, for estimators on the right. + + Overloaded multiplication operation for parameter fitters. + Implemented for ``other`` being: + + * a forecaster, results in ``PluginParamsForecaster`` + * a transformer, results in ``PluginParamsTransformer`` + * otherwise returns `NotImplemented`. + + Parameters + ---------- + other: `sktime` estimator, must be one of the types specified above + otherwise, `NotImplemented` is returned + + Returns + ------- + one of the plugin estimator objects, + concatenation of `self` (first) with `other` (last). + """ + from sktime.forecasting.base import BaseForecaster + from sktime.param_est.plugin import ( + PluginParamsForecaster, + PluginParamsTransformer, + ) + from sktime.transformations.base import BaseTransformer + + if isinstance(other, BaseForecaster): + return PluginParamsForecaster(param_est=self, forecaster=other) + elif isinstance(other, BaseTransformer): + return PluginParamsTransformer(param_est=self, transformer=other) + else: + return NotImplemented + def __rmul__(self, other): """Magic * method, return concatenated ParamFitterPipeline, trafos on left. - Overloaded multiplication operation for classifiers. Implemented for `other` - being a transformer, otherwise returns `NotImplemented`. + Overloaded multiplication operation for parameter fitters. + Implemented for ``other`` being a transformer, + otherwise returns `NotImplemented`. Parameters ---------- @@ -381,23 +418,3 @@ def _update(self, X): # but looping to self.fit for now to avoid interface break return self - - def _get_fitted_params(self): - """Get fitted parameters. - - private _get_fitted_params, called from get_fitted_params - - State required: - Requires state to be "fitted". - - Returns - ------- - fitted_params : dict - """ - # default retrieves all self attributes ending in "_" - # and returns them with keys that have the "_" removed - fitted_params = [attr for attr in dir(self) if attr.endswith("_")] - fitted_params = [x for x in fitted_params if not x.startswith("_")] - fitted_param_dict = {p[:-1]: getattr(self, p) for p in fitted_params} - - return fitted_param_dict diff --git a/sktime/param_est/compose/__init__.py b/sktime/param_est/compose/__init__.py new file mode 100644 index 00000000000..10423cfb2b0 --- /dev/null +++ b/sktime/param_est/compose/__init__.py @@ -0,0 +1,7 @@ +"""Composition involving parameter estimators.""" +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +from sktime.param_est.compose._func_fitter import FunctionParamFitter +from sktime.param_est.compose._pipeline import ParamFitterPipeline + +__author__ = ["fkiraly", "tpvasconcelos"] +__all__ = ["ParamFitterPipeline", "FunctionParamFitter"] diff --git a/sktime/param_est/compose/_func_fitter.py b/sktime/param_est/compose/_func_fitter.py new file mode 100644 index 00000000000..32807df4848 --- /dev/null +++ b/sktime/param_est/compose/_func_fitter.py @@ -0,0 +1,164 @@ +"""Implements FunctionParamFitter, a class to create custom parameter fitters.""" +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +from sktime.datatypes import ALL_TIME_SERIES_MTYPES +from sktime.param_est.base import BaseParamFitter + +__author__ = ["tpvasconcelos"] +__all__ = ["FunctionParamFitter"] + + +class FunctionParamFitter(BaseParamFitter): + r"""Constructs a parameter fitter from an arbitrary callable. + + A FunctionParamFitter forwards its X argument to a user-defined + function (or callable object) and sets the result of this function + to the ``param`` attribute. This can be useful for stateless + estimators such as simple conditional parameter selectors. + + Note: If a lambda function is used as the ``func``, then the + resulting estimator will not be pickleable. + + Parameters + ---------- + param : str + The name of the parameter to set. + func : callable (X: X_type, **kwargs) -> Any + The callable to use for the parameter estimation. This will be + passed the same arguments as estimator, with args and kwargs + forwarded. + kw_args : dict, default=None + Dictionary of additional keyword arguments to pass to func. + X_type : str, one of "pd.DataFrame, pd.Series, np.ndarray", or list thereof + default = ["pd.DataFrame", "pd.Series", "np.ndarray"] + list of types that func is assumed to allow for X (see signature above) + if X passed to transform/inverse_transform is not on the list, + it will be converted to the first list element before passed to funcs + + See Also + -------- + sktime.param_est.plugin.PluginParamsForecaster : + Plugs parameters from a parameter estimator into a forecaster. + sktime.forecasting.compose.MultiplexForecaster : + MultiplexForecaster for selecting among different models. + + Examples + -------- + This class could be used to construct a parameter estimator that + selects a forecaster based on the input data's length. The + selected forecaster can be stored in the ``selected_forecaster_`` + attribute, which can be then passed down to a + :class:`~sktime.forecasting.compose.MultiplexForecaster` via a + :class:`~sktime.param_est.plugin.PluginParamsForecaster`. + + >>> import numpy as np + >>> param_est = FunctionParamFitter( + ... param="selected_forecaster", + ... func=( + ... lambda X, threshold: "naive-seasonal" + ... if len(X) >= threshold + ... else "naive-last" + ... ), + ... kw_args={"threshold": 7}, + ... ) + >>> param_est.fit(np.asarray([1, 2, 3, 4])) + FunctionParamFitter(...) + >>> param_est.get_fitted_params() + {'selected_forecaster': 'naive-last'} + >>> param_est.fit(np.asarray([1, 2, 3, 4, 5, 6, 7])) + FunctionParamFitter(...) + >>> param_est.get_fitted_params() + {'selected_forecaster': 'naive-seasonal'} + + The full conditional forecaster selection pipeline could look + like this: + + >>> from sktime.forecasting.compose import MultiplexForecaster + >>> from sktime.forecasting.naive import NaiveForecaster + >>> from sktime.param_est.plugin import PluginParamsForecaster + >>> forecaster = PluginParamsForecaster( + ... param_est=param_est, + ... forecaster=MultiplexForecaster( + ... forecasters=[ + ... ("naive-last", NaiveForecaster()), + ... ("naive-seasonal", NaiveForecaster(sp=7)), + ... ] + ... ), + ... ) + >>> forecaster.fit(np.asarray([1, 2, 3, 4])) + PluginParamsForecaster(...) + >>> forecaster.predict(fh=[1,2,3]) + array([[4.], + [4.], + [4.]]) + >>> forecaster.fit(np.asarray([1, 2, 3, 4, 5, 6, 7])) + PluginParamsForecaster(...) + >>> forecaster.predict(fh=[1,2,3]) + array([[1.], + [2.], + [3.]]) + """ + + _tags = { + "authors": ["tpvasconcelos"], + "maintainers": ["tpvasconcelos"], + "X_inner_mtype": ALL_TIME_SERIES_MTYPES, + "scitype:X": ["Series", "Panel", "Hierarchical"], + "capability:missing_values": True, + "capability:multivariate": False, + } + + def __init__(self, param, func, kw_args=None, X_type=None): + self.param = param + self.func = func + self.kw_args = kw_args + self.X_type = X_type + super().__init__() + + if X_type is not None: + self.set_tags(X_inner_mtype=X_type) + + def _fit(self, X): + """Fit estimator and estimate parameters. + + private _fit containing the core logic, called from fit + + Writes to self: + Sets fitted model attributes ending in "_". + + Parameters + ---------- + X : guaranteed to be of a type in self.get_tag("X_inner_mtype") + Time series to which to fit the estimator. + + Returns + ------- + self : reference to self + """ + param = self.param.rstrip("_") + "_" + setattr(self, param, self.func(X, **(self.kw_args or {}))) + return self + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + There are no reserved values for parameter estimators. + + Returns + ------- + params : dict or list of dict, default = {} + Parameters to create testing instances of the class + Each dict are parameters to construct an "interesting" test instance, i.e., + `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. + `create_test_instance` uses the first (or only) dictionary in `params` + """ + params = [ + {"param": "param", "func": lambda X: "foo"}, + {"param": "param", "func": lambda X, kwarg: "foo", "kw_args": {"kwarg": 1}}, + ] + return params diff --git a/sktime/param_est/compose.py b/sktime/param_est/compose/_pipeline.py similarity index 98% rename from sktime/param_est/compose.py rename to sktime/param_est/compose/_pipeline.py index 7c4d3d8e47b..662441f7966 100644 --- a/sktime/param_est/compose.py +++ b/sktime/param_est/compose/_pipeline.py @@ -1,4 +1,7 @@ -"""Composition involving parameter estimators.""" +"""Implements ParamFitterPipeline. + +A class to create a pipeline of transformers and a parameter estimator. +""" # copyright: sktime developers, BSD-3-Clause License (see LICENSE file) from sktime.base import _HeterogenousMetaEstimator from sktime.param_est.base import BaseParamFitter @@ -8,7 +11,6 @@ __author__ = ["fkiraly"] __all__ = ["ParamFitterPipeline"] - # we ensure that internally we convert to pandas for now SUPPORTED_MTYPES = ["pd.DataFrame", "pd.Series", "pd-multiindex", "pd_multiindex_hier"] @@ -86,6 +88,7 @@ class ParamFitterPipeline(_HeterogenousMetaEstimator, BaseParamFitter): """ _tags = { + "authors": "fkiraly", "X_inner_mtype": SUPPORTED_MTYPES, # which types do _fit/_predict, support for X? "scitype:X": ["Series", "Panel", "Hierarchical"], diff --git a/sktime/param_est/fixed.py b/sktime/param_est/fixed.py index 88092cd9a92..bfb4e806a59 100644 --- a/sktime/param_est/fixed.py +++ b/sktime/param_est/fixed.py @@ -25,6 +25,7 @@ class FixedParams(BaseParamFitter): """ _tags = { + "authors": "fkiraly", "X_inner_mtype": ALL_TIME_SERIES_MTYPES, # which types do _fit/_predict, support for X? "scitype:X": ["Series", "Panel", "Hierarchical"], diff --git a/sktime/param_est/plugin/__init__.py b/sktime/param_est/plugin/__init__.py new file mode 100644 index 00000000000..04cf864a7e4 --- /dev/null +++ b/sktime/param_est/plugin/__init__.py @@ -0,0 +1,10 @@ +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +"""Plugin composites for parameter estimators.""" + +__all__ = [ + "PluginParamsForecaster", + "PluginParamsTransformer", +] + +from sktime.param_est.plugin._forecaster import PluginParamsForecaster +from sktime.param_est.plugin._transformer import PluginParamsTransformer diff --git a/sktime/param_est/plugin/_common.py b/sktime/param_est/plugin/_common.py new file mode 100644 index 00000000000..7d71f8bd49b --- /dev/null +++ b/sktime/param_est/plugin/_common.py @@ -0,0 +1,52 @@ +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +"""Common routines for plugin estimators.""" + +__author__ = ["fkiraly"] + + +def _resolve_param_map(param_est, estimator, params=None): + """Resolve parameter map from params for parameter plugin compositors. + + Parameters + ---------- + param_est : sktime estimator object with a fit method, inheriting from BaseEstimator + e.g., estimator inheriting from BaseParamFitter + assumed to be fitted and have ``get_fitted_params`` method + estimator : sktime object, inheriting from BaseObject or Basestimator + assumed to have ``get_params`` method, not assumed to be fitted + params : None, str, list of str, dict with str values/keys, optional, default=None + determines which parameters from param_est are plugged into estimator and where + None: all parameters of param_est are plugged into estimator + only parameters present in both ``estimator`` and ``param_est`` are plugged in + list of str: parameters in the list are plugged into parameters of the same name + only parameters present in both ``estimator`` and ``param_est`` are plugged in + str: considered as a one-element list of str with the string as single element + dict: parameter with name of value is plugged into parameter with name of key + only keys present in ``param_est`` and values in ``estimator`` are plugged in + + Returns + ------- + param_map : dict with str keys and str values + mapping of parameters from ``param_est_`` to estimator used in ``fit``, + after filtering for parameters present in both + to be used as ``param_map`` attribute of plugin compositor + """ + fitted_params = param_est.get_fitted_params() + + # normalize params to a dict with str keys and str values + if params is None: + param_map = {x: x for x in fitted_params} + elif isinstance(params, str): + param_map = {params: params} + elif isinstance(params, list): + param_map = {x: x for x in params} + elif isinstance(params, dict): + param_map = params + else: + raise TypeError("params must be None, a str, a list of str, or a dict") + + # obtain the mapping restricted to param names that are available in both + param_map = {x: param_map[x] for x in param_map if x in estimator.get_params()} + param_map = {x: param_map[x] for x in param_map if param_map[x] in fitted_params} + + return param_map diff --git a/sktime/param_est/plugin.py b/sktime/param_est/plugin/_forecaster.py similarity index 78% rename from sktime/param_est/plugin.py rename to sktime/param_est/plugin/_forecaster.py index 8b9aa0ee1ed..fac00d660c6 100644 --- a/sktime/param_est/plugin.py +++ b/sktime/param_est/plugin/_forecaster.py @@ -1,5 +1,5 @@ # copyright: sktime developers, BSD-3-Clause License (see LICENSE file) -"""Parameter estimators for seasonality.""" +"""Plugin composite for substituting parameter estimator fit into forecasters.""" __author__ = ["fkiraly"] __all__ = ["PluginParamsForecaster"] @@ -7,56 +7,63 @@ from inspect import signature from sktime.forecasting.base._delegate import _DelegatedForecaster +from sktime.param_est.plugin._common import _resolve_param_map class PluginParamsForecaster(_DelegatedForecaster): """Plugs parameters from a parameter estimator into a forecaster. - In `fit`, first fits `param_est` to data passed: + In ``fit``, first fits ``param_est`` to data passed: - * `y` of `fit` is passed as the first arg to `param_est.fit` - * `X` of `fit` is passed as the second arg, if `param_est.fit` has a second arg - * `fh` of `fit` is passed as `fh`, if any remaining arg of `param_est.fit` is `fh` + * ``y`` of ``fit`` is passed as the first arg to ``param_est.fit`` + * ``X`` of ``fit`` is passed as the second arg, + if ``param_est.fit`` has a second arg + * ``fh`` of ``fit`` is passed as ``fh``, + if any remaining arg of ``param_est.fit`` is ``fh`` - Then, does `forecaster.set_params` with desired/selected parameters. - Parameters of the fitted `param_est` are passed on to `forecaster`, - from/to pairs are as specified by the `params` parameter of `self`, see below. + Then, does ``forecaster.set_params`` with desired/selected parameters. + Parameters of the fitted ``param_est`` are passed on to ``forecaster``, + from/to pairs are as specified by the ``params`` parameter of ``self``, see below. - Then, fits `forecaster` to the data passed in `fit`. + Then, fits ``forecaster`` to the data passed in ``fit``. After that, behaves identically to `forecaster` with those parameters set. `update` behaviour is controlled by the `update_params` parameter. - Example: `param_est` seasonality test to determine `sp` parameter; - `forecaster` being any forecaster with an `sp` parameter. + Example: ``param_est`` seasonality test to determine ``sp`` parameter; + ``forecaster`` a forecaster with an ``sp`` parameter, + e.g., ``ExponentialSmoothing``. Parameters ---------- param_est : sktime estimator object with a fit method, inheriting from BaseEstimator e.g., estimator inheriting from BaseParamFitter or forecaster this is a "blueprint" estimator, state does not change when `fit` is called + forecaster : sktime forecaster, i.e., estimator inheriting from BaseForecaster this is a "blueprint" estimator, state does not change when `fit` is called + params : None, str, list of str, dict with str values/keys, optional, default=None - determines which parameters from param_est are plugged into forecaster and where + determines which parameters from ``param_est`` are plugged into forecaster where None: all parameters of param_est are plugged into forecaster - only parameters present in both `forecaster` and `param_est` are plugged in + only parameters present in both ``forecaster`` and ``param_est`` are plugged in list of str: parameters in the list are plugged into parameters of the same name - only parameters present in both `forecaster` and `param_est` are plugged in + only parameters present in both ``forecaster`` and ``param_est`` are plugged in str: considered as a one-element list of str with the string as single element dict: parameter with name of value is plugged into parameter with name of key - only keys present in `param_est` and values in `forecaster` are plugged in + only keys present in ``param_est`` and values in ``forecaster`` are plugged in + update_params : bool, optional, default=False whether fitted parameters by param_est_ are to be updated in self.update Attributes ---------- - param_est_ : sktime parameter estimator, clone of estimator in `param_est` - this clone is fitted in the pipeline when `fit` is called - forecaster_ : sktime forecaster, clone of forecaster in `forecaster` - this clone is fitted in the pipeline when `fit` is called + param_est_ : sktime parameter estimator, clone of estimator in ``param_est`` + this clone is fitted in the pipeline when ``fit`` is called + forecaster_ : sktime forecaster, clone of ``forecaster`` + this clone is fitted in the pipeline when ``fit`` is called param_map_ : dict - mapping of parameters from `param_est_` to `forecaster_` used in `fit`, + mapping of parameters from ``param_est_`` to ``forecaster_`` used in ``fit``, after filtering for parameters present in both Examples @@ -68,24 +75,38 @@ class PluginParamsForecaster(_DelegatedForecaster): >>> from sktime.transformations.series.difference import Differencer >>> >>> y = load_airline() # doctest: +SKIP + >>> + >>> # sp_est is a seasonality estimator + >>> # ACF assumes stationarity so we concat with differencing first >>> sp_est = Differencer() * SeasonalityACF() # doctest: +SKIP + >>> + >>> # fcst is a forecaster with a "sp" parameter which we want to tune >>> fcst = NaiveForecaster() # doctest: +SKIP + >>> + >>> # sp_auto is auto-tuned via PluginParamsForecaster >>> sp_auto = PluginParamsForecaster(sp_est, fcst) # doctest: +SKIP + >>> + >>> # fit sp_auto to data, predict, and inspect the tuned sp parameter >>> sp_auto.fit(y, fh=[1, 2, 3]) # doctest: +SKIP PluginParamsForecaster(...) >>> y_pred = sp_auto.predict() # doctest: +SKIP >>> sp_auto.forecaster_.get_params()["sp"] # doctest: +SKIP 12 + >>> # shorthand ways to specify sp_auto, via dunder, does the same + >>> sp_auto = sp_est * fcst # doctest: +SKIP + >>> # or entire pipeline in one go + >>> sp_auto = Differencer() * SeasonalityACF() * NaiveForecaster() # doctest: +SKIP using dictionary to plug "foo" parameter into "sp" >>> from sktime.param_est.fixed import FixedParams >>> sp_plugin = PluginParamsForecaster( - ... FixedParams({"foo": 12}), NaiveForecaster(), params={"foo": "sp"} + ... FixedParams({"foo": 12}), NaiveForecaster(), params={"sp": "foo"} ... ) # doctest: +SKIP """ _tags = { + "authors": "fkiraly", "requires-fh-in-fit": False, "handles-missing-data": False, "scitype:y": "both", @@ -107,10 +128,19 @@ def __init__(self, param_est, forecaster, params=None, update_params=False): self.update_params = update_params super().__init__() - self.clone_tags(self.forecaster_) + + self._set_delegated_tags(self.forecaster_) + + # parameter estimators that are univariate do not broadcast, + # so broadcasting needs to be done by the composite (i.e., self) + if param_est.get_tags()["object_type"] == "param_est": + if not param_est.get_tags()["capability:multivariate"]: + self.set_tags(**{"scitype:y": "univariate"}) + self.set_tags(**{"fit_is_empty": False}) # todo: only works for single series now # think about how to deal with vectorization later + self.set_tags(**{"X_inner_mtype": ["pd.DataFrame", "pd.Series", "np.ndarray"]}) self.set_tags(**{"y_inner_mtype": ["pd.DataFrame", "pd.Series", "np.ndarray"]}) def _fit(self, y, X, fh): @@ -162,26 +192,7 @@ def _fit(self, y, X, fh): param_est.fit(y, **fit_kwargs) fitted_params = param_est.get_fitted_params() - # obtain the mapping restricted to param names that are available - fc_par_names = forecaster.get_params().keys() - pe_par_names = fitted_params.keys() - - params = self.params - if params is None: - param_map = {x: x for x in fitted_params.keys()} - elif isinstance(params, str): - param_map = {params: params} - elif isinstance(params, list): - param_map = {x: x for x in params} - elif isinstance(params, dict): - param_map = params - else: - raise TypeError("params must be None, a str, a list of str, or a dict") - - param_map = {x: param_map[x] for x in param_map.keys() if x in fc_par_names} - param_map = { - x: param_map[x] for x in param_map.keys() if param_map[x] in pe_par_names - } + param_map = _resolve_param_map(param_est, forecaster, self.params) self.param_map_ = param_map # obtain the values of fitted params, and set forecaster to those @@ -259,7 +270,7 @@ def get_test_params(cls, parameter_set="default"): parameter_set : str, default="default" Name of the set of test parameters to return, for use in tests. If no special parameters are defined for a value, will return `"default"` set. - There are currently no reserved values for transformers. + There are currently no reserved values for forecasters. Returns ------- @@ -278,7 +289,7 @@ def get_test_params(cls, parameter_set="default"): params1 = { "forecaster": NaiveForecaster(), "param_est": FixedParams({"foo": 12}), - "params": {"foo": "sp"}, + "params": {"sp": "foo"}, } params = [params1] diff --git a/sktime/param_est/plugin/_transformer.py b/sktime/param_est/plugin/_transformer.py new file mode 100644 index 00000000000..aa02c51987c --- /dev/null +++ b/sktime/param_est/plugin/_transformer.py @@ -0,0 +1,241 @@ +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +"""Plugin composite for substituting parameter estimator fit into transformers.""" + +__author__ = ["fkiraly"] +__all__ = ["PluginParamsTransformer"] + +from inspect import signature + +from sktime.param_est.plugin._common import _resolve_param_map +from sktime.transformations._delegate import _DelegatedTransformer + + +class PluginParamsTransformer(_DelegatedTransformer): + """Plugs parameters from a parameter estimator into a transformer. + + In ``fit``, first fits ``param_est`` to data passed: + + * ``X`` of ``fit`` is passed as the first arg to ``param_est.fit`` + * ``y`` of ``fit`` is passed as the second arg to ``param_est.fit``, + if ``param_est.fit`` has a second arg + + Then, does ``transformer.set_params`` with desired/selected parameters. + Parameters of the fitted `param_est` are passed on to ``transformer``, + from/to pairs are as specified by the `params` parameter of ``self``, see below. + + Then, fits ``transformer`` to the data passed in ``fit``. + + After that, behaves identically to ``transformer`` with those parameters set. + + Example: ``param_est`` seasonality test to determine ``sp`` parameter; + ``transformer`` a transformer with an ``sp`` parameter, e.g., ``Deseasonalizer``. + + Parameters + ---------- + param_est : sktime estimator object with a fit method, inheriting from BaseEstimator + e.g., estimator inheriting from BaseParamFitter or transformer + this is a "blueprint" estimator, state does not change when `fit` is called + + transformer : sktime transformer, i.e., estimator inheriting from BaseTransformer + this is a "blueprint" estimator, state does not change when `fit` is called + + params : None, str, list of str, dict with str values/keys, optional, default=None + determines which parameters from ``param_est`` are plugged into trafo and where + None: all parameters of param_est are plugged into transformer + only parameters present in both ``transformer`` and ``param_est`` are plugged in + list of str: parameters in the list are plugged into parameters of the same name + only parameters present in both ``transformer`` and ``param_est`` are plugged in + str: considered as a one-element list of str with the string as single element + dict: parameter with name of value is plugged into parameter with name of key + only keys present in ``param_est`` and values in ``transformer`` are plugged in + + Attributes + ---------- + param_est_ : sktime parameter estimator, clone of estimator in ``param_est`` + this clone is fitted in the pipeline when ``fit`` is called + transformer_ : sktime transformer, clone of ``transformer`` + this clone is fitted in the pipeline when ``fit`` is called + param_map_ : dict + mapping of parameters from `param_est_` to `transformer_` used in `fit`, + after filtering for parameters present in both + + Examples + -------- + >>> from sktime.datasets import load_airline + >>> from sktime.param_est.plugin import PluginParamsTransformer + >>> from sktime.param_est.seasonality import SeasonalityACF + >>> from sktime.transformations.series.detrend import Deseasonalizer + >>> from sktime.transformations.series.difference import Differencer + >>> + >>> X = load_airline() # doctest: +SKIP + >>> + >>> # sp_est is a seasonality estimator + >>> # ACF assumes stationarity so we concat with differencing first + >>> sp_est = Differencer() * SeasonalityACF() # doctest: +SKIP + + >>> # trafo is a forecaster with a "sp" parameter which we want to tune + >>> trafo = Deseasonalizer() # doctest: +SKIP + >>> sp_auto = PluginParamsTransformer(sp_est, trafo) # doctest: +SKIP + >>> + >>> # fit sp_auto to data, transform, and inspect the tuned sp parameter + >>> sp_auto.fit(X) # doctest: +SKIP + PluginParamsTransformer(...) + >>> Xt = sp_auto.transform(X) # doctest: +SKIP + >>> sp_auto.transformer_.get_params()["sp"] # doctest: +SKIP + 12 + >>> # shorthand ways to specify sp_auto, via dunder, does the same + >>> sp_auto = sp_est * trafo # doctest: +SKIP + >>> # or entire pipeline in one go + >>> sp_auto = Differencer() * SeasonalityACF() * Deseasonalizer() # doctest: +SKIP + + using dictionary to plug "foo" parameter into "sp" + + >>> from sktime.param_est.fixed import FixedParams + >>> sp_plugin = PluginParamsTransformer( + ... FixedParams({"foo": 12}), Deseasonalizer(), params={"sp": "foo"} + ... ) # doctest: +SKIP + """ + + _tags = { + "authors": "fkiraly", + "capability:inverse_transform": True, # can the transformer inverse transform? + "univariate-only": False, # can the transformer handle multivariate X? + "fit_is_empty": False, # is fit empty and can be skipped? Yes = True + "remember_data": False, # whether all data seen is remembered as self._X + } + + # attribute for _DelegatedTransformer, which then delegates + # all non-overridden methods to those of same name in self.transformer_ + # see further details in _DelegatedTransformer docstring + _delegate_name = "transformer_" + + def __init__(self, param_est, transformer, params=None, update_params=False): + self.param_est = param_est + self.param_est_ = param_est.clone() + self.transformer = transformer + self.transformer_ = transformer.clone() + self.params = params + self.update_params = update_params + + super().__init__() + + TAGS_TO_CLONE = [ + "scitype:transform-input", + "scitype:transform-output", + "scitype:transform-labels", + "scitype:instancewise", + "capability:inverse_transform", + "capability:inverse_transform:range", + "capability:inverse_transform:exact", + "univariate-only", + "y_inner_mtype", + "requires_y", + "enforce_index_type", + "X-y-must-have-same-index", + "transform-returns-same-time-index", + "skip-inverse-transform", + "capability:unequal_length", + "capability:unequal_length:removes", + "handles-missing-data", + "capability:missing_values:removes", + ] + + self.clone_tags(self.transformer_, TAGS_TO_CLONE) + + # todo: only works for single series now + # think about how to deal with vectorization later + SERIES_MTYPES = ["pd.DataFrame", "pd.Series", "np.ndarray"] + self.set_tags(**{"X_inner_mtype": SERIES_MTYPES}) + + if self.get_tags()["y_inner_mtype"] not in [None, "None"]: + self.set_tags(**{"y_inner_mtype": SERIES_MTYPES}) + + def _fit(self, X, y=None): + """Fit transformer to X and y. + + private _fit containing the core logic, called from fit + + Parameters + ---------- + X : Series or Panel of mtype X_inner_mtype + if X_inner_mtype is list, _fit must support all types in it + Data to fit transform to + y : Series or Panel of mtype y_inner_mtype, default=None + Additional data, e.g., labels for transformation + + Returns + ------- + self: reference to self + """ + # reference to delegate + transformer = self._get_delegate() + + # fit the parameter estimator to X + param_est = self.param_est_ + + # map args X, y onto inner signature + # X is passed always + # y is passed if param_est fit has at least two arguments + inner_params = list(signature(param_est.fit).parameters.keys()) + fit_kwargs = {} + if len(inner_params) > 1: + fit_kwargs[inner_params[1]] = y + + param_est.fit(X, **fit_kwargs) + fitted_params = param_est.get_fitted_params() + + param_map = _resolve_param_map(param_est, transformer, self.params) + self.param_map_ = param_map + + # obtain the values of fitted params, and set transformer to those + new_params = {k: fitted_params[v] for k, v in param_map.items()} + transformer.set_params(**new_params) + + # fit the transformer, with the fitted parameter values + transformer.fit(X=X, y=y) + return self + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + There are currently no reserved values for transformers. + + Returns + ------- + params : dict or list of dict, default = {} + Parameters to create testing instances of the class + Each dict are parameters to construct an "interesting" test instance, i.e., + `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. + `create_test_instance` uses the first (or only) dictionary in `params` + """ + from sktime.param_est.fixed import FixedParams + from sktime.param_est.seasonality import SeasonalityACF + from sktime.transformations.series.detrend import Deseasonalizer + from sktime.transformations.series.exponent import ExponentTransformer + from sktime.utils.validation._dependencies import _check_estimator_deps + + # use of dictionary to plug "foo" parameter into "power", uses mock param_est + params1 = { + "transformer": ExponentTransformer(), + "param_est": FixedParams({"foo": 12}), + "params": {"power": "foo"}, + } + params = [params1] + + # uses a "real" param est that depends on statsmodels, requires statsmodels + if _check_estimator_deps(SeasonalityACF, severity="none"): + # explicit reference to a parameter "sp", present in both estimators + params2 = { + "transformer": Deseasonalizer(), + "param_est": SeasonalityACF(), + "params": "sp", + } + params = params + [params2] + + return params diff --git a/sktime/param_est/plugin/tests/__init__.py b/sktime/param_est/plugin/tests/__init__.py new file mode 100644 index 00000000000..8f604b2023b --- /dev/null +++ b/sktime/param_est/plugin/tests/__init__.py @@ -0,0 +1,2 @@ +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +"""Tests for plugin composites for parameter estimators.""" diff --git a/sktime/param_est/plugin/tests/test_plugin.py b/sktime/param_est/plugin/tests/test_plugin.py new file mode 100644 index 00000000000..ca608c37d71 --- /dev/null +++ b/sktime/param_est/plugin/tests/test_plugin.py @@ -0,0 +1,107 @@ +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +"""Tests for plugin composites for parameter estimators.""" + +import pandas as pd +import pytest + +from sktime.param_est.seasonality import SeasonalityACF +from sktime.utils.validation._dependencies import _check_estimator_deps + + +@pytest.mark.skipif( + not _check_estimator_deps(SeasonalityACF, severity="none"), + reason="skip test if required soft dependencies not available", +) +def test_plugin_fcst(): + """Test PluginParamsForecaster - same as docstring.""" + from sktime.datasets import load_airline + from sktime.forecasting.naive import NaiveForecaster + from sktime.param_est.fixed import FixedParams + from sktime.param_est.plugin import PluginParamsForecaster + from sktime.transformations.series.difference import Differencer + + y = load_airline() + + # sp_est is a seasonality estimator + # ACF assumes stationarity so we concat with differencing first + sp_est = Differencer() * SeasonalityACF() + + # fcst is a forecaster with a "sp" parameter which we want to tune + fcst = NaiveForecaster() + + # sp_auto is auto-tuned via PluginParamsForecaster + sp_auto = PluginParamsForecaster(sp_est, fcst) + + # fit sp_auto to data, predict, and inspect the tuned sp parameter + sp_auto.fit(y, fh=[1, 2, 3]) + y_pred = sp_auto.predict() + assert isinstance(y_pred, pd.Series) + + assert sp_auto.forecaster_.get_params()["sp"] == 12 + + # shorthand ways to specify sp_auto, via dunder, does the same + sp_auto2 = sp_est * fcst + assert isinstance(sp_auto2, PluginParamsForecaster) + assert sp_auto2 == sp_auto + + # or entire pipeline in one go + sp_auto3 = Differencer() * SeasonalityACF() * NaiveForecaster() + assert isinstance(sp_auto3, PluginParamsForecaster) + assert sp_auto3 == sp_auto + + # plugin with dict + sp_plugin = PluginParamsForecaster( + FixedParams({"foo": 42}), NaiveForecaster(), params={"sp": "foo"} + ) + + sp_plugin.fit(y, fh=[1, 2, 3]) + assert sp_plugin.forecaster_.get_params()["sp"] == 42 + + +@pytest.mark.skipif( + not _check_estimator_deps(SeasonalityACF, severity="none"), + reason="skip test if required soft dependencies not available", +) +def test_plugin_trafo(): + """Test PluginParamsTransformer - same as docstring.""" + from sktime.datasets import load_airline + from sktime.param_est.fixed import FixedParams + from sktime.param_est.plugin import PluginParamsTransformer + from sktime.param_est.seasonality import SeasonalityACF + from sktime.transformations.series.detrend import Deseasonalizer + from sktime.transformations.series.difference import Differencer + + X = load_airline() + + # sp_est is a seasonality estimator + # ACF assumes stationarity so we concat with differencing first + sp_est = Differencer() * SeasonalityACF() + + # trafo is a forecaster with a "sp" parameter which we want to tune + trafo = Deseasonalizer() + sp_auto = PluginParamsTransformer(sp_est, trafo) + + # fit sp_auto to data, transform, and inspect the tuned sp parameter + sp_auto.fit(X) + + Xt = sp_auto.transform(X) + assert isinstance(Xt, pd.Series) + assert sp_auto.transformer_.get_params()["sp"] == 12 + + # shorthand ways to specify sp_auto, via dunder, does the same + sp_auto2 = sp_est * trafo + assert isinstance(sp_auto2, PluginParamsTransformer) + assert sp_auto2 == sp_auto + + # or entire pipeline in one go + sp_auto3 = Differencer() * SeasonalityACF() * Deseasonalizer() + assert isinstance(sp_auto3, PluginParamsTransformer) + assert sp_auto3 == sp_auto + + # plugin with dict + sp_plugin = PluginParamsTransformer( + FixedParams({"foo": 42}), Deseasonalizer(), params={"sp": "foo"} + ) + + sp_plugin.fit(X) + assert sp_plugin.transformer_.get_params()["sp"] == 42 diff --git a/sktime/param_est/seasonality.py b/sktime/param_est/seasonality.py index a6174c302c8..b6540d22b9a 100644 --- a/sktime/param_est/seasonality.py +++ b/sktime/param_est/seasonality.py @@ -87,6 +87,7 @@ class SeasonalityACF(BaseParamFitter): """ _tags = { + "authors": "fkiraly", "X_inner_mtype": "pd.Series", # which types do _fit/_predict, support for X? "scitype:X": "Series", # which X scitypes are supported natively? "capability:missing_values": True, # can estimator handle missing data? @@ -273,6 +274,7 @@ class SeasonalityACFqstat(BaseParamFitter): """ _tags = { + "authors": "fkiraly", "X_inner_mtype": "pd.Series", # which types do _fit/_predict, support for X? "scitype:X": "Series", # which X scitypes are supported natively? "capability:missing_values": True, # can estimator handle missing data? @@ -452,6 +454,8 @@ class SeasonalityPeriodogram(BaseParamFitter): """ _tags = { + "authors": ["blazingbhavneek"], + "maintainers": ["blaingbhavneek"], "X_inner_mtype": "pd.Series", "scitype:X": "Series", "capability:missing_values": True, diff --git a/sktime/param_est/stationarity/__init__.py b/sktime/param_est/stationarity/__init__.py new file mode 100644 index 00000000000..ef6f4343cb6 --- /dev/null +++ b/sktime/param_est/stationarity/__init__.py @@ -0,0 +1,23 @@ +"""Module for parameter estimators of stationarity tests.""" + +__author__ = ["fkiraly", "Vasudeva-bit"] +__all__ = [ + "StationarityADF", + "StationarityKPSS", + "StationarityADFArch", + "StationarityDFGLS", + "StationarityPhillipsPerron", + "StationarityKPSSArch", + "StationarityZivotAndrews", + "StationarityVarianceRatio", +] + +from sktime.param_est.stationarity._arch import ( + StationarityADFArch, + StationarityDFGLS, + StationarityKPSSArch, + StationarityPhillipsPerron, + StationarityVarianceRatio, + StationarityZivotAndrews, +) +from sktime.param_est.stationarity._statsmodels import StationarityADF, StationarityKPSS diff --git a/sktime/param_est/stationarity/_arch.py b/sktime/param_est/stationarity/_arch.py new file mode 100644 index 00000000000..24af0c96f6d --- /dev/null +++ b/sktime/param_est/stationarity/_arch.py @@ -0,0 +1,895 @@ +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +"""Parameter estimators for stationarity.""" + +__author__ = ["Vasudeva-bit"] +__all__ = [ + "StationarityADFArch", + "StationarityDFGLS", + "StationarityPhillipsPerron", + "StationarityKPSSArch", + "StationarityZivotAndrews", + "StationarityVarianceRatio", +] + +from sktime.param_est.base import BaseParamFitter + + +class StationarityADFArch(BaseParamFitter): + """Test for stationarity via the Augmented Dickey-Fuller Unit Root Test (ADF). + + Direct interface to ``DFGLS`` test from the ``arch`` package. + Does not assume ARCH process, naming is due to the use of the ``arch`` package. + + Uses ``arch.unitroot.ADF`` as a test for unit roots, + and derives a boolean statement whether a series is stationary. + + Also returns test results for the unit root test as fitted parameters. + + Parameters + ---------- + lags : int, optional + The number of lags to use in the ADF regression. If omitted or None, + ``method`` is used to automatically select the lag length with no more + than ``max_lags`` are included. + trend : {"n", "c", "ct", "ctt"}, optional + The trend component to include in the test + + - "n" - No trend components + - "c" - Include a constant (Default) + - "ct" - Include a constant and linear time trend + - "ctt" - Include a constant and linear and quadratic time trends + + max_lags : int, optional + The maximum number of lags to use when selecting lag length + method : {"AIC", "BIC", "t-stat"}, optional + The method to use when selecting the lag length + + - "AIC" - Select the minimum of the Akaike IC + - "BIC" - Select the minimum of the Schwarz/Bayesian IC + - "t-stat" - Select the minimum of the Schwarz/Bayesian IC + + low_memory : bool + Flag indicating whether to use a low memory implementation of the + lag selection algorithm. The low memory algorithm is slower than + the standard algorithm but will use 2-4% of the memory required for + the standard algorithm. This options allows automatic lag selection + to be used in very long time series. If None, use automatic selection + of algorithm. + + Attributes + ---------- + stationary_ : bool + whether the series in ``fit`` is stationary according to the test + more precisely, whether the null of the ADF test is rejected at ``p_threshold`` + test_statistic_ : float + The ADF test statistic, of running ``adfuller`` on ``y`` in ``fit`` + pvalue_ : float : float + MacKinnon's approximate p-value based on MacKinnon (1994, 2010), + obtained when running ``adfuller`` on ``y`` in ``fit`` + usedlag_ : int + The number of lags used in the test. + + Examples + -------- + >>> from sktime.datasets import load_airline + >>> from sktime.param_est.stationarity import StationarityADFArch + >>> + >>> X = load_airline() # doctest: +SKIP + >>> sty_est = StationarityADFArch() # doctest: +SKIP + >>> sty_est.fit(X) # doctest: +SKIP + StationarityADFArch(...) + >>> sty_est.get_fitted_params()["stationary"] # doctest: +SKIP + False + """ + + _tags = { + "authors": ["Vasudeva-bit"], + "maintainers": ["Vasudeva-bit"], + "X_inner_mtype": ["pd.Series", "np.ndarray"], + "scitype:X": "Series", + "python_dependencies": "arch", + } + + def __init__( + self, + lags=None, + trend="c", + max_lags=None, + method="aic", + low_memory=None, + p_threshold=0.05, + ): + self.lags = lags + self.trend = trend + self.max_lags = max_lags + self.method = method + self.low_memory = low_memory + self.p_threshold = p_threshold + super().__init__() + + def _fit(self, X): + """Fit estimator and estimate parameters. + + private _fit containing the core logic, called from fit + + Writes to self: + Sets fitted model attributes ending in "_". + + Parameters + ---------- + X : {ndarray, Series} + The data to test for a unit root + + Returns + ------- + self : reference to self + """ + from arch.unitroot import ADF + + p_threshold = self.p_threshold + + result = ADF( + y=X, + lags=self.lags, + trend=self.trend, + max_lags=self.max_lags, + method=self.method, + low_memory=self.low_memory, + ) + self.test_statistic_ = result.stat + self.pvalue = result.pvalue + self.stationary_ = result.pvalue <= p_threshold + self.used_lag_ = result._lags + + return self + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + There are no reserved values for parameter estimators. + + Returns + ------- + params : dict or list of dict, default = {} + Parameters to create testing instances of the class + Each dict are parameters to construct an "interesting" test instance, i.e., + `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. + `create_test_instance` uses the first (or only) dictionary in `params` + """ + params1 = {} + params2 = { + "lags": 5, + "trend": "ctt", + "max_lags": 10, + "method": "t-stat", + "low_memory": True, + "p_threshold": 0.1, + } + + return [params1, params2] + + +class StationarityDFGLS(BaseParamFitter): + """Test for stationarity via the Dickey-Fuller GLS (DFGLS) Unit Root Test. + + Direct interface to ``DFGLS`` test from the ``arch`` package. + + Uses ``arch.unitroot.DFGLS`` as a test for unit roots, + and derives a boolean statement whether a series is stationary. + + Also returns test results for the unit root test as fitted parameters. + + Parameters + ---------- + lags : int, optional + The number of lags to use in the ADF regression. If omitted or None, + ``method`` is used to automatically select the lag length with no more + than ``max_lags`` are included. + trend : {"c", "ct"}, optional + The trend component to include in the test + + - "c" - Include a constant (Default) + - "ct" - Include a constant and linear time trend + + max_lags : int, optional + The maximum number of lags to use when selecting lag length. When using + automatic lag length selection, the lag is selected using OLS + detrending rather than GLS detrending ([2]_). + method : {"AIC", "BIC", "t-stat"}, optional + The method to use when selecting the lag length + + - "AIC" - Select the minimum of the Akaike IC + - "BIC" - Select the minimum of the Schwarz/Bayesian IC + - "t-stat" - Select the minimum of the Schwarz/Bayesian IC + + Attributes + ---------- + stationary_ : bool + whether the series in ``fit`` is stationary according to the test + more precisely, whether the null of the Dickey-Fuller-GLS test is rejected at + ``p_threshold`` + test_statistic_ : float + The DFGLS test statistic, of running ``DFGLS`` on ``y`` in ``fit`` + pvalue_ : float : float + p-value obtained when running ``DFGLS`` on ``y`` in ``fit`` + usedlag_ : int + The number of lags used in the test. + + Examples + -------- + >>> from sktime.datasets import load_airline + >>> from sktime.param_est.stationarity import StationarityDFGLS + >>> + >>> X = load_airline() # doctest: +SKIP + >>> sty_est = StationarityDFGLS() # doctest: +SKIP + >>> sty_est.fit(X) # doctest: +SKIP + StationarityDFGLS(...) + >>> sty_est.get_fitted_params()["stationary"] # doctest: +SKIP + False + """ + + _tags = { + "authors": ["Vasudeva-bit"], + "maintainers": ["Vasudeva-bit"], + "X_inner_mtype": ["pd.Series", "np.ndarray"], + "scitype:X": "Series", + "python_dependencies": "arch", + } + + def __init__( + self, + lags=None, + trend="c", + max_lags=None, + method="aic", + p_threshold=0.05, + ): + self.lags = lags + self.trend = trend + self.max_lags = max_lags + self.method = method + self.p_threshold = p_threshold + super().__init__() + + def _fit(self, X): + """Fit estimator and estimate parameters. + + private _fit containing the core logic, called from fit + + Writes to self: + Sets fitted model attributes ending in "_". + + Parameters + ---------- + X : {ndarray, Series} + The data to test for a unit root + + Returns + ------- + self : reference to self + """ + from arch.unitroot import DFGLS + + p_threshold = self.p_threshold + + result = DFGLS( + y=X, + lags=self.lags, + trend=self.trend, + max_lags=self.max_lags, + method=self.method, + ) + self.test_statistic_ = result.stat + self.pvalue = result.pvalue + self.stationary_ = result.pvalue <= p_threshold + self.used_lag_ = result._lags + + return self + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + There are no reserved values for parameter estimators. + + Returns + ------- + params : dict or list of dict, default = {} + Parameters to create testing instances of the class + Each dict are parameters to construct an "interesting" test instance, i.e., + `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. + `create_test_instance` uses the first (or only) dictionary in `params` + """ + params1 = {} + params2 = { + "lags": 5, + "trend": "ct", + "max_lags": 10, + "method": "t-stat", + "p_threshold": 0.1, + } + + return [params1, params2] + + +class StationarityPhillipsPerron(BaseParamFitter): + """Test for unit root order 1 via the Phillips-Perron Unit Root Test. + + Direct interface to ``PhillipsPerron`` test from the ``arch`` package. + + Uses ``arch.unitroot.PhillipsPerron`` as a test for unit roots, + and derives a boolean statement whether a series is stationary. + + Also returns test results for the unit root test as fitted parameters. + + Parameters + ---------- + lags : int, optional + The number of lags to use in the Newey-West estimator of the long-run + covariance. If omitted or None, the lag length is set automatically to + ``12 * (nobs/100) ** (1/4)`` + trend : {"n", "c", "ct"}, optional + The trend component to include in the test + + - "n" - No trend components + - "c" - Include a constant (Default) + - "ct" - Include a constant and linear time trend + + test_type : {"tau", "rho"} + The test to use when computing the test statistic. "tau" is based on + the t-stat and "rho" uses a test based on nobs times the re-centered + regression coefficient + + Attributes + ---------- + stationary_ : bool + whether the series in ``fit`` is integrated of order 1 + more precisely, whether the null of the Phillips-Perron test is rejected at + ``p_threshold`` + test_statistic_ : float + The PP test statistic, of running ``PhillipsPerron`` on ``y`` in ``fit`` + pvalue_ : float : float + p-value obtained when running ``PhillipsPerron`` on ``y`` in ``fit`` + usedlag_ : int + The number of lags used in the test. + + Examples + -------- + >>> from sktime.datasets import load_airline + >>> from sktime.param_est.stationarity import StationarityPhillipsPerron + >>> + >>> X = load_airline() # doctest: +SKIP + >>> sty_est = StationarityPhillipsPerron() # doctest: +SKIP + >>> sty_est.fit(X) # doctest: +SKIP + StationarityPhillipsPerron(...) + >>> sty_est.get_fitted_params()["stationary"] # doctest: +SKIP + False + """ + + _tags = { + "authors": ["Vasudeva-bit"], + "maintainers": ["Vasudeva-bit"], + "X_inner_mtype": ["pd.Series", "np.ndarray"], + "scitype:X": "Series", + "python_dependencies": "arch", + } + + def __init__( + self, + lags=None, + trend="c", + test_type="tau", + p_threshold=0.05, + ): + self.lags = lags + self.trend = trend + self.test_type = test_type + self.p_threshold = p_threshold + super().__init__() + + def _fit(self, X): + """Fit estimator and estimate parameters. + + private _fit containing the core logic, called from fit + + Writes to self: + Sets fitted model attributes ending in "_". + + Parameters + ---------- + X : {ndarray, Series} + The data to test for a unit root + + Returns + ------- + self : reference to self + """ + from arch.unitroot import PhillipsPerron + + p_threshold = self.p_threshold + + result = PhillipsPerron( + y=X, + lags=self.lags, + trend=self.trend, + test_type=self.test_type, + ) + self.test_statistic_ = result.stat + self.pvalue = result.pvalue + self.stationary_ = result.pvalue <= p_threshold + self.used_lag_ = result._lags + + return self + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + There are no reserved values for parameter estimators. + + Returns + ------- + params : dict or list of dict, default = {} + Parameters to create testing instances of the class + Each dict are parameters to construct an "interesting" test instance, i.e., + `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. + `create_test_instance` uses the first (or only) dictionary in `params` + """ + params1 = {} + params2 = { + "lags": 5, + "trend": "ct", + "test_type": "rho", + "p_threshold": 0.1, + } + + return [params1, params2] + + +class StationarityKPSSArch(BaseParamFitter): + """Test for stationarity via the Kwiatkowski-Phillips-Schmidt-Shin Unit Root Test. + + Direct interface to ``KPSS`` test from the ``arch`` package. + Does not assume ARCH process, naming is due to the use of the ``arch`` package. + + Uses ``arch.unitroot.KPSS`` as a test for trend-stationarity, + and derives a boolean statement whether a series is (trend-)stationary. + + Also returns test results for the unit root test as fitted parameters. + + Parameters + ---------- + lags : int, optional + The number of lags to use in the Newey-West estimator of the long-run + covariance. If omitted or None, the number of lags is calculated + with the data-dependent method of Hobijn et al. (1998). See also + Andrews (1991), Newey & West (1994), and Schwert (1989). + Set ``lags=-1`` to use the old method that only depends on the sample + size, ``12 * (nobs/100) ** (1/4)``. + trend : {"c", "ct"}, optional + The trend component to include in the ADF test + "c" - Include a constant (Default) + "ct" - Include a constant and linear time trend + + Attributes + ---------- + stationary_ : bool + whether the series in ``fit`` is stationary according to the test + more precisely, whether the null of the KPSS test is accepted at ``p_threshold`` + test_statistic_ : float + The KPSS test statistic, of running ``KPSS`` on ``y`` in ``fit`` + pvalue_ : float : float + p-value obtained when running ``KPSS`` on ``y`` in ``fit`` + usedlag_ : int + The number of lags used in the test. + + Examples + -------- + >>> from sktime.datasets import load_airline + >>> from sktime.param_est.stationarity import StationarityKPSSArch + >>> + >>> X = load_airline() # doctest: +SKIP + >>> sty_est = StationarityKPSSArch() # doctest: +SKIP + >>> sty_est.fit(X) # doctest: +SKIP + StationarityKPSSArch(...) + >>> sty_est.get_fitted_params()["stationary"] # doctest: +SKIP + True + """ + + _tags = { + "authors": ["Vasudeva-bit"], + "maintainers": ["Vasudeva-bit"], + "X_inner_mtype": ["pd.Series", "np.ndarray"], + "scitype:X": "Series", + "python_dependencies": "arch", + } + + def __init__( + self, + lags=None, + trend="c", + p_threshold=0.05, + ): + self.lags = lags + self.trend = trend + self.p_threshold = p_threshold + super().__init__() + + def _fit(self, X): + """Fit estimator and estimate parameters. + + private _fit containing the core logic, called from fit + + Writes to self: + Sets fitted model attributes ending in "_". + + Parameters + ---------- + X : {ndarray, Series} + The data to test for a unit root + + Returns + ------- + self : reference to self + """ + from arch.unitroot import KPSS + + p_threshold = self.p_threshold + + result = KPSS( + y=X, + lags=self.lags, + trend=self.trend, + ) + self.test_statistic_ = result.stat + self.pvalue = result.pvalue + self.stationary_ = result.pvalue > p_threshold + self.used_lag_ = result._lags + + return self + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + There are no reserved values for parameter estimators. + + Returns + ------- + params : dict or list of dict, default = {} + Parameters to create testing instances of the class + Each dict are parameters to construct an "interesting" test instance, i.e., + `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. + `create_test_instance` uses the first (or only) dictionary in `params` + """ + params1 = {} + params2 = { + "lags": 5, + "trend": "ct", + "p_threshold": 0.1, + } + + return [params1, params2] + + +class StationarityZivotAndrews(BaseParamFitter): + """Test for stationarity via the Zivot-Andrews Unit Root Test. + + Direct interface to ``ZivotAndrews`` test from the `arch` package. + + Uses ``arch.unitroot.ZivotAndrews`` as a test for unit roots, + and derives a boolean statement whether a series is stationary. + + Also returns test results for the unit root test as fitted parameters. + + Parameters + ---------- + lags : int, optional + The number of lags to use in the ADF regression. If omitted or None, + ``method`` is used to automatically select the lag length with no more + than `max_lags` are included. + trend : {"c", "t", "ct"}, optional + The trend component to include in the test + + - "c" - Include a constant (Default) + - "t" - Include a linear time trend + - "ct" - Include a constant and linear time trend + + trim : float + percentage of series at begin/end to exclude from break-period + calculation in range [0, 0.333] (default=0.15) + max_lags : int, optional + The maximum number of lags to use when selecting lag length + method : {"AIC", "BIC", "t-stat"}, optional + The method to use when selecting the lag length + + - "AIC" - Select the minimum of the Akaike IC + - "BIC" - Select the minimum of the Schwarz/Bayesian IC + - "t-stat" - Select the minimum of the Schwarz/Bayesian IC + + Attributes + ---------- + stationary_ : bool, whether the series in `fit` has a unit root + (with structural break) + more precisely, whether the null of the Zivot-Andrews test is rejected at + ``p_threshold`` + test_statistic_ : float + The ZA test statistic, of running ``ZivotAndrews`` on ``y`` in ``fit`` + pvalue_ : float : float + p-value obtained when running ``ZivotAndrews`` on ``y`` in ``fit`` + usedlag_ : int + The number of lags used in the test. + + Examples + -------- + >>> from sktime.datasets import load_airline + >>> from sktime.param_est.stationarity import StationarityZivotAndrews + >>> + >>> X = load_airline() # doctest: +SKIP + >>> sty_est = StationarityZivotAndrews() # doctest: +SKIP + >>> sty_est.fit(X) # doctest: +SKIP + StationarityZivotAndrews(...) + >>> sty_est.get_fitted_params()["stationary"] # doctest: +SKIP + False + """ + + _tags = { + "authors": ["Vasudeva-bit"], + "maintainers": ["Vasudeva-bit"], + "X_inner_mtype": ["pd.Series", "np.ndarray"], + "scitype:X": "Series", + "python_dependencies": "arch", + } + + def __init__( + self, + lags=None, + trend="c", + trim=0.15, + max_lags=None, + method="aic", + p_threshold=0.05, + ): + self.lags = lags + self.trend = trend + self.trim = trim + self.max_lags = max_lags + self.method = method + self.p_threshold = p_threshold + super().__init__() + + def _fit(self, X): + """Fit estimator and estimate parameters. + + private _fit containing the core logic, called from fit + + Writes to self: + Sets fitted model attributes ending in "_". + + Parameters + ---------- + X : {ndarray, Series} + The data to test for a unit root + + Returns + ------- + self : reference to self + """ + from arch.unitroot import ZivotAndrews + + p_threshold = self.p_threshold + + result = ZivotAndrews( + y=X, + lags=self.lags, + trend=self.trend, + trim=self.trim, + max_lags=self.max_lags, + method=self.method, + ) + self.test_statistic_ = result.stat + self.pvalue = result.pvalue + self.stationary_ = result.pvalue <= p_threshold + self.used_lag_ = result._lags + + return self + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + There are no reserved values for parameter estimators. + + Returns + ------- + params : dict or list of dict, default = {} + Parameters to create testing instances of the class + Each dict are parameters to construct an "interesting" test instance, i.e., + `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. + `create_test_instance` uses the first (or only) dictionary in `params` + """ + params1 = {} + params2 = { + "lags": 5, + "trend": "ct", + "trim": 0.1, + "max_lags": 10, + "method": "t-stat", + "p_threshold": 0.1, + } + + return [params1, params2] + + +class StationarityVarianceRatio(BaseParamFitter): + """Test for stationarity via the variance ratio test for random walks. + + Direct interface to ``VarianceRatio`` test from the `arch` package. + + Uses ``arch.unitroot.VarianceRatio`` as a test for unit roots, + and derives a boolean statement whether a series is stationary. + + Also returns test results for the unit root test as fitted parameters. + + Parameters + ---------- + lags : int + The number of periods to used in the multi-period variance, which is + the numerator of the test statistic. Must be at least 2 + trend : {"n", "c"}, optional + "c" allows for a non-zero drift in the random walk, while "n" requires + that the increments to y are mean 0 + overlap : bool, optional + Indicates whether to use all overlapping blocks. Default is True. If + False, the number of observations in y minus 1 must be an exact + multiple of lags. If this condition is not satisfied, some values at + the end of y will be discarded. + robust : bool, optional + Indicates whether to use heteroskedasticity robust inference. Default + is True. + debiased : bool, optional + Indicates whether to use a debiased version of the test. Default is + True. Only applicable if overlap is True. + + Attributes + ---------- + stationary_ : bool + whether the series in ``fit`` is stationary according to the test + more precisely, whether the null of the variance ratio test is accepted at + ``p_threshold`` + test_statistic_ : float + The VR test statistic, of running ``VarianceRatio`` on ``y`` in ``fit`` + pvalue_ : float : float + p-value obtained when running ``VarianceRatio`` on ``y`` in ``fit`` + usedlag_ : int + The number of lags used in the test. + + Examples + -------- + >>> from sktime.datasets import load_airline + >>> from sktime.param_est.stationarity import StationarityVarianceRatio + >>> + >>> X = load_airline() # doctest: +SKIP + >>> sty_est = StationarityVarianceRatio() # doctest: +SKIP + >>> sty_est.fit(X) # doctest: +SKIP + StationarityVarianceRatio(...) + >>> sty_est.get_fitted_params()["stationary"] # doctest: +SKIP + True + """ + + _tags = { + "authors": ["Vasudeva-bit"], + "maintainers": ["Vasudeva-bit"], + "X_inner_mtype": ["pd.Series", "np.ndarray"], + "scitype:X": "Series", + "python_dependencies": "arch", + } + + def __init__( + self, + lags=2, + trend="c", + overlap=True, + robust=True, + debiased=True, + p_threshold=0.05, + ): + self.lags = lags + self.trend = trend + self.overlap = overlap + self.robust = robust + self.debiased = debiased + self.p_threshold = p_threshold + super().__init__() + + def _fit(self, X): + """Fit estimator and estimate parameters. + + private _fit containing the core logic, called from fit + + Writes to self: + Sets fitted model attributes ending in "_". + + Parameters + ---------- + X : {ndarray, Series} + The data to test for a unit root + + Returns + ------- + self : reference to self + """ + from arch.unitroot import VarianceRatio + + p_threshold = self.p_threshold + + result = VarianceRatio( + y=X, + lags=self.lags, + trend=self.trend, + overlap=self.overlap, + robust=self.robust, + debiased=self.debiased, + ) + self.test_statistic_ = result.stat + self.pvalue = result.pvalue + self.stationary_ = result.pvalue > p_threshold + self.used_lag_ = result._lags + + return self + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + There are no reserved values for parameter estimators. + + Returns + ------- + params : dict or list of dict, default = {} + Parameters to create testing instances of the class + Each dict are parameters to construct an "interesting" test instance, i.e., + `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. + `create_test_instance` uses the first (or only) dictionary in `params` + """ + params1 = {} + params2 = { + "lags": 5, + "overlap": False, + "robust": False, + "debiased": False, + "p_threshold": 0.1, + } + + return [params1, params2] diff --git a/sktime/param_est/stationarity.py b/sktime/param_est/stationarity/_statsmodels.py similarity index 90% rename from sktime/param_est/stationarity.py rename to sktime/param_est/stationarity/_statsmodels.py index 8eef716134d..49523100568 100644 --- a/sktime/param_est/stationarity.py +++ b/sktime/param_est/stationarity/_statsmodels.py @@ -2,7 +2,10 @@ """Parameter estimators for stationarity.""" __author__ = ["fkiraly"] -__all__ = ["StationarityADF", "StationarityKPSS"] +__all__ = [ + "StationarityADF", + "StationarityKPSS", +] from sktime.param_est.base import BaseParamFitter @@ -10,7 +13,7 @@ class StationarityADF(BaseParamFitter): """Test for stationarity via the Augmented Dickey-Fuller Unit Root Test (ADF). - Uses `statsmodels.tsa.stattools.adfuller` as a test for unit roots, + Uses ``statsmodels.tsa.stattools.adfuller`` as a test for unit roots, and derives a boolean statement whether a series is stationary. Also returns test results for the unit root test as fitted parameters. @@ -43,13 +46,14 @@ class StationarityADF(BaseParamFitter): Attributes ---------- - stationary_ : bool, whether the series in `fit` is stationary according to the test - more precisely, whether the null of the ADF test is rejected at `p_threshold` + stationary_ : bool + whether the series in ``fit`` is stationary according to the test + more precisely, whether the null of the ADF test is rejected at ``p_threshold`` test_statistic_ : float - The ADF test statistic, of running `adfuller` on `y` in `fit` + The ADF test statistic, of running ``adfuller`` on ``y`` in ``fit`` pvalue_ : float : float MacKinnon's approximate p-value based on MacKinnon (1994, 2010), - obtained when running `adfuller` on `y` in `fit` + obtained when running `adfuller` on ``y`` in ``fit`` usedlag_ : int The number of lags used in the test. @@ -62,11 +66,12 @@ class StationarityADF(BaseParamFitter): >>> sty_est = StationarityADF() # doctest: +SKIP >>> sty_est.fit(X) # doctest: +SKIP StationarityADF(...) - >>> sp_est.get_fitted_params()["stationary"] # doctest: +SKIP + >>> sty_est.get_fitted_params()["stationary"] # doctest: +SKIP False """ _tags = { + "authors": "fkiraly", "X_inner_mtype": "pd.Series", # which types do _fit/_predict, support for X? "scitype:X": "Series", # which X scitypes are supported natively? "capability:missing_values": False, # can estimator handle missing data? @@ -154,7 +159,7 @@ def get_test_params(cls, parameter_set="default"): class StationarityKPSS(BaseParamFitter): """Test for stationarity via the Kwiatkowski-Phillips-Schmidt-Shin Test. - Uses `statsmodels.tsa.stattools.kpss` as a test for trend-stationairty, + Uses ``statsmodels.tsa.stattools.kpss`` as a test for trend-stationarity, and derives a boolean statement whether a series is (trend-)stationary. Also returns test results for the trend-stationarity test as fitted parameters. @@ -180,12 +185,13 @@ class StationarityKPSS(BaseParamFitter): Attributes ---------- - stationary_ : bool, whether the series in `fit` is stationary according to the test - more precisely, whether the null of the KPSS test is accepted at `p_threshold` + stationary_ : bool + whether the series in ``fit`` is stationary according to the test + more precisely, whether the null of the KPSS test is accepted at ``p_threshold`` test_statistic_ : float - The KPSS test statistic, of running `kpss` on `y` in `fit` + The KPSS test statistic, of running ``kpss`` on ``y`` in ``fit`` pvalue_ : float : float - The p-value of the KPSS test, of running `kpss` on `y` in `fit`. + The p-value of the KPSS test, of running ``kpss`` on ``y`` in ``fit``. The p-value is interpolated from Table 1 in Kwiatkowski et al. (1992), and a boundary point is returned if the test statistic is outside the table of critical values, that is, if the p-value is outside the interval (0.01, 0.1). @@ -201,11 +207,12 @@ class StationarityKPSS(BaseParamFitter): >>> sty_est = StationarityKPSS() # doctest: +SKIP >>> sty_est.fit(X) # doctest: +SKIP StationarityKPSS(...) - >>> sp_est.get_fitted_params()["stationary"] # doctest: +SKIP + >>> sty_est.get_fitted_params()["stationary"] # doctest: +SKIP False """ _tags = { + "authors": "fkiraly", "X_inner_mtype": "pd.Series", # which types do _fit/_predict, support for X? "scitype:X": "Series", # which X scitypes are supported natively? "capability:missing_values": False, # can estimator handle missing data? diff --git a/sktime/performance_metrics/base/_base.py b/sktime/performance_metrics/base/_base.py index cc90b1cca02..8d2840b8960 100644 --- a/sktime/performance_metrics/base/_base.py +++ b/sktime/performance_metrics/base/_base.py @@ -13,7 +13,11 @@ class BaseMetric(BaseObject): Extends sktime BaseObject. """ - _tags = {"object_type": "metric"} + _tags = { + "object_type": "metric", + "authors": "sktime developers", # author(s) of the object + "maintainers": "sktime developers", # current maintainer(s) of the object + } def __init__(self): super().__init__() diff --git a/sktime/performance_metrics/forecasting/_classes.py b/sktime/performance_metrics/forecasting/_classes.py index 08d3313837f..9e4eec76ddb 100644 --- a/sktime/performance_metrics/forecasting/_classes.py +++ b/sktime/performance_metrics/forecasting/_classes.py @@ -273,12 +273,17 @@ def _evaluate_vectorized(self, y_true, y_pred, **kwargs): y_pred : VectorizedDF non-time-like instances of y_true, y_pred must be identical """ + backend = dict() + backend["backend"] = self.get_config()["backend:parallel"] + backend["backend_params"] = self.get_config()["backend:parallel:params"] + eval_result = y_true.vectorize_est( estimator=self.clone(), method="_evaluate", varname_of_self="y_true", args={**kwargs, "y_pred": y_pred}, colname_default=self.name, + **backend, ) if isinstance(self.multioutput, str) and self.multioutput == "raw_values": @@ -305,6 +310,10 @@ def _evaluate_by_index_vectorized(self, y_true, y_pred, **kwargs): y_pred : VectorizedDF non-time-like instances of y_true, y_pred must be identical """ + backend = dict() + backend["backend"] = self.get_config()["backend:parallel"] + backend["backend_params"] = self.get_config()["backend:parallel:params"] + eval_result = y_true.vectorize_est( estimator=self.clone().set_params(**{"multilevel": "uniform_average"}), method="_evaluate_by_index", @@ -312,6 +321,7 @@ def _evaluate_by_index_vectorized(self, y_true, y_pred, **kwargs): args={**kwargs, "y_pred": y_pred}, colname_default=self.name, return_type="list", + **backend, ) eval_result = y_true.reconstruct(eval_result) @@ -573,6 +583,10 @@ def _evaluate(self, y_true, y_pred, **kwargs): else: func = self.func + return self._evaluate_func(func=func, y_true=y_true, y_pred=y_pred, **params) + + def _evaluate_func(self, func, y_true, y_pred, **params): + """Call func with kwargs subset to func parameters.""" # import here for now to avoid interaction with getmembers in tests # todo: clean up ancient getmembers in test_metrics_classes from functools import partial @@ -584,6 +598,15 @@ def _evaluate(self, y_true, y_pred, **kwargs): func_params = func_params.intersection(params.keys()) params = {key: params[key] for key in func_params} + # deal with sklearn specific parameter constraints + # as these are a decorator, they obfuscate python native inspection + # via signature, so have to be dealt with separately + if hasattr(func, "_skl_parameter_constraints"): + constr = func._skl_parameter_constraints + if isinstance(constr, dict): + constr_params = set(constr.keys()).intersection(params.keys()) + params = {key: params[key] for key in constr_params} + res = func(y_true=y_true, y_pred=y_pred, **params) return res @@ -609,6 +632,16 @@ def __init__( self.set_tags(**{"lower_is_better": lower_is_better}) + def _evaluate(self, y_true, y_pred, **kwargs): + """Evaluate the desired metric on given inputs.""" + # this dict should contain all parameters + params = kwargs + params.update({"multioutput": self.multioutput, "multilevel": self.multilevel}) + + func = self.func + + return self._evaluate_func(func=func, y_true=y_true, y_pred=y_pred, **params) + @classmethod def get_test_params(cls, parameter_set="default"): """Return testing parameter settings for the estimator. @@ -1830,6 +1863,56 @@ def __init__( self.symmetric = symmetric super().__init__(multioutput=multioutput, multilevel=multilevel) + def _evaluate_by_index(self, y_true, y_pred, **kwargs): + """Return the metric evaluated at each time point. + + private _evaluate_by_index containing core logic, called from evaluate_by_index + + Parameters + ---------- + y_true : time series in sktime compatible pandas based data container format + Ground truth (correct) target values + y can be in one of the following formats: + Series scitype: pd.DataFrame + Panel scitype: pd.DataFrame with 2-level row MultiIndex + Hierarchical scitype: pd.DataFrame with 3 or more level row MultiIndex + y_pred :time series in sktime compatible data container format + Forecasted values to evaluate + must be of same format as y_true, same indices and columns if indexed + + Returns + ------- + loss : pd.Series or pd.DataFrame + Calculated metric, by time point (default=jackknife pseudo-values). + pd.Series if self.multioutput="uniform_average" or array-like + index is equal to index of y_true + entry at index i is metric at time i, averaged over variables + pd.DataFrame if self.multioutput="raw_values" + index and columns equal to those of y_true + i,j-th entry is metric at time i, at variable j + """ + multioutput = self.multioutput + symmetric = self.symmetric + + numer_values = (y_true - y_pred).abs() + + if symmetric: + denom_values = (y_true.abs() + y_pred.abs()) / 2 + else: + denom_values = y_true.abs() + + raw_values = numer_values / denom_values + + if isinstance(multioutput, str): + if multioutput == "raw_values": + return raw_values + + if multioutput == "uniform_average": + return raw_values.mean(axis=1) + + # else, we expect multioutput to be array-like + return raw_values.dot(multioutput) + @classmethod def get_test_params(cls, parameter_set="default"): """Return testing parameter settings for the estimator. diff --git a/sktime/performance_metrics/forecasting/_functions.py b/sktime/performance_metrics/forecasting/_functions.py index 67742950c25..2e8966be22e 100644 --- a/sktime/performance_metrics/forecasting/_functions.py +++ b/sktime/performance_metrics/forecasting/_functions.py @@ -8,6 +8,7 @@ """ import numpy as np +import sklearn from scipy.stats import gmean from sklearn.metrics import mean_absolute_error as _mean_absolute_error from sklearn.metrics import mean_squared_error as _mean_squared_error @@ -18,6 +19,9 @@ from sktime.utils.stats import _weighted_geometric_mean +if sklearn.__version__ >= "1.4.0": + from sklearn.metrics import root_mean_squared_error as _root_mean_squared_error + __author__ = ["mloning", "tch", "RNKuhns"] __all__ = [ "relative_loss", @@ -998,18 +1002,24 @@ def mean_squared_error( >>> mean_squared_error(y_true, y_pred, multioutput=[0.3, 0.7], square_root=True) 0.8936491673103708 """ - # Scikit-learn argument `squared` returns MSE when True and RMSE when False - # Scikit-time argument `square_root` returns RMSE when True and MSE when False - # Therefore need to pass the opposite of square_root as squared argument - # to the scikit-learn function being wrapped - squared = not square_root - return _mean_squared_error( - y_true, - y_pred, - sample_weight=horizon_weight, - multioutput=multioutput, - squared=squared, - ) + metric_args = (y_true, y_pred) + metric_kwargs = {"sample_weight": horizon_weight, "multioutput": multioutput} + + if not square_root: + metric_function = _mean_squared_error + elif sklearn.__version__ < "1.4.0": + # Scikit-learn argument `squared` returns MSE when True and RMSE when False + # Scikit-time argument `square_root` returns RMSE when True and MSE when False + # Therefore need to pass the opposite of square_root as squared argument + # to the scikit-learn function being wrapped + metric_function = _mean_squared_error + metric_kwargs["squared"] = False + else: + # sklearn 1.4 introduced ``root_mean_squared_error`` function, so we can + # use that directly to avoid DeprecationWarning from sklearn 1.6 + metric_function = _root_mean_squared_error + + return metric_function(*metric_args, **metric_kwargs) def median_absolute_error( diff --git a/sktime/performance_metrics/forecasting/probabilistic/_classes.py b/sktime/performance_metrics/forecasting/probabilistic/_classes.py index 2c6d07223c1..9208d73c318 100644 --- a/sktime/performance_metrics/forecasting/probabilistic/_classes.py +++ b/sktime/performance_metrics/forecasting/probabilistic/_classes.py @@ -119,16 +119,16 @@ def evaluate(self, y_true, y_pred, multioutput=None, **kwargs): if isinstance(multioutput, str): if self.score_average and multioutput == "uniform_average": - out = float(out.mean(axis=1).iloc[0]) # average over all + out = out.mean(axis=1).iloc[0] # average over all if self.score_average and multioutput == "raw_values": - out = out.groupby(axis=1, level=0).mean() # average over scores + out = out.T.groupby(level=0).mean().T # average over scores if not self.score_average and multioutput == "uniform_average": - out = out.groupby(axis=1, level=1).mean() # average over variables + out = out.T.groupby(level=1).mean().T # average over variables if not self.score_average and multioutput == "raw_values": out = out # don't average else: # is np.array with weights if self.score_average: - out_raw = out.groupby(axis=1, level=0).mean() + out_raw = out.T.groupby(level=0).mean().T out = out_raw.dot(multioutput)[0] else: out = _groupby_dot(out, multioutput) @@ -215,14 +215,14 @@ def evaluate_by_index(self, y_true, y_pred, multioutput=None, **kwargs): if self.score_average and multioutput == "uniform_average": out = out.mean(axis=1) # average over all if self.score_average and multioutput == "raw_values": - out = out.groupby(axis=1, level=0).mean() # average over scores + out = out.T.groupby(level=0).mean().T # average over scores if not self.score_average and multioutput == "uniform_average": - out = out.groupby(axis=1, level=1).mean() # average over variables + out = out.T.groupby(level=1).mean().T # average over variables if not self.score_average and multioutput == "raw_values": out = out # don't average else: # numpy array if self.score_average: - out_raw = out.groupby(axis=1, level=0).mean() + out_raw = out.T.groupby(level=0).mean().T out = out_raw.dot(multioutput) else: out = _groupby_dot(out, multioutput) diff --git a/sktime/performance_metrics/forecasting/tests/test_metrics.py b/sktime/performance_metrics/forecasting/tests/test_metrics.py index 1b2d07c4fcd..12f9709bf8f 100644 --- a/sktime/performance_metrics/forecasting/tests/test_metrics.py +++ b/sktime/performance_metrics/forecasting/tests/test_metrics.py @@ -129,3 +129,18 @@ def test_make_scorer(): scorer = make_forecasting_scorer(rmsle, name="RMSLE") scorer.evaluate(pd.Series([1, 2, 3]), pd.Series([1, 2, 4])) + + +def test_make_scorer_sklearn(): + """Test make_forecasting_scorer and the failure case in #5715. + + Naive adaptation fails on newer sklearn versions due to + decoration with sklearn's custom input constraint wrapper. + """ + from sklearn.metrics import mean_absolute_error + + from sktime.performance_metrics.forecasting import make_forecasting_scorer + + scorer = make_forecasting_scorer(mean_absolute_error, name="RMSLE") + + scorer.evaluate(pd.Series([1, 2, 3]), pd.Series([1, 2, 4])) diff --git a/sktime/performance_metrics/tests/test_metrics_classes.py b/sktime/performance_metrics/tests/test_metrics_classes.py index 1b5d8a6aeab..1eeda271982 100644 --- a/sktime/performance_metrics/tests/test_metrics_classes.py +++ b/sktime/performance_metrics/tests/test_metrics_classes.py @@ -14,6 +14,7 @@ from sktime.utils._testing.hierarchical import _make_hierarchical from sktime.utils._testing.panel import _make_panel from sktime.utils._testing.series import _make_series +from sktime.utils.parallel import _get_parallel_test_fixtures metric_classes = getmembers(_classes, isclass) @@ -24,6 +25,9 @@ MULTIOUTPUT = ["uniform_average", "raw_values", "numpy"] +# list of parallelization backends to test +BACKENDS = _get_parallel_test_fixtures("config") + @pytest.mark.parametrize("n_columns", [1, 2]) @pytest.mark.parametrize("multioutput", MULTIOUTPUT) @@ -76,12 +80,13 @@ def test_metric_output_direct(metric, multioutput, n_columns): assert np.allclose(res[1], res[2]) +@pytest.mark.parametrize("backend", BACKENDS) @pytest.mark.parametrize("n_columns", [1, 2]) @pytest.mark.parametrize( "multilevel", ["uniform_average", "uniform_average_time", "raw_values"] ) @pytest.mark.parametrize("multioutput", MULTIOUTPUT) -def test_metric_hierarchical(multioutput, multilevel, n_columns): +def test_metric_hierarchical(multioutput, multilevel, n_columns, backend): """Test hierarchical input for metrics.""" # create numpy weights based on n_columns if multioutput == "numpy": @@ -94,6 +99,7 @@ def test_metric_hierarchical(multioutput, multilevel, n_columns): y_true = _make_hierarchical(random_state=42, n_columns=n_columns) metric = MeanSquaredError(multioutput=multioutput, multilevel=multilevel) + metric.set_config(**backend) res = metric( y_true=y_true, @@ -183,10 +189,11 @@ def test_metric_output_by_instance(metric, multioutput, n_columns): assert (res.index == y_true.index).all() +@pytest.mark.parametrize("backend", BACKENDS) @pytest.mark.parametrize("n_columns", [1, 2]) @pytest.mark.parametrize("multilevel", ["uniform_average", "raw_values"]) @pytest.mark.parametrize("multioutput", MULTIOUTPUT) -def test_metric_hierarchical_by_index(multioutput, multilevel, n_columns): +def test_metric_hierarchical_by_index(multioutput, multilevel, n_columns, backend): """Test hierarchical input for metrics.""" # create numpy weights based on n_columns if multioutput == "numpy": @@ -199,6 +206,7 @@ def test_metric_hierarchical_by_index(multioutput, multilevel, n_columns): y_true = _make_hierarchical(random_state=42, n_columns=n_columns) metric = MeanSquaredError(multioutput=multioutput, multilevel=multilevel) + metric.set_config(**backend) res = metric.evaluate_by_index( y_true=y_true, diff --git a/sktime/pipeline/pipeline.py b/sktime/pipeline/pipeline.py index 94a243a8131..8f23b6cb009 100644 --- a/sktime/pipeline/pipeline.py +++ b/sktime/pipeline/pipeline.py @@ -1,6 +1,5 @@ """class that implements a graph pipeline.""" import warnings -import weakref from copy import copy, deepcopy from sktime.base import BaseEstimator @@ -183,6 +182,17 @@ def __init__(self, steps=None): self.steps = steps self._steps = steps if steps is not None else [] + object_types = [step["skobject"].get_tag("object_type") for step in self._steps] + if len(set(object_types)) == 1: + self.set_tags(**{"object_type": object_types[0]}) + elif len(set(object_types) - {"transformer"}) == 1: + self.set_tags( + **{"object_type": list(set(object_types) - {"transformer"})[0]} + ) + else: + # Mixture of different object types + pass + for step_information in self._steps: if "method" not in step_information: step_information["method"] = None @@ -194,12 +204,10 @@ def _get_unique_id(self, skobject): self.counter += 1 # Check if not already an skobject cloned from the provided # skobject is part of the pipeline - if (id(skobject) not in self.id_to_obj) or self.id_to_obj[ - id(skobject) - ]() is None: - # In this case set a weakref of that skobject to id_to_obj to prevent that + if id(skobject) not in self.id_to_obj: + # In this case store that skobject to id_to_obj to prevent that # the garbage collector reassigns the id. - self.id_to_obj[id(skobject)] = weakref.ref(skobject) + self.id_to_obj[id(skobject)] = skobject self.id_to_true_id[id(skobject)] = self.counter return self.id_to_true_id[id(skobject)] @@ -358,7 +366,7 @@ def _assemble_steps(self): self._last_step_name = name self._assembled = True - def fit(self, X, y=None, **kwargs): + def fit(self, X=None, y=None, **kwargs): """Fit graph pipeline to training data. Parameters @@ -377,6 +385,8 @@ def fit(self, X, y=None, **kwargs): """ self._assembled = False self._initiate_call(X, y, kwargs) + + assert (X is not None) or (y is not None), "Either X or y must be provided." self._y = y self._X = X @@ -452,7 +462,7 @@ def transform(self, X, y=None, **kwargs): .result ) - def predict(self, X, y=None, **kwargs): + def predict(self, X=None, y=None, **kwargs): """Perform a prediction. I.e. calls predict or transform on each element in the graph pipeline. @@ -588,10 +598,18 @@ def predict_residuals(self, X, y=None, **kwargs): def _initiate_call(self, X, y, kwargs): if not self._assembled: self._assemble_steps() - for step in self.assembled_steps.values(): - step.reset() - self.assembled_steps["X"].buffer = X - self.assembled_steps["y"].buffer = y + for key, step in self.assembled_steps.items(): + # Empty the buffer of all steps except for the dummy + # steps X and y (input steps) + if key in ["X", "y"]: + step.reset(reset_buffer=False) + else: + step.reset() + # Overwrite the buffer of X and y if data are provided + if X is not None: + self.assembled_steps["X"].buffer = X + if y is not None: + self.assembled_steps["y"].buffer = y self.kwargs.update(kwargs) def _method_allowed(self, method): @@ -620,3 +638,72 @@ def _create_subsetter(self, edg): params={}, ) self.assembled_steps[edg] = step + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + There are currently no reserved values for forecasters. + + Returns + ------- + params : dict or list of dict, default = {} + Parameters to create testing instances of the class + Each dict are parameters to construct an "interesting" test instance, i.e., + `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. + `create_test_instance` uses the first (or only) dictionary in `params` + """ + from sktime.classification.distance_based import KNeighborsTimeSeriesClassifier + from sktime.forecasting.naive import NaiveForecaster + from sktime.transformations.series.boxcox import BoxCoxTransformer + from sktime.transformations.series.exponent import ExponentTransformer + + return [ + { + "steps": [ + { + "skobject": ExponentTransformer(), + "name": "exp", + "edges": {"X": "X"}, + }, + { + "skobject": BoxCoxTransformer(), + "name": "box", + "edges": {"X": "exp"}, + }, + ] + }, + { + "steps": [ + { + "skobject": ExponentTransformer(), + "name": "exp", + "edges": {"X": "X"}, + }, + { + "skobject": KNeighborsTimeSeriesClassifier(), + "name": "knnclassifier", + "edges": {"X": "exp", "y": "y"}, + }, + ] + }, + { + "steps": [ + { + "skobject": ExponentTransformer(), + "name": "exp", + "edges": {"X": "y"}, + }, + { + "skobject": NaiveForecaster(), + "name": "naive", + "edges": {"X": "exp", "y": "y"}, + }, + ] + }, + ] diff --git a/sktime/pipeline/step.py b/sktime/pipeline/step.py index 0810d422db0..01d2274f075 100644 --- a/sktime/pipeline/step.py +++ b/sktime/pipeline/step.py @@ -73,9 +73,10 @@ def __init__( self.input_edges = input_edges self.params = params - def reset(self): + def reset(self, reset_buffer=True): """Reset the step.""" - self.buffer = None + if reset_buffer: + self.buffer = None self.mode = "" def get_allowed_method(self): @@ -212,7 +213,7 @@ def _fetch_input_data(self, fit, required_method, mro, kwargs): self.mode = result.mode if result.result is not None: all_none = False - if len(results) != 0 and not results[0] is None: + if len(results) != 0 and results[0] is not None: if len(results) > 1: input_data[step_name] = pd.concat( results, axis=1, keys=transformer_names diff --git a/sktime/pipeline/tests/regression_tests/test_pipeline_regression.py b/sktime/pipeline/tests/regression_tests/test_pipeline_regression.py index e32b398d1ce..c555139edd8 100644 --- a/sktime/pipeline/tests/regression_tests/test_pipeline_regression.py +++ b/sktime/pipeline/tests/regression_tests/test_pipeline_regression.py @@ -2,10 +2,11 @@ import pandas as pd import pytest from skbase.utils.dependencies import _check_soft_dependencies +from sklearn.linear_model import Ridge from sktime.classification.dummy import DummyClassifier -from sktime.datasets import load_arrow_head, load_longley -from sktime.forecasting.compose import ForecastX +from sktime.datasets import load_airline, load_arrow_head, load_longley +from sktime.forecasting.compose import ForecastX, make_reduction from sktime.forecasting.naive import NaiveForecaster from sktime.forecasting.sarimax import SARIMAX from sktime.pipeline.pipeline import Pipeline @@ -317,3 +318,20 @@ def test_forecasterX_regression(): general_pipeline.fit(y=y, X=X, fh=[1, 2, 3]) result_general = general_pipeline.predict(None, None) pd.testing.assert_series_equal(result, result_general) + + +def test_lagged_y_prediction(): + # regression test for issue 5830 + y = load_airline() + y_train, y_test = temporal_train_test_split(y) + + forecaster = make_reduction(Ridge(), window_length=12, strategy="recursive") + + pipe = Pipeline() + pipe = pipe.add_step(Differencer(lags=[1, 3]), "differencer", edges={"X": "y"}) + pipe = pipe.add_step( + forecaster, name="forecaster", edges={"X": "differencer", "y": "y"} + ) + pipe.fit(y=y_train) + y_pred = pipe.predict(fh=y_test.index) + assert y_pred.shape == y_test.shape diff --git a/sktime/proba/base.py b/sktime/proba/base.py index 11ca9f97313..06d7550e9f6 100644 --- a/sktime/proba/base.py +++ b/sktime/proba/base.py @@ -11,6 +11,7 @@ import pandas as pd from sktime.base import BaseObject +from sktime.utils.pandas import df_map from sktime.utils.validation._dependencies import _check_estimator_deps @@ -19,15 +20,23 @@ class BaseDistribution(BaseObject): # default tag values - these typically make the "safest" assumption _tags = { + # packaging info + # -------------- + "authors": "sktime developers", # author(s) of the object + "maintainers": "sktime developers", # current maintainer(s) of the object + "python_version": None, # PEP 440 python version specifier to limit versions + "python_dependencies": None, # str or list of str, package soft dependencies + # estimator type + # -------------- "object_type": "distribution", # type of object, e.g., 'distribution' "python_version": None, # PEP 440 python version specifier to limit versions - "python_dependencies": None, # string or str list of pkg soft dependencies "reserved_params": ["index", "columns"], "capabilities:approx": ["energy", "mean", "var", "pdfnorm"], "approx_mean_spl": 1000, # sample size used in MC estimates of mean "approx_var_spl": 1000, # sample size used in MC estimates of var "approx_energy_spl": 1000, # sample size used in MC estimates of energy "approx_spl": 1000, # sample size used in other MC estimates + "bisect_iter": 1000, # max iters for bisection method in ppf } def __init__(self, index=None, columns=None): @@ -41,15 +50,15 @@ def __init__(self, index=None, columns=None): def loc(self): """Location indexer. - Use `my_distribution.loc[index]` for `pandas`-like row/column subsetting of - `BaseDistribution` descendants. + Use `my_distribution.loc[index]` for `pandas`-like row/column subsetting + of `BaseDistribution` descendants. `index` can be any `pandas` `loc` compatible index subsetter. `my_distribution.loc[index]` or `my_distribution.loc[row_index, col_index]` - subset `my_distribution` to rows defined by `row_index`, cols by `col_index`, to - exactly the same/cols rows as `pandas` `loc` would subset rows in - `my_distribution.index` and columns in `my_distribution.columns`. + subset `my_distribution` to rows defined by `row_index`, cols by `col_index`, + to exactly the same/cols rows as `pandas` `loc` would subset + rows in `my_distribution.index` and columns in `my_distribution.columns`. """ return _Indexer(ref=self, method="_loc") @@ -57,15 +66,15 @@ def loc(self): def iloc(self): """Integer location indexer. - Use `my_distribution.iloc[index]` for `pandas`-like row/column subsetting of - `BaseDistribution` descendants. + Use `my_distribution.iloc[index]` for `pandas`-like row/column subsetting + of `BaseDistribution` descendants. `index` can be any `pandas` `iloc` compatible index subsetter. `my_distribution.iloc[index]` or `my_distribution.iloc[row_index, col_index]` - subset `my_distribution` to rows defined by `row_index`, cols by `col_index`, to - exactly the same/cols rows as `pandas` `iloc` would subset rows in - `my_distribution.index` and columns in `my_distribution.columns`. + subset `my_distribution` to rows defined by `row_index`, cols by `col_index`, + to exactly the same/cols rows as `pandas` `iloc` would subset + rows in `my_distribution.index` and columns in `my_distribution.columns`. """ return _Indexer(ref=self, method="_iloc") @@ -90,9 +99,12 @@ def _subset_params(self, rowidx, colidx): subset_param_dict = {} for param, val in params.items(): - arr = np.array(val) - if len(arr.shape) == 0: - subset_param_dict + if val is not None: + arr = np.array(val) + else: + arr = None + # if len(arr.shape) == 0: + # do nothing with arr if len(arr.shape) >= 1 and rowidx is not None: arr = arr[rowidx] if len(arr.shape) >= 2 and colidx is not None: @@ -225,7 +237,7 @@ def pdf(self, x): "this may be numerically unstable" ) warn(self._method_error_msg("pdf", fill_in=approx_method)) - return self.log_pdf(x=x).applymap(np.exp) + return df_map(self.log_pdf(x=x))(np.exp) raise NotImplementedError(self._method_error_msg("pdf", "error")) @@ -265,7 +277,7 @@ def log_pdf(self, x): ) warn(self._method_error_msg("log_pdf", fill_in=approx_method)) - return self.pdf(x=x).applymap(np.log) + return df_map(self.pdf(x=x))(np.log) raise NotImplementedError(self._method_error_msg("log_pdf", "error")) @@ -282,10 +294,42 @@ def cdf(self, x): spl = self.sample(N) ind = splx <= spl - return ind.groupby(level=1).mean() + return ind.groupby(level=1, sort=False).mean() def ppf(self, p): """Quantile function = percent point function = inverse cdf.""" + if self._has_implementation_of("cdf"): + from scipy.optimize import bisect + + max_iter = self.get_tag("bisect_iter") + approx_method = ( + "by using the bisection method (scipy.optimize.bisect) on " + f"the cdf, at {max_iter} maximum iterations" + ) + warn(self._method_error_msg("cdf", fill_in=approx_method)) + + result = pd.DataFrame(index=p.index, columns=p.columns, dtype="float") + for ix in p.index: + for col in p.columns: + d_ix = self.loc[[ix], [col]] + p_ix = p.loc[ix, col] + + def opt_fun(x): + """Optimization function, to find x s.t. cdf(x) = p_ix.""" + x = pd.DataFrame(x, index=[ix], columns=[col]) # noqa: B023 + return d_ix.cdf(x).values[0][0] - p_ix # noqa: B023 + + left_bd = -1e6 + right_bd = 1e6 + while opt_fun(left_bd) > 0: + left_bd *= 10 + while opt_fun(right_bd) < 0: + right_bd *= 10 + result.loc[ix, col] = bisect( + opt_fun, left_bd, right_bd, maxiter=max_iter + ) + return result + raise NotImplementedError(self._method_error_msg("ppf", "error")) def energy(self, x=None): @@ -330,7 +374,8 @@ def energy(self, x=None): # approx E[abs(X-Y)] via mean of samples of abs(X-Y) obtained from splx, sply spl = splx - sply - energy = spl.apply(np.linalg.norm, axis=1, ord=1).groupby(level=1).mean() + energy = spl.apply(np.linalg.norm, axis=1, ord=1) + energy = energy.groupby(level=1, sort=False).mean() energy = pd.DataFrame(energy, index=self.index, columns=["energy"]) return energy @@ -353,7 +398,7 @@ def mean(self): warn(self._method_error_msg("mean", fill_in=approx_method)) spl = self.sample(approx_spl_size) - return spl.groupby(level=1).mean() + return spl.groupby(level=1, sort=False).mean() def var(self): r"""Return element/entry-wise variance of the distribution. @@ -376,10 +421,10 @@ def var(self): spl1 = self.sample(approx_spl_size) spl2 = self.sample(approx_spl_size) spl = (spl1 - spl2) ** 2 - return spl.groupby(level=1).mean() + return spl.groupby(level=1, sort=False).mean() def pdfnorm(self, a=2): - r"""A-norm of pdf, defaults to 2-norm. + r"""a-norm of pdf, defaults to 2-norm. computes a-norm of the entry marginal pdf, i.e., :math:`\mathbb{E}[p_X(X)^{a-1}] = \int p(x)^a dx`, @@ -408,7 +453,7 @@ def pdfnorm(self, a=2): # uses formula int p(x)^a dx = E[p(X)^{a-1}], and MC approximates the RHS spl = [self.pdf(self.sample()) ** (a - 1) for _ in range(approx_spl_size)] - return pd.concat(spl, axis=0).groupby(level=1).mean() + return pd.concat(spl, axis=0).groupby(level=1, sort=False).mean() def _coerce_to_self_index_df(self, x): x = np.array(x) @@ -430,7 +475,7 @@ def quantile(self, alpha): The `ppf` method also computes quantiles, but broadcasts differently, in `numpy` style closer to `tensorflow`. In contrast, this `quantile` method broadcasts - as forecaster `predict_quantiles`, i.e., columns first. + as ``sktime`` forecaster `predict_quantiles`, i.e., columns first. Parameters ---------- diff --git a/sktime/proba/empirical.py b/sktime/proba/empirical.py index b19ab5f0e6d..dfb20a141ab 100644 --- a/sktime/proba/empirical.py +++ b/sktime/proba/empirical.py @@ -16,12 +16,12 @@ class Empirical(BaseDistribution): ---------- spl : pd.DataFrame with pd.MultiIndex empirical sample - last (highest) index is time, first (lowest) index is sample + last (highest) index is instance, first (lowest) index is sample weights : pd.Series, with same index and length as spl, optional, default=None if not passed, ``spl`` is assumed to be unweighted time_indep : bool, optional, default=True - if True, ``sample`` will sample individual time indices independently - if False, ``sample`` will sample etire instances from ``spl`` + if True, ``sample`` will sample individual instance indices independently + if False, ``sample`` will sample entire instances from ``spl`` index : pd.Index, optional, default = RangeIndex columns : pd.Index, optional, default = RangeIndex @@ -43,6 +43,7 @@ class Empirical(BaseDistribution): """ _tags = { + "authors": ["fkiraly"], "capabilities:approx": [], "capabilities:exact": ["mean", "var", "energy", "cdf", "ppf"], "distr:measuretype": "discrete", @@ -79,7 +80,6 @@ def _init_sorted(self): sorted = {} weights = {} - weights for t in times: sorted[t] = {} weights[t] = {} @@ -124,8 +124,42 @@ def _apply_per_ix(self, func, params, x=None): x_t = x.loc[ix, col] else: x_t = x - res.loc[ix, col] = func(spl=spl_t, weights=weights_t, x=x_t, **params) - return res.convert_dtypes() + res.at[ix, col] = func(spl=spl_t, weights=weights_t, x=x_t, **params) + return res.apply(pd.to_numeric) + + def _iloc(self, rowidx=None, colidx=None): + index = self.index + columns = self.columns + weights = self.weights + + spl_subset = self.spl + + if rowidx is not None: + rowidx_loc = index[rowidx] + # subset multiindex to rowidx by last level + spl_subset = self.spl.loc[(slice(None), rowidx_loc), :] + if weights is not None: + weights_subset = weights.loc[(slice(None), rowidx_loc)] + else: + weights_subset = None + subs_rowidx = index[rowidx] + else: + subs_rowidx = index + weights_subset = weights + + if colidx is not None: + spl_subset = spl_subset.iloc[:, colidx] + subs_colidx = columns[colidx] + else: + subs_colidx = columns + + return Empirical( + spl_subset, + weights=weights_subset, + time_indep=self.time_indep, + index=subs_rowidx, + columns=subs_colidx, + ) def energy(self, x=None): r"""Energy of self, w.r.t. self or a constant frame x. @@ -162,9 +196,9 @@ def mean(self): """ spl = self.spl if self.weights is None: - mean_df = spl.groupby(level=-1).mean() + mean_df = spl.groupby(level=-1, sort=False).mean() else: - mean_df = spl.groupby(level=-1).apply( + mean_df = spl.groupby(level=-1, sort=False).apply( lambda x: np.average(x, weights=self.weights.loc[x.index], axis=0) ) mean_df = pd.DataFrame(mean_df.tolist(), index=mean_df.index) @@ -186,11 +220,11 @@ def var(self): spl = self.spl N = self._N if self.weights is None: - var_df = spl.groupby(level=-1).var(ddof=0) + var_df = spl.groupby(level=-1, sort=False).var(ddof=0) else: mean = self.mean() means = pd.concat([mean] * N, axis=0, keys=self._spl_instances) - var_df = spl.groupby(level=-1).apply( + var_df = spl.groupby(level=-1, sort=False).apply( lambda x: np.average( (x - means.loc[x.index]) ** 2, weights=self.weights.loc[x.index], @@ -334,7 +368,7 @@ def _energy_np(spl, x=None, weights=None, assume_sorted=False): if x is None: cum_fwd = np.cumsum(weights[:-1]) - cum_back = np.cumsum(weights[1::-1])[::-1] + cum_back = np.cumsum(weights[1:][::-1])[::-1] energy = 2 * np.sum(cum_fwd * cum_back * spl_diff) else: spl_diff = np.abs(spl - x) diff --git a/sktime/proba/laplace.py b/sktime/proba/laplace.py index 8f8345c6162..11158d7abc1 100644 --- a/sktime/proba/laplace.py +++ b/sktime/proba/laplace.py @@ -29,6 +29,7 @@ class Laplace(BaseDistribution): """ _tags = { + "authors": ["fkiraly"], "capabilities:approx": ["pdfnorm"], "capabilities:exact": ["mean", "var", "energy", "pdf", "log_pdf", "cdf", "ppf"], "distr:measuretype": "continuous", @@ -43,7 +44,7 @@ def __init__(self, mu, scale, index=None, columns=None): # todo: untangle index handling # and broadcast of parameters. # move this functionality to the base class - self._mu, self._scale = self._get_bc_params() + self._mu, self._scale = self._get_bc_params(self.mu, self.scale) shape = self._mu.shape if index is None: @@ -54,16 +55,6 @@ def __init__(self, mu, scale, index=None, columns=None): super().__init__(index=index, columns=columns) - def _get_bc_params(self): - """Fully broadcast parameters of self, given param shapes and index, columns.""" - to_broadcast = [self.mu, self.scale] - if hasattr(self, "index") and self.index is not None: - to_broadcast += [self.index.to_numpy().reshape(-1, 1)] - if hasattr(self, "columns") and self.columns is not None: - to_broadcast += [self.columns.to_numpy()] - bc = np.broadcast_arrays(*to_broadcast) - return bc[0], bc[1] - def energy(self, x=None): r"""Energy of self, w.r.t. self or a constant frame x. diff --git a/sktime/proba/normal.py b/sktime/proba/normal.py index 6de59c06e33..8edbc5ac0a8 100644 --- a/sktime/proba/normal.py +++ b/sktime/proba/normal.py @@ -30,6 +30,7 @@ class Normal(BaseDistribution): """ _tags = { + "authors": ["fkiraly"], "capabilities:approx": ["pdfnorm"], "capabilities:exact": ["mean", "var", "energy", "pdf", "log_pdf", "cdf", "ppf"], "distr:measuretype": "continuous", @@ -44,7 +45,6 @@ def __init__(self, mu, sigma, index=None, columns=None): # todo: untangle index handling # and broadcast of parameters. # move this functionality to the base class - # 0.19.0? self._mu, self._sigma = self._get_bc_params(self.mu, self.sigma) shape = self._mu.shape diff --git a/sktime/proba/t.py b/sktime/proba/t.py index e273cbeecf6..c290f553fc3 100644 --- a/sktime/proba/t.py +++ b/sktime/proba/t.py @@ -32,6 +32,8 @@ class TDistribution(BaseDistribution): """ _tags = { + "authors": ["Alex-JG3"], + "maintainers": ["Alex-JG3"], "capabilities:approx": ["pdfnorm", "energy"], "capabilities:exact": ["mean", "var", "pdf", "log_pdf", "cdf", "ppf"], "distr:measuretype": "continuous", diff --git a/sktime/proba/tests/test_all_distrs.py b/sktime/proba/tests/test_all_distrs.py index 5808d9d2cbc..0a12fc98c70 100644 --- a/sktime/proba/tests/test_all_distrs.py +++ b/sktime/proba/tests/test_all_distrs.py @@ -1,7 +1,7 @@ # copyright: sktime developers, BSD-3-Clause License (see LICENSE file) """Tests for BaseDistribution API points.""" -__author__ = ["fkiraly"] +__author__ = ["fkiraly", "Alex-JG3"] import numpy as np import pandas as pd @@ -9,6 +9,7 @@ from sktime.datatypes import check_is_mtype from sktime.tests.test_all_estimators import BaseFixtureGenerator, QuickTester +from sktime.utils.index import random_ss_ix class DistributionFixtureGenerator(BaseFixtureGenerator): @@ -54,12 +55,16 @@ def _has_capability(distr, method): class TestAllDistributions(DistributionFixtureGenerator, QuickTester): - """Module level tests for all sktime parameter fitters.""" + """Module level tests for all sktime distributions.""" - def test_sample(self, estimator_instance): + @pytest.mark.parametrize("shuffled", [False, True]) + def test_sample(self, estimator_instance, shuffled): """Test sample expected return.""" d = estimator_instance + if shuffled: + d = _shuffle_distr(d) + res = d.sample() assert d.shape == res.shape @@ -72,36 +77,50 @@ def test_sample(self, estimator_instance): assert (res_panel.index == dummy_panel.index).all() assert (res_panel.columns == dummy_panel.columns).all() + @pytest.mark.parametrize("shuffled", [False, True]) @pytest.mark.parametrize("method", METHODS_SCALAR, ids=METHODS_SCALAR) - def test_methods_scalar(self, estimator_instance, method): + def test_methods_scalar(self, estimator_instance, method, shuffled): """Test expected return of scalar methods.""" if not _has_capability(estimator_instance, method): return None d = estimator_instance - res = getattr(estimator_instance, method)() + if shuffled: + d = _shuffle_distr(d) + + res = getattr(d, method)() _check_output_format(res, d, method) + @pytest.mark.parametrize("shuffled", [False, True]) @pytest.mark.parametrize("method", METHODS_X, ids=METHODS_X) - def test_methods_x(self, estimator_instance, method): + def test_methods_x(self, estimator_instance, method, shuffled): """Test expected return of methods that take sample-like argument.""" if not _has_capability(estimator_instance, method): return None d = estimator_instance + + if shuffled: + d = _shuffle_distr(d) + x = d.sample() - res = getattr(estimator_instance, method)(x) + res = getattr(d, method)(x) _check_output_format(res, d, method) + @pytest.mark.parametrize("shuffled", [False, True]) @pytest.mark.parametrize("method", METHODS_P, ids=METHODS_P) - def test_methods_p(self, estimator_instance, method): + def test_methods_p(self, estimator_instance, method, shuffled): """Test expected return of methods that take percentage-like argument.""" if not _has_capability(estimator_instance, method): return None d = estimator_instance + + if shuffled: + d = _shuffle_distr(d) + np_unif = np.random.uniform(size=d.shape) p = pd.DataFrame(np_unif, index=d.index, columns=d.columns) res = getattr(estimator_instance, method)(p) @@ -117,7 +136,9 @@ def test_quantile(self, estimator_instance, q): d = estimator_instance def _check_quantile_output(obj, q): - assert check_is_mtype(obj, "pred_quantiles", "Proba") + assert check_is_mtype( + obj, "pred_quantiles", "Proba", msg_return_dict="list" + ) assert (obj.index == d.index).all() if not isinstance(q, list): @@ -128,6 +149,63 @@ def _check_quantile_output(obj, q): res = d.quantile(q) _check_quantile_output(res, q) + @pytest.mark.parametrize("subset_row", [True, False]) + @pytest.mark.parametrize("subset_col", [True, False]) + def test_subsetting(self, estimator_instance, subset_row, subset_col): + """Test subsetting of distribution.""" + d = estimator_instance + + if subset_row: + ix_loc = random_ss_ix(d.index, 3) + ix_iloc = d.index.get_indexer(ix_loc) + else: + ix_loc = d.index + ix_iloc = pd.RangeIndex(len(d.index)) + + if subset_col: + iy_loc = random_ss_ix(d.columns, 1) + iy_iloc = d.columns.get_indexer(iy_loc) + else: + iy_loc = d.columns + iy_iloc = pd.RangeIndex(len(d.columns)) + + res_loc = d.loc[ix_loc, iy_loc] + + assert isinstance(res_loc, type(d)) + assert res_loc.shape == (len(ix_loc), len(iy_loc)) + assert (res_loc.index == ix_loc).all() + assert (res_loc.columns == iy_loc).all() + + res_iloc = d.iloc[ix_iloc, iy_iloc] + + assert isinstance(res_iloc, type(d)) + assert res_iloc.shape == (len(ix_iloc), len(iy_iloc)) + assert (res_iloc.index == ix_loc).all() + assert (res_iloc.columns == iy_loc).all() + + def test_log_pdf_and_pdf(self, estimator_instance): + """Test that the log of the pdf and log_pdf function are similar.""" + d = estimator_instance + capabilities_exact = d.get_tags()["capabilities:exact"] + + if "log_pdf" not in capabilities_exact or "pdf" not in capabilities_exact: + return + x = d.sample() + pdf = d.pdf(x) + log_pdf = d.log_pdf(x) + assert np.allclose(np.log(pdf), log_pdf) + + def test_ppf_and_cdf(self, estimator_instance): + """Test that the ppf is the inverse of the cdf.""" + d = estimator_instance + capabilities_exact = d.get_tags()["capabilities:exact"] + + if "ppf" not in capabilities_exact or "cdf" not in capabilities_exact: + return + x = d.sample() + x_approx = d.ppf(d.cdf(x)) + assert np.allclose(x.values, x_approx.values) + def _check_output_format(res, dist, method): """Check output format expectations for BaseDistribution tests.""" @@ -142,3 +220,16 @@ def _check_output_format(res, dist, method): if method in METHODS_SCALAR_POS or method in METHODS_X_POS: assert (res >= 0).all().all() + + if isinstance(res, pd.DataFrame): + assert res.apply(pd.api.types.is_numeric_dtype).all() + elif isinstance(res, pd.Series): + assert pd.api.types.is_numeric_dtype(res) + else: + raise TypeError("res must be a pandas DataFrame or Series.") + + +def _shuffle_distr(d): + """Shuffle distribution row index.""" + shuffled_index = pd.DataFrame(d.index).sample(frac=1).index + return d.loc[shuffled_index] diff --git a/sktime/proba/tfp.py b/sktime/proba/tfp.py index 3d363a2d236..9b3674c544a 100644 --- a/sktime/proba/tfp.py +++ b/sktime/proba/tfp.py @@ -30,6 +30,7 @@ class TFNormal(_BaseTFDistribution): """ _tags = { + "authors": ["fkiraly"], "python_dependencies": "tensorflow_probability", "capabilities:approx": ["pdfnorm"], "capabilities:exact": ["mean", "var", "energy", "pdf", "log_pdf", "cdf"], diff --git a/sktime/registry/_lookup.py b/sktime/registry/_lookup.py index aa0694c3c86..6c484d32096 100644 --- a/sktime/registry/_lookup.py +++ b/sktime/registry/_lookup.py @@ -62,35 +62,46 @@ def all_estimators( Which kind of estimators should be returned. if None, no filter is applied and all estimators are returned. if str or list of str, strings define scitypes specified in search - only estimators that are of (at least) one of the scitypes are returned - possible str values are entries of registry.BASE_CLASS_REGISTER (first col) - for instance 'classifier', 'regressor', 'transformer', 'forecaster' + only estimators that are of (at least) one of the scitypes are returned + possible str values are entries of registry.BASE_CLASS_REGISTER (first col) + for instance 'classifier', 'regressor', 'transformer', 'forecaster' + return_names: bool, optional (default=True) - if True, estimator class name is included in the all_estimators() - return in the order: name, estimator class, optional tags, either as - a tuple or as pandas.DataFrame columns - if False, estimator class name is removed from the all_estimators() - return. + + if True, estimator class name is included in the ``all_estimators`` + return in the order: name, estimator class, optional tags, either as + a tuple or as pandas.DataFrame columns + + if False, estimator class name is removed from the ``all_estimators`` return. + filter_tags: dict of (str or list of str), optional (default=None) For a list of valid tag strings, use the registry.all_tags utility. - subsets the returned estimators as follows: - each key/value pair is statement in "and"/conjunction - key is tag name to sub-set on - value str or list of string are tag values - condition is "key must be equal to value, or in set(value)" + + ``filter_tags`` subsets the returned estimators as follows: + + * each key/value pair is statement in "and"/conjunction + * key is tag name to sub-set on + * value str or list of string are tag values + * condition is "key must be equal to value, or in set(value)" + exclude_estimators: str, list of str, optional (default=None) Names of estimators to exclude. + as_dataframe: bool, optional (default=False) - if True, all_estimators will return a pandas.DataFrame with named - columns for all of the attributes being returned. - if False, all_estimators will return a list (either a list of - estimators or a list of tuples, see Returns) + + True: ``all_estimators`` will return a pandas.DataFrame with named + columns for all of the attributes being returned. + + False: ``all_estimators`` will return a list (either a list of + estimators or a list of tuples, see Returns) + return_tags: str or list of str, optional (default=None) Names of tags to fetch and return each estimator's value of. For a list of valid tag strings, use the registry.all_tags utility. if str or list of str, - the tag values named in return_tags will be fetched for each - estimator and will be appended as either columns or tuple entries. + the tag values named in return_tags will be fetched for each + estimator and will be appended as either columns or tuple entries. + suppress_import_stdout : bool, optional. Default=True whether to suppress stdout printout upon import. @@ -99,7 +110,7 @@ def all_estimators( all_estimators will return one of the following: 1. list of estimators, if return_names=False, and return_tags is None 2. list of tuples (optional estimator name, class, ~optional estimator - tags), if return_names=True or return_tags is not None. + tags), if return_names=True or return_tags is not None. 3. pandas.DataFrame if as_dataframe = True if list of estimators: entries are estimators matching the query, @@ -109,10 +120,10 @@ def all_estimators( tags) matching the query, in alphabetical order of estimator name, where ``name`` is the estimator name as string, and is an - optional return + optional return ``estimator`` is the actual estimator ``tags`` are the estimator's values for each tag in return_tags - and is an optional return. + and is an optional return. if dataframe: all_estimators will return a pandas.DataFrame. column names represent the attributes contained in each column. @@ -271,15 +282,16 @@ def all_tags( Parameters ---------- estimator_types: string, list of string, optional (default=None) - Which kind of estimators should be returned. - - If None, no filter is applied and all estimators are returned. + Ta gs for hich kind of estimators should be returned. + + - If None, no filter is applied and tags for all estimators are returned. - Possible values are 'classifier', 'regressor', 'transformer' and - 'forecaster' to get estimators only of these specific types, or a list of - these to get the estimators that fit at least one of the types. + 'forecaster' to get estimator tags only fo these specific types, or a list of + these to get tags for estimators that fit at least one of the types. + as_dataframe: bool, optional (default=False) - if False, return is as described below; - if True, return is converted into a pandas.DataFrame for pretty - display + if False, return is as described below; + if True, return is converted into a pandas.DataFrame for pretty display Returns ------- @@ -287,14 +299,16 @@ def all_tags( in alphabetical order by a a : string - name of the tag as used in the _tags dictionary b : string - name of the scitype this tag applies to - must be in _base_classes.BASE_CLASS_SCITYPE_LIST + must be in _base_classes.BASE_CLASS_SCITYPE_LIST c : string - expected type of the tag value - should be one of: - "bool" - valid values are True/False - "int" - valid values are all integers - "str" - valid values are all strings - ("str", list_of_string) - any string in list_of_string is valid - ("list", list_of_string) - any individual string and sub-list is valid + should be one of: + + * ``"bool"`` - valid values are True/False + * ``"int"`` - valid values are all integers + * ``"str"`` - valid values are all strings + * ``("str", "list_of_string")`` - any string in ``list_of_string`` is valid + * ``("list", "list_of_string")`` - any string element or sub-list is valid + d : string - plain English description of the tag """ @@ -305,6 +319,10 @@ def is_tag_for_type(tag, estimator_types): if isinstance(estimator_types, str): estimator_types = [estimator_types] + # also retrieve all tags for topmost base classes + # "estimator" has also been used for object tags, so is always included + estimator_types += ["estimator", "object"] + tag_types = set(tag_types) estimator_types = set(estimator_types) is_valid_tag_for_type = len(tag_types.intersection(estimator_types)) > 0 diff --git a/sktime/registry/_scitype.py b/sktime/registry/_scitype.py index 054dcd4babe..b140ccde848 100644 --- a/sktime/registry/_scitype.py +++ b/sktime/registry/_scitype.py @@ -7,7 +7,9 @@ from sktime.registry._base_classes import BASE_CLASS_REGISTER -def scitype(obj, force_single_scitype=True, coerce_to_list=False): +def scitype( + obj, force_single_scitype=True, coerce_to_list=False, raise_on_unknown=True +): """Determine scitype string of obj. Parameters @@ -18,15 +20,19 @@ def scitype(obj, force_single_scitype=True, coerce_to_list=False): if True, only the *first* scitype found will be returned order is determined by the order in BASE_CLASS_REGISTER coerce_to_list : bool, optional, default = False - whether return should be coerced to list, even if only one scitype is identified + determines the return type: if True, returns a single str, + if False, returns a list of str + raise_on_unknown : bool, optional, default = True + if True, raises an error if no scitype can be determined for obj + if False, returns "object" scitype Returns ------- scitype : str, or list of str of sktime scitype strings from BASE_CLASS_REGISTER str, sktime scitype string, if exactly one scitype can be determined for obj - or force_single_scitype is True, and if coerce_to_list is False + or force_single_scitype is True, and if coerce_to_list is False list of str, of scitype strings, if more than one scitype are determined, - or if coerce_to_list is True + or if coerce_to_list is True obj has scitype if it inherits from class in same row of BASE_CLASS_REGISTER Raises @@ -40,7 +46,14 @@ def scitype(obj, force_single_scitype=True, coerce_to_list=False): else: tag_type = obj.get_tag("object_type", None, raise_error=False) if tag_type is not None: - return tag_type + if not isinstance(tag_type, list): + tag_type = [tag_type] + if force_single_scitype and len(tag_type) > 1: + tag_type = [tag_type[0]] + if coerce_to_list: + return tag_type + else: + return tag_type[0] # if the tag is not present, determine scitype from legacy base class logic if isclass(obj): @@ -49,7 +62,10 @@ def scitype(obj, force_single_scitype=True, coerce_to_list=False): scitypes = [sci[0] for sci in BASE_CLASS_REGISTER if isinstance(obj, sci[1])] if len(scitypes) == 0: - raise TypeError("Error, no scitype could be determined for obj") + if raise_on_unknown: + raise TypeError("Error, no scitype could be determined for obj") + else: + scitypes = ["object"] if len(scitypes) > 1 and "object" in scitypes: scitypes = list(set(scitypes).difference(["object"])) diff --git a/sktime/registry/_tags.py b/sktime/registry/_tags.py index 512204ca180..99dab113665 100644 --- a/sktime/registry/_tags.py +++ b/sktime/registry/_tags.py @@ -135,7 +135,7 @@ [ "pd.Series", "pd.DataFrame", - "np.array", + "np.ndarray", "nested_univ", "pd-multiindex", "numpy3D", @@ -158,7 +158,7 @@ [ "pd.Series", "pd.DataFrame", - "np.array", + "np.ndarray", "nested_univ", "pd-multiindex", "numpy3D", @@ -492,6 +492,30 @@ "int", "sample size used in approximating other statistics if not available", ), + ( + "bisect_iter", + "distribution", + "int", + "max iters for bisection method in ppf", + ), + ( + "capability:multioutput", + ["classifier", "regressor"], # might need to add "early_classifier" here + "bool", + "can the estimator handle multioutput data?", + ), + ( + "maintainers", + "object", + ("list", "str"), + "list of current maintainers of the object, each maintainer a GitHub handle", + ), + ( + "authors", + "object", + ("list", "str"), + "list of authors of the object, each author a GitHub handle", + ), ] ESTIMATOR_TAG_TABLE = pd.DataFrame(ESTIMATOR_TAG_REGISTER) diff --git a/sktime/registry/tests/test_lookup.py b/sktime/registry/tests/test_lookup.py index 3d58b02c322..e37380db78b 100644 --- a/sktime/registry/tests/test_lookup.py +++ b/sktime/registry/tests/test_lookup.py @@ -15,18 +15,9 @@ from sktime.registry._lookup import _check_estimator_types VALID_SCITYPES_SET = set( - BASE_CLASS_SCITYPE_LIST + TRANSFORMER_MIXIN_SCITYPE_LIST + ["estimator"] + BASE_CLASS_SCITYPE_LIST + TRANSFORMER_MIXIN_SCITYPE_LIST + ["estimator", "object"] ) -# some scitypes have no associated tags yet -SCITYPES_WITHOUT_TAGS = [ - "series-annotator", - "clusterer", - "object", - "splitter", - "network", -] - # shorthands for easy reading b = BASE_CLASS_SCITYPE_LIST n = len(b) @@ -101,14 +92,8 @@ def test_all_tags(estimator_scitype): assert isinstance(tags, list) # there should be at least one tag returned - # exception: scitypes which we know don't have tags associated - est_list = ( - estimator_scitype - if isinstance(estimator_scitype, list) - else [estimator_scitype] - ) - if not set(est_list).issubset(SCITYPES_WITHOUT_TAGS): - assert len(tags) > 0 + # even scitypes without tags should return those for "object" + assert len(tags) > 0 # checks return type specification (see docstring) for tag in tags: @@ -122,6 +107,11 @@ def test_all_tags(estimator_scitype): assert isinstance(tag[2][1], (str, list)) assert isinstance(tag[3], str) + # check some tags that all object types should have + tags_strs = [tag[0] for tag in tags] + assert "python_dependencies" in tags_strs + assert "python_version" in tags_strs + @pytest.mark.parametrize("return_names", [True, False]) def test_all_estimators_return_names(return_names): diff --git a/sktime/registry/tests/test_scitype.py b/sktime/registry/tests/test_scitype.py new file mode 100644 index 00000000000..c3370a07c45 --- /dev/null +++ b/sktime/registry/tests/test_scitype.py @@ -0,0 +1,94 @@ +"""Tests for scitype typipng function.""" + +import pytest + +from sktime.registry._scitype import scitype + + +@pytest.mark.parametrize("coerce_to_list", [True, False]) +def test_scitype(coerce_to_list): + """Test that the scitype function recovers the correct scitype(s).""" + from sktime.forecasting.arima import ARIMA + from sktime.forecasting.naive import NaiveForecaster + from sktime.transformations.series.exponent import ExponentTransformer + + # test that scitype works for classes with soft dependencies + result_arima = scitype(ARIMA, coerce_to_list=coerce_to_list) + if coerce_to_list: + assert isinstance(result_arima, list) + assert "forecaster" == result_arima[0] + else: + assert "forecaster" == result_arima + + # test that scitype works for instances + result_naive = scitype(NaiveForecaster(), coerce_to_list=coerce_to_list) + if coerce_to_list: + assert isinstance(result_naive, list) + assert "forecaster" == result_naive[0] + else: + assert "forecaster" == result_naive + + # test transformer object + result_transformer = scitype(ExponentTransformer, coerce_to_list=coerce_to_list) + if coerce_to_list: + assert isinstance(result_transformer, list) + assert "transformer" == result_transformer[0] + else: + assert "transformer" == result_transformer + + +@pytest.mark.parametrize("force_single_scitype", [True, False]) +@pytest.mark.parametrize("coerce_to_list", [True, False]) +def test_scitype_generic(force_single_scitype, coerce_to_list): + """Test that the scitype function recovers the correct scitype(s).""" + from sktime.base import BaseObject + + class _DummyClass(BaseObject): + _tags = {"object_type": ["foo", "bar"]} + + scitype_inferred = scitype( + _DummyClass(), + force_single_scitype=force_single_scitype, + coerce_to_list=coerce_to_list, + ) + + if force_single_scitype and coerce_to_list: + expected = ["foo"] + if not force_single_scitype and coerce_to_list: + expected = ["foo", "bar"] + if not coerce_to_list: + expected = "foo" + + assert scitype_inferred == expected + + class _DummyClass2(BaseObject): + _tags = {"object_type": "foo"} + + scitype_inferred = scitype( + _DummyClass2(), + force_single_scitype=force_single_scitype, + coerce_to_list=coerce_to_list, + ) + + if coerce_to_list: + expected = ["foo"] + if not coerce_to_list: + expected = "foo" + + assert scitype_inferred == expected + + class _DummyClass3(BaseObject): + _tags = {"object_type": ["foo"]} + + scitype_inferred = scitype( + _DummyClass3(), + force_single_scitype=force_single_scitype, + coerce_to_list=coerce_to_list, + ) + + if coerce_to_list: + expected = ["foo"] + if not coerce_to_list: + expected = "foo" + + assert scitype_inferred == expected diff --git a/sktime/registry/tests/test_tags.py b/sktime/registry/tests/test_tags.py index e3e73816359..74064d28637 100644 --- a/sktime/registry/tests/test_tags.py +++ b/sktime/registry/tests/test_tags.py @@ -1,4 +1,4 @@ -"""Tests for tag register an tag functionality.""" +"""Tests for tag register and tag functionality.""" from sktime.registry._tags import ESTIMATOR_TAG_REGISTER diff --git a/sktime/regression/base.py b/sktime/regression/base.py index 1ac7cdad25f..ef95794ea0e 100644 --- a/sktime/regression/base.py +++ b/sktime/regression/base.py @@ -23,19 +23,16 @@ class name: BaseRegressor __author__ = ["mloning", "fkiraly"] import time -from abc import ABC, abstractmethod import numpy as np -import pandas as pd -from sktime.base import BaseEstimator -from sktime.datatypes import check_is_scitype, convert_to +from sktime.base import BasePanelMixin +from sktime.datatypes import VectorizedDF from sktime.utils.sklearn import is_sklearn_transformer from sktime.utils.validation import check_n_jobs -from sktime.utils.warnings import warn -class BaseRegressor(BaseEstimator, ABC): +class BaseRegressor(BasePanelMixin): """Abstract base class for time series regressors. The base regressor specifies the methods and method signatures that all @@ -52,13 +49,17 @@ class BaseRegressor(BaseEstimator, ABC): _tags = { "object_type": "regressor", # type of object "X_inner_mtype": "numpy3D", # which type do _fit/_predict, support for X? + "y_inner_mtype": "numpy1D", # which type do _fit/_predict, support for y? # it should be either "numpy3D" or "nested_univ" (nested pd.DataFrame) + "capability:multioutput": False, # whether regressor supports multioutput "capability:multivariate": False, "capability:unequal_length": False, "capability:missing_values": False, "capability:train_estimate": False, "capability:contractable": False, "capability:multithreading": False, + "authors": "sktime developers", # author(s) of the object + "maintainers": "sktime developers", # current maintainer(s) of the object } # convenience constant to control which metadata of input data @@ -70,6 +71,14 @@ class BaseRegressor(BaseEstimator, ABC): "is_equal_length", ] + # attribute name where vectorized estimators are stored + VECTORIZATION_ATTR = "regressors_" # e.g., classifiers_, regressors_ + + # used in error messages + TASK = "regression" # e.g., classification, regression + EST_TYPE = "regressor" # e.g., classifier, regressor + EST_TYPE_PLURAL = "regressors" # e.g., classifiers, regressors + def __init__(self): self.fit_time_ = 0 self._class_dictionary = {} @@ -79,6 +88,9 @@ def __init__(self): # required for compatibility with some sklearn interfaces # i.e. CalibratedRegressorCV self._estimator_type = "regressor" + self._is_vectorized = False + self._is_timed = False + self._converter_store_y = {} super().__init__() @@ -123,19 +135,31 @@ def __rmul__(self, other): def fit(self, X, y): """Fit time series regressor to training data. + State change: + Changes state to "fitted". + + Writes to self: + Sets self.is_fitted to True. + Sets fitted model attributes ending in "_". + Parameters ---------- - X : 3D np.array (any number of dimensions, equal length series) - of shape [n_instances, n_dimensions, series_length] - or 2D np.array (univariate, equal length series) - of shape [n_instances, series_length] - or pd.DataFrame with each column a dimension, each cell a pd.Series - (any number of dimensions, equal or unequal length series) + X : sktime compatible time series panel data container, Panel scitype, e.g., + pd-multiindex: pd.DataFrame with columns = variables, + index = pd.MultiIndex with first level = instance indices, + second level = time indices + numpy3D: 3D np.array (any number of dimensions, equal length series) + of shape [n_instances, n_dimensions, series_length] or of any other supported Panel mtype - for list of mtypes, see datatypes.SCITYPE_REGISTER - for specifications, see examples/AA_datatypes_and_datasets.ipynb - y : 1D np.array of float, of shape [n_instances] - regression labels for fitting - indices correspond to instance indices in X + for list of mtypes, see datatypes.SCITYPE_REGISTER + for specifications, see examples/AA_datatypes_and_datasets.ipynb + y : sktime compatible tabular data container, Table scitype + 1D iterable, of shape [n_instances] + or 2D iterable, of shape [n_instances, n_dimensions] + class labels for fitting + 0-th indices correspond to instance indices in X + 1-st indices (if applicable) correspond to multioutput vector indices in X + supported sktime types: np.ndarray (1D, 2D), pd.Series, pd.DataFrame Returns ------- @@ -146,21 +170,47 @@ def fit(self, X, y): Changes state by creating a fitted model that updates attributes ending in "_" and sets is_fitted flag to True. """ + self.reset() + + # fit timer start start = int(round(time.time() * 1000)) + + # check and convert y for multioutput vectorization + y, y_metadata, y_inner_mtype = self._check_y(y, return_to_mtype=True) + self._y_metadata = y_metadata + self._y_inner_mtype = y_inner_mtype + self._is_vectorized = isinstance(y, VectorizedDF) + + if self._is_vectorized: + self._vectorize("fit", X=X, y=y) + # fit timer end + self.fit_time_ = int(round(time.time() * 1000)) - start + # this should happen last: fitted state is set to True + self._is_fitted = True + return self + + # no vectorization needed, proceed with normal fit + # convenience conversions to allow user flexibility: # if X is 2D array, convert to 3D, if y is Series, convert to numpy - X, y = _internal_convert(X, y) - X_metadata = _check_regressor_input( + X, y = self._internal_convert(X, y) + + # y float coercion + if y is not None and isinstance(y, np.ndarray): + y = y.astype("float") + + # input checks + X_metadata = self._check_input( X, y, return_metadata=self.METADATA_REQ_IN_CHECKS ) self._X_metadata = X_metadata - missing = X_metadata["has_nans"] - multivariate = not X_metadata["is_univariate"] - unequal = not X_metadata["is_equal_length"] + X_mtype = X_metadata["mtype"] + # Check this regressor can handle characteristics - self._check_capabilities(missing, multivariate, unequal) + self._check_capabilities(X_metadata) + # Convert data as dictated by the regressor tags - X = self._convert_X(X) + X = self._convert_X(X, X_mtype) multithread = self.get_tag("capability:multithreading") if multithread: try: @@ -172,7 +222,8 @@ def fit(self, X, y): self._fit(X, y) self.fit_time_ = int(round(time.time() * 1000)) - start - # this should happen last + + # this should happen last: fitted state is set to True self._is_fitted = True return self @@ -181,44 +232,64 @@ def predict(self, X) -> np.ndarray: Parameters ---------- - X : 3D np.array (any number of dimensions, equal length series) - of shape [n_instances, n_dimensions, series_length] - or 2D np.array (univariate, equal length series) - of shape [n_instances, series_length] - or pd.DataFrame with each column a dimension, each cell a pd.Series - (any number of dimensions, equal or unequal length series) + X : sktime compatible time series panel data container, Panel scitype, e.g., + pd-multiindex: pd.DataFrame with columns = variables, + index = pd.MultiIndex with first level = instance indices, + second level = time indices + numpy3D: 3D np.array (any number of dimensions, equal length series) + of shape [n_instances, n_dimensions, series_length] or of any other supported Panel mtype - for list of mtypes, see datatypes.SCITYPE_REGISTER - for specifications, see examples/AA_datatypes_and_datasets.ipynb + for list of mtypes, see datatypes.SCITYPE_REGISTER + for specifications, see examples/AA_datatypes_and_datasets.ipynb Returns ------- - y : 1D np.array of float, of shape [n_instances] - predicted regression labels - indices correspond to instance indices in X + y_pred : sktime compatible tabular data container, Table scitype + 1D iterable, of shape [n_instances] + or 2D iterable, of shape [n_instances, n_dimensions] + predicted class labels + 0-th indices correspond to instance indices in X + 1-st indices (if applicable) correspond to multioutput vector indices in X + 1D np.npdarray, if y univariate (one dimension) + otherwise, same type as y passed in fit """ self.check_is_fitted() + # enter vectorized mode if needed + if self._is_vectorized: + return self._vectorize("predict", X=X) + # boilerplate input checks for predict-like methods X = self._check_convert_X_for_predict(X) - return self._predict(X) + # call internal _predict, convert output + y_pred_inner = self._predict(X) + y_pred = self._convert_output_y(y_pred_inner) + return y_pred - def score(self, X, y) -> float: + def score(self, X, y, multioutput="uniform_average") -> float: """Scores predicted labels against ground truth labels on X. Parameters ---------- - X : 3D np.array (any number of dimensions, equal length series) - of shape [n_instances, n_dimensions, series_length] - or 2D np.array (univariate, equal length series) - of shape [n_instances, series_length] - or pd.DataFrame with each column a dimension, each cell a pd.Series - (any number of dimensions, equal or unequal length series) + X : sktime compatible time series panel data container, Panel scitype, e.g., + pd-multiindex: pd.DataFrame with columns = variables, + index = pd.MultiIndex with first level = instance indices, + second level = time indices + numpy3D: 3D np.array (any number of dimensions, equal length series) + of shape [n_instances, n_dimensions, series_length] or of any other supported Panel mtype - for list of mtypes, see datatypes.SCITYPE_REGISTER - for specifications, see examples/AA_datatypes_and_datasets.ipynb - y : 1D np.array of float, of shape [n_instances] - regression labels (gnr truth) - indices correspond to instance indices in X + for list of mtypes, see datatypes.SCITYPE_REGISTER + for specifications, see examples/AA_datatypes_and_datasets.ipynb + y : 2D np.array of int, of shape [n_instances, n_dimensions] - regression labels + for fitting indices correspond to instance indices in X + or 1D np.array of int, of shape [n_instances] - regression labels for + fitting indices correspond to instance indices in X + multioutput : str, optional (default="uniform_average") + {"raw_values", "uniform_average", "variance_weighted"}, array-like of shape + (n_outputs,) or None, default="uniform_average". + Defines aggregating of multiple output scores. Array-like value defines + weights used to average scores. Returns ------- @@ -228,9 +299,8 @@ def score(self, X, y) -> float: self.check_is_fitted() - return r2_score(y, self.predict(X), normalize=True) + return r2_score(y, self.predict(X), normalize=True, multioutput=multioutput) - @abstractmethod def _fit(self, X, y): """Fit time series regressor to training data. @@ -240,13 +310,21 @@ def _fit(self, X, y): ---------- X : guaranteed to be of a type in self.get_tag("X_inner_mtype") if self.get_tag("X_inner_mtype") = "numpy3D": - 3D np.ndarray of shape = [n_instances, n_dimensions, series_length] + 3D np.ndarray of shape = [n_instances, n_dimensions, series_length] + if self.get_tag("X_inner_mtype") = "pd-multiindex": + pd.DataFrame with columns = variables, + index = pd.MultiIndex with first level = instance indices, + second level = time indices if self.get_tag("X_inner_mtype") = "nested_univ": - pd.DataFrame with each column a dimension, each cell a pd.Series + pd.DataFrame with each column a dimension, each cell a pd.Series for list of other mtypes, see datatypes.SCITYPE_REGISTER for specifications, see examples/AA_datatypes_and_datasets.ipynb - y : 1D np.array of float, of shape [n_instances] - regression labels for fitting - indices correspond to instance indices in X + y : guaranteed to be of a type in self.get_tag("y_inner_mtype") + 1D iterable, of shape [n_instances] + or 2D iterable, of shape [n_instances, n_dimensions] + class labels for fitting + if self.get_tag("capaility:multioutput") = False, guaranteed to be 1D + if self.get_tag("capaility:multioutput") = True, guaranteed to be 2D Returns ------- @@ -256,9 +334,8 @@ def _fit(self, X, y): ----- Changes state by creating a fitted model that updates attributes ending in "_" """ - ... + raise NotImplementedError("abstract method") - @abstractmethod def _predict(self, X) -> np.ndarray: """Predicts labels for sequences in X. @@ -279,207 +356,4 @@ def _predict(self, X) -> np.ndarray: y : 1D np.array of float, of shape [n_instances] - predicted regression labels indices correspond to instance indices in X """ - ... - - def _check_convert_X_for_predict(self, X): - """Input checks, capability checks, repeated in all predict/score methods. - - Parameters - ---------- - X : any object (to check/convert) - should be of a supported Panel mtype or 2D numpy.ndarray - - Returns - ------- - X: an object of a supported Panel mtype, numpy3D if X was a 2D numpy.ndarray - - Raises - ------ - ValueError if X is of invalid input data type, or there is not enough data - ValueError if the capabilities in self._tags do not handle the data. - """ - X = _internal_convert(X) - X_metadata = _check_regressor_input( - X, return_metadata=self.METADATA_REQ_IN_CHECKS - ) - missing = X_metadata["has_nans"] - multivariate = not X_metadata["is_univariate"] - unequal = not X_metadata["is_equal_length"] - # Check this regressor can handle characteristics - self._check_capabilities(missing, multivariate, unequal) - # Convert data as dictated by the regressor tags - X = self._convert_X(X) - - return X - - def _check_capabilities(self, missing, multivariate, unequal): - """Check whether this regressor can handle the data characteristics. - - Parameters - ---------- - missing : boolean, does the data passed to fit contain missing values? - multivariate : boolean, does the data passed to fit contain missing values? - unequal : boolea, do the time series passed to fit have variable lengths? - - Raises - ------ - ValueError if the capabilities in self._tags do not handle the data. - """ - allow_multivariate = self.get_tag("capability:multivariate") - allow_missing = self.get_tag("capability:missing_values") - allow_unequal = self.get_tag("capability:unequal_length") - - self_name = type(self).__name__ - - # identify problems, mismatch of capability and inputs - problems = [] - if missing and not allow_missing: - problems += ["missing values"] - if multivariate and not allow_multivariate: - problems += ["multivariate series"] - if unequal and not allow_unequal: - problems += ["unequal length series"] - - # construct error message - problems_and = " and ".join(problems) - problems_or = " or ".join(problems) - msg = ( - f"Data seen by {self_name} instance has {problems_and}, " - f"but this {self_name} instance cannot handle {problems_or}. " - f"Calls with {problems_or} may result in error or unreliable results." - ) - - # raise exception or warning with message - # if self is composite, raise a warning, since passing could be fine - # see discussion in PR 2366 why - if len(problems) > 0: - if self.is_composite(): - warn(msg, obj=self) - else: - raise ValueError(msg) - - def _convert_X(self, X): - """Convert equal length series from DataFrame to numpy array or vice versa. - - Parameters - ---------- - self : this regressor - X : pd.DataFrame or np.ndarray. Input attribute data - - Returns - ------- - X : input X converted to type in "X_inner_mtype" tag - usually a pd.DataFrame (nested) or 3D np.ndarray - Checked and possibly converted input data - """ - inner_type = self.get_tag("X_inner_mtype") - # convert pd.DataFrame - X = convert_to( - X, - to_type=inner_type, - as_scitype="Panel", - ) - return X - - -def _check_regressor_input( - X, - y=None, - enforce_min_instances=1, - return_metadata=True, -): - """Check whether input X and y are valid formats with minimum data. - - Raises a ValueError if the input is not valid. - - Parameters - ---------- - X : check whether conformant with any sktime Panel mtype specification - y : check whether a pd.Series or np.array - enforce_min_instances : int, optional (default=1) - check there are a minimum number of instances. - return_metadata : bool, str, or list of str - metadata fields to return with X_metadata, input to check_is_scitype - - Returns - ------- - metadata : dict with metadata for X returned by datatypes.check_is_scitype - - Raises - ------ - ValueError - If y or X is invalid input data type, or there is not enough data - """ - # Check X is valid input type and recover the data characteristics - X_valid, _, X_metadata = check_is_scitype( - X, scitype="Panel", return_metadata=return_metadata - ) - if not X_valid: - raise TypeError( - f"X is not of a supported input data type." - f"X must be in a supported mtype format for Panel, found {type(X)}" - f"Use datatypes.check_is_mtype to check conformance with specifications." - ) - n_cases = X_metadata["n_instances"] - if n_cases < enforce_min_instances: - raise ValueError( - f"Minimum number of cases required is {enforce_min_instances} but X " - f"has : {n_cases}" - ) - - # Check y if passed - if y is not None: - # Check y valid input - if not isinstance(y, (pd.Series, np.ndarray)) and not ( - isinstance(y, pd.DataFrame) and y.shape[1] == 1 - ): - raise ValueError( - f"y must be a np.array, pd.Series or a 1-D pd.DataFrame," - f"but found type: {type(y)}" - ) - # Check matching number of labels - n_labels = y.shape[0] - if n_cases != n_labels: - raise ValueError( - f"Mismatch in number of cases. Number in X = {n_cases} nos in y = " - f"{n_labels}" - ) - if isinstance(y, np.ndarray): - if y.ndim > 1: - raise ValueError( - f"np.ndarray y must be 1-dimensional, " - f"but found {y.ndim} dimensions" - ) - return X_metadata - - -def _internal_convert(X, y=None): - """Convert X and y if necessary as a user convenience. - - Convert X to a 3D numpy array if already a 2D and convert y into an 1D numpy - array if passed as a Series. - - Parameters - ---------- - X : an object of a supported Panel mtype, or 2D numpy.ndarray - y : np.ndarray or pd.Series - - Returns - ------- - X: an object of a supported Panel mtype, numpy3D if X was a 2D numpy.ndarray - y: np.ndarray - """ - if isinstance(X, np.ndarray): - # Temporary fix to insist on 3D numpy. For univariate problems, - # most regressors simply convert back to 2D. This squeezing should be - # done here, but touches a lot of files, so will get this to work first. - if X.ndim == 2: - X = X.reshape(X.shape[0], 1, X.shape[1]) - if y is not None and isinstance(y, pd.Series): - # y should be a numpy array, although we allow Series for user convenience - y = pd.Series.to_numpy(y) - if y is not None and isinstance(y, np.ndarray): - y = y.astype("float") - if y is None: - return X - return X, y + raise NotImplementedError("abstract method") diff --git a/sktime/regression/compose/_ensemble.py b/sktime/regression/compose/_ensemble.py index ff5e84ff595..4b4c3d2964e 100644 --- a/sktime/regression/compose/_ensemble.py +++ b/sktime/regression/compose/_ensemble.py @@ -18,8 +18,8 @@ from sklearn.pipeline import Pipeline from sklearn.tree import DecisionTreeRegressor +from sktime.base._panel.forest._composable import BaseTimeSeriesForest from sktime.regression.base import BaseRegressor -from sktime.series_as_features.base.estimators._ensemble import BaseTimeSeriesForest from sktime.transformations.panel.summarize import RandomIntervalFeatureExtractor from sktime.utils.slope_and_trend import _slope from sktime.utils.validation.panel import check_X, check_X_y diff --git a/sktime/regression/deep_learning/__init__.py b/sktime/regression/deep_learning/__init__.py index cb7052b8a9a..7e144d0c03b 100644 --- a/sktime/regression/deep_learning/__init__.py +++ b/sktime/regression/deep_learning/__init__.py @@ -1,8 +1,14 @@ """Deep learning based regressors.""" __all__ = [ "CNNRegressor", + "MCDCNNRegressor", + "ResNetRegressor", + "SimpleRNNRegressor", "TapNetRegressor", ] from sktime.regression.deep_learning.cnn import CNNRegressor +from sktime.regression.deep_learning.mcdcnn import MCDCNNRegressor +from sktime.regression.deep_learning.resnet import ResNetRegressor +from sktime.regression.deep_learning.rnn import SimpleRNNRegressor from sktime.regression.deep_learning.tapnet import TapNetRegressor diff --git a/sktime/regression/deep_learning/cnn.py b/sktime/regression/deep_learning/cnn.py index c440c39f0cf..02d418ea7df 100644 --- a/sktime/regression/deep_learning/cnn.py +++ b/sktime/regression/deep_learning/cnn.py @@ -55,6 +55,15 @@ class CNNRegressor(BaseDeepRegressor): https://github.com/hfawaz/dl-4-tsc/blob/master/classifiers/cnn.py """ + _tags = { + # packaging info + # -------------- + "authors": ["AurumnPegasus", "achieveordie"], + "maintainers": ["AurumnPegasus", "achieveordie"], + "python_dependencies": "tensorflow", + # estimator type handled by parent class + } + def __init__( self, n_epochs=2000, diff --git a/sktime/regression/deep_learning/mcdcnn.py b/sktime/regression/deep_learning/mcdcnn.py index 1b667ed2766..2cf62b677fc 100644 --- a/sktime/regression/deep_learning/mcdcnn.py +++ b/sktime/regression/deep_learning/mcdcnn.py @@ -1,8 +1,6 @@ """Multi Channel Deep Convolutional Neural Regressor (MCDCNN).""" -__author__ = [ - "JamesLarge", -] +__author__ = ["James-Large"] from copy import deepcopy @@ -79,7 +77,13 @@ class MCDCNNRegressor(BaseDeepRegressor): MCDCNRegressor(...) """ - _tags = {"python_dependencies": "tensorflow"} + _tags = { + # packaging info + # -------------- + "authors": ["James-Large"], + "python_dependencies": "tensorflow", + # estimator type handled by parent class + } def __init__( self, diff --git a/sktime/regression/deep_learning/resnet.py b/sktime/regression/deep_learning/resnet.py index 684d9635757..ccc48120aaa 100644 --- a/sktime/regression/deep_learning/resnet.py +++ b/sktime/regression/deep_learning/resnet.py @@ -59,7 +59,14 @@ class ResNetRegressor(BaseDeepRegressor): ResNetRegressor(...) """ - _tags = {"python_dependencies": ["tensorflow"]} + _tags = { + # packaging info + # -------------- + "authors": ["James-Large", "Withington"], + "maintainers": ["Withington"], + "python_dependencies": "tensorflow", + # estimator type handled by parent class + } def __init__( self, diff --git a/sktime/regression/deep_learning/rnn.py b/sktime/regression/deep_learning/rnn.py index c32bd81999a..de2e773f5b0 100644 --- a/sktime/regression/deep_learning/rnn.py +++ b/sktime/regression/deep_learning/rnn.py @@ -49,9 +49,17 @@ class SimpleRNNRegressor(BaseDeepRegressor): https://github.com/Mcompetitions/M4-methods """ + _tags = { + # packaging info + # -------------- + "authors": ["mloning"], + "python_dependencies": "tensorflow", + # estimator type handled by parent class + } + def __init__( self, - num_epochs=100, + n_epochs=100, batch_size=1, units=6, callbacks=None, @@ -65,8 +73,9 @@ def __init__( optimizer=None, ): _check_dl_dependencies(severity="error") + super().__init__() - self.num_epochs = num_epochs + self.batch_size = batch_size self.verbose = verbose self.units = units @@ -80,6 +89,7 @@ def __init__( self.optimizer = optimizer self.history = None self._network = RNNNetwork(random_state=random_state, units=units) + self.n_epochs = n_epochs def build_model(self, input_shape, **kwargs): """Construct a compiled, un-trained, keras model that is ready for training. @@ -183,7 +193,7 @@ def _fit(self, X, y): X, y, batch_size=self.batch_size, - epochs=self.num_epochs, + epochs=self.n_epochs, verbose=self.verbose, callbacks=self.callbacks_, ) @@ -212,7 +222,7 @@ def get_test_params(cls, parameter_set="default"): """ params1 = {} params2 = { - "num_epochs": 50, + "n_epochs": 50, "batch_size": 2, "units": 5, "use_bias": False, diff --git a/sktime/regression/deep_learning/tapnet.py b/sktime/regression/deep_learning/tapnet.py index 73ac382e4db..7903ae69abf 100644 --- a/sktime/regression/deep_learning/tapnet.py +++ b/sktime/regression/deep_learning/tapnet.py @@ -1,11 +1,7 @@ """Time Convolutional Neural Network (CNN) for classification.""" -__author__ = [ - "Jack Russon", -] -__all__ = [ - "TapNetRegressor", -] +__author__ = ["jnrusson1"] +__all__ = ["TapNetRegressor"] from copy import deepcopy @@ -77,7 +73,14 @@ class TapNetRegressor(BaseDeepRegressor): or class based self attention. """ - _tags = {"python_dependencies": "tensorflow"} + _tags = { + # packaging info + # -------------- + "authors": ["jnrusson1"], + "maintainers": ["jnrusson1"], + "python_dependencies": "tensorflow", + # estimator type handled by parent class + } def __init__( self, diff --git a/sktime/regression/distance_based/_time_series_neighbors.py b/sktime/regression/distance_based/_time_series_neighbors.py index c801b938a24..824561b0891 100644 --- a/sktime/regression/distance_based/_time_series_neighbors.py +++ b/sktime/regression/distance_based/_time_series_neighbors.py @@ -90,11 +90,16 @@ class KNeighborsTimeSeriesRegressor(BaseRegressor): """ _tags = { + # packaging info + # -------------- + "authors": ["fkiraly"], + "python_dependencies": "numba", + # estimator type + # -------------- "capability:multivariate": True, "capability:unequal_length": True, "capability:missing_values": True, "X_inner_mtype": ["pd-multiindex", "numpy3D"], - "python_dependencies": "numba", } def __init__( diff --git a/sktime/regression/dummy/_dummy.py b/sktime/regression/dummy/_dummy.py index f6864f51ce2..878f452b1d4 100644 --- a/sktime/regression/dummy/_dummy.py +++ b/sktime/regression/dummy/_dummy.py @@ -1,6 +1,6 @@ """Dummy time series regressor.""" -__author__ = ["Badr-Eddine Marani"] +__author__ = ["badrmarani"] __all__ = ["DummyRegressor"] import numpy as np @@ -58,6 +58,12 @@ class DummyRegressor(BaseRegressor): """ _tags = { + # packaging info + # -------------- + "authors": "badrmarani", + "maintainers": "badrmarani", + # estimator type + # -------------- "X_inner_mtype": "nested_univ", "capability:missing_values": True, "capability:unequal_length": True, diff --git a/sktime/regression/interval_based/_tsf.py b/sktime/regression/interval_based/_tsf.py index 597fba1f853..b3685f5edb0 100644 --- a/sktime/regression/interval_based/_tsf.py +++ b/sktime/regression/interval_based/_tsf.py @@ -8,11 +8,8 @@ from sklearn.ensemble._forest import ForestRegressor from sklearn.tree import DecisionTreeRegressor +from sktime.base._panel.forest._tsf import BaseTimeSeriesForest, _transform from sktime.regression.base import BaseRegressor -from sktime.series_as_features.base.estimators.interval_based._tsf import ( - BaseTimeSeriesForest, - _transform, -) class TimeSeriesForestRegressor(BaseTimeSeriesForest, ForestRegressor, BaseRegressor): @@ -77,6 +74,12 @@ class TimeSeriesForestRegressor(BaseTimeSeriesForest, ForestRegressor, BaseRegre """ _tags = { + # packaging info + # -------------- + "authors": ["TonyBagnall", "kkoziara", "luiszugasti", "kanand77", "mloning"], + "maintainers": ["kkoziara", "luiszugasti", "kanand77"], + # estimator type + # -------------- "capability:multivariate": False, "X_inner_mtype": "numpy3D", } diff --git a/sktime/regression/kernel_based/_rocket_regressor.py b/sktime/regression/kernel_based/_rocket_regressor.py index c6b99294d0e..1d9e65305c4 100644 --- a/sktime/regression/kernel_based/_rocket_regressor.py +++ b/sktime/regression/kernel_based/_rocket_regressor.py @@ -100,9 +100,14 @@ class RocketRegressor(_DelegatedRegressor, BaseRegressor): """ _tags = { + # packaging info + # -------------- + "authors": "fkiraly", + "python_dependencies": "numba", + # estimator type + # -------------- "capability:multivariate": True, "capability:multithreading": True, - "python_dependencies": "numba", } # valid rocket strings for input validity checking diff --git a/sktime/regression/tests/test_all_regressors.py b/sktime/regression/tests/test_all_regressors.py index 3dfea1768f6..c3e8b1c4ab9 100644 --- a/sktime/regression/tests/test_all_regressors.py +++ b/sktime/regression/tests/test_all_regressors.py @@ -4,10 +4,12 @@ import numpy as np +import pandas as pd import pytest from sktime.datatypes import check_is_scitype from sktime.tests.test_all_estimators import BaseFixtureGenerator, QuickTester +from sktime.utils._testing.panel import make_regression_problem from sktime.utils._testing.scenarios_classification import ( ClassifierFitPredictMultivariate, ) @@ -80,3 +82,25 @@ def test_regressor_output(self, estimator_instance, scenario): assert isinstance(y_pred, np.ndarray) assert y_pred.shape == (X_new_instances,) assert np.issubdtype(y_pred.dtype, np.floating) + + def test_multioutput(self, estimator_instance): + """Test multioutput regression for all classifiers. + + All classifiers should follow the same interface, + those that do not genuinely should vectorize/broadcast over y. + """ + n_instances = 20 + X, y = make_regression_problem(n_instances=n_instances) + y_mult = pd.DataFrame({"a": y, "b": y}) + + estimator_instance.fit(X, y_mult) + y_pred = estimator_instance.predict(X) + + assert isinstance(y_pred, pd.DataFrame) + assert y_pred.shape == y_mult.shape + + vectorized = estimator_instance.get_tag("capability:multioutput") + if vectorized: + assert hasattr(estimator_instance, "regressors_") + assert isinstance(estimator_instance.regressors_, pd.DataFrame) + assert estimator_instance.regressors_.shape == (1, 2) diff --git a/sktime/series_as_features/base/__init__.py b/sktime/series_as_features/base/__init__.py deleted file mode 100644 index 4ebe8357503..00000000000 --- a/sktime/series_as_features/base/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""sktime.series_as_features.base module.""" diff --git a/sktime/series_as_features/base/estimators/__init__.py b/sktime/series_as_features/base/estimators/__init__.py deleted file mode 100644 index 7ddff84176e..00000000000 --- a/sktime/series_as_features/base/estimators/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -"""sktime.series_as_features.base.estimators module.""" -__all__ = ["BaseTimeSeriesForest"] - -from ._ensemble import BaseTimeSeriesForest diff --git a/sktime/series_as_features/base/estimators/interval_based/__init__.py b/sktime/series_as_features/base/estimators/interval_based/__init__.py deleted file mode 100644 index 7ccd4695c4c..00000000000 --- a/sktime/series_as_features/base/estimators/interval_based/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -"""Interval based series-as-features estimators.""" - -__all__ = ["BaseTimeSeriesForest"] - -from sktime.series_as_features.base.estimators.interval_based._tsf import ( - BaseTimeSeriesForest, -) diff --git a/sktime/series_as_features/base/estimators/tests/__init__.py b/sktime/series_as_features/base/estimators/tests/__init__.py deleted file mode 100644 index 5e0f0cc7f01..00000000000 --- a/sktime/series_as_features/base/estimators/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Tests for sktime.series_as_features.base.estimators module.""" diff --git a/sktime/split/__init__.py b/sktime/split/__init__.py index 78e8d81a84b..a872aaf8fa2 100644 --- a/sktime/split/__init__.py +++ b/sktime/split/__init__.py @@ -2,6 +2,7 @@ __all__ = [ "CutoffSplitter", + "CutoffFhSplitter", "ExpandingGreedySplitter", "ExpandingWindowSplitter", "SameLocSplitter", @@ -12,7 +13,7 @@ "temporal_train_test_split", ] -from sktime.split.cutoff import CutoffSplitter +from sktime.split.cutoff import CutoffFhSplitter, CutoffSplitter from sktime.split.expandinggreedy import ExpandingGreedySplitter from sktime.split.expandingwindow import ExpandingWindowSplitter from sktime.split.sameloc import SameLocSplitter diff --git a/sktime/split/base/_base_splitter.py b/sktime/split/base/_base_splitter.py index b1325307eb7..07ceb8e6d39 100644 --- a/sktime/split/base/_base_splitter.py +++ b/sktime/split/base/_base_splitter.py @@ -95,6 +95,8 @@ class BaseSplitter(BaseObject): # split_series_uses: "iloc" or "loc", whether split_series under the hood # calls split ("iloc") or split_loc ("loc"). Setting this can give # performance advantages, e.g., if "loc" is faster to obtain. + "authors": "sktime developers", # author(s) of the object + "maintainers": "sktime developers", # current maintainer(s) of the object } def __init__( @@ -113,10 +115,10 @@ def split(self, y: ACCEPTED_Y_TYPES) -> SPLIT_GENERATOR_TYPE: Parameters ---------- y : pd.Index or time series in sktime compatible time series format, - time series can be in any Series, Panel, or Hierarchical mtype format + time series can be in any Series, Panel, or Hierarchical mtype format Index of time series to split, or time series to split If time series, considered as index of equivalent pandas type container: - pd.DataFrame, pd.Series, pd-multiindex, or pd_multiindex_hier mtype + pd.DataFrame, pd.Series, pd-multiindex, or pd_multiindex_hier mtype Yields ------ @@ -144,8 +146,8 @@ def _split(self, y: pd.Index) -> SPLIT_GENERATOR_TYPE: Parameters ---------- - y : pd.Index or time series in sktime compatible time series format - Time series to split, or index of time series to split + y : pd.Index + Index of time series to split Yields ------ @@ -197,8 +199,10 @@ def split_loc(self, y: ACCEPTED_Y_TYPES) -> Iterator[Tuple[pd.Index, pd.Index]]: Parameters ---------- y : pd.Index or time series in sktime compatible time series format, - time series can be in any Series, Panel, or Hierarchical mtype format - Time series to split, or index of time series to split + time series can be in any Series, Panel, or Hierarchical mtype format + Index of time series to split, or time series to split + If time series, considered as index of equivalent pandas type container: + pd.DataFrame, pd.Series, pd-multiindex, or pd_multiindex_hier mtype Yields ------ @@ -240,10 +244,11 @@ def split_series(self, y: ACCEPTED_Y_TYPES) -> Iterator[SPLIT_TYPE]: Parameters ---------- - y : time series in sktime compatible time series format, - time series can be in any Series, Panel, or Hierarchical mtype format - e.g., pd.Series, pd.DataFrame, np.ndarray - Time series to split, or index of time series to split + y : pd.Index or time series in sktime compatible time series format, + time series can be in any Series, Panel, or Hierarchical mtype format + Index of time series to split, or time series to split + If time series, considered as index of equivalent pandas type container: + pd.DataFrame, pd.Series, pd-multiindex, or pd_multiindex_hier mtype Yields ------ @@ -387,8 +392,11 @@ def get_n_splits(self, y: Optional[ACCEPTED_Y_TYPES] = None) -> int: Parameters ---------- - y : pd.Series or pd.Index, optional (default=None) - Time series to split + y : pd.Index or time series in sktime compatible time series format, + time series can be in any Series, Panel, or Hierarchical mtype format + Index of time series to split, or time series to split + If time series, considered as index of equivalent pandas type container: + pd.DataFrame, pd.Series, pd-multiindex, or pd_multiindex_hier mtype Returns ------- diff --git a/sktime/split/compose/__init__.py b/sktime/split/compose/__init__.py new file mode 100644 index 00000000000..1799457e131 --- /dev/null +++ b/sktime/split/compose/__init__.py @@ -0,0 +1,6 @@ +"""Compositors for splitters.""" +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) + +__all__ = ["Repeat"] + +from sktime.split.compose._repeat import Repeat diff --git a/sktime/split/compose/_repeat.py b/sktime/split/compose/_repeat.py new file mode 100644 index 00000000000..30e816b3c69 --- /dev/null +++ b/sktime/split/compose/_repeat.py @@ -0,0 +1,197 @@ +"""Splitter obtained from repeating another splitter.""" +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) + +__author__ = ["fkiraly"] + + +from sktime.split.base import BaseSplitter + + +class Repeat(BaseSplitter): + """Add repetitions to a splitter, element-wise or sequence-wise. + + Element-wise means: if the original splitter splits a series s into s1, s2, s3, + then a 2-times repeat splits s into s1, s1, s2, s2, s3, s3. + Sequence-wise means: if the original splitter splits a series s into s1, s2, s3, + then a 2-times repeat splits s into s1, s2, s3, s1, s2, s3. + + This splitter also allows to control whether repetitions are exact + or independent pseuo-random, for stochastic splitters. + + Parameters + ---------- + splitter : sktime splitter object, BaseSplitter descendant instance + splitter to repeat + times : int, default=1 + number of times to repeat the splitter + mode : str, one of "entry" and "sequence", default="entry" + mode of repetition + "entry" repeats each entry of the split ``times`` times + "sequence" repeats the entire sequence of splits ``times`` times + random_repeat : bool, default=False + whether repetitions should be exact or independent pseudo-random + If False, repetitions are exact (default) + If True, repetitions are random, ``splitter`` is cloned for each repetition. + Note: if a random seed is set in ``splitter``, the effect is the same + as setting ``random_repeat`` to False, even if ``random_repeat`` is True. + """ + + _tags = { + "split_hierarchical": True, + "split_series_uses": "iloc", + } + + def __init__(self, splitter, times=1, mode="entry", random_repeat=False): + self.splitter = splitter + self.times = times + self.mode = mode + self.random_repeat = random_repeat + + super().__init__() + + ALLOWED_MODES = ["entry", "sequence"] + if mode not in ALLOWED_MODES: + raise ValueError( + f"Mode in Repeat splitter should be one of {ALLOWED_MODES}, " + f"but found {mode}" + ) + + tags_to_clone = ["split_series_uses"] + + self.clone_tags(splitter, tags_to_clone) + + def _split(self, y): + """Get iloc references to train/test splits of `y`. + + private _split containing the core logic, called from split + + Parameters + ---------- + y : pd.Index + Index of time series to split + + Yields + ------ + train : 1D np.ndarray of dtype int + Training window indices, iloc references to training indices in y + test : 1D np.ndarray of dtype int + Test window indices, iloc references to test indices in y + """ + yield from self._repeat(y, method="split") + + def _split_loc(self, y): + """Get loc references to train/test splits of `y`. + + private _split containing the core logic, called from split_loc + + Default implements using split and y.index to look up the loc indices. + Can be overridden for faster implementation. + + Parameters + ---------- + y : pd.Index + index of time series to split + + Yields + ------ + train : pd.Index + Training window indices, loc references to training indices in y + test : pd.Index + Test window indices, loc references to test indices in y + """ + yield from self._repeat(y, method="split_loc") + + def _repeat(self, y, method="split"): + """Repeat the splitter. + + Parameters + ---------- + method : str, one of "split" and "split_loc", default="split" + method to repeat + + Yields + ------ + train : 1D np.ndarray of dtype int or pd.Index + Training window indices, iloc or loc references to training indices in y + test : 1D np.ndarray of dtype int or pd.Index + Test window indices, iloc or loc references to test indices in y + """ + random_repeat = self.random_repeat + + if random_repeat: + spl_clones = [self.splitter.clone() for _ in range(self.times)] + spl_gens = [getattr(spl, method)(y) for spl in spl_clones] + else: + one_clone = self.splitter.clone() + one_gen = getattr(one_clone, method)(y) + + if self.mode == "entry" and not random_repeat: + for train, test in one_gen: + for _ in range(self.times): + yield train, test + elif self.mode == "entry" and random_repeat: + for _ in range(self.times): + for spl_gen in spl_gens: + yield next(spl_gen) + elif self.mode == "sequence" and not random_repeat: + all_res = list(one_gen) + for _ in range(self.times): + for train, test in all_res: + yield train, test + elif self.mode == "sequence" and random_repeat: + for spl_gen in spl_gens: + yield from spl_gen + + def get_n_splits(self, y) -> int: + """Return the number of splits. + + Parameters + ---------- + y : pd.Series or pd.Index, optional (default=None) + Time series to split + + Returns + ------- + n_splits : int + The number of splits. + """ + return self._splitter.get_n_splits(y) * self.times + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the splitter. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + + Returns + ------- + params : dict or list of dict, default = {} + Parameters to create testing instances of the class + Each dict are parameters to construct an "interesting" test instance, i.e., + `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. + `create_test_instance` uses the first (or only) dictionary in `params` + """ + from sktime.split import ExpandingWindowSplitter + + modes = ["entry", "sequence"] + repeats = [True, False] + timess = [2, 3, 7] + + params = [] + for mode in modes: + for random_repeat in repeats: + for times in timess: + params.append( + { + "mode": mode, + "random_repeat": random_repeat, + "times": times, + "splitter": ExpandingWindowSplitter(), + } + ) + + return params diff --git a/sktime/split/cutoff.py b/sktime/split/cutoff.py index 8191514accb..b1b4554198e 100644 --- a/sktime/split/cutoff.py +++ b/sktime/split/cutoff.py @@ -6,6 +6,7 @@ __all__ = [ "CutoffSplitter", + "CutoffFhSplitter", ] from typing import Optional @@ -125,7 +126,7 @@ class CutoffSplitter(BaseSplitter): relative to the end of the training window. It will contain as many indices as there are forecasting horizons provided to the `fh` argument. - For a forecasating horizon :math:`(h_1,\ldots,h_H)`, the test window will + For a forecasting horizon :math:`(h_1,\ldots,h_H)`, the test window will consist of the indices :math:`(k_n+h_1,\ldots, k_n+h_H)`. The number of splits returned by `.get_n_splits` @@ -240,3 +241,117 @@ def get_test_params(cls, parameter_set="default"): `create_test_instance` uses the first (or only) dictionary in `params` """ return [{"cutoffs": np.array([3, 7, 10])}, {"cutoffs": [21, 22]}] + + +class CutoffFhSplitter(BaseSplitter): + r"""Temporal train-test splitter, based on cutoff and forecasting horizon. + + Train and test splits are determied as follows: + + for each cutoff point `k=cutoff[i]`, in `split`: + + * training fold is all loc indices up to and including `k` + * if `fh` is not passed, test fold is all loc indices strictly after `k` + * if `fh is passed`, test fold is all loc indices in `k + fh`, if `fh` is relative. + More precisely, `fh.to_absolute_index(cutoff=k) + If `fh` is absolute, then the test window is `fh` itself. + + It should be noted that, unlike in `CutoffSplitter`, + test folds are not determined by a window length, + but by indices of the forecasting horizon `fh`, i.e., test folds can be + non-contiguous, even if the data index is regular. + + Parameters + ---------- + cutoff : np.array or pd.Index + Cutoff points, positive and integer- or datetime-index like. + Type should match the type of `fh` input. + fh : None, ForecastingHorizon, int, timedelta, iterable of ints or timedeltas + Forecasting horizon, relative or absolute, to determine test folds. + Type should match the type of `cutoffs` input. + If not ForecastingHorizon, is coerced. + """ + + _tags = { + "split_hierarchical": False, + "split_series_uses": "loc", + } + + def __init__(self, cutoff, fh=None): + self.cutoff = cutoff + self.fh = fh + super().__init__(fh=fh) + + def _split_loc(self, y): + """Get loc references to train/test splits of `y`. + + private _split containing the core logic, called from split_loc + + Parameters + ---------- + y : pd.Index + index of time series to split + + Yields + ------ + train : pd.Index + Training window indices, loc references to training indices in y + test : pd.Index + Test window indices, loc references to test indices in y + """ + cutoff = self.cutoff + fh = self.fh + + if fh is not None: + from sktime.forecasting.base import ForecastingHorizon + + if not isinstance(fh, ForecastingHorizon): + fh = ForecastingHorizon(fh) + + for k in cutoff: + train = y[y <= k] + if fh is not None: + test = fh.to_absolute_index(cutoff=k) + else: + test = y[y > k] + yield train, test + + def get_n_splits(self, y=None) -> int: + """Return the number of splits. + + Since this splitter returns a single train/test split, + this number is trivially 1. + + Parameters + ---------- + y : pd.Series or pd.Index, optional (default=None) + Time series to split + + Returns + ------- + n_splits : int + The number of splits. + """ + return len(self.cutoffs) + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the splitter. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + + Returns + ------- + params : dict or list of dict, default = {} + Parameters to create testing instances of the class + Each dict are parameters to construct an "interesting" test instance, i.e., + `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. + `create_test_instance` uses the first (or only) dictionary in `params` + """ + params1 = {"cutoff": 3} + params2 = {"cutoff": [3, 4], "fh": [1, 2]} + return [params1, params2] diff --git a/sktime/split/expandinggreedy.py b/sktime/split/expandinggreedy.py index 5baf1f7bf66..b67e16a5440 100644 --- a/sktime/split/expandinggreedy.py +++ b/sktime/split/expandinggreedy.py @@ -7,6 +7,7 @@ __all__ = [ "ExpandingGreedySplitter", ] +__author__ = ["davidgilbertson"] import numpy as np import pandas as pd @@ -18,21 +19,28 @@ class ExpandingGreedySplitter(BaseSplitter): """Splitter that successively cuts test folds off the end of the series. - Takes an integer `test_size` that defines the number of steps included in the + Takes an integer ``test_size`` that defines the number of steps included in the test set of each fold. The train set of each fold will contain all data before - the test set. If the data contains multiple instances, `test_size` is + the test set. If the data contains multiple instances, ``test_size`` is _per instance_. - If no `step_length` is defined, the test sets (one for each fold) will be - adjacent, taken from the end of the dataset. + If no ``step_length`` is defined, the test sets (one for each fold) will be + adjacent and disjoint, taken from the end of the dataset. - For example, with `test_size=7` and `folds=5`, the test sets in total will cover + For example, with ``test_size=7`` and ``folds=5``, the test sets in total will cover the last 35 steps of the data with no overlap. Parameters ---------- - test_size : int - The number of steps included in the test set of each fold. + test_size : int or float + If int: the number of steps included in the test set of each fold. + Formally, steps are consecutive ``iloc`` indices. + If float: the proportion of steps included in the test set of each fold, + as a proportion of the total number of consecutive ``iloc`` indices. + Must be between 0.0 and 1.0. Proportions are rounded to the + next higher integer count of samples (ceil). + Cave: not the ``loc`` proportion between start and end locations, + but a proportion of total number of consecutive ``iloc`` indices. folds : int, default = 5 The number of folds. step_length : int, optional @@ -61,18 +69,29 @@ def __init__(self, test_size: int, folds: int = 5, step_length: int = None): self.step_length = step_length self.fh = np.arange(test_size) + 1 + # no algorithm implemented that is faster for float than naive iteration + if isinstance(test_size, float): + self.set_tags(**{"split_hierarchical": False}) + def _split(self, y: pd.Index) -> SPLIT_GENERATOR_TYPE: + test_size = self.test_size + + if isinstance(test_size, float): + _test_size = np.ceil(len(y) * test_size) + else: + _test_size = test_size + if isinstance(y, pd.MultiIndex): - groups = pd.Series(index=y).groupby(y.names[:-1]) + groups = pd.Series(index=y, dtype="float64").groupby(y.names[:-1]) reverse_idx = groups.transform("size") - groups.cumcount() - 1 else: reverse_idx = np.arange(len(y))[::-1] - step_length = self.step_length or self.test_size + step_length = self.step_length or _test_size for i in reversed(range(self.folds)): tst_end = i * step_length - trn_end = tst_end + self.test_size + trn_end = tst_end + _test_size trn_indices = np.flatnonzero(reverse_idx >= trn_end) tst_indices = np.flatnonzero( (reverse_idx < trn_end) & (reverse_idx >= tst_end) @@ -99,4 +118,5 @@ def get_test_params(cls, parameter_set="default"): """ params1 = {"test_size": 1} params2 = {"test_size": 3, "folds": 2, "step_length": 2} - return [params1, params2] + params3 = {"test_size": 0.2, "folds": 2} + return [params1, params2, params3] diff --git a/sktime/split/sameloc.py b/sktime/split/sameloc.py index 040c748d301..c94e1bb6cb6 100644 --- a/sktime/split/sameloc.py +++ b/sktime/split/sameloc.py @@ -141,10 +141,7 @@ def get_test_params(cls, parameter_set="default"): `create_test_instance` uses the first (or only) dictionary in `params` """ from sktime.datasets import load_airline - from sktime.forecasting.model_selection import ( - ExpandingWindowSplitter, - SingleWindowSplitter, - ) + from sktime.split import ExpandingWindowSplitter, SingleWindowSplitter y = load_airline() y_temp = y[:60] diff --git a/sktime/split/slidingwindow.py b/sktime/split/slidingwindow.py index 031ffe6e28f..ed55667e4ed 100644 --- a/sktime/split/slidingwindow.py +++ b/sktime/split/slidingwindow.py @@ -51,9 +51,9 @@ class SlidingWindowSplitter(BaseWindowSplitter): Parameters ---------- - fh : int, list or np.array + fh : int, list or np.array, optional (default=1) Forecasting horizon - window_length : int or timedelta or pd.DateOffset + window_length : int or timedelta or pd.DateOffset, optional (default=10) Window length step_length : int or timedelta or pd.DateOffset, optional (default=1) Step length between windows diff --git a/sktime/split/temporal_train_test_split.py b/sktime/split/temporal_train_test_split.py index 2509b0ec9af..55e7e91956d 100644 --- a/sktime/split/temporal_train_test_split.py +++ b/sktime/split/temporal_train_test_split.py @@ -91,8 +91,8 @@ def temporal_train_test_split( Examples -------- - >>> from sktime.forecasting.model_selection import temporal_train_test_split >>> from sktime.datasets import load_airline, load_osuleaf + >>> from sktime.split import temporal_train_test_split >>> from sktime.utils._testing.panel import _make_panel >>> # univariate time series >>> y = load_airline() diff --git a/sktime/split/testplustrain.py b/sktime/split/testplustrain.py index 73981a9c661..a803a52c9f0 100644 --- a/sktime/split/testplustrain.py +++ b/sktime/split/testplustrain.py @@ -131,10 +131,7 @@ def get_test_params(cls, parameter_set="default"): `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. `create_test_instance` uses the first (or only) dictionary in `params` """ - from sktime.forecasting.model_selection import ( - ExpandingWindowSplitter, - SingleWindowSplitter, - ) + from sktime.split import ExpandingWindowSplitter, SingleWindowSplitter cv_1 = ExpandingWindowSplitter(fh=[2, 4], initial_window=24, step_length=12) cv_2 = SingleWindowSplitter(fh=[2, 4], window_length=24) diff --git a/sktime/split/tests/test_cutoff.py b/sktime/split/tests/test_cutoff.py index ddd3aa94b4c..8afe761153e 100644 --- a/sktime/split/tests/test_cutoff.py +++ b/sktime/split/tests/test_cutoff.py @@ -2,6 +2,7 @@ """Tests for cutoff splitter.""" import numpy as np +import pandas as pd import pytest from sktime.forecasting.tests._config import ( @@ -11,7 +12,7 @@ TEST_WINDOW_LENGTHS, TEST_YS, ) -from sktime.split import CutoffSplitter +from sktime.split import CutoffFhSplitter, CutoffSplitter from sktime.split.base._common import _inputs_are_supported from sktime.split.tests.test_split import _check_cv @@ -30,3 +31,30 @@ def test_cutoff_window_splitter(y, cutoffs, fh, window_length): match = "Unsupported combination of types" with pytest.raises(TypeError, match=match): CutoffSplitter(cutoffs, fh=fh, window_length=window_length) + + +def test_cutoff_fh_splitter(): + """Test CutoffFhSplitter.""" + from sktime.forecasting.base import ForecastingHorizon + from sktime.utils._testing.series import _make_series + + y = _make_series() + cutoff = y.index[[10]] + cutoff.freq = y.index.freq + fh = ForecastingHorizon([1, 2, 3], freq=y.index.freq) + + spl = CutoffFhSplitter(cutoff, fh) + + spl_tt = list(spl.split_loc(y))[0] + spl_train = spl_tt[0] + spl_test = spl_tt[1] + + assert isinstance(spl_train, pd.DatetimeIndex) + assert isinstance(spl_test, pd.DatetimeIndex) + + assert np.all(spl_train == y.index[:11]) + + expected_test = pd.DatetimeIndex( + ["2000-01-12", "2000-01-13", "2000-01-14"], dtype="datetime64[ns]", freq="D" + ) + assert np.all(spl_test == expected_test) diff --git a/sktime/tests/_config.py b/sktime/tests/_config.py index 989d1335bd0..7a9aabbf502 100644 --- a/sktime/tests/_config.py +++ b/sktime/tests/_config.py @@ -77,6 +77,7 @@ "test_persistence_via_pickle", "test_fit_does_not_overwrite_hyper_params", "test_save_estimators_to_file", + "test_multiprocessing_idempotent", # see 5658 ], "ProximityForest": [ "test_persistence_via_pickle", @@ -116,6 +117,11 @@ "MLPClassifier": [ "test_fit_idempotent", ], + "CNTCClassifier": [ + "test_fit_idempotent", + "test_persistence_via_pickle", + "test_save_estimators_to_file", + ], "InceptionTimeClassifier": [ "test_fit_idempotent", ], @@ -178,6 +184,11 @@ "test_hierarchical_with_exogeneous", # refer to #4743 ], "Pipeline": ["test_inheritance"], # does not inherit from intermediate base classes + # networks do not support negative fh + "LTSFLinearForecaster": ["test_predict_time_index_in_sample_full"], + "LTSFDLinearForecaster": ["test_predict_time_index_in_sample_full"], + "LTSFNLinearForecaster": ["test_predict_time_index_in_sample_full"], + "WEASEL": ["test_multiprocessing_idempotent"], # see 5658 } # We use estimator tags in addition to class hierarchies to further distinguish diff --git a/sktime/tests/test_all_estimators.py b/sktime/tests/test_all_estimators.py index 6d6b35bcbe5..f7ad4ef4a78 100644 --- a/sktime/tests/test_all_estimators.py +++ b/sktime/tests/test_all_estimators.py @@ -42,7 +42,6 @@ from sktime.utils._testing._conditional_fixtures import ( create_conditional_fixtures_and_names, ) -from sktime.utils._testing.deep_equals import deep_equals from sktime.utils._testing.estimator_checks import ( _assert_array_almost_equal, _assert_array_equal, @@ -51,6 +50,7 @@ _list_required_methods, ) from sktime.utils._testing.scenarios_getter import retrieve_scenarios +from sktime.utils.deep_equals import deep_equals from sktime.utils.random_state import set_random_state from sktime.utils.sampling import random_partition from sktime.utils.validation._dependencies import _check_soft_dependencies @@ -876,6 +876,10 @@ def test_inheritance(self, estimator_class): f"estimator: {estimator_class} has fit method, but" f"is not a sub-class of BaseEstimator." ) + from sktime.pipeline import Pipeline + + if issubclass(estimator_class, Pipeline): + return # Usually estimators inherit only from one BaseEstimator type, but in some cases # they may be predictor and transformer at the same time (e.g. pipelines) @@ -1428,8 +1432,6 @@ def test_save_estimators_to_file( err_msg=msg, ) - # todo: this needs to be diagnosed and fixed - temporary skip - @pytest.mark.skip(reason="hangs on mac and unix remote tests") def test_multiprocessing_idempotent( self, estimator_instance, scenario, method_nsc_arraylike ): @@ -1443,29 +1445,39 @@ def test_multiprocessing_idempotent( method_nsc = method_nsc_arraylike params = estimator_instance.get_params() - if "n_jobs" in params: - # run on a single process - # ----------------------- - estimator = deepcopy(estimator_instance) - estimator.set_params(n_jobs=1) - set_random_state(estimator) - result_single_process = scenario.run( - estimator, method_sequence=["fit", method_nsc] - ) + # test runs only if n_jobs is a parameter of the estimator + if "n_jobs" not in params: + return None - # run on multiple processes - # ------------------------- - estimator = deepcopy(estimator_instance) - estimator.set_params(n_jobs=-1) - set_random_state(estimator) - result_multiple_process = scenario.run( - estimator, method_sequence=["fit", method_nsc] - ) - _assert_array_equal( - result_single_process, - result_multiple_process, - err_msg="Results are not equal for n_jobs=1 and n_jobs=-1", - ) + # skip test for predict_proba + # this produces a BaseDistribution object, for which no ready + # equality check is implemented + if method_nsc == "predict_proba": + return None + + # run on a single process + # ----------------------- + estimator = deepcopy(estimator_instance) + estimator.set_params(n_jobs=1) + set_random_state(estimator) + result_single_process = scenario.run( + estimator, method_sequence=["fit", method_nsc] + ) + + # run on multiple processes + # ------------------------- + estimator = deepcopy(estimator_instance) + estimator.set_params(n_jobs=-1) + set_random_state(estimator) + result_multiple_process = scenario.run( + estimator, method_sequence=["fit", method_nsc] + ) + + _assert_array_equal( + result_single_process, + result_multiple_process, + err_msg="Results are not equal for n_jobs=1 and n_jobs=-1", + ) def test_dl_constructor_initializes_deeply(self, estimator_class): """Test DL estimators that they pass custom parameters to underlying Network.""" diff --git a/sktime/tests/test_class_register.py b/sktime/tests/test_class_register.py new file mode 100644 index 00000000000..f7839bb358f --- /dev/null +++ b/sktime/tests/test_class_register.py @@ -0,0 +1,116 @@ +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +"""Registry and dispatcher for test classes. + +Module does not contain tests, only test utilities. +""" + +__author__ = ["fkiraly"] + +from inspect import isclass + + +def get_test_class_registry(): + """Return test class registry. + + Wrapped in a function to avoid circular imports. + + Returns + ------- + testclass_dict : dict + test class registry + keys are scitypes, values are test classes TestAll[Scitype] + """ + from sktime.alignment.tests.test_all_aligners import TestAllAligners + from sktime.classification.early_classification.tests.test_all_early_classifiers import ( # noqa E501 + TestAllEarlyClassifiers, + ) + from sktime.classification.tests.test_all_classifiers import TestAllClassifiers + from sktime.dists_kernels.tests.test_all_dist_kernels import ( + TestAllPairwiseTransformers, + TestAllPanelTransformers, + ) + from sktime.forecasting.tests.test_all_forecasters import TestAllForecasters + from sktime.param_est.tests.test_all_param_est import TestAllParamFitters + from sktime.proba.tests.test_all_distrs import TestAllDistributions + from sktime.regression.tests.test_all_regressors import TestAllRegressors + from sktime.tests.test_all_estimators import TestAllEstimators, TestAllObjects + from sktime.transformations.tests.test_all_transformers import TestAllTransformers + + testclass_dict = dict() + # every object in sktime inherits from BaseObject + # "object" tests are run for all objects + testclass_dict["object"] = TestAllObjects + # fittable objects inherit from BaseEstimator + # "estimator" tests are run for all estimators + # estimators are also objects + testclass_dict["estimator"] = TestAllEstimators + # more specific base classes + # these inherit either from BaseEstimator or BaseObject, + # so also imply estimator and object tests, or only object tests + testclass_dict["aligner"] = TestAllAligners + testclass_dict["classifier"] = TestAllClassifiers + testclass_dict["distribution"] = TestAllDistributions + testclass_dict["early_classifier"] = TestAllEarlyClassifiers + testclass_dict["forecaster"] = TestAllForecasters + testclass_dict["param_est"] = TestAllParamFitters + testclass_dict["regressor"] = TestAllRegressors + testclass_dict["transformer"] = TestAllTransformers + testclass_dict["transformer-pairwise"] = TestAllPairwiseTransformers + testclass_dict["transformer-pairwise-panel"] = TestAllPanelTransformers + + return testclass_dict + + +def get_test_classes_for_obj(obj): + """Get all test classes relevant for an object or estimator. + + Parameters + ---------- + obj : object or estimator, descendant of sktime BaseObject or BaseEstimator + object or estimator for which to get test classes + + Returns + ------- + test_classes : list of test classes + list of test classes relevant for obj + these are references to the actual classes, not strings + if obj was not a descendant of BaseObject or BaseEstimator, returns empty list + """ + from sktime.base import BaseEstimator, BaseObject + from sktime.registry import scitype + + def is_object(obj): + """Return whether obj is an estimator class or estimator object.""" + if isclass(obj): + return issubclass(obj, BaseObject) + else: + return isinstance(obj, BaseObject) + + def is_estimator(obj): + """Return whether obj is an estimator class or estimator object.""" + if isclass(obj): + return issubclass(obj, BaseEstimator) + else: + return isinstance(obj, BaseEstimator) + + if not is_object(obj): + return [] + + testclass_dict = get_test_class_registry() + + # we always need to run "object" tests + test_clss = [testclass_dict["object"]] + + if is_estimator(obj): + test_clss += [testclass_dict["estimator"]] + + try: + obj_scitypes = scitype(obj, force_single_scitype=False, coerce_to_list=True) + except Exception: + obj_scitypes = [] + + for obj_scitype in obj_scitypes: + if obj_scitype in testclass_dict: + test_clss += [testclass_dict[obj_scitype]] + + return test_clss diff --git a/sktime/tests/test_switch.py b/sktime/tests/test_switch.py index 1daf04cd692..742cc457d03 100644 --- a/sktime/tests/test_switch.py +++ b/sktime/tests/test_switch.py @@ -1,5 +1,8 @@ # copyright: sktime developers, BSD-3-Clause License (see LICENSE file) -"""Switch utility for determining whether tests for a class should be run or not.""" +"""Switch utility for determining whether tests for a class should be run or not. + +Module does not contain tests, only test utilities. +""" __author__ = ["fkiraly"] @@ -13,17 +16,36 @@ def run_test_for_class(cls): 1. whether all required soft dependencies are present. If not, does not run the test. - 2. If yes: - * if ONLY_CHANGED_MODULES setting is on, runs the test if and only - if the module containing the class/func has changed according to is_class_changed - * if ONLY_CHANGED_MODULES if off, always runs the test if all soft dependencies - are present. + If yes, behaviour depends on ONLY_CHANGED_MODULES setting: + if off (False), always runs the test (return True); + if on (True), runs test if and only if + at least one of conditions 2, 3, 4 below are met. + + 2. Condition 2: + + If the module containing the class/func has changed according to is_class_changed, + or one of the modules containing any parent classes in sktime, + then condition 2 is met. + + 3. Condition 3: + + If the object is an sktime ``BaseObject``, and one of the test classes + covering the class have changed, then condition 3 is met. + + 4. Condition 4: + + If the object is an sktime ``BaseObject``, and the package requirements + for any of its dependencies have changed in ``pyproject.toml``, + condition 4 is met. cls can also be a list of classes or functions, - in this case the test is run if and only if: + in this case the test is run if and only if both of the following are True: * all required soft dependencies are present - * if yes, if any of the estimators in the list should be tested by criterion 2 above + * if ``ONLY_CHANGED_MODULES`` is True, additionally, + if any of the estimators in the list should be tested by + at least one of criteria 2-4 above. + If ``ONLY_CHANGED_MODULES`` is False, this condition is always True. Parameters ---------- @@ -39,9 +61,11 @@ class for which to determine whether it should be tested cls = [cls] from sktime.tests.test_all_estimators import ONLY_CHANGED_MODULES - from sktime.utils.git_diff import is_class_changed + from sktime.utils.git_diff import get_packages_with_changed_specs, is_class_changed from sktime.utils.validation._dependencies import _check_estimator_deps + PACKAGE_REQ_CHANGED = get_packages_with_changed_specs() + def _required_deps_present(obj): """Check if all required soft dependencies are present, return bool.""" if hasattr(obj, "get_class_tag"): @@ -62,15 +86,53 @@ def _is_class_changed_or_sktime_parents(cls): ] return any(is_class_changed(x) for x in cls_and_sktime_parents) + def _tests_covering_class_changed(cls): + """Check if any of the tests covering cls have changed, return bool.""" + from sktime.tests.test_class_register import get_test_classes_for_obj + + test_classes = get_test_classes_for_obj(cls) + return any(is_class_changed(x) for x in test_classes) + + def _is_impacted_by_pyproject_change(cls): + """Check if the dep specifcations of cls have changed, return bool.""" + from packaging.requirements import Requirement + + if not isclass(cls) or not hasattr(cls, "get_class_tags"): + return False + + cls_reqs = cls.get_class_tag("python_dependencies", []) + if cls_reqs is None: + cls_reqs = [] + if not isinstance(cls_reqs, list): + cls_reqs = [cls_reqs] + package_deps = [Requirement(req).name for req in cls_reqs] + + return any(x in PACKAGE_REQ_CHANGED for x in package_deps) + + # Condition 1: # if any of the required soft dependencies are not present, do not run the test if not all(_required_deps_present(x) for x in cls): return False + # otherwise, continue + + # if ONLY_CHANGED_MODULES is off: always True + # tests are always run if soft dependencies are present + if not ONLY_CHANGED_MODULES: + return True - # if ONLY_CHANGED_MODULES is on, run the test if and only if + # Condition 2: # any of the modules containing any of the classes in the list have changed - if ONLY_CHANGED_MODULES: - return any(_is_class_changed_or_sktime_parents(x) for x in cls) + # or any of the modules containing any parent classes in sktime have changed + cond2 = any(_is_class_changed_or_sktime_parents(x) for x in cls) + + # Condition 3: + # if the object is an sktime BaseObject, and one of the test classes + # covering the class have changed, then run the test + cond3 = any(_tests_covering_class_changed(x) for x in cls) + + # Condition 4: + # the package requirements for any dependency in pyproject.toml have changed + cond4 = any(_is_impacted_by_pyproject_change(x) for x in cls) - # otherwise - # i.e., dependencies are present, and differential testing is disabled - return True + # run the test if and only if at least one of the conditions 2-4 are met + return cond2 or cond3 or cond4 diff --git a/sktime/transformations/base.py b/sktime/transformations/base.py index 430037f06d4..7bc2c0577db 100644 --- a/sktime/transformations/base.py +++ b/sktime/transformations/base.py @@ -56,6 +56,7 @@ class name: BaseTransformer from sktime.base import BaseEstimator from sktime.datatypes import ( VectorizedDF, + check_is_error_msg, check_is_mtype, check_is_scitype, convert, @@ -132,11 +133,14 @@ class BaseTransformer(BaseEstimator): # todo: rename to capability:missing_values "capability:missing_values:removes": False, # is transform result always guaranteed to contain no missing values? - "python_version": None, # PEP 440 python version specifier to limit versions "remember_data": False, # whether all data seen is remembered as self._X + "python_version": None, # PEP 440 python version specifier to limit versions + "authors": "sktime developers", # author(s) of the object + "maintainers": "sktime developers", # current maintainer(s) of the object } # default config values + # see set_config documentation for details _config = { "input_conversion": "on", # controls input checks and conversions, @@ -155,46 +159,31 @@ class BaseTransformer(BaseEstimator): # {None, "dask", "loky", "multiprocessing", "threading"} # None: no parallelization # "loky", "multiprocessing" and "threading": uses `joblib` Parallel loops + # "joblib": uses custom joblib backend, set via `joblib_backend` tag # "dask": uses `dask`, requires `dask` package in environment "backend:parallel:params": None, # params for parallelization backend } _config_doc = { - "backend:parallel": """ - backend:parallel : str, optional, default="None" - backend to use for parallelization when broadcasting/vectorizing, one of - - - "None": executes loop sequentally, simple list comprehension - - "loky", "multiprocessing" and "threading": uses ``joblib`` ``Parallel`` - - "dask": uses ``dask``, requires ``dask`` package in environment - """, - "backend:parallel:params": """ - backend:parallel:params : dict, optional, default={} (no parameters passed) - additional parameters passed to the parallelization backend as config. - Valid keys depend on the value of ``backend:parallel``: - - - "None": no additional parameters, ``backend_params`` is ignored - - "loky", "multiprocessing" and "threading": - any valid keys for ``joblib.Parallel`` can be passed here, - e.g., ``n_jobs``, with the exception of ``backend`` which is directly - controlled by ``backend:parallel`` - - "dask": any valid keys for ``dask.compute`` - can be passed, e.g., ``scheduler`` - """, "input_conversion": """ - input_conversion : str, one of "on", "off", valid mtype string + input_conversion : str, one of "on" (default), "off", or valid mtype string controls input checks and conversions, - for _fit, _transform, _inverse_transform, _update - "on" - input check and conversion is carried out - "off" - input check and conversion not done before passing to inner methods - valid mtype string - input is assumed to specified mtype + for ``_fit``, ``_transform``, ``_inverse_transform``, ``_update`` + + * ``"on"`` - input check and conversion is carried out + * ``"off"`` - input check and conversion are not carried out + before passing data to inner methods + * valid mtype string - input is assumed to specified mtype, + conversion is carried out but no check """, "output_conversion": """ output_conversion : str, one of "on", "off", valid mtype string - controls output conversion for _transform, _inverse_transform - "on" - if input_conversion is "on", output conversion is carried out - "off" - output of _transform, _inverse_transform is directly returned - valid mtype string - output is converted to specified mtype + controls output conversion for ``_transform``, ``_inverse_transform`` + + * ``"on"`` - if input_conversion is "on", output conversion is carried out + * ``"off"`` - output of ``_transform``, ``_inverse_transform`` + is directly returned + * valid mtype string - output is converted to specified mtype """, } @@ -219,6 +208,24 @@ def __init__(self): super().__init__() _check_estimator_deps(self) + def _is_transformer(self, other): + """Check whether other is a transformer - sklearn or sktime. + + Returns True iff at least one of the following is True: + + * ``is_sklearn_transformer(other)`` + * ``scitype(other) == "transformer"`` + + Parameters + ---------- + other : object + object to check + """ + from sktime.registry import scitype + + is_sktime_transformr = scitype(other, raise_on_unknown=False) == "transformer" + return is_sklearn_transformer(other) or is_sktime_transformr + def __mul__(self, other): """Magic * method, return (right) concatenated TransformerPipeline. @@ -226,7 +233,7 @@ def __mul__(self, other): Parameters ---------- - other: `sktime` transformer, must inherit from BaseTransformer + other: ``sktime`` or ``sklearn`` compatible transformer otherwise, `NotImplemented` is returned Returns @@ -239,11 +246,10 @@ def __mul__(self, other): # we wrap self in a pipeline, and concatenate with the other # the TransformerPipeline does the rest, e.g., case distinctions on other if ( - isinstance(other, BaseTransformer) + self._is_transformer(other) or is_sklearn_classifier(other) or is_sklearn_clusterer(other) or is_sklearn_regressor(other) - or is_sklearn_transformer(other) ): self_as_pipeline = TransformerPipeline(steps=[self]) return self_as_pipeline * other @@ -257,7 +263,7 @@ def __rmul__(self, other): Parameters ---------- - other: `sktime` transformer, must inherit from BaseTransformer + other: ``sktime`` or ``sklearn`` compatible transformer otherwise, `NotImplemented` is returned Returns @@ -269,7 +275,7 @@ def __rmul__(self, other): # we wrap self in a pipeline, and concatenate with the other # the TransformerPipeline does the rest, e.g., case distinctions on other - if isinstance(other, BaseTransformer) or is_sklearn_transformer(other): + if self._is_transformer(other): self_as_pipeline = TransformerPipeline(steps=[self]) return other * self_as_pipeline else: @@ -282,7 +288,8 @@ def __or__(self, other): Parameters ---------- - other: `sktime` transformer or sktime MultiplexTransformer + other: ``sktime`` or ``sklearn`` compatible transformer + otherwise, `NotImplemented` is returned Returns ------- @@ -290,7 +297,7 @@ def __or__(self, other): """ from sktime.transformations.compose import MultiplexTransformer - if isinstance(other, BaseTransformer): + if self._is_transformer(other): multiplex_self = MultiplexTransformer([self]) return multiplex_self | other else: @@ -303,7 +310,7 @@ def __add__(self, other): Parameters ---------- - other: `sktime` transformer, must inherit from BaseTransformer + other: ``sktime`` or ``sklearn`` compatible transformer otherwise, `NotImplemented` is returned Returns @@ -315,7 +322,7 @@ def __add__(self, other): # we wrap self in a pipeline, and concatenate with the other # the FeatureUnion does the rest, e.g., case distinctions on other - if isinstance(other, BaseTransformer): + if self._is_transformer(other): self_as_pipeline = FeatureUnion(transformer_list=[self]) return self_as_pipeline + other else: @@ -328,7 +335,7 @@ def __radd__(self, other): Parameters ---------- - other: `sktime` transformer, must inherit from BaseTransformer + other: ``sktime`` or ``sklearn`` compatible transformer otherwise, `NotImplemented` is returned Returns @@ -340,7 +347,7 @@ def __radd__(self, other): # we wrap self in a pipeline, and concatenate with the other # the TransformerPipeline does the rest, e.g., case distinctions on other - if isinstance(other, BaseTransformer): + if self._is_transformer(other): self_as_pipeline = FeatureUnion(transformer_list=[self]) return other + self_as_pipeline else: @@ -591,7 +598,7 @@ def transform(self, X, y=None): output_conv = configs["output_conversion"] # convert to output mtype - if X is None: + if X is None or Xt is None: X_out = Xt elif input_conv and output_conv: X_out = self._convert_output(Xt, metadata=metadata) @@ -952,7 +959,11 @@ def _most_complex_scitype(scitypes, smaller_equal_than=None): elif smaller_equal_than is not None: return _most_complex_scitype(scitypes) else: - raise ValueError("no series scitypes supported, bug in estimator") + raise ValueError( + f"Error in {type(self).__name__}, no series scitypes supported, " + "likely a bug in estimator: scitypes arg passed to " + f"_most_complex_scitype are {scitypes}" + ) def _scitype_A_higher_B(scitypeA, scitypeB): """Compare two scitypes regarding complexity.""" @@ -983,32 +994,27 @@ def _scitype_A_higher_B(scitypeA, scitypeB): var_name="X", ) - msg_invalid_input = ( - f"must be in an sktime compatible format, " - f"of scitype Series, Panel or Hierarchical, " - f"for instance a pandas.DataFrame with sktime compatible time indices, " - f"or with MultiIndex and last(-1) level an sktime compatible time index. " - f"Allowed compatible mtype format specifications are: {ALLOWED_MTYPES} ." - # f"See the transformers tutorial examples/05_transformers.ipynb, or" - f" See the data format tutorial examples/AA_datatypes_and_datasets.ipynb. " - f"If you think the data is already in an sktime supported input format, " - f"run sktime.datatypes.check_raise(data, mtype) to diagnose the error, " - f"where mtype is the string of the type specification you want. " - f"Error message for checked mtypes, in format [mtype: message], as follows:" - ) - if not X_valid: - for mtype, err in msg.items(): - msg_invalid_input += f" [{mtype}: {err}] " - raise TypeError("X " + msg_invalid_input) - X_scitype = X_metadata["scitype"] X_mtype = X_metadata["mtype"] # remember these for potential back-conversion (in transform etc) metadata["_X_mtype_last_seen"] = X_mtype metadata["_X_input_scitype"] = X_scitype - if X_mtype not in ALLOWED_MTYPES: - raise TypeError("X " + msg_invalid_input) + # raise informative error message if X is in wrong format + allowed_msg = ( + f"Allowed scitypes for X in transformations are " + f"Series, Panel or Hierarchical, " + f"for instance a pandas.DataFrame with sktime compatible time indices, " + f"or with MultiIndex and last(-1) level an sktime compatible time index. " + f"Allowed compatible mtype format specifications are: {ALLOWED_MTYPES} ." + ) + msg_start = f"Unsupported input data type in {self.__class__.__name__}, input " + msg_X = msg_start + "X" + if not X_valid or X_mtype not in ALLOWED_MTYPES: + msg = {k: v for k, v in msg.items() if k in ALLOWED_MTYPES} + check_is_error_msg( + msg, var_name=msg_X, allowed_msg=allowed_msg, raise_exception=True + ) if X_scitype in X_inner_scitype: case = "case 1: scitype supported" @@ -1041,14 +1047,21 @@ def _scitype_A_higher_B(scitypeA, scitypeB): y_valid, msg, y_metadata = check_is_scitype( y, scitype=y_possible_scitypes, return_metadata=[], var_name="y" ) - if not y_valid: - for mtype, err in msg.items(): - msg_invalid_input += f" [{mtype}: {err}] " - raise TypeError("y " + msg_invalid_input) - y_scitype = y_metadata["scitype"] y_mtype = y_metadata["mtype"] + # raise informative error message if y is is in wrong format + if not y_valid: + allowed_msg = ( + f"Allowed scitypes for y in transformations depend on X passed. " + f"Passed X scitype was {X_scitype}, " + f"so allowed scitypes for y are {y_possible_scitypes}. " + ) + msg_y = msg_start + "y" + check_is_error_msg( + msg, var_name=msg_y, allowed_msg=allowed_msg, raise_exception=True + ) + else: # y_scitype is used below - set to None if y is None y_scitype = None @@ -1177,10 +1190,20 @@ def _convert_output(self, X, metadata, inverse=False): # skipped for output_scitype = "Primitives" # since then the output always is a pd.DataFrame if case == "case 2: higher scitype supported" and output_scitype == "Series": - Xt = convert_to( - Xt, - to_type=["pd-multiindex", "numpy3D", "df-list", "pd_multiindex_hier"], - ) + if self.get_tags()["scitype:transform-input"] == "Panel": + # Conversion from Series to Panel done for being compatible with + # algorithm. Thus, the returned Series should stay a Series. + pass + else: + Xt = convert_to( + Xt, + to_type=[ + "pd-multiindex", + "numpy3D", + "df-list", + "pd_multiindex_hier", + ], + ) Xt = convert_to_scitype(Xt, to_scitype=X_input_scitype) # now, in all cases, Xt is in the right scitype, @@ -1194,7 +1217,6 @@ def _convert_output(self, X, metadata, inverse=False): if output_scitype == "Series": # output mtype is input mtype X_output_mtype = X_input_mtype - # exception to this: if the transformer outputs multivariate series, # we cannot convert back to pd.Series, do pd.DataFrame instead then # this happens only for Series, not Panel @@ -1207,6 +1229,7 @@ def _convert_output(self, X, metadata, inverse=False): valid, msg, metadata = check_is_mtype( Xt, ["pd.DataFrame", "pd.Series", "np.ndarray"], + msg_return_dict="list", return_metadata=Xt_metadata_required, ) @@ -1219,6 +1242,13 @@ def _convert_output(self, X, metadata, inverse=False): ) if X_input_mtype == "pd.Series" and not metadata["is_univariate"]: X_output_mtype = "pd.DataFrame" + elif self.get_tags()["scitype:transform-input"] == "Panel": + # Input has always to be Panel + X_output_mtype = "pd.DataFrame" + else: + # Input can be Panel or Hierarchical, since it is supported + # by the used mtype + output_scitype = X_input_scitype # Xt_mtype = metadata["mtype"] # else: # Xt_mtype = X_input_mtype @@ -1231,10 +1261,10 @@ def _convert_output(self, X, metadata, inverse=False): # store=_converter_store_X, # store_behaviour="freeze", # ) - Xt = convert_to( + return convert_to( Xt, to_type=X_output_mtype, - as_scitype=X_input_scitype, + as_scitype=output_scitype, store=_converter_store_X, store_behaviour="freeze", ) @@ -1250,7 +1280,7 @@ def _convert_output(self, X, metadata, inverse=False): # else this is only zeros and should be reset to RangeIndex else: Xt = Xt.reset_index(drop=True) - Xt = convert_to( + return convert_to( Xt, to_type="pd_DataFrame_Table", as_scitype="Table", @@ -1305,9 +1335,19 @@ def _vectorize(self, methodname, **kwargs): n_fit = n * m if n_trafos != n_fit: raise RuntimeError( + f"{type(self).__name__} is a transformer that applies per " + "individual time series, and broadcasts across instances. " + f"In fit, {type(self).__name__} makes one fit per instance, " + "and applies that fit to the instance with the same index in " + "transform. Vanilla use therefore requires the same number " + "of instances in fit and transform, but" "found different number of instances in transform than in fit. " f"number of instances seen in fit: {n_fit}; " - f"number of instances seen in transform: {n_trafos}" + f"number of instances seen in transform: {n_trafos}. " + "For fit/transforming per instance, e.g., for pre-processinng " + "in a time series classification, regression or clustering " + "pipeline, wrap this transformer in " + "FitInTransform, from sktime.transformations.compose." ) transformers_ = self.transformers_ @@ -1441,6 +1481,10 @@ def _update(self, X, y=None): return self +# initialize dynamic docstrings +BaseTransformer._init_dynamic_doc() + + class _SeriesToPrimitivesTransformer(BaseTransformer): """Transformer base class for series to primitive(s) transforms.""" diff --git a/sktime/transformations/bootstrap/_mbb.py b/sktime/transformations/bootstrap/_mbb.py index 53bef156d80..574e6b6be1b 100644 --- a/sktime/transformations/bootstrap/_mbb.py +++ b/sktime/transformations/bootstrap/_mbb.py @@ -40,7 +40,7 @@ class STLBootstrapTransformer(BaseTransformer): Parameters ---------- n_series : int, optional - The number of bootstraped time series that will be generated, by default 10. + The number of bootstrapped time series that will be generated, by default 10. sp : int, optional Seasonal periodicity of the data in integer form, by default 12. Must be an integer >= 2 @@ -165,6 +165,12 @@ class STLBootstrapTransformer(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": "ltsaprounis", + "python_dependencies": "statsmodels", + # estimator type + # -------------- # todo: what is the scitype of X: Series, or Panel "scitype:transform-input": "Series", # todo: what scitype is returned: Primitives, Series, Panel @@ -183,7 +189,6 @@ class STLBootstrapTransformer(BaseTransformer): "enforce_index_type": None, # index type that needs to be enforced in X/y "fit_is_empty": False, # is fit empty and can be skipped? Yes = True "transform-returns-same-time-index": False, - "python_dependencies": "statsmodels", } def __init__( @@ -422,7 +427,7 @@ class MovingBlockBootstrapTransformer(BaseTransformer): Parameters ---------- n_series : int, optional - The number of bootstraped time series that will be generated, by default 10 + The number of bootstrapped time series that will be generated, by default 10 block_length : int, optional The length of the block in the MBB method, by default None. If not provided, the following heuristic is used, the block length will the diff --git a/sktime/transformations/bootstrap/_splitterboot.py b/sktime/transformations/bootstrap/_splitterboot.py index 4804eca2c1b..7c4b13cbf92 100644 --- a/sktime/transformations/bootstrap/_splitterboot.py +++ b/sktime/transformations/bootstrap/_splitterboot.py @@ -86,11 +86,11 @@ class SplitterBootstrapTransformer(BaseTransformer): """ _tags = { - # todo: what is the scitype of X: Series, or Panel + # what is the scitype of X: Series, or Panel "scitype:transform-input": "Series", - # todo: what scitype is returned: Primitives, Series, Panel + # what scitype is returned: Primitives, Series, Panel "scitype:transform-output": "Panel", - # todo: what is the scitype of y: None (not needed), Primitives, Series, Panel + # what is the scitype of y: None (not needed), Primitives, Series, Panel "scitype:transform-labels": "None", "scitype:instancewise": True, # is this an instance-wise transform? "X_inner_mtype": "pd.DataFrame", # which mtypes do _fit/_predict support for X? diff --git a/sktime/transformations/compose/_column.py b/sktime/transformations/compose/_column.py index e0c1af86bbe..5e09e2a71c2 100644 --- a/sktime/transformations/compose/_column.py +++ b/sktime/transformations/compose/_column.py @@ -120,6 +120,7 @@ class ColumnEnsembleTransformer( """ _tags = { + "authors": ["fkiraly", "mloning"], "X_inner_mtype": PANDAS_MTYPES, "y_inner_mtype": PANDAS_MTYPES, "fit_is_empty": False, diff --git a/sktime/transformations/compose/_featureunion.py b/sktime/transformations/compose/_featureunion.py index db6e80937d9..d2c83880d4c 100644 --- a/sktime/transformations/compose/_featureunion.py +++ b/sktime/transformations/compose/_featureunion.py @@ -8,6 +8,7 @@ from sktime.base._meta import _HeterogenousMetaEstimator from sktime.transformations.base import BaseTransformer +from sktime.transformations.compose._common import _coerce_to_sktime from sktime.utils.multiindex import flatten_multiindex @@ -42,6 +43,7 @@ class FeatureUnion(_HeterogenousMetaEstimator, BaseTransformer): """ _tags = { + "authors": ["fkiraly", "mloning"], "scitype:transform-input": "Series", "scitype:transform-output": "Series", "scitype:transform-labels": "None", @@ -132,6 +134,7 @@ def __add__(self, other): TransformerPipeline object, concatenation of `self` (first) with `other` (last). not nested, contains only non-FeatureUnion `sktime` transformers """ + other = _coerce_to_sktime(other) return self._dunder_concat( other=other, base_class=BaseTransformer, @@ -155,6 +158,7 @@ def __radd__(self, other): TransformerPipeline object, concatenation of `self` (last) with `other` (first). not nested, contains only non-FeatureUnion `sktime` transformers """ + other = _coerce_to_sktime(other) return self._dunder_concat( other=other, base_class=BaseTransformer, diff --git a/sktime/transformations/compose/_fitintransform.py b/sktime/transformations/compose/_fitintransform.py index 190b1638240..d5d2b28bdf6 100644 --- a/sktime/transformations/compose/_fitintransform.py +++ b/sktime/transformations/compose/_fitintransform.py @@ -58,6 +58,8 @@ class FitInTransform(BaseTransformer): >>> y_pred = pipe.predict(fh=fh, X=X_test) """ + _tags = {"authors": ["aiwalter", "fkiraly"]} + def __init__(self, transformer, skip_inverse_transform=True): self.transformer = transformer self.skip_inverse_transform = skip_inverse_transform diff --git a/sktime/transformations/compose/_grouped.py b/sktime/transformations/compose/_grouped.py index 6dcfbf6ebca..ff6664cf711 100644 --- a/sktime/transformations/compose/_grouped.py +++ b/sktime/transformations/compose/_grouped.py @@ -57,6 +57,7 @@ class TransformByLevel(_DelegatedTransformer): """ _tags = { + "authors": ["fkiraly"], "requires-fh-in-fit": False, "handles-missing-data": True, "X_inner_mtype": ALL_TIME_SERIES_MTYPES, diff --git a/sktime/transformations/compose/_id.py b/sktime/transformations/compose/_id.py index b60026461b3..7466ac094a8 100644 --- a/sktime/transformations/compose/_id.py +++ b/sktime/transformations/compose/_id.py @@ -16,6 +16,7 @@ class Id(BaseTransformer): """Identity transformer, returns data unchanged in transform/inverse_transform.""" _tags = { + "authors": "fkiraly", "capability:inverse_transform": True, # can the transformer inverse transform? "univariate-only": False, # can the transformer handle multivariate X? "X_inner_mtype": CORE_MTYPES, # which mtypes do _fit/_predict support for X? diff --git a/sktime/transformations/compose/_invert.py b/sktime/transformations/compose/_invert.py index 686b459ef2e..3282d197210 100644 --- a/sktime/transformations/compose/_invert.py +++ b/sktime/transformations/compose/_invert.py @@ -35,6 +35,7 @@ class InvertTransform(_DelegatedTransformer): """ _tags = { + "authors": ["fkiraly"], "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/compose/_ixtox.py b/sktime/transformations/compose/_ixtox.py index 26a98c58eeb..3715bdc2b50 100644 --- a/sktime/transformations/compose/_ixtox.py +++ b/sktime/transformations/compose/_ixtox.py @@ -4,7 +4,8 @@ __author__ = ["fkiraly"] __all__ = ["IxToX"] -from pandas.api.types import is_datetime64_any_dtype, is_period_dtype +import pandas as pd +from pandas.api.types import is_datetime64_any_dtype from sktime.transformations.base import BaseTransformer @@ -63,6 +64,7 @@ class IxToX(BaseTransformer): """ _tags = { + "authors": "fkiraly", "transform-returns-same-time-index": True, "skip-inverse-transform": False, "univariate-only": False, @@ -101,7 +103,7 @@ def _transform(self, X, y=None): level = self.level def is_date_like(x): - return is_datetime64_any_dtype(x) or is_period_dtype(x) + return is_datetime64_any_dtype(x) or isinstance(x, pd.PeriodDtype) if ix_source == "y" and y is not None: X = y diff --git a/sktime/transformations/compose/_multiplex.py b/sktime/transformations/compose/_multiplex.py index a23bce396bc..731eb4ca44a 100644 --- a/sktime/transformations/compose/_multiplex.py +++ b/sktime/transformations/compose/_multiplex.py @@ -90,6 +90,7 @@ class MultiplexTransformer(_HeterogenousMetaEstimator, _DelegatedTransformer): # tags will largely be copied from selected_transformer _tags = { + "authors": ["miraep8", "fkiraly"], "fit_is_empty": False, "univariate-only": False, "X_inner_mtype": ALL_TIME_SERIES_MTYPES, diff --git a/sktime/transformations/compose/_optional.py b/sktime/transformations/compose/_optional.py index c54ed2d5921..4df2416c61f 100644 --- a/sktime/transformations/compose/_optional.py +++ b/sktime/transformations/compose/_optional.py @@ -71,6 +71,7 @@ class OptionalPassthrough(_DelegatedTransformer): """ _tags = { + "authors": ["aiwalter", "fkiraly"], "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/compose/_pipeline.py b/sktime/transformations/compose/_pipeline.py index 2da71e4d1f5..47a0d682667 100644 --- a/sktime/transformations/compose/_pipeline.py +++ b/sktime/transformations/compose/_pipeline.py @@ -118,6 +118,7 @@ class TransformerPipeline(_HeterogenousMetaEstimator, BaseTransformer): """ _tags = { + "authors": "fkiraly", # we let all X inputs through to be handled by first transformer "X_inner_mtype": CORE_MTYPES, "univariate-only": False, @@ -145,7 +146,6 @@ def __init__(self, steps): # abbreviate for readability ests = self.steps_ first_trafo = ests[0][1] - last_trafo = ests[-1][1] # input mtype and input type are as of the first estimator self.clone_tags(first_trafo, ["scitype:transform-input"]) @@ -153,7 +153,7 @@ def __init__(self, steps): # if "Primitives" occur in the middle, then output is set to that too # this is in a case where "Series-to-Series" is applied to primitive df # e.g., in a case of pipelining with scikit-learn transformers - last_out = last_trafo.get_tag("scitype:transform-output") + last_out = self._trafo_out() self._anytagis_then_set( "scitype:transform-output", "Primitives", last_out, ests ) @@ -397,3 +397,63 @@ def get_test_params(cls, parameter_set="default"): params3 = {"steps": [("foo", t1), ("foo", t2), ("foo_1", t3)]} return [params1, params2, params3] + + def _to_dim(self, x): + """Translate scitype:transform-input or output tag to data dimension. + + Parameters + ---------- + x : str, one of "Series", "Panel", "Hierarchical" + scitype:transform-input or output tag + + Returns + ------- + int + data dimension corresponding to x + """ + if x == "Series": + return 1 + elif x == "Panel": + return 2 + else: + return 3 + + def _dim_diff(self, obj): + """Compute difference between input and output dimension.""" + inp = obj.get_tag("scitype:transform-input") + out = obj.get_tag("scitype:transform-output") + return self._to_dim(out) - self._to_dim(inp) + + def _dim_to_sci(self, d): + """Translate data dimension to scitype:transform-output tag. + + Parameters + ---------- + d : int + data dimension + + Returns + ------- + str + scitype:transform-output tag corresponding to data dimension + """ + if d <= 1: + return "Series" + elif d == 2: + return "Panel" + else: + return "Hierarchical" + + def _trafo_out(self): + """Infer scitype:transform-output tag. + + Uses the self.steps_ attribute, assumes it is initialized already. + """ + ests = self.steps_ + est_list = [x[1] for x in ests] + inp_dim = self._to_dim(est_list[0].get_tag("scitype:transform-input")) + out_dim = inp_dim + for est in est_list: + dim_diff = self._dim_diff(est) + out_dim = out_dim + dim_diff + return self._dim_to_sci(out_dim) diff --git a/sktime/transformations/compose/_transformif.py b/sktime/transformations/compose/_transformif.py index 5d77b3f4bc3..f0807ca14c2 100644 --- a/sktime/transformations/compose/_transformif.py +++ b/sktime/transformations/compose/_transformif.py @@ -82,6 +82,7 @@ class TransformIf(_DelegatedTransformer): """ _tags = { + "authors": ["fkiraly"], "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/compose/_ytox.py b/sktime/transformations/compose/_ytox.py index 002b3ccc3e0..2f50b8c5733 100644 --- a/sktime/transformations/compose/_ytox.py +++ b/sktime/transformations/compose/_ytox.py @@ -22,6 +22,7 @@ class YtoX(BaseTransformer): """ _tags = { + "authors": ["fkiraly"], "transform-returns-same-time-index": True, "skip-inverse-transform": False, "univariate-only": False, diff --git a/sktime/transformations/hierarchical/aggregate.py b/sktime/transformations/hierarchical/aggregate.py index bf4334b38a1..cb3f6ba9b71 100644 --- a/sktime/transformations/hierarchical/aggregate.py +++ b/sktime/transformations/hierarchical/aggregate.py @@ -49,6 +49,12 @@ class Aggregator(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": "ciaran-g", + "maintainers": "ciaran-g", + # estimator type + # -------------- "scitype:transform-input": "Series", "scitype:transform-output": "Series", "scitype:transform-labels": "None", diff --git a/sktime/transformations/hierarchical/reconcile.py b/sktime/transformations/hierarchical/reconcile.py index 50e7b827da8..6a742ca29aa 100644 --- a/sktime/transformations/hierarchical/reconcile.py +++ b/sktime/transformations/hierarchical/reconcile.py @@ -73,6 +73,12 @@ class Reconciler(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["ciaran-g", "eenticott-shell", "k1m190r"], + "maintainers": "ciaran-g", + # estimator type + # -------------- "scitype:transform-input": "Series", "scitype:transform-output": "Series", "scitype:transform-labels": "None", diff --git a/sktime/transformations/merger.py b/sktime/transformations/merger.py new file mode 100644 index 00000000000..ea6b55e381c --- /dev/null +++ b/sktime/transformations/merger.py @@ -0,0 +1,140 @@ +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +"""Implements a merger for panel data.""" +import numpy as np + +__author__ = ["benHeid"] + + +from sktime.transformations.base import BaseTransformer + + +class Merger(BaseTransformer): + """Aggregates Panel data containing overlapping windows of one time series. + + The input data contains multiple overlapping time series elements that could + arranged as follows: + xxxx..... + .xxxx.... + ..xxxx... + ...xxxx.. + ....xxxx. + .....xxxx + ......xxxx + .......xxxx + ........xxxx + .........xxxx + The merger aggregates the data by aligning the time series windows as shown above + and applying a aggregation function to the overlapping data points. + The aggregation function can be one of "mean" or "median". I.e., the `mean` or + `median` of each column is calculated, resulting in a univariate time series. + + Parameters + ---------- + method : {`median`, `mean`}, default="median" + The method to use for aggregation. Can be one of "mean" or "median". + stride : int, default=0 + The stride to use for the aggregation. The stride determines the number of + shifts between consecutive instances. A stride of 0 means no shift. A + stride of 1 means that the time series is aggregated as above. + + Examples + -------- + >>> from sktime.transformations.merger import Merger + >>> from sktime.utils._testing.panel import _make_panel + >>> y = _make_panel(n_instances=10, n_columns=3, n_timepoints=5) + >>> result = Merger(method="median").fit_transform(y) + >>> result.shape + (3, 5) + + >>> from sktime.transformations.merger import Merger + >>> from sktime.utils._testing.panel import _make_panel + >>> y = _make_panel(n_instances=10, n_columns=3, n_timepoints=5) + >>> result = Merger(method="median", stride=1).fit_transform(y) + >>> result.shape + (14, 3) + """ + + _tags = { + # packaging info + # -------------- + "authors": "benHeid", + "maintainers": "benHeid", + # estimator type + # --------------- + "scitype:transform-input": "Panel", + "scitype:transform-output": "Series", + "X_inner_mtype": "numpy3D", + "fit_is_empty": True, + } + + def __init__(self, method="median", stride=0): + self.stride = stride + if method not in ["median", "mean"]: + raise ValueError(f"{method} must be 'mean' or 'median'.") + self.method = method + super().__init__() + + def _transform(self, X=None, y=None): + """Merge the Panel data by aligning them temporally. + + Parameters + ---------- + X : pd.DataFrame + The input panel data. + y : pd.Series + ignored + + Returns + ------- + returns a single time series + """ + horizon = X.shape[-1] + + if self.method == "mean": + result = np.nanmean(self._align_temporal(horizon, X), axis=0) + elif self.method == "median": + result = np.nanmedian(self._align_temporal(horizon, X), axis=0) + else: + raise ValueError(f"{self.method} must be 'mean' or 'median'.") + return result + + def _align_temporal(self, horizon, x): + x = x.astype(float) + if self.stride > 0: + x = np.insert( + x, np.arange(1, x.shape[0]).repeat(self.stride - 1), np.nan, axis=0 + ) + elif self.stride == 0: + return x + r = [] + for i in range(horizon): + _res = np.concatenate( + [ + np.full(fill_value=np.nan, shape=(i, x.shape[1])), + x[:, :, i], + np.full(fill_value=np.nan, shape=((horizon - 1 - i), x.shape[1])), + ] + ) + r.append(_res) + return np.stack(r) + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + There are currently no reserved values for forecasters. + + Returns + ------- + params : dict or list of dict, default = {} + Parameters to create testing instances of the class + Each dict are parameters to construct an "interesting" test instance, i.e., + `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. + `create_test_instance` uses the first (or only) dictionary in `params` + """ + return [{"method": "mean"}, {"method": "median"}] diff --git a/sktime/transformations/panel/catch22.py b/sktime/transformations/panel/catch22.py index 53ac4e29058..2339a9f6020 100644 --- a/sktime/transformations/panel/catch22.py +++ b/sktime/transformations/panel/catch22.py @@ -159,13 +159,18 @@ class Catch22(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["MatthewMiddlehurst"], + "python_dependencies": "numba", + # estimator type + # -------------- "scitype:transform-input": "Series", "scitype:transform-output": "Primitives", "scitype:instancewise": True, "X_inner_mtype": "nested_univ", "y_inner_mtype": "None", "fit_is_empty": True, - "python_dependencies": "numba", } def __init__( @@ -323,7 +328,7 @@ def _transform_case(self, X, f_idx): f_count = -1 for i in range(len(X)): - series = np.array(X[i]) + series = np.array(X.iloc[i]) dim = i * len(f_idx) outlier_series = None smin = None @@ -403,9 +408,7 @@ def _transform_case(self, X, f_idx): return c22 def _transform_single_feature(self, X, feature, case_id=None): - if isinstance(feature, (int, np.integer)) or isinstance( - feature, (float, float) - ): + if isinstance(feature, (int, np.integer)) or isinstance(feature, float): if feature > 21 or feature < 0: raise ValueError("Invalid catch22 feature ID") elif isinstance(feature, str): diff --git a/sktime/transformations/panel/catch22wrapper.py b/sktime/transformations/panel/catch22wrapper.py index 2a6cadfa2fd..62a389a68c9 100644 --- a/sktime/transformations/panel/catch22wrapper.py +++ b/sktime/transformations/panel/catch22wrapper.py @@ -71,13 +71,19 @@ class Catch22Wrapper(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["MatthewMiddlehurst"], + "maintainers": "benfulcher", + "python_dependencies": "pycatch22", + # estimator type + # -------------- "scitype:transform-input": "Series", "scitype:transform-output": "Primitives", "scitype:instancewise": True, "X_inner_mtype": "nested_univ", "y_inner_mtype": "None", "fit_is_empty": True, - "python_dependencies": "pycatch22", } def __init__( @@ -192,7 +198,7 @@ def _transform_case(self, X, f_idx, features): f_count = -1 for i in range(len(X)): dim = i * len(f_idx) - series = list(X[i]) + series = list(X.iloc[i]) if self.outlier_norm and (3 in f_idx or 4 in f_idx): outlier_series = np.array(series) diff --git a/sktime/transformations/panel/channel_selection.py b/sktime/transformations/panel/channel_selection.py index 8da0ee2fc3b..906e6fb8fd8 100644 --- a/sktime/transformations/panel/channel_selection.py +++ b/sktime/transformations/panel/channel_selection.py @@ -177,6 +177,8 @@ class pair across each channel. """ _tags = { + "authors": ["haskarb", "a-pasos-ruiz", "TonyBagnall", "fkiraly"], + "maintainers": ["haskarb"], "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel # "scitype:transform-output": "Primitives", diff --git a/sktime/transformations/panel/compose.py b/sktime/transformations/panel/compose.py index 6b17de3ebe7..65ec33eae8e 100644 --- a/sktime/transformations/panel/compose.py +++ b/sktime/transformations/panel/compose.py @@ -15,6 +15,7 @@ from sktime.transformations.base import BaseTransformer, _PanelToPanelTransformer from sktime.utils.multiindex import flatten_multiindex +from sktime.utils.validation._dependencies import _check_soft_dependencies from sktime.utils.validation.panel import check_X @@ -106,7 +107,10 @@ class ColumnTransformer(_ColumnTransformer, _PanelToPanelTransformer): of the individual transformations and the `sparse_threshold` keyword. """ - _tags = {"python_dependencies": "scipy"} + _tags = { + "authors": ["mloning", "sajaysurya", "fkiraly"], + "python_dependencies": ["scipy", "sklearn<1.4"], + } def __init__( self, @@ -117,6 +121,8 @@ def __init__( transformer_weights=None, preserve_dataframe=True, ): + self.preserve_dataframe = preserve_dataframe + warn( "ColumnTransformer is not fully compliant with the sktime interface " "and will be replaced by sktime.transformations.ColumnEnsembleTransformer " @@ -127,6 +133,18 @@ def __init__( "ColumnTransformer can simply be replaced by ColumnEnsembleTransformer." ) + if not _check_soft_dependencies("sklearn<1.4", severity="none"): + raise ModuleNotFoundError( + "ColumnTransformer is not fully compliant with the sktime interface " + "and distributed only for reasons of downwards compatibility. " + "ColumnTransformer requires scikit-learn<1.4 " + "to be present in the python environment, with version, " + "due to reliance on sklearn.compose.ColumnTransformer, " + "and is not compatible with scikit-learn>=1.4. " + "Please use sktime.transformations.ColumnEnsembleTransformer instead, " + "if you have scikit-learn>=1.4 installed." + ) + super().__init__( transformers=transformers, remainder=remainder, @@ -135,7 +153,7 @@ def __init__( transformer_weights=transformer_weights, ) BaseTransformer.__init__(self) - self.preserve_dataframe = preserve_dataframe + self._is_fitted = False def _hstack(self, Xs): diff --git a/sktime/transformations/panel/compose_distance.py b/sktime/transformations/panel/compose_distance.py index 6e28f38e64e..576f82f4f49 100644 --- a/sktime/transformations/panel/compose_distance.py +++ b/sktime/transformations/panel/compose_distance.py @@ -45,6 +45,7 @@ class DistanceFeatures(BaseTransformer): """ _tags = { + "authors": "fkiraly", "X_inner_mtype": ["pd-multiindex", "pd_multiindex_hier"], "y_inner_mtype": "None", "scitype:transform-input": "Series", diff --git a/sktime/transformations/panel/dictionary_based/__init__.py b/sktime/transformations/panel/dictionary_based/__init__.py index aca0dbda125..8e3b9c56dc6 100644 --- a/sktime/transformations/panel/dictionary_based/__init__.py +++ b/sktime/transformations/panel/dictionary_based/__init__.py @@ -1,7 +1,10 @@ """Transformers.""" -__all__ = ["PAA", "SFA", "SFAFast", "SAX"] -from sktime.transformations.panel.dictionary_based._paa import PAA -from sktime.transformations.panel.dictionary_based._sax import SAX +# TODO 0.28.0 - remove exports of PAA, SAX +__all__ = ["PAA", "SFA", "SFAFast", "SAX", "PAAlegacy", "SAXlegacy"] + +# TODO 0.28.0 - remove exports of PAA, SAX +from sktime.transformations.panel.dictionary_based._paa import PAA, PAAlegacy +from sktime.transformations.panel.dictionary_based._sax import SAX, SAXlegacy from sktime.transformations.panel.dictionary_based._sfa import SFA from sktime.transformations.panel.dictionary_based._sfa_fast import SFAFast diff --git a/sktime/transformations/panel/dictionary_based/_paa.py b/sktime/transformations/panel/dictionary_based/_paa.py index 42059ed92bb..b0ce795d765 100644 --- a/sktime/transformations/panel/dictionary_based/_paa.py +++ b/sktime/transformations/panel/dictionary_based/_paa.py @@ -3,10 +3,12 @@ from sktime.datatypes._panel._convert import from_nested_to_2d_array from sktime.transformations.base import BaseTransformer +from sktime.utils.warnings import warn __author__ = ["MatthewMiddlehurst"] +# TODO 0.27.0: rename the class PAA to PAAlegacy class PAA(BaseTransformer): """Piecewise Aggregate Approximation Transformer (PAA). @@ -29,6 +31,7 @@ class PAA(BaseTransformer): """ _tags = { + "authors": ["MatthewMiddlehurst"], "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", @@ -42,6 +45,23 @@ def __init__(self, num_intervals=8): self.num_intervals = num_intervals super().__init__() + warn( + "panel.dictionary_based.PAA will be renamed to PAAlegacy in sktime 0.27.0, " + "while sktime.transformations.series.PAA2 will be renamed to PAA. " + "PAA2 will become the primary PAA implementation in sktime, " + "while the current PAA will continue to be available as PAAlegacy. " + "Both estimators are also available under their future name at their " + "current location, and will be available under their deprecated name " + "until 0.28.0. " + "To prepare for the name change, do one of the following: " + "1. replace use of PAA from sktime.transformations.panel.dictionary_based " + "by use of PAA2 from sktime.transformations.series.paa, or " + "2. replace use of PAA from sktime.transformations.panel.dictionary_based " + "by use of PAAlegacy from sktime.transformations.panel.dictionary_based. ", + DeprecationWarning, + obj=self, + ) + def set_num_intervals(self, n): """Set self.num_intervals to n.""" self.num_intervals = n @@ -151,3 +171,8 @@ def _check_parameters(self, num_atts): + type(self.num_intervals).__name__ + "' instead." ) + + +# TODO 0.27.0: switch the line to PAA = PAAlegacy +# TODO 0.28.0: remove this alias altogether +PAAlegacy = PAA diff --git a/sktime/transformations/panel/dictionary_based/_sax.py b/sktime/transformations/panel/dictionary_based/_sax.py index 8346100326b..a3c754b064a 100644 --- a/sktime/transformations/panel/dictionary_based/_sax.py +++ b/sktime/transformations/panel/dictionary_based/_sax.py @@ -7,17 +7,13 @@ import scipy.stats from sktime.transformations.base import BaseTransformer -from sktime.transformations.panel.dictionary_based import PAA - -# TO DO: verify this returned pandas is consistent with sktime -# definition. Timestamps? - -# from numba import types -# from numba.experimental import jitclass +from sktime.transformations.panel.dictionary_based import PAAlegacy as PAA +from sktime.utils.warnings import warn __author__ = ["MatthewMiddlehurst"] +# TODO 0.27.0: rename the class SAX to SAXlegacy class SAX(BaseTransformer): """Symbolic Aggregate approXimation (SAX) transformer. @@ -60,6 +56,7 @@ class SAX(BaseTransformer): """ _tags = { + "authors": ["MatthewMiddlehurst"], "univariate-only": True, "fit_is_empty": True, "scitype:transform-input": "Series", @@ -89,6 +86,24 @@ def __init__( self.words = [] super().__init__() + + warn( + "panel.dictionary_based.SAX will be renamed to SAXlegacy in sktime 0.27.0, " + "while sktime.transformations.series.SAX2 will be renamed to SAX. " + "SAX2 will become the primary SAX implementation in sktime, " + "while the current SAX will continue to be available as SAXlegacy. " + "Both estimators are also available under their future name at their " + "current location, and will be available under their deprecated name " + "until 0.28.0. " + "To prepare for the name change, do one of the following: " + "1. replace use of SAX from sktime.transformations.panel.dictionary_based " + "by use of SAX2 from sktime.transformations.series.sax, or " + "2. replace use of SAX from sktime.transformations.panel.dictionary_based " + "by use of SAXlegacy from sktime.transformations.panel.dictionary_based. ", + DeprecationWarning, + obj=self, + ) + self.set_config(**{"output_conversion": "off"}) # todo: looks like this just loops over series instances @@ -219,3 +234,8 @@ def get_test_params(cls, parameter_set="default"): # small word length, window size for testing params = {"word_length": 2, "window_size": 4} return params + + +# TODO 0.27.0: switch the line to SAX = SAXlegacy +# TODO 0.28.0: remove this alias altogether +SAXlegacy = SAX diff --git a/sktime/transformations/panel/dictionary_based/_sfa.py b/sktime/transformations/panel/dictionary_based/_sfa.py index 75dac238571..ffd997d85e4 100644 --- a/sktime/transformations/panel/dictionary_based/_sfa.py +++ b/sktime/transformations/panel/dictionary_based/_sfa.py @@ -101,6 +101,7 @@ class SFA(BaseTransformer): """ _tags = { + "authors": ["MatthewMiddlehurst", "patrickzib"], "univariate-only": True, "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel diff --git a/sktime/transformations/panel/dictionary_based/_sfa_fast.py b/sktime/transformations/panel/dictionary_based/_sfa_fast.py index 08db7f42989..3d5bf772252 100644 --- a/sktime/transformations/panel/dictionary_based/_sfa_fast.py +++ b/sktime/transformations/panel/dictionary_based/_sfa_fast.py @@ -123,6 +123,7 @@ class SFAFast(BaseTransformer): """ _tags = { + "authors": ["patrickzib"], "univariate-only": True, "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel diff --git a/sktime/transformations/panel/dictionary_based/tests/test_paa.py b/sktime/transformations/panel/dictionary_based/tests/test_paa.py index 822216aaac4..aa631d9918c 100644 --- a/sktime/transformations/panel/dictionary_based/tests/test_paa.py +++ b/sktime/transformations/panel/dictionary_based/tests/test_paa.py @@ -4,7 +4,7 @@ import pandas as pd import pytest -from sktime.transformations.panel.dictionary_based._paa import PAA +from sktime.transformations.panel.dictionary_based._paa import PAAlegacy as PAA from sktime.utils._testing.panel import _make_nested_from_array diff --git a/sktime/transformations/panel/dwt.py b/sktime/transformations/panel/dwt.py index be0a70cf7e9..a2e020b815a 100644 --- a/sktime/transformations/panel/dwt.py +++ b/sktime/transformations/panel/dwt.py @@ -7,7 +7,7 @@ from sktime.datatypes import convert from sktime.transformations.base import BaseTransformer -__author__ = ["Vincent Nicholson"] +__author__ = ["vnicholson1"] class DWTTransformer(BaseTransformer): @@ -22,6 +22,7 @@ class DWTTransformer(BaseTransformer): """ _tags = { + "authors": "vnicholson1", "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/panel/hog1d.py b/sktime/transformations/panel/hog1d.py index 7c39cc0be7d..58b1a217e0d 100644 --- a/sktime/transformations/panel/hog1d.py +++ b/sktime/transformations/panel/hog1d.py @@ -41,6 +41,7 @@ class HOG1DTransformer(BaseTransformer): """ _tags = { + "authors": ["vnicholson1"], "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/panel/interpolate.py b/sktime/transformations/panel/interpolate.py index 05631e7f77a..3805c26c81d 100644 --- a/sktime/transformations/panel/interpolate.py +++ b/sktime/transformations/panel/interpolate.py @@ -3,6 +3,7 @@ import pandas as pd from sktime.transformations.base import BaseTransformer +from sktime.utils.pandas import df_map __author__ = ["mloning"] @@ -24,6 +25,7 @@ class TSInterpolator(BaseTransformer): """ _tags = { + "authors": ["mloning"], "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", @@ -84,7 +86,7 @@ def _transform(self, X, y=None): pandas DataFrame : Transformed pandas DataFrame of shape [n_samples, n_features] follows nested_univ format """ - return X.applymap(self._resize_cell) + return df_map(X)(self._resize_cell) @classmethod def get_test_params(cls): @@ -98,5 +100,6 @@ def get_test_params(cls): `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. `create_test_instance` uses the first (or only) dictionary in `params`. """ - params = {"length": 10} - return params + params1 = {"length": 10} + params2 = {"length": 5} + return [params1, params2] diff --git a/sktime/transformations/panel/matrix_profile.py b/sktime/transformations/panel/matrix_profile.py index 2b7b623dd28..189b14a4194 100644 --- a/sktime/transformations/panel/matrix_profile.py +++ b/sktime/transformations/panel/matrix_profile.py @@ -206,6 +206,7 @@ class MatrixProfile(BaseTransformer): """ _tags = { + "authors": "Claudia Rincon Sanchez", "univariate-only": True, "fit_is_empty": True, "scitype:transform-input": "Series", diff --git a/sktime/transformations/panel/padder.py b/sktime/transformations/panel/padder.py index b3893cedf23..d32ca69bdf0 100644 --- a/sktime/transformations/panel/padder.py +++ b/sktime/transformations/panel/padder.py @@ -3,6 +3,7 @@ import pandas as pd from sktime.transformations.base import BaseTransformer +from sktime.utils.pandas import df_map __all__ = ["PaddingTransformer"] __author__ = ["abostrom"] @@ -23,6 +24,8 @@ class PaddingTransformer(BaseTransformer): """ _tags = { + "authors": ["abostrom"], + "maintainers": ["abostrom"], "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", @@ -103,7 +106,7 @@ def _transform(self, X, y=None): ) pad = [pd.Series([self._create_pad(series) for series in out]) for out in arr] - Xt = pd.DataFrame(pad).applymap(pd.Series) + Xt = df_map(pd.DataFrame(pad))(pd.Series) return Xt diff --git a/sktime/transformations/panel/pca.py b/sktime/transformations/panel/pca.py index 8c4dbd6e11f..3303f424630 100644 --- a/sktime/transformations/panel/pca.py +++ b/sktime/transformations/panel/pca.py @@ -74,6 +74,8 @@ class PCATransformer(BaseTransformer): """ _tags = { + "authors": ["prockenschaub", "fkiraly"], + "maintainers": ["prockenschaub"], "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/panel/random_intervals.py b/sktime/transformations/panel/random_intervals.py index 1e64a64fb55..2c25b333fb8 100644 --- a/sktime/transformations/panel/random_intervals.py +++ b/sktime/transformations/panel/random_intervals.py @@ -46,6 +46,7 @@ class RandomIntervals(BaseTransformer): """ _tags = { + "authors": ["MatthewMiddlehurst"], "scitype:transform-input": "Series", "scitype:transform-output": "Primitives", "scitype:instancewise": True, diff --git a/sktime/transformations/panel/reduce.py b/sktime/transformations/panel/reduce.py index b60ea0d0006..42af4eaf27f 100644 --- a/sktime/transformations/panel/reduce.py +++ b/sktime/transformations/panel/reduce.py @@ -11,6 +11,7 @@ from sktime.datatypes import convert, convert_to from sktime.transformations.base import BaseTransformer +from sktime.utils.pandas import df_map class Tabularizer(BaseTransformer): @@ -24,6 +25,7 @@ class Tabularizer(BaseTransformer): """ _tags = { + "authors": ["mloning", "fkiraly", "kcc-lion"], "fit_is_empty": True, "univariate-only": False, "scitype:transform-input": "Series", @@ -95,6 +97,8 @@ class TimeBinner(BaseTransformer): """ _tags = { + "authors": ["kcc-lion", "fkiraly"], + "maintainers": ["kcc-lion"], "fit_is_empty": True, "univariate-only": False, "scitype:transform-input": "Series", @@ -150,7 +154,7 @@ def _transform(self, X, y=None): transformed version of X """ idx = pd.cut(X.iloc[0, 0].index, bins=self.idx, include_lowest=True) - Xt = X.applymap(lambda x: x.groupby(idx).apply(self._aggfunc)) + Xt = df_map(X)(lambda x: x.groupby(idx).apply(self._aggfunc)) Xt = convert_to(Xt, to_type="numpyflat", as_scitype="Panel") return Xt diff --git a/sktime/transformations/panel/rocket/_minirocket.py b/sktime/transformations/panel/rocket/_minirocket.py index 1254403742c..e482d664030 100644 --- a/sktime/transformations/panel/rocket/_minirocket.py +++ b/sktime/transformations/panel/rocket/_minirocket.py @@ -20,6 +20,14 @@ class MiniRocket(BaseTransformer): MiniRocket is for unviariate time series only. Use class MiniRocketMultivariate for multivariate time series. + This transformer fits one set of paramereters per individual series, + and applies them to series of the same number in the test set. + + To fit and transform at the same time, + without an identification of fit/transform instances, + wrap this transformer in ``FitInTransform``, + from ``sktime.transformations.compose``. + Parameters ---------- num_kernels : int, default=10,000 @@ -57,6 +65,13 @@ class MiniRocket(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["angus924"], + "maintainers": ["angus924"], + "python_dependencies": "numba", + # estimator tags + # -------------- "univariate-only": True, "fit_is_empty": False, "scitype:transform-input": "Series", @@ -66,7 +81,6 @@ class MiniRocket(BaseTransformer): "scitype:instancewise": False, # is this an instance-wise transform? "X_inner_mtype": "numpy3D", # which mtypes do _fit/_predict support for X? "y_inner_mtype": "None", # which mtypes do _fit/_predict support for X? - "python_dependencies": "numba", } def __init__( diff --git a/sktime/transformations/panel/rocket/_minirocket_multivariate.py b/sktime/transformations/panel/rocket/_minirocket_multivariate.py index 74569fd3789..a60b579e706 100644 --- a/sktime/transformations/panel/rocket/_minirocket_multivariate.py +++ b/sktime/transformations/panel/rocket/_minirocket_multivariate.py @@ -19,6 +19,15 @@ class MiniRocketMultivariate(BaseTransformer): convolutions with six of one weight, three of the second weight to seed dilations. MiniRocketMultivariate works with univariate and multivariate time series. + This transformer fits one set of paramereters per individual series, + and applies the transform with fitted parameter i to the i-th series in transform. + Vanilla use requires same number of series in fit and transform. + + To fit and transform series at the same time, + without an identification of fit/transform instances, + wrap this transformer in ``FitInTransform``, + from ``sktime.transformations.compose``. + Parameters ---------- num_kernels : int, default=10,000 @@ -56,6 +65,8 @@ class MiniRocketMultivariate(BaseTransformer): """ _tags = { + "authors": ["angus924"], + "maintainers": ["angus924"], "univariate-only": False, "fit_is_empty": False, "scitype:transform-input": "Series", diff --git a/sktime/transformations/panel/rocket/_minirocket_multivariate_variable.py b/sktime/transformations/panel/rocket/_minirocket_multivariate_variable.py index ada0429d24a..059abe2586d 100644 --- a/sktime/transformations/panel/rocket/_minirocket_multivariate_variable.py +++ b/sktime/transformations/panel/rocket/_minirocket_multivariate_variable.py @@ -25,6 +25,15 @@ class MiniRocketMultivariateVariable(BaseTransformer): performance, use the sktime class MiniRocket for univariate input, and MiniRocketMultivariate to equal length multivariate input. + This transformer fits one set of paramereters per individual series, + and applies the transform with fitted parameter i to the i-th series in transform. + Vanilla use requires same number of series in fit and transform. + + To fit and transform series at the same time, + without an identification of fit/transform instances, + wrap this transformer in ``FitInTransform``, + from ``sktime.transformations.compose``. + Parameters ---------- num_kernels : int, default=10,000 @@ -80,6 +89,8 @@ class MiniRocketMultivariateVariable(BaseTransformer): """ _tags = { + "authors": ["angus924", "michaelfeil"], + "maintainers": ["angus924", "michaelfeil"], "univariate-only": False, "fit_is_empty": False, "scitype:transform-input": "Series", diff --git a/sktime/transformations/panel/rocket/_multirocket.py b/sktime/transformations/panel/rocket/_multirocket.py index dbb904c44ee..03b068d6a61 100644 --- a/sktime/transformations/panel/rocket/_multirocket.py +++ b/sktime/transformations/panel/rocket/_multirocket.py @@ -8,6 +8,8 @@ from sktime.datatypes import convert from sktime.transformations.base import BaseTransformer +__author__ = ["ChangWeiTan", "fstinner", "angus924"] + class MultiRocket(BaseTransformer): """Multi RandOm Convolutional KErnel Transform (MultiRocket). @@ -20,6 +22,15 @@ class MultiRocket(BaseTransformer): Positive Values (LSPV). This version is for univariate time series only. Use class MultiRocketMultivariate for multivariate input. + This transformer fits one set of paramereters per individual series, + and applies the transform with fitted parameter i to the i-th series in transform. + Vanilla use requires same number of series in fit and transform. + + To fit and transform series at the same time, + without an identification of fit/transform instances, + wrap this transformer in ``FitInTransform``, + from ``sktime.transformations.compose``. + Parameters ---------- num_kernels : int, default = 6,250 @@ -45,7 +56,6 @@ class MultiRocket(BaseTransformer): parameter (dilations, num_features_per_dilation, biases) for transformation of input X1 = np.diff(X, 1) - See Also -------- MultiRocketMultivariate, MiniRocket, MiniRocketMultivariate, Rocket @@ -72,6 +82,13 @@ class MultiRocket(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["ChangWeiTan", "fstinner", "angus924"], + "maintainers": ["ChangWeiTan", "fstinner", "angus924"], + "python_dependencies": "numba", + # estimator type + # -------------- "univariate-only": True, "fit_is_empty": False, "scitype:transform-input": "Series", @@ -81,7 +98,6 @@ class MultiRocket(BaseTransformer): "scitype:instancewise": False, # is this an instance-wise transform? "X_inner_mtype": "numpy3D", # which mtypes do _fit/_predict support for X? "y_inner_mtype": "None", # which mtypes do _fit/_predict support for X? - "python_dependencies": "numba", } def __init__( diff --git a/sktime/transformations/panel/rocket/_multirocket_multivariate.py b/sktime/transformations/panel/rocket/_multirocket_multivariate.py index 7ebe0f7a676..07f6f0516a5 100644 --- a/sktime/transformations/panel/rocket/_multirocket_multivariate.py +++ b/sktime/transformations/panel/rocket/_multirocket_multivariate.py @@ -5,6 +5,8 @@ from sktime.transformations.base import BaseTransformer +__author__ = ["ChangWeiTan", "fstinner", "angus924"] + class MultiRocketMultivariate(BaseTransformer): """Multi RandOm Convolutional KErnel Transform (MultiRocket). @@ -16,6 +18,15 @@ class MultiRocketMultivariate(BaseTransformer): Values (MPV); Mean of Indices of Positive Values (MIPV); and Longest Stretch of Positive Values (LSPV). This version is the multivariate version. + This transformer fits one set of paramereters per individual series, + and applies the transform with fitted parameter i to the i-th series in transform. + Vanilla use requires same number of series in fit and transform. + + To fit and transform series at the same time, + without an identification of fit/transform instances, + wrap this transformer in ``FitInTransform``, + from ``sktime.transformations.compose``. + Parameters ---------- num_kernels : int, default=6,250 @@ -41,7 +52,6 @@ class MultiRocketMultivariate(BaseTransformer): parameter (dilations, num_features_per_dilation, biases) for transformation of input X1 = np.diff(X, 1) - See Also -------- MultiRocketMultivariate, MiniRocket, MiniRocketMultivariate, Rocket @@ -68,6 +78,13 @@ class MultiRocketMultivariate(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["ChangWeiTan", "fstinner", "angus924"], + "maintainers": ["ChangWeiTan", "fstinner", "angus924"], + "python_dependencies": "numba", + # estimator type + # -------------- "univariate-only": False, "fit_is_empty": False, "scitype:transform-input": "Series", @@ -77,7 +94,6 @@ class MultiRocketMultivariate(BaseTransformer): "scitype:instancewise": False, # is this an instance-wise transform? "X_inner_mtype": "numpy3D", # which mtypes do _fit/_predict support for X? "y_inner_mtype": "None", # which mtypes do _fit/_predict support for X? - "python_dependencies": "numba", } def __init__( @@ -190,6 +206,9 @@ def _get_parameter(self, X): _quantiles, ) + if self.random_state is not None: + np.random.seed(self.random_state) + _, num_channels, input_length = X.shape num_kernels = 84 diff --git a/sktime/transformations/panel/rocket/_rocket.py b/sktime/transformations/panel/rocket/_rocket.py index 8218b26e458..e478162de26 100755 --- a/sktime/transformations/panel/rocket/_rocket.py +++ b/sktime/transformations/panel/rocket/_rocket.py @@ -18,6 +18,14 @@ class Rocket(BaseTransformer): dilation. It transforms the time series with two features per kernel. The first feature is global max pooling and the second is proportion of positive values. + This transformer fits one set of paramereters per individual series, + and applies the transform with fitted parameter i to the i-th series in transform. + Vanilla use requires same number of series in fit and transform. + + To fit and transform series at the same time, + without an identification of fit/transform instances, + wrap this transformer in ``FitInTransform``, + from ``sktime.transformations.compose``. Parameters ---------- @@ -57,6 +65,13 @@ class Rocket(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["angus924"], + "maintainers": ["angus924"], + "python_dependencies": "numba", + # estimator type + # -------------- "univariate-only": False, "fit_is_empty": False, "scitype:transform-input": "Series", @@ -66,7 +81,6 @@ class Rocket(BaseTransformer): "scitype:instancewise": False, # is this an instance-wise transform? "X_inner_mtype": "numpy3D", # which mtypes do _fit/_predict support for X? "y_inner_mtype": "None", # which mtypes do _fit/_predict support for X? - "python_dependencies": "numba", } def __init__(self, num_kernels=10_000, normalise=True, n_jobs=1, random_state=None): diff --git a/sktime/transformations/panel/segment.py b/sktime/transformations/panel/segment.py index ce180363b39..00b71651f32 100644 --- a/sktime/transformations/panel/segment.py +++ b/sktime/transformations/panel/segment.py @@ -35,6 +35,7 @@ class IntervalSegmenter(BaseTransformer): """ _tags = { + "authors": "mloning", "univariate-only": True, "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel @@ -188,6 +189,7 @@ class RandomIntervalSegmenter(_DelegatedTransformer): """ _tags = { + "authors": "mloning", "X_inner_mtype": ["pd.DataFrame", "pd-multiindex"], # which mtype do _fit/_predict support for X? "y_inner_mtype": "pd_Series_Table", diff --git a/sktime/transformations/panel/shapelet_transform.py b/sktime/transformations/panel/shapelet_transform.py index 91f169cc399..f3e91fd5bf2 100644 --- a/sktime/transformations/panel/shapelet_transform.py +++ b/sktime/transformations/panel/shapelet_transform.py @@ -123,6 +123,8 @@ class ShapeletTransform(BaseTransformer): """ _tags = { + "authors": ["MatthewMiddlehurst", "jasonlines", "dguijo"], + "maintainers": ["dguijo"], "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Primitives", @@ -1066,6 +1068,8 @@ class RandomShapeletTransform(BaseTransformer): """ _tags = { + "authors": ["MatthewMiddlehurst", "jasonlines", "dguijo"], + "maintainers": ["dguijo"], "fit_is_empty": False, "univariate-only": False, "scitype:transform-input": "Series", diff --git a/sktime/transformations/panel/signature_based/_augmentations.py b/sktime/transformations/panel/signature_based/_augmentations.py index 0a3d2305ea4..8eb88358ef1 100644 --- a/sktime/transformations/panel/signature_based/_augmentations.py +++ b/sktime/transformations/panel/signature_based/_augmentations.py @@ -5,7 +5,7 @@ def _make_augmentation_pipeline(augmentation_list): - """Buids an sklearn pipeline of augmentations from a tuple of strings. + """Build an sklearn pipeline of augmentations from a tuple of strings. Parameters ---------- @@ -43,11 +43,11 @@ def _make_augmentation_pipeline(augmentation_list): if augmentation_list is not None: if isinstance(augmentation_list, str): augmentation_list = (augmentation_list,) - assert all( - [x in list(AUGMENTATIONS.keys()) for x in augmentation_list] - ), "augmentation_list must only contain string elements from {}. Given: {}.".format( - list(AUGMENTATIONS.keys()), augmentation_list - ) + if not [x in list(AUGMENTATIONS.keys()) for x in augmentation_list]: + raise ValueError( + "augmentation_list must only contain string elements from " + f" {list(AUGMENTATIONS.keys())}. Found: {augmentation_list}" + ) # Setup pipeline if augmentation_list is not None: @@ -68,6 +68,12 @@ class _AddTime(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": "jambo6", + "maintainers": "jambo6", + # estimator type + # -------------- "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/panel/signature_based/_compute.py b/sktime/transformations/panel/signature_based/_compute.py index c75269b8e3d..9d2ee3fa2ff 100644 --- a/sktime/transformations/panel/signature_based/_compute.py +++ b/sktime/transformations/panel/signature_based/_compute.py @@ -45,6 +45,7 @@ def __init__( sig_tfm=None, sig_depth=None, rescaling=None, + backend=None, ): super().__init__() self.window_name = window_name @@ -54,6 +55,7 @@ def __init__( self.sig_tfm = sig_tfm self.sig_depth = sig_depth self.rescaling = rescaling + self.backend = backend self.window = _window_getter( self.window_name, self.window_depth, self.window_length, self.window_step @@ -62,6 +64,9 @@ def __init__( def _transform(self, X, y=None): import esig + if self.backend == "iisignature": + esig.set_backend("iisignature") + depth = self.sig_depth data = np.swapaxes(X, 1, 2) diff --git a/sktime/transformations/panel/signature_based/_signature_method.py b/sktime/transformations/panel/signature_based/_signature_method.py index 0ef27595f2c..b01e36bff00 100644 --- a/sktime/transformations/panel/signature_based/_signature_method.py +++ b/sktime/transformations/panel/signature_based/_signature_method.py @@ -9,6 +9,8 @@ from sktime.transformations.panel.signature_based._compute import ( _WindowSignatureTransform, ) +from sktime.utils.validation._dependencies import _check_soft_dependencies +from sktime.utils.warnings import warn class SignatureTransformer(BaseTransformer): @@ -19,19 +21,34 @@ class SignatureTransformer(BaseTransformer): Parameters ---------- - augmentation_list: tuple of strings, contains the augmentations to be - applied before application of the signature transform. - window_name: str, The name of the window transform to apply. - window_depth: int, The depth of the dyadic window. (Active only if - `window_name == 'dyadic'`). - window_length: int, The length of the sliding/expanding window. (Active - only if `window_name in ['sliding, 'expanding']`. - window_step: int, The step of the sliding/expanding window. (Active - only if `window_name in ['sliding, 'expanding']`. - rescaling: str or None, The method of signature rescaling. - sig_tfm: str, String to specify the type of signature transform. One of: - ['signature', 'logsignature']). - depth: int, Signature truncation depth. + augmentation_list: list or tuple of strings, possible strings are + ['leadlag', 'ir', 'addtime', 'cumsum', 'basepoint'] + Augmentations to apply to the data before computing the signature. + The order of the augmentations is the order in which they are applied. + default: ('basepoint', 'addtime') + window_name: str, one of ``['global', 'sliding', 'expanding', 'dyadic']`` + default: 'dyadic' + Type of the window to use for the signature transform. + window_depth: int, default=3 + The depth of the dyadic window. + Ignored unless ``window_name`` is ``'dyadic'``. + window_length: None (default) or int + The length of the sliding/expanding window. (Active + Ignored unless ``window_name`` is one of ``['sliding, 'expanding']``. + window_step: None (default) or int + The step of the sliding/expanding window. + Ignored unless ``window_name`` is one of ``['sliding, 'expanding']``. + rescaling: None (default) or str, "pre" or "post", + None: No rescaling is applied. + "pre": rescale the path last signature term should be roughly O(1) + "post": Rescales the output signature by multiplying the depth-d term by d!. + Aim is that every term becomes ~O(1). + sig_tfm: str, one of ``['signature', 'logsignature']``. default: ``'signature'`` + The type of signature transform to use, plain or logarithmic. + depth: int, default=4 + Signature truncation depth. + backend: str, one of: ``'esig'`` (default), or ``'iisignature'``. + The backend to use for signature computation. Attributes ---------- @@ -40,6 +57,14 @@ class SignatureTransformer(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": "jambo6", + "maintainers": "jambo6", + "python_dependencies": "esig", + "python_version": "<3.10", + # estimator type + # -------------- "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Primitives", @@ -48,8 +73,6 @@ class SignatureTransformer(BaseTransformer): "X_inner_mtype": "numpy3D", # which mtypes do _fit/_predict support for X? "y_inner_mtype": "None", # which mtypes do _fit/_predict support for X?# "fit_is_empty": False, - "python_dependencies": "esig", - "python_version": "<3.10", } def __init__( @@ -62,6 +85,7 @@ def __init__( rescaling=None, sig_tfm="signature", depth=4, + backend="esig", ): self.augmentation_list = augmentation_list self.window_name = window_name @@ -71,8 +95,27 @@ def __init__( self.rescaling = rescaling self.sig_tfm = sig_tfm self.depth = depth + self.backend = backend super().__init__() + + if backend == "esig": + _check_soft_dependencies("esig") + elif backend == "iisignature": + _check_soft_dependencies("iisignature") + warn( + "iisignature backend of SignatureTransformer is experimental " + "and not systematically tested, due to lack of stable installation " + "process for iisignature via pip. Kindly exercise caution, " + "and report any issues on the sktime issue tracker.", + stacklevel=2, + ) + else: + raise ValueError( + "Error in SignatureTransformer, backend " + "must be one of 'esig' or 'iisignature'" + ) + self.setup_feature_pipeline() def setup_feature_pipeline(self): @@ -86,6 +129,7 @@ def setup_feature_pipeline(self): sig_tfm=self.sig_tfm, sig_depth=self.depth, rescaling=self.rescaling, + backend=self.backend, ) # The so-called 'signature method' as defined in the reference paper diff --git a/sktime/transformations/panel/slope.py b/sktime/transformations/panel/slope.py index 1a45d23fea8..756fa925e5e 100644 --- a/sktime/transformations/panel/slope.py +++ b/sktime/transformations/panel/slope.py @@ -27,6 +27,7 @@ class SlopeTransformer(BaseTransformer): """ _tags = { + "authors": ["mloning"], "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/panel/summarize/_extract.py b/sktime/transformations/panel/summarize/_extract.py index 801f07311fc..a7222d1dd34 100644 --- a/sktime/transformations/panel/summarize/_extract.py +++ b/sktime/transformations/panel/summarize/_extract.py @@ -10,6 +10,7 @@ from sktime.datatypes import convert_to from sktime.transformations.base import BaseTransformer from sktime.transformations.panel.segment import RandomIntervalSegmenter +from sktime.utils.pandas import df_map class PlateauFinder(BaseTransformer): @@ -30,6 +31,7 @@ class PlateauFinder(BaseTransformer): """ _tags = { + "authors": ["mloning"], "fit_is_empty": True, "univariate-only": True, "scitype:transform-input": "Series", @@ -103,7 +105,7 @@ def _transform(self, X, y=None): Xt["%s_starts" % column_prefix] = pd.Series(self._starts) Xt["%s_lengths" % column_prefix] = pd.Series(self._lengths) - Xt = Xt.applymap(lambda x: pd.Series(x)) + Xt = df_map(Xt)(lambda x: pd.Series(x)) return Xt @@ -140,7 +142,10 @@ def row_wise_get_der(X): def get_der(x): der = [] for i in range(1, len(x) - 1): - der.append(((x[i] - x[i - 1]) + ((x[i + 1] - x[i - 1]) / 2)) / 2) + xi = x.iloc[i] + xim1 = x.iloc[i - 1] + xip1 = x.iloc[i + 1] + der.append(0.5 * ((xi - xim1) + 0.5 * (xip1 - xim1))) return pd.Series([der[0]] + der + [der[-1]]) return [get_der(x) for x in X] diff --git a/sktime/transformations/panel/supervised_intervals.py b/sktime/transformations/panel/supervised_intervals.py index 86dcf78741a..1b0b5c067c6 100644 --- a/sktime/transformations/panel/supervised_intervals.py +++ b/sktime/transformations/panel/supervised_intervals.py @@ -92,6 +92,7 @@ class SupervisedIntervals(BaseTransformer): """ _tags = { + "authors": ["MatthewMiddlehurst"], "scitype:transform-input": "Series", "scitype:transform-output": "Primitives", "scitype:instancewise": False, diff --git a/sktime/transformations/panel/tests/test_compose.py b/sktime/transformations/panel/tests/test_compose.py index a95031ba534..28766ab7dd6 100644 --- a/sktime/transformations/panel/tests/test_compose.py +++ b/sktime/transformations/panel/tests/test_compose.py @@ -1,5 +1,6 @@ """Tests for panel compositors.""" import numpy as np +import pytest from sklearn.ensemble import RandomForestClassifier from sklearn.pipeline import Pipeline from sklearn.preprocessing import FunctionTransformer @@ -7,8 +8,13 @@ from sktime.datasets import load_basic_motions from sktime.transformations.panel.compose import ColumnTransformer from sktime.transformations.panel.reduce import Tabularizer +from sktime.utils.validation._dependencies import _check_soft_dependencies +@pytest.mark.skipif( + not _check_soft_dependencies("sklearn<1.4", severity="none"), + reason="ColumnTransformer requires sklearn<1.4 due to reliance on private methods", +) def test_ColumnTransformer_pipeline(): """Test pipeline with ColumnTransformer.""" X_train, y_train = load_basic_motions(split="train", return_X_y=True) diff --git a/sktime/transformations/panel/tests/test_interpolate.py b/sktime/transformations/panel/tests/test_interpolate.py index 25d9c3fe5ee..bbc4d4b4669 100644 --- a/sktime/transformations/panel/tests/test_interpolate.py +++ b/sktime/transformations/panel/tests/test_interpolate.py @@ -28,14 +28,14 @@ def test_resizing(): # 1) Check that lengths of all time series (all via the axis=1 - for # all dims in first row) are equal. - ts_lens_before = [len(X.iloc[0][i]) for i in range(len(X.iloc[0]))] + ts_lens_before = [len(X.iloc[0].iloc[i]) for i in range(len(X.iloc[0]))] # all lengths are equal to first length in array assert all([length == ts_lens_before[0] for length in ts_lens_before]) # 2) cutting each time series in each cell of X to make lengths different X = cut_X_ts(X) # get lengths to ensure that they are really different - ts_lens_after_cut = [len(X.iloc[0][i]) for i in range(len(X.iloc[0]))] + ts_lens_after_cut = [len(X.iloc[0].iloc[i]) for i in range(len(X.iloc[0]))] assert not all( [length == ts_lens_after_cut[0] for length in ts_lens_after_cut] ) # are different @@ -46,5 +46,5 @@ def test_resizing(): # 4) check that result time series have lengths equal to `target_len # that we set above - ts_lens_after_resize = [len(Xt.iloc[0][i]) for i in range(len(Xt.iloc[0]))] + ts_lens_after_resize = [len(Xt.iloc[0].iloc[i]) for i in range(len(Xt.iloc[0]))] assert all([length == target_len for length in ts_lens_after_resize]) diff --git a/sktime/transformations/panel/truncation.py b/sktime/transformations/panel/truncation.py index de4f6a2d8bb..ec46191e7b4 100644 --- a/sktime/transformations/panel/truncation.py +++ b/sktime/transformations/panel/truncation.py @@ -25,6 +25,8 @@ class TruncationTransformer(BaseTransformer): """ _tags = { + "authors": ["abostrom"], + "maintainers": ["abostrom"], "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/panel/tsfresh.py b/sktime/transformations/panel/tsfresh.py index 48ce7661c0c..561205d2e7f 100644 --- a/sktime/transformations/panel/tsfresh.py +++ b/sktime/transformations/panel/tsfresh.py @@ -12,6 +12,8 @@ class _TSFreshFeatureExtractor(BaseTransformer): """Base adapter class for tsfresh transformations.""" _tags = { + "authors": ["AyushmaanSeth", "mloning", "alwinw", "MatthewMiddlehurst"], + "maintainers": ["AyushmaanSeth"], "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Primitives", @@ -98,6 +100,12 @@ def _get_extraction_params(self): if value is not None: extraction_params[name] = value + # Fixes key mismatch between tsfresh and sktime + # tsfresh uses "profile" while sktime uses "profiling" + # This fix keeps compatibility + if name == "profile": + extraction_params[name] = self.profiling + self.n_jobs = n_jobs # Convert convenience string arguments to tsfresh parameters classes @@ -708,4 +716,9 @@ def get_test_params(cls, parameter_set="default"): "show_warnings": False, "fdr_level": 0.01, } - return params + params2 = { + "default_fc_parameters": "minimal", + "disable_progressbar": True, + "show_warnings": False, + } + return [params, params2] diff --git a/sktime/transformations/series/acf.py b/sktime/transformations/series/acf.py index 1f91e2db6f1..2923be30d6e 100644 --- a/sktime/transformations/series/acf.py +++ b/sktime/transformations/series/acf.py @@ -67,6 +67,13 @@ class AutoCorrelationTransformer(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": "afzal442", + "maintainers": "afzal442", + "python_dependencies": "statsmodels", + # estimator type + # -------------- "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", @@ -76,7 +83,6 @@ class AutoCorrelationTransformer(BaseTransformer): "y_inner_mtype": "None", # which mtypes do _fit/_predict support for y? "univariate-only": True, "fit_is_empty": True, - "python_dependencies": "statsmodels", } def __init__( diff --git a/sktime/transformations/series/adapt.py b/sktime/transformations/series/adapt.py index a654c59165f..1c7f3c15a3f 100644 --- a/sktime/transformations/series/adapt.py +++ b/sktime/transformations/series/adapt.py @@ -101,6 +101,11 @@ class TabularToSeriesAdaptor(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["mloning", "fkiraly"], + # estimator type + # -------------- "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/series/augmenter.py b/sktime/transformations/series/augmenter.py index 18ae7aadc32..7e53683ad44 100755 --- a/sktime/transformations/series/augmenter.py +++ b/sktime/transformations/series/augmenter.py @@ -19,6 +19,12 @@ class _AugmenterTags: _tags = { + # packaging info + # ---------------- + "authors": ["MrPr3ntice", "MFehsenfeld", "iljamaurer"], + "maintainers": ["MrPr3ntice", "MFehsenfeld", "iljamaurer"], + # estimator type + # -------------- "scitype:transform-input": "Series", "scitype:transform-output": "Series", "scitype:transform-labels": "None", diff --git a/sktime/transformations/series/binning.py b/sktime/transformations/series/binning.py index 34129bd66e3..1db22b992d9 100644 --- a/sktime/transformations/series/binning.py +++ b/sktime/transformations/series/binning.py @@ -54,6 +54,7 @@ class TimeBinAggregate(BaseTransformer): """ _tags = { + "authors": "fkiraly", "fit_is_empty": True, "univariate-only": False, "scitype:transform-input": "Series", diff --git a/sktime/transformations/series/bkfilter.py b/sktime/transformations/series/bkfilter.py index 353d1148ee4..f4c9372aab3 100644 --- a/sktime/transformations/series/bkfilter.py +++ b/sktime/transformations/series/bkfilter.py @@ -63,6 +63,13 @@ class BKFilter(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["klam-data", "pyyim", "mgorlin"], + "maintainers": "klam-data", + "python_dependencies": "statsmodels", + # estimator type + # -------------- "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", @@ -83,7 +90,6 @@ class BKFilter(BaseTransformer): # can the transformer handle unequal length time series (if passed Panel)? "handles-missing-data": False, # can estimator handle missing data? "remember_data": False, # whether all data seen is remembered as self._X - "python_dependencies": "statsmodels", } def __init__( diff --git a/sktime/transformations/series/boxcox.py b/sktime/transformations/series/boxcox.py index 4e7ce83c8e6..9889d966c3a 100644 --- a/sktime/transformations/series/boxcox.py +++ b/sktime/transformations/series/boxcox.py @@ -158,6 +158,12 @@ class BoxCoxTransformer(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["mloning", "aiwalter", "fkiraly"], + "python_dependencies": "scipy", + # estimator type + # -------------- "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", @@ -169,7 +175,6 @@ class BoxCoxTransformer(BaseTransformer): "fit_is_empty": False, "univariate-only": True, "capability:inverse_transform": True, - "python_dependencies": "scipy", } def __init__( @@ -528,7 +533,8 @@ def _guerrero(x, sp, bounds=None): if sp is None or not is_int(sp) or sp < 2: raise ValueError( - "Guerrero method requires an integer seasonal periodicity (sp) value >= 2." + "In BoxCoxTransformer, method='guerrero' requires an integer seasonal " + f"periodicity (sp) value >= 2, but found sp={sp}" ) x = np.asarray(x) diff --git a/sktime/transformations/series/cffilter.py b/sktime/transformations/series/cffilter.py index 7507d1914e8..628649ae93b 100644 --- a/sktime/transformations/series/cffilter.py +++ b/sktime/transformations/series/cffilter.py @@ -51,6 +51,13 @@ class CFFilter(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["ken-maeda"], + "maintainers": ["ken-maeda"], + "python_dependencies": "statsmodels", + # estimator type + # -------------- "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", @@ -71,7 +78,6 @@ class CFFilter(BaseTransformer): # can the transformer handle unequal length time series (if passed Panel)? "handles-missing-data": False, # can estimator handle missing data? "remember_data": False, # whether all data seen is remembered as self._X - "python_dependencies": "statsmodels", } def __init__( diff --git a/sktime/transformations/series/clasp.py b/sktime/transformations/series/clasp.py index f08a9ecdd8e..819ece24a98 100644 --- a/sktime/transformations/series/clasp.py +++ b/sktime/transformations/series/clasp.py @@ -58,6 +58,13 @@ class ClaSPTransformer(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["ermshaua", "patrickzib"], + "maintainers": ["ermshaua"], + "python_dependencies": "numba", + # estimator type + # -------------- "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", @@ -67,7 +74,6 @@ class ClaSPTransformer(BaseTransformer): "y_inner_mtype": "None", # which mtypes do _fit/_predict support for y? "univariate-only": True, "fit_is_empty": True, - "python_dependencies": "numba", } def __init__( diff --git a/sktime/transformations/series/clear_sky.py b/sktime/transformations/series/clear_sky.py index 49b36e5d010..6410f47eba3 100644 --- a/sktime/transformations/series/clear_sky.py +++ b/sktime/transformations/series/clear_sky.py @@ -73,6 +73,13 @@ class ClearSky(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["ciaran-g"], + "maintainers": ["ciaran-g"], + "python_dependencies": ["statsmodels", "scipy"], + # estimator type + # -------------- "scitype:transform-input": "Series", "scitype:transform-output": "Series", "scitype:transform-labels": "None", @@ -96,8 +103,6 @@ class ClearSky(BaseTransformer): "capability:unequal_length:removes": True, # ? "handles-missing-data": False, "capability:missing_values:removes": True, - "python_version": None, # PEP 440 python version specifier to limit versions - "python_dependencies": ["statsmodels", "scipy"], } def __init__( diff --git a/sktime/transformations/series/cos.py b/sktime/transformations/series/cos.py index c911a5c6cb6..d5fd1bf5abc 100644 --- a/sktime/transformations/series/cos.py +++ b/sktime/transformations/series/cos.py @@ -31,6 +31,12 @@ class CosineTransformer(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": "afzal442", + "maintainers": "afzal442", + # estimator type + # -------------- "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/series/date.py b/sktime/transformations/series/date.py index 412df68dfb0..7fab30ae2c6 100644 --- a/sktime/transformations/series/date.py +++ b/sktime/transformations/series/date.py @@ -169,6 +169,13 @@ class DateTimeFeatures(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["danbartl", "KishManani", "VyomkeshVyas"], + "maintainers": ["VyomkeshVyas"], + "python_dependencies": "pandas>=1.2.0", # from DateTimeProperties + # estimator type + # -------------- "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", @@ -187,7 +194,6 @@ class DateTimeFeatures(BaseTransformer): "transform-returns-same-time-index": True, "enforce_index_type": [pd.DatetimeIndex, pd.PeriodIndex], "skip-inverse-transform": True, - "python_dependencies": "pandas>=1.2.0", # from DateTimeProperties } def __init__( diff --git a/sktime/transformations/series/detrend/_deseasonalize.py b/sktime/transformations/series/detrend/_deseasonalize.py index b79095a82e5..7211d048153 100644 --- a/sktime/transformations/series/detrend/_deseasonalize.py +++ b/sktime/transformations/series/detrend/_deseasonalize.py @@ -63,6 +63,12 @@ class Deseasonalizer(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["mloning", "eyalshafran", "aiwalter"], + "python_dependencies": "statsmodels", + # estimator type + # -------------- "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", @@ -75,7 +81,6 @@ class Deseasonalizer(BaseTransformer): "capability:inverse_transform": True, "transform-returns-same-time-index": True, "univariate-only": True, - "python_dependencies": "statsmodels", } def __init__(self, sp=1, model="additive"): @@ -363,16 +368,25 @@ def _fit(self, X, y=None): class STLTransformer(BaseTransformer): """Remove seasonal components from a time-series using STL. - Interfaces STL from statsmodels as an sktime transformer. + Interfaces ``statsmodels.tsa.seasonal.STL`` as an sktime transformer. + + ``STLTransformer`` can be used to perform deseasonalization or decomposition: + + If ``return_components=False``, it will return the deseasonalized series, i.e., + the trend component from ``statsmodels`` ``STL``. + + If ``return_components=True``, it will transform the series into a decomposition + of component, returning the trend, seasonal, and residual components. + + ``STLTransformer`` performs ``inverse_transform`` by summing any components, + and can be used for pipelining in a ``TransformedTargetForecaster``. - The STLTransformer is a descriptive transformer to remove seasonality - from a series and is based on statsmodels.STL. It returns deseasonalized - data. Components are returned in addition if return_components=True - STLTransformer can not inverse_transform on indices not seen in fit(). - This means that for pipelining, the Deseasonalizer or Detrender must be - used instead of STLTransformer. + Important: for separate forecasts of trend and seasonality, and an + inverse transform that respects seasonality, ensure + that ``return_components=True`` is set, otherwise the inverse will just + return the trend component. - Important note: the returned series has seasonality removed, but not trend. + An alternative for pipeline-style composition is ``STLForecaster``. Parameters ---------- @@ -414,7 +428,7 @@ class STLTransformer(BaseTransformer): the two are linearly interpolated. Higher values reduce estimation time. return_components : bool, default=False - if False, will return only the STL transformed series + if False, will return only the trend component if True, will return the transformed series, as well as three components as variables in the returned multivariate series (DataFrame cols) "transformed" - the transformed series diff --git a/sktime/transformations/series/detrend/_detrend.py b/sktime/transformations/series/detrend/_detrend.py index be410df7eae..69e705dfe2f 100644 --- a/sktime/transformations/series/detrend/_detrend.py +++ b/sktime/transformations/series/detrend/_detrend.py @@ -68,6 +68,12 @@ class Detrender(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["mloning", "SveaMeyer13", "KishManani", "fkiraly"], + "maintainers": ["SveaMeyer13", "KishManani"], + # estimator type + # -------------- "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/series/detrend/mstl.py b/sktime/transformations/series/detrend/mstl.py index 8d19ad6b9e2..87d8e48d740 100644 --- a/sktime/transformations/series/detrend/mstl.py +++ b/sktime/transformations/series/detrend/mstl.py @@ -99,6 +99,13 @@ class MSTL(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["luca-miniati"], + "maintainers": ["luca-miniati"], + "python_dependencies": "statsmodels", + # estimator type + # -------------- "scitype:transform-input": "Series", "scitype:transform-output": "Series", "scitype:instancewise": True, @@ -110,7 +117,6 @@ class MSTL(BaseTransformer): "capability:inverse_transform:exact": False, "skip-inverse-transform": False, "fit_is_empty": False, - "python_dependencies": "statsmodels", } def __init__( diff --git a/sktime/transformations/series/difference.py b/sktime/transformations/series/difference.py index 47ba582956d..a3f76227343 100644 --- a/sktime/transformations/series/difference.py +++ b/sktime/transformations/series/difference.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 -u # copyright: sktime developers, BSD-3-Clause License (see LICENSE file) """Class to iteratively apply differences to a time series.""" -__author__ = ["RNKuhns", "fkiraly"] +__author__ = ["RNKuhns", "fkiraly", "benheid"] __all__ = ["Differencer"] from typing import Union @@ -232,6 +232,11 @@ class Differencer(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["RNKuhns", "fkiraly", "benheid"], + # estimator type + # -------------- "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/series/dilation_mapping.py b/sktime/transformations/series/dilation_mapping.py new file mode 100644 index 00000000000..967db827b00 --- /dev/null +++ b/sktime/transformations/series/dilation_mapping.py @@ -0,0 +1,133 @@ +"""DilationMapping transformer. + +A transformer for applying dilation mapping to time series data. +""" + +__author__ = ["fspinna"] +__all__ = ["DilationMappingTransformer"] + +import pandas as pd + +from sktime.transformations.base import BaseTransformer + + +class DilationMappingTransformer(BaseTransformer): + r"""Dilation mapping transformer. + + A transformer for applying an index grid dilation mapping to time series data, + in the terminology of [1]_. + + This transformation is motivated by kernel dilation, it + reorders the timesteps of a time series to simulate the effect of dilation. + For instance, in a pipeline, it enables a dilation-like effect for downstream + models that do not inherently support such a feature. + + Mathematically, the mapping operates on sequences :math:`x_1, \dots, x_k`. + The dilation with factor :math:`d` is defined as the sequence + :math:`x_1, x_{1+d}, x_{1+2d}, \dots, x_2, x_{2+d}, x_{2+2d}, \dots, x_d, x_{2d}, \dots`, + where the subsequences with grid spacing :math:`d` are maximal. + + The resulting sequence is of equal length to the input sequence. + + This transformer reorders the values, and resets the sequence index + to a ``RangeIndex``, if the mtype is ``pandas`` based. + + Parameters + ---------- + dilation : int, default=2 + The dilation factor. Determines the spacing between original data points in the + transformed series. Must be an integer greater than 0. A dilation of 1 means no + change, while higher values increase the spacing. + + References + ---------- + .. [1] Patrick SchΓ€fer and Ulf Leser, + "WEASEL 2.0--A Random Dilated Dictionary Transform for Fast, + Accurate and Memory Constrained Time Series Classification", 2023, + arXiv preprint arXiv:2301.10194. + + Example + ---------- + >>> from sktime.transformations.series.dilation_mapping import \ + ... DilationMappingTransformer + >>> from sktime.datasets import load_airline + >>> y = load_airline() + >>> y_transform = DilationMappingTransformer(dilation=2).fit_transform(y) + """ # noqa: E501 + + _tags = { + # packaging info + # -------------- + "authors": ["fspinna"], + "maintainers": ["fspinna"], + # estimator type + # -------------- + "scitype:transform-input": "Series", + "scitype:transform-output": "Series", + "scitype:instancewise": True, + "scitype:transform-labels": "None", + "X_inner_mtype": "pd.Series", + "y_inner_mtype": "None", + "univariate-only": True, + "requires_y": False, + "fit_is_empty": True, + "capability:inverse_transform": False, + "capability:unequal_length": True, + "handles-missing-data": True, + } + + def __init__(self, dilation=2): + self.dilation = dilation + + super().__init__() + + if dilation < 1: + raise ValueError("Dilation must be greater than 0") + + def _transform(self, X, y=None): + """Transform X and return a transformed version. + + private _transform containing core logic, called from transform + + Parameters + ---------- + X : Series, Panel, or Hierarchical data, of mtype X_inner_mtype + if X_inner_mtype is list, _transform must support all types in it + Data to be transformed + y : Series, Panel, or Hierarchical data, of mtype y_inner_mtype, default=None + Additional data, e.g., labels for transformation + + Returns + ------- + # X_transformed : Series of mtype pd.Series + # transformed version of X + """ + return self._dilate_series(X, self.dilation) + + def _dilate_series(self, x, d): + x_dilations = [x[i::d] for i in range(0, d)] + x_dilated = pd.concat(x_dilations, axis=0) + x_dilated.name = x.name + return x_dilated.reset_index(drop=True) + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + There are currently no reserved values for transformers. + + Returns + ------- + params : dict or list of dict, default = {} + Parameters to create testing instances of the class + Each dict are parameters to construct an "interesting" test instance, i.e., + `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. + `create_test_instance` uses the first (or only) dictionary in `params` + """ + params = [{"dilation": 2}] + return params diff --git a/sktime/transformations/series/dobin.py b/sktime/transformations/series/dobin.py index d55e9c202fa..39d974a1ce4 100644 --- a/sktime/transformations/series/dobin.py +++ b/sktime/transformations/series/dobin.py @@ -78,10 +78,15 @@ class DOBIN(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": "KatieBuc", + "python_dependencies": "scipy", + # estimator type + # -------------- "X_inner_mtype": "pd.DataFrame", "fit_is_empty": False, "skip-inverse-transform": True, - "python_dependencies": "scipy", } def __init__( diff --git a/sktime/transformations/series/dropna.py b/sktime/transformations/series/dropna.py index 2f9fa76cc81..2521988230e 100644 --- a/sktime/transformations/series/dropna.py +++ b/sktime/transformations/series/dropna.py @@ -43,6 +43,8 @@ class DropNA(BaseTransformer): """ _tags = { + "authors": ["hliebert"], + "maintainers": ["hliebert"], "univariate-only": False, "scitype:transform-input": "Series", "scitype:transform-output": "Series", diff --git a/sktime/transformations/series/exponent.py b/sktime/transformations/series/exponent.py index 5fd8d29392a..d607d0e07dc 100644 --- a/sktime/transformations/series/exponent.py +++ b/sktime/transformations/series/exponent.py @@ -70,6 +70,7 @@ class ExponentTransformer(BaseTransformer): """ _tags = { + "authors": ["RNKuhns"], "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/series/feature_selection.py b/sktime/transformations/series/feature_selection.py index 54b173fb4da..2a9f955d836 100644 --- a/sktime/transformations/series/feature_selection.py +++ b/sktime/transformations/series/feature_selection.py @@ -30,7 +30,7 @@ class FeatureSelection(BaseTransformer): Requires parameter n_columns. * "random": Randomly select n_columns features. Requires parameter n_columns. * "columns": Select features by given names. - * "none": Remove all columns by setting Z to None. + * "none": Remove all columns, transform returns None. * "all": Select all given features. regressor : sklearn-like regressor, optional, default=None. Used as meta-model for the method "feature-importances". The given @@ -70,6 +70,7 @@ class FeatureSelection(BaseTransformer): """ _tags = { + "authors": ["aiwalter"], "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/series/filter.py b/sktime/transformations/series/filter.py index 4a5362b9650..3117be08a86 100644 --- a/sktime/transformations/series/filter.py +++ b/sktime/transformations/series/filter.py @@ -35,6 +35,12 @@ class Filter(BaseTransformer): # default tag values for "Series-to-Series" _tags = { + # packaging info + # -------------- + "authors": ["sveameyer13"], + "python_dependencies": "mne", + # estimator type + # -------------- "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", @@ -43,7 +49,6 @@ class Filter(BaseTransformer): "X_inner_mtype": ["np.ndarray", "numpy3D"], "y_inner_mtype": "None", # which mtypes do _fit/_predict support for X? "fit_is_empty": True, # is fit empty and can be skipped? Yes = True - "python_dependencies": "mne", } def __init__( diff --git a/sktime/transformations/series/fourier.py b/sktime/transformations/series/fourier.py index b1b3478c12a..13f02ee1c8f 100644 --- a/sktime/transformations/series/fourier.py +++ b/sktime/transformations/series/fourier.py @@ -23,27 +23,40 @@ class FourierFeatures(BaseTransformer): - sin_sp_k = :math:`sin(\frac{2 \pi k t}{sp})` - cos_sp_k = :math:`cos(\frac{2 \pi k t}{sp})` - Where :math:`t` is the number of time steps elapsed from the beginning of the time - series. + Where :math:`t` is the elapsed time since the beginning of the seasonal period and + :math:`sp` the total time of the seasonal period. - The output of the transform is a pandas DataFrame that includes the fourier terms as + The transformed output is a pandas DataFrame that includes the fourier terms as additional columns with the naming convention stated above (sin_sp_k and cos_sp_k). - For instance for sp_list = [12, 3] and fourier_terms_list = [2, 1] the transformed - series will have the additional columns: - "cos_12_1", "sin_12_1", "cos_12_2", "sin_12_2", "cos_3_1", "sin_3_1" + The numbers of Fourier terms :math:`K` in the fourier_terms_list + determines the number of Fourier terms that will be used for each seasonal period, + i.e., Fourier terms :math:`k = 1\dots K` (integers), cos and sine, will be generated + for the seasonality :math:`sp` at the same list index. + For example, consider sp_list = [12, "Y"] and fourier_terms_list = [2, 1]. + This says that we compute 2 (2 cos, 2 sine) Fourier terms for + seasonality 12 periods, and 1 Fourier term (1 cos and 1 sine) + for seasonality 1 year. + The transformed series will then have columns with the following names: + "cos_12_1", "sin_12_1", "cos_12_2", "sin_12_2", "cos_Y_1", "sin_Y_1" The implementation is based on the fourier function from the R forecast package [3]_ Parameters ---------- - sp_list : List[float] - list of seasonal periods + sp_list : List[float and/or str] + List of seasonal periods. Can be defined with the following options: + * float : Periodicity defined as number of timesteps since the beginning of the + data seen in `fit`. + * string : Periodicity defined as a column name in X that contains the + :math:`t/sp` values + * string : Periodicity defined as a pandas period alias: + https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#period-aliases fourier_terms_list : List[int] - list of number of fourier terms (K) for each seasonal period. - Each K matches to the sp (seasonal period) of the sp_list. - For example, if sp_list = [7, 365] and fourier_terms_list = [3, 9], the seasonal - frequency of 7 will have 3 fourier terms and the seasonal frequency of 365 - will have 9 fourier terms. + List of number of fourier terms (:math:`K`) per corresponding (:math:`sp`); each + :math:`K` matches to one :math:`sp` of the sp_list. For example, if sp_list = + [7, "Y"] and fourier_terms_list = [3, 9], the seasonality of 7 timesteps will + have 3 sin_sp_k and 3 cos_sp_k fourier terms and the yearly seasonality "Y" will + have 9 sin_sp_k and 9 cos_sp_k fourier terms. freq : str, optional, default = None Only used when X has a pd.DatetimeIndex without a specified frequency. Specifies the frequency of the index of your data. The string should @@ -66,11 +79,16 @@ class FourierFeatures(BaseTransformer): >>> from sktime.transformations.series.fourier import FourierFeatures >>> from sktime.datasets import load_airline >>> y = load_airline() - >>> transformer = FourierFeatures(sp_list=[12], fourier_terms_list=[4]) + >>> transformer = FourierFeatures(sp_list=[12, "Y"], fourier_terms_list=[4, 1]) >>> y_hat = transformer.fit_transform(y) """ _tags = { + # packaging info + # -------------- + "authors": ["ltsaprounis", "blazingbhavneek"], + # estimator type + # -------------- "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", @@ -103,7 +121,6 @@ class FourierFeatures(BaseTransformer): # todo: rename to capability:missing_values "capability:missing_values:removes": False, # is transform result always guaranteed to contain no missing values? - "python_version": None, # PEP 440 python version specifier to limit versions } def __init__( @@ -124,11 +141,16 @@ def __init__( "to the length of fourier_terms_list." ) - if np.any(np.array(self.sp_list) / np.array(self.fourier_terms_list) < 1): - raise ValueError( - "In FourierFeatures the number of each element of fourier_terms_list" - "needs to be lower from the corresponding element of the sp_list" - ) + for i in range(len(self.sp_list)): + if ( + not isinstance(sp_list[i], str) + and sp_list[i] / fourier_terms_list[i] < 1 + ): + raise ValueError( + "In FourierFeatures the number of each element of " + "fourier_terms_list needs to be lower from the corresponding " + "element of the sp_list" + ) super().__init__() @@ -144,11 +166,6 @@ def _fit(self, X, y=None): Data to fit transform to y : Series or Panel of mtype y_inner_mtype, default=None Additional data, e.g., labels for transformation - freq : str, optional, default = None - Only used when X has a pd.DatetimeIndex without a specified frequency. - Specifies the frequency of the index of your data. The string should - match a pandas offset alias: - https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#offset-aliases Returns ------- @@ -160,17 +177,21 @@ def _fit(self, X, y=None): coefficient_list = [] for i, sp in enumerate(self.sp_list): for k in range(1, self.fourier_terms_list[i] + 1): - coef = k / sp - if coef not in coefficient_list: - coefficient_list.append(coef) + if not isinstance(sp, str): # periodicity sp relative to start + coef = k / sp + if coef not in coefficient_list: + coefficient_list.append(coef) + self.sp_k_pairs_list_.append((sp, k)) + else: + warnings.warn( + f"The terms sin_{sp}_{k} and cos_{sp}_{k} from " + "FourierFeatures will be skipped because the resulting " + "coefficient already exists from other seasonal period, " + "fourier term pairs.", + stacklevel=2, + ) + else: # periodicity sp from offset string or X column self.sp_k_pairs_list_.append((sp, k)) - else: - warnings.warn( - f"The terms sin_{sp}_{k} and cos_{sp}_{k} from FourierFeatures " - "will be skipped because the resulting coefficient already " - "exists from other seasonal period, fourier term pairs.", - stacklevel=2, - ) time_index = X.index @@ -178,10 +199,10 @@ def _fit(self, X, y=None): # Chooses first non None value self.freq_ = time_index.freq or self.freq or pd.infer_freq(time_index) if self.freq_ is None: - ValueError("X has no known frequency and none is supplied") + raise ValueError("X has no known frequency and none is supplied") if self.freq_ == time_index.freq and self.freq_ != self.freq: warnings.warn( - f"Using frequency from index: {time_index.freq}, which" + f"Using frequency from index: {time_index.freq}, which " f"does not match the frequency given:{self.freq}.", stacklevel=2, ) @@ -211,10 +232,12 @@ def _transform(self, X, y=None): transformed version of X """ X_transformed = pd.DataFrame(index=X.index) - time_index = X.index + X_df = pd.DataFrame(X) - if isinstance(time_index, pd.DatetimeIndex): - time_index = time_index.to_period(self.freq_) + if isinstance(X.index, pd.DatetimeIndex): + time_index = X.index.to_period(self.freq_) + else: + time_index = X.index # get the integer form of the PeriodIndex int_index = time_index.astype("int64") - self.min_t_ @@ -223,14 +246,76 @@ def _transform(self, X, y=None): sp = sp_k[0] k = sp_k[1] - X_transformed[f"sin_{sp}_{k}"] = np.sin(int_index * 2 * k * np.pi / sp) - X_transformed[f"cos_{sp}_{k}"] = np.cos(int_index * 2 * k * np.pi / sp) + if not isinstance(sp, str): # periodicity sp relative to start + X_transformed[f"sin_{sp}_{k}"] = np.sin(int_index * 2 * k * np.pi / sp) + X_transformed[f"cos_{sp}_{k}"] = np.cos(int_index * 2 * k * np.pi / sp) + + elif sp in X_df.columns: # periodicity sp from X column + frac_index = X_df[sp].values + X_transformed[f"sin_{sp}_{k}"] = np.sin(frac_index * 2 * k * np.pi) + X_transformed[f"cos_{sp}_{k}"] = np.cos(frac_index * 2 * k * np.pi) + + else: # periodicity sp from offset string + if isinstance(X.index, pd.PeriodIndex): + datetime_index = X.index.to_timestamp() + else: + datetime_index = X.index + + frac_index = self._offset_frac_since_prev_offset( + datetime_index=datetime_index, + period_str=sp, + ) + X_transformed[f"sin_{sp}_{k}"] = np.sin(frac_index * 2 * k * np.pi) + X_transformed[f"cos_{sp}_{k}"] = np.cos(frac_index * 2 * k * np.pi) if self.keep_original_columns: X_transformed = pd.concat([X, X_transformed], axis=1, copy=True) return X_transformed + def _offset_frac_since_prev_offset(self, datetime_index, period_str): + """Get time passed as fraction of the current period. + + Parameters + ---------- + datetime_index : pandas DatetimeIndex + period_str : pandas period str + Cannot contain digits + + Returns + ------- + numpy array containing the time passed between [previous offset, next offset) + as fraction in the interval [0, 1) for every datetime in datetimes + """ + + def _get_frac(datetime, offset_boundaries): + i = np.searchsorted(offset_boundaries, datetime, side="right") + prev = offset_boundaries[i - 1] + next = offset_boundaries[i] + period_timedelta = next - prev + since_prev_timedelta = datetime - prev + return since_prev_timedelta / period_timedelta + + offset = pd.tseries.frequencies.to_offset(period_str) + offset_boundaries = pd.date_range( + start=np.amin(datetime_index) - offset, + end=np.amax(datetime_index) + offset, + freq=period_str, + tz=datetime_index.tz, + ) + + # date_range created with offsets <= 1day have boundaries on the first + # moment of the new period, but date_range created with offsets > 1day + # have boundaries on the last day of the period rather than the desired + # first day of new period. workaround: shift by 1 day + offset_td = pd.to_timedelta(offset, errors="coerce") + if not offset_td <= pd.Timedelta(days=1): + offset_boundaries = offset_boundaries + pd.Timedelta(days=1) + + fracs = [_get_frac(dt, offset_boundaries) for dt in datetime_index] + + return np.array(fracs) + @classmethod def get_test_params(cls, parameter_set="default"): """Return testing parameter settings for the estimator. @@ -253,6 +338,8 @@ def get_test_params(cls, parameter_set="default"): params = [ {"sp_list": [12], "fourier_terms_list": [4]}, {"sp_list": [12, 6.2], "fourier_terms_list": [3, 4]}, + {"sp_list": ["Y"], "fourier_terms_list": [4]}, + {"sp_list": ["Y", "Q"], "fourier_terms_list": [3, 4]}, ] return params diff --git a/sktime/transformations/series/func_transform.py b/sktime/transformations/series/func_transform.py index 0d853141d9a..dd692d5e30a 100644 --- a/sktime/transformations/series/func_transform.py +++ b/sktime/transformations/series/func_transform.py @@ -18,12 +18,12 @@ class FunctionTransformer(BaseTransformer): r"""Constructs a transformer from an arbitrary callable. A FunctionTransformer forwards its y (and optionally X) arguments to a - user-defined function or function object and returns the result of this + user-defined function (or callable object) and returns the result of this function. This is useful for stateless transformations such as taking the log of frequencies, doing custom scaling, etc. - Note: If a lambda is used as the function, then the resulting - transformer will not be pickleable. + Note: If a lambda function is used as the ``func``, then the + resulting transformer will not be pickleable. Parameters ---------- @@ -74,6 +74,7 @@ class FunctionTransformer(BaseTransformer): """ _tags = { + "authors": ["BoukePostma"], "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/series/hidalgo.py b/sktime/transformations/series/hidalgo.py index 4e96a027954..9cfc0da8e00 100644 --- a/sktime/transformations/series/hidalgo.py +++ b/sktime/transformations/series/hidalgo.py @@ -84,6 +84,7 @@ class Hidalgo(BaseTransformer): """ _tags = { + "authors": ["KatieBuc"], "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/series/holiday/_holidayfeats.py b/sktime/transformations/series/holiday/_holidayfeats.py index 10d478f511d..385bfe67d6e 100644 --- a/sktime/transformations/series/holiday/_holidayfeats.py +++ b/sktime/transformations/series/holiday/_holidayfeats.py @@ -88,6 +88,13 @@ class HolidayFeatures(BaseTransformer): _required_parameters = ["calendar"] _tags = { + # packaging info + # -------------- + "authors": ["mloning", "VyomkeshVyas"], + "maintainers": "VyomkeshVyas", + "python_dependencies": ["holidays"], + # estimator type + # -------------- "scitype:transform-input": "Series", "scitype:transform-output": "Series", "scitype:transform-labels": "None", @@ -102,7 +109,6 @@ class HolidayFeatures(BaseTransformer): "enforce_index_type": [pd.DatetimeIndex], "transform-returns-same-time-index": True, "skip-inverse-transform": True, - "python_dependencies": ["holidays"], } def __init__( diff --git a/sktime/transformations/series/holiday/country_holidays.py b/sktime/transformations/series/holiday/country_holidays.py index 35d11a73604..b0b6d0913fe 100644 --- a/sktime/transformations/series/holiday/country_holidays.py +++ b/sktime/transformations/series/holiday/country_holidays.py @@ -67,6 +67,14 @@ class CountryHolidaysTransformer(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": "yarnabrina", + "maintainers": "yarnabrina", + "python_version": ">=3.8", + "python_dependencies": ["holidays"], + # estimator type + # -------------- "scitype:transform-input": "Series", "scitype:transform-output": "Series", "scitype:instancewise": True, @@ -79,8 +87,6 @@ class CountryHolidaysTransformer(BaseTransformer): "capability:inverse_transform": False, "capability:unequal_length": True, "handles-missing-data": True, - "python_version": ">=3.8", - "python_dependencies": ["holidays"], } def __init__( diff --git a/sktime/transformations/series/holiday/financial_holidays.py b/sktime/transformations/series/holiday/financial_holidays.py index e037c6a0ca7..42a0281ef52 100644 --- a/sktime/transformations/series/holiday/financial_holidays.py +++ b/sktime/transformations/series/holiday/financial_holidays.py @@ -67,6 +67,14 @@ class FinancialHolidaysTransformer(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": "yarnabrina", + "maintainers": "yarnabrina", + "python_version": ">=3.8", + "python_dependencies": ["holidays"], + # estimator type + # -------------- "scitype:transform-input": "Series", "scitype:transform-output": "Series", "scitype:instancewise": True, @@ -79,8 +87,6 @@ class FinancialHolidaysTransformer(BaseTransformer): "capability:inverse_transform": False, "capability:unequal_length": True, "handles-missing-data": True, - "python_version": ">=3.8", - "python_dependencies": ["holidays"], } def __init__(self, market, years=None, expand=True, observed=True, name=None): diff --git a/sktime/transformations/series/hpfilter.py b/sktime/transformations/series/hpfilter.py index 3ced37e68cc..04918c5a8fc 100644 --- a/sktime/transformations/series/hpfilter.py +++ b/sktime/transformations/series/hpfilter.py @@ -53,6 +53,8 @@ class HPFilter(BaseTransformer): """ _tags = { + "authors": ["ken_maeda"], + "maintainers": ["ken_maeda"], "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/series/impute.py b/sktime/transformations/series/impute.py index 40e4d6fa608..efbc4bae536 100644 --- a/sktime/transformations/series/impute.py +++ b/sktime/transformations/series/impute.py @@ -26,41 +26,54 @@ class Imputer(BaseTransformer): Method to fill the missing values. * "drift" : drift/trend values by sktime.PolynomialTrendForecaster(degree=1) - first, X in transform() is filled with ffill then bfill - then PolynomialTrendForecaster(degree=1) is fitted to filled X, and - predict values are queried at indices which had missing values + first, X in transform() is filled with ffill then bfill + then PolynomialTrendForecaster(degree=1) is fitted to filled X, and + predict values are queried at indices which had missing values * "linear" : linear interpolation, uses pd.Series.interpolate() WARNING: This method can not extrapolate, so it is fitted always on the data given to transform(). * "nearest" : use nearest value, uses pd.Series.interpolate() * "constant" : same constant value (given in arg value) for all NaN - * "mean" : pd.Series.mean() of *fit* data - * "median" : pd.Series.median() of *fit* data - * "backfill" to "bfill" : adapted from pd.Series.fillna() - * "pad" or "ffill" : adapted from pd.Series.fillna() + * "mean" : pd.Series.mean() of data seen in ``fit`` + to use data in transform, wrap this estimator in ``FitInTransform`` + * "median" : pd.Series.median() of data seen in ``fit`` + to use data in transform, wrap this estimator in ``FitInTransform`` + * "backfill" to "bfill" : applies ``pd.Series.bfill`` to all data + * "pad" or "ffill" : applies ``pd.Series.ffill`` to all data * "random" : random values between pd.Series.min() and .max() of *fit* data - if pd.Series dtype is int, sample is uniform discrete - if pd.Series dtype is float, sample is uniform continuous - * "forecaster" : use an sktime Forecaster, given in param forecaster. - First, X in *fit* is filled with ffill then bfill - then forecaster is fitted to filled X, and *predict* values are queried - at indices of X data in *transform* which had missing values - For the following methods, the train data is used to fit them: - "drift", "mean", "median", "random". For all other methods, the - transform data is sufficient to compute the impute values. - - missing_values : int/float/str, default=None - The placeholder for the missing values. All occurrences of - missing_values will be imputed, in addition to np.nan. - If None, then only np.nan values are imputed. + if pd.Series dtype is int, sample is uniform discrete + if pd.Series dtype is float, sample is uniform continuous + * "forecaster" : use an sktime forecaster, given in param ``forecaster``. + First, X seed in ``fit`` is filled with ``ffill`` then ``bfill`` + then forecaster is fitted to filled X, and ``predict`` values are queried + at indices of X data in ``transform`` which had missing values. + ``forecaster`` is always applied by variable and instance. + + The following methods, fit non-trivially to the data seen in ``fit``: + "drift", "mean", "median", "random". All other methods + do not depend on values seen in ``fit``. + + missing_values : str, int, float, regex, list, or None, default=None + Value to consider as `np.nan`` and impute, passed to ``DataFrame.replace`` + If str, int, float, all entries equal to ``missing_values`` will be imputed, + in addition to ``np.nan.`` + If regex, all entrie matching regex will be imputed, in addition to ``np.nan.`` + If list, must be list of str, int, float, or regex. + Values matching any list element by above rules will be imputed, + in addition to ``np.nan``. + If None, then only ``np.nan`` values are imputed. + value : int/float, default=None Value to use to fill missing values when method="constant". + Only used if ``method="constant"``, otherwise ignored. + forecaster : Any Forecaster based on sktime.BaseForecaster, default=None Use a given Forecaster to impute by insample predictions when - method="forecaster". Before fitting, missing data is imputed with - method="ffill" or "bfill" as heuristic. in case of multivariate X, - the forecaster is applied separate to each column like a - ColumnEnsembleForecaster. + ``method="forecaster"``. Before fitting, missing data is imputed with + ``method="ffill"`` or ``"bfill"`` as heuristic. In case of multivariate X, + a clone of ``forecaster`` is applied per column. + Only used if ``method="forecaster"``, otherwise ignored. + random_state : int/float/str, optional Value to set random.seed() if method="random", default None @@ -79,6 +92,7 @@ class Imputer(BaseTransformer): """ _tags = { + "authors": ["aiwalter"], "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", @@ -220,13 +234,13 @@ def _transform(self, X, y=None): X_grouped = X.groupby(level=list(range(index.nlevels - 1))) if self.method in ["backfill", "bfill"]: - X = X_grouped.fillna(method="bfill") + X = X_grouped.bfill() # fill trailing NAs of panel instances with reverse method - return X.fillna(method="ffill") + return X.ffill() elif self.method in ["pad", "ffill"]: - X = X_grouped.fillna(method="ffill") + X = X_grouped.ffill() # fill leading NAs of panel instances with reverse method - return X.fillna(method="bfill") + return X.bfill() elif self.method == "mean": return X_grouped.fillna(value=self._mean) elif self.method == "median": @@ -234,8 +248,10 @@ def _transform(self, X, y=None): else: raise AssertionError("Code should not be reached") else: - if self.method in ["backfill", "bfill", "pad", "ffill"]: - X = X.fillna(method=self.method) + if self.method in ["backfill", "bfill"]: + X = X.bfill() + elif self.method in ["pad", "ffill"]: + X = X.ffill() elif self.method == "drift": X = self._impute_with_forecaster(X, y) elif self.method == "forecaster": @@ -251,7 +267,7 @@ def _transform(self, X, y=None): # fill first/last elements of series, # as some methods (e.g. "linear") can't impute those - X = X.fillna(method="ffill").fillna(method="backfill") + X = X.ffill().bfill() return X @@ -272,25 +288,15 @@ def _check_method(self): "forecaster", ]: raise ValueError(f"Given method {method} is not an allowed method.") - if ( - self.value is not None - and method != "constant" - or method == "constant" - and self.value is None - ): + if method == "constant" and self.value is None: raise ValueError( - """Imputing with a value can only be - used if method="constant" and if parameter "value" is not None""" + """Imputing with method=\"constant\" can only be used if parameter + value" is not None""" ) - elif ( - self.forecaster is not None - and method != "forecaster" - or method == "forecaster" - and self.forecaster is None - ): + elif method == "forecaster" and self.forecaster is None: raise ValueError( - """Imputing with a forecaster can only be used if - method=\"forecaster\" and if arg forecaster is not None""" + """Imputing with method=\"forecaster\" can only be + used if param forecaster is not None""" ) else: pass @@ -344,10 +350,8 @@ def _impute_with_forecaster(self, X, y): # fill NaN before fitting with ffill and backfill (heuristic) self._forecaster.fit( - y=self._X[col].fillna(method="ffill").fillna(method="backfill"), - X=self._y[col].fillna(method="ffill").fillna(method="backfill") - if self._y is not None - else None, + y=self._X[col].ffill().bfill(), + X=self._y[col].ffill().bfill() if self._y is not None else None, fh=fh, ) diff --git a/sktime/transformations/series/kalman_filter.py b/sktime/transformations/series/kalman_filter.py index 360e5069eb7..843a7be7ac2 100644 --- a/sktime/transformations/series/kalman_filter.py +++ b/sktime/transformations/series/kalman_filter.py @@ -271,6 +271,8 @@ class BaseKalmanFilter: https://www.stat.pitt.edu/stoffer/dss_files/em.pdf """ + _tags = {"authors": ["NoaBenAmi", "lielleravid"], "maintainers": ["NoaBenAmi"]} + def __init__( self, state_dim, @@ -533,6 +535,14 @@ class KalmanFilterTransformerPK(BaseKalmanFilter, BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["NoaBenAmi", "lielleravid"], + "maintainers": ["NoaBenAmi"], + "python_dependencies": "pykalman-bardo", + "python_dependencies_alias": {"pykalman-bardo": "pykalman"}, + # estimator type + # -------------- "X_inner_mtype": "np.ndarray", # which mtypes do _fit/_predict support for X? "requires_y": False, # does y need to be passed in fit? "fit_is_empty": False, # is fit empty and can be skipped? Yes = True @@ -542,8 +552,6 @@ class KalmanFilterTransformerPK(BaseKalmanFilter, BaseTransformer): "capability:missing_values:removes": False, # is transform result always guaranteed to contain no missing values? "scitype:instancewise": True, # is this an instance-wise transform? - "python_dependencies": "pykalman-bardo", - "python_dependencies_alias": {"pykalman-bardo": "pykalman"}, } def __init__( @@ -998,6 +1006,13 @@ class KalmanFilterTransformerFP(BaseKalmanFilter, BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["NoaBenAmi", "lielleravid"], + "maintainers": ["NoaBenAmi"], + "python_dependencies": "filterpy", + # estimator type + # -------------- "scitype:transform-labels": "Series", # what is the scitype of y: None (not needed), Primitives, Series, Panel "X_inner_mtype": "np.ndarray", # which mtypes do _fit/_predict support for X? @@ -1010,7 +1025,6 @@ class KalmanFilterTransformerFP(BaseKalmanFilter, BaseTransformer): "capability:missing_values:removes": False, # is transform result always guaranteed to contain no missing values? "scitype:instancewise": True, # is this an instance-wise transform? - "python_dependencies": "filterpy", } def __init__( diff --git a/sktime/transformations/series/kinematic.py b/sktime/transformations/series/kinematic.py index 07acc721f56..36fb3eeb2f0 100644 --- a/sktime/transformations/series/kinematic.py +++ b/sktime/transformations/series/kinematic.py @@ -65,6 +65,7 @@ class KinematicFeatures(BaseTransformer): """ _tags = { + "authors": ["fkiraly"], "scitype:transform-input": "Series", "scitype:transform-output": "Series", "scitype:instancewise": True, diff --git a/sktime/transformations/series/lag.py b/sktime/transformations/series/lag.py index 3e359e8e468..5af0b25a527 100644 --- a/sktime/transformations/series/lag.py +++ b/sktime/transformations/series/lag.py @@ -116,6 +116,7 @@ class Lag(BaseTransformer): """ _tags = { + "authors": ["fkiraly"], "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/series/matrix_profile.py b/sktime/transformations/series/matrix_profile.py index 9ca3bba8753..ed6b037b048 100644 --- a/sktime/transformations/series/matrix_profile.py +++ b/sktime/transformations/series/matrix_profile.py @@ -39,6 +39,12 @@ class MatrixProfileTransformer(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["mloning"], + "python_dependencies": "stumpy", + # estimator type + # -------------- "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", @@ -49,7 +55,6 @@ class MatrixProfileTransformer(BaseTransformer): "y_inner_mtype": "None", # which mtypes do _fit/_predict support for y?, "univariate-only": True, "fit_is_empty": True, # for unit test cases - "python_dependencies": "stumpy", } def __init__(self, window_length=3): diff --git a/sktime/transformations/series/outlier_detection.py b/sktime/transformations/series/outlier_detection.py index 26344ed1fd6..68c13b0bc2a 100644 --- a/sktime/transformations/series/outlier_detection.py +++ b/sktime/transformations/series/outlier_detection.py @@ -53,6 +53,7 @@ class HampelFilter(BaseTransformer): """ _tags = { + "authors": ["aiwalter"], "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", @@ -171,8 +172,8 @@ def get_test_params(cls, parameter_set="default"): def _hampel_filter(Z, cv, n_sigma, half_window_length, k): for i in cv.split(Z): cv_window = i[0] - cv_median = np.nanmedian(Z[cv_window]) - cv_sigma = k * np.nanmedian(np.abs(Z[cv_window] - cv_median)) + cv_median = np.nanmedian(Z.iloc[cv_window]) + cv_sigma = k * np.nanmedian(np.abs(Z.iloc[cv_window] - cv_median)) is_start_window = cv_window[-1] == cv.window_length - 1 is_end_window = cv_window[-1] == len(Z) - 1 diff --git a/sktime/transformations/series/paa.py b/sktime/transformations/series/paa.py new file mode 100644 index 00000000000..229d16ea876 --- /dev/null +++ b/sktime/transformations/series/paa.py @@ -0,0 +1,173 @@ +"""Piecewise Aggregate Approximation Transformer.""" + +__author__ = ["steenrotsman"] + +import numpy as np + +from sktime.transformations.base import BaseTransformer +from sktime.utils.warnings import warn + + +# TODO 0.27.0: rename the class PAA2 to PAA +class PAA2(BaseTransformer): + """Piecewise Aggregate Approximation Transformer (PAA). + + PAA [1]_ is a dimensionality reduction technique that divides a time series + into frames and takes their mean. This implementation offers two variants: + 1) the original, which takes the desired number of frames and can set the + frame size to a fraction to support cases where the time series cannot be + divided into the frames equally. + 2) a variant that takes the desired frame size and can decrease the frame + size of the last frame to support cases where the time series is not + evenly divisible into frames. + + Parameters + ---------- + frames : int, optional (default=8, greater equal 1 if frame_size=0) + length of transformed time series. Ignored if `frame_size` is set. + frame_size : int, optional (default=0, greater equal 0) + length of the frames over which the mean is taken. Overrides `frames` if > 0. + + References + ---------- + .. [1] Keogh, E., Chakrabarti, K., Pazzani, M., and Mehrotra, S. + Dimensionality Reduction for Fast Similarity Search + in Large Time Series Databases. + Knowledge and Information Systems 3, 263β286 (2001). + https://doi.org/10.1007/PL00011669 + + Examples + -------- + >>> from numpy import arange + >>> from sktime.transformations.series.paa import PAA2 + + >>> X = arange(10) + >>> paa = PAA2(frames=3) + >>> paa.fit_transform(X) # doctest: +SKIP + array([1.2, 4.5, 7.8]) + >>> paa = PAA2(frame_size=3) # doctest: +SKIP + array([1, 4, 7, 9]) + """ + + _tags = { + "authors": ["steenrotsman"], + "maintainers": ["steenrotsman"], + "scitype:transform-input": "Series", + "scitype:transform-output": "Series", + "scitype:instancewise": True, + "scitype:transform-labels": "None", + "X_inner_mtype": "np.ndarray", + "y_inner_mtype": "None", + "univariate-only": True, + "requires_y": False, + "fit_is_empty": True, + "capability:inverse_transform": False, + "handles-missing-data": False, + } + + def __init__(self, frames=8, frame_size=0): + self.frames = frames + self.frame_size = frame_size + + super().__init__() + + warn( + "In sktime 0.27.0, PAA2 will become the primary PAA implementation in " + "sktime, and will be renamed to PAA. " + "PAA2 is available under both its current and future name at its " + "current location, imports under the deprecated name PAA2 will be possible" + "until 0.28.0. " + "To prepare for the name change, replace imports of PAA2 from " + "sktime.transformations.series.paa by imports of PAA from the same " + "module.", + DeprecationWarning, + obj=self, + ) + + self._check_params() + + def _transform(self, X, y=None): + """Transform X and return a transformed version. + + private _transform containing core logic, called from transform + + Parameters + ---------- + X : Series of mtype np.ndarray + data to be transformed + y : None + unused + + Returns + ------- + X_transformed : Series of mtype np.ndarray + transformed version of X + """ + if self.frame_size: + return self._transform_frame_size(X) + return self._transform_frames(X) + + def _transform_frames(self, X): + """Original PAA definition. + + First performs validity check and handles trivial cases. If self.frames evenly + divides X, calculation is easy. Else, values in X are weighed into the frames. + Last case corrects and adapts https://vigne.sh/posts/piecewise-aggregate-approx/ + """ + if self.frames > X.shape[0]: + raise ValueError( + "Series length cannot be shorter than the desired number of frames." + ) + elif not X.shape[0] % self.frames: + return X.reshape(self.frames, -1).mean(axis=1).T + + indices = np.arange(X.shape[0] * self.frames) // self.frames + return X[indices.reshape(self.frames, -1)].sum(axis=1) / X.shape[0] + + def _transform_frame_size(self, X): + if self.frame_size > X.shape[0]: + raise ValueError( + "Series length cannot be shorter than the desired frame size." + ) + elif last_frame_length := (X.shape[0] % self.frame_size): + last_frame_mean = np.mean(X[-last_frame_length:]) + last_frame_fill = [last_frame_mean] * (self.frame_size - last_frame_length) + X = np.append(X, last_frame_fill) + + return np.mean(X.reshape(-1, self.frame_size), axis=1).T + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + There are currently no reserved values for transformers. + + Returns + ------- + params : dict or list of dict, default = {} + Parameters to create testing instances of the class + Each dict are parameters to construct an "interesting" test instance, i.e., + `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. + `create_test_instance` uses the first (or only) dictionary in `params` + """ + params = {"frames": 4} + return params + + def _check_params(self): + for attribute in ["frames", "frame_size"]: + if not isinstance(getattr(self, attribute), int): + t = type(getattr(self, attribute)).__name__ + raise TypeError(f"{attribute} must be of type int. Found {t}.") + + if self.frames < 1 and not self.frame_size: + raise ValueError("frames must be at least 1.") + + +# TODO 0.27.0: switch to PAA2 = PAA +# TODO 0.28.0: remove the alias line altogether +PAA = PAA2 diff --git a/sktime/transformations/series/peak.py b/sktime/transformations/series/peak.py index c79850dd2ae..81cc91dbbc0 100644 --- a/sktime/transformations/series/peak.py +++ b/sktime/transformations/series/peak.py @@ -132,11 +132,11 @@ class PeakTimeFeature(BaseTransformer): Examples -------- - >>> from sktime.transformations.series.peak import PeakTimeFeature - >>> from sktime.datasets import load_solar - >>> y = load_solar() - >>> y = y.tz_localize(None) - >>> y = y.asfreq("H") + >>> from sktime.transformations.series.peak import PeakTimeFeature # doctest: +SKIP + >>> from sktime.datasets import # doctest: +SKIP + >>> y = load_solar() # doctest: +SKIP + >>> y = y.tz_localize(None) # doctest: +SKIP + >>> y = y.asfreq("H") # doctest: +SKIP Example 1: one interval for peak hour and working hour. (based on one start/end interval) @@ -146,8 +146,8 @@ class PeakTimeFeature(BaseTransformer): >>> transformer = PeakTimeFeature(ts_freq="H", ... peak_hour_start=[6], peak_hour_end=[9], ... working_hour_start=[8], working_hour_end=[16] - ... ) - >>> y_hat_peak = transformer.fit_transform(y) + ... ) # doctest: +SKIP + >>> y_hat_peak = transformer.fit_transform(y) # doctest: +SKIP Example 2: two intervals for peak hour and working hour. (based on two start/end intervals) @@ -157,8 +157,8 @@ class PeakTimeFeature(BaseTransformer): >>> transformer = PeakTimeFeature(ts_freq="H", ... peak_hour_start=[6, 16], peak_hour_end=[9, 20], ... working_hour_start=[8, 15], working_hour_end=[12, 19] - ... ) - >>> y_hat_peak = transformer.fit_transform(y) + ... ) # doctest: +SKIP + >>> y_hat_peak = transformer.fit_transform(y) # doctest: +SKIP Example 3: We may have peak for different seasonality Here is an example for peak hour, peak day, peak week, peak month for @@ -171,11 +171,18 @@ class PeakTimeFeature(BaseTransformer): ... peak_day_start=[1, 2], peak_day_end=[2, 3], ... peak_week_start=[35, 45], peak_week_end=[40, 52], ... peak_month_start=[1, 7], peak_month_end=[6, 12] - ... ) - >>> y_hat_peak = transformer.fit_transform(y) + ... ) # doctest: +SKIP + >>> y_hat_peak = transformer.fit_transform(y) # doctest: +SKIP """ _tags = { + # packaging info + # -------------- + "authors": ["ali-parizad"], + "maintainers": ["ali-parizad"], + "python_dependencies": "pandas>=1.2.0", # from DateTimeProperties + # estimator type + # -------------- "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", @@ -194,7 +201,6 @@ class PeakTimeFeature(BaseTransformer): "transform-returns-same-time-index": True, "enforce_index_type": [pd.DatetimeIndex, pd.PeriodIndex], "skip-inverse-transform": True, - "python_dependencies": "pandas>=1.2.0", # from DateTimeProperties } def __init__( diff --git a/sktime/transformations/series/sax.py b/sktime/transformations/series/sax.py new file mode 100644 index 00000000000..e6414b0b04c --- /dev/null +++ b/sktime/transformations/series/sax.py @@ -0,0 +1,163 @@ +"""Symbolic Aggregate Approximation Transformer.""" +__author__ = ["steenrotsman"] +import numpy as np +from scipy.stats import norm, zscore + +from sktime.transformations.base import BaseTransformer +from sktime.transformations.series.paa import PAA +from sktime.utils.warnings import warn + + +# TODO 0.27.0: rename the class SAX2 to SAX +class SAX2(BaseTransformer): + """Symbolic Aggregate approXimation Transformer (SAX). + + SAX [2]_ is a dimensionality reduction technique that z-normalises a time + series, applies Piecewise Aggregate Approximation (PAA) [1]_, and bins the + mean of each PAA frame to a discrete value, resulting in a SAX word. + + This implementation offers two variants: + 1) the original, which takes the desired number of frames and can set the + frame size to a fraction to support cases where the time series cannot be + divided into the frames equally. + 2) a variant that takes the desired frame size and can decrease the frame + size of the last frame to support cases where the time series is not + evenly divisible into frames. + + Parameters + ---------- + word_size : int, optional (default=8, greater equal 1 if frame_size=0) + length of transformed time series. Ignored if `frame_size` is set. + alphabet_size : int, optional (default=5, greater equal 2) + number of discrete values transformed time series is binned to. + frame_size : int, optional (default=0, greater equal 0) + length of the frames over which the mean is taken. Overrides `frames` if > 0. + + References + ---------- + .. [1] Keogh, E., Chakrabarti, K., Pazzani, M., and Mehrotra, S. + Dimensionality Reduction for Fast Similarity Search + in Large Time Series Databases. + Knowledge and Information Systems 3, 263β286 (2001). + https://doi.org/10.1007/PL00011669 + .. [2] Lin, J., Keogh, E., Wei, L., and Lonardi, S. + Experiencing SAX: A Novel Symbolic Representation of Time Series. + Data Mining and Knowledge Discovery 15, 107β144 (2007). + https://doi.org/10.1007/s10618-007-0064-z + + Examples + -------- + >>> from numpy import arange + >>> from sktime.transformations.series.sax import SAX2 + + >>> X = arange(10) + >>> sax = SAX2(word_size=3, alphabet_size=5) + >>> sax.fit_transform(X) # doctest: +SKIP + array([0, 2, 4]) + >>> sax = SAX2(frame_size=2, alphabet_size=5) # doctest: +SKIP + array([0, 1, 2, 3, 4]) + """ + + _tags = { + "authors": ["steenrotsman"], + "maintainers": ["steenrotsman"], + "scitype:transform-input": "Series", + "scitype:transform-output": "Series", + "scitype:instancewise": True, + "scitype:transform-labels": "None", + "X_inner_mtype": "np.ndarray", + "y_inner_mtype": "None", + "univariate-only": True, + "requires_y": False, + "fit_is_empty": True, + "capability:inverse_transform": False, + "handles-missing-data": False, + } + + def __init__(self, word_size=8, alphabet_size=5, frame_size=0): + self.word_size = word_size + self.alphabet_size = alphabet_size + self.frame_size = frame_size + + super().__init__() + + warn( + "In sktime 0.27.0, SAX2 will become the primary SAX implementation in " + "sktime, and will be renamed to SAX. " + "SAX2 is available under both its current and future name at its " + "current location, imports under the deprecated name SAX2 will be possible" + "until 0.28.0. " + "To prepare for the name change, replace imports of SAX2 from " + "sktime.transformations.series.sax by imports of SAX from the same " + "module.", + DeprecationWarning, + obj=self, + ) + + self._check_params() + + def _transform(self, X, y=None): + """Transform X and return a transformed version. + + private _transform containing core logic, called from transform + + Parameters + ---------- + X : Series of mtype np.ndarray + data to be transformed + y : None + unused + + Returns + ------- + X_transformed : Series of mtype np.ndarray + transformed version of X + """ + X_transformed = zscore(X) + paa = PAA(self.word_size, self.frame_size) + X_transformed = paa.fit_transform(X_transformed) + X_transformed = np.digitize(X_transformed, self._get_breakpoints()) + return X_transformed + + def _get_breakpoints(self): + return norm.ppf(np.arange(1, self.alphabet_size) / self.alphabet_size, loc=0) + + @classmethod + def get_test_params(cls, parameter_set="default"): + """Return testing parameter settings for the estimator. + + Parameters + ---------- + parameter_set : str, default="default" + Name of the set of test parameters to return, for use in tests. If no + special parameters are defined for a value, will return `"default"` set. + There are currently no reserved values for transformers. + + Returns + ------- + params : dict or list of dict, default = {} + Parameters to create testing instances of the class + Each dict are parameters to construct an "interesting" test instance, i.e., + `MyClass(**params)` or `MyClass(**params[i])` creates a valid test instance. + `create_test_instance` uses the first (or only) dictionary in `params` + """ + params = {"word_size": 4, "alphabet_size": 5} + return params + + def _check_params(self): + for attribute in ["word_size", "alphabet_size", "frame_size"]: + if not isinstance(getattr(self, attribute), int): + t = type(getattr(self, attribute)).__name__ + raise TypeError(f"{attribute} must be of type int. Found {t}.") + + if self.word_size < 1 and not self.frame_size: + raise ValueError("word_size must be at least 1.") + if self.alphabet_size < 2: + raise ValueError("alphabet_size must be at least 2.") + if self.frame_size < 0: + raise ValueError("frame_size must be at least 0.") + + +# TODO 0.27.0: switch to SAX2 = SAX +# TODO 0.28.0: remove the alias line altogether +SAX = SAX2 diff --git a/sktime/transformations/series/scaledasinh.py b/sktime/transformations/series/scaledasinh.py index 8df1b26532d..b459ad0d7e5 100644 --- a/sktime/transformations/series/scaledasinh.py +++ b/sktime/transformations/series/scaledasinh.py @@ -1,7 +1,7 @@ # copyright: sktime developers, BSD-3-Clause License (see LICENSE file) """Implements the Hyperbolic Sine transformation and its inverse.""" -__author__ = ["Ali Parizad"] +__author__ = ["ali-parizad"] __all__ = ["ScaledAsinhTransformer"] @@ -16,7 +16,7 @@ class ScaledAsinhTransformer(BaseTransformer): Known as variance stabilizing transformation, Combined with an sktime.forecasting.compose.TransformedTargetForecaster, - can be usefull in time series that exhibit spikes [1]_, [2]_ + can be useful in time series that exhibit spikes [1]_, [2]_ Parameters ---------- @@ -82,6 +82,12 @@ class ScaledAsinhTransformer(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["ali-parizad"], + "maintainers": ["ali-parizad"], + # estimator type + # -------------- "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/series/scaledlogit.py b/sktime/transformations/series/scaledlogit.py index 741931c9b01..e87b9ff6cbe 100644 --- a/sktime/transformations/series/scaledlogit.py +++ b/sktime/transformations/series/scaledlogit.py @@ -90,6 +90,11 @@ class ScaledLogitTransformer(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["ltsaprounis"], + # estimator type + # -------------- "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/series/subset.py b/sktime/transformations/series/subset.py index d82b6a0eeb0..53ab86a3751 100644 --- a/sktime/transformations/series/subset.py +++ b/sktime/transformations/series/subset.py @@ -36,6 +36,7 @@ class IndexSubset(BaseTransformer): """ _tags = { + "authors": ["fkiraly"], "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/series/summarize.py b/sktime/transformations/series/summarize.py index 977f8920ef3..5d4836b134a 100644 --- a/sktime/transformations/series/summarize.py +++ b/sktime/transformations/series/summarize.py @@ -11,6 +11,7 @@ from sktime.split import ExpandingWindowSplitter, SlidingWindowSplitter from sktime.transformations.base import BaseTransformer from sktime.utils.multiindex import flatten_multiindex +from sktime.utils.warnings import warn class WindowSummarizer(BaseTransformer): @@ -189,6 +190,12 @@ class WindowSummarizer(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["danbartl", "grzegorzrut", "ltsaprounis"], + "maintainers": ["danbartl"], + # estimator type + # -------------- "scitype:transform-input": "Series", "scitype:transform-output": "Series", "scitype:instancewise": True, @@ -455,7 +462,7 @@ class description for in-depth explanation. else: feat = getattr( Z.shift(lag) - .fillna(method="bfill") + .bfill() .rolling(window=window_length, min_periods=window_length), summarizer, )() @@ -474,7 +481,7 @@ class description for in-depth explanation. feat = Z.apply( lambda x: getattr( x.shift(lag) - .fillna(method="bfill") + .bfill() .rolling(window=window_length, min_periods=window_length), summarizer, )() @@ -483,7 +490,7 @@ class description for in-depth explanation. if bfill is False: feat = Z.shift(lag) else: - feat = Z.shift(lag).fillna(method="bfill") + feat = Z.shift(lag).bfill() if isinstance(Z, pd.core.groupby.generic.SeriesGroupBy) and callable( summarizer ): @@ -498,7 +505,7 @@ class description for in-depth explanation. ) feat = pd.DataFrame(feat) if bfill is True: - feat = feat.fillna(method="bfill") + feat = feat.bfill() if callable(summarizer): name = summarizer.__name__ @@ -645,6 +652,11 @@ class SummaryTransformer(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["RNKuhns", "fkiraly"], + # estimator type + # -------------- "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Primitives", @@ -763,6 +775,7 @@ def get_test_params(cls, parameter_set="default"): return [params1, params2, params3, params4] +# TODO 0.27.0: remove remember_data from docstring and __init__ class SplitterSummarizer(BaseTransformer): """Create summary values of a time series' splits. @@ -780,21 +793,46 @@ class SplitterSummarizer(BaseTransformer): Parameters ---------- transformer : `sktime` transformer inheriting from `BaseTransformer` - series-to-primitives transformer used to convert series to primitives. + series-to-primitives transformer used to convert series to primitives. splitter : `sktime` splitter inheriting from `BaseSplitter`, optional (default=None) - splitter used to divide the series. - If None, it takes `ExpandingWindowSplitter` with `start_with_window=False` - and otherwise default parameters. + splitter used to divide the series. + If None, it takes `ExpandingWindowSplitter` with `start_with_window=False` + and otherwise default parameters. index : str, optional (default="last") - Determines the indexing approach for the resulting series. - If "last", the latest index of the split is used. - If anything else, the row's number becomes the index. - - remember_data : bool, optional (default=True) - if True, memorizes data seen in ``fit``, ``update``, uses it in ``transform`` - if False, only uses data seen in ``transform`` for splits and summaries. + Determines the indexing approach for the resulting series. + If "last", the latest index of the split is used. + If anything else, the row's number becomes the index. + + fit_on : str, optional (default="transform_train") + What data to fit ``transformer`` on, for the ``i``-th row + of the resulting series. + + * "all_train" : transform the ``i``-th train split obtained from + ``splitter.split_series``, called on + all data seen in ``fit`` and ``update`` calls, + plus all data seen in ``transform``. + * "all_test" : transform the ``i``-th test split obtained from + ``splitter.split_series``, called on + all data seen in ``fit`` and ``update`` calls, + plus all data seen in ``transform``. + * "transform_train" : transform the ``i``-th train split obtained from + ``splitter.split_series``, called on the data seen in ``transform``. + * "transform_test" : transform the ``i``-th test split obtained from + ``splitter.split_series``, called on the data seen in ``transform``. + + transform_on : str, optional (default="transform_train") + What data to transform with ``transformer``, for the ``i``-th row + of the resulting series. + Values and meaning same as for ``fit_on``. + + remember_data : bool, optional (default=False) + deprecated, will be removed in 0.27.0. + If set, overrides ``fit_on`` and ``transform_on``: + + * True: ``fit_on="all_train"``, ``transform_on="all_train"`` + * False: ``fit_on="transform_train"``, ``transform_on="transform_train"`` Methods ------- @@ -819,6 +857,11 @@ class SplitterSummarizer(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["BensHamza", "fkiraly"], + # estimator type + # -------------- "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", @@ -830,11 +873,21 @@ class SplitterSummarizer(BaseTransformer): "fit_is_empty": True, } - def __init__(self, transformer, splitter=None, index="last", remember_data=False): + def __init__( + self, + transformer, + splitter=None, + index="last", + remember_data=None, + fit_on="transform_train", + transform_on="transform_train", + ): self.transformer = transformer self.index = index self.splitter = splitter self.remember_data = remember_data + self.fit_on = fit_on + self.transform_on = transform_on if splitter is None: self._splitter = SlidingWindowSplitter(start_with_window=False) @@ -851,12 +904,34 @@ def __init__(self, transformer, splitter=None, index="last", remember_data=False if not hasattr(self._splitter, "split_series"): raise ValueError( f"Error in {self.__class__.__name__}, splitter parameter, if passed, " - "should be an BaseSplitter descendant with a seplit_series method" + "should be an BaseSplitter descendant with a split_series method" ) - if remember_data: + # TODO 0.27.0: remove remember_data and related logic + # remove next lie + need_to_remember_data = remember_data is not None and remember_data + # replace next two lines by + # need_to_remember_data = fit_on.startswith("all") + # or transform_on.startswith("all") + need_to_remember_data = need_to_remember_data or fit_on.startswith("all") + need_to_remember_data = need_to_remember_data or transform_on.startswith("all") + + if need_to_remember_data: self.set_tags(**{"remember_data": True, "fit_is_empty": False}) + # TODO 0.27.0: remove remember_data and related logic + if remember_data is not None: + warn( + "remember_data is deprecated and will be removed in 0.27.0. " + "Use fit_on and transform_on instead. " + "Replace remember_data=True with fit_on='all_train' and " + "transform_on='all_train'. Replace remember_data=False with " + "fit_on='transform_train' and transform_on='transform_train'.", + DeprecationWarning, + obj=self, + stacklevel=2, + ) + def _transform(self, X, y=None): """Transform X and return a transformed version. @@ -874,16 +949,38 @@ def _transform(self, X, y=None): Xt : pd.DataFrame The transformed Data """ - if self.remember_data: - X = X.combine_first(self._X) + fit_on = self.fit_on + transform_on = self.transform_on + + if self.remember_data is not None: + if self.remember_data: + fit_on = "all_train" + transform_on = "all_train" + else: + fit_on = "transform_train" + transform_on = "transform_train" + + X_dict = {"transform": X} + + if fit_on.startswith("all") or transform_on.startswith("all"): + X_all = X.combine_first(self._X) + X_dict["all"] = X_all + + fit_on_data = fit_on.split("_")[0] + transform_on_data = transform_on.split("_")[0] + fit_on_ix = int(fit_on.split("_")[1] == "test") + transform_on_ix = int(transform_on.split("_")[1] == "test") transformed_series = [] - splits = self._splitter.split_series(X) + splits_fit = self._splitter.split_series(X_dict[fit_on_data]) + splits_transform = self._splitter.split_series(X_dict[transform_on_data]) - for split in splits: + for split_fit, split_transform in zip(splits_fit, splits_transform): tf = self.transformer.clone() - transformed_split = tf.fit_transform(split[0]) - transformed_split.index = [split[0].index[-1]] + X_fit = split_fit[fit_on_ix] + X_transform = split_transform[transform_on_ix] + transformed_split = tf.fit(X_fit).transform(X_transform) + transformed_split.index = [X_transform.index[-1]] transformed_series.append(transformed_split) Xt = pd.concat(transformed_series) @@ -927,7 +1024,8 @@ def get_test_params(cls, parameter_set="default"): params3 = { "transformer": SummaryTransformer(), "splitter": SlidingWindowSplitter(window_length=3, step_length=2), - "remember_data": True, + "fit_on": "all_train", + "transform_on": "all_train", } params4 = { @@ -936,6 +1034,8 @@ def get_test_params(cls, parameter_set="default"): window_length=3, step_length=2, fh=1, start_with_window=True ), "index": "last", + "fit_on": "all_test", + "transform_on": "transform_test", } return [params1, params2, params3, params4] diff --git a/sktime/transformations/series/tests/test_imputer.py b/sktime/transformations/series/tests/test_imputer.py index d0275454e02..05b958d105b 100644 --- a/sktime/transformations/series/tests/test_imputer.py +++ b/sktime/transformations/series/tests/test_imputer.py @@ -31,6 +31,8 @@ z.iloc[-1] = np.nan +@pytest.mark.parametrize("forecaster", [None, NaiveForecaster()]) +@pytest.mark.parametrize("value", [None, 1]) @pytest.mark.parametrize("Z", [y, X, z]) @pytest.mark.parametrize( "method", @@ -47,10 +49,10 @@ "forecaster", ], ) -def test_imputer(method, Z): +def test_imputer(method, Z, value, forecaster): """Test univariate and multivariate Imputer with all methods.""" - forecaster = NaiveForecaster() if method == "forecaster" else None - value = 3 if method == "constant" else None + forecaster = NaiveForecaster() if method == "forecaster" else forecaster + value = 1 if method == "constant" else value t = Imputer(method=method, forecaster=forecaster, value=value) y_hat = t.fit_transform(Z) assert not y_hat.isnull().to_numpy().any() diff --git a/sktime/transformations/series/tests/test_paa.py b/sktime/transformations/series/tests/test_paa.py new file mode 100644 index 00000000000..4acf1b13d68 --- /dev/null +++ b/sktime/transformations/series/tests/test_paa.py @@ -0,0 +1,44 @@ +"""PAA transformer test code.""" +import numpy as np +import pytest + +from sktime.transformations.series.paa import PAA2 + + +# Check that exception is raised for bad frames values. +# input types - string, float, negative int, negative float, empty dict. +# correct input is an integer of 1 or more, but less than or equal to series length. +@pytest.mark.parametrize("bad_frames", ["str", 1.2, -1.2, -1, {}, 0, 11]) +def test_bad_input_args(bad_frames): + """Test that exception is raised for bad num levels.""" + X = np.arange(10).T + + if not isinstance(bad_frames, int): + for attribute in ["frames", "frame_size"]: + with pytest.raises(TypeError): + PAA2(**{attribute: bad_frames}).fit(X).transform(X) + else: + with pytest.raises(ValueError): + PAA2(bad_frames).fit(X).transform(X) + + +@pytest.mark.parametrize( + "frames,frame_size,expected", + [ + (1, 0, [4.5]), + (2, 0, [2, 7]), + (3, 0, [1.2, 4.5, 7.8]), + (10, 0, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), + (0, 1, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), + (0, 2, [0.5, 2.5, 4.5, 6.5, 8.5]), + (0, 3, [1, 4, 7, 9]), + (0, 10, [4.5]), + ], +) +def test_output_of_transformer(frames, frame_size, expected): + """Test that the transformer has changed the data correctly.""" + X = np.arange(10).T + paa = PAA2(frames, frame_size) + res = paa.fit_transform(X) + want = np.array(expected, dtype=np.float64).T + np.testing.assert_array_equal(res, want) diff --git a/sktime/transformations/series/tests/test_sax.py b/sktime/transformations/series/tests/test_sax.py new file mode 100644 index 00000000000..ca122c932ff --- /dev/null +++ b/sktime/transformations/series/tests/test_sax.py @@ -0,0 +1,48 @@ +"""SAX transformer test code.""" +import numpy as np +import pytest + +from sktime.transformations.series.sax import SAX2 + + +# Check that exception is raised for bad size values. +# input types - string, float, negative float, empty dict. +# correct input is an integer, see below for value restrictions. +@pytest.mark.parametrize("bad_size", ["str", 1.2, -1.2, {}]) +def test_bad_input_types(bad_size): + """Test that exception is raised for bad sizes.""" + for attribute in ["word_size", "alphabet_size", "frame_size"]: + with pytest.raises(TypeError): + SAX2(**{attribute: bad_size}) + + +@pytest.mark.parametrize( + "attribute,bad_size", + [ + ("word_size", 0), + ("alphabet_size", 1), + ("frame_size", -1), + ], +) +def test_bad_input_values(attribute, bad_size): + """Test that word_size is at least 1 (if frame_size is not set).""" + with pytest.raises(ValueError): + SAX2(**{attribute: bad_size}) + + +@pytest.mark.parametrize( + "word_size,alphabet_size,frame_size,expected", + [ + (2, 5, 0, [0, 4]), + (3, 5, 0, [0, 2, 4]), + (0, 5, 2, [0, 1, 2, 3, 4]), + (0, 5, 3, [0, 2, 4, 4]), + ], +) +def test_output_of_transformer(word_size, alphabet_size, frame_size, expected): + """Test that the transformer has changed the data correctly.""" + X = np.arange(10).T + sax = SAX2(word_size, alphabet_size, frame_size) + res = sax.fit_transform(X) + want = np.array(expected, dtype=np.float64).T + np.testing.assert_array_equal(res, want) diff --git a/sktime/transformations/series/theta.py b/sktime/transformations/series/theta.py index 38243d91b1a..f980ff6243f 100644 --- a/sktime/transformations/series/theta.py +++ b/sktime/transformations/series/theta.py @@ -60,6 +60,11 @@ class ThetaLinesTransformer(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["GuzalBulatova", "mloning"], + # estimator type + # -------------- "scitype:transform-input": "Series", # what is the scitype of X: Series, or Panel "scitype:transform-output": "Series", diff --git a/sktime/transformations/series/time_since.py b/sktime/transformations/series/time_since.py index 21b85c1c645..d7732cdfaf2 100644 --- a/sktime/transformations/series/time_since.py +++ b/sktime/transformations/series/time_since.py @@ -73,6 +73,12 @@ class TimeSince(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["KishManani"], + "maintainers": ["KishManani"], + # estimator type + # -------------- # what is the scitype of X: Series, or Panel "scitype:transform-input": "Series", # what scitype is returned: Primitives, Series, Panel diff --git a/sktime/transformations/series/vmd/_vmd.py b/sktime/transformations/series/vmd/_vmd.py index 155670a7531..3dcc9744c3f 100644 --- a/sktime/transformations/series/vmd/_vmd.py +++ b/sktime/transformations/series/vmd/_vmd.py @@ -97,6 +97,12 @@ class VmdTransformer(BaseTransformer): """ _tags = { + # packaging info + # -------------- + "authors": ["DaneLyttinen", "vcarvo"], + "maintainers": ["DaneLyttinen", "vcarvo"], + # estimator type + # -------------- "scitype:transform-input": "Series", "scitype:transform-output": "Series", "scitype:instancewise": True, diff --git a/sktime/transformations/tests/test_all_transformers.py b/sktime/transformations/tests/test_all_transformers.py index 493fb63d33f..b6a9699ac62 100644 --- a/sktime/transformations/tests/test_all_transformers.py +++ b/sktime/transformations/tests/test_all_transformers.py @@ -78,6 +78,8 @@ def _expected_trafo_output_scitype(self, X_scitype, trafo_input, trafo_output): return "Panel" if X_scitype in ["Panel", "Hierarchical"]: return "Hierarchical" + if trafo_input == "Panel" and trafo_output == "Series": + return "Series" def test_fit_transform_output(self, estimator_instance, scenario): """Test that transform output is of expected scitype.""" diff --git a/sktime/transformations/tests/test_base.py b/sktime/transformations/tests/test_base.py index 4e09393af9f..be3b7f85b4a 100644 --- a/sktime/transformations/tests/test_base.py +++ b/sktime/transformations/tests/test_base.py @@ -35,11 +35,15 @@ TransformerFitTransformSeriesUnivariate, ) from sktime.utils._testing.series import _make_series +from sktime.utils.parallel import _get_parallel_test_fixtures from sktime.utils.validation._dependencies import _check_soft_dependencies # other scenarios that might be needed later in development: # TransformerFitTransformPanelUnivariateWithClassY, +# list of parallelization backends to test +BACKENDS = _get_parallel_test_fixtures("config") + def inner_X_scitypes(est): """Return list of scitypes supported by class est, as list of str.""" @@ -183,7 +187,7 @@ def test_panel_in_panel_out_supported(): # todo: possibly, add mtype check, use metadata return -@pytest.mark.parametrize("backend", [None, "joblib", "loky", "threading"]) +@pytest.mark.parametrize("backend", BACKENDS) def test_panel_in_panel_out_not_supported_but_series(backend): """Test that fit/transform runs and returns the correct output type. @@ -199,7 +203,7 @@ def test_panel_in_panel_out_not_supported_but_series(backend): # one example for a transformer which supports Series internally but not Panel cls = BoxCoxTransformer est = cls.create_test_instance() - est.set_config(**{"backend:parallel": backend}) + est.set_config(**backend.copy()) # ensure cls is a good example, if this fails, choose another example # (if this changes, it may be due to implementing more scitypes) # (then this is not a failure of cls, but we need to choose another example) @@ -253,7 +257,7 @@ def test_series_in_primitives_out_supported_fit_in_transform(): assert len(Xt) == 1 -@pytest.mark.parametrize("backend", [None, "joblib", "loky", "threading"]) +@pytest.mark.parametrize("backend", BACKENDS) def test_panel_in_primitives_out_not_supported_fit_in_transform(backend): """Test that fit/transform runs and returns the correct output type. @@ -269,7 +273,7 @@ def test_panel_in_primitives_out_not_supported_fit_in_transform(backend): # one example for a transformer which supports Series internally but not Panel cls = SummaryTransformer est = cls.create_test_instance() - est.set_config(**{"backend:parallel": backend}) + est.set_config(**backend.copy()) # ensure cls is a good example, if this fails, choose another example # (if this changes, it may be due to implementing more scitypes) # (then this is not a failure of cls, but we need to choose another example) @@ -370,7 +374,7 @@ def test_panel_in_primitives_out_supported_with_y_in_fit_but_not_transform(): assert len(Xt) == 7 -@pytest.mark.parametrize("backend", [None, "joblib", "loky", "threading"]) +@pytest.mark.parametrize("backend", BACKENDS) def test_hierarchical_in_hierarchical_out_not_supported_but_series(backend): """Test that fit/transform runs and returns the correct output type. @@ -386,7 +390,7 @@ def test_hierarchical_in_hierarchical_out_not_supported_but_series(backend): # one example for a transformer which supports Series internally cls = BoxCoxTransformer est = cls.create_test_instance() - est.set_config(**{"backend:parallel": backend}) + est.set_config(**backend.copy()) # ensure cls is a good example, if this fails, choose another example # (if this changes, it may be due to implementing more scitypes) # (then this is not a failure of cls, but we need to choose another example) @@ -444,7 +448,7 @@ def test_hierarchical_in_hierarchical_out_not_supported_but_series_fit_in_transf assert len(Xt) == 2 * 4 * 12 -@pytest.mark.parametrize("backend", [None, "joblib", "loky", "threading"]) +@pytest.mark.parametrize("backend", BACKENDS) def test_vectorization_multivariate_no_row_vectorization(backend): """Test that multivariate vectorization of univariate transformers works. @@ -463,7 +467,7 @@ def test_vectorization_multivariate_no_row_vectorization(backend): # one example for a transformer which supports Series internally cls = BoxCoxTransformer est = cls.create_test_instance() - est.set_config(**{"backend:parallel": backend}) + est.set_config(**backend.copy()) # ensure cls is a good example, if this fails, choose another example # (if this changes, it may be due to implementing multivariate functionality) # (then this is not a failure of cls, but we need to choose another example) @@ -485,7 +489,7 @@ def test_vectorization_multivariate_no_row_vectorization(backend): assert len(Xt.columns) == len(scenario.args["fit"]["X"].columns) -@pytest.mark.parametrize("backend", [None, "joblib", "loky", "threading"]) +@pytest.mark.parametrize("backend", BACKENDS) def test_vectorization_multivariate_and_hierarchical(backend): """Test that fit/transform runs and returns the correct output type. @@ -504,7 +508,7 @@ def test_vectorization_multivariate_and_hierarchical(backend): # one example for a transformer which supports Series internally cls = BoxCoxTransformer est = cls.create_test_instance() - est.set_config(**{"backend:parallel": backend}) + est.set_config(**backend.copy()) # ensure cls is a good example, if this fails, choose another example # (if this changes, it may be due to implementing more scitypes) # (then this is not a failure of cls, but we need to choose another example) @@ -528,7 +532,7 @@ def test_vectorization_multivariate_and_hierarchical(backend): assert len(Xt.columns) == len(scenario.args["fit"]["X"].columns) -@pytest.mark.parametrize("backend", [None, "joblib", "loky", "threading"]) +@pytest.mark.parametrize("backend", BACKENDS) def test_vectorization_multivariate_no_row_vectorization_empty_fit(backend): """Test that multivariate vectorization of univariate transformers works. @@ -547,7 +551,7 @@ def test_vectorization_multivariate_no_row_vectorization_empty_fit(backend): # one example for a transformer which supports Series internally cls = BoxCoxTransformer est = FitInTransform(cls.create_test_instance()) - est.set_config(**{"backend:parallel": backend}) + est.set_config(**backend.copy()) # ensure cls is a good example, if this fails, choose another example # (if this changes, it may be due to implementing multivariate functionality) # (then this is not a failure of cls, but we need to choose another example) @@ -569,7 +573,7 @@ def test_vectorization_multivariate_no_row_vectorization_empty_fit(backend): assert len(Xt.columns) == len(scenario.args["fit"]["X"].columns) -@pytest.mark.parametrize("backend", [None, "joblib", "loky", "threading"]) +@pytest.mark.parametrize("backend", BACKENDS) def test_vectorization_multivariate_and_hierarchical_empty_fit(backend): """Test that fit/transform runs and returns the correct output type. @@ -588,7 +592,7 @@ def test_vectorization_multivariate_and_hierarchical_empty_fit(backend): # one example for a transformer which supports Series internally cls = BoxCoxTransformer est = FitInTransform(cls.create_test_instance()) - est.set_config(**{"backend:parallel": backend}) + est.set_config(**backend.copy()) # ensure cls is a good example, if this fails, choose another example # (if this changes, it may be due to implementing more scitypes) # (then this is not a failure of cls, but we need to choose another example) diff --git a/sktime/transformations/tests/test_compose.py b/sktime/transformations/tests/test_compose.py index 92cb635b5a5..0b64a605be9 100644 --- a/sktime/transformations/tests/test_compose.py +++ b/sktime/transformations/tests/test_compose.py @@ -5,10 +5,12 @@ __all__ = [] import pandas as pd +import pytest from sklearn.preprocessing import StandardScaler from sktime.datasets import load_airline from sktime.datatypes import get_examples +from sktime.transformations.bootstrap import STLBootstrapTransformer from sktime.transformations.compose import ( FeatureUnion, InvertTransform, @@ -22,8 +24,9 @@ from sktime.transformations.series.subset import ColumnSelect from sktime.transformations.series.summarize import SummaryTransformer from sktime.transformations.series.theta import ThetaLinesTransformer -from sktime.utils._testing.deep_equals import deep_equals from sktime.utils._testing.estimator_checks import _assert_array_almost_equal +from sktime.utils.deep_equals import deep_equals +from sktime.utils.validation._dependencies import _check_estimator_deps def test_dunder_mul(): @@ -83,8 +86,28 @@ def test_dunder_add(): _assert_array_almost_equal(t123r.fit_transform(X), t123.fit_transform(X)) +def test_add_sklearn_autoadapt(): + """Test the add dunder method, with sklearn coercion.""" + X = pd.DataFrame({"a": [1, 2], "b": [3, 4]}) + + t1 = ExponentTransformer(power=2) + t2 = StandardScaler() + t3 = ExponentTransformer(power=3) + + t123 = t1 + t2 + t3 + t123r = t1 + (t2 + t3) + t123l = (t1 + t2) + t3 + + assert isinstance(t123, FeatureUnion) + assert isinstance(t123r, FeatureUnion) + assert isinstance(t123l, FeatureUnion) + + _assert_array_almost_equal(t123.fit_transform(X), t123l.fit_transform(X)) + _assert_array_almost_equal(t123r.fit_transform(X), t123l.fit_transform(X)) + + def test_mul_sklearn_autoadapt(): - """Test auto-adapter for sklearn in mul.""" + """Test the mul dunder method, with sklearn coercion.""" X = pd.DataFrame({"a": [1, 2], "b": [3, 4]}) t1 = ExponentTransformer(power=2) @@ -262,3 +285,26 @@ def test_dunder_neg(): assert isinstance(tp.get_params()["transformer"], ExponentTransformer) _assert_array_almost_equal(tp.fit_transform(X), X) + + +@pytest.mark.skipif( + not _check_estimator_deps(STLBootstrapTransformer, severity="none"), + reason="skip test if required soft dependency for statsmodels not available", +) +def test_input_output_series_panel_chain(): + """Test that series-to-panel can be chained with series-to-series trafos. + + Failure case of #5624. + """ + from sktime.datasets import load_airline + from sktime.transformations.series.impute import Imputer + + X = load_airline() + bootstrap_trafo = STLBootstrapTransformer(4, sp=4) * Imputer(method="nearest") + + assert bootstrap_trafo.get_tags()["scitype:transform-input"] == "Series" + assert bootstrap_trafo.get_tags()["scitype:transform-output"] == "Panel" + + Xt = bootstrap_trafo.fit_transform(X) + assert isinstance(Xt, pd.DataFrame) + assert isinstance(Xt.index, pd.MultiIndex) diff --git a/sktime/utils/_maint/_show_versions.py b/sktime/utils/_maint/_show_versions.py index d45caa54679..cc2c621ced6 100644 --- a/sktime/utils/_maint/_show_versions.py +++ b/sktime/utils/_maint/_show_versions.py @@ -75,7 +75,7 @@ def _get_deps_info(deps=None): deps = ["sktime"] def get_version(module): - return module.__version__ + return getattr(module, "__version__", None) deps_info = {} @@ -85,10 +85,11 @@ def get_version(module): mod = sys.modules[modname] else: mod = importlib.import_module(modname) - ver = get_version(mod) - deps_info[modname] = ver except ImportError: deps_info[modname] = None + else: + ver = get_version(mod) + deps_info[modname] = ver return deps_info diff --git a/sktime/utils/_maint/tests/test_show_versions.py b/sktime/utils/_maint/tests/test_show_versions.py index 0953f97a345..25c7a06b639 100644 --- a/sktime/utils/_maint/tests/test_show_versions.py +++ b/sktime/utils/_maint/tests/test_show_versions.py @@ -1,4 +1,6 @@ """Tests for the show_versions utility.""" +import pathlib +import uuid from sktime.utils._maint._show_versions import ( DEFAULT_DEPS_TO_SHOW, @@ -31,3 +33,15 @@ def test_deps_info(): assert _check_soft_dependencies(f"{key}=={deps_info_default[key]}") deps_single_key = _get_deps_info([key]) assert set(deps_single_key.keys()) == {key} + + +def test_deps_info_deps_missing_package_present_directory(): + """Test that _get_deps_info does not fail if a dependency is missing.""" + dummy_package_name = uuid.uuid4().hex + + dummy_folder_path = pathlib.Path(dummy_package_name) + dummy_folder_path.mkdir() + + assert _get_deps_info([dummy_package_name]) == {dummy_package_name: None} + + dummy_folder_path.rmdir() diff --git a/sktime/utils/_testing/deep_equals.py b/sktime/utils/_testing/deep_equals.py index 84494ad5987..f3f81adbc8e 100644 --- a/sktime/utils/_testing/deep_equals.py +++ b/sktime/utils/_testing/deep_equals.py @@ -16,9 +16,86 @@ import pandas as pd +# todo 0.27.0: check whether scikit-base>=0.6.1 lower bound is 0.6.1 or higher +# if yes, remove this legacy function and use the new one from sktime.utils.deep_equals def deep_equals(x, y, return_msg=False): """Test two objects for equality in value. + Correct if x/y are one of the following valid types: + types compatible with != comparison + pd.Series, pd.DataFrame, np.ndarray + lists, tuples, or dicts of a valid type (recursive) + delayed types that result in the above when calling .compute(), e.g., dask df + + Important note: + this function will return "not equal" if types of x,y are different + for instant, bool and numpy.bool are *not* considered equal + + Parameters + ---------- + x : object + y : object + return_msg : bool, optional, default=False + whether to return informative message about what is not equal + + Returns + ------- + is_equal: bool - True if x and y are equal in value + x and y do not need to be equal in reference + msg : str, only returned if return_msg = True + indication of what is the reason for not being equal + concatenation of the following strings: + .type - type is not equal + .len - length is not equal + .value - value is not equal + .keys - if dict, keys of dict are not equal + if class/object, names of attributes and methods are not equal + .dtype - dtype of pandas or numpy object is not equal + .index - index of pandas object is not equal + .series_equals, .df_equals, .index_equals - .equals of pd returns False + [i] - if tuple/list: i-th element not equal + [key] - if dict: value at key is not equal + [colname] - if pandas.DataFrame: column with name colname is not equal + != - call to generic != returns False + """ + from sktime.utils.validation._dependencies import _check_soft_dependencies + from sktime.utils.warnings import warn + + deprec_explain = ( + "The legacy deep_equals from sktime.utils._testing.deep_equals is " + "deprecated and should be replaced by the new deep_equals," + " from sktime.utils.deep_equals, which requires scikit-base>=0.6.1. " + ) + + removal_schedule = ( + "The legacy deep_equals is not scheduled for removal yet, this " + "warning will change to specify a removal date when it is scheduled." + ) + + if _check_soft_dependencies( + "scikit-base>=0.6.1", + package_import_alias={"scikit-base": "skbase"}, + ): + env_msg = ( + "As you have scikit-base>=0.6.1, please update your imports to use the " + "new deep_equals utility. " + ) + else: + env_msg = ( + "As you have scikit-base<0.6.1, please consider updating your environment " + "to scikit-base>=0.6.1, and update your imports to use the " + "new deep_equals utility. " + ) + + msg = deprec_explain + env_msg + removal_schedule + warn(msg, FutureWarning, stacklevel=2) + + return deep_equals_legacy(x, y, return_msg=return_msg) + + +def deep_equals_legacy(x, y, return_msg=False): + """Test two objects for equality in value. + Correct if x/y are one of the following valid types: types compatible with != comparison pd.Series, pd.DataFrame, np.ndarray @@ -98,11 +175,67 @@ def ret(is_equal, msg="", string_arguments: list = None): else: return ret(x.equals(y), ".series_equals, x = {} != y = {}", [x, y]) elif isinstance(x, pd.DataFrame): + # check column names for equality if not x.columns.equals(y.columns): return ret( False, f".columns, x.columns = {x.columns} != y.columns = {y.columns}" ) - # if columns are equal and at least one is object, recurse over Series + # check dtypes for equality + if not x.dtypes.equals(y.dtypes): + return ret( + False, f".dtypes, x.dtypes = {x.dtypes} != y.dtypes = {y.dtypes}" + ) + # check index for equality + # we are not recursing due to ambiguity in integer index types + # which may differ from pandas version to pandas version + # and would upset the type check, e.g., RangeIndex(2) vs Index([0, 1]) + xix = x.index + yix = y.index + if hasattr(xix, "dtype") and hasattr(xix, "dtype"): + if not xix.dtype == yix.dtype: + return ret( + False, + ".index.dtype, x.index.dtype = {} != y.index.dtype = {}", + [xix.dtype, yix.dtype], + ) + if hasattr(xix, "dtypes") and hasattr(yix, "dtypes"): + if not x.dtypes.equals(y.dtypes): + return ret( + False, + ".index.dtypes, x.dtypes = {} != y.index.dtypes = {}", + [xix.dtypes, yix.dtypes], + ) + ix_eq = xix.equals(yix) + if not ix_eq: + if not len(xix) == len(yix): + return ret( + False, + ".index.len, x.index.len = {} != y.index.len = {}", + [len(xix), len(yix)], + ) + if hasattr(xix, "name") and hasattr(yix, "name"): + if not xix.name == yix.name: + return ret( + False, + ".index.name, x.index.name = {} != y.index.name = {}", + [xix.name, yix.name], + ) + if hasattr(xix, "names") and hasattr(yix, "names"): + if not len(xix.names) == len(yix.names): + return ret( + False, + ".index.names, x.index.names = {} != y.index.name = {}", + [xix.names, yix.names], + ) + if not np.all(xix.names == yix.names): + return ret( + False, + ".index.names, x.index.names = {} != y.index.name = {}", + [xix.names, yix.names], + ) + elts_eq = np.all(xix == yix) + return ret(elts_eq, ".index.equals, x = {} != y = {}", [xix, yix]) + # if columns, dtypes are equal and at least one is object, recurse over Series if sum(x.dtypes == "object") > 0: for c in x.columns: is_equal, msg = deep_equals(x[c], y[c], return_msg=True) @@ -112,11 +245,22 @@ def ret(is_equal, msg="", string_arguments: list = None): else: return ret(x.equals(y), ".df_equals, x = {} != y = {}", [x, y]) elif isinstance(x, pd.Index): + if hasattr(x, "dtype") and hasattr(y, "dtype"): + if not x.dtype == y.dtype: + return ret(False, f".dtype, x.dtype = {x.dtype} != y.dtype = {y.dtype}") + if hasattr(x, "dtypes") and hasattr(y, "dtypes"): + if not x.dtypes.equals(y.dtypes): + return ret( + False, f".dtypes, x.dtypes = {x.dtypes} != y.dtypes = {y.dtypes}" + ) return ret(x.equals(y), ".index_equals, x = {} != y = {}", [x, y]) elif isinstance(x, np.ndarray): if x.dtype != y.dtype: return ret(False, f".dtype, x.dtype = {x.dtype} != y.dtype = {y.dtype}") - return ret(np.array_equal(x, y, equal_nan=True), ".values") + if x.dtype in ["object", "str"]: + return ret(np.array_equal(x, y), ".values") + else: + return ret(np.array_equal(x, y, equal_nan=True), ".values") # recursion through lists, tuples and dicts elif isinstance(x, (list, tuple)): return ret(*_tuple_equals(x, y, return_msg=True)) diff --git a/sktime/utils/_testing/estimator_checks.py b/sktime/utils/_testing/estimator_checks.py index a275d8d644e..ff56eb21fd1 100644 --- a/sktime/utils/_testing/estimator_checks.py +++ b/sktime/utils/_testing/estimator_checks.py @@ -20,6 +20,7 @@ from sktime.datatypes._panel._check import is_nested_dataframe from sktime.dists_kernels import BasePairwiseTransformer, BasePairwiseTransformerPanel from sktime.forecasting.base import BaseForecaster +from sktime.registry import scitype from sktime.regression.base import BaseRegressor from sktime.tests._config import VALID_ESTIMATOR_TYPES from sktime.transformations.base import BaseTransformer @@ -216,6 +217,11 @@ def get_tag(est, tag_name, tag_value_default=None): return True return get_tag(est, "capability:pred_int", False) # skip transform for forecasters that have it - pipelines - if method == "transform" and isinstance(est, BaseForecaster): + if method == "transform" and scitype(est) in ( + "classifier", + "forecaster", + ): + return False + if method == "predict" and scitype(est) == "transformer": return False return True diff --git a/sktime/utils/_testing/scenarios_classification.py b/sktime/utils/_testing/scenarios_classification.py index ae12056bc14..dedff1ed032 100644 --- a/sktime/utils/_testing/scenarios_classification.py +++ b/sktime/utils/_testing/scenarios_classification.py @@ -14,9 +14,7 @@ from inspect import isclass from sktime.base import BaseObject -from sktime.classification.base import BaseClassifier -from sktime.classification.early_classification import BaseEarlyClassifier -from sktime.regression.base import BaseRegressor +from sktime.registry import scitype from sktime.utils._testing.hierarchical import _make_hierarchical from sktime.utils._testing.panel import _make_classification_y, _make_panel_X from sktime.utils._testing.scenarios import TestScenario @@ -71,12 +69,14 @@ def get_tag(obj, tag_name): else: return obj.get_tag(tag_name) - regr_or_classf = (BaseClassifier, BaseEarlyClassifier, BaseRegressor) - # applicable only if obj inherits from BaseClassifier, BaseEarlyClassifier or # BaseRegressor. currently we test both classifiers and regressors using these # scenarios - if not isinstance(obj, regr_or_classf) and not issubclass(obj, regr_or_classf): + if scitype(obj) not in ( + "classifier", + "early_classifier", + "regressor", + ): return False # if X is multivariate, applicable only if can handle multivariate diff --git a/sktime/utils/_testing/scenarios_forecasting.py b/sktime/utils/_testing/scenarios_forecasting.py index 2dc06aecd25..9281153fde7 100644 --- a/sktime/utils/_testing/scenarios_forecasting.py +++ b/sktime/utils/_testing/scenarios_forecasting.py @@ -18,7 +18,7 @@ from sktime.base import BaseObject from sktime.datatypes import mtype_to_scitype -from sktime.forecasting.base import BaseForecaster +from sktime.registry import scitype from sktime.utils._testing.hierarchical import _make_hierarchical from sktime.utils._testing.panel import _make_panel_X from sktime.utils._testing.scenarios import TestScenario @@ -49,7 +49,7 @@ def get_tag(obj, tag_name): return obj.get_tag(tag_name) # applicable only if obj inherits from BaseForecaster - if not isinstance(obj, BaseForecaster) and not issubclass(obj, BaseForecaster): + if scitype(obj) != "forecaster": return False # applicable only if number of variables in y complies with scitype:y diff --git a/sktime/utils/_testing/tests/test_panel.py b/sktime/utils/_testing/tests/test_panel.py index c791eaa571d..788c7f057cf 100644 --- a/sktime/utils/_testing/tests/test_panel.py +++ b/sktime/utils/_testing/tests/test_panel.py @@ -58,7 +58,9 @@ def test_make_panel(n_instances, n_columns, n_timepoints, return_mtype): return_mtype=return_mtype, ) - valid, _, metadata = check_is_mtype(X, mtype=return_mtype, return_metadata=True) + valid, _, metadata = check_is_mtype( + X, mtype=return_mtype, return_metadata=True, msg_return_dict="list" + ) msg = f"_make_panel_X generated data does not comply with mtype {return_mtype}" assert valid, msg assert metadata["n_instances"] == n_instances diff --git a/sktime/utils/deep_equals/__init__.py b/sktime/utils/deep_equals/__init__.py new file mode 100644 index 00000000000..cdbd0571aff --- /dev/null +++ b/sktime/utils/deep_equals/__init__.py @@ -0,0 +1,19 @@ +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) +"""Module for nested equality checking.""" +from sktime.utils.validation._dependencies import _check_soft_dependencies + +# todo 0.27.0: check whether scikit-base>=0.6.1 lower bound is 0.6.1 or higher +# if yes, remove legacy handling and only use the new deep_equals +if _check_soft_dependencies( + "scikit-base<0.6.1", + package_import_alias={"scikit-base": "skbase"}, + severity="none", +): + from sktime.utils._testing.deep_equals import deep_equals + +else: + from sktime.utils.deep_equals._deep_equals import deep_equals + +__all__ = [ + "deep_equals", +] diff --git a/sktime/utils/deep_equals/_deep_equals.py b/sktime/utils/deep_equals/_deep_equals.py new file mode 100644 index 00000000000..1d7d3397767 --- /dev/null +++ b/sktime/utils/deep_equals/_deep_equals.py @@ -0,0 +1,187 @@ +"""Testing utility to compare equality in value for nested objects. + +Objects compared can have one of the following valid types: + types compatible with != comparison + pd.Series, pd.DataFrame, np.ndarray + lists, tuples, or dicts of a valid type (recursive) + polars.DataFrame, polars.LazyFrame +""" +from skbase.utils.deep_equals._common import _make_ret +from skbase.utils.deep_equals._deep_equals import deep_equals as _deep_equals + +__author__ = ["fkiraly"] +__all__ = ["deep_equals"] + + +def deep_equals(x, y, return_msg=False, plugins=None): + """Test two objects for equality in value. + + Correct if x/y are one of the following valid types: + types compatible with != comparison + pd.Series, pd.DataFrame, np.ndarray + lists, tuples, or dicts of a valid type (recursive) + + Important note: + this function will return "not equal" if types of x,y are different + for instant, bool and numpy.bool are *not* considered equal + + Parameters + ---------- + x : object + y : object + return_msg : bool, optional, default=False + whether to return informative message about what is not equal + plugins : list, optional, default=None + optional additional deep_equals plugins to use + will be appended to the default plugins from ``skbase`` ``deep_equals_custom`` + see ``skbase`` ``deep_equals_custom`` for details of signature of plugins + + Returns + ------- + is_equal: bool - True if x and y are equal in value + x and y do not need to be equal in reference + msg : str, only returned if return_msg = True + indication of what is the reason for not being equal + concatenation of the following strings: + .type - type is not equal + .len - length is not equal + .value - value is not equal + .keys - if dict, keys of dict are not equal + if class/object, names of attributes and methods are not equal + .dtype - dtype of pandas or numpy object is not equal + .index - index of pandas object is not equal + .series_equals, .df_equals, .index_equals - .equals of pd returns False + [i] - if tuple/list: i-th element not equal + [key] - if dict: value at key is not equal + [colname] - if pandas.DataFrame: column with name colname is not equal + != - call to generic != returns False + """ + # call deep_equals_custom with default plugins + plugins_default = [ + _csr_matrix_equals_plugin, + _dask_dataframe_equals_plugin, + _fh_equals_plugin, + ] + + if plugins is not None: + plugins_inner = plugins_default + plugins + else: + plugins_inner = plugins_default + + res = _deep_equals(x, y, return_msg=return_msg, plugins=plugins_inner) + return res + + +def _fh_equals_plugin(x, y, return_msg=False, deep_equals=None): + """Test two forecasting horizons for equality. + + Correct if both x and y are ForecastingHorizon. + + Parameters + ---------- + x: ForcastingHorizon + y: ForcastingHorizon + return_msg : bool, optional, default=False + whether to return informative message about what is not equal + + Returns + ------- + is_equal: bool - True if x and y are equal in value + x and y do not need to be equal in reference + msg : str, only returned if return_msg = True + indication of what is the reason for not being equal + concatenation of the following strings: + .is_relative - x is absolute and y is relative, or vice versa + .values - values of x and y are not equal + """ + if type(x).__name__ != "ForecastingHorizon": + return None + + ret = _make_ret(return_msg) + + if x.is_relative != y.is_relative: + return ret(False, ".is_relative") + + # recurse through values of x, y + is_equal, msg = deep_equals(x._values, y._values, return_msg=True) + if not is_equal: + return ret(False, ".values" + msg) + + return ret(True, "") + + +def _csr_matrix_equals_plugin(x, y, return_msg=False, deep_equals=None): + """Test two scipy csr_matrix for equality. + + Correct if both x and y are csr_matrix. + + Parameters + ---------- + x: csr_matrix + y: csr_matrix + return_msg : bool, optional, default=False + whether to return informative message about what is not equal + + Returns + ------- + is_equal: bool - True if x and y are equal in value + x and y do not need to be equal in reference + msg : str, only returned if return_msg = True + indication of what is the reason for not being equal + if unequal, returns string + returns None if this function does not apply, i.e., x is not dask + """ + if type(x).__name__ != "csr_matrix": # isinstance(x, csr_matrix): + return None + + import numpy as np + + ret = _make_ret(return_msg) + + # csr-matrix must not be compared using np.any(x!=y) + if not np.allclose(x.A, y.A): + return ret(False, " !=, {} != {}", [x, y]) + + return ret(True, "") + + +def _dask_dataframe_equals_plugin(x, y, return_msg=False, deep_equals=None): + """Test two dask dataframes for equality. + + Correct if both x and y are dask.dataframe. + + Parameters + ---------- + x: dask.dataframe + y: dask.dataframe + return_msg : bool, optional, default=False + whether to return informative message about what is not equal + + Returns + ------- + is_equal: bool - True if x and y are equal in value + x and y do not need to be equal in reference + msg : str, only returned if return_msg = True + indication of what is the reason for not being equal + if unequal, returns string + returns None if this function does not apply, i.e., x is not dask.dataframe + """ + if not hasattr(x, "compute"): + return None + + from sktime.utils.validation._dependencies import _check_soft_dependencies + + dask_available = _check_soft_dependencies("dask", severity="none") + + if not dask_available: + return None + + import dask + + if not isinstance(x, dask.dataframe.DataFrame): + return None + + x = x.compute() + y = y.compute() + + return deep_equals(x, y, return_msg=return_msg) diff --git a/sktime/utils/deep_equals/tests/__init__.py b/sktime/utils/deep_equals/tests/__init__.py new file mode 100644 index 00000000000..b55ccc21978 --- /dev/null +++ b/sktime/utils/deep_equals/tests/__init__.py @@ -0,0 +1 @@ +"""Tests for deep_equals utility.""" diff --git a/sktime/utils/_testing/tests/test_deep_equals.py b/sktime/utils/deep_equals/tests/test_deep_equals.py similarity index 85% rename from sktime/utils/_testing/tests/test_deep_equals.py rename to sktime/utils/deep_equals/tests/test_deep_equals.py index 9d16330eb17..7b1b849f88f 100644 --- a/sktime/utils/_testing/tests/test_deep_equals.py +++ b/sktime/utils/deep_equals/tests/test_deep_equals.py @@ -4,9 +4,10 @@ import numpy as np import pandas as pd import pytest +from scipy.sparse import csr_matrix from sktime.forecasting.base import ForecastingHorizon -from sktime.utils._testing.deep_equals import deep_equals +from sktime.utils.deep_equals._deep_equals import deep_equals # examples used for comparison below EXAMPLES = [ @@ -26,6 +27,11 @@ ForecastingHorizon([1, 2, 3], is_relative=False), {"foo": [42], "bar": pd.Series([1, 2])}, {"bar": [42], "foo": pd.Series([1, 2])}, + csr_matrix((3, 4), dtype=np.int8), + pd.Index([1, 2, 3]), + pd.Index([2, 3, 4]), + np.array([0.1, 1], dtype="object"), + np.array([0.2, 1], dtype="object"), ] diff --git a/sktime/utils/estimator_checks.py b/sktime/utils/estimator_checks.py index 46319ee11cd..1d05c65dccc 100644 --- a/sktime/utils/estimator_checks.py +++ b/sktime/utils/estimator_checks.py @@ -3,8 +3,6 @@ __author__ = ["fkiraly"] __all__ = ["check_estimator"] -from inspect import isclass - from sktime.utils.validation._dependencies import _check_soft_dependencies @@ -108,70 +106,14 @@ def check_estimator( ) _check_soft_dependencies("pytest", msg=msg) - from sktime.alignment.tests.test_all_aligners import TestAllAligners - from sktime.base import BaseEstimator - from sktime.classification.early_classification.tests.test_all_early_classifiers import ( # noqa E501 - TestAllEarlyClassifiers, - ) - from sktime.classification.tests.test_all_classifiers import TestAllClassifiers - from sktime.dists_kernels.tests.test_all_dist_kernels import ( - TestAllPairwiseTransformers, - TestAllPanelTransformers, - ) - from sktime.forecasting.tests.test_all_forecasters import TestAllForecasters - from sktime.param_est.tests.test_all_param_est import TestAllParamFitters - from sktime.proba.tests.test_all_distrs import TestAllDistributions - from sktime.registry import scitype - from sktime.regression.tests.test_all_regressors import TestAllRegressors - from sktime.tests.test_all_estimators import TestAllEstimators, TestAllObjects - from sktime.transformations.tests.test_all_transformers import TestAllTransformers - - testclass_dict = dict() - testclass_dict["aligner"] = TestAllAligners - testclass_dict["classifier"] = TestAllClassifiers - testclass_dict["distribution"] = TestAllDistributions - testclass_dict["early_classifier"] = TestAllEarlyClassifiers - testclass_dict["forecaster"] = TestAllForecasters - testclass_dict["param_est"] = TestAllParamFitters - testclass_dict["regressor"] = TestAllRegressors - testclass_dict["transformer"] = TestAllTransformers - testclass_dict["transformer-pairwise"] = TestAllPairwiseTransformers - testclass_dict["transformer-pairwise-panel"] = TestAllPanelTransformers - - results = TestAllObjects().run_tests( - estimator=estimator, - raise_exceptions=raise_exceptions, - tests_to_run=tests_to_run, - fixtures_to_run=fixtures_to_run, - tests_to_exclude=tests_to_exclude, - fixtures_to_exclude=fixtures_to_exclude, - ) - - def is_estimator(obj): - """Return whether obj is an estimator class or estimator object.""" - if isclass(obj): - return issubclass(obj, BaseEstimator) - else: - return isinstance(obj, BaseEstimator) + from sktime.tests.test_class_register import get_test_classes_for_obj - if is_estimator(estimator): - results_estimator = TestAllEstimators().run_tests( - estimator=estimator, - raise_exceptions=raise_exceptions, - tests_to_run=tests_to_run, - fixtures_to_run=fixtures_to_run, - tests_to_exclude=tests_to_exclude, - fixtures_to_exclude=fixtures_to_exclude, - ) - results.update(results_estimator) + test_clss_for_est = get_test_classes_for_obj(estimator) - try: - scitype_of_estimator = scitype(estimator) - except Exception: - scitype_of_estimator = "" + results = {} - if scitype_of_estimator in testclass_dict.keys(): - results_scitype = testclass_dict[scitype_of_estimator]().run_tests( + for test_cls in test_clss_for_est: + test_cls_results = test_cls().run_tests( estimator=estimator, raise_exceptions=raise_exceptions, tests_to_run=tests_to_run, @@ -179,7 +121,7 @@ def is_estimator(obj): tests_to_exclude=tests_to_exclude, fixtures_to_exclude=fixtures_to_exclude, ) - results.update(results_scitype) + results.update(test_cls_results) failed_tests = [key for key in results.keys() if results[key] != "PASSED"] if len(failed_tests) > 0: diff --git a/sktime/utils/estimators/tests/test_forecasters.py b/sktime/utils/estimators/tests/test_forecasters.py index 686c481f6a7..2e2419ce2ad 100644 --- a/sktime/utils/estimators/tests/test_forecasters.py +++ b/sktime/utils/estimators/tests/test_forecasters.py @@ -8,7 +8,6 @@ from sktime.datasets import load_airline from sktime.forecasting.base import ForecastingHorizon -from sktime.utils._testing.deep_equals import deep_equals from sktime.utils.estimators import MockUnivariateForecasterLogger y_series = load_airline().iloc[:-5] @@ -39,6 +38,8 @@ def test_mock_univariate_forecaster_log(y, X_train, X_pred, fh): - All the private methods that have logging enabled are in the log - the correct inner mtypes are preserved, according to the forecaster tags """ + from sktime.utils.deep_equals import deep_equals + forecaster = MockUnivariateForecasterLogger() forecaster.fit(y, X_train, fh) forecaster.predict(fh, X_pred) diff --git a/sktime/utils/git_diff.py b/sktime/utils/git_diff.py index a88a7e9ac6a..fb0b29a70fb 100644 --- a/sktime/utils/git_diff.py +++ b/sktime/utils/git_diff.py @@ -78,3 +78,83 @@ class to get module string from, e.g., NaiveForecaster """ module_str = get_module_from_class(cls) return is_module_changed(module_str) + + +def get_changed_lines(file_path, only_indented=True): + """Get changed or added lines from a file. + + Compares the current branch to the origin-main branch. + + Parameters + ---------- + file_path : str + path to file to get changed lines from + only_indented : bool, default=True + if True, only indented lines are returned, otherwise all lines are returned; + more precisely, only changed/added lines starting with a space are returned + + Returns + ------- + list of str : changed or added lines on current branch + """ + cmd = f"git diff remotes/origin/main -- {file_path}" + + try: + # Run 'git diff' command to get the changes in the specified file + result = subprocess.check_output(cmd, shell=True, text=True) + + # if only indented lines are requested, add space to start_chars + start_chars = "+" + if only_indented: + start_chars += " " + + # Extract the changed or new lines and return as a list of strings + changed_lines = [ + line.strip() for line in result.split("\n") if line.startswith(start_chars) + ] + # remove first character ('+') from each line + changed_lines = [line[1:] for line in changed_lines] + + return changed_lines + + except subprocess.CalledProcessError: + return [] + + +def get_packages_with_changed_specs(): + """Get packages with changed or added specs. + + Returns + ------- + list of str : names of packages with changed or added specs + """ + from packaging.requirements import Requirement + + changed_lines = get_changed_lines("pyproject.toml") + + packages = [] + for line in changed_lines: + if line.find("'") > line.find('"') and line.find('"') != -1: + sep = '"' + elif line.find("'") == -1: + sep = '"' + else: + sep = "'" + + splits = line.split(sep) + if len(splits) < 2: + continue + + req = line.split(sep)[1] + + # deal with ; python_version >= "3.7" in requirements + if ";" in req: + req = req.split(";")[0] + + pkg = Requirement(req).name + packages.append(pkg) + + # make unique + packages = list(set(packages)) + + return packages diff --git a/sktime/utils/index.py b/sktime/utils/index.py new file mode 100644 index 00000000000..c9c4cde9f68 --- /dev/null +++ b/sktime/utils/index.py @@ -0,0 +1,20 @@ +"""Utility functions for working with indices.""" + +import numpy as np + + +def random_ss_ix(ix, size, replace=True): + """Randomly uniformly sample indices from a list of indices. + + Parameters + ---------- + ix : pd.Index or subsettable iterable via getitem + list of indices to sample from + size : int + number of indices to sample + replace : bool, default=True + whether to sample with replacement + """ + a = range(len(ix)) + ixs = ix[np.random.choice(a, size=size, replace=replace)] + return ixs diff --git a/sktime/utils/mlflow_sktime.py b/sktime/utils/mlflow_sktime.py index 7c720bcdf52..4124bda414b 100644 --- a/sktime/utils/mlflow_sktime.py +++ b/sktime/utils/mlflow_sktime.py @@ -33,7 +33,7 @@ `pyfunc.predict()` will return output from sktime `predict()` method. """ -__author__ = ["benjaminbluhm"] +__author__ = ["benjaminbluhm", "achieveordie"] __all__ = [ "get_default_pip_requirements", "get_default_conda_env", @@ -44,17 +44,17 @@ import logging import os -import pickle import pandas as pd import yaml import sktime from sktime import utils +from sktime.base._serialize import load from sktime.utils.multiindex import flatten_multiindex -from sktime.utils.validation._dependencies import _check_soft_dependencies +from sktime.utils.validation._dependencies import _check_mlflow_dependencies -if _check_soft_dependencies("mlflow", severity="warning"): +if _check_mlflow_dependencies(severity="warning"): from mlflow import pyfunc FLAVOR_NAME = "mlflow_sktime" @@ -93,7 +93,7 @@ def get_default_pip_requirements(include_cloudpickle=False): Calls to :func:`save_model()` and :func:`log_model()` produce a pip environment that, at a minimum, contains these requirements. """ - _check_soft_dependencies("mlflow", severity="error") + _check_mlflow_dependencies(severity="error") from mlflow.utils.requirements_utils import _get_pinned_requirement pip_deps = [_get_pinned_requirement("sktime")] @@ -111,7 +111,7 @@ def get_default_conda_env(include_cloudpickle=False): The default Conda environment for MLflow Models produced by calls to :func:`save_model()` and :func:`log_model()` """ - _check_soft_dependencies("mlflow", severity="error") + _check_mlflow_dependencies(severity="error") from mlflow.utils.environment import _mlflow_conda_env return _mlflow_conda_env( @@ -211,7 +211,7 @@ def save_model( >>> loaded_model = mlflow_sktime.load_model(model_uri=model_path) # doctest: +SKIP >>> loaded_model.predict(fh=[1, 2, 3]) # doctest: +SKIP """ # noqa: E501 - _check_soft_dependencies("mlflow", severity="error") + _check_mlflow_dependencies(severity="error") from mlflow.exceptions import MlflowException from mlflow.models import Model from mlflow.models.model import MLMODEL_FILE_NAME @@ -258,7 +258,7 @@ def save_model( if input_example is not None: _save_example(mlflow_model, input_example, path) - model_data_subpath = "model.pkl" + model_data_subpath = "model" model_data_path = os.path.join(path, model_data_subpath) _save_model( sktime_model, model_data_path, serialization_format=serialization_format @@ -420,7 +420,7 @@ def log_model( ... sktime_model=forecaster, ... artifact_path=artifact_path) # doctest: +SKIP """ # noqa: E501 - _check_soft_dependencies("mlflow", severity="error") + _check_mlflow_dependencies(severity="error") from mlflow.models import Model if await_registration_for is None: @@ -493,7 +493,7 @@ def load_model(model_uri, dst_path=None): ... path=model_path) >>> loaded_model = mlflow_sktime.load_model(model_uri=model_path) # doctest: +SKIP """ # noqa: E501 - _check_soft_dependencies("mlflow", severity="error") + _check_mlflow_dependencies(severity="error") from mlflow.tracking.artifact_utils import _download_artifact_from_uri from mlflow.utils.model_utils import ( _add_code_from_conf_to_system_path, @@ -519,30 +519,20 @@ def load_model(model_uri, dst_path=None): def _save_model(model, path, serialization_format): - _check_soft_dependencies("mlflow", severity="error") + _check_mlflow_dependencies(severity="error") from mlflow.exceptions import MlflowException from mlflow.protos.databricks_pb2 import INTERNAL_ERROR - with open(path, "wb") as out: - if serialization_format == SERIALIZATION_FORMAT_PICKLE: - pickle.dump(model, out) - elif serialization_format == SERIALIZATION_FORMAT_CLOUDPICKLE: - _check_soft_dependencies("cloudpickle", severity="error") - import cloudpickle - - cloudpickle.dump(model, out) - else: - raise MlflowException( - message="Unrecognized serialization format: " - "{serialization_format}".format( - serialization_format=serialization_format - ), - error_code=INTERNAL_ERROR, - ) + if serialization_format not in SUPPORTED_SERIALIZATION_FORMATS: + raise MlflowException( + message="Unrecognized serialization format: " f"{serialization_format}.", + error_code=INTERNAL_ERROR, + ) + model.save(path=path, serialization_format=serialization_format) def _load_model(path, serialization_format): - _check_soft_dependencies("mlflow", severity="error") + _check_mlflow_dependencies(severity="error") from mlflow.exceptions import MlflowException from mlflow.protos.databricks_pb2 import INVALID_PARAMETER_VALUE @@ -559,14 +549,7 @@ def _load_model(path, serialization_format): error_code=INVALID_PARAMETER_VALUE, ) - with open(path, "rb") as pickled_model: - if serialization_format == SERIALIZATION_FORMAT_PICKLE: - return pickle.load(pickled_model) - elif serialization_format == SERIALIZATION_FORMAT_CLOUDPICKLE: - _check_soft_dependencies("cloudpickle", severity="error") - import cloudpickle - - return cloudpickle.load(pickled_model) + return load(path) def _load_pyfunc(path): @@ -585,7 +568,7 @@ def _load_pyfunc(path): ---------- .. [1] https://www.mlflow.org/docs/latest/python_api/mlflow.pyfunc.html#mlflow.pyfunc.load_model """ # noqa: E501 - _check_soft_dependencies("mlflow", severity="error") + _check_mlflow_dependencies(severity="error") from mlflow.exceptions import MlflowException from mlflow.utils.model_utils import _get_flavor_configuration @@ -621,7 +604,7 @@ def _load_pyfunc(path): class _SktimeModelWrapper: def __init__(self, sktime_model): - _check_soft_dependencies("mlflow", severity="error") + _check_mlflow_dependencies(severity="error") self.sktime_model = sktime_model def predict(self, X): diff --git a/sktime/utils/pandas.py b/sktime/utils/pandas.py new file mode 100644 index 00000000000..b0419e67bd2 --- /dev/null +++ b/sktime/utils/pandas.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 -u +"""Utilities for pandas adapbation.""" + +__author__ = ["fkiraly"] + + +def df_map(x): + """Access map or applymap, of DataFrame. + + In pandas 2.1.0, applymap was deprecated in favor of the newly introduced map. + To ensure compatibility with older versions, we use map if available, + otherwise applymap. + + Parameters + ---------- + x : assumed pd.DataFrame + + Returns + ------- + x.map, if available, otherwise x.applymap + Note: returns method itself, not result of method call + """ + if hasattr(x, "map"): + return x.map + else: + return x.applymap diff --git a/sktime/utils/parallel.py b/sktime/utils/parallel.py index ab839145cac..5e099248523 100644 --- a/sktime/utils/parallel.py +++ b/sktime/utils/parallel.py @@ -38,6 +38,7 @@ def parallelize(fun, iter, meta=None, backend=None, backend_params=None): - "None": executes loop sequentally, simple list comprehension - "loky", "multiprocessing" and "threading": uses ``joblib`` ``Parallel`` loops + - "joblib": custom and 3rd party ``joblib`` backends, e.g., ``spark`` - "dask": uses ``dask``, requires ``dask`` package in environment - "dask_lazy": same as ``"dask"``, but returns delayed object instead of list @@ -46,9 +47,16 @@ def parallelize(fun, iter, meta=None, backend=None, backend_params=None): Valid keys depend on the value of ``backend``: - "None": no additional parameters, ``backend_params`` is ignored - - "loky", "multiprocessing" and "threading": + - "loky", "multiprocessing" and "threading": default ``joblib`` backends any valid keys for ``joblib.Parallel`` can be passed here, e.g., ``n_jobs``, - with the exception of ``backend`` which is directly controlled by ``backend`` + with the exception of ``backend`` which is directly controlled by ``backend``. + If ``n_jobs`` is not passed, it will default to ``-1``, other parameters + will default to ``joblib`` defaults. + - "joblib": custom and 3rd party ``joblib`` backends, e.g., ``spark``. + any valid keys for ``joblib.Parallel`` can be passed here, e.g., ``n_jobs``, + ``backend`` must be passed as a key of ``backend_params`` in this case. + If ``n_jobs`` is not passed, it will default to ``-1``, other parameters + will default to ``joblib`` defaults. - "dask": any valid keys for ``dask.compute`` can be passed, e.g., ``scheduler`` """ if meta is None: @@ -72,6 +80,7 @@ def parallelize(fun, iter, meta=None, backend=None, backend_params=None): "loky": "joblib", "multiprocessing": "joblib", "threading": "joblib", + "joblib": "joblib", "dask": "dask", "dask_lazy": "dask", } @@ -92,7 +101,29 @@ def _parallelize_joblib(fun, iter, meta, backend, backend_params): from joblib import Parallel, delayed par_params = backend_params.copy() - par_params["backend"] = backend + if "backend" not in par_params: + # if user selects custom joblib backend but does not specify backend explicitly, + # raise a ValueError + if backend == "joblib": + raise ValueError( + '"joblib" was selected as first layer parallelization backend, ' + "but no backend string was " + 'passed in the backend parameters dict, e.g., "spark". ' + "Please specify a backend to joblib as a key-value pair " + "in the backend_params arg or the backend:parallel:params config " + 'when using "joblib". ' + 'For clarity, "joblib" should only be used for two-layer ' + "backend dispatch, where the first layer is joblib, " + "and the second layer is a custom backend of joblib, e.g., spark. " + "For first-party joblib backends, please use the backend string " + 'of sktime directly, e.g., by specifying "multiprocessing" or "loky".' + ) + # in all other cases, we ensure the backend parameter is one of + # "loky", "multiprocessing" or "threading", as passed via backend + else: + par_params["backend"] = backend + elif backend != "joblib": + par_params["backend"] = backend if "n_jobs" not in par_params: par_params["n_jobs"] = -1 @@ -118,11 +149,31 @@ def _parallelize_dask(fun, iter, meta, backend, backend_params): para_dict["dask"] = _parallelize_dask -def _get_parallel_test_fixtures(): +def _get_parallel_test_fixtures(naming="estimator"): """Return fixtures for parallelization tests. Returns a list of parameter fixtures, where each fixture is a dict with keys "backend" and "backend_params". + + Parameters + ---------- + naming : str, optional + naming convention for the parameters, one of + + "estimator": for use in estimator constructors, + ``backend`` and ``backend_params`` + "config": for use in ``set_config``, + ``backend:parallel`` and ``backend:parallel:params`` + + Returns + ------- + fixtures : list of dict + list of backend parameter fixtures + keys depend on ``naming`` parameter, see above + either ``backend`` and ``backend_params`` (``naming="estimator"``), + or ``backend:parallel`` and ``backend:parallel:params`` (``naming="config"``) + values are backend strings and backend parameter dicts + only backends that are available in the environment are included """ from sktime.utils.validation._dependencies import _check_soft_dependencies diff --git a/sktime/utils/plotting.py b/sktime/utils/plotting.py index 64e2b49fa8f..ef4af2ce468 100644 --- a/sktime/utils/plotting.py +++ b/sktime/utils/plotting.py @@ -2,8 +2,8 @@ # copyright: sktime developers, BSD-3-Clause License (see LICENSE file) """Common timeseries plotting functionality.""" -__all__ = ["plot_series", "plot_correlations", "plot_windows"] -__author__ = ["mloning", "RNKuhns", "Dbhasin1", "chillerobscuro"] +__all__ = ["plot_series", "plot_correlations", "plot_windows", "plot_calibration"] +__author__ = ["mloning", "RNKuhns", "Dbhasin1", "chillerobscuro", "benheid"] import math from warnings import simplefilter, warn @@ -176,20 +176,23 @@ def format_fn(tick_val, tick_pos): ax.legend() if pred_interval is not None: check_interval_df(pred_interval, series[-1].index) - ax = plot_interval(ax, pred_interval) + ax = plot_interval(ax, pred_interval, index) if _ax_kwarg_is_none: return fig, ax else: return ax -def plot_interval(ax, interval_df): +def plot_interval(ax, interval_df, ix=None): cov = interval_df.columns.levels[1][0] var_name = interval_df.columns.levels[0][0] + x_ix = np.argwhere(ix.isin(interval_df.index)).ravel() + x_ix = np.array(x_ix) + ax.fill_between( - ax.get_lines()[-1].get_xdata(), - interval_df[var_name][cov]["lower"].astype("float64"), - interval_df[var_name][cov]["upper"].astype("float64"), + x_ix, + interval_df[var_name][cov]["lower"].astype("float64").to_numpy(), + interval_df[var_name][cov]["upper"].astype("float64").to_numpy(), alpha=0.2, color=ax.get_lines()[-1].get_c(), label=f"{int(cov * 100)}% prediction interval", @@ -446,7 +449,7 @@ def plot_windows(cv, y, title="", ax=None): # create figure if no ax provided for plotting if _ax_kwarg_is_none: - fig, ax = plt.subplots(1, figsize=plt.figaspect(0.25)) + fig, ax = plt.subplots(figsize=plt.figaspect(0.3)) train_windows, test_windows = _get_windows(cv, y) @@ -460,8 +463,6 @@ def get_y(length, split): train_color, test_color = sns.color_palette("colorblind")[:2] - fig, ax = plt.subplots(figsize=plt.figaspect(0.3)) - for i in range(n_splits): train = train_windows[i] test = test_windows[i] @@ -501,3 +502,66 @@ def get_y(length, split): return fig, ax else: return ax + + +def plot_calibration(y_true, y_pred, ax=None): + """Plot the calibration of a probabilistic forecast. + + Calculates internally the calibration of the quantile forecast and + visualise it. + + x-axis: interval from 0 to 1 + y-axis: interval from 0 to 1 + plot elements: the calibration fo the forecast (blue) and the ideal + calibration (orange) + + Parameters + ---------- + y_true : pd.Series, single columned pd.DataFrame, or single columned np.array. + The actual values of the forecast + y_pred : pd.DataFrame + The quantile forecast. + ax : matplotlib.axes.Axes, optional (default=None) + Axes on which to plot. If None, axes will be created and returned. + + Returns + ------- + fig : matplotlib.figure.Figure, returned only if ax is None + matplotlib figure object + ax : matplotlib.axes.Axes + matplotlib axes object with the figure + """ + import matplotlib.pyplot as plt + + series = convert_to(y_true, "pd.Series", "Series") + + _ax_kwarg_is_none = True if ax is None else False + + if _ax_kwarg_is_none: + fig, ax = plt.subplots(1, figsize=plt.figaspect(0.25)) + + result = [0] + ideal_calibration = [0] + + for col in y_pred.columns: + if isinstance(col, tuple): + q = col[1] + else: + q = col + pred_q = convert_to(y_pred[[col]], "pd.Series", "Series") + result.append(sum(series.values < pred_q.values) / len(pred_q.values)) + ideal_calibration.append(q) + result.append(1) + ideal_calibration.append(1) + + df = pd.DataFrame( + {"Forecast's Calibration": result, "Ideal Calibration": ideal_calibration}, + index=ideal_calibration, + ) + + df.plot(ax=ax) + + if _ax_kwarg_is_none: + return fig, ax + else: + return ax diff --git a/sktime/utils/sklearn/__init__.py b/sktime/utils/sklearn/__init__.py new file mode 100644 index 00000000000..5b1546d3361 --- /dev/null +++ b/sktime/utils/sklearn/__init__.py @@ -0,0 +1,21 @@ +"""Sklearn related utility functionality.""" + +from sktime.utils.sklearn._adapt_df import prep_skl_df +from sktime.utils.sklearn._scitype import ( + is_sklearn_classifier, + is_sklearn_clusterer, + is_sklearn_estimator, + is_sklearn_regressor, + is_sklearn_transformer, + sklearn_scitype, +) + +__all__ = [ + "prep_skl_df", + "is_sklearn_estimator", + "is_sklearn_transformer", + "is_sklearn_classifier", + "is_sklearn_regressor", + "is_sklearn_clusterer", + "sklearn_scitype", +] diff --git a/sktime/utils/sklearn/_adapt_df.py b/sktime/utils/sklearn/_adapt_df.py new file mode 100644 index 00000000000..300764c1b67 --- /dev/null +++ b/sktime/utils/sklearn/_adapt_df.py @@ -0,0 +1,31 @@ +"""Utility functions for adapting to sklearn.""" +# copyright: sktime developers, BSD-3-Clause License (see LICENSE file) + +import numpy as np + + +def prep_skl_df(df, copy_df=False): + """Make df compatible with sklearn input expectations. + + Changes: + turns column index into a list of strings + + Parameters + ---------- + df : pd.DataFrame + list of indices to sample from + copy_df : bool, default=False + whether to mutate df or return a copy + if False, index of df is mutated + if True, original df is not mutated. If index is not a list of strings, + a copy is made and the copy is mutated. Otherwise, the original df is returned. + """ + cols = df.columns + str_cols = cols.astype(str) + + if not np.all(str_cols == cols): + if copy_df: + df = df.copy() + df.columns = str_cols + + return df diff --git a/sktime/utils/sklearn.py b/sktime/utils/sklearn/_scitype.py similarity index 100% rename from sktime/utils/sklearn.py rename to sktime/utils/sklearn/_scitype.py diff --git a/sktime/utils/sklearn/tests/__init__.py b/sktime/utils/sklearn/tests/__init__.py new file mode 100644 index 00000000000..1d9b760fee6 --- /dev/null +++ b/sktime/utils/sklearn/tests/__init__.py @@ -0,0 +1 @@ +"""Tests for sklearn related utility functionality.""" diff --git a/sktime/utils/sklearn/tests/test_sklearn_df_adapt.py b/sktime/utils/sklearn/tests/test_sklearn_df_adapt.py new file mode 100644 index 00000000000..57b36ebcdfc --- /dev/null +++ b/sktime/utils/sklearn/tests/test_sklearn_df_adapt.py @@ -0,0 +1,33 @@ +"""Tests for sklearn dataframe coercion.""" + +__author__ = ["fkiraly"] + +import numpy as np +import pandas as pd +import pytest + +from sktime.utils.sklearn._adapt_df import prep_skl_df + + +@pytest.mark.parametrize("copy_df", [True, False]) +def test_prep_skl_df_coercion(copy_df): + """Test that prep_skl_df behaves correctly on the coercion case.""" + mixed_example = pd.DataFrame({0: [1, 2, 3], "b": [1, 2, 3]}) + + res = prep_skl_df(mixed_example, copy_df=copy_df) + + assert np.all(res.columns == ["0", "b"]) + + if not copy_df: + assert res is mixed_example + + +@pytest.mark.parametrize("copy_df", [True, False]) +def test_prep_skl_df_non_coercion(copy_df): + """Test that prep_skl_df behaves correctly on the non-coercion case.""" + mixed_example = pd.DataFrame({"a": [1, 2, 3], "b": [1, 2, 3]}) + + res = prep_skl_df(mixed_example, copy_df=copy_df) + + assert np.all(res.columns == ["a", "b"]) + assert res is mixed_example diff --git a/sktime/utils/tests/test_sklearn_typing.py b/sktime/utils/sklearn/tests/test_sklearn_typing.py similarity index 100% rename from sktime/utils/tests/test_sklearn_typing.py rename to sktime/utils/sklearn/tests/test_sklearn_typing.py diff --git a/sktime/utils/tests/test_mlflow_sktime_model_export.py b/sktime/utils/tests/test_mlflow_sktime_model_export.py index 6143ae5eac0..f46fcb2bb45 100644 --- a/sktime/utils/tests/test_mlflow_sktime_model_export.py +++ b/sktime/utils/tests/test_mlflow_sktime_model_export.py @@ -1,6 +1,6 @@ """Tests for mlflow-sktime custom model flavor.""" -__author__ = ["benjaminbluhm"] +__author__ = ["benjaminbluhm", "achieveordie"] import os import sys @@ -11,10 +11,11 @@ import pandas as pd import pytest -from sktime.datasets import load_airline, load_longley +from sktime.datasets import load_airline, load_arrow_head, load_longley from sktime.forecasting.arima import AutoARIMA from sktime.forecasting.naive import NaiveForecaster from sktime.split import temporal_train_test_split +from sktime.tests.test_switch import run_test_for_class from sktime.utils.multiindex import flatten_multiindex from sktime.utils.validation._dependencies import _check_soft_dependencies @@ -41,7 +42,12 @@ def mock_s3_bucket(): ------- string with name of mock S3 bucket """ - with moto.mock_s3(): + if moto.__version__ < "5.0.0": + mock_method = moto.mock_s3 + else: + mock_method = moto.mock_aws + + with mock_method(): bucket_name = "mock-bucket" my_config = Config(region_name="us-east-1") s3_client = boto3.client("s3", config=my_config) @@ -77,6 +83,18 @@ def test_data_longley(): return y_train, y_test, X_train, X_test +@pytest.fixture(scope="module") +def test_data_arrow_head(): + """Create sample data for univariate classification.""" + X_train, y_train = load_arrow_head(split="TRAIN") + X_test, y_test = load_arrow_head(split="TEST") + return y_train.astype(int), y_test.astype(int), X_train, X_test + + +@pytest.mark.skipif( + not run_test_for_class(AutoARIMA), + reason="Skip AutoARIMA to test mlflow functionalities since soft deps are missing.", +) @pytest.fixture(scope="module") def auto_arima_model(test_data_airline): """Create instance of fitted auto arima model.""" @@ -85,6 +103,22 @@ def auto_arima_model(test_data_airline): ) +@pytest.mark.skipif( + not _check_soft_dependencies("tensorflow", severity="none"), + reason="skip test if required soft dependency is not available.", +) +@pytest.fixture(scope="module") +def cnn_model(test_data_arrow_head): + """Create an instance of fitted ResNet Classifier model.""" + from sktime.classification.deep_learning.cnn import CNNClassifier + + y_train, _, X_train, _ = test_data_arrow_head + + return CNNClassifier(n_epochs=1, n_conv_layers=1, kernel_size=3).fit( + X_train, y_train + ) + + @pytest.fixture(scope="module") def naive_forecaster_model_with_regressor(test_data_longley): """Create instance of fitted naive forecaster model.""" @@ -94,8 +128,11 @@ def naive_forecaster_model_with_regressor(test_data_longley): @pytest.mark.skipif( - not _check_soft_dependencies("mlflow", severity="none"), - reason="skip test if required soft dependency not available", + not ( + _check_soft_dependencies("mlflow", severity="none") + and run_test_for_class(AutoARIMA) + ), + reason="Skip AutoARIMA to test mlflow functionalities since soft deps are missing.", ) @pytest.mark.parametrize("serialization_format", ["pickle", "cloudpickle"]) def test_auto_arima_model_save_and_load( @@ -117,8 +154,11 @@ def test_auto_arima_model_save_and_load( @pytest.mark.skipif( - not _check_soft_dependencies("mlflow", severity="none"), - reason="skip test if required soft dependency not available", + not ( + _check_soft_dependencies("mlflow", severity="none") + and run_test_for_class(AutoARIMA) + ), + reason="Skip AutoARIMA to test mlflow functionalities since soft deps are missing.", ) @pytest.mark.parametrize("serialization_format", ["pickle", "cloudpickle"]) def test_auto_arima_model_pyfunc_output( @@ -169,8 +209,36 @@ def test_auto_arima_model_pyfunc_output( @pytest.mark.skipif( - not _check_soft_dependencies("mlflow", severity="none"), - reason="skip test if required soft dependency not available", + not _check_soft_dependencies(["mlflow", "tensorflow"], severity="none"), + reason="skip mlflow tests on CNN if required soft dependency not available", +) +@pytest.mark.parametrize("serialization_format", ["pickle", "cloudpickle"]) +def test_cnn_model_save_and_load( + cnn_model, test_data_arrow_head, model_path, serialization_format +): + """Test saving and loading of DL sktime estimator.""" + from sktime.utils import mlflow_sktime + + mlflow_sktime.save_model( + sktime_model=cnn_model, + path=model_path, + serialization_format=serialization_format, + ) + loaded_model = mlflow_sktime.load_model(model_uri=model_path) + + _, _, _, X_test = test_data_arrow_head + + np.testing.assert_array_almost_equal( + cnn_model.predict(X_test), loaded_model.predict(X_test) + ) + + +@pytest.mark.skipif( + not ( + _check_soft_dependencies("mlflow", severity="none") + and run_test_for_class(AutoARIMA) + ), + reason="Skip AutoARIMA to test mlflow functionalities since soft deps are missing.", ) def test_auto_arima_model_pyfunc_with_params_output(auto_arima_model, model_path): """Test auto arima prediction of loaded pyfunc model with parameters.""" @@ -223,8 +291,11 @@ def test_auto_arima_model_pyfunc_with_params_output(auto_arima_model, model_path @pytest.mark.skipif( - not _check_soft_dependencies("mlflow", severity="none"), - reason="skip test if required soft dependency not available", + not ( + _check_soft_dependencies("mlflow", severity="none") + and run_test_for_class(AutoARIMA) + ), + reason="Skip AutoARIMA to test mlflow functionalities since soft deps are missing.", ) def test_auto_arima_model_pyfunc_without_params_output(auto_arima_model, model_path): """Test auto arima prediction of loaded pyfunc model without parameters.""" @@ -277,8 +348,11 @@ def test_auto_arima_model_pyfunc_without_params_output(auto_arima_model, model_p @pytest.mark.skipif( - not _check_soft_dependencies("mlflow", severity="none"), - reason="skip test if required soft dependency not available", + not ( + _check_soft_dependencies("mlflow", severity="none") + and run_test_for_class(AutoARIMA) + ), + reason="Skip AutoARIMA to test mlflow functionalities since soft deps are missing.", ) def test_auto_arima_model_pyfunc_without_conf_output(auto_arima_model, model_path): """Test auto arima prediction of loaded pyfunc model without config.""" @@ -355,8 +429,11 @@ def test_naive_forecaster_model_with_regressor_pyfunc_output( @pytest.mark.skipif( - not _check_soft_dependencies("mlflow", severity="none"), - reason="skip test if required soft dependency not available", + not ( + _check_soft_dependencies("mlflow", severity="none") + and run_test_for_class(AutoARIMA) + ), + reason="Skip AutoARIMA to test mlflow functionalities since soft deps are missing.", ) @pytest.mark.parametrize("use_signature", [True, False]) @pytest.mark.parametrize("use_example", [True, False]) @@ -390,8 +467,11 @@ def test_signature_and_examples_saved_correctly( @pytest.mark.skipif( - not _check_soft_dependencies("mlflow", severity="none"), - reason="skip test if required soft dependency not available", + not ( + _check_soft_dependencies("mlflow", severity="none") + and run_test_for_class(AutoARIMA) + ), + reason="Skip AutoARIMA to test mlflow functionalities since soft deps are missing.", ) @pytest.mark.parametrize("use_signature", [True, False]) def test_predict_var_signature_saved_correctly( @@ -413,8 +493,11 @@ def test_predict_var_signature_saved_correctly( @pytest.mark.skipif( - not _check_soft_dependencies("mlflow", severity="none"), - reason="skip test if required soft dependency not available", + not ( + _check_soft_dependencies("mlflow", severity="none") + and run_test_for_class(AutoARIMA) + ), + reason="Skip AutoARIMA to test mlflow functionalities since soft deps are missing.", ) @pytest.mark.parametrize("use_signature", [True, False]) @pytest.mark.parametrize("use_example", [True, False]) @@ -461,8 +544,11 @@ def test_signature_and_example_for_pyfunc_predict( @pytest.mark.skipif( - not _check_soft_dependencies("mlflow", severity="none"), - reason="skip test if required soft dependency not available", + not ( + _check_soft_dependencies("mlflow", severity="none") + and run_test_for_class(AutoARIMA) + ), + reason="Skip AutoARIMA to test mlflow functionalities since soft deps are missing.", ) def test_load_from_remote_uri_succeeds(auto_arima_model, model_path, mock_s3_bucket): """Test loading native sktime model from mock S3 bucket.""" @@ -487,8 +573,11 @@ def test_load_from_remote_uri_succeeds(auto_arima_model, model_path, mock_s3_buc @pytest.mark.skipif( - not _check_soft_dependencies("mlflow", severity="none"), - reason="skip test if required soft dependency not available", + not ( + _check_soft_dependencies("mlflow", severity="none") + and run_test_for_class(AutoARIMA) + ), + reason="Skip AutoARIMA to test mlflow functionalities since soft deps are missing.", ) @pytest.mark.parametrize("should_start_run", [True, False]) @pytest.mark.parametrize("serialization_format", ["pickle", "cloudpickle"]) @@ -531,8 +620,11 @@ def test_log_model(auto_arima_model, tmp_path, should_start_run, serialization_f @pytest.mark.xfail(reason="known failure to be debugged, see #4904") @pytest.mark.skipif( - not _check_soft_dependencies("mlflow", severity="none"), - reason="skip test if required soft dependency not available", + not ( + _check_soft_dependencies("mlflow", severity="none") + and run_test_for_class(AutoARIMA) + ), + reason="Skip AutoARIMA to test mlflow functionalities since soft deps are missing.", ) def test_log_model_calls_register_model(auto_arima_model, tmp_path): """Test log model calls register model.""" @@ -562,8 +654,11 @@ def test_log_model_calls_register_model(auto_arima_model, tmp_path): @pytest.mark.skipif( - not _check_soft_dependencies("mlflow", severity="none"), - reason="skip test if required soft dependency not available", + not ( + _check_soft_dependencies("mlflow", severity="none") + and run_test_for_class(AutoARIMA) + ), + reason="Skip AutoARIMA to test mlflow functionalities since soft deps are missing.", ) def test_log_model_no_registered_model_name(auto_arima_model, tmp_path): """Test log model calls register model without registered model name.""" @@ -586,8 +681,11 @@ def test_log_model_no_registered_model_name(auto_arima_model, tmp_path): @pytest.mark.skipif( - not _check_soft_dependencies("mlflow", severity="none"), - reason="skip test if required soft dependency not available", + not ( + _check_soft_dependencies("mlflow", severity="none") + and run_test_for_class(AutoARIMA) + ), + reason="Skip AutoARIMA to test mlflow functionalities since soft deps are missing.", ) def test_pyfunc_raises_invalid_attribute_type(auto_arima_model, model_path): """Test pyfunc raises exception with invalid attribute type.""" @@ -607,8 +705,11 @@ def test_pyfunc_raises_invalid_attribute_type(auto_arima_model, model_path): @pytest.mark.skipif( - not _check_soft_dependencies("mlflow", severity="none"), - reason="skip test if required soft dependency not available", + not ( + _check_soft_dependencies("mlflow", severity="none") + and run_test_for_class(AutoARIMA) + ), + reason="Skip AutoARIMA to test mlflow functionalities since soft deps are missing.", ) def test_pyfunc_raises_invalid_dict_key(auto_arima_model, model_path): """Test pyfunc raises exception with invalid dict key.""" @@ -628,8 +729,11 @@ def test_pyfunc_raises_invalid_dict_key(auto_arima_model, model_path): @pytest.mark.skipif( - not _check_soft_dependencies("mlflow", severity="none"), - reason="skip test if required soft dependency not available", + not ( + _check_soft_dependencies("mlflow", severity="none") + and run_test_for_class(AutoARIMA) + ), + reason="Skip AutoARIMA to test mlflow functionalities since soft deps are missing.", ) def test_pyfunc_raises_invalid_dict_value_type(auto_arima_model, model_path): """Test pyfunc raises exception with invalid dict value type.""" @@ -648,8 +752,11 @@ def test_pyfunc_raises_invalid_dict_value_type(auto_arima_model, model_path): @pytest.mark.skipif( - not _check_soft_dependencies("mlflow", severity="none"), - reason="skip test if required soft dependency not available", + not ( + _check_soft_dependencies("mlflow", severity="none") + and run_test_for_class(AutoARIMA) + ), + reason="Skip AutoARIMA to test mlflow functionalities since soft deps are missing.", ) def test_pyfunc_raises_invalid_dict_value(auto_arima_model, model_path): """Test pyfunc raises exception with invalid dict value.""" @@ -669,8 +776,11 @@ def test_pyfunc_raises_invalid_dict_value(auto_arima_model, model_path): @pytest.mark.skipif( - not _check_soft_dependencies("mlflow", severity="none"), - reason="skip test if required soft dependency not available", + not ( + _check_soft_dependencies("mlflow", severity="none") + and run_test_for_class(AutoARIMA) + ), + reason="Skip AutoARIMA to test mlflow functionalities since soft deps are missing.", ) def test_pyfunc_predict_proba_raises_invalid_attribute_type( auto_arima_model, model_path @@ -693,8 +803,11 @@ def test_pyfunc_predict_proba_raises_invalid_attribute_type( @pytest.mark.skipif( - not _check_soft_dependencies("mlflow", severity="none"), - reason="skip test if required soft dependency not available", + not ( + _check_soft_dependencies("mlflow", severity="none") + and run_test_for_class(AutoARIMA) + ), + reason="Skip AutoARIMA to test mlflow functionalities since soft deps are missing.", ) def test_pyfunc_predict_proba_raises_invalid_dict_value(auto_arima_model, model_path): """Test pyfunc predict_proba raises exception with invalid dict value.""" diff --git a/sktime/utils/tests/test_plotting.py b/sktime/utils/tests/test_plotting.py index ebc62f14100..832827ae78e 100644 --- a/sktime/utils/tests/test_plotting.py +++ b/sktime/utils/tests/test_plotting.py @@ -244,6 +244,28 @@ def test_plot_series_uniform_treatment_of_int64_range_index_types(): plt.close() +@pytest.mark.skipif( + not run_test_for_class(plot_series), + reason="run test only if softdeps are present and incrementally (if requested)", +) +@pytest.mark.skipif( + not _check_soft_dependencies("matplotlib", severity="none"), + reason="skip test if required soft dependency for matplotlib not available", +) +def test_plot_series_interval(): + """Test prediction interval plotting functionality in plot_series.""" + from sktime.forecasting.base import ForecastingHorizon + from sktime.forecasting.naive import NaiveForecaster + + model = NaiveForecaster() + y = load_airline() + model.fit(y[:-3]) + fh = ForecastingHorizon(y[-3:].index, is_relative=False) + pred = model.predict(fh) + interval = model.predict_interval(fh) + plot_series(y[:-3], y[-3:], pred, pred_interval=interval) + + # Generically test whether plots only accepting univariate input run @pytest.mark.skipif( not run_test_for_class(univariate_plots), diff --git a/sktime/utils/tests/test_sampling.py b/sktime/utils/tests/test_sampling.py index eda0b6ee925..40d5bfe3b67 100644 --- a/sktime/utils/tests/test_sampling.py +++ b/sktime/utils/tests/test_sampling.py @@ -5,7 +5,6 @@ from sktime.datasets import load_unit_test from sktime.datatypes import check_is_scitype -from sktime.utils._testing.deep_equals import deep_equals from sktime.utils.sampling import random_partition, stratified_resample NK_FIXTURES = [(10, 3), (15, 5), (19, 6), (3, 1), (1, 2)] @@ -40,6 +39,8 @@ def test_partition(n, k): @pytest.mark.parametrize("n, k", NK_FIXTURES) def test_seed(n, k, seed): """Test that seed is deterministic.""" + from sktime.utils.deep_equals import deep_equals + part = random_partition(n, k, seed) part2 = random_partition(n, k, seed) diff --git a/sktime/utils/validation/_dependencies.py b/sktime/utils/validation/_dependencies.py index b927273be96..ce974049106 100644 --- a/sktime/utils/validation/_dependencies.py +++ b/sktime/utils/validation/_dependencies.py @@ -40,7 +40,7 @@ def _check_soft_dependencies( should be provided if import name differs from package name severity : str, "error" (default), "warning", "none" behaviour for raising errors or warnings - "error" - raises a `ModuleNotFoundException` if one of packages is not installed + "error" - raises a `ModuleNotFoundError` if one of packages is not installed "warning" - raises a warning if one of packages is not installed function returns False if one of packages is not installed, otherwise True "none" - does not raise exception or warning @@ -216,7 +216,7 @@ def _check_dl_dependencies(msg=None, severity="error"): error message to be returned in the `ModuleNotFoundError`, overrides default severity : str, "error" (default), "warning", "none" behaviour for raising errors or warnings - "error" - raises a ModuleNotFoundException if one of packages is not installed + "error" - raises a ModuleNotFoundError if one of packages is not installed "warning" - raises a warning if one of packages is not installed function returns False if one of packages is not installed, otherwise True "none" - does not raise exception or warning @@ -254,6 +254,49 @@ def _check_dl_dependencies(msg=None, severity="error"): ) +def _check_mlflow_dependencies( + msg=None, severity="error", suppress_import_stdout=False +): + """Check if `mlflow` and its dependencies are installed. + + Parameters + ---------- + msg: str, optional, default= default message (msg below) + error message to be returned when `ModuleNotFoundError` is raised. + severity: str, either of "error", "warning" or "none" + behaviour for raising errors or warnings + "error" - raises a `ModuleNotFound` if mlflow-related packages are not found. + "warning" - raises a warning message if any mlflow-related package is not + installed also returns False. In case all packages are present, + returns True. + "none" - does not raise any exception or warning and simply returns True + if all packages are installed otherwise return False. + + Raise + ----- + ModuleNotFoundError + User Friendly error with a suggested action to install mlflow dependencies + + Returns + ------- + boolean - whether all mlflow-related packages are installed. + """ + if not isinstance(msg, str): + msg = ( + "`mlflow` is an extra dependency and is not included " + "in the base sktime installation. " + "Please run `pip install mlflow` " + "or `pip install sktime[mlflow]` to install the package." + ) + + return _check_soft_dependencies( + "mlflow", + msg=msg, + severity=severity, + suppress_import_stdout=suppress_import_stdout, + ) + + def _check_python_version(obj, package=None, msg=None, severity="error"): """Check if system python version is compatible with requirements of obj. @@ -348,7 +391,7 @@ def _check_estimator_deps(obj, msg=None, severity="error"): error message to be returned in the `ModuleNotFoundError`, overrides default severity : str, "error" (default), "warning", or "none" behaviour for raising errors or warnings - "error" - raises a ModuleNotFoundException if environment is incompatible + "error" - raises a `ModuleNotFoundError` if environment is incompatible "warning" - raises a warning if environment is incompatible function returns False if environment is incompatible, otherwise True "none" - does not raise exception or warning diff --git a/sktime/utils/validation/forecasting.py b/sktime/utils/validation/forecasting.py index f446a5c5abe..21fdedd9666 100644 --- a/sktime/utils/validation/forecasting.py +++ b/sktime/utils/validation/forecasting.py @@ -511,7 +511,9 @@ def check_interval_df(interval_df, index_to_match): """ from sktime.datatypes import check_is_mtype - checked = check_is_mtype(interval_df, "pred_interval", return_metadata=True) + checked = check_is_mtype( + interval_df, "pred_interval", return_metadata=True, msg_return_dict="list" + ) if not checked[0]: raise ValueError(checked[1]) df_idx = interval_df.index