From 62950b0244cd119ac7cd5d998ad8ba0413f19322 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Wed, 8 Feb 2023 00:27:45 +0100 Subject: [PATCH 01/44] replace the loc and scale parameters in gumbel to a parameter dict --- .pre-commit-config.yaml | 151 ++++++---- poetry.lock | 106 +++---- pyproject.toml | 4 +- statista/distributions.py | 300 ++++++++++++++------ tests/conftest.py | 2 +- tests/test_distributions.py | 549 +++++++++++++++++++----------------- 6 files changed, 653 insertions(+), 459 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e3bc9b5..e818050 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,85 +1,114 @@ +fail_fast: true repos: -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v2.3.0 - hooks: - - id: end-of-file-fixer - name: "[py - check] validate yaml" - - id: trailing-whitespace - name: "[file - format] trim trailing whitespace" - args: [ --markdown-linebreak-ext=md ] - - id: check-added-large-files + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.1.0 + hooks: + - id: end-of-file-fixer + name: "[py - check] validate yaml" + - id: trailing-whitespace + name: "[file - format] trim trailing whitespace" + args: [ --markdown-linebreak-ext=md ] + - id: check-added-large-files name: "[file - check] large file" args: [ --maxkb=5000 ] - - id: check-docstring-first + - id: check-docstring-first name: "[py - check] docstring first" files: /examples types : [file, python ] - - id: check-json + - id: check-json name: "[json - check] validate json" - - id: check-merge-conflict + - id: check-merge-conflict name: "[git - check] merge conflict" - - id: debug-statements + - id: debug-statements name: "[py - check] debug statements" - - id: detect-private-key + - id: detect-private-key name: "[cred - check] private keys" - - id: fix-encoding-pragma + - id: fix-encoding-pragma name: "[file - format] coding pragma" args: [ --remove ] - - id: mixed-line-ending + - id: mixed-line-ending name: "[file - format] mixed line ending" args: [ --fix=auto ] - - id: pretty-format-json + - id: pretty-format-json name: "[json - format] pretty json" args: [ --autofix, --indent=4, --no-sort-keys ] - - id: requirements-txt-fixer + - id: requirements-txt-fixer name: "[reqs - format] fix requirements.txt" - - id: check-yaml + - id: check-yaml name: "[yaml - check] validate yaml" -- repo: https://github.com/PyCQA/docformatter - rev: v1.4 - hooks: - - id: docformatter - name: "[py - format] docformatter" - args: [ -i, --wrap-summaries, "0" ] +# - repo: https://github.com/pre-commit/mirrors-isort +# rev: v5.10.1 +# hooks: +# - id: isort +# name: "[py - format] isort" + - repo: https://github.com/PyCQA/docformatter + rev: v1.4 + hooks: + - id: docformatter + name: "[py - format] docformatter" + args: [ -i, --wrap-summaries, "0" ] -- repo: https://github.com/PyCQA/pydocstyle - rev: 6.1.1 - hooks: - - id: pydocstyle - name: "[py - check] pydocstyle" - files: ^Hapi/ + - repo: https://github.com/PyCQA/pydocstyle + rev: 6.1.1 + hooks: + - id: pydocstyle + name: "[py - check] pydocstyle" + files: ^Hapi/ -- repo: https://gitlab.com/pycqa/flake8 - rev: 3.8.4 - hooks: - - id: flake8 - name: "[py - check] flake8" - language_version: python3.9 - exclude: ^(examples/|tests/) + - repo: https://gitlab.com/pycqa/flake8 + rev: 4.0.1 + hooks: + - id: flake8 + name: "[py - check] flake8" + language_version: python3.9 + exclude: ^(examples/|tests/) -- repo: https://github.com/psf/black - rev: 22.8.0 - hooks: - - id: black -- repo: https://github.com/pre-commit/mirrors-isort - rev: v5.7.0 - hooks: - - id: isort - name: "[py - format] isort" -- repo: https://github.com/ambv/black - rev: 22.8.0 - hooks: - - id: black - name: "[py - format] black" - language_version: python3.9 + #- repo: https://github.com/psf/black + # rev: 22.8.0 + # hooks: + # - id: black + - repo: https://github.com/ambv/black + rev: 22.8.0 + hooks: + - id: black + name: "[py - format] black" + language_version: python3.9 + - repo: https://github.com/lovesegfault/beautysh + rev: v6.2.1 + hooks: + - id: beautysh + name: "[bash - format] beautysh" -- repo: local - hooks: - - id: pytest-check - name: pytest-check - entry: pytest - language: system - pass_filenames: false - always_run: true + # pre-commit-shell: Checks shell scripts against shellcheck. + - repo: https://github.com/detailyang/pre-commit-shell + rev: v1.0.6 + hooks: + - id: shell-lint + name: "[bash - lint] shell-lint" + + - repo: https://github.com/rlindsgaard/pre-commit-commit-msg-hooks + rev: 0.1.0 + hooks: + - id: check-description-max-length + name: "[bash - format] check-description-max-length" + - id: check-second-line-empty + name: "[bash - format] check-second-line-empty" + - id: check-summary-capitalized + name: "[bash - format] check-summary-capitalized" + - id: check-summary-imperative + name: "[bash - format] check-summary-imperative" + - id: check-summary-max-length + name: "[bash - format] check-summary-max-length" + - id: check-summary-punctuation + name: "[bash - format] check-summary-punctuation" + + - repo: local + hooks: + - id: pytest-check + name: pytest-check + entry: pytest -vvv --cov=Hapi + language: system + pass_filenames: false + always_run: true diff --git a/poetry.lock b/poetry.lock index 8d130d0..7d431d5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -706,14 +706,14 @@ files = [ [[package]] name = "mypy-extensions" -version = "0.4.3" -description = "Experimental type system extensions for programs checked with the mypy typechecker." +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.5" files = [ - {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, - {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] [[package]] @@ -733,40 +733,40 @@ setuptools = "*" [[package]] name = "numpy" -version = "1.24.1" +version = "1.24.2" description = "Fundamental package for array computing in Python" category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "numpy-1.24.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:179a7ef0889ab769cc03573b6217f54c8bd8e16cef80aad369e1e8185f994cd7"}, - {file = "numpy-1.24.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b09804ff570b907da323b3d762e74432fb07955701b17b08ff1b5ebaa8cfe6a9"}, - {file = "numpy-1.24.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1b739841821968798947d3afcefd386fa56da0caf97722a5de53e07c4ccedc7"}, - {file = "numpy-1.24.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e3463e6ac25313462e04aea3fb8a0a30fb906d5d300f58b3bc2c23da6a15398"}, - {file = "numpy-1.24.1-cp310-cp310-win32.whl", hash = "sha256:b31da69ed0c18be8b77bfce48d234e55d040793cebb25398e2a7d84199fbc7e2"}, - {file = "numpy-1.24.1-cp310-cp310-win_amd64.whl", hash = "sha256:b07b40f5fb4fa034120a5796288f24c1fe0e0580bbfff99897ba6267af42def2"}, - {file = "numpy-1.24.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7094891dcf79ccc6bc2a1f30428fa5edb1e6fb955411ffff3401fb4ea93780a8"}, - {file = "numpy-1.24.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28e418681372520c992805bb723e29d69d6b7aa411065f48216d8329d02ba032"}, - {file = "numpy-1.24.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e274f0f6c7efd0d577744f52032fdd24344f11c5ae668fe8d01aac0422611df1"}, - {file = "numpy-1.24.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0044f7d944ee882400890f9ae955220d29b33d809a038923d88e4e01d652acd9"}, - {file = "numpy-1.24.1-cp311-cp311-win32.whl", hash = "sha256:442feb5e5bada8408e8fcd43f3360b78683ff12a4444670a7d9e9824c1817d36"}, - {file = "numpy-1.24.1-cp311-cp311-win_amd64.whl", hash = "sha256:de92efa737875329b052982e37bd4371d52cabf469f83e7b8be9bb7752d67e51"}, - {file = "numpy-1.24.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b162ac10ca38850510caf8ea33f89edcb7b0bb0dfa5592d59909419986b72407"}, - {file = "numpy-1.24.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:26089487086f2648944f17adaa1a97ca6aee57f513ba5f1c0b7ebdabbe2b9954"}, - {file = "numpy-1.24.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:caf65a396c0d1f9809596be2e444e3bd4190d86d5c1ce21f5fc4be60a3bc5b36"}, - {file = "numpy-1.24.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0677a52f5d896e84414761531947c7a330d1adc07c3a4372262f25d84af7bf7"}, - {file = "numpy-1.24.1-cp38-cp38-win32.whl", hash = "sha256:dae46bed2cb79a58d6496ff6d8da1e3b95ba09afeca2e277628171ca99b99db1"}, - {file = "numpy-1.24.1-cp38-cp38-win_amd64.whl", hash = "sha256:6ec0c021cd9fe732e5bab6401adea5a409214ca5592cd92a114f7067febcba0c"}, - {file = "numpy-1.24.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:28bc9750ae1f75264ee0f10561709b1462d450a4808cd97c013046073ae64ab6"}, - {file = "numpy-1.24.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:84e789a085aabef2f36c0515f45e459f02f570c4b4c4c108ac1179c34d475ed7"}, - {file = "numpy-1.24.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e669fbdcdd1e945691079c2cae335f3e3a56554e06bbd45d7609a6cf568c700"}, - {file = "numpy-1.24.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef85cf1f693c88c1fd229ccd1055570cb41cdf4875873b7728b6301f12cd05bf"}, - {file = "numpy-1.24.1-cp39-cp39-win32.whl", hash = "sha256:87a118968fba001b248aac90e502c0b13606721b1343cdaddbc6e552e8dfb56f"}, - {file = "numpy-1.24.1-cp39-cp39-win_amd64.whl", hash = "sha256:ddc7ab52b322eb1e40521eb422c4e0a20716c271a306860979d450decbb51b8e"}, - {file = "numpy-1.24.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ed5fb71d79e771ec930566fae9c02626b939e37271ec285e9efaf1b5d4370e7d"}, - {file = "numpy-1.24.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad2925567f43643f51255220424c23d204024ed428afc5aad0f86f3ffc080086"}, - {file = "numpy-1.24.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cfa1161c6ac8f92dea03d625c2d0c05e084668f4a06568b77a25a89111621566"}, - {file = "numpy-1.24.1.tar.gz", hash = "sha256:2386da9a471cc00a1f47845e27d916d5ec5346ae9696e01a8a34760858fe9dd2"}, + {file = "numpy-1.24.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eef70b4fc1e872ebddc38cddacc87c19a3709c0e3e5d20bf3954c147b1dd941d"}, + {file = "numpy-1.24.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8d2859428712785e8a8b7d2b3ef0a1d1565892367b32f915c4a4df44d0e64f5"}, + {file = "numpy-1.24.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6524630f71631be2dabe0c541e7675db82651eb998496bbe16bc4f77f0772253"}, + {file = "numpy-1.24.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a51725a815a6188c662fb66fb32077709a9ca38053f0274640293a14fdd22978"}, + {file = "numpy-1.24.2-cp310-cp310-win32.whl", hash = "sha256:2620e8592136e073bd12ee4536149380695fbe9ebeae845b81237f986479ffc9"}, + {file = "numpy-1.24.2-cp310-cp310-win_amd64.whl", hash = "sha256:97cf27e51fa078078c649a51d7ade3c92d9e709ba2bfb97493007103c741f1d0"}, + {file = "numpy-1.24.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7de8fdde0003f4294655aa5d5f0a89c26b9f22c0a58790c38fae1ed392d44a5a"}, + {file = "numpy-1.24.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4173bde9fa2a005c2c6e2ea8ac1618e2ed2c1c6ec8a7657237854d42094123a0"}, + {file = "numpy-1.24.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cecaed30dc14123020f77b03601559fff3e6cd0c048f8b5289f4eeabb0eb281"}, + {file = "numpy-1.24.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a23f8440561a633204a67fb44617ce2a299beecf3295f0d13c495518908e910"}, + {file = "numpy-1.24.2-cp311-cp311-win32.whl", hash = "sha256:e428c4fbfa085f947b536706a2fc349245d7baa8334f0c5723c56a10595f9b95"}, + {file = "numpy-1.24.2-cp311-cp311-win_amd64.whl", hash = "sha256:557d42778a6869c2162deb40ad82612645e21d79e11c1dc62c6e82a2220ffb04"}, + {file = "numpy-1.24.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d0a2db9d20117bf523dde15858398e7c0858aadca7c0f088ac0d6edd360e9ad2"}, + {file = "numpy-1.24.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c72a6b2f4af1adfe193f7beb91ddf708ff867a3f977ef2ec53c0ffb8283ab9f5"}, + {file = "numpy-1.24.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c29e6bd0ec49a44d7690ecb623a8eac5ab8a923bce0bea6293953992edf3a76a"}, + {file = "numpy-1.24.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eabd64ddb96a1239791da78fa5f4e1693ae2dadc82a76bc76a14cbb2b966e96"}, + {file = "numpy-1.24.2-cp38-cp38-win32.whl", hash = "sha256:e3ab5d32784e843fc0dd3ab6dcafc67ef806e6b6828dc6af2f689be0eb4d781d"}, + {file = "numpy-1.24.2-cp38-cp38-win_amd64.whl", hash = "sha256:76807b4063f0002c8532cfeac47a3068a69561e9c8715efdad3c642eb27c0756"}, + {file = "numpy-1.24.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4199e7cfc307a778f72d293372736223e39ec9ac096ff0a2e64853b866a8e18a"}, + {file = "numpy-1.24.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:adbdce121896fd3a17a77ab0b0b5eedf05a9834a18699db6829a64e1dfccca7f"}, + {file = "numpy-1.24.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:889b2cc88b837d86eda1b17008ebeb679d82875022200c6e8e4ce6cf549b7acb"}, + {file = "numpy-1.24.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f64bb98ac59b3ea3bf74b02f13836eb2e24e48e0ab0145bbda646295769bd780"}, + {file = "numpy-1.24.2-cp39-cp39-win32.whl", hash = "sha256:63e45511ee4d9d976637d11e6c9864eae50e12dc9598f531c035265991910468"}, + {file = "numpy-1.24.2-cp39-cp39-win_amd64.whl", hash = "sha256:a77d3e1163a7770164404607b7ba3967fb49b24782a6ef85d9b5f54126cc39e5"}, + {file = "numpy-1.24.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:92011118955724465fb6853def593cf397b4a1367495e0b59a7e69d40c4eb71d"}, + {file = "numpy-1.24.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9006288bcf4895917d02583cf3411f98631275bc67cce355a7f39f8c14338fa"}, + {file = "numpy-1.24.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:150947adbdfeceec4e5926d956a06865c1c690f2fd902efede4ca6fe2e657c3f"}, + {file = "numpy-1.24.2.tar.gz", hash = "sha256:003a9f530e880cb2cd177cba1af7220b9aa42def9c4afc2a2fc3ee6be7eb2b22"}, ] [[package]] @@ -948,19 +948,19 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa [[package]] name = "platformdirs" -version = "2.6.2" +version = "3.0.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-2.6.2-py3-none-any.whl", hash = "sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490"}, - {file = "platformdirs-2.6.2.tar.gz", hash = "sha256:e1fea1fe471b9ff8332e229df3cb7de4f53eeea4998d3b6bfff542115e998bd2"}, + {file = "platformdirs-3.0.0-py3-none-any.whl", hash = "sha256:b1d5eb14f221506f50d6604a561f4c5786d9e80355219694a1b244bcd96f4567"}, + {file = "platformdirs-3.0.0.tar.gz", hash = "sha256:8a1228abb1ef82d788f74139988b137e78692984ec7b08eaa6c65f1723af28f9"}, ] [package.extras] -docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] +docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] [[package]] name = "pluggy" @@ -980,14 +980,14 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "3.0.2" +version = "3.0.4" description = "A framework for managing and maintaining multi-language pre-commit hooks." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "pre_commit-3.0.2-py2.py3-none-any.whl", hash = "sha256:f448d5224c70e196a6c6f87961d2333dfdc49988ebbf660477f9efe991c03597"}, - {file = "pre_commit-3.0.2.tar.gz", hash = "sha256:aa97fa71e7ab48225538e1e91a6b26e483029e6de64824f04760c32557bc91d7"}, + {file = "pre_commit-3.0.4-py2.py3-none-any.whl", hash = "sha256:9e3255edb0c9e7fe9b4f328cb3dc86069f8fdc38026f1bf521018a05eaf4d67b"}, + {file = "pre_commit-3.0.4.tar.gz", hash = "sha256:bc4687478d55578c4ac37272fe96df66f73d9b5cf81be6f28627d4e712e752d5"}, ] [package.dependencies] @@ -1380,14 +1380,14 @@ test = ["asv", "gmpy2", "mpmath", "pytest", "pytest-cov", "pytest-xdist", "sciki [[package]] name = "setuptools" -version = "67.0.0" +version = "67.2.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-67.0.0-py3-none-any.whl", hash = "sha256:9d790961ba6219e9ff7d9557622d2fe136816a264dd01d5997cfc057d804853d"}, - {file = "setuptools-67.0.0.tar.gz", hash = "sha256:883131c5b6efa70b9101c7ef30b2b7b780a4283d5fc1616383cdf22c83cbefe6"}, + {file = "setuptools-67.2.0-py3-none-any.whl", hash = "sha256:16ccf598aab3b506593c17378473978908a2734d7336755a8769b480906bec1c"}, + {file = "setuptools-67.2.0.tar.gz", hash = "sha256:b440ee5f7e607bb8c9de15259dba2583dd41a38879a7abc1d43a71c59524da48"}, ] [package.extras] @@ -1484,24 +1484,24 @@ files = [ [[package]] name = "virtualenv" -version = "20.17.1" +version = "20.19.0" description = "Virtual Python Environment builder" category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "virtualenv-20.17.1-py3-none-any.whl", hash = "sha256:ce3b1684d6e1a20a3e5ed36795a97dfc6af29bc3970ca8dab93e11ac6094b3c4"}, - {file = "virtualenv-20.17.1.tar.gz", hash = "sha256:f8b927684efc6f1cc206c9db297a570ab9ad0e51c16fa9e45487d36d1905c058"}, + {file = "virtualenv-20.19.0-py3-none-any.whl", hash = "sha256:54eb59e7352b573aa04d53f80fc9736ed0ad5143af445a1e539aada6eb947dd1"}, + {file = "virtualenv-20.19.0.tar.gz", hash = "sha256:37a640ba82ed40b226599c522d411e4be5edb339a0c0de030c0dc7b646d61590"}, ] [package.dependencies] distlib = ">=0.3.6,<1" filelock = ">=3.4.1,<4" -platformdirs = ">=2.4,<3" +platformdirs = ">=2.4,<4" [package.extras] -docs = ["proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-argparse (>=0.3.2)", "sphinx-rtd-theme (>=1)", "towncrier (>=22.8)"] -testing = ["coverage (>=6.2)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=21.3)", "pytest (>=7.0.1)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.6.1)", "pytest-randomly (>=3.10.3)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"] +test = ["covdefaults (>=2.2.2)", "coverage (>=7.1)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23)", "pytest (>=7.2.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)"] [[package]] name = "win32-setctime" @@ -1521,4 +1521,4 @@ dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.15" -content-hash = "d20710aa2622038b46baa4162c425d6290dc376a38f97de331ec50ed737ff46b" +content-hash = "706ebbcd63d2c6031aa2299d9bfd7980c09e79656c4336b0a63c06f7c7d258c7" diff --git a/pyproject.toml b/pyproject.toml index f8d4f1d..86aa15a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ loguru = "^0.6.0" [tool.poetry.dev-dependencies] pytest = "^7.2.1" pytest-cov = "^4.0.0" -pre-commit = "^3.0.2" +pre-commit = "^3.0.3" black = "^22.12.0" flake8-bandit = "^4.1.1" flake8-bugbear = "^23.1.20" @@ -61,7 +61,7 @@ source = ["statista"] [tool.coverage.report] show_missing = true -fail_under = 40 +fail_under = 0 [tool.isort] diff --git a/statista/distributions.py b/statista/distributions.py index 41abc5a..6472086 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -1,5 +1,5 @@ from collections import OrderedDict -from typing import Any, List, Tuple, Union # Dict, +from typing import Any, List, Tuple, Union, Dict, Callable import matplotlib.pyplot as plt import numpy as np @@ -26,62 +26,165 @@ def __init__(self): pass @staticmethod - def weibul(data: Union[list, np.ndarray], option: int = 1) -> np.ndarray: + def returnPeriod(F: Union[list, np.ndarray]) -> np.ndarray: + """returnPeriod. + + Parameters + ---------- + F: [list/array] + non exceedence probability. + + Returns + ------- + array: + return period. + """ + F = np.array(F) + T = 1 / (1 - F) + return T + + @staticmethod + def weibul(data: Union[list, np.ndarray], return_period: int = False) -> np.ndarray: """Weibul. - Weibul method to calculate the cumulative distribution function CDF or + Weibul method to calculate the cumulative distribution function cdf or return period. Parameters ---------- data : [list/array] list/array of the data. - option : [1/2] - 1 to calculate the cumulative distribution function cdf or - 2 to calculate the return period.default=1 + return_period : [bool] + False to calculate the cumulative distribution function cdf or + True to calculate the return period. Default=False Returns ------- - CDF/T: [list] + cdf/T: [list] list of cumulative distribution function or return period. """ data.sort() - if option == 1: - CDF = np.array([j / (len(data) + 1) for j in range(1, len(data) + 1)]) - return CDF + if not return_period: + cdf = np.array([j / (len(data) + 1) for j in range(1, len(data) + 1)]) + return cdf else: - CDF = [j / (len(data) + 1) for j in range(1, len(data) + 1)] - T = np.array([1 / (1 - j) for j in CDF]) + cdf = [j / (len(data) + 1) for j in range(1, len(data) + 1)] + T = PlottingPosition.returnPeriod( + cdf + ) # np.array([1 / (1 - j) for j in cdf]) return T - @staticmethod - def returnPeriod(F: Union[list, np.ndarray]) -> np.ndarray: - """returnPeriod. + +class AbstractDistribution: + parameters: Dict[str, Union[float, Any]] + cdf_Weibul: ndarray + + def __init__( + self, + data: Union[list, np.ndarray] = None, + parameters: Dict[str, str] = None, + # loc: Union[int, float] = None, + # scale: Union[int, float] = None, + ): + """Gumbel. Parameters ---------- - F: [list/array] - non exceedence probability. + data : [list] + data time series. + parameters: Dict[str, str] + {"loc": val, "scale": val, "shape": value} + - loc: [numeric] + location parameter + - scale: [numeric] + scale parameter + """ + if isinstance(data, list) or isinstance(data, np.ndarray): + self.data = np.array(data) + self.data_sorted = np.sort(data) + self.cdf_Weibul = PlottingPosition.weibul(data) + self.KStable = 1.22 / np.sqrt(len(self.data)) + + # self.loc = loc + # self.scale = scale + self.parameters = parameters + + self.Dstatic = None + self.KS_Pvalue = None + self.chistatic = None + self.chi_Pvalue = None + + pass + + def pdf( + self, + loc: Union[float, int], + scale: Union[float, int], + plot_figure: bool = False, + figsize: tuple = (6, 5), + xlabel: str = "Actual data", + ylabel: str = "pdf", + fontsize: Union[float, int] = 15, + actualdata: Union[bool, np.ndarray] = True, + ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: + """pdf. + + Returns the value of Gumbel's pdf with parameters loc and scale at x . + + Parameters: + ----------- + loc : [numeric] + location parameter of the gumbel distribution. + scale : [numeric] + scale parameter of the gumbel distribution. Returns ------- - array: - return period. + pdf : [array] + probability density function pdf. """ - F = np.array(F) - T = 1 / (1 - F) - return T + if scale <= 0: + raise ValueError("Scale parameter is negative") + + if isinstance(actualdata, bool): + ts = self.data + else: + ts = actualdata + + z = (ts - loc) / scale + pdf = (1.0 / scale) * (np.exp(-(z + (np.exp(-z))))) + # gumbel_r.pdf(data, loc=loc, scale=scale) + if plot_figure: + Qx = np.linspace( + float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 + ) + pdf_fitted = self.pdf(loc, scale, actualdata=Qx) + + fig, ax = plot.pdf( + Qx, + pdf_fitted, + self.data_sorted, + figsize=figsize, + xlabel=xlabel, + ylabel=ylabel, + fontsize=fontsize, + ) + return pdf, fig, ax + else: + return pdf class Gumbel: """Gumbel distribution.""" + cdf_Weibul: ndarray + parameters: dict[str, Union[float, Any]] + def __init__( self, data: Union[list, np.ndarray] = None, - loc: Union[int, float] = None, - scale: Union[int, float] = None, + parameters: Dict[str, str] = None, ): """Gumbel. @@ -89,10 +192,12 @@ def __init__( ---------- data : [list] data time series. - loc: [numeric] - location parameter - scale: [numeric] - scale parameter + parameters: Dict[str, str] + {"loc": val, "scale": val} + - loc: [numeric] + location parameter of the gumbel distribution. + - scale: [numeric] + scale parameter of the gumbel distribution. """ if isinstance(data, list) or isinstance(data, np.ndarray): self.data = np.array(data) @@ -100,8 +205,7 @@ def __init__( self.cdf_Weibul = PlottingPosition.weibul(data) self.KStable = 1.22 / np.sqrt(len(self.data)) - self.loc = loc - self.scale = scale + self.parameters = parameters self.Dstatic = None self.KS_Pvalue = None self.chistatic = None @@ -111,8 +215,7 @@ def __init__( def pdf( self, - loc: Union[float, int], - scale: Union[float, int], + parameters: Dict[str, Union[float, Any]], plot_figure: bool = False, figsize: tuple = (6, 5), xlabel: str = "Actual data", @@ -126,16 +229,21 @@ def pdf( Parameters: ----------- - loc : [numeric] - location parameter of the gumbel distribution. - scale : [numeric] - scale parameter of the gumbel distribution. + parameters: Dict[str, str] + {"loc": val, "scale": val} + - loc: [numeric] + location parameter of the gumbel distribution. + - scale: [numeric] + scale parameter of the gumbel distribution. Returns ------- pdf : [array] probability density function pdf. """ + loc = parameters.get("loc") + scale = parameters.get("scale") + if scale <= 0: raise ValueError("Scale parameter is negative") @@ -151,7 +259,7 @@ def pdf( Qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 ) - pdf_fitted = self.pdf(loc, scale, actualdata=Qx) + pdf_fitted = self.pdf(parameters, actualdata=Qx) fig, ax = plot.pdf( Qx, @@ -168,8 +276,7 @@ def pdf( def cdf( self, - loc: Union[float, int], - scale: Union[float, int], + parameters: Dict[str, Union[float, Any]], plot_figure: bool = False, figsize: tuple = (6, 5), xlabel: str = "data", @@ -183,11 +290,15 @@ def cdf( parameter: ---------- - 1- loc : [numeric] + parameters: Dict[str, str] + {"loc": val, "scale": val} + - loc: [numeric] location parameter of the gumbel distribution. - 2- scale : [numeric] + - scale: [numeric] scale parameter of the gumbel distribution. """ + loc = parameters.get("loc") + scale = parameters.get("scale") if scale <= 0: raise ValueError("Scale parameter is negative") @@ -203,7 +314,7 @@ def cdf( Qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 ) - cdf_fitted = self.cdf(loc, scale, actualdata=Qx) + cdf_fitted = self.cdf(parameters, actualdata=Qx) cdf_Weibul = PlottingPosition.weibul(self.data_sorted) @@ -256,9 +367,10 @@ def ObjectiveFn(p, x): """ObjectiveFn. Link : https://stackoverflow.com/questions/23217484/how-to-find-parameters-of-gumbels-distribution-using-scipy-optimize - :param p: - :param x: - :return: + Parameters + ---------- + p: + x: """ threshold = p[0] loc = p[1] @@ -268,19 +380,20 @@ def ObjectiveFn(p, x): nx2 = len(x[x >= threshold]) # pdf with a scaled pdf # L1 is pdf based - L1 = (-np.log((Gumbel.pdf(x1, loc, scale) / scale))).sum() + parameters = {"loc": loc, "scale": scale} + L1 = (-np.log((Gumbel.pdf(0, parameters, actualdata=x1) / scale))).sum() # L2 is cdf based - L2 = (-np.log(1 - Gumbel.cdf(threshold, loc, scale))) * nx2 + L2 = (-np.log(1 - Gumbel.cdf(0, parameters, actualdata=threshold))) * nx2 # print x1, nx2, L1, L2 return L1 + L2 def estimateParameter( self, method: str = "mle", - ObjFunc=None, + ObjFunc: Callable = None, threshold: Union[None, float, int] = None, test: bool = True, - ) -> tuple: + ) -> Dict[str, str]: """estimateParameter. EstimateParameter estimate the distribution parameter based on MLM @@ -307,9 +420,12 @@ def estimateParameter( Returns ------- - Param : [list] - scale and location parameter of the gumbel distribution. - [loc, scale] + Dict[str, str]: + {"loc": val, "scale": val} + - loc: [numeric] + location parameter of the gumbel distribution. + - scale: [numeric] + scale parameter of the gumbel distribution. """ # obj_func = lambda p, x: (-np.log(Gumbel.pdf(x, p[0], p[1]))).sum() # #first we make a simple Gumbel fit @@ -338,9 +454,8 @@ def estimateParameter( maxfun=500, ) Param = [Param[1], Param[2]] - - self.loc = Param[0] - self.scale = Param[1] + Param = {"loc": Param[0], "scale": Param[1]} + self.parameters = Param if test: self.ks() @@ -350,7 +465,7 @@ def estimateParameter( @staticmethod def theporeticalEstimate( - loc: Union[float, int], scale: Union[float, int], cdf: np.ndarray + parameters: Dict[str, Union[float, Any]], cdf: np.ndarray ) -> np.ndarray: """theporeticalEstimate. @@ -358,8 +473,12 @@ def theporeticalEstimate( Parameters: ----------- - param : [list] - location ans scale parameters of the gumbel distribution. + parameters: Dict[str, str] + {"loc": val, "scale": val} + - loc: [numeric] + location parameter of the gumbel distribution. + - scale: [numeric] + scale parameter of the gumbel distribution. cdf: [list] cummulative distribution function/ Non Exceedence probability. @@ -368,6 +487,9 @@ def theporeticalEstimate( theoreticalvalue : [numeric] Value based on the theoretical distribution """ + loc = parameters.get("loc") + scale = parameters.get("scale") + if scale <= 0: raise ValueError("Scale parameter is negative") @@ -394,12 +516,12 @@ def ks(self) -> tuple: Pvalue : [numeric] IF Pvalue < signeficance level ------ reject the null hypotethis """ - if self.loc is None or self.scale is None: + if self.parameters is None: raise ValueError( - "Value of loc/scale parameter is unknown please use " - "'EstimateParameter' to obtain them" + "Value of parameters is unknown please use " + "'EstimateParameter' to obtain estimate the distribution parameters" ) - Qth = self.theporeticalEstimate(self.loc, self.scale, self.cdf_Weibul) + Qth = self.theporeticalEstimate(self.parameters, self.cdf_Weibul) test = ks_2samp(self.data, Qth) self.Dstatic = test.statistic @@ -421,13 +543,13 @@ def chisquare(self) -> tuple: ------- """ - if self.loc is None or self.scale is None: + if self.parameters is None: raise ValueError( "Value of loc/scale parameter is unknown please use " "'EstimateParameter' to obtain them" ) - Qth = self.theporeticalEstimate(self.loc, self.scale, self.cdf_Weibul) + Qth = self.theporeticalEstimate(self.parameters, self.cdf_Weibul) try: test = chisquare(st.standardize(Qth), st.standardize(self.data)) self.chistatic = test.statistic @@ -442,8 +564,7 @@ def chisquare(self) -> tuple: def confidenceInterval( self, - loc: Union[float, int], - scale: Union[float, int], + parameters: Dict[str, Union[float, Any]], F: np.ndarray, alpha: float = 0.1, ) -> Tuple[np.ndarray, np.ndarray]: @@ -451,10 +572,12 @@ def confidenceInterval( Parameters: ----------- - loc : [numeric] - location parameter of the gumbel distribution. - scale : [numeric] - scale parameter of the gumbel distribution. + parameters: Dict[str, str] + {"loc": val, "scale": val} + - loc: [numeric] + location parameter of the gumbel distribution. + - scale: [numeric] + scale parameter of the gumbel distribution. F : [list] Non Exceedence probability alpha : [numeric] @@ -462,15 +585,23 @@ def confidenceInterval( Return: ------- + parameters: Dict[str, str] + {"loc": val, "scale": val, "shape": value} + - loc: [numeric] + location parameter + - scale: [numeric] + scale parameter Qupper : [list] upper bound coresponding to the confidence interval. Qlower : [list] lower bound coresponding to the confidence interval. """ + scale = parameters.get("scale") + if scale <= 0: raise ValueError("Scale parameter is negative") - Qth = self.theporeticalEstimate(loc, scale, F) + Qth = self.theporeticalEstimate(parameters, F) Y = [-np.log(-np.log(j)) for j in F] StdError = [ (scale / np.sqrt(len(self.data))) @@ -484,8 +615,7 @@ def confidenceInterval( def probapilityPlot( self, - loc: float, - scale: float, + parameters: Dict[str, Union[float, Any]], F: np.ndarray, alpha: float = 0.1, fig1size: tuple = (10, 5), @@ -501,10 +631,12 @@ def probapilityPlot( Parameters ---------- - loc : [numeric] - location parameter of the gumbel distribution. - scale : [numeric] - scale parameter of the gumbel distribution. + parameters: Dict[str, str] + {"loc": val, "scale": val} + - loc: [numeric] + location parameter of the gumbel distribution. + - scale: [numeric] + scale parameter of the gumbel distribution. F : [np.ndarray] theoretical cdf calculated using weibul or using the distribution cdf function. alpha : [float] @@ -530,17 +662,19 @@ def probapilityPlot( Qlower : [list] lower bound coresponding to the confidence interval. """ + scale = parameters.get("scale") + if scale <= 0: raise ValueError("Scale parameter is negative") - Qth = self.theporeticalEstimate(loc, scale, F) - Qupper, Qlower = self.confidenceInterval(loc, scale, F, alpha) + Qth = self.theporeticalEstimate(parameters, F) + Qupper, Qlower = self.confidenceInterval(parameters, F, alpha) Qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 ) - pdf_fitted = self.pdf(loc, scale, actualdata=Qx) - cdf_fitted = self.cdf(loc, scale, actualdata=Qx) + pdf_fitted = self.pdf(parameters, actualdata=Qx) + cdf_fitted = self.cdf(parameters, actualdata=Qx) fig, ax = plot.details( Qx, @@ -590,7 +724,6 @@ def __init__( self.cdf_Weibul = PlottingPosition.weibul(data) self.KStable = 1.22 / np.sqrt(len(self.data)) - self.shape = shape self.loc = loc self.scale = scale self.Dstatic = None @@ -598,6 +731,8 @@ def __init__( self.chistatic = None self.chi_Pvalue = None + + self.shape = shape pass def pdf( @@ -1139,6 +1274,7 @@ def BSIndexes(data, n_samples=10000): for _ in range(n_samples): yield randint(data.shape[0], size=(data.shape[0],)) + @staticmethod def BootStrap( data: Union[list, np.ndarray], statfunction, diff --git a/tests/conftest.py b/tests/conftest.py index b7c1381..4f4fed2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -31,4 +31,4 @@ def confidence_interval_alpha() -> float: @pytest.fixture(scope="module") def parameter_estimation_optimization_threshold() -> int: - return 17 + return 800 # 17 diff --git a/tests/test_distributions.py b/tests/test_distributions.py index 8f29f97..847b32f 100644 --- a/tests/test_distributions.py +++ b/tests/test_distributions.py @@ -6,268 +6,297 @@ from statista.distributions import GEV, ConfidenceInterval, Gumbel, PlottingPosition -def test_plotting_position_weibul( - time_series1: list, -): - cdf = PlottingPosition.weibul(time_series1, option=1) - assert isinstance(cdf, np.ndarray) - rp = PlottingPosition.weibul(time_series1, option=2) - assert isinstance(rp, np.ndarray) - - -def test_plotting_position_rp( - time_series1: list, -): - cdf = PlottingPosition.weibul(time_series1, option=1) - rp = PlottingPosition.returnPeriod(cdf) - assert isinstance(rp, np.ndarray) - - -def test_create_gumbel_instance( - time_series1: list, -): - Gdist = Gumbel(time_series1) - assert isinstance(Gdist.data, np.ndarray) - assert isinstance(Gdist.data_sorted, np.ndarray) - - -def test_gumbel_estimate_parameter( - time_series2: list, - dist_estimation_parameters: List[str], -): - Gdist = Gumbel(time_series2) - for i in range(len(dist_estimation_parameters)): +class TestPlottingPosition: + def test_plotting_position_weibul( + self, + time_series1: list, + ): + cdf = PlottingPosition.weibul(time_series1, return_period=False) + assert isinstance(cdf, np.ndarray) + rp = PlottingPosition.weibul(time_series1, return_period=True) + assert isinstance(rp, np.ndarray) + + def test_plotting_position_rp( + self, + time_series1: list, + ): + cdf = PlottingPosition.weibul(time_series1, return_period=False) + rp = PlottingPosition.returnPeriod(cdf) + assert isinstance(rp, np.ndarray) + + +class TestGumbel: + def test_create_gumbel_instance( + self, + time_series1: list, + ): + Gdist = Gumbel(time_series1) + assert isinstance(Gdist.data, np.ndarray) + assert isinstance(Gdist.data_sorted, np.ndarray) + + def test_gumbel_estimate_parameter( + self, + time_series2: list, + dist_estimation_parameters: List[str], + ): + Gdist = Gumbel(time_series2) + for i in range(len(dist_estimation_parameters)): + param = Gdist.estimateParameter( + method=dist_estimation_parameters[i], test=False + ) + assert isinstance(param, dict) + assert all(i in param.keys() for i in ["loc", "scale"]) + assert Gdist.parameters.get("loc") is not None + assert Gdist.parameters.get("scale") is not None + + def test_parameter_estimation_optimization( + self, + time_series2: list, + dist_estimation_parameters: List[str], + parameter_estimation_optimization_threshold: int, + ): + Gdist = Gumbel(time_series2) param = Gdist.estimateParameter( - method=dist_estimation_parameters[i], test=False + method="optimization", + ObjFunc=Gumbel.ObjectiveFn, + threshold=parameter_estimation_optimization_threshold, ) - assert isinstance(param, list) - assert Gdist.loc - assert Gdist.scale - - -def test_parameter_estimation_optimization( - time_series2: list, - dist_estimation_parameters: List[str], - parameter_estimation_optimization_threshold: int, -): - Gdist = Gumbel(time_series2) - param = Gdist.estimateParameter( - method="optimization", - ObjFunc=Gumbel.ObjectiveFn, - threshold=parameter_estimation_optimization_threshold, - ) - assert isinstance(param, list) - assert Gdist.loc - assert Gdist.scale - - -def test_gumbel_ks( - time_series2: list, - dist_estimation_parameters_ks: str, -): - Gdist = Gumbel(time_series2) - Gdist.estimateParameter(method=dist_estimation_parameters_ks, test=False) - Gdist.ks() - assert Gdist.Dstatic - assert Gdist.KS_Pvalue - - -def test_gumbel_chisquare( - time_series2: list, - dist_estimation_parameters_ks: str, -): - Gdist = Gumbel(time_series2) - Gdist.estimateParameter(method=dist_estimation_parameters_ks, test=False) - Gdist.chisquare() - assert Gdist.chistatic - assert Gdist.chi_Pvalue - - -def test_gumbel_pdf( - time_series2: list, - dist_estimation_parameters_ks: str, -): - Gdist = Gumbel(time_series2) - Param = Gdist.estimateParameter(method=dist_estimation_parameters_ks, test=False) - pdf, fig, ax = Gdist.pdf(Param[0], Param[1], plot_figure=True) - assert isinstance(pdf, np.ndarray) - assert isinstance(fig, Figure) - - -def test_gumbel_cdf( - time_series2: list, - dist_estimation_parameters_ks: str, -): - Gdist = Gumbel(time_series2) - Param = Gdist.estimateParameter(method=dist_estimation_parameters_ks, test=False) - cdf, fig, ax = Gdist.cdf(Param[0], Param[1], plot_figure=True) - assert isinstance(cdf, np.ndarray) - assert isinstance(fig, Figure) - - -def test_gumbel_TheporeticalEstimate( - time_series2: list, - dist_estimation_parameters_ks: str, -): - Gdist = Gumbel(time_series2) - cdf_Weibul = PlottingPosition.weibul(time_series2) - Param = Gdist.estimateParameter(method=dist_estimation_parameters_ks, test=False) - Qth = Gdist.theporeticalEstimate(Param[0], Param[1], cdf_Weibul) - assert isinstance(Qth, np.ndarray) - - -def test_gumbel_confidence_interval( - time_series2: list, - dist_estimation_parameters_ks: str, - confidence_interval_alpha: float, -): - Gdist = Gumbel(time_series2) - cdf_Weibul = PlottingPosition.weibul(time_series2) - Param = Gdist.estimateParameter(method=dist_estimation_parameters_ks, test=False) - upper, lower = Gdist.confidenceInterval( - Param[0], Param[1], cdf_Weibul, alpha=confidence_interval_alpha - ) - assert isinstance(upper, np.ndarray) - assert isinstance(lower, np.ndarray) - - -def test_gumbel_probapility_plot( - time_series2: list, - dist_estimation_parameters_ks: str, - confidence_interval_alpha: float, -): - Gdist = Gumbel(time_series2) - cdf_Weibul = PlottingPosition.weibul(time_series2) - Param = Gdist.estimateParameter(method=dist_estimation_parameters_ks, test=False) - [fig1, fig2], [ax1, ax2] = Gdist.probapilityPlot( - Param[0], Param[1], cdf_Weibul, alpha=confidence_interval_alpha - ) - assert isinstance(fig1, Figure) - assert isinstance(fig2, Figure) - - -def test_create_gev_instance( - time_series1: list, -): - Gdist = GEV(time_series1) - assert isinstance(Gdist.data, np.ndarray) - assert isinstance(Gdist.data_sorted, np.ndarray) - - -def test_gev_estimate_parameter( - time_series1: list, - dist_estimation_parameters: List[str], -): - Gdist = GEV(time_series1) - for i in range(len(dist_estimation_parameters)): - param = Gdist.estimateParameter( - method=dist_estimation_parameters[i], test=False + assert isinstance(param, dict) + assert all(i in param.keys() for i in ["loc", "scale"]) + assert Gdist.parameters.get("loc") is not None + assert Gdist.parameters.get("scale") is not None + + def test_gumbel_ks( + self, + time_series2: list, + dist_estimation_parameters_ks: str, + ): + Gdist = Gumbel(time_series2) + Gdist.estimateParameter(method=dist_estimation_parameters_ks, test=False) + Gdist.ks() + assert Gdist.Dstatic + assert Gdist.KS_Pvalue + + def test_gumbel_chisquare( + self, + time_series2: list, + dist_estimation_parameters_ks: str, + ): + Gdist = Gumbel(time_series2) + Gdist.estimateParameter(method=dist_estimation_parameters_ks, test=False) + Gdist.chisquare() + assert Gdist.chistatic + assert Gdist.chi_Pvalue + + def test_gumbel_pdf( + self, + time_series2: list, + dist_estimation_parameters_ks: str, + ): + Gdist = Gumbel(time_series2) + Param = Gdist.estimateParameter( + method=dist_estimation_parameters_ks, test=False ) - assert isinstance(param, list) - assert Gdist.loc - assert Gdist.scale - assert Gdist.shape + pdf, fig, ax = Gdist.pdf(Param, plot_figure=True) + assert isinstance(pdf, np.ndarray) + assert isinstance(fig, Figure) + + def test_gumbel_cdf( + self, + time_series2: list, + dist_estimation_parameters_ks: str, + ): + Gdist = Gumbel(time_series2) + Param = Gdist.estimateParameter( + method=dist_estimation_parameters_ks, test=False + ) + cdf, fig, ax = Gdist.cdf(Param, plot_figure=True) + assert isinstance(cdf, np.ndarray) + assert isinstance(fig, Figure) + + def test_gumbel_TheporeticalEstimate( + self, + time_series2: list, + dist_estimation_parameters_ks: str, + ): + Gdist = Gumbel(time_series2) + cdf_Weibul = PlottingPosition.weibul(time_series2) + Param = Gdist.estimateParameter( + method=dist_estimation_parameters_ks, test=False + ) + Qth = Gdist.theporeticalEstimate(Param, cdf_Weibul) + assert isinstance(Qth, np.ndarray) + + def test_gumbel_confidence_interval( + self, + time_series2: list, + dist_estimation_parameters_ks: str, + confidence_interval_alpha: float, + ): + Gdist = Gumbel(time_series2) + cdf_Weibul = PlottingPosition.weibul(time_series2) + Param = Gdist.estimateParameter( + method=dist_estimation_parameters_ks, test=False + ) + upper, lower = Gdist.confidenceInterval( + Param, cdf_Weibul, alpha=confidence_interval_alpha + ) + assert isinstance(upper, np.ndarray) + assert isinstance(lower, np.ndarray) + + def test_gumbel_probapility_plot( + self, + time_series2: list, + dist_estimation_parameters_ks: str, + confidence_interval_alpha: float, + ): + Gdist = Gumbel(time_series2) + cdf_Weibul = PlottingPosition.weibul(time_series2) + Param = Gdist.estimateParameter( + method=dist_estimation_parameters_ks, test=False + ) + [fig1, fig2], [ax1, ax2] = Gdist.probapilityPlot( + Param, cdf_Weibul, alpha=confidence_interval_alpha + ) + assert isinstance(fig1, Figure) + assert isinstance(fig2, Figure) + + +class TestGEV: + def test_create_gev_instance( + self, + time_series1: list, + ): + Gdist = GEV(time_series1) + assert isinstance(Gdist.data, np.ndarray) + assert isinstance(Gdist.data_sorted, np.ndarray) + + def test_gev_estimate_parameter( + self, + time_series1: list, + dist_estimation_parameters: List[str], + ): + Gdist = GEV(time_series1) + for i in range(len(dist_estimation_parameters)): + param = Gdist.estimateParameter( + method=dist_estimation_parameters[i], test=False + ) + assert isinstance(param, list) + assert Gdist.loc + assert Gdist.scale + assert Gdist.shape + + def test_gev_ks( + self, + time_series1: list, + dist_estimation_parameters_ks: str, + ): + Gdist = GEV(time_series1) + Gdist.estimateParameter(method=dist_estimation_parameters_ks, test=False) + Gdist.ks() + assert Gdist.Dstatic + assert Gdist.KS_Pvalue + + def test_gev_chisquare( + self, + time_series1: list, + dist_estimation_parameters_ks: str, + ): + Gdist = GEV(time_series1) + Gdist.estimateParameter(method=dist_estimation_parameters_ks, test=False) + Gdist.chisquare() + assert Gdist.chistatic + assert Gdist.chi_Pvalue + + def test_gev_pdf( + self, + time_series1: list, + dist_estimation_parameters_ks: str, + ): + Gdist = GEV(time_series1) + Param = Gdist.estimateParameter( + method=dist_estimation_parameters_ks, test=False + ) + pdf, fig, ax = Gdist.pdf(Param[0], Param[1], Param[2], plot_figure=True) + assert isinstance(pdf, np.ndarray) + assert isinstance(fig, Figure) + + def test_gev_cdf( + self, + time_series1: list, + dist_estimation_parameters_ks: str, + ): + Gdist = GEV(time_series1) + Param = Gdist.estimateParameter( + method=dist_estimation_parameters_ks, test=False + ) + cdf, fig, ax = Gdist.cdf(Param[0], Param[1], Param[2], plot_figure=True) + assert isinstance(cdf, np.ndarray) + assert isinstance(fig, Figure) + + def test_gev_TheporeticalEstimate( + self, + time_series1: list, + dist_estimation_parameters_ks: str, + ): + Gdist = GEV(time_series1) + cdf_Weibul = PlottingPosition.weibul(time_series1) + Param = Gdist.estimateParameter( + method=dist_estimation_parameters_ks, test=False + ) + Qth = Gdist.theporeticalEstimate(Param[0], Param[1], Param[2], cdf_Weibul) + assert isinstance(Qth, np.ndarray) + + def test_gev_confidence_interval( + self, + time_series1: list, + dist_estimation_parameters_ks: str, + confidence_interval_alpha: float, + ): + Gdist = GEV(time_series1) + cdf_Weibul = PlottingPosition.weibul(time_series1) + Param = Gdist.estimateParameter( + method=dist_estimation_parameters_ks, test=False + ) + func = ConfidenceInterval.GEVfunc + upper, lower = Gdist.confidenceInterval( + Param[0], + Param[1], + Param[2], + F=cdf_Weibul, + alpha=confidence_interval_alpha, + statfunction=func, + n_samples=len(time_series1), + ) + assert isinstance(upper, np.ndarray) + assert isinstance(lower, np.ndarray) + + def test_confidence_interval_directly( + self, + time_series1: list, + dist_estimation_parameters_ks: str, + confidence_interval_alpha: float, + ): + Gdist = GEV(time_series1) + cdf_Weibul = PlottingPosition.weibul(time_series1) + Param = Gdist.estimateParameter( + method=dist_estimation_parameters_ks, test=False + ) + func = ConfidenceInterval.GEVfunc + # upper, lower = Gdist.ConfidenceInterval( + # Param[0], Param[1], Param[2], F=cdf_Weibul, alpha=confidence_interval_alpha, + # statfunction=func, n_samples=len(time_series1) + # ) + CI = ConfidenceInterval.BootStrap( + time_series1, + statfunction=func, + gevfit=Param, + n_samples=len(time_series1), + F=cdf_Weibul, + ) + LB = CI["LB"] + UB = CI["UB"] -def test_gev_ks( - time_series1: list, - dist_estimation_parameters_ks: str, -): - Gdist = GEV(time_series1) - Gdist.estimateParameter(method=dist_estimation_parameters_ks, test=False) - Gdist.ks() - assert Gdist.Dstatic - assert Gdist.KS_Pvalue - - -def test_gev_chisquare( - time_series1: list, - dist_estimation_parameters_ks: str, -): - Gdist = GEV(time_series1) - Gdist.estimateParameter(method=dist_estimation_parameters_ks, test=False) - Gdist.chisquare() - assert Gdist.chistatic - assert Gdist.chi_Pvalue - - -def test_gev_pdf( - time_series1: list, - dist_estimation_parameters_ks: str, -): - Gdist = GEV(time_series1) - Param = Gdist.estimateParameter(method=dist_estimation_parameters_ks, test=False) - pdf, fig, ax = Gdist.pdf(Param[0], Param[1], Param[2], plot_figure=True) - assert isinstance(pdf, np.ndarray) - assert isinstance(fig, Figure) - - -def test_gev_cdf( - time_series1: list, - dist_estimation_parameters_ks: str, -): - Gdist = GEV(time_series1) - Param = Gdist.estimateParameter(method=dist_estimation_parameters_ks, test=False) - cdf, fig, ax = Gdist.cdf(Param[0], Param[1], Param[2], plot_figure=True) - assert isinstance(cdf, np.ndarray) - assert isinstance(fig, Figure) - - -def test_gev_TheporeticalEstimate( - time_series1: list, - dist_estimation_parameters_ks: str, -): - Gdist = GEV(time_series1) - cdf_Weibul = PlottingPosition.weibul(time_series1) - Param = Gdist.estimateParameter(method=dist_estimation_parameters_ks, test=False) - Qth = Gdist.theporeticalEstimate(Param[0], Param[1], Param[2], cdf_Weibul) - assert isinstance(Qth, np.ndarray) - - -def test_gev_confidence_interval( - time_series1: list, - dist_estimation_parameters_ks: str, - confidence_interval_alpha: float, -): - Gdist = GEV(time_series1) - cdf_Weibul = PlottingPosition.weibul(time_series1) - Param = Gdist.estimateParameter(method=dist_estimation_parameters_ks, test=False) - func = ConfidenceInterval.GEVfunc - upper, lower = Gdist.confidenceInterval( - Param[0], - Param[1], - Param[2], - F=cdf_Weibul, - alpha=confidence_interval_alpha, - statfunction=func, - n_samples=len(time_series1), - ) - assert isinstance(upper, np.ndarray) - assert isinstance(lower, np.ndarray) - - -def test_confidence_interval_directly( - time_series1: list, - dist_estimation_parameters_ks: str, - confidence_interval_alpha: float, -): - Gdist = GEV(time_series1) - cdf_Weibul = PlottingPosition.weibul(time_series1) - Param = Gdist.estimateParameter(method=dist_estimation_parameters_ks, test=False) - func = ConfidenceInterval.GEVfunc - # upper, lower = Gdist.ConfidenceInterval( - # Param[0], Param[1], Param[2], F=cdf_Weibul, alpha=confidence_interval_alpha, - # statfunction=func, n_samples=len(time_series1) - # ) - CI = ConfidenceInterval.BootStrap( - time_series1, - statfunction=func, - gevfit=Param, - n_samples=len(time_series1), - F=cdf_Weibul, - ) - LB = CI["LB"] - UB = CI["UB"] - - assert isinstance(LB, np.ndarray) - assert isinstance(UB, np.ndarray) + assert isinstance(LB, np.ndarray) + assert isinstance(UB, np.ndarray) From 0bb8638d0f27c32b04ec787d768a674812f79129 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Wed, 8 Feb 2023 02:08:40 +0100 Subject: [PATCH 02/44] replace the separate parameter by an dict input containing all the parameters --- environment.yml | 13 + poetry.lock | 1524 ----------------------------------- pyproject.toml | 87 -- requirements-dev.txt | 12 + requirements.txt | 7 + setup.py | 41 + statista/distributions.py | 132 +-- tests/test_distributions.py | 20 +- 8 files changed, 153 insertions(+), 1683 deletions(-) create mode 100644 environment.yml delete mode 100644 poetry.lock delete mode 100644 pyproject.toml create mode 100644 requirements-dev.txt create mode 100644 requirements.txt create mode 100644 setup.py diff --git a/environment.yml b/environment.yml new file mode 100644 index 0000000..bd8ed5a --- /dev/null +++ b/environment.yml @@ -0,0 +1,13 @@ +channels: + - conda-forge +dependencies: + - python >=3.9,<3.11 + - numpy ==1.24.1 + - pip >=22.3.1 + - matplotlib >=3.6.3 + - pandas >=1.5.3 + - scipy >=1.9.0 + - scikit-learn >=1.2.1 + - loguru >=0.6.0 + - pytest >=7.2.0 + - pytest-cov >= 4.0.0 \ No newline at end of file diff --git a/poetry.lock b/poetry.lock deleted file mode 100644 index 7d431d5..0000000 --- a/poetry.lock +++ /dev/null @@ -1,1524 +0,0 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. - -[[package]] -name = "attrs" -version = "22.2.0" -description = "Classes Without Boilerplate" -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"}, - {file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"}, -] - -[package.extras] -cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"] -tests = ["attrs[tests-no-zope]", "zope.interface"] -tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"] - -[[package]] -name = "bandit" -version = "1.7.4" -description = "Security oriented static analyser for python code." -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "bandit-1.7.4-py3-none-any.whl", hash = "sha256:412d3f259dab4077d0e7f0c11f50f650cc7d10db905d98f6520a95a18049658a"}, - {file = "bandit-1.7.4.tar.gz", hash = "sha256:2d63a8c573417bae338962d4b9b06fbc6080f74ecd955a092849e1e65c717bd2"}, -] - -[package.dependencies] -colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""} -GitPython = ">=1.0.1" -PyYAML = ">=5.3.1" -stevedore = ">=1.20.0" - -[package.extras] -test = ["beautifulsoup4 (>=4.8.0)", "coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "pylint (==1.9.4)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)", "toml"] -toml = ["toml"] -yaml = ["PyYAML"] - -[[package]] -name = "black" -version = "22.12.0" -description = "The uncompromising code formatter." -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"}, - {file = "black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"}, - {file = "black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f"}, - {file = "black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4"}, - {file = "black-22.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2"}, - {file = "black-22.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350"}, - {file = "black-22.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d"}, - {file = "black-22.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc"}, - {file = "black-22.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320"}, - {file = "black-22.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148"}, - {file = "black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf"}, - {file = "black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} -typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - -[[package]] -name = "cfgv" -version = "3.3.1" -description = "Validate configuration and produce human readable error messages." -category = "dev" -optional = false -python-versions = ">=3.6.1" -files = [ - {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, - {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, -] - -[[package]] -name = "classify-imports" -version = "4.2.0" -description = "Utilities for refactoring imports in python-like syntax." -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "classify_imports-4.2.0-py2.py3-none-any.whl", hash = "sha256:dbbc264b70a470ed8c6c95976a11dfb8b7f63df44ed1af87328bbed2663f5161"}, - {file = "classify_imports-4.2.0.tar.gz", hash = "sha256:7abfb7ea92149b29d046bd34573d247ba6e68cc28100c801eba4af17964fc40e"}, -] - -[[package]] -name = "click" -version = "8.1.3" -description = "Composable command line interface toolkit" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, - {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -category = "main" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] - -[[package]] -name = "contourpy" -version = "1.0.7" -description = "Python library for calculating contours of 2D quadrilateral grids" -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "contourpy-1.0.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:95c3acddf921944f241b6773b767f1cbce71d03307270e2d769fd584d5d1092d"}, - {file = "contourpy-1.0.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fc1464c97579da9f3ab16763c32e5c5d5bb5fa1ec7ce509a4ca6108b61b84fab"}, - {file = "contourpy-1.0.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8acf74b5d383414401926c1598ed77825cd530ac7b463ebc2e4f46638f56cce6"}, - {file = "contourpy-1.0.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c71fdd8f1c0f84ffd58fca37d00ca4ebaa9e502fb49825484da075ac0b0b803"}, - {file = "contourpy-1.0.7-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f99e9486bf1bb979d95d5cffed40689cb595abb2b841f2991fc894b3452290e8"}, - {file = "contourpy-1.0.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87f4d8941a9564cda3f7fa6a6cd9b32ec575830780677932abdec7bcb61717b0"}, - {file = "contourpy-1.0.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9e20e5a1908e18aaa60d9077a6d8753090e3f85ca25da6e25d30dc0a9e84c2c6"}, - {file = "contourpy-1.0.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a877ada905f7d69b2a31796c4b66e31a8068b37aa9b78832d41c82fc3e056ddd"}, - {file = "contourpy-1.0.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6381fa66866b0ea35e15d197fc06ac3840a9b2643a6475c8fff267db8b9f1e69"}, - {file = "contourpy-1.0.7-cp310-cp310-win32.whl", hash = "sha256:3c184ad2433635f216645fdf0493011a4667e8d46b34082f5a3de702b6ec42e3"}, - {file = "contourpy-1.0.7-cp310-cp310-win_amd64.whl", hash = "sha256:3caea6365b13119626ee996711ab63e0c9d7496f65641f4459c60a009a1f3e80"}, - {file = "contourpy-1.0.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ed33433fc3820263a6368e532f19ddb4c5990855e4886088ad84fd7c4e561c71"}, - {file = "contourpy-1.0.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:38e2e577f0f092b8e6774459317c05a69935a1755ecfb621c0a98f0e3c09c9a5"}, - {file = "contourpy-1.0.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ae90d5a8590e5310c32a7630b4b8618cef7563cebf649011da80874d0aa8f414"}, - {file = "contourpy-1.0.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:130230b7e49825c98edf0b428b7aa1125503d91732735ef897786fe5452b1ec2"}, - {file = "contourpy-1.0.7-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58569c491e7f7e874f11519ef46737cea1d6eda1b514e4eb5ac7dab6aa864d02"}, - {file = "contourpy-1.0.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54d43960d809c4c12508a60b66cb936e7ed57d51fb5e30b513934a4a23874fae"}, - {file = "contourpy-1.0.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:152fd8f730c31fd67fe0ffebe1df38ab6a669403da93df218801a893645c6ccc"}, - {file = "contourpy-1.0.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9056c5310eb1daa33fc234ef39ebfb8c8e2533f088bbf0bc7350f70a29bde1ac"}, - {file = "contourpy-1.0.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a9d7587d2fdc820cc9177139b56795c39fb8560f540bba9ceea215f1f66e1566"}, - {file = "contourpy-1.0.7-cp311-cp311-win32.whl", hash = "sha256:4ee3ee247f795a69e53cd91d927146fb16c4e803c7ac86c84104940c7d2cabf0"}, - {file = "contourpy-1.0.7-cp311-cp311-win_amd64.whl", hash = "sha256:5caeacc68642e5f19d707471890f037a13007feba8427eb7f2a60811a1fc1350"}, - {file = "contourpy-1.0.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fd7dc0e6812b799a34f6d12fcb1000539098c249c8da54f3566c6a6461d0dbad"}, - {file = "contourpy-1.0.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0f9d350b639db6c2c233d92c7f213d94d2e444d8e8fc5ca44c9706cf72193772"}, - {file = "contourpy-1.0.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e96a08b62bb8de960d3a6afbc5ed8421bf1a2d9c85cc4ea73f4bc81b4910500f"}, - {file = "contourpy-1.0.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:031154ed61f7328ad7f97662e48660a150ef84ee1bc8876b6472af88bf5a9b98"}, - {file = "contourpy-1.0.7-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e9ebb4425fc1b658e13bace354c48a933b842d53c458f02c86f371cecbedecc"}, - {file = "contourpy-1.0.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efb8f6d08ca7998cf59eaf50c9d60717f29a1a0a09caa46460d33b2924839dbd"}, - {file = "contourpy-1.0.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6c180d89a28787e4b73b07e9b0e2dac7741261dbdca95f2b489c4f8f887dd810"}, - {file = "contourpy-1.0.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b8d587cc39057d0afd4166083d289bdeff221ac6d3ee5046aef2d480dc4b503c"}, - {file = "contourpy-1.0.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:769eef00437edf115e24d87f8926955f00f7704bede656ce605097584f9966dc"}, - {file = "contourpy-1.0.7-cp38-cp38-win32.whl", hash = "sha256:62398c80ef57589bdbe1eb8537127321c1abcfdf8c5f14f479dbbe27d0322e66"}, - {file = "contourpy-1.0.7-cp38-cp38-win_amd64.whl", hash = "sha256:57119b0116e3f408acbdccf9eb6ef19d7fe7baf0d1e9aaa5381489bc1aa56556"}, - {file = "contourpy-1.0.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:30676ca45084ee61e9c3da589042c24a57592e375d4b138bd84d8709893a1ba4"}, - {file = "contourpy-1.0.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e927b3868bd1e12acee7cc8f3747d815b4ab3e445a28d2e5373a7f4a6e76ba1"}, - {file = "contourpy-1.0.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:366a0cf0fc079af5204801786ad7a1c007714ee3909e364dbac1729f5b0849e5"}, - {file = "contourpy-1.0.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89ba9bb365446a22411f0673abf6ee1fea3b2cf47b37533b970904880ceb72f3"}, - {file = "contourpy-1.0.7-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:71b0bf0c30d432278793d2141362ac853859e87de0a7dee24a1cea35231f0d50"}, - {file = "contourpy-1.0.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7281244c99fd7c6f27c1c6bfafba878517b0b62925a09b586d88ce750a016d2"}, - {file = "contourpy-1.0.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b6d0f9e1d39dbfb3977f9dd79f156c86eb03e57a7face96f199e02b18e58d32a"}, - {file = "contourpy-1.0.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7f6979d20ee5693a1057ab53e043adffa1e7418d734c1532e2d9e915b08d8ec2"}, - {file = "contourpy-1.0.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5dd34c1ae752515318224cba7fc62b53130c45ac6a1040c8b7c1a223c46e8967"}, - {file = "contourpy-1.0.7-cp39-cp39-win32.whl", hash = "sha256:c5210e5d5117e9aec8c47d9156d1d3835570dd909a899171b9535cb4a3f32693"}, - {file = "contourpy-1.0.7-cp39-cp39-win_amd64.whl", hash = "sha256:60835badb5ed5f4e194a6f21c09283dd6e007664a86101431bf870d9e86266c4"}, - {file = "contourpy-1.0.7-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ce41676b3d0dd16dbcfabcc1dc46090aaf4688fd6e819ef343dbda5a57ef0161"}, - {file = "contourpy-1.0.7-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a011cf354107b47c58ea932d13b04d93c6d1d69b8b6dce885e642531f847566"}, - {file = "contourpy-1.0.7-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:31a55dccc8426e71817e3fe09b37d6d48ae40aae4ecbc8c7ad59d6893569c436"}, - {file = "contourpy-1.0.7-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69f8ff4db108815addd900a74df665e135dbbd6547a8a69333a68e1f6e368ac2"}, - {file = "contourpy-1.0.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:efe99298ba37e37787f6a2ea868265465410822f7bea163edcc1bd3903354ea9"}, - {file = "contourpy-1.0.7-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a1e97b86f73715e8670ef45292d7cc033548266f07d54e2183ecb3c87598888f"}, - {file = "contourpy-1.0.7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc331c13902d0f50845099434cd936d49d7a2ca76cb654b39691974cb1e4812d"}, - {file = "contourpy-1.0.7-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:24847601071f740837aefb730e01bd169fbcaa610209779a78db7ebb6e6a7051"}, - {file = "contourpy-1.0.7-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abf298af1e7ad44eeb93501e40eb5a67abbf93b5d90e468d01fc0c4451971afa"}, - {file = "contourpy-1.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:64757f6460fc55d7e16ed4f1de193f362104285c667c112b50a804d482777edd"}, - {file = "contourpy-1.0.7.tar.gz", hash = "sha256:d8165a088d31798b59e91117d1f5fc3df8168d8b48c4acc10fc0df0d0bdbcc5e"}, -] - -[package.dependencies] -numpy = ">=1.16" - -[package.extras] -bokeh = ["bokeh", "chromedriver", "selenium"] -docs = ["furo", "sphinx-copybutton"] -mypy = ["contourpy[bokeh]", "docutils-stubs", "mypy (==0.991)", "types-Pillow"] -test = ["Pillow", "matplotlib", "pytest"] -test-no-images = ["pytest"] - -[[package]] -name = "coverage" -version = "7.1.0" -description = "Code coverage measurement for Python" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "coverage-7.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3b946bbcd5a8231383450b195cfb58cb01cbe7f8949f5758566b881df4b33baf"}, - {file = "coverage-7.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ec8e767f13be637d056f7e07e61d089e555f719b387a7070154ad80a0ff31801"}, - {file = "coverage-7.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4a5a5879a939cb84959d86869132b00176197ca561c664fc21478c1eee60d75"}, - {file = "coverage-7.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b643cb30821e7570c0aaf54feaf0bfb630b79059f85741843e9dc23f33aaca2c"}, - {file = "coverage-7.1.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32df215215f3af2c1617a55dbdfb403b772d463d54d219985ac7cd3bf124cada"}, - {file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:33d1ae9d4079e05ac4cc1ef9e20c648f5afabf1a92adfaf2ccf509c50b85717f"}, - {file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:29571503c37f2ef2138a306d23e7270687c0efb9cab4bd8038d609b5c2393a3a"}, - {file = "coverage-7.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:63ffd21aa133ff48c4dff7adcc46b7ec8b565491bfc371212122dd999812ea1c"}, - {file = "coverage-7.1.0-cp310-cp310-win32.whl", hash = "sha256:4b14d5e09c656de5038a3f9bfe5228f53439282abcab87317c9f7f1acb280352"}, - {file = "coverage-7.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:8361be1c2c073919500b6601220a6f2f98ea0b6d2fec5014c1d9cfa23dd07038"}, - {file = "coverage-7.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:da9b41d4539eefd408c46725fb76ecba3a50a3367cafb7dea5f250d0653c1040"}, - {file = "coverage-7.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5b15ed7644ae4bee0ecf74fee95808dcc34ba6ace87e8dfbf5cb0dc20eab45a"}, - {file = "coverage-7.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d12d076582507ea460ea2a89a8c85cb558f83406c8a41dd641d7be9a32e1274f"}, - {file = "coverage-7.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2617759031dae1bf183c16cef8fcfb3de7617f394c813fa5e8e46e9b82d4222"}, - {file = "coverage-7.1.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4e4881fa9e9667afcc742f0c244d9364d197490fbc91d12ac3b5de0bf2df146"}, - {file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9d58885215094ab4a86a6aef044e42994a2bd76a446dc59b352622655ba6621b"}, - {file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ffeeb38ee4a80a30a6877c5c4c359e5498eec095878f1581453202bfacc8fbc2"}, - {file = "coverage-7.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3baf5f126f30781b5e93dbefcc8271cb2491647f8283f20ac54d12161dff080e"}, - {file = "coverage-7.1.0-cp311-cp311-win32.whl", hash = "sha256:ded59300d6330be27bc6cf0b74b89ada58069ced87c48eaf9344e5e84b0072f7"}, - {file = "coverage-7.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:6a43c7823cd7427b4ed763aa7fb63901ca8288591323b58c9cd6ec31ad910f3c"}, - {file = "coverage-7.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7a726d742816cb3a8973c8c9a97539c734b3a309345236cd533c4883dda05b8d"}, - {file = "coverage-7.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc7c85a150501286f8b56bd8ed3aa4093f4b88fb68c0843d21ff9656f0009d6a"}, - {file = "coverage-7.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5b4198d85a3755d27e64c52f8c95d6333119e49fd001ae5798dac872c95e0f8"}, - {file = "coverage-7.1.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddb726cb861c3117a553f940372a495fe1078249ff5f8a5478c0576c7be12050"}, - {file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:51b236e764840a6df0661b67e50697aaa0e7d4124ca95e5058fa3d7cbc240b7c"}, - {file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7ee5c9bb51695f80878faaa5598040dd6c9e172ddcf490382e8aedb8ec3fec8d"}, - {file = "coverage-7.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c31b75ae466c053a98bf26843563b3b3517b8f37da4d47b1c582fdc703112bc3"}, - {file = "coverage-7.1.0-cp37-cp37m-win32.whl", hash = "sha256:3b155caf3760408d1cb903b21e6a97ad4e2bdad43cbc265e3ce0afb8e0057e73"}, - {file = "coverage-7.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2a60d6513781e87047c3e630b33b4d1e89f39836dac6e069ffee28c4786715f5"}, - {file = "coverage-7.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f2cba5c6db29ce991029b5e4ac51eb36774458f0a3b8d3137241b32d1bb91f06"}, - {file = "coverage-7.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:beeb129cacea34490ffd4d6153af70509aa3cda20fdda2ea1a2be870dfec8d52"}, - {file = "coverage-7.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c45948f613d5d18c9ec5eaa203ce06a653334cf1bd47c783a12d0dd4fd9c851"}, - {file = "coverage-7.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef382417db92ba23dfb5864a3fc9be27ea4894e86620d342a116b243ade5d35d"}, - {file = "coverage-7.1.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c7c0d0827e853315c9bbd43c1162c006dd808dbbe297db7ae66cd17b07830f0"}, - {file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e5cdbb5cafcedea04924568d990e20ce7f1945a1dd54b560f879ee2d57226912"}, - {file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9817733f0d3ea91bea80de0f79ef971ae94f81ca52f9b66500c6a2fea8e4b4f8"}, - {file = "coverage-7.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:218fe982371ac7387304153ecd51205f14e9d731b34fb0568181abaf7b443ba0"}, - {file = "coverage-7.1.0-cp38-cp38-win32.whl", hash = "sha256:04481245ef966fbd24ae9b9e537ce899ae584d521dfbe78f89cad003c38ca2ab"}, - {file = "coverage-7.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:8ae125d1134bf236acba8b83e74c603d1b30e207266121e76484562bc816344c"}, - {file = "coverage-7.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2bf1d5f2084c3932b56b962a683074a3692bce7cabd3aa023c987a2a8e7612f6"}, - {file = "coverage-7.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:98b85dd86514d889a2e3dd22ab3c18c9d0019e696478391d86708b805f4ea0fa"}, - {file = "coverage-7.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38da2db80cc505a611938d8624801158e409928b136c8916cd2e203970dde4dc"}, - {file = "coverage-7.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3164d31078fa9efe406e198aecd2a02d32a62fecbdef74f76dad6a46c7e48311"}, - {file = "coverage-7.1.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db61a79c07331e88b9a9974815c075fbd812bc9dbc4dc44b366b5368a2936063"}, - {file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ccb092c9ede70b2517a57382a601619d20981f56f440eae7e4d7eaafd1d1d09"}, - {file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:33ff26d0f6cc3ca8de13d14fde1ff8efe1456b53e3f0273e63cc8b3c84a063d8"}, - {file = "coverage-7.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d47dd659a4ee952e90dc56c97d78132573dc5c7b09d61b416a9deef4ebe01a0c"}, - {file = "coverage-7.1.0-cp39-cp39-win32.whl", hash = "sha256:d248cd4a92065a4d4543b8331660121b31c4148dd00a691bfb7a5cdc7483cfa4"}, - {file = "coverage-7.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:7ed681b0f8e8bcbbffa58ba26fcf5dbc8f79e7997595bf071ed5430d8c08d6f3"}, - {file = "coverage-7.1.0-pp37.pp38.pp39-none-any.whl", hash = "sha256:755e89e32376c850f826c425ece2c35a4fc266c081490eb0a841e7c1cb0d3bda"}, - {file = "coverage-7.1.0.tar.gz", hash = "sha256:10188fe543560ec4874f974b5305cd1a8bdcfa885ee00ea3a03733464c4ca265"}, -] - -[package.dependencies] -tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} - -[package.extras] -toml = ["tomli"] - -[[package]] -name = "cycler" -version = "0.11.0" -description = "Composable style cycles" -category = "main" -optional = false -python-versions = ">=3.6" -files = [ - {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, - {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, -] - -[[package]] -name = "darglint" -version = "1.8.1" -description = "A utility for ensuring Google-style docstrings stay up to date with the source code." -category = "dev" -optional = false -python-versions = ">=3.6,<4.0" -files = [ - {file = "darglint-1.8.1-py3-none-any.whl", hash = "sha256:5ae11c259c17b0701618a20c3da343a3eb98b3bc4b5a83d31cdd94f5ebdced8d"}, - {file = "darglint-1.8.1.tar.gz", hash = "sha256:080d5106df149b199822e7ee7deb9c012b49891538f14a11be681044f0bb20da"}, -] - -[[package]] -name = "distlib" -version = "0.3.6" -description = "Distribution utilities" -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"}, - {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, -] - -[[package]] -name = "docutils" -version = "0.19" -description = "Docutils -- Python Documentation Utilities" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "docutils-0.19-py3-none-any.whl", hash = "sha256:5e1de4d849fee02c63b040a4a3fd567f4ab104defd8a5511fbbc24a8a017efbc"}, - {file = "docutils-0.19.tar.gz", hash = "sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6"}, -] - -[[package]] -name = "exceptiongroup" -version = "1.1.0" -description = "Backport of PEP 654 (exception groups)" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "exceptiongroup-1.1.0-py3-none-any.whl", hash = "sha256:327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e"}, - {file = "exceptiongroup-1.1.0.tar.gz", hash = "sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23"}, -] - -[package.extras] -test = ["pytest (>=6)"] - -[[package]] -name = "filelock" -version = "3.9.0" -description = "A platform independent file lock." -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "filelock-3.9.0-py3-none-any.whl", hash = "sha256:f58d535af89bb9ad5cd4df046f741f8553a418c01a7856bf0d173bbc9f6bd16d"}, - {file = "filelock-3.9.0.tar.gz", hash = "sha256:7b319f24340b51f55a2bf7a12ac0755a9b03e718311dac567a0f4f7fabd2f5de"}, -] - -[package.extras] -docs = ["furo (>=2022.12.7)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"] -testing = ["covdefaults (>=2.2.2)", "coverage (>=7.0.1)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-timeout (>=2.1)"] - -[[package]] -name = "flake8" -version = "6.0.0" -description = "the modular source code checker: pep8 pyflakes and co" -category = "dev" -optional = false -python-versions = ">=3.8.1" -files = [ - {file = "flake8-6.0.0-py2.py3-none-any.whl", hash = "sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7"}, - {file = "flake8-6.0.0.tar.gz", hash = "sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181"}, -] - -[package.dependencies] -mccabe = ">=0.7.0,<0.8.0" -pycodestyle = ">=2.10.0,<2.11.0" -pyflakes = ">=3.0.0,<3.1.0" - -[[package]] -name = "flake8-bandit" -version = "4.1.1" -description = "Automated security testing with bandit and flake8." -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "flake8_bandit-4.1.1-py3-none-any.whl", hash = "sha256:4c8a53eb48f23d4ef1e59293657181a3c989d0077c9952717e98a0eace43e06d"}, - {file = "flake8_bandit-4.1.1.tar.gz", hash = "sha256:068e09287189cbfd7f986e92605adea2067630b75380c6b5733dab7d87f9a84e"}, -] - -[package.dependencies] -bandit = ">=1.7.3" -flake8 = ">=5.0.0" - -[[package]] -name = "flake8-bugbear" -version = "23.1.20" -description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "flake8-bugbear-23.1.20.tar.gz", hash = "sha256:55902ab5a48c5ea53d8689ecd146eda548e72f2724192b9c1d68f6d975d13c06"}, - {file = "flake8_bugbear-23.1.20-py3-none-any.whl", hash = "sha256:04a115e5f9c8e87c38bdbbcdf9f58223ffe05469c07c9a7bd8633330bc4d078b"}, -] - -[package.dependencies] -attrs = ">=19.2.0" -flake8 = ">=3.0.0" - -[package.extras] -dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit", "pytest", "tox"] - -[[package]] -name = "flake8-docstrings" -version = "1.7.0" -description = "Extension for flake8 which uses pydocstyle to check docstrings" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "flake8_docstrings-1.7.0-py2.py3-none-any.whl", hash = "sha256:51f2344026da083fc084166a9353f5082b01f72901df422f74b4d953ae88ac75"}, - {file = "flake8_docstrings-1.7.0.tar.gz", hash = "sha256:4c8cc748dc16e6869728699e5d0d685da9a10b0ea718e090b1ba088e67a941af"}, -] - -[package.dependencies] -flake8 = ">=3" -pydocstyle = ">=2.1" - -[[package]] -name = "flake8-rst-docstrings" -version = "0.3.0" -description = "Python docstring reStructuredText (RST) validator for flake8" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "flake8-rst-docstrings-0.3.0.tar.gz", hash = "sha256:d1ce22b4bd37b73cd86b8d980e946ef198cfcc18ed82fedb674ceaa2f8d1afa4"}, - {file = "flake8_rst_docstrings-0.3.0-py3-none-any.whl", hash = "sha256:f8c3c6892ff402292651c31983a38da082480ad3ba253743de52989bdc84ca1c"}, -] - -[package.dependencies] -flake8 = ">=3" -pygments = "*" -restructuredtext-lint = "*" - -[package.extras] -develop = ["build", "twine"] - -[[package]] -name = "fonttools" -version = "4.38.0" -description = "Tools to manipulate font files" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "fonttools-4.38.0-py3-none-any.whl", hash = "sha256:820466f43c8be8c3009aef8b87e785014133508f0de64ec469e4efb643ae54fb"}, - {file = "fonttools-4.38.0.zip", hash = "sha256:2bb244009f9bf3fa100fc3ead6aeb99febe5985fa20afbfbaa2f8946c2fbdaf1"}, -] - -[package.extras] -all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=14.0.0)", "xattr", "zopfli (>=0.1.4)"] -graphite = ["lz4 (>=1.7.4.2)"] -interpolatable = ["munkres", "scipy"] -lxml = ["lxml (>=4.0,<5)"] -pathops = ["skia-pathops (>=0.5.0)"] -plot = ["matplotlib"] -repacker = ["uharfbuzz (>=0.23.0)"] -symfont = ["sympy"] -type1 = ["xattr"] -ufo = ["fs (>=2.2.0,<3)"] -unicode = ["unicodedata2 (>=14.0.0)"] -woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] - -[[package]] -name = "gitdb" -version = "4.0.10" -description = "Git Object Database" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "gitdb-4.0.10-py3-none-any.whl", hash = "sha256:c286cf298426064079ed96a9e4a9d39e7f3e9bf15ba60701e95f5492f28415c7"}, - {file = "gitdb-4.0.10.tar.gz", hash = "sha256:6eb990b69df4e15bad899ea868dc46572c3f75339735663b81de79b06f17eb9a"}, -] - -[package.dependencies] -smmap = ">=3.0.1,<6" - -[[package]] -name = "gitpython" -version = "3.1.30" -description = "GitPython is a python library used to interact with Git repositories" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "GitPython-3.1.30-py3-none-any.whl", hash = "sha256:cd455b0000615c60e286208ba540271af9fe531fa6a87cc590a7298785ab2882"}, - {file = "GitPython-3.1.30.tar.gz", hash = "sha256:769c2d83e13f5d938b7688479da374c4e3d49f71549aaf462b646db9602ea6f8"}, -] - -[package.dependencies] -gitdb = ">=4.0.1,<5" - -[[package]] -name = "identify" -version = "2.5.17" -description = "File identification library for Python" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "identify-2.5.17-py2.py3-none-any.whl", hash = "sha256:7d526dd1283555aafcc91539acc061d8f6f59adb0a7bba462735b0a318bff7ed"}, - {file = "identify-2.5.17.tar.gz", hash = "sha256:93cc61a861052de9d4c541a7acb7e3dcc9c11b398a2144f6e52ae5285f5f4f06"}, -] - -[package.extras] -license = ["ukkonen"] - -[[package]] -name = "iniconfig" -version = "2.0.0" -description = "brain-dead simple config-ini parsing" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, -] - -[[package]] -name = "joblib" -version = "1.2.0" -description = "Lightweight pipelining with Python functions" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "joblib-1.2.0-py3-none-any.whl", hash = "sha256:091138ed78f800342968c523bdde947e7a305b8594b910a0fea2ab83c3c6d385"}, - {file = "joblib-1.2.0.tar.gz", hash = "sha256:e1cee4a79e4af22881164f218d4311f60074197fb707e082e803b61f6d137018"}, -] - -[[package]] -name = "kiwisolver" -version = "1.4.4" -description = "A fast implementation of the Cassowary constraint solver" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2f5e60fabb7343a836360c4f0919b8cd0d6dbf08ad2ca6b9cf90bf0c76a3c4f6"}, - {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:10ee06759482c78bdb864f4109886dff7b8a56529bc1609d4f1112b93fe6423c"}, - {file = "kiwisolver-1.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c79ebe8f3676a4c6630fd3f777f3cfecf9289666c84e775a67d1d358578dc2e3"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abbe9fa13da955feb8202e215c4018f4bb57469b1b78c7a4c5c7b93001699938"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7577c1987baa3adc4b3c62c33bd1118c3ef5c8ddef36f0f2c950ae0b199e100d"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8ad8285b01b0d4695102546b342b493b3ccc6781fc28c8c6a1bb63e95d22f09"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed58b8acf29798b036d347791141767ccf65eee7f26bde03a71c944449e53de"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a68b62a02953b9841730db7797422f983935aeefceb1679f0fc85cbfbd311c32"}, - {file = "kiwisolver-1.4.4-cp310-cp310-win32.whl", hash = "sha256:e92a513161077b53447160b9bd8f522edfbed4bd9759e4c18ab05d7ef7e49408"}, - {file = "kiwisolver-1.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:3fe20f63c9ecee44560d0e7f116b3a747a5d7203376abeea292ab3152334d004"}, - {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ea21f66820452a3f5d1655f8704a60d66ba1191359b96541eaf457710a5fc6"}, - {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bc9db8a3efb3e403e4ecc6cd9489ea2bac94244f80c78e27c31dcc00d2790ac2"}, - {file = "kiwisolver-1.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d5b61785a9ce44e5a4b880272baa7cf6c8f48a5180c3e81c59553ba0cb0821ca"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c2dbb44c3f7e6c4d3487b31037b1bdbf424d97687c1747ce4ff2895795c9bf69"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6295ecd49304dcf3bfbfa45d9a081c96509e95f4b9d0eb7ee4ec0530c4a96514"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bd472dbe5e136f96a4b18f295d159d7f26fd399136f5b17b08c4e5f498cd494"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf7d9fce9bcc4752ca4a1b80aabd38f6d19009ea5cbda0e0856983cf6d0023f5"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d6601aed50c74e0ef02f4204da1816147a6d3fbdc8b3872d263338a9052c51"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:877272cf6b4b7e94c9614f9b10140e198d2186363728ed0f701c6eee1baec1da"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:db608a6757adabb32f1cfe6066e39b3706d8c3aa69bbc353a5b61edad36a5cb4"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5853eb494c71e267912275e5586fe281444eb5e722de4e131cddf9d442615626"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f0a1dbdb5ecbef0d34eb77e56fcb3e95bbd7e50835d9782a45df81cc46949750"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:283dffbf061a4ec60391d51e6155e372a1f7a4f5b15d59c8505339454f8989e4"}, - {file = "kiwisolver-1.4.4-cp311-cp311-win32.whl", hash = "sha256:d06adcfa62a4431d404c31216f0f8ac97397d799cd53800e9d3efc2fbb3cf14e"}, - {file = "kiwisolver-1.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e7da3fec7408813a7cebc9e4ec55afed2d0fd65c4754bc376bf03498d4e92686"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:62ac9cc684da4cf1778d07a89bf5f81b35834cb96ca523d3a7fb32509380cbf6"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41dae968a94b1ef1897cb322b39360a0812661dba7c682aa45098eb8e193dbdf"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02f79693ec433cb4b5f51694e8477ae83b3205768a6fb48ffba60549080e295b"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0611a0a2a518464c05ddd5a3a1a0e856ccc10e67079bb17f265ad19ab3c7597"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:db5283d90da4174865d520e7366801a93777201e91e79bacbac6e6927cbceede"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1041feb4cda8708ce73bb4dcb9ce1ccf49d553bf87c3954bdfa46f0c3f77252c"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-win32.whl", hash = "sha256:a553dadda40fef6bfa1456dc4be49b113aa92c2a9a9e8711e955618cd69622e3"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:03baab2d6b4a54ddbb43bba1a3a2d1627e82d205c5cf8f4c924dc49284b87166"}, - {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:841293b17ad704d70c578f1f0013c890e219952169ce8a24ebc063eecf775454"}, - {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f4f270de01dd3e129a72efad823da90cc4d6aafb64c410c9033aba70db9f1ff0"}, - {file = "kiwisolver-1.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f9f39e2f049db33a908319cf46624a569b36983c7c78318e9726a4cb8923b26c"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97528e64cb9ebeff9701e7938653a9951922f2a38bd847787d4a8e498cc83ae"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d1573129aa0fd901076e2bfb4275a35f5b7aa60fbfb984499d661ec950320b0"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad881edc7ccb9d65b0224f4e4d05a1e85cf62d73aab798943df6d48ab0cd79a1"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b428ef021242344340460fa4c9185d0b1f66fbdbfecc6c63eff4b7c29fad429d"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2e407cb4bd5a13984a6c2c0fe1845e4e41e96f183e5e5cd4d77a857d9693494c"}, - {file = "kiwisolver-1.4.4-cp38-cp38-win32.whl", hash = "sha256:75facbe9606748f43428fc91a43edb46c7ff68889b91fa31f53b58894503a191"}, - {file = "kiwisolver-1.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:5bce61af018b0cb2055e0e72e7d65290d822d3feee430b7b8203d8a855e78766"}, - {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8c808594c88a025d4e322d5bb549282c93c8e1ba71b790f539567932722d7bd8"}, - {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0a71d85ecdd570ded8ac3d1c0f480842f49a40beb423bb8014539a9f32a5897"}, - {file = "kiwisolver-1.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b533558eae785e33e8c148a8d9921692a9fe5aa516efbdff8606e7d87b9d5824"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:efda5fc8cc1c61e4f639b8067d118e742b812c930f708e6667a5ce0d13499e29"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7c43e1e1206cd421cd92e6b3280d4385d41d7166b3ed577ac20444b6995a445f"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc8d3bd6c72b2dd9decf16ce70e20abcb3274ba01b4e1c96031e0c4067d1e7cd"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ea39b0ccc4f5d803e3337dd46bcce60b702be4d86fd0b3d7531ef10fd99a1ac"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:968f44fdbf6dd757d12920d63b566eeb4d5b395fd2d00d29d7ef00a00582aac9"}, - {file = "kiwisolver-1.4.4-cp39-cp39-win32.whl", hash = "sha256:da7e547706e69e45d95e116e6939488d62174e033b763ab1496b4c29b76fabea"}, - {file = "kiwisolver-1.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:ba59c92039ec0a66103b1d5fe588fa546373587a7d68f5c96f743c3396afc04b"}, - {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:91672bacaa030f92fc2f43b620d7b337fd9a5af28b0d6ed3f77afc43c4a64b5a"}, - {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:787518a6789009c159453da4d6b683f468ef7a65bbde796bcea803ccf191058d"}, - {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da152d8cdcab0e56e4f45eb08b9aea6455845ec83172092f09b0e077ece2cf7a"}, - {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ecb1fa0db7bf4cff9dac752abb19505a233c7f16684c5826d1f11ebd9472b871"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:28bc5b299f48150b5f822ce68624e445040595a4ac3d59251703779836eceff9"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:81e38381b782cc7e1e46c4e14cd997ee6040768101aefc8fa3c24a4cc58e98f8"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2a66fdfb34e05b705620dd567f5a03f239a088d5a3f321e7b6ac3239d22aa286"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:872b8ca05c40d309ed13eb2e582cab0c5a05e81e987ab9c521bf05ad1d5cf5cb"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:70e7c2e7b750585569564e2e5ca9845acfaa5da56ac46df68414f29fea97be9f"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9f85003f5dfa867e86d53fac6f7e6f30c045673fa27b603c397753bebadc3008"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e307eb9bd99801f82789b44bb45e9f541961831c7311521b13a6c85afc09767"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1792d939ec70abe76f5054d3f36ed5656021dcad1322d1cc996d4e54165cef9"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cb459eea32a4e2cf18ba5fcece2dbdf496384413bc1bae15583f19e567f3b2"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36dafec3d6d6088d34e2de6b85f9d8e2324eb734162fba59d2ba9ed7a2043d5b"}, - {file = "kiwisolver-1.4.4.tar.gz", hash = "sha256:d41997519fcba4a1e46eb4a2fe31bc12f0ff957b2b81bac28db24744f333e955"}, -] - -[[package]] -name = "loguru" -version = "0.6.0" -description = "Python logging made (stupidly) simple" -category = "main" -optional = false -python-versions = ">=3.5" -files = [ - {file = "loguru-0.6.0-py3-none-any.whl", hash = "sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3"}, - {file = "loguru-0.6.0.tar.gz", hash = "sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c"}, -] - -[package.dependencies] -colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} -win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} - -[package.extras] -dev = ["Sphinx (>=4.1.1)", "black (>=19.10b0)", "colorama (>=0.3.4)", "docutils (==0.16)", "flake8 (>=3.7.7)", "isort (>=5.1.1)", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "sphinx-autobuild (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "tox (>=3.9.0)"] - -[[package]] -name = "matplotlib" -version = "3.6.3" -description = "Python plotting package" -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "matplotlib-3.6.3-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:80c166a0e28512e26755f69040e6bf2f946a02ffdb7c00bf6158cca3d2b146e6"}, - {file = "matplotlib-3.6.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:eb9421c403ffd387fbe729de6d9a03005bf42faba5e8432f4e51e703215b49fc"}, - {file = "matplotlib-3.6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5223affa21050fb6118353c1380c15e23aedfb436bf3e162c26dc950617a7519"}, - {file = "matplotlib-3.6.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d00c248ab6b92bea3f8148714837937053a083ff03b4c5e30ed37e28fc0e7e56"}, - {file = "matplotlib-3.6.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca94f0362f6b6f424b555b956971dcb94b12d0368a6c3e07dc7a40d32d6d873d"}, - {file = "matplotlib-3.6.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59400cc9451094b7f08cc3f321972e6e1db4cd37a978d4e8a12824bf7fd2f03b"}, - {file = "matplotlib-3.6.3-cp310-cp310-win32.whl", hash = "sha256:57ad1aee29043163374bfa8990e1a2a10ff72c9a1bfaa92e9c46f6ea59269121"}, - {file = "matplotlib-3.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:1fcc4cad498533d3c393a160975acc9b36ffa224d15a6b90ae579eacee5d8579"}, - {file = "matplotlib-3.6.3-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:d2cfaa7fd62294d945b8843ea24228a27c8e7c5b48fa634f3c168153b825a21b"}, - {file = "matplotlib-3.6.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:c3f08df2ac4636249b8bc7a85b8b82c983bef1441595936f62c2918370ca7e1d"}, - {file = "matplotlib-3.6.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff2aa84e74f80891e6bcf292ebb1dd57714ffbe13177642d65fee25384a30894"}, - {file = "matplotlib-3.6.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:11011c97d62c1db7bc20509572557842dbb8c2a2ddd3dd7f20501aa1cde3e54e"}, - {file = "matplotlib-3.6.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c235bf9be052347373f589e018988cad177abb3f997ab1a2e2210c41562cc0c"}, - {file = "matplotlib-3.6.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bebcff4c3ed02c6399d47329f3554193abd824d3d53b5ca02cf583bcd94470e2"}, - {file = "matplotlib-3.6.3-cp311-cp311-win32.whl", hash = "sha256:d5f18430f5cfa5571ab8f4c72c89af52aa0618e864c60028f11a857d62200cba"}, - {file = "matplotlib-3.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:dfba7057609ca9567b9704626756f0142e97ec8c5ba2c70c6e7bd1c25ef99f06"}, - {file = "matplotlib-3.6.3-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:9fb8fb19d03abf3c5dab89a8677e62c4023632f919a62b6dd1d6d2dbf42cd9f5"}, - {file = "matplotlib-3.6.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:bbf269e1d24bc25247095d71c7a969813f7080e2a7c6fa28931a603f747ab012"}, - {file = "matplotlib-3.6.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:994637e2995b0342699b396a320698b07cd148bbcf2dd2fa2daba73f34dd19f2"}, - {file = "matplotlib-3.6.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:77b384cee7ab8cf75ffccbfea351a09b97564fc62d149827a5e864bec81526e5"}, - {file = "matplotlib-3.6.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:73b93af33634ed919e72811c9703e1105185cd3fb46d76f30b7f4cfbbd063f89"}, - {file = "matplotlib-3.6.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:debeab8e2ab07e5e3dac33e12456da79c7e104270d2b2d1df92b9e40347cca75"}, - {file = "matplotlib-3.6.3-cp38-cp38-win32.whl", hash = "sha256:acc3b1a4bddbf56fe461e36fb9ef94c2cb607fc90d24ccc650040bfcc7610de4"}, - {file = "matplotlib-3.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:1183877d008c752d7d535396096c910f4663e4b74a18313adee1213328388e1e"}, - {file = "matplotlib-3.6.3-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:6adc441b5b2098a4b904bbf9d9e92fb816fef50c55aa2ea6a823fc89b94bb838"}, - {file = "matplotlib-3.6.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:6d81b11ede69e3a751424b98dc869c96c10256b2206bfdf41f9c720eee86844c"}, - {file = "matplotlib-3.6.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:29f17b7f2e068dc346687cbdf80b430580bab42346625821c2d3abf3a1ec5417"}, - {file = "matplotlib-3.6.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f56a7252eee8f3438447f75f5e1148a1896a2756a92285fe5d73bed6deebff4"}, - {file = "matplotlib-3.6.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bbddfeb1495484351fb5b30cf5bdf06b3de0bc4626a707d29e43dfd61af2a780"}, - {file = "matplotlib-3.6.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:809119d1cba3ece3c9742eb01827fe7a0e781ea3c5d89534655a75e07979344f"}, - {file = "matplotlib-3.6.3-cp39-cp39-win32.whl", hash = "sha256:e0a64d7cc336b52e90f59e6d638ae847b966f68582a7af041e063d568e814740"}, - {file = "matplotlib-3.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:79e501eb847f4a489eb7065bb8d3187117f65a4c02d12ea3a19d6c5bef173bcc"}, - {file = "matplotlib-3.6.3-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2787a16df07370dcba385fe20cdd0cc3cfaabd3c873ddabca78c10514c799721"}, - {file = "matplotlib-3.6.3-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68d94a436f62b8a861bf3ace82067a71bafb724b4e4f9133521e4d8012420dd7"}, - {file = "matplotlib-3.6.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81b409b2790cf8d7c1ef35920f01676d2ae7afa8241844e7aa5484fdf493a9a0"}, - {file = "matplotlib-3.6.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:faff486b36530a836a6b4395850322e74211cd81fc17f28b4904e1bd53668e3e"}, - {file = "matplotlib-3.6.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:38d38cb1ea1d80ee0f6351b65c6f76cad6060bbbead015720ba001348ae90f0c"}, - {file = "matplotlib-3.6.3-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12f999661589981e74d793ee2f41b924b3b87d65fd929f6153bf0f30675c59b1"}, - {file = "matplotlib-3.6.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01b7f521a9a73c383825813af255f8c4485d1706e4f3e2ed5ae771e4403a40ab"}, - {file = "matplotlib-3.6.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:9ceebaf73f1a3444fa11014f38b9da37ff7ea328d6efa1652241fe3777bfdab9"}, - {file = "matplotlib-3.6.3.tar.gz", hash = "sha256:1f4d69707b1677560cd952544ee4962f68ff07952fb9069ff8c12b56353cb8c9"}, -] - -[package.dependencies] -contourpy = ">=1.0.1" -cycler = ">=0.10" -fonttools = ">=4.22.0" -kiwisolver = ">=1.0.1" -numpy = ">=1.19" -packaging = ">=20.0" -pillow = ">=6.2.0" -pyparsing = ">=2.2.1" -python-dateutil = ">=2.7" - -[[package]] -name = "mccabe" -version = "0.7.0" -description = "McCabe checker, plugin for flake8" -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, - {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, -] - -[[package]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." -category = "dev" -optional = false -python-versions = ">=3.5" -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, -] - -[[package]] -name = "nodeenv" -version = "1.7.0" -description = "Node.js virtual environment builder" -category = "dev" -optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" -files = [ - {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, - {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"}, -] - -[package.dependencies] -setuptools = "*" - -[[package]] -name = "numpy" -version = "1.24.2" -description = "Fundamental package for array computing in Python" -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "numpy-1.24.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eef70b4fc1e872ebddc38cddacc87c19a3709c0e3e5d20bf3954c147b1dd941d"}, - {file = "numpy-1.24.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8d2859428712785e8a8b7d2b3ef0a1d1565892367b32f915c4a4df44d0e64f5"}, - {file = "numpy-1.24.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6524630f71631be2dabe0c541e7675db82651eb998496bbe16bc4f77f0772253"}, - {file = "numpy-1.24.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a51725a815a6188c662fb66fb32077709a9ca38053f0274640293a14fdd22978"}, - {file = "numpy-1.24.2-cp310-cp310-win32.whl", hash = "sha256:2620e8592136e073bd12ee4536149380695fbe9ebeae845b81237f986479ffc9"}, - {file = "numpy-1.24.2-cp310-cp310-win_amd64.whl", hash = "sha256:97cf27e51fa078078c649a51d7ade3c92d9e709ba2bfb97493007103c741f1d0"}, - {file = "numpy-1.24.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7de8fdde0003f4294655aa5d5f0a89c26b9f22c0a58790c38fae1ed392d44a5a"}, - {file = "numpy-1.24.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4173bde9fa2a005c2c6e2ea8ac1618e2ed2c1c6ec8a7657237854d42094123a0"}, - {file = "numpy-1.24.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cecaed30dc14123020f77b03601559fff3e6cd0c048f8b5289f4eeabb0eb281"}, - {file = "numpy-1.24.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a23f8440561a633204a67fb44617ce2a299beecf3295f0d13c495518908e910"}, - {file = "numpy-1.24.2-cp311-cp311-win32.whl", hash = "sha256:e428c4fbfa085f947b536706a2fc349245d7baa8334f0c5723c56a10595f9b95"}, - {file = "numpy-1.24.2-cp311-cp311-win_amd64.whl", hash = "sha256:557d42778a6869c2162deb40ad82612645e21d79e11c1dc62c6e82a2220ffb04"}, - {file = "numpy-1.24.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d0a2db9d20117bf523dde15858398e7c0858aadca7c0f088ac0d6edd360e9ad2"}, - {file = "numpy-1.24.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c72a6b2f4af1adfe193f7beb91ddf708ff867a3f977ef2ec53c0ffb8283ab9f5"}, - {file = "numpy-1.24.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c29e6bd0ec49a44d7690ecb623a8eac5ab8a923bce0bea6293953992edf3a76a"}, - {file = "numpy-1.24.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eabd64ddb96a1239791da78fa5f4e1693ae2dadc82a76bc76a14cbb2b966e96"}, - {file = "numpy-1.24.2-cp38-cp38-win32.whl", hash = "sha256:e3ab5d32784e843fc0dd3ab6dcafc67ef806e6b6828dc6af2f689be0eb4d781d"}, - {file = "numpy-1.24.2-cp38-cp38-win_amd64.whl", hash = "sha256:76807b4063f0002c8532cfeac47a3068a69561e9c8715efdad3c642eb27c0756"}, - {file = "numpy-1.24.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4199e7cfc307a778f72d293372736223e39ec9ac096ff0a2e64853b866a8e18a"}, - {file = "numpy-1.24.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:adbdce121896fd3a17a77ab0b0b5eedf05a9834a18699db6829a64e1dfccca7f"}, - {file = "numpy-1.24.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:889b2cc88b837d86eda1b17008ebeb679d82875022200c6e8e4ce6cf549b7acb"}, - {file = "numpy-1.24.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f64bb98ac59b3ea3bf74b02f13836eb2e24e48e0ab0145bbda646295769bd780"}, - {file = "numpy-1.24.2-cp39-cp39-win32.whl", hash = "sha256:63e45511ee4d9d976637d11e6c9864eae50e12dc9598f531c035265991910468"}, - {file = "numpy-1.24.2-cp39-cp39-win_amd64.whl", hash = "sha256:a77d3e1163a7770164404607b7ba3967fb49b24782a6ef85d9b5f54126cc39e5"}, - {file = "numpy-1.24.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:92011118955724465fb6853def593cf397b4a1367495e0b59a7e69d40c4eb71d"}, - {file = "numpy-1.24.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9006288bcf4895917d02583cf3411f98631275bc67cce355a7f39f8c14338fa"}, - {file = "numpy-1.24.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:150947adbdfeceec4e5926d956a06865c1c690f2fd902efede4ca6fe2e657c3f"}, - {file = "numpy-1.24.2.tar.gz", hash = "sha256:003a9f530e880cb2cd177cba1af7220b9aa42def9c4afc2a2fc3ee6be7eb2b22"}, -] - -[[package]] -name = "packaging" -version = "23.0" -description = "Core utilities for Python packages" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, - {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, -] - -[[package]] -name = "pandas" -version = "1.5.3" -description = "Powerful data structures for data analysis, time series, and statistics" -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3749077d86e3a2f0ed51367f30bf5b82e131cc0f14260c4d3e499186fccc4406"}, - {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:972d8a45395f2a2d26733eb8d0f629b2f90bebe8e8eddbb8829b180c09639572"}, - {file = "pandas-1.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:50869a35cbb0f2e0cd5ec04b191e7b12ed688874bd05dd777c19b28cbea90996"}, - {file = "pandas-1.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3ac844a0fe00bfaeb2c9b51ab1424e5c8744f89860b138434a363b1f620f354"}, - {file = "pandas-1.5.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a0a56cef15fd1586726dace5616db75ebcfec9179a3a55e78f72c5639fa2a23"}, - {file = "pandas-1.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:478ff646ca42b20376e4ed3fa2e8d7341e8a63105586efe54fa2508ee087f328"}, - {file = "pandas-1.5.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6973549c01ca91ec96199e940495219c887ea815b2083722821f1d7abfa2b4dc"}, - {file = "pandas-1.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c39a8da13cede5adcd3be1182883aea1c925476f4e84b2807a46e2775306305d"}, - {file = "pandas-1.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f76d097d12c82a535fda9dfe5e8dd4127952b45fea9b0276cb30cca5ea313fbc"}, - {file = "pandas-1.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e474390e60ed609cec869b0da796ad94f420bb057d86784191eefc62b65819ae"}, - {file = "pandas-1.5.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f2b952406a1588ad4cad5b3f55f520e82e902388a6d5a4a91baa8d38d23c7f6"}, - {file = "pandas-1.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:bc4c368f42b551bf72fac35c5128963a171b40dce866fb066540eeaf46faa003"}, - {file = "pandas-1.5.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:14e45300521902689a81f3f41386dc86f19b8ba8dd5ac5a3c7010ef8d2932813"}, - {file = "pandas-1.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9842b6f4b8479e41968eced654487258ed81df7d1c9b7b870ceea24ed9459b31"}, - {file = "pandas-1.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:26d9c71772c7afb9d5046e6e9cf42d83dd147b5cf5bcb9d97252077118543792"}, - {file = "pandas-1.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fbcb19d6fceb9e946b3e23258757c7b225ba450990d9ed63ccceeb8cae609f7"}, - {file = "pandas-1.5.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:565fa34a5434d38e9d250af3c12ff931abaf88050551d9fbcdfafca50d62babf"}, - {file = "pandas-1.5.3-cp38-cp38-win32.whl", hash = "sha256:87bd9c03da1ac870a6d2c8902a0e1fd4267ca00f13bc494c9e5a9020920e1d51"}, - {file = "pandas-1.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:41179ce559943d83a9b4bbacb736b04c928b095b5f25dd2b7389eda08f46f373"}, - {file = "pandas-1.5.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c74a62747864ed568f5a82a49a23a8d7fe171d0c69038b38cedf0976831296fa"}, - {file = "pandas-1.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c4c00e0b0597c8e4f59e8d461f797e5d70b4d025880516a8261b2817c47759ee"}, - {file = "pandas-1.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a50d9a4336a9621cab7b8eb3fb11adb82de58f9b91d84c2cd526576b881a0c5a"}, - {file = "pandas-1.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd05f7783b3274aa206a1af06f0ceed3f9b412cf665b7247eacd83be41cf7bf0"}, - {file = "pandas-1.5.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f69c4029613de47816b1bb30ff5ac778686688751a5e9c99ad8c7031f6508e5"}, - {file = "pandas-1.5.3-cp39-cp39-win32.whl", hash = "sha256:7cec0bee9f294e5de5bbfc14d0573f65526071029d036b753ee6507d2a21480a"}, - {file = "pandas-1.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:dfd681c5dc216037e0b0a2c821f5ed99ba9f03ebcf119c7dac0e9a7b960b9ec9"}, - {file = "pandas-1.5.3.tar.gz", hash = "sha256:74a3fd7e5a7ec052f183273dc7b0acd3a863edf7520f5d3a1765c04ffdb3b0b1"}, -] - -[package.dependencies] -numpy = [ - {version = ">=1.20.3", markers = "python_version < \"3.10\""}, - {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, - {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, -] -python-dateutil = ">=2.8.1" -pytz = ">=2020.1" - -[package.extras] -test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] - -[[package]] -name = "pathspec" -version = "0.11.0" -description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pathspec-0.11.0-py3-none-any.whl", hash = "sha256:3a66eb970cbac598f9e5ccb5b2cf58930cd8e3ed86d393d541eaf2d8b1705229"}, - {file = "pathspec-0.11.0.tar.gz", hash = "sha256:64d338d4e0914e91c1792321e6907b5a593f1ab1851de7fc269557a21b30ebbc"}, -] - -[[package]] -name = "pbr" -version = "5.11.1" -description = "Python Build Reasonableness" -category = "dev" -optional = false -python-versions = ">=2.6" -files = [ - {file = "pbr-5.11.1-py2.py3-none-any.whl", hash = "sha256:567f09558bae2b3ab53cb3c1e2e33e726ff3338e7bae3db5dc954b3a44eef12b"}, - {file = "pbr-5.11.1.tar.gz", hash = "sha256:aefc51675b0b533d56bb5fd1c8c6c0522fe31896679882e1c4c63d5e4a0fccb3"}, -] - -[[package]] -name = "pep8-naming" -version = "0.13.3" -description = "Check PEP-8 naming conventions, plugin for flake8" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pep8-naming-0.13.3.tar.gz", hash = "sha256:1705f046dfcd851378aac3be1cd1551c7c1e5ff363bacad707d43007877fa971"}, - {file = "pep8_naming-0.13.3-py3-none-any.whl", hash = "sha256:1a86b8c71a03337c97181917e2b472f0f5e4ccb06844a0d6f0a33522549e7a80"}, -] - -[package.dependencies] -flake8 = ">=5.0.0" - -[[package]] -name = "pillow" -version = "9.4.0" -description = "Python Imaging Library (Fork)" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "Pillow-9.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:2968c58feca624bb6c8502f9564dd187d0e1389964898f5e9e1fbc8533169157"}, - {file = "Pillow-9.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c5c1362c14aee73f50143d74389b2c158707b4abce2cb055b7ad37ce60738d47"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd752c5ff1b4a870b7661234694f24b1d2b9076b8bf337321a814c612665f343"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a3049a10261d7f2b6514d35bbb7a4dfc3ece4c4de14ef5876c4b7a23a0e566d"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16a8df99701f9095bea8a6c4b3197da105df6f74e6176c5b410bc2df2fd29a57"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:94cdff45173b1919350601f82d61365e792895e3c3a3443cf99819e6fbf717a5"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ed3e4b4e1e6de75fdc16d3259098de7c6571b1a6cc863b1a49e7d3d53e036070"}, - {file = "Pillow-9.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5b2f8a31bd43e0f18172d8ac82347c8f37ef3e0b414431157718aa234991b28"}, - {file = "Pillow-9.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:09b89ddc95c248ee788328528e6a2996e09eaccddeeb82a5356e92645733be35"}, - {file = "Pillow-9.4.0-cp310-cp310-win32.whl", hash = "sha256:f09598b416ba39a8f489c124447b007fe865f786a89dbfa48bb5cf395693132a"}, - {file = "Pillow-9.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:f6e78171be3fb7941f9910ea15b4b14ec27725865a73c15277bc39f5ca4f8391"}, - {file = "Pillow-9.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:3fa1284762aacca6dc97474ee9c16f83990b8eeb6697f2ba17140d54b453e133"}, - {file = "Pillow-9.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:eaef5d2de3c7e9b21f1e762f289d17b726c2239a42b11e25446abf82b26ac132"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4dfdae195335abb4e89cc9762b2edc524f3c6e80d647a9a81bf81e17e3fb6f0"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6abfb51a82e919e3933eb137e17c4ae9c0475a25508ea88993bb59faf82f3b35"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:451f10ef963918e65b8869e17d67db5e2f4ab40e716ee6ce7129b0cde2876eab"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:6663977496d616b618b6cfa43ec86e479ee62b942e1da76a2c3daa1c75933ef4"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:60e7da3a3ad1812c128750fc1bc14a7ceeb8d29f77e0a2356a8fb2aa8925287d"}, - {file = "Pillow-9.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:19005a8e58b7c1796bc0167862b1f54a64d3b44ee5d48152b06bb861458bc0f8"}, - {file = "Pillow-9.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f715c32e774a60a337b2bb8ad9839b4abf75b267a0f18806f6f4f5f1688c4b5a"}, - {file = "Pillow-9.4.0-cp311-cp311-win32.whl", hash = "sha256:b222090c455d6d1a64e6b7bb5f4035c4dff479e22455c9eaa1bdd4c75b52c80c"}, - {file = "Pillow-9.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:ba6612b6548220ff5e9df85261bddc811a057b0b465a1226b39bfb8550616aee"}, - {file = "Pillow-9.4.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:5f532a2ad4d174eb73494e7397988e22bf427f91acc8e6ebf5bb10597b49c493"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dd5a9c3091a0f414a963d427f920368e2b6a4c2f7527fdd82cde8ef0bc7a327"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef21af928e807f10bf4141cad4746eee692a0dd3ff56cfb25fce076ec3cc8abe"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:847b114580c5cc9ebaf216dd8c8dbc6b00a3b7ab0131e173d7120e6deade1f57"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:653d7fb2df65efefbcbf81ef5fe5e5be931f1ee4332c2893ca638c9b11a409c4"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:46f39cab8bbf4a384ba7cb0bc8bae7b7062b6a11cfac1ca4bc144dea90d4a9f5"}, - {file = "Pillow-9.4.0-cp37-cp37m-win32.whl", hash = "sha256:7ac7594397698f77bce84382929747130765f66406dc2cd8b4ab4da68ade4c6e"}, - {file = "Pillow-9.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:46c259e87199041583658457372a183636ae8cd56dbf3f0755e0f376a7f9d0e6"}, - {file = "Pillow-9.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:0e51f608da093e5d9038c592b5b575cadc12fd748af1479b5e858045fff955a9"}, - {file = "Pillow-9.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:765cb54c0b8724a7c12c55146ae4647e0274a839fb6de7bcba841e04298e1011"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:519e14e2c49fcf7616d6d2cfc5c70adae95682ae20f0395e9280db85e8d6c4df"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d197df5489004db87d90b918033edbeee0bd6df3848a204bca3ff0a903bef837"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0845adc64fe9886db00f5ab68c4a8cd933ab749a87747555cec1c95acea64b0b"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:e1339790c083c5a4de48f688b4841f18df839eb3c9584a770cbd818b33e26d5d"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:a96e6e23f2b79433390273eaf8cc94fec9c6370842e577ab10dabdcc7ea0a66b"}, - {file = "Pillow-9.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7cfc287da09f9d2a7ec146ee4d72d6ea1342e770d975e49a8621bf54eaa8f30f"}, - {file = "Pillow-9.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d7081c084ceb58278dd3cf81f836bc818978c0ccc770cbbb202125ddabec6628"}, - {file = "Pillow-9.4.0-cp38-cp38-win32.whl", hash = "sha256:df41112ccce5d47770a0c13651479fbcd8793f34232a2dd9faeccb75eb5d0d0d"}, - {file = "Pillow-9.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:7a21222644ab69ddd9967cfe6f2bb420b460dae4289c9d40ff9a4896e7c35c9a"}, - {file = "Pillow-9.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0f3269304c1a7ce82f1759c12ce731ef9b6e95b6df829dccd9fe42912cc48569"}, - {file = "Pillow-9.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cb362e3b0976dc994857391b776ddaa8c13c28a16f80ac6522c23d5257156bed"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2e0f87144fcbbe54297cae708c5e7f9da21a4646523456b00cc956bd4c65815"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:28676836c7796805914b76b1837a40f76827ee0d5398f72f7dcc634bae7c6264"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0884ba7b515163a1a05440a138adeb722b8a6ae2c2b33aea93ea3118dd3a899e"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:53dcb50fbdc3fb2c55431a9b30caeb2f7027fcd2aeb501459464f0214200a503"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:e8c5cf126889a4de385c02a2c3d3aba4b00f70234bfddae82a5eaa3ee6d5e3e6"}, - {file = "Pillow-9.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6c6b1389ed66cdd174d040105123a5a1bc91d0aa7059c7261d20e583b6d8cbd2"}, - {file = "Pillow-9.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0dd4c681b82214b36273c18ca7ee87065a50e013112eea7d78c7a1b89a739153"}, - {file = "Pillow-9.4.0-cp39-cp39-win32.whl", hash = "sha256:6d9dfb9959a3b0039ee06c1a1a90dc23bac3b430842dcb97908ddde05870601c"}, - {file = "Pillow-9.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:54614444887e0d3043557d9dbc697dbb16cfb5a35d672b7a0fcc1ed0cf1c600b"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b9b752ab91e78234941e44abdecc07f1f0d8f51fb62941d32995b8161f68cfe5"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3b56206244dc8711f7e8b7d6cad4663917cd5b2d950799425076681e8766286"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aabdab8ec1e7ca7f1434d042bf8b1e92056245fb179790dc97ed040361f16bfd"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:db74f5562c09953b2c5f8ec4b7dfd3f5421f31811e97d1dbc0a7c93d6e3a24df"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e9d7747847c53a16a729b6ee5e737cf170f7a16611c143d95aa60a109a59c336"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b52ff4f4e002f828ea6483faf4c4e8deea8d743cf801b74910243c58acc6eda3"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:575d8912dca808edd9acd6f7795199332696d3469665ef26163cd090fa1f8bfa"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3c4ed2ff6760e98d262e0cc9c9a7f7b8a9f61aa4d47c58835cdaf7b0b8811bb"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e621b0246192d3b9cb1dc62c78cfa4c6f6d2ddc0ec207d43c0dedecb914f152a"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8f127e7b028900421cad64f51f75c051b628db17fb00e099eb148761eed598c9"}, - {file = "Pillow-9.4.0.tar.gz", hash = "sha256:a1c2d7780448eb93fbcc3789bf3916aa5720d942e37945f4056680317f1cd23e"}, -] - -[package.extras] -docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinxext-opengraph"] -tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] - -[[package]] -name = "platformdirs" -version = "3.0.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "platformdirs-3.0.0-py3-none-any.whl", hash = "sha256:b1d5eb14f221506f50d6604a561f4c5786d9e80355219694a1b244bcd96f4567"}, - {file = "platformdirs-3.0.0.tar.gz", hash = "sha256:8a1228abb1ef82d788f74139988b137e78692984ec7b08eaa6c65f1723af28f9"}, -] - -[package.extras] -docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] - -[[package]] -name = "pluggy" -version = "1.0.0" -description = "plugin and hook calling mechanisms for python" -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, - {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, -] - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] - -[[package]] -name = "pre-commit" -version = "3.0.4" -description = "A framework for managing and maintaining multi-language pre-commit hooks." -category = "dev" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pre_commit-3.0.4-py2.py3-none-any.whl", hash = "sha256:9e3255edb0c9e7fe9b4f328cb3dc86069f8fdc38026f1bf521018a05eaf4d67b"}, - {file = "pre_commit-3.0.4.tar.gz", hash = "sha256:bc4687478d55578c4ac37272fe96df66f73d9b5cf81be6f28627d4e712e752d5"}, -] - -[package.dependencies] -cfgv = ">=2.0.0" -identify = ">=1.0.0" -nodeenv = ">=0.11.1" -pyyaml = ">=5.1" -virtualenv = ">=20.10.0" - -[[package]] -name = "pre-commit-hooks" -version = "4.4.0" -description = "Some out-of-the-box hooks for pre-commit." -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pre_commit_hooks-4.4.0-py2.py3-none-any.whl", hash = "sha256:fc8837335476221ccccda3d176ed6ae29fe58753ce7e8b7863f5d0f987328fc6"}, - {file = "pre_commit_hooks-4.4.0.tar.gz", hash = "sha256:7011eed8e1a25cde94693da009cba76392194cecc2f3f06c51a44ea6ad6c2af9"}, -] - -[package.dependencies] -"ruamel.yaml" = ">=0.15" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} - -[[package]] -name = "pycodestyle" -version = "2.10.0" -description = "Python style guide checker" -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "pycodestyle-2.10.0-py2.py3-none-any.whl", hash = "sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"}, - {file = "pycodestyle-2.10.0.tar.gz", hash = "sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053"}, -] - -[[package]] -name = "pydocstyle" -version = "6.3.0" -description = "Python docstring style checker" -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "pydocstyle-6.3.0-py3-none-any.whl", hash = "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019"}, - {file = "pydocstyle-6.3.0.tar.gz", hash = "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1"}, -] - -[package.dependencies] -snowballstemmer = ">=2.2.0" - -[package.extras] -toml = ["tomli (>=1.2.3)"] - -[[package]] -name = "pyflakes" -version = "3.0.1" -description = "passive checker of Python programs" -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "pyflakes-3.0.1-py2.py3-none-any.whl", hash = "sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf"}, - {file = "pyflakes-3.0.1.tar.gz", hash = "sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd"}, -] - -[[package]] -name = "pygments" -version = "2.14.0" -description = "Pygments is a syntax highlighting package written in Python." -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "Pygments-2.14.0-py3-none-any.whl", hash = "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"}, - {file = "Pygments-2.14.0.tar.gz", hash = "sha256:b3ed06a9e8ac9a9aae5a6f5dbe78a8a58655d17b43b93c078f094ddc476ae297"}, -] - -[package.extras] -plugins = ["importlib-metadata"] - -[[package]] -name = "pyparsing" -version = "3.0.9" -description = "pyparsing module - Classes and methods to define and execute parsing grammars" -category = "main" -optional = false -python-versions = ">=3.6.8" -files = [ - {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, - {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, -] - -[package.extras] -diagrams = ["jinja2", "railroad-diagrams"] - -[[package]] -name = "pytest" -version = "7.2.1" -description = "pytest: simple powerful testing with Python" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pytest-7.2.1-py3-none-any.whl", hash = "sha256:c7c6ca206e93355074ae32f7403e8ea12163b1163c976fee7d4d84027c162be5"}, - {file = "pytest-7.2.1.tar.gz", hash = "sha256:d45e0952f3727241918b8fd0f376f5ff6b301cc0777c6f9a556935c92d8a7d42"}, -] - -[package.dependencies] -attrs = ">=19.2.0" -colorama = {version = "*", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=0.12,<2.0" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} - -[package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] - -[[package]] -name = "pytest-cov" -version = "4.0.0" -description = "Pytest plugin for measuring coverage." -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, - {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, -] - -[package.dependencies] -coverage = {version = ">=5.2.1", extras = ["toml"]} -pytest = ">=4.6" - -[package.extras] -testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] - -[[package]] -name = "python-dateutil" -version = "2.8.2" -description = "Extensions to the standard Python datetime module" -category = "main" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, -] - -[package.dependencies] -six = ">=1.5" - -[[package]] -name = "pytz" -version = "2022.7.1" -description = "World timezone definitions, modern and historical" -category = "main" -optional = false -python-versions = "*" -files = [ - {file = "pytz-2022.7.1-py2.py3-none-any.whl", hash = "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"}, - {file = "pytz-2022.7.1.tar.gz", hash = "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0"}, -] - -[[package]] -name = "pyyaml" -version = "6.0" -description = "YAML parser and emitter for Python" -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, - {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, - {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, - {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, - {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, - {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, - {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, - {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, - {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, - {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, - {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, - {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, - {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, - {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, - {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, - {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, - {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, - {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, -] - -[[package]] -name = "reorder-python-imports" -version = "3.9.0" -description = "Tool for reordering python imports" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "reorder_python_imports-3.9.0-py2.py3-none-any.whl", hash = "sha256:3f9c16e8781f54c944756d0d1eb34a8c863554f7a4eb3693f574fe19b1a29b56"}, - {file = "reorder_python_imports-3.9.0.tar.gz", hash = "sha256:49292ed537829a6bece9fb3746fc1bbe98f52643be5de01a4e13680268a5b0ec"}, -] - -[package.dependencies] -classify-imports = ">=4.1" - -[[package]] -name = "restructuredtext-lint" -version = "1.4.0" -description = "reStructuredText linter" -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "restructuredtext_lint-1.4.0.tar.gz", hash = "sha256:1b235c0c922341ab6c530390892eb9e92f90b9b75046063e047cacfb0f050c45"}, -] - -[package.dependencies] -docutils = ">=0.11,<1.0" - -[[package]] -name = "ruamel-yaml" -version = "0.17.21" -description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" -category = "dev" -optional = false -python-versions = ">=3" -files = [ - {file = "ruamel.yaml-0.17.21-py3-none-any.whl", hash = "sha256:742b35d3d665023981bd6d16b3d24248ce5df75fdb4e2924e93a05c1f8b61ca7"}, - {file = "ruamel.yaml-0.17.21.tar.gz", hash = "sha256:8b7ce697a2f212752a35c1ac414471dc16c424c9573be4926b56ff3f5d23b7af"}, -] - -[package.dependencies] -"ruamel.yaml.clib" = {version = ">=0.2.6", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.11\""} - -[package.extras] -docs = ["ryd"] -jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] - -[[package]] -name = "ruamel-yaml-clib" -version = "0.2.7" -description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" -category = "dev" -optional = false -python-versions = ">=3.5" -files = [ - {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5859983f26d8cd7bb5c287ef452e8aacc86501487634573d260968f753e1d71"}, - {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:debc87a9516b237d0466a711b18b6ebeb17ba9f391eb7f91c649c5c4ec5006c7"}, - {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:df5828871e6648db72d1c19b4bd24819b80a755c4541d3409f0f7acd0f335c80"}, - {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:efa08d63ef03d079dcae1dfe334f6c8847ba8b645d08df286358b1f5293d24ab"}, - {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-win32.whl", hash = "sha256:763d65baa3b952479c4e972669f679fe490eee058d5aa85da483ebae2009d231"}, - {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:d000f258cf42fec2b1bbf2863c61d7b8918d31ffee905da62dede869254d3b8a"}, - {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:045e0626baf1c52e5527bd5db361bc83180faaba2ff586e763d3d5982a876a9e"}, - {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_12_6_arm64.whl", hash = "sha256:721bc4ba4525f53f6a611ec0967bdcee61b31df5a56801281027a3a6d1c2daf5"}, - {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4b3a93bb9bc662fc1f99c5c3ea8e623d8b23ad22f861eb6fce9377ac07ad6072"}, - {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-macosx_12_0_arm64.whl", hash = "sha256:a234a20ae07e8469da311e182e70ef6b199d0fbeb6c6cc2901204dd87fb867e8"}, - {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:15910ef4f3e537eea7fe45f8a5d19997479940d9196f357152a09031c5be59f3"}, - {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:370445fd795706fd291ab00c9df38a0caed0f17a6fb46b0f607668ecb16ce763"}, - {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-win32.whl", hash = "sha256:ecdf1a604009bd35c674b9225a8fa609e0282d9b896c03dd441a91e5f53b534e"}, - {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-win_amd64.whl", hash = "sha256:f34019dced51047d6f70cb9383b2ae2853b7fc4dce65129a5acd49f4f9256646"}, - {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2aa261c29a5545adfef9296b7e33941f46aa5bbd21164228e833412af4c9c75f"}, - {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f01da5790e95815eb5a8a138508c01c758e5f5bc0ce4286c4f7028b8dd7ac3d0"}, - {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:40d030e2329ce5286d6b231b8726959ebbe0404c92f0a578c0e2482182e38282"}, - {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c3ca1fbba4ae962521e5eb66d72998b51f0f4d0f608d3c0347a48e1af262efa7"}, - {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-win32.whl", hash = "sha256:7bdb4c06b063f6fd55e472e201317a3bb6cdeeee5d5a38512ea5c01e1acbdd93"}, - {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:be2a7ad8fd8f7442b24323d24ba0b56c51219513cfa45b9ada3b87b76c374d4b"}, - {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:91a789b4aa0097b78c93e3dc4b40040ba55bef518f84a40d4442f713b4094acb"}, - {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:99e77daab5d13a48a4054803d052ff40780278240a902b880dd37a51ba01a307"}, - {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:3243f48ecd450eddadc2d11b5feb08aca941b5cd98c9b1db14b2fd128be8c697"}, - {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:8831a2cedcd0f0927f788c5bdf6567d9dc9cc235646a434986a852af1cb54b4b"}, - {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-win32.whl", hash = "sha256:3110a99e0f94a4a3470ff67fc20d3f96c25b13d24c6980ff841e82bafe827cac"}, - {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:92460ce908546ab69770b2e576e4f99fbb4ce6ab4b245345a3869a0a0410488f"}, - {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5bc0667c1eb8f83a3752b71b9c4ba55ef7c7058ae57022dd9b29065186a113d9"}, - {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:4a4d8d417868d68b979076a9be6a38c676eca060785abaa6709c7b31593c35d1"}, - {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:bf9a6bc4a0221538b1a7de3ed7bca4c93c02346853f44e1cd764be0023cd3640"}, - {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a7b301ff08055d73223058b5c46c55638917f04d21577c95e00e0c4d79201a6b"}, - {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-win32.whl", hash = "sha256:d5e51e2901ec2366b79f16c2299a03e74ba4531ddcfacc1416639c557aef0ad8"}, - {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:184faeaec61dbaa3cace407cffc5819f7b977e75360e8d5ca19461cd851a5fc5"}, - {file = "ruamel.yaml.clib-0.2.7.tar.gz", hash = "sha256:1f08fd5a2bea9c4180db71678e850b995d2a5f4537be0e94557668cf0f5f9497"}, -] - -[[package]] -name = "scikit-learn" -version = "1.2.1" -description = "A set of python modules for machine learning and data mining" -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "scikit-learn-1.2.1.tar.gz", hash = "sha256:fbf8a5c893c9b4b99bcc7ed8fb3e8500957a113f4101860386d06635520f7cfb"}, - {file = "scikit_learn-1.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bed9f75763bd392c094bf474c7ab75a01d68b15146ea7a20c0f9ff6fb3063dad"}, - {file = "scikit_learn-1.2.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:c9285275a435d1f8f47bbe3500346ab9ead2499e0e090518404d318ea90d1c1c"}, - {file = "scikit_learn-1.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc838b5a4057c55ba81b82316ea8bf443af445f96eb21500b0e40618017e0923"}, - {file = "scikit_learn-1.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8bcd303dd982494842a3f482f844d539484c6043b4eed896b43ea8e5f609a21"}, - {file = "scikit_learn-1.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:a9abf17d177df54e529154f26acfd42930e19117d045e8a9a8e893ca82dd94ec"}, - {file = "scikit_learn-1.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:70fa30d146b7e9d0c256e73e271b3e17f23123b7c4adcbde1a385031adf59090"}, - {file = "scikit_learn-1.2.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:5a8111f3c7a314017ebf90d6feab861c11d1ca14f3dbafb39abcc31aa4c54ba6"}, - {file = "scikit_learn-1.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cba0c7c6bf1493f8ce670bab69f9317874826ee838988de377ae355abd4d74cf"}, - {file = "scikit_learn-1.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:479aedd0abedbda6b8b4529145fe4cd8622f69f726a72cef8f75548a93eeb1e1"}, - {file = "scikit_learn-1.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:5523e21ab2b4d52b2bd41bedd335dbe8f3c1b5f6dd7c9c001b2e17ec9818af8d"}, - {file = "scikit_learn-1.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:dcfab6a19b236194af88771d8e6e778a60c3339248ab0018696ebf2b7c8bed4b"}, - {file = "scikit_learn-1.2.1-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:559f66e12f93b34c8c85c0a5728c3b8af98f04eb12f2c9ee18ea3c82c3d2fad1"}, - {file = "scikit_learn-1.2.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbb7831b2308c67bb6dd83c5ea3cdaf8e8cafd2de4000b93d78bb689126bd2cf"}, - {file = "scikit_learn-1.2.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b2c5d9930ced2b7821ad936b9940706ccb5471d89b8a516bb641cec87257d1c"}, - {file = "scikit_learn-1.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:54731e2c2fbff40da6d76cbb9022ace5f44a4020a10bd5cd92107e86882bad15"}, - {file = "scikit_learn-1.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d00e46a2a7fce6e118ed0f4c6263785bf6c297a94ffd0cd7b32455043c508cc8"}, - {file = "scikit_learn-1.2.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:da0e2d50a8435ea8dc5cd21f1fc1a45d329bae03dcca92087ebed859d22d184e"}, - {file = "scikit_learn-1.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61bb9c654b5d2e6cdd4b1c7e6048fc66270c1682bda1b0f7d2726fdae09010f4"}, - {file = "scikit_learn-1.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0ee4d4d32c94e082344308528f7b3c9294b60ab19c84eb37a2d9c88bdffd9d1"}, - {file = "scikit_learn-1.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:c722f3446ad8c4f1a93b2399fe1a188635b94709a3f25e6f4d61efbe75fe8eaa"}, -] - -[package.dependencies] -joblib = ">=1.1.1" -numpy = ">=1.17.3" -scipy = ">=1.3.2" -threadpoolctl = ">=2.0.0" - -[package.extras] -benchmark = ["matplotlib (>=3.1.3)", "memory-profiler (>=0.57.0)", "pandas (>=1.0.5)"] -docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.1.3)", "memory-profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.0.5)", "plotly (>=5.10.0)", "pooch (>=1.6.0)", "scikit-image (>=0.16.2)", "seaborn (>=0.9.0)", "sphinx (>=4.0.1)", "sphinx-gallery (>=0.7.0)", "sphinx-prompt (>=1.3.0)", "sphinxext-opengraph (>=0.4.2)"] -examples = ["matplotlib (>=3.1.3)", "pandas (>=1.0.5)", "plotly (>=5.10.0)", "pooch (>=1.6.0)", "scikit-image (>=0.16.2)", "seaborn (>=0.9.0)"] -tests = ["black (>=22.3.0)", "flake8 (>=3.8.2)", "matplotlib (>=3.1.3)", "mypy (>=0.961)", "numpydoc (>=1.2.0)", "pandas (>=1.0.5)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pytest (>=5.3.1)", "pytest-cov (>=2.9.0)", "scikit-image (>=0.16.2)"] - -[[package]] -name = "scipy" -version = "1.9.3" -description = "Fundamental algorithms for scientific computing in Python" -category = "main" -optional = false -python-versions = ">=3.8" -files = [ - {file = "scipy-1.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1884b66a54887e21addf9c16fb588720a8309a57b2e258ae1c7986d4444d3bc0"}, - {file = "scipy-1.9.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:83b89e9586c62e787f5012e8475fbb12185bafb996a03257e9675cd73d3736dd"}, - {file = "scipy-1.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a72d885fa44247f92743fc20732ae55564ff2a519e8302fb7e18717c5355a8b"}, - {file = "scipy-1.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d01e1dd7b15bd2449c8bfc6b7cc67d630700ed655654f0dfcf121600bad205c9"}, - {file = "scipy-1.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:68239b6aa6f9c593da8be1509a05cb7f9efe98b80f43a5861cd24c7557e98523"}, - {file = "scipy-1.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b41bc822679ad1c9a5f023bc93f6d0543129ca0f37c1ce294dd9d386f0a21096"}, - {file = "scipy-1.9.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:90453d2b93ea82a9f434e4e1cba043e779ff67b92f7a0e85d05d286a3625df3c"}, - {file = "scipy-1.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83c06e62a390a9167da60bedd4575a14c1f58ca9dfde59830fc42e5197283dab"}, - {file = "scipy-1.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abaf921531b5aeaafced90157db505e10345e45038c39e5d9b6c7922d68085cb"}, - {file = "scipy-1.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:06d2e1b4c491dc7d8eacea139a1b0b295f74e1a1a0f704c375028f8320d16e31"}, - {file = "scipy-1.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5a04cd7d0d3eff6ea4719371cbc44df31411862b9646db617c99718ff68d4840"}, - {file = "scipy-1.9.3-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:545c83ffb518094d8c9d83cce216c0c32f8c04aaf28b92cc8283eda0685162d5"}, - {file = "scipy-1.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d54222d7a3ba6022fdf5773931b5d7c56efe41ede7f7128c7b1637700409108"}, - {file = "scipy-1.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cff3a5295234037e39500d35316a4c5794739433528310e117b8a9a0c76d20fc"}, - {file = "scipy-1.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:2318bef588acc7a574f5bfdff9c172d0b1bf2c8143d9582e05f878e580a3781e"}, - {file = "scipy-1.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d644a64e174c16cb4b2e41dfea6af722053e83d066da7343f333a54dae9bc31c"}, - {file = "scipy-1.9.3-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:da8245491d73ed0a994ed9c2e380fd058ce2fa8a18da204681f2fe1f57f98f95"}, - {file = "scipy-1.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4db5b30849606a95dcf519763dd3ab6fe9bd91df49eba517359e450a7d80ce2e"}, - {file = "scipy-1.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c68db6b290cbd4049012990d7fe71a2abd9ffbe82c0056ebe0f01df8be5436b0"}, - {file = "scipy-1.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:5b88e6d91ad9d59478fafe92a7c757d00c59e3bdc3331be8ada76a4f8d683f58"}, - {file = "scipy-1.9.3.tar.gz", hash = "sha256:fbc5c05c85c1a02be77b1ff591087c83bc44579c6d2bd9fb798bb64ea5e1a027"}, -] - -[package.dependencies] -numpy = ">=1.18.5,<1.26.0" - -[package.extras] -dev = ["flake8", "mypy", "pycodestyle", "typing_extensions"] -doc = ["matplotlib (>2)", "numpydoc", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-panels (>=0.5.2)", "sphinx-tabs"] -test = ["asv", "gmpy2", "mpmath", "pytest", "pytest-cov", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] - -[[package]] -name = "setuptools" -version = "67.2.0" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "setuptools-67.2.0-py3-none-any.whl", hash = "sha256:16ccf598aab3b506593c17378473978908a2734d7336755a8769b480906bec1c"}, - {file = "setuptools-67.2.0.tar.gz", hash = "sha256:b440ee5f7e607bb8c9de15259dba2583dd41a38879a7abc1d43a71c59524da48"}, -] - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] - -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] - -[[package]] -name = "smmap" -version = "5.0.0" -description = "A pure Python implementation of a sliding window memory map manager" -category = "dev" -optional = false -python-versions = ">=3.6" -files = [ - {file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"}, - {file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"}, -] - -[[package]] -name = "snowballstemmer" -version = "2.2.0" -description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, - {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, -] - -[[package]] -name = "stevedore" -version = "4.1.1" -description = "Manage dynamic plugins for Python applications" -category = "dev" -optional = false -python-versions = ">=3.8" -files = [ - {file = "stevedore-4.1.1-py3-none-any.whl", hash = "sha256:aa6436565c069b2946fe4ebff07f5041e0c8bf18c7376dd29edf80cf7d524e4e"}, - {file = "stevedore-4.1.1.tar.gz", hash = "sha256:7f8aeb6e3f90f96832c301bff21a7eb5eefbe894c88c506483d355565d88cc1a"}, -] - -[package.dependencies] -pbr = ">=2.0.0,<2.1.0 || >2.1.0" - -[[package]] -name = "threadpoolctl" -version = "3.1.0" -description = "threadpoolctl" -category = "main" -optional = false -python-versions = ">=3.6" -files = [ - {file = "threadpoolctl-3.1.0-py3-none-any.whl", hash = "sha256:8b99adda265feb6773280df41eece7b2e6561b772d21ffd52e372f999024907b"}, - {file = "threadpoolctl-3.1.0.tar.gz", hash = "sha256:a335baacfaa4400ae1f0d8e3a58d6674d2f8828e3716bb2802c44955ad391380"}, -] - -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] - -[[package]] -name = "typing-extensions" -version = "4.4.0" -description = "Backported and Experimental Type Hints for Python 3.7+" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, - {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, -] - -[[package]] -name = "virtualenv" -version = "20.19.0" -description = "Virtual Python Environment builder" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "virtualenv-20.19.0-py3-none-any.whl", hash = "sha256:54eb59e7352b573aa04d53f80fc9736ed0ad5143af445a1e539aada6eb947dd1"}, - {file = "virtualenv-20.19.0.tar.gz", hash = "sha256:37a640ba82ed40b226599c522d411e4be5edb339a0c0de030c0dc7b646d61590"}, -] - -[package.dependencies] -distlib = ">=0.3.6,<1" -filelock = ">=3.4.1,<4" -platformdirs = ">=2.4,<4" - -[package.extras] -docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"] -test = ["covdefaults (>=2.2.2)", "coverage (>=7.1)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23)", "pytest (>=7.2.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)"] - -[[package]] -name = "win32-setctime" -version = "1.1.0" -description = "A small Python utility to set file creation time on Windows" -category = "main" -optional = false -python-versions = ">=3.5" -files = [ - {file = "win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"}, - {file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"}, -] - -[package.extras] -dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] - -[metadata] -lock-version = "2.0" -python-versions = ">=3.9,<3.15" -content-hash = "706ebbcd63d2c6031aa2299d9bfd7980c09e79656c4336b0a63c06f7c7d258c7" diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 86aa15a..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,87 +0,0 @@ -[tool.poetry] -name = "statista" -version = "0.1.8" -description = "statistics package" -authors = ["Mostafa Farrag "] -readme = "README.md" -license = "GNU General Public License v3" -repository = "https://github.com/MAfarrag/statista" -documentation = "https://statista.readthedocs.io/" -keywords = ["statistics", "distributions"] -classifiers=[ - "Development Status :: 5 - Production/Stable", - "Environment :: Console", - "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", - "Natural Language :: English", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Intended Audience :: Science/Research", - "Intended Audience :: Developers", - ] - - - -[tool.poetry.dependencies] -python = ">=3.9,<3.15" -numpy = "^1.24.1" -matplotlib = "^3.6.3" -pandas = "^1.5.3" -scipy = "^1.9.0" -scikit-learn = "^1.2.1" -loguru = "^0.6.0" - - - -[tool.poetry.dev-dependencies] -pytest = "^7.2.1" -pytest-cov = "^4.0.0" -pre-commit = "^3.0.3" -black = "^22.12.0" -flake8-bandit = "^4.1.1" -flake8-bugbear = "^23.1.20" -flake8-docstrings = "^1.7.0" -flake8-rst-docstrings = "^0.3.0" -pep8-naming = "^0.13.3" -darglint = "^1.8.1" -reorder-python-imports = "^3.9.0" -pre-commit-hooks = "^4.4.0" - - -[tool.poetry.scripts] - -[tool.coverage.paths] -source = ["statista", "*/site-packages"] - - -[tool.coverage.run] -branch = true -source = ["statista"] - - -[tool.coverage.report] -show_missing = true -fail_under = 0 - - -[tool.isort] -multi_line_output=3 -include_trailing_comma=true -force_grid_wrap=0 -use_parentheses=true -line_length=88 -ensure_newline_before_comments=true -profile="black" - - -[tool.pytest.ini_options] -minversion = "7.0" -addopts = "-ra -q" -testpaths = [ - "tests", -] - - -[build-system] -requires = ["setuptools", "poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..7ce99f8 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,12 @@ +black >=22.12.0 +darglint >=1.8.1 +flake8-bandit >=4.1.1 +flake8-bugbear >=22.12.6 +flake8-docstrings >=1.6.0 +flake8-rst-docstrings >=0.3.0 +pep8-naming >=0.13.3 +pre-commit >=2.20.0 +pre-commit-hooks >=4.4.0 +pytest >=7.2.0 +pytest-cov >= 4.0.0 +reorder-python-imports >=3.9.0 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..38cb0da --- /dev/null +++ b/requirements.txt @@ -0,0 +1,7 @@ +numpy ==1.24.1 +pip >=22.3.1 +matplotlib >=3.6.3 +pandas >=1.5.3 +scipy >=1.9.0 +scikit-learn >=1.2.1 +loguru >=0.6.0 \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..48bd2ad --- /dev/null +++ b/setup.py @@ -0,0 +1,41 @@ +from setuptools import find_packages, setup + +with open("README.md", "r") as readme_file: + readme = readme_file.read() + +with open("HISTORY.rst") as history_file: + history = history_file.read() + +requirements = [line.strip() for line in open("requirements.txt").readlines()] +requirements_dev = [line.strip() for line in open("requirements-dev.txt").readlines()] + +setup( + name="statista", + version="0.1.8", + description="statistics package", + author="Mostafa Farrag", + author_email="moah.farag@gmail.come", + url="https://github.com/MAfarrag/statista", + keywords=["remote sensing", "ecmwf"], + long_description=readme + "\n\n" + history, + long_description_content_type="text/markdown", + license="GNU General Public License v3", + zip_safe=False, + packages=find_packages(include=["statista", "statista.*"]), + test_suite="tests", + tests_require=requirements_dev, + install_requires=requirements, + classifiers=[ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", + "Natural Language :: English", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Topic :: Scientific/Engineering :: GIS", + "Intended Audience :: Science/Research", + "Intended Audience :: Developers", + ], +) diff --git a/statista/distributions.py b/statista/distributions.py index 6472086..7252ae8 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -699,14 +699,13 @@ def probapilityPlot( class GEV: """GEV (Genalized Extreme value statistics)""" + parameters: dict[str, Union[float, Any]] data: ndarray def __init__( - self, - data: Union[list, np.ndarray] = None, - shape: Union[int, float] = None, - loc: Union[int, float] = None, - scale: Union[int, float] = None, + self, + data: Union[list, np.ndarray] = None, + parameters: Dict[str, str] = None, ): """GEV. @@ -714,9 +713,13 @@ def __init__( ---------- data : [list] data time series. - shape - loc - scale + + parameters: Dict[str, str] + {"loc": val, "scale": val, "shape": value} + - loc: [numeric] + location parameter of the gumbel distribution. + - scale: [numeric] + scale parameter of the gumbel distribution. """ if isinstance(data, list) or isinstance(data, np.ndarray): self.data = np.array(data) @@ -724,28 +727,24 @@ def __init__( self.cdf_Weibul = PlottingPosition.weibul(data) self.KStable = 1.22 / np.sqrt(len(self.data)) - self.loc = loc - self.scale = scale + self.parameters = parameters self.Dstatic = None self.KS_Pvalue = None self.chistatic = None self.chi_Pvalue = None - self.shape = shape pass def pdf( - self, - shape: Union[float, int], - loc: Union[float, int], - scale: Union[float, int], - plot_figure: bool = False, - figsize: tuple = (6, 5), - xlabel: str = "Actual data", - ylabel: str = "pdf", - fontsize: int = 15, - actualdata: Union[bool, np.ndarray] = True, + self, + parameters: Dict[str, Union[float, Any]], + plot_figure: bool = False, + figsize: tuple = (6, 5), + xlabel: str = "Actual data", + ylabel: str = "pdf", + fontsize: int = 15, + actualdata: Union[bool, np.ndarray] = True, ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: """pdf. @@ -778,6 +777,10 @@ def pdf( TYPE DESCRIPTION. """ + loc = parameters.get("loc") + scale = parameters.get("scale") + shape = parameters.get("shape") + if isinstance(actualdata, bool): ts = self.data_sorted else: @@ -824,7 +827,7 @@ def pdf( Qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 ) - pdf_fitted = self.pdf(shape, loc, scale, actualdata=Qx) + pdf_fitted = self.pdf(parameters, actualdata=Qx) fig, ax = plot.pdf( Qx, @@ -841,9 +844,7 @@ def pdf( def cdf( self, - shape: Union[float, int], - loc: Union[float, int], - scale: Union[float, int], + parameters: Dict[str, Union[float, Any]], plot_figure: bool = False, figsize: tuple = (6, 5), xlabel: str = "Actual data", @@ -856,6 +857,10 @@ def cdf( Returns the value of Gumbel's cdf with parameters loc and scale at x. """ + loc = parameters.get("loc") + scale = parameters.get("scale") + shape = parameters.get("shape") + if scale <= 0: raise ValueError("Scale parameter is negative") @@ -886,7 +891,7 @@ def cdf( Qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 ) - cdf_fitted = self.cdf(shape, loc, scale, actualdata=Qx) + cdf_fitted = self.cdf(parameters, actualdata=Qx) cdf_Weibul = PlottingPosition.weibul(self.data_sorted) @@ -943,7 +948,7 @@ def estimateParameter( ObjFunc=None, threshold: Union[int, float, None] = None, test: bool = True, - ) -> tuple: + ) -> Dict[str, Any]: """estimateParameter. EstimateParameter estimate the distribution parameter based on MLM @@ -1003,9 +1008,8 @@ def estimateParameter( ) Param = [Param[1], Param[2], Param[3]] - self.shape = Param[0] - self.loc = Param[1] - self.scale = Param[2] + Param = {"loc": Param[1], "scale": Param[2], "shape": Param[0]} + self.parameters = Param if test: self.ks() @@ -1018,10 +1022,8 @@ def estimateParameter( @staticmethod def theporeticalEstimate( - shape: Union[float, int], - loc: Union[float, int], - scale: Union[float, int], - F: np.ndarray, + parameters: Dict[str, Union[float, Any]], + F: np.ndarray, ) -> np.ndarray: """TheporeticalEstimate. @@ -1039,6 +1041,10 @@ def theporeticalEstimate( theoreticalvalue : [numeric] Value based on the theoretical distribution """ + loc = parameters.get("loc") + scale = parameters.get("scale") + shape = parameters.get("shape") + if scale <= 0: raise ValueError("Parameters Invalid") @@ -1078,14 +1084,12 @@ def ks(self): Pvalue : [numeric] IF Pvalue < signeficance level ------ reject the null hypotethis """ - if not hasattr(self, "loc") or not hasattr(self, "scale"): + if self.parameters is None: raise ValueError( "Value of loc/scale parameter is unknown please use " "'EstimateParameter' to obtain them" ) - Qth = self.theporeticalEstimate( - self.shape, self.loc, self.scale, self.cdf_Weibul - ) + Qth = self.theporeticalEstimate(self.parameters, self.cdf_Weibul) test = ks_2samp(self.data, Qth) self.Dstatic = test.statistic @@ -1101,15 +1105,13 @@ def ks(self): return test.statistic, test.pvalue def chisquare(self): - if not hasattr(self, "loc") or not hasattr(self, "scale"): + if self.parameters is None: raise ValueError( "Value of loc/scale parameter is unknown please use " "'EstimateParameter' to obtain them" ) - Qth = self.theporeticalEstimate( - self.shape, self.loc, self.scale, self.cdf_Weibul - ) + Qth = self.theporeticalEstimate(self.parameters, self.cdf_Weibul) test = chisquare(st.standardize(Qth), st.standardize(self.data)) self.chistatic = test.statistic @@ -1121,15 +1123,13 @@ def chisquare(self): return test.statistic, test.pvalue def confidenceInterval( - self, - shape: Union[float, int], - loc: Union[float, int], - scale: Union[float, int], - F: np.ndarray, - alpha: float = 0.1, - statfunction=np.average, - n_samples: int = 100, - **kargs, + self, + parameters: Dict[str, Union[float, Any]], + F: np.ndarray, + alpha: float = 0.1, + statfunction=np.average, + n_samples: int = 100, + **kargs, ): """confidenceInterval. @@ -1151,14 +1151,18 @@ def confidenceInterval( Qlower : [list] lower bound coresponding to the confidence interval. """ + loc = parameters.get("loc") + scale = parameters.get("scale") + shape = parameters.get("shape") + if scale <= 0: raise ValueError("Scale parameter is negative") - Param = [shape, loc, scale] + # Param = [shape, loc, scale] CI = ConfidenceInterval.BootStrap( self.data, statfunction=statfunction, - gevfit=Param, + gevfit=parameters, F=F, alpha=alpha, n_samples=n_samples, @@ -1171,9 +1175,7 @@ def confidenceInterval( def probapilityPlot( self, - shape: Union[float, int], - loc: Union[float, int], - scale: Union[float, int], + parameters: Dict[str, Union[float, Any]], F, alpha=0.1, func=None, @@ -1218,10 +1220,14 @@ def probapilityPlot( func : [function] function to be used in the confidence interval calculation. """ + loc = parameters.get("loc") + scale = parameters.get("scale") + shape = parameters.get("shape") + if scale <= 0: raise ValueError("Scale parameter is negative") - Qth = self.theporeticalEstimate(shape, loc, scale, F) + Qth = self.theporeticalEstimate(parameters, F) if func is None: func = ConfidenceInterval.GEVfunc @@ -1358,11 +1364,12 @@ def GEVfunc(data, **kwargs): gevfit = kwargs["gevfit"] F = kwargs["F"] - shape = gevfit[0] - loc = gevfit[1] - scale = gevfit[2] + # shape = gevfit[0] + # loc = gevfit[1] + # scale = gevfit[2] + # parameters = {"loc": loc, "scale": scale, "shape": shape} # generate theoretical estimates based on a random cdf, and the dist parameters - sample = GEV.theporeticalEstimate(shape, loc, scale, np.random.rand(len(data))) + sample = GEV.theporeticalEstimate(gevfit, np.random.rand(len(data))) # get parameters based on the new generated sample LM = Lmoments(sample) mum = LM.Lmom() @@ -1376,7 +1383,8 @@ def GEVfunc(data, **kwargs): # T = np.linspace(0.1, 999, len(data)) + 1 # coresponding theoretical estimate to T # F = 1 - 1 / T - Qth = GEV.theporeticalEstimate(shape, loc, scale, F) + parameters = {"loc": loc, "scale": scale, "shape": shape} + Qth = GEV.theporeticalEstimate(parameters, F) res = newfit res.extend(Qth) diff --git a/tests/test_distributions.py b/tests/test_distributions.py index 847b32f..619a63c 100644 --- a/tests/test_distributions.py +++ b/tests/test_distributions.py @@ -182,10 +182,12 @@ def test_gev_estimate_parameter( param = Gdist.estimateParameter( method=dist_estimation_parameters[i], test=False ) - assert isinstance(param, list) - assert Gdist.loc - assert Gdist.scale - assert Gdist.shape + + assert isinstance(param, dict) + assert all(i in param.keys() for i in ["loc", "scale", "shape"]) + assert Gdist.parameters.get("loc") is not None + assert Gdist.parameters.get("scale") is not None + assert Gdist.parameters.get("shape") is not None def test_gev_ks( self, @@ -218,7 +220,7 @@ def test_gev_pdf( Param = Gdist.estimateParameter( method=dist_estimation_parameters_ks, test=False ) - pdf, fig, ax = Gdist.pdf(Param[0], Param[1], Param[2], plot_figure=True) + pdf, fig, ax = Gdist.pdf(Param, plot_figure=True) assert isinstance(pdf, np.ndarray) assert isinstance(fig, Figure) @@ -231,7 +233,7 @@ def test_gev_cdf( Param = Gdist.estimateParameter( method=dist_estimation_parameters_ks, test=False ) - cdf, fig, ax = Gdist.cdf(Param[0], Param[1], Param[2], plot_figure=True) + cdf, fig, ax = Gdist.cdf(Param, plot_figure=True) assert isinstance(cdf, np.ndarray) assert isinstance(fig, Figure) @@ -245,7 +247,7 @@ def test_gev_TheporeticalEstimate( Param = Gdist.estimateParameter( method=dist_estimation_parameters_ks, test=False ) - Qth = Gdist.theporeticalEstimate(Param[0], Param[1], Param[2], cdf_Weibul) + Qth = Gdist.theporeticalEstimate(Param, cdf_Weibul) assert isinstance(Qth, np.ndarray) def test_gev_confidence_interval( @@ -261,9 +263,7 @@ def test_gev_confidence_interval( ) func = ConfidenceInterval.GEVfunc upper, lower = Gdist.confidenceInterval( - Param[0], - Param[1], - Param[2], + Param, F=cdf_Weibul, alpha=confidence_interval_alpha, statfunction=func, From b7e00d0a0a457fda8e909fbcd66d01138a4ab53c Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Wed, 8 Feb 2023 02:16:51 +0100 Subject: [PATCH 03/44] refactor --- statista/distributions.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/statista/distributions.py b/statista/distributions.py index 7252ae8..28fdd7d 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -433,7 +433,7 @@ def estimateParameter( method = method.lower() if method not in ["mle", "mm", "lmoments", "optimization"]: raise ValueError( - method + "value should be 'mle', 'mm', 'lmoments' or 'optimization'" + f"{method} value should be 'mle', 'mm', 'lmoments' or 'optimization'" ) if method == "mle" or method == "mm": Param = list(gumbel_r.fit(self.data, method=method)) @@ -1364,26 +1364,19 @@ def GEVfunc(data, **kwargs): gevfit = kwargs["gevfit"] F = kwargs["F"] - # shape = gevfit[0] - # loc = gevfit[1] - # scale = gevfit[2] - # parameters = {"loc": loc, "scale": scale, "shape": shape} # generate theoretical estimates based on a random cdf, and the dist parameters sample = GEV.theporeticalEstimate(gevfit, np.random.rand(len(data))) # get parameters based on the new generated sample LM = Lmoments(sample) mum = LM.Lmom() newfit = LM.GEV(mum) - shape = newfit[0] - loc = newfit[1] - scale = newfit[2] # return period # T = np.arange(0.1, 999.1, 0.1) + 1 # +1 in order not to make 1- 1/0.1 = -9 # T = np.linspace(0.1, 999, len(data)) + 1 # coresponding theoretical estimate to T # F = 1 - 1 / T - parameters = {"loc": loc, "scale": scale, "shape": shape} + parameters = {"loc": newfit[1], "scale": newfit[2], "shape": newfit[0]} Qth = GEV.theporeticalEstimate(parameters, F) res = newfit @@ -1397,6 +1390,7 @@ class plot: def __init__(self): pass + @staticmethod def pdf( Qx: np.ndarray, pdf_fitted, From 49ffcbc6ae437e59ae294f75eb0ca391e0cbc61e Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Wed, 8 Feb 2023 02:19:50 +0100 Subject: [PATCH 04/44] fix error in optimization method for parameter estimation --- statista/distributions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/statista/distributions.py b/statista/distributions.py index 28fdd7d..daf3098 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -444,7 +444,7 @@ def estimateParameter( elif method == "optimization": if ObjFunc is None or threshold is None: raise TypeError("threshold should be numeric value") - Param = gumbel_r.fit(self.data, method=method) + Param = gumbel_r.fit(self.data, method="mle") # then we use the result as starting value for your truncated Gumbel fit Param = so.fmin( ObjFunc, From 8cdfe89aa9e97e018f5f672a4eb5f7414ef9bd2c Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Wed, 8 Feb 2023 02:23:09 +0100 Subject: [PATCH 05/44] change workflow to setup.py instead of pyproject.toml --- .github/workflows/ubuntu.yml | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 56e2386..4ea9068 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -23,15 +23,10 @@ jobs: with: python-version: ${{ matrix.python-version }} architecture: x64 - - name: Install poetry - run: | - pip install --user poetry==1.2.2 - export PATH="${PATH}:/root/.poetry/bin" - - name: Install dependencies run: | - poetry install - source `poetry env info --path`/bin/activate + pip install -r requirements.txt -r requirements-dev.txt + python setup.py install - name: Install & Lint with flake8 run: | @@ -42,7 +37,7 @@ jobs: run: | pip install pytest pip install pytest-cov - poetry run pytest -vvv --cov=statista --cov-report=xml + python -m pytest -vvv --cov=statista --cov-report=xml - name: Upload coverage reports to Codecov with GitHub Action uses: codecov/codecov-action@v3 From a507aa236793a83615f46ac844e41af51333642d Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Wed, 8 Feb 2023 02:38:33 +0100 Subject: [PATCH 06/44] add the abstractdistribution as a super class --- statista/distributions.py | 300 ++++++++++++++++++++++++++++---------- 1 file changed, 226 insertions(+), 74 deletions(-) diff --git a/statista/distributions.py b/statista/distributions.py index daf3098..e4387ed 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -84,8 +84,6 @@ def __init__( self, data: Union[list, np.ndarray] = None, parameters: Dict[str, str] = None, - # loc: Union[int, float] = None, - # scale: Union[int, float] = None, ): """Gumbel. @@ -106,8 +104,6 @@ def __init__( self.cdf_Weibul = PlottingPosition.weibul(data) self.KStable = 1.22 / np.sqrt(len(self.data)) - # self.loc = loc - # self.scale = scale self.parameters = parameters self.Dstatic = None @@ -117,16 +113,16 @@ def __init__( pass + def pdf( - self, - loc: Union[float, int], - scale: Union[float, int], - plot_figure: bool = False, - figsize: tuple = (6, 5), - xlabel: str = "Actual data", - ylabel: str = "pdf", - fontsize: Union[float, int] = 15, - actualdata: Union[bool, np.ndarray] = True, + self, + parameters: Dict[str, Union[float, Any]], + plot_figure: bool = False, + figsize: tuple = (6, 5), + xlabel: str = "Actual data", + ylabel: str = "pdf", + fontsize: Union[float, int] = 15, + actualdata: Union[bool, np.ndarray] = True, ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: """pdf. @@ -134,48 +130,227 @@ def pdf( Parameters: ----------- - loc : [numeric] - location parameter of the gumbel distribution. - scale : [numeric] - scale parameter of the gumbel distribution. + parameters: Dict[str, str] + {"loc": val, "scale": val} + - loc: [numeric] + location parameter of the gumbel distribution. + - scale: [numeric] + scale parameter of the gumbel distribution. Returns ------- pdf : [array] probability density function pdf. """ - if scale <= 0: - raise ValueError("Scale parameter is negative") + pass - if isinstance(actualdata, bool): - ts = self.data - else: - ts = actualdata + def cdf( + self, + parameters: Dict[str, Union[float, Any]], + plot_figure: bool = False, + figsize: tuple = (6, 5), + xlabel: str = "data", + ylabel: str = "cdf", + fontsize: int = 15, + actualdata: Union[bool, np.ndarray] = True, + ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: + """cdf. - z = (ts - loc) / scale - pdf = (1.0 / scale) * (np.exp(-(z + (np.exp(-z))))) - # gumbel_r.pdf(data, loc=loc, scale=scale) - if plot_figure: - Qx = np.linspace( - float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 - ) - pdf_fitted = self.pdf(loc, scale, actualdata=Qx) + cdf calculates the value of Gumbel's cdf with parameters loc and scale at x. - fig, ax = plot.pdf( - Qx, - pdf_fitted, - self.data_sorted, - figsize=figsize, - xlabel=xlabel, - ylabel=ylabel, - fontsize=fontsize, - ) - return pdf, fig, ax - else: - return pdf + parameter: + ---------- + parameters: Dict[str, str] + {"loc": val, "scale": val} + - loc: [numeric] + location parameter of the gumbel distribution. + - scale: [numeric] + scale parameter of the gumbel distribution. + """ + pass + + def estimateParameter( + self, + method: str = "mle", + ObjFunc: Callable = None, + threshold: Union[None, float, int] = None, + test: bool = True, + ) -> Dict[str, str]: + """estimateParameter. + + EstimateParameter estimate the distribution parameter based on MLM + (Maximum liklihood method), if an objective function is entered as an input + + There are two likelihood functions (L1 and L2), one for values above some + threshold (x>=C) and one for values below (x < C), now the likeliest parameters + are those at the max value of mutiplication between two functions max(L1*L2). + + In this case the L1 is still the product of multiplication of probability + density function's values at xi, but the L2 is the probability that threshold + value C will be exceeded (1-F(C)). + + Parameters + ---------- + ObjFunc : [function] + function to be used to get the distribution parameters. + threshold : [numeric] + Value you want to consider only the greater values. + method : [string] + 'mle', 'mm', 'lmoments', optimization + test: [bool] + Default is True. + + Returns + ------- + Dict[str, str]: + {"loc": val, "scale": val} + - loc: [numeric] + location parameter of the gumbel distribution. + - scale: [numeric] + scale parameter of the gumbel distribution. + """ + pass + + + @staticmethod + def theporeticalEstimate( + parameters: Dict[str, Union[float, Any]], cdf: np.ndarray + ) -> np.ndarray: + """theporeticalEstimate. + + TheporeticalEstimate method calculates the theoretical values based on the Gumbel distribution + + Parameters: + ----------- + parameters: Dict[str, str] + {"loc": val, "scale": val} + - loc: [numeric] + location parameter of the gumbel distribution. + - scale: [numeric] + scale parameter of the gumbel distribution. + cdf: [list] + cummulative distribution function/ Non Exceedence probability. + + Return: + ------- + theoreticalvalue : [numeric] + Value based on the theoretical distribution + """ + pass + + + def ks(self) -> tuple: + """Kolmogorov-Smirnov (KS) test. + + The smaller the D static the more likely that the two samples are drawn from the same distribution + IF Pvalue < signeficance level ------ reject + + returns: + -------- + Dstatic: [numeric] + The smaller the D static the more likely that the two samples are drawn from the same distribution + Pvalue : [numeric] + IF Pvalue < signeficance level ------ reject the null hypotethis + """ + pass + + def chisquare(self) -> tuple: + """ + + Returns + ------- + + """ + pass + + def confidenceInterval( + self, + parameters: Dict[str, Union[float, Any]], + F: np.ndarray, + alpha: float = 0.1, + ) -> Tuple[np.ndarray, np.ndarray]: + """confidenceInterval. + + Parameters: + ----------- + parameters: Dict[str, str] + {"loc": val, "scale": val} + - loc: [numeric] + location parameter of the gumbel distribution. + - scale: [numeric] + scale parameter of the gumbel distribution. + F : [list] + Non Exceedence probability + alpha : [numeric] + alpha or SignificanceLevel is a value of the confidence interval. + + Return: + ------- + parameters: Dict[str, str] + {"loc": val, "scale": val, "shape": value} + - loc: [numeric] + location parameter + - scale: [numeric] + scale parameter + Qupper : [list] + upper bound coresponding to the confidence interval. + Qlower : [list] + lower bound coresponding to the confidence interval. + """ + pass + + def probapilityPlot( + self, + parameters: Dict[str, Union[float, Any]], + F: np.ndarray, + alpha: float = 0.1, + fig1size: tuple = (10, 5), + fig2size: tuple = (6, 6), + xlabel: str = "Actual data", + ylabel: str = "cdf", + fontsize: int = 15, + ) -> Tuple[List[Figure], list]: + """probapilityPlot. + ProbapilityPlot method calculates the theoretical values based on the Gumbel distribution + parameters, theoretical cdf (or weibul), and calculate the confidence interval. + + Parameters + ---------- + parameters: Dict[str, str] + {"loc": val, "scale": val} + - loc: [numeric] + location parameter of the gumbel distribution. + - scale: [numeric] + scale parameter of the gumbel distribution. + F : [np.ndarray] + theoretical cdf calculated using weibul or using the distribution cdf function. + alpha : [float] + value between 0 and 1. + fig1size: [tuple] + Default is (10, 5) + fig2size: [tuple] + Default is (6, 6) + xlabel: [str] + Default is "Actual data" + ylabel: [str] + Default is "cdf" + fontsize: [float] + Default is 15. -class Gumbel: + Returns + ------- + Qth : [list] + theoretical generated values based on the theoretical cdf calculated from + weibul or the distribution parameters. + Qupper : [list] + upper bound coresponding to the confidence interval. + Qlower : [list] + lower bound coresponding to the confidence interval. + """ + pass + +class Gumbel(AbstractDistribution): """Gumbel distribution.""" cdf_Weibul: ndarray @@ -199,18 +374,7 @@ def __init__( - scale: [numeric] scale parameter of the gumbel distribution. """ - if isinstance(data, list) or isinstance(data, np.ndarray): - self.data = np.array(data) - self.data_sorted = np.sort(data) - self.cdf_Weibul = PlottingPosition.weibul(data) - self.KStable = 1.22 / np.sqrt(len(self.data)) - - self.parameters = parameters - self.Dstatic = None - self.KS_Pvalue = None - self.chistatic = None - self.chi_Pvalue = None - + super().__init__(data, parameters) pass def pdf( @@ -696,7 +860,7 @@ def probapilityPlot( return fig, ax -class GEV: +class GEV(AbstractDistribution): """GEV (Genalized Extreme value statistics)""" parameters: dict[str, Union[float, Any]] @@ -721,19 +885,7 @@ def __init__( - scale: [numeric] scale parameter of the gumbel distribution. """ - if isinstance(data, list) or isinstance(data, np.ndarray): - self.data = np.array(data) - self.data_sorted = np.sort(data) - self.cdf_Weibul = PlottingPosition.weibul(data) - self.KStable = 1.22 / np.sqrt(len(self.data)) - - self.parameters = parameters - self.Dstatic = None - self.KS_Pvalue = None - - self.chistatic = None - self.chi_Pvalue = None - + super().__init__(data, parameters) pass def pdf( @@ -777,15 +929,15 @@ def pdf( TYPE DESCRIPTION. """ - loc = parameters.get("loc") - scale = parameters.get("scale") - shape = parameters.get("shape") - if isinstance(actualdata, bool): ts = self.data_sorted else: ts = actualdata + + loc = parameters.get("loc") + scale = parameters.get("scale") + shape = parameters.get("shape") pdf = [] for i in range(len(ts)): z = (ts[i] - loc) / scale From bc9086134f3fcd54cb17e7961477e69f1b94be51 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Wed, 8 Feb 2023 02:58:48 +0100 Subject: [PATCH 07/44] refactor --- environment.yml | 2 +- requirements.txt | 8 +- statista/distributions.py | 187 ++++++++++++++---------------------- tests/test_distributions.py | 3 + 4 files changed, 81 insertions(+), 119 deletions(-) diff --git a/environment.yml b/environment.yml index bd8ed5a..2dd5e0b 100644 --- a/environment.yml +++ b/environment.yml @@ -10,4 +10,4 @@ dependencies: - scikit-learn >=1.2.1 - loguru >=0.6.0 - pytest >=7.2.0 - - pytest-cov >= 4.0.0 \ No newline at end of file + - pytest-cov >= 4.0.0 diff --git a/requirements.txt b/requirements.txt index 38cb0da..c01b42d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ -numpy ==1.24.1 -pip >=22.3.1 +loguru >=0.6.0 matplotlib >=3.6.3 +numpy ==1.24.1 pandas >=1.5.3 -scipy >=1.9.0 +pip >=22.3.1 scikit-learn >=1.2.1 -loguru >=0.6.0 \ No newline at end of file +scipy >=1.9.0 diff --git a/statista/distributions.py b/statista/distributions.py index e4387ed..0f0166f 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -113,16 +113,15 @@ def __init__( pass - def pdf( - self, - parameters: Dict[str, Union[float, Any]], - plot_figure: bool = False, - figsize: tuple = (6, 5), - xlabel: str = "Actual data", - ylabel: str = "pdf", - fontsize: Union[float, int] = 15, - actualdata: Union[bool, np.ndarray] = True, + self, + parameters: Dict[str, Union[float, Any]], + plot_figure: bool = False, + figsize: tuple = (6, 5), + xlabel: str = "Actual data", + ylabel: str = "pdf", + fontsize: Union[float, int] = 15, + actualdata: Union[bool, np.ndarray] = True, ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: """pdf. @@ -211,7 +210,6 @@ def estimateParameter( """ pass - @staticmethod def theporeticalEstimate( parameters: Dict[str, Union[float, Any]], cdf: np.ndarray @@ -238,7 +236,6 @@ def theporeticalEstimate( """ pass - def ks(self) -> tuple: """Kolmogorov-Smirnov (KS) test. @@ -252,7 +249,25 @@ def ks(self) -> tuple: Pvalue : [numeric] IF Pvalue < signeficance level ------ reject the null hypotethis """ - pass + if self.parameters is None: + raise ValueError( + "Value of parameters is unknown please use " + "'EstimateParameter' to obtain estimate the distribution parameters" + ) + Qth = self.theporeticalEstimate(self.parameters, self.cdf_Weibul) + + test = ks_2samp(self.data, Qth) + self.Dstatic = test.statistic + self.KS_Pvalue = test.pvalue + + print("-----KS Test--------") + print(f"Statistic = {test.statistic}") + if self.Dstatic < self.KStable: + print("Accept Hypothesis") + else: + print("reject Hypothesis") + print(f"P value = {test.pvalue}") + return test.statistic, test.pvalue def chisquare(self) -> tuple: """ @@ -261,7 +276,24 @@ def chisquare(self) -> tuple: ------- """ - pass + if self.parameters is None: + raise ValueError( + "Value of loc/scale parameter is unknown please use " + "'EstimateParameter' to obtain them" + ) + + Qth = self.theporeticalEstimate(self.parameters, self.cdf_Weibul) + try: + test = chisquare(st.standardize(Qth), st.standardize(self.data)) + self.chistatic = test.statistic + self.chi_Pvalue = test.pvalue + print("-----chisquare Test-----") + print("Statistic = " + str(test.statistic)) + print("P value = " + str(test.pvalue)) + return test.statistic, test.pvalue + except Exception as e: + print(e) + return def confidenceInterval( self, @@ -350,6 +382,7 @@ def probapilityPlot( """ pass + class Gumbel(AbstractDistribution): """Gumbel distribution.""" @@ -680,25 +713,7 @@ def ks(self) -> tuple: Pvalue : [numeric] IF Pvalue < signeficance level ------ reject the null hypotethis """ - if self.parameters is None: - raise ValueError( - "Value of parameters is unknown please use " - "'EstimateParameter' to obtain estimate the distribution parameters" - ) - Qth = self.theporeticalEstimate(self.parameters, self.cdf_Weibul) - - test = ks_2samp(self.data, Qth) - self.Dstatic = test.statistic - self.KS_Pvalue = test.pvalue - - print("-----KS Test--------") - print(f"Statistic = {test.statistic}") - if self.Dstatic < self.KStable: - print("Accept Hypothesis") - else: - print("reject Hypothesis") - print(f"P value = {test.pvalue}") - return test.statistic, test.pvalue + return super().ks() def chisquare(self) -> tuple: """ @@ -707,24 +722,7 @@ def chisquare(self) -> tuple: ------- """ - if self.parameters is None: - raise ValueError( - "Value of loc/scale parameter is unknown please use " - "'EstimateParameter' to obtain them" - ) - - Qth = self.theporeticalEstimate(self.parameters, self.cdf_Weibul) - try: - test = chisquare(st.standardize(Qth), st.standardize(self.data)) - self.chistatic = test.statistic - self.chi_Pvalue = test.pvalue - print("-----chisquare Test-----") - print("Statistic = " + str(test.statistic)) - print("P value = " + str(test.pvalue)) - return test.statistic, test.pvalue - except Exception as e: - print(e) - # raise + return super().chisquare() def confidenceInterval( self, @@ -867,9 +865,9 @@ class GEV(AbstractDistribution): data: ndarray def __init__( - self, - data: Union[list, np.ndarray] = None, - parameters: Dict[str, str] = None, + self, + data: Union[list, np.ndarray] = None, + parameters: Dict[str, str] = None, ): """GEV. @@ -889,14 +887,14 @@ def __init__( pass def pdf( - self, - parameters: Dict[str, Union[float, Any]], - plot_figure: bool = False, - figsize: tuple = (6, 5), - xlabel: str = "Actual data", - ylabel: str = "pdf", - fontsize: int = 15, - actualdata: Union[bool, np.ndarray] = True, + self, + parameters: Dict[str, Union[float, Any]], + plot_figure: bool = False, + figsize: tuple = (6, 5), + xlabel: str = "Actual data", + ylabel: str = "pdf", + fontsize: int = 15, + actualdata: Union[bool, np.ndarray] = True, ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: """pdf. @@ -934,13 +932,12 @@ def pdf( else: ts = actualdata - loc = parameters.get("loc") scale = parameters.get("scale") shape = parameters.get("shape") pdf = [] - for i in range(len(ts)): - z = (ts[i] - loc) / scale + for i, ts_val in enumerate(ts): + z = (ts_val - loc) / scale if shape == 0: val = np.exp(-(z + np.exp(-z))) pdf.append((1 / scale) * val) @@ -1138,7 +1135,6 @@ def estimateParameter( raise ValueError( method + "value should be 'mle', 'mm', 'lmoments' or 'optimization'" ) - if method == "mle" or method == "mm": Param = list(genextreme.fit(self.data, method=method)) elif method == "lmoments": @@ -1149,7 +1145,7 @@ def estimateParameter( if ObjFunc is None or threshold is None: raise TypeError("ObjFunc and threshold should be numeric value") - Param = genextreme.fit(self.data, method=method) + Param = genextreme.fit(self.data, method="mle") # then we use the result as starting value for your truncated Gumbel fit Param = so.fmin( ObjFunc, @@ -1174,8 +1170,8 @@ def estimateParameter( @staticmethod def theporeticalEstimate( - parameters: Dict[str, Union[float, Any]], - F: np.ndarray, + parameters: Dict[str, Union[float, Any]], + F: np.ndarray, ) -> np.ndarray: """TheporeticalEstimate. @@ -1236,52 +1232,19 @@ def ks(self): Pvalue : [numeric] IF Pvalue < signeficance level ------ reject the null hypotethis """ - if self.parameters is None: - raise ValueError( - "Value of loc/scale parameter is unknown please use " - "'EstimateParameter' to obtain them" - ) - Qth = self.theporeticalEstimate(self.parameters, self.cdf_Weibul) - - test = ks_2samp(self.data, Qth) - self.Dstatic = test.statistic - self.KS_Pvalue = test.pvalue - print("-----KS Test--------") - print("Statistic = " + str(test.statistic)) - if self.Dstatic < self.KStable: - print("Accept Hypothesis") - else: - print("reject Hypothesis") - print("P value = " + str(test.pvalue)) - - return test.statistic, test.pvalue + return super().ks() def chisquare(self): - if self.parameters is None: - raise ValueError( - "Value of loc/scale parameter is unknown please use " - "'EstimateParameter' to obtain them" - ) - - Qth = self.theporeticalEstimate(self.parameters, self.cdf_Weibul) - - test = chisquare(st.standardize(Qth), st.standardize(self.data)) - self.chistatic = test.statistic - self.chi_Pvalue = test.pvalue - print("-----chisquare Test-----") - print("Statistic = " + str(test.statistic)) - print("P value = " + str(test.pvalue)) - - return test.statistic, test.pvalue + return super().chisquare() def confidenceInterval( - self, - parameters: Dict[str, Union[float, Any]], - F: np.ndarray, - alpha: float = 0.1, - statfunction=np.average, - n_samples: int = 100, - **kargs, + self, + parameters: Dict[str, Union[float, Any]], + F: np.ndarray, + alpha: float = 0.1, + statfunction=np.average, + n_samples: int = 100, + **kargs, ): """confidenceInterval. @@ -1303,14 +1266,10 @@ def confidenceInterval( Qlower : [list] lower bound coresponding to the confidence interval. """ - loc = parameters.get("loc") scale = parameters.get("scale") - shape = parameters.get("shape") - if scale <= 0: raise ValueError("Scale parameter is negative") - # Param = [shape, loc, scale] CI = ConfidenceInterval.BootStrap( self.data, statfunction=statfunction, diff --git a/tests/test_distributions.py b/tests/test_distributions.py index 619a63c..2715eb4 100644 --- a/tests/test_distributions.py +++ b/tests/test_distributions.py @@ -300,3 +300,6 @@ def test_confidence_interval_directly( assert isinstance(LB, np.ndarray) assert isinstance(UB, np.ndarray) + + +# class TestAbstractDistrition: From 4ff95799174df2f2e2d0c742ed159b331422b0e4 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Wed, 29 Nov 2023 21:00:53 +0100 Subject: [PATCH 08/44] refactor-snake case names --- examples/Extreme value statistics.py | 28 ++++++------ examples/heavy-tail-example.py | 4 +- examples/rhine_example.py | 8 ++-- statista/distributions.py | 66 +++++++++++++++------------- statista/eva.py | 16 +++---- tests/test_distributions.py | 66 ++++++++++++++-------------- 6 files changed, 96 insertions(+), 92 deletions(-) diff --git a/examples/Extreme value statistics.py b/examples/Extreme value statistics.py index 774a37b..16653a7 100644 --- a/examples/Extreme value statistics.py +++ b/examples/Extreme value statistics.py @@ -13,7 +13,7 @@ #%% Gdist = Gumbel(time_series1) # defult parameter estimation method is maximum liklihood method -Param_mle = Gdist.estimateParameter(method="mle") +Param_mle = Gdist.estimate_parameter(method="mle") Gdist.ks() Gdist.chisquare() print(Param_mle) @@ -23,7 +23,7 @@ pdf = Gdist.pdf(loc, scale, plot_figure=True) cdf, _, _ = Gdist.cdf(loc, scale, plot_figure=True) #%% lmoments -Param_lmoments = Gdist.estimateParameter(method="lmoments") +Param_lmoments = Gdist.estimate_parameter(method="lmoments") Gdist.ks() Gdist.chisquare() print(Param_lmoments) @@ -38,38 +38,38 @@ # calculate the F (Non Exceedence probability based on weibul) cdf_Weibul = PlottingPosition.weibul(time_series1) # TheporeticalEstimate method calculates the theoretical values based on the Gumbel distribution -Qth = Gdist.theporeticalEstimate(loc, scale, cdf_Weibul) +Qth = Gdist.theoretical_estimate(loc, scale, cdf_Weibul) # test = stats.chisquare(st.Standardize(Qth), st.Standardize(time_series1),ddof=5) # calculate the confidence interval -upper, lower = Gdist.confidenceInterval(loc, scale, cdf_Weibul, alpha=0.1) +upper, lower = Gdist.confidence_interval(loc, scale, cdf_Weibul, alpha=0.1) # ProbapilityPlot can estimate the Qth and the lower and upper confidence interval in the process of plotting -fig, ax = Gdist.probapilityPlot(loc, scale, cdf_Weibul, alpha=0.1) +fig, ax = Gdist.probapility_plot(loc, scale, cdf_Weibul, alpha=0.1) #%% """ if you want to focus only on high values, you can use a threshold to make the code focus on what is higher this threshold. """ threshold = 17 -Param_dist = Gdist.estimateParameter( +Param_dist = Gdist.estimate_parameter( method="optimization", ObjFunc=Gumbel.ObjectiveFn, threshold=threshold ) print(Param_dist) loc = Param_dist[0] scale = Param_dist[1] -Gdist.probapilityPlot(loc, scale, cdf_Weibul, alpha=0.1) +Gdist.probapility_plot(loc, scale, cdf_Weibul, alpha=0.1) #%% threshold = 18 -Param_dist = Gdist.estimateParameter( +Param_dist = Gdist.estimate_parameter( method="optimization", ObjFunc=Gumbel.ObjectiveFn, threshold=threshold ) print(Param_dist) loc = Param_dist[0] scale = Param_dist[1] -Gdist.probapilityPlot(loc, scale, cdf_Weibul, alpha=0.1) +Gdist.probapility_plot(loc, scale, cdf_Weibul, alpha=0.1) #%% Generalized Extreme Value (GEV) Gevdist = GEV(time_series2) # default parameter estimation method is maximum liklihood method -mle_param = Gevdist.estimateParameter(method="mle") +mle_param = Gevdist.estimate_parameter(method="mle") Gevdist.ks() Gevdist.chisquare() @@ -81,7 +81,7 @@ pdf, fig, ax = Gevdist.pdf(shape, loc, scale, plot_figure=True) cdf, _, _ = Gevdist.cdf(shape, loc, scale, plot_figure=True) #%% lmoment method -lmom_param = Gevdist.estimateParameter(method="lmoments") +lmom_param = Gevdist.estimate_parameter(method="lmoments") print(lmom_param) shape = lmom_param[0] loc = lmom_param[1] @@ -95,10 +95,10 @@ cdf_Weibul = PlottingPosition.weibul(time_series1) T = PlottingPosition.weibul(time_series1, option=2) # TheporeticalEstimate method calculates the theoretical values based on the Gumbel distribution -Qth = Gevdist.theporeticalEstimate(shape, loc, scale, cdf_Weibul) +Qth = Gevdist.theoretical_estimate(shape, loc, scale, cdf_Weibul) func = GEV.ci_func -upper, lower = Gevdist.confidenceInterval( +upper, lower = Gevdist.confidence_interval( shape, loc, scale, @@ -121,6 +121,6 @@ LB = CI["LB"] UB = CI["UB"] #%% -fig, ax = Gevdist.probapilityPlot( +fig, ax = Gevdist.probapility_plot( shape, loc, scale, cdf_Weibul, func=func, n_samples=len(time_series1) ) diff --git a/examples/heavy-tail-example.py b/examples/heavy-tail-example.py index 7f41049..5791849 100644 --- a/examples/heavy-tail-example.py +++ b/examples/heavy-tail-example.py @@ -22,6 +22,6 @@ dung["scipy -ve"] = pdf #%% method = "lmoments" # "mle" -parameters_lm = dist_negative.estimateParameter(method=method) -parameters_mle = dist_negative.estimateParameter(method="mle") +parameters_lm = dist_negative.estimate_parameter(method=method) +parameters_mle = dist_negative.estimate_parameter(method="mle") #%% diff --git a/examples/rhine_example.py b/examples/rhine_example.py index c937851..38619d5 100644 --- a/examples/rhine_example.py +++ b/examples/rhine_example.py @@ -23,7 +23,7 @@ #%% Exponential distribution (mle) dist_obj = Exponential(cologne_gauge) # default parameter estimation method is maximum liklihood method -mle_param = dist_obj.estimateParameter(method="mle") +mle_param = dist_obj.estimate_parameter(method="mle") dist_obj.ks() dist_obj.chisquare() @@ -36,7 +36,7 @@ #%% exponential distribution (lmoments) dist_obj = Exponential(cologne_gauge) # default parameter estimation method is maximum liklihood method -mle_param = dist_obj.estimateParameter(method="lmoments") +mle_param = dist_obj.estimate_parameter(method="lmoments") dist_obj.ks() dist_obj.chisquare() @@ -49,7 +49,7 @@ #%% GEV (mle) gev_cologne = GEV(cologne_gauge) # default parameter estimation method is maximum liklihood method -mle_param = gev_cologne.estimateParameter(method="mle") +mle_param = gev_cologne.estimate_parameter(method="mle") gev_cologne.ks() gev_cologne.chisquare() @@ -64,7 +64,7 @@ #%% cologne (lmoment) gev_cologne = GEV(cologne_gauge) # default parameter estimation method is maximum liklihood method -lmom_param = gev_cologne.estimateParameter(method="lmoments") +lmom_param = gev_cologne.estimate_parameter(method="lmoments") gev_cologne.ks() gev_cologne.chisquare() diff --git a/statista/distributions.py b/statista/distributions.py index a5c8d21..f5f1746 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -24,7 +24,7 @@ def __init__(self): pass @staticmethod - def returnPeriod(F: Union[list, np.ndarray]) -> np.ndarray: + def return_period(F: Union[list, np.ndarray]) -> np.ndarray: """returnPeriod. Parameters @@ -68,11 +68,15 @@ def weibul(data: Union[list, np.ndarray], return_period: int = False) -> np.ndar if not return_period: return cdf else: - T = PlottingPosition.returnPeriod(cdf) + T = PlottingPosition.return_period(cdf) return T class AbstractDistribution: + """ + AbstractDistribution. + """ + parameters: Dict[str, Union[float, Any]] cdf_Weibul: ndarray @@ -164,7 +168,7 @@ def cdf( """ pass - def estimateParameter( + def estimate_parameter( self, method: str = "mle", ObjFunc: Callable = None, @@ -207,7 +211,7 @@ def estimateParameter( pass @staticmethod - def theporeticalEstimate( + def theoretical_estimate( parameters: Dict[str, Union[float, Any]], cdf: np.ndarray ) -> np.ndarray: """theporeticalEstimate. @@ -250,7 +254,7 @@ def ks(self) -> tuple: "Value of parameters is unknown please use " "'EstimateParameter' to obtain estimate the distribution parameters" ) - Qth = self.theporeticalEstimate(self.parameters, self.cdf_Weibul) + Qth = self.theoretical_estimate(self.parameters, self.cdf_Weibul) test = ks_2samp(self.data, Qth) self.Dstatic = test.statistic @@ -278,7 +282,7 @@ def chisquare(self) -> tuple: "'EstimateParameter' to obtain them" ) - Qth = self.theporeticalEstimate(self.parameters, self.cdf_Weibul) + Qth = self.theoretical_estimate(self.parameters, self.cdf_Weibul) try: test = chisquare(st.standardize(Qth), st.standardize(self.data)) self.chistatic = test.statistic @@ -291,7 +295,7 @@ def chisquare(self) -> tuple: print(e) return - def confidenceInterval( + def confidence_interval( self, parameters: Dict[str, Union[float, Any]], F: np.ndarray, @@ -327,7 +331,7 @@ def confidenceInterval( """ pass - def probapilityPlot( + def probapility_plot( self, parameters: Dict[str, Union[float, Any]], F: np.ndarray, @@ -529,7 +533,7 @@ def cdf( else: return cdf - def getRP(self, loc, scale, data): + def get_rp(self, loc, scale, data): """getRP. getRP calculates the return period for a list/array of values or a single value. @@ -582,7 +586,7 @@ def ObjectiveFn(p, x): # print x1, nx2, L1, L2 return L1 + L2 - def estimateParameter( + def estimate_parameter( self, method: str = "mle", ObjFunc: Callable = None, @@ -659,7 +663,7 @@ def estimateParameter( return Param @staticmethod - def theporeticalEstimate( + def theoretical_estimate( parameters: Dict[str, Union[float, Any]], cdf: np.ndarray ) -> np.ndarray: """theporeticalEstimate. @@ -722,7 +726,7 @@ def chisquare(self) -> tuple: """ return super().chisquare() - def confidenceInterval( + def confidence_interval( self, parameters: Dict[str, Union[float, Any]], F: np.ndarray, @@ -761,7 +765,7 @@ def confidenceInterval( if scale <= 0: raise ValueError("Scale parameter is negative") - Qth = self.theporeticalEstimate(parameters, F) + Qth = self.theoretical_estimate(parameters, F) Y = [-np.log(-np.log(j)) for j in F] StdError = [ (scale / np.sqrt(len(self.data))) @@ -773,7 +777,7 @@ def confidenceInterval( Qlower = np.array([Qth[j] - v * StdError[j] for j in range(len(self.data))]) return Qupper, Qlower - def probapilityPlot( + def probapility_plot( self, parameters: Dict[str, Union[float, Any]], F: np.ndarray, @@ -827,8 +831,8 @@ def probapilityPlot( if scale <= 0: raise ValueError("Scale parameter is negative") - Qth = self.theporeticalEstimate(parameters, F) - Qupper, Qlower = self.confidenceInterval(parameters, F, alpha) + Qth = self.theoretical_estimate(parameters, F) + Qupper, Qlower = self.confidence_interval(parameters, F, alpha) Qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 @@ -1053,7 +1057,7 @@ def cdf( else: return cdf - def getRP(self, shape: float, loc: float, scale: float, data: np.ndarray): + def get_rp(self, shape: float, loc: float, scale: float, data: np.ndarray): """getRP. getRP calculates the return period for a list/array of values or a single value. @@ -1083,7 +1087,7 @@ def getRP(self, shape: float, loc: float, scale: float, data: np.ndarray): return rp - def estimateParameter( + def estimate_parameter( self, method: str = "mle", ObjFunc=None, @@ -1161,7 +1165,7 @@ def estimateParameter( return Param @staticmethod - def theporeticalEstimate( + def theoretical_estimate( parameters: Dict[str, Union[float, Any]], F: np.ndarray, ) -> np.ndarray: @@ -1229,7 +1233,7 @@ def ks(self): def chisquare(self): return super().chisquare() - def confidenceInterval( + def confidence_interval( self, parameters: Dict[str, Union[float, Any]], F: np.ndarray, @@ -1285,7 +1289,7 @@ def confidenceInterval( return Qupper, Qlower - def probapilityPlot( + def probapility_plot( self, parameters: Dict[str, Union[float, Any]], F, @@ -1343,7 +1347,7 @@ def probapilityPlot( if scale <= 0: raise ValueError("Scale parameter is negative") - Qth = self.theporeticalEstimate(parameters, F) + Qth = self.theoretical_estimate(parameters, F) if func is None: func = GEV.ci_func @@ -1407,11 +1411,11 @@ def ci_func(data: Union[list, np.ndarray], **kwargs): F = kwargs["F"] method = kwargs["method"] # generate theoretical estimates based on a random cdf, and the dist parameters - sample = GEV.theporeticalEstimate(gevfit, np.random.rand(len(data))) + sample = GEV.theoretical_estimate(gevfit, np.random.rand(len(data))) # get parameters based on the new generated sample Gdist = GEV(sample) - new_param = Gdist.estimateParameter(method=method, test=False) + new_param = Gdist.estimate_parameter(method=method, test=False) # return period # T = np.arange(0.1, 999.1, 0.1) + 1 @@ -1419,7 +1423,7 @@ def ci_func(data: Union[list, np.ndarray], **kwargs): # T = np.linspace(0.1, 999, len(data)) + 1 # coresponding theoretical estimate to T # F = 1 - 1 / T - Qth = GEV.theporeticalEstimate(new_param, F) + Qth = GEV.theoretical_estimate(new_param, F) res = list(new_param.values()) res.extend(Qth) @@ -1871,7 +1875,7 @@ def cdf( else: return cdf - def estimateParameter( + def estimate_parameter( self, method: str = "mle", ObjFunc=None, @@ -1950,7 +1954,7 @@ def estimateParameter( return Param @staticmethod - def theporeticalEstimate( + def theoretical_estimate( loc: Union[float, int], scale: Union[float, int], F: np.ndarray, @@ -1999,7 +2003,7 @@ def ks(self): "Value of loc/scale parameter is unknown please use " "'EstimateParameter' to obtain them" ) - Qth = self.theporeticalEstimate(self.loc, self.scale, self.cdf_Weibul) + Qth = self.theoretical_estimate(self.loc, self.scale, self.cdf_Weibul) test = ks_2samp(self.data, Qth) self.Dstatic = test.statistic @@ -2021,7 +2025,7 @@ def chisquare(self): "'EstimateParameter' to obtain them" ) - Qth = self.theporeticalEstimate(self.loc, self.scale, self.cdf_Weibul) + Qth = self.theoretical_estimate(self.loc, self.scale, self.cdf_Weibul) test = chisquare(st.standardize(Qth), st.standardize(self.data)) self.chistatic = test.statistic @@ -2182,7 +2186,7 @@ def cdf( else: return cdf - def estimateParameter( + def estimate_parameter( self, method: str = "mle", ObjFunc=None, @@ -2261,7 +2265,7 @@ def estimateParameter( return Param @staticmethod - def theporeticalEstimate( + def theoretical_estimate( loc: Union[float, int], scale: Union[float, int], F: np.ndarray, diff --git a/statista/eva.py b/statista/eva.py index 62e13eb..2ec4e15 100644 --- a/statista/eva.py +++ b/statista/eva.py @@ -151,14 +151,14 @@ def ams_analysis( threshold = np.quantile(ams_df, quartile) if distribution == "GEV": dist = GEV(ams_df) - param_dist = dist.estimateParameter( + param_dist = dist.estimate_parameter( method="optimization", ObjFunc=Gumbel.ObjectiveFn, threshold=threshold, ) else: dist = Gumbel(ams_df) - param_dist = dist.estimateParameter( + param_dist = dist.estimate_parameter( method="optimization", ObjFunc=Gumbel.ObjectiveFn, threshold=threshold, @@ -169,12 +169,12 @@ def ams_analysis( if distribution == "GEV": dist = GEV(ams_df) # defult parameter estimation method is maximum liklihood method - param_dist = dist.estimateParameter(method=method) + param_dist = dist.estimate_parameter(method=method) else: # A gumbel distribution is fitted to the annual maxima dist = Gumbel(ams_df) # defult parameter estimation method is maximum liklihood method - param_dist = dist.estimateParameter(method=method) + param_dist = dist.estimate_parameter(method=method) except Exception as e: logger.warning( f"The gauge {i} parameters could not be estimated because of {e}" @@ -196,11 +196,11 @@ def ams_analysis( # Return periods from the fitted distribution are stored. # get the Discharge coresponding to the return periods if distribution == "GEV": - Qrp = dist.theporeticalEstimate( + Qrp = dist.theoretical_estimate( param_dist[0], param_dist[1], param_dist[2], F ) else: - Qrp = dist.theporeticalEstimate(param_dist[0], param_dist[1], F) + Qrp = dist.theoretical_estimate(param_dist[0], param_dist[1], F) # to get the Non Exceedance probability for a specific Value # sort the ams_df @@ -212,7 +212,7 @@ def ams_analysis( # parameters, theoretical cdf (or weibul), and calculate the confidence interval if save_plots: if distribution == "GEV": - fig, ax = dist.probapilityPlot( + fig, ax = dist.probapility_plot( param_dist[0], param_dist[1], param_dist[2], @@ -221,7 +221,7 @@ def ams_analysis( method=method, ) else: - fig, ax = dist.probapilityPlot( + fig, ax = dist.probapility_plot( param_dist[0], param_dist[1], cdf_Weibul, diff --git a/tests/test_distributions.py b/tests/test_distributions.py index 281e913..aaf8ae2 100644 --- a/tests/test_distributions.py +++ b/tests/test_distributions.py @@ -28,7 +28,7 @@ def test_plotting_position_rp( time_series1: list, ): cdf = PlottingPosition.weibul(time_series1, return_period=False) - rp = PlottingPosition.returnPeriod(cdf) + rp = PlottingPosition.return_period(cdf) assert isinstance(rp, np.ndarray) @@ -48,7 +48,7 @@ def test_gumbel_estimate_parameter( ): Gdist = Gumbel(time_series2) for i in range(len(dist_estimation_parameters)): - param = Gdist.estimateParameter( + param = Gdist.estimate_parameter( method=dist_estimation_parameters[i], test=False ) assert isinstance(param, dict) @@ -63,7 +63,7 @@ def test_parameter_estimation_optimization( parameter_estimation_optimization_threshold: int, ): Gdist = Gumbel(time_series2) - param = Gdist.estimateParameter( + param = Gdist.estimate_parameter( method="optimization", ObjFunc=Gumbel.ObjectiveFn, threshold=parameter_estimation_optimization_threshold, @@ -79,7 +79,7 @@ def test_gumbel_ks( dist_estimation_parameters_ks: str, ): Gdist = Gumbel(time_series2) - Gdist.estimateParameter(method=dist_estimation_parameters_ks, test=False) + Gdist.estimate_parameter(method=dist_estimation_parameters_ks, test=False) Gdist.ks() assert Gdist.Dstatic assert Gdist.KS_Pvalue @@ -90,7 +90,7 @@ def test_gumbel_chisquare( dist_estimation_parameters_ks: str, ): Gdist = Gumbel(time_series2) - Gdist.estimateParameter(method=dist_estimation_parameters_ks, test=False) + Gdist.estimate_parameter(method=dist_estimation_parameters_ks, test=False) Gdist.chisquare() assert Gdist.chistatic assert Gdist.chi_Pvalue @@ -101,7 +101,7 @@ def test_gumbel_pdf( dist_estimation_parameters_ks: str, ): Gdist = Gumbel(time_series2) - Param = Gdist.estimateParameter( + Param = Gdist.estimate_parameter( method=dist_estimation_parameters_ks, test=False ) @@ -115,7 +115,7 @@ def test_gumbel_cdf( dist_estimation_parameters_ks: str, ): Gdist = Gumbel(time_series2) - Param = Gdist.estimateParameter( + Param = Gdist.estimate_parameter( method=dist_estimation_parameters_ks, test=False ) cdf, fig, ax = Gdist.cdf(Param, plot_figure=True) @@ -130,10 +130,10 @@ def test_gumbel_TheporeticalEstimate( ): Gdist = Gumbel(time_series2) cdf_Weibul = PlottingPosition.weibul(time_series2) - Param = Gdist.estimateParameter( + Param = Gdist.estimate_parameter( method=dist_estimation_parameters_ks, test=False ) - Qth = Gdist.theporeticalEstimate(Param, cdf_Weibul) + Qth = Gdist.theoretical_estimate(Param, cdf_Weibul) assert isinstance(Qth, np.ndarray) def test_gumbel_confidence_interval( @@ -144,10 +144,10 @@ def test_gumbel_confidence_interval( ): Gdist = Gumbel(time_series2) cdf_Weibul = PlottingPosition.weibul(time_series2) - Param = Gdist.estimateParameter( + Param = Gdist.estimate_parameter( method=dist_estimation_parameters_ks, test=False ) - upper, lower = Gdist.confidenceInterval( + upper, lower = Gdist.confidence_interval( Param, cdf_Weibul, alpha=confidence_interval_alpha ) assert isinstance(upper, np.ndarray) @@ -161,10 +161,10 @@ def test_gumbel_probapility_plot( ): Gdist = Gumbel(time_series2) cdf_Weibul = PlottingPosition.weibul(time_series2) - Param = Gdist.estimateParameter( + Param = Gdist.estimate_parameter( method=dist_estimation_parameters_ks, test=False ) - [fig1, fig2], [ax1, ax2] = Gdist.probapilityPlot( + [fig1, fig2], [ax1, ax2] = Gdist.probapility_plot( Param, cdf_Weibul, alpha=confidence_interval_alpha ) assert isinstance(fig1, Figure) @@ -187,7 +187,7 @@ def test_gev_estimate_parameter( ): Gdist = GEV(time_series1) for i in range(len(dist_estimation_parameters)): - param = Gdist.estimateParameter( + param = Gdist.estimate_parameter( method=dist_estimation_parameters[i], test=False ) @@ -203,7 +203,7 @@ def test_gev_ks( dist_estimation_parameters_ks: str, ): Gdist = GEV(time_series1) - Gdist.estimateParameter(method=dist_estimation_parameters_ks, test=False) + Gdist.estimate_parameter(method=dist_estimation_parameters_ks, test=False) Gdist.ks() assert Gdist.Dstatic assert Gdist.KS_Pvalue @@ -214,7 +214,7 @@ def test_gev_chisquare( dist_estimation_parameters_ks: str, ): Gdist = GEV(time_series1) - Gdist.estimateParameter(method=dist_estimation_parameters_ks, test=False) + Gdist.estimate_parameter(method=dist_estimation_parameters_ks, test=False) Gdist.chisquare() assert Gdist.chistatic assert Gdist.chi_Pvalue @@ -225,7 +225,7 @@ def test_gev_pdf( dist_estimation_parameters_ks: str, ): Gdist = GEV(time_series1) - Param = Gdist.estimateParameter( + Param = Gdist.estimate_parameter( method=dist_estimation_parameters_ks, test=False ) @@ -239,7 +239,7 @@ def test_gev_cdf( dist_estimation_parameters_ks: str, ): Gdist = GEV(time_series1) - Param = Gdist.estimateParameter( + Param = Gdist.estimate_parameter( method=dist_estimation_parameters_ks, test=False ) cdf, fig, ax = Gdist.cdf(Param, plot_figure=True) @@ -253,10 +253,10 @@ def test_gev_TheporeticalEstimate( ): Gdist = GEV(time_series1) cdf_Weibul = PlottingPosition.weibul(time_series1) - Param = Gdist.estimateParameter( + Param = Gdist.estimate_parameter( method=dist_estimation_parameters_ks, test=False ) - Qth = Gdist.theporeticalEstimate(Param, cdf_Weibul) + Qth = Gdist.theoretical_estimate(Param, cdf_Weibul) assert isinstance(Qth, np.ndarray) def test_gev_confidence_interval( @@ -267,12 +267,12 @@ def test_gev_confidence_interval( ): Gdist = GEV(time_series1) cdf_Weibul = PlottingPosition.weibul(time_series1) - Param = Gdist.estimateParameter( + Param = Gdist.estimate_parameter( method=dist_estimation_parameters_ks, test=False ) func = GEV.ci_func - upper, lower = Gdist.confidenceInterval( + upper, lower = Gdist.confidence_interval( Param, F=cdf_Weibul, alpha=confidence_interval_alpha, @@ -290,7 +290,7 @@ def test_confidence_interval_directly( ): Gdist = GEV(time_series1) cdf_Weibul = PlottingPosition.weibul(time_series1) - Param = Gdist.estimateParameter( + Param = Gdist.estimate_parameter( method=dist_estimation_parameters_ks, test=False ) @@ -330,7 +330,7 @@ def test_estimate_parameter( ): Edist = Exponential(time_series2) for i in range(len(dist_estimation_parameters)): - param = Edist.estimateParameter( + param = Edist.estimate_parameter( method=dist_estimation_parameters[i], test=False ) assert isinstance(param, list) @@ -343,7 +343,7 @@ def test_pdf( dist_estimation_parameters_ks: str, ): Edist = Exponential(time_series2) - Param = Edist.estimateParameter( + Param = Edist.estimate_parameter( method=dist_estimation_parameters_ks, test=False ) pdf, fig, ax = Edist.pdf(Param[0], Param[1], plot_figure=True) @@ -356,7 +356,7 @@ def test_cdf( dist_estimation_parameters_ks: str, ): Edist = Exponential(time_series2) - Param = Edist.estimateParameter( + Param = Edist.estimate_parameter( method=dist_estimation_parameters_ks, test=False ) cdf, fig, ax = Edist.cdf(Param[0], Param[1], plot_figure=True) @@ -370,10 +370,10 @@ def test_TheporeticalEstimate( ): Edist = Exponential(time_series2) cdf_Weibul = PlottingPosition.weibul(time_series2) - Param = Edist.estimateParameter( + Param = Edist.estimate_parameter( method=dist_estimation_parameters_ks, test=False ) - Qth = Edist.theporeticalEstimate(Param[0], Param[1], cdf_Weibul) + Qth = Edist.theoretical_estimate(Param[0], Param[1], cdf_Weibul) assert isinstance(Qth, np.ndarray) @@ -393,7 +393,7 @@ def test_estimate_parameter( ): Edist = Normal(time_series2) for method in dist_estimation_parameters: - param = Edist.estimateParameter(method=method, test=False) + param = Edist.estimate_parameter(method=method, test=False) assert isinstance(param, list) assert Edist.loc assert Edist.scale @@ -404,7 +404,7 @@ def test_pdf( dist_estimation_parameters_ks: str, ): Edist = Normal(time_series2) - Param = Edist.estimateParameter( + Param = Edist.estimate_parameter( method=dist_estimation_parameters_ks, test=False ) pdf, fig, ax = Edist.pdf(Param[0], Param[1], plot_figure=True) @@ -417,7 +417,7 @@ def test_cdf( dist_estimation_parameters_ks: str, ): Edist = Normal(time_series2) - Param = Edist.estimateParameter( + Param = Edist.estimate_parameter( method=dist_estimation_parameters_ks, test=False ) cdf, fig, ax = Edist.cdf(Param[0], Param[1], plot_figure=True) @@ -431,8 +431,8 @@ def test_TheporeticalEstimate( ): Edist = Normal(time_series2) cdf_Weibul = PlottingPosition.weibul(time_series2) - Param = Edist.estimateParameter( + Param = Edist.estimate_parameter( method=dist_estimation_parameters_ks, test=False ) - Qth = Edist.theporeticalEstimate(Param[0], Param[1], cdf_Weibul) + Qth = Edist.theoretical_estimate(Param[0], Param[1], cdf_Weibul) assert isinstance(Qth, np.ndarray) From 188685e08ab8fd842af98d88c96a2307bfa31962 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Wed, 29 Nov 2023 21:02:59 +0100 Subject: [PATCH 09/44] ignore pycharm run directory --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 6c9b086..80f014e 100644 --- a/.gitignore +++ b/.gitignore @@ -146,3 +146,4 @@ build_artifacts mo_* conda/ *.zip +.run/ From 6639e75cb3a3d79484cf46bf3e7fe657c3309b7a Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Wed, 29 Nov 2023 21:48:36 +0100 Subject: [PATCH 10/44] move pearson3 to separate branch --- statista/distributions.py | 174 +------------------------------------- 1 file changed, 2 insertions(+), 172 deletions(-) diff --git a/statista/distributions.py b/statista/distributions.py index f5f1746..6bc193e 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -5,7 +5,7 @@ from matplotlib.figure import Figure from numpy import ndarray -from scipy.stats import chisquare, genextreme, gumbel_r, ks_2samp, norm, expon, pearson3 +from scipy.stats import chisquare, genextreme, gumbel_r, ks_2samp, norm, expon from statista.parameters import Lmoments from statista.tools import Tools as st @@ -14,7 +14,7 @@ ninf = 1e-5 -__all__ = ["PlottingPosition", "Gumbel", "GEV", "Exponential", "Normal", "Pearson3"] +__all__ = ["PlottingPosition", "Gumbel", "GEV", "Exponential", "Normal"] class PlottingPosition: @@ -2295,173 +2295,3 @@ def theoretical_estimate( # the main equation from scipy Qth = norm.ppf(F, loc=loc, scale=scale) return Qth - - -class Pearson3: - - data: ndarray - - def __init__( - self, - data: Union[list, np.ndarray] = None, - shape: Union[int, float] = None, - loc: Union[int, float] = None, - scale: Union[int, float] = None, - ): - """GEV. - - Parameters - ---------- - data : [list] - data time series. - shape - loc - scale - """ - if isinstance(data, list) or isinstance(data, np.ndarray): - self.data = np.array(data) - self.data_sorted = np.sort(data) - self.cdf_Weibul = PlottingPosition.weibul(data) - self.KStable = 1.22 / np.sqrt(len(self.data)) - - self.loc = loc - self.scale = scale - self.Dstatic = None - self.KS_Pvalue = None - - self.chistatic = None - self.chi_Pvalue = None - pass - - @staticmethod - def pdf( - self, - loc: Union[float, int], - scale: Union[float, int], - plot_figure: bool = False, - figsize: tuple = (6, 5), - xlabel: str = "Actual data", - ylabel: str = "pdf", - fontsize: int = 15, - actualdata: Union[bool, np.ndarray] = True, - ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: - """pdf. - - Returns the value of GEV's pdf with parameters loc and scale at x . - - Parameters - ---------- - loc : [numeric] - location parameter. - scale : [numeric] - scale parameter. - plot_figure: [bool] - Default is False. - figsize: [tuple] - Default is (6, 5). - xlabel: [str] - Default is "Actual data". - ylabel: [str] - Default is "pdf". - fontsize: [int] - Default is 15. - actualdata : [bool/array] - true if you want to calculate the pdf for the actual time series, array - if you want to calculate the pdf for a theoretical time series - - Returns - ------- - TYPE - DESCRIPTION. - """ - if isinstance(actualdata, bool): - ts = self.data_sorted - else: - ts = actualdata - - pdf = pearson3.pdf(ts, loc=loc, scale=scale) - - if plot_figure: - Qx = np.linspace( - float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 - ) - pdf_fitted = self.pdf(loc, scale, actualdata=Qx) - - fig, ax = Plot.pdf( - Qx, - pdf_fitted, - self.data_sorted, - figsize=figsize, - xlabel=xlabel, - ylabel=ylabel, - fontsize=fontsize, - ) - return pdf, fig, ax - else: - return pdf - - def cdf( - self, - shape: Union[float, int], - loc: Union[float, int], - scale: Union[float, int], - plot_figure: bool = False, - figsize: tuple = (6, 5), - xlabel: str = "Actual data", - ylabel: str = "cdf", - fontsize: int = 15, - actualdata: Union[bool, np.ndarray] = True, - ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: - """cdf. - - Returns the value of Gumbel's cdf with parameters loc and scale - at x. - """ - if scale <= 0: - raise ValueError("Scale parameter is negative") - - if isinstance(actualdata, bool): - ts = self.data - else: - ts = actualdata - - z = (ts - loc) / scale - if shape == 0: - # GEV is Gumbel distribution - cdf = np.exp(-np.exp(-z)) - else: - y = 1 - shape * z - cdf = list() - for y_i in y: - if y_i > ninf: - logY = -np.log(y_i) / shape - cdf.append(np.exp(-np.exp(-logY))) - elif shape < 0: - cdf.append(0) - else: - cdf.append(1) - - cdf = np.array(cdf) - - if plot_figure: - Qx = np.linspace( - float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 - ) - cdf_fitted = self.cdf(shape, loc, scale, actualdata=Qx) - - cdf_Weibul = PlottingPosition.weibul(self.data_sorted) - - fig, ax = Plot.cdf( - Qx, - cdf_fitted, - self.data_sorted, - cdf_Weibul, - figsize=figsize, - xlabel=xlabel, - ylabel=ylabel, - fontsize=fontsize, - ) - - return cdf, fig, ax - else: - return cdf From e630c02ccd62a3c8bb9470809ebc86299414ee8a Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Thu, 30 Nov 2023 13:47:45 +0100 Subject: [PATCH 11/44] exponential class uses the abstract class --- statista/distributions.py | 132 ++++++++++++++---------------------- tests/test_distributions.py | 25 +++---- 2 files changed, 65 insertions(+), 92 deletions(-) diff --git a/statista/distributions.py b/statista/distributions.py index 6bc193e..2cb4dea 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -388,6 +388,7 @@ class Gumbel(AbstractDistribution): cdf_Weibul: ndarray parameters: dict[str, Union[float, Any]] + data: ndarray def __init__( self, @@ -643,6 +644,7 @@ def estimate_parameter( elif method == "optimization": if ObjFunc is None or threshold is None: raise TypeError("threshold should be numeric value") + Param = gumbel_r.fit(self.data, method="mle") # then we use the result as starting value for your truncated Gumbel fit Param = so.fmin( @@ -699,7 +701,7 @@ def theoretical_estimate( Qth = loc - scale * (np.log(-np.log(cdf))) # the main equation form scipy - # Qth = gumbel_r.ppf(F, loc=param_dist[0], scale=param_dist[1]) + # Qth = gumbel_r.ppf(F, loc=loc, scale=scale) return Qth def ks(self) -> tuple: @@ -971,6 +973,7 @@ def pdf( # pdf = np.array(pdf) pdf = genextreme.pdf(ts, loc=loc, scale=scale, c=shape) + if plot_figure: Qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 @@ -1708,47 +1711,34 @@ def ci_func(data: Union[list, np.ndarray], **kwargs): # return Qth -class Exponential: - +class Exponential(AbstractDistribution): """ f(x: threshold, scale) = (1/scale) e **(- (x-threshold)/scale) - """ def __init__( self, data: Union[list, np.ndarray] = None, - loc: Union[int, float] = None, - scale: Union[int, float] = None, + parameters: Dict[str, str] = None, ): - """Gumbel. + """Exponential Distribution. Parameters ---------- data : [list] data time series. - loc: [numeric] - location parameter - scale: [numeric] - scale parameter + parameters: Dict[str, str] + {"loc": val, "scale": val} + - loc: [numeric] + location parameter of the exponential distribution. + - scale: [numeric] + scale parameter of the exponential distribution. """ - if isinstance(data, list) or isinstance(data, np.ndarray): - self.data = np.array(data) - self.data_sorted = np.sort(data) - self.cdf_Weibul = PlottingPosition.weibul(data) - self.KStable = 1.22 / np.sqrt(len(self.data)) - - self.loc = loc - self.scale = scale - self.Dstatic = None - self.KS_Pvalue = None - self.chistatic = None - self.chi_Pvalue = None + super().__init__(data, parameters) def pdf( self, - loc: Union[float, int], - scale: Union[float, int], + parameters: Dict[str, Union[float, Any]], plot_figure: bool = False, figsize: tuple = (6, 5), xlabel: str = "Actual data", @@ -1762,16 +1752,21 @@ def pdf( Parameters: ----------- - loc : [numeric] - location parameter of the gumbel distribution. - scale : [numeric] - scale parameter of the gumbel distribution. + parameters: Dict[str, str] + {"loc": val, "scale": val} + - loc: [numeric] + location parameter of the gumbel distribution. + - scale: [numeric] + scale parameter of the gumbel distribution. Returns ------- pdf : [array] probability density function pdf. """ + loc = parameters.get("loc") + scale = parameters.get("scale") + if scale <= 0: raise ValueError("Scale parameter is negative") @@ -1793,11 +1788,12 @@ def pdf( # pdf = pdf[0] pdf = expon.pdf(ts, loc=loc, scale=scale) + if plot_figure: Qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 ) - pdf_fitted = self.pdf(loc, scale, actualdata=Qx) + pdf_fitted = self.pdf(parameters, actualdata=Qx) fig, ax = Plot.pdf( Qx, @@ -1814,8 +1810,7 @@ def pdf( def cdf( self, - loc: Union[float, int], - scale: Union[float, int], + parameters: Dict[str, Union[float, Any]], plot_figure: bool = False, figsize: tuple = (6, 5), xlabel: str = "data", @@ -1829,11 +1824,15 @@ def cdf( parameter: ---------- - 1- loc : [numeric] + parameters: Dict[str, str] + {"loc": val, "scale": val} + - loc: [numeric] location parameter of the gumbel distribution. - 2- scale : [numeric] + - scale: [numeric] scale parameter of the gumbel distribution. """ + loc = parameters.get("loc") + scale = parameters.get("scale") if scale <= 0: raise ValueError("Scale parameter is negative") if loc <= 0: @@ -1856,7 +1855,7 @@ def cdf( Qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 ) - cdf_fitted = self.cdf(loc, scale, actualdata=Qx) + cdf_fitted = self.cdf(parameters, actualdata=Qx) cdf_Weibul = PlottingPosition.weibul(self.data_sorted) @@ -1941,8 +1940,8 @@ def estimate_parameter( ) Param = [Param[1], Param[2]] - self.loc = Param[0] - self.scale = Param[1] + Param = {"loc": Param[0], "scale": Param[1]} + self.parameters = Param if test: self.ks() @@ -1955,9 +1954,8 @@ def estimate_parameter( @staticmethod def theoretical_estimate( - loc: Union[float, int], - scale: Union[float, int], - F: np.ndarray, + parameters: Dict[str, Union[float, Any]], + cdf: np.ndarray, ) -> np.ndarray: """TheporeticalEstimate. @@ -1965,9 +1963,13 @@ def theoretical_estimate( Parameters: ----------- - param : [list] - location ans scale parameters of the gumbel distribution. - F : [list] + parameters: Dict[str, str] + {"loc": val, "scale": val} + - loc: [numeric] + location parameter of the gumbel distribution. + - scale: [numeric] + scale parameter of the gumbel distribution. + cdf: [list] cummulative distribution function/ Non Exceedence probability. Return: @@ -1975,14 +1977,17 @@ def theoretical_estimate( theoreticalvalue : [numeric] Value based on the theoretical distribution """ + loc = parameters.get("loc") + scale = parameters.get("scale") + if scale <= 0: raise ValueError("Parameters Invalid") - if any(F) < 0 or any(F) > 1: + if any(cdf) < 0 or any(cdf) > 1: raise ValueError("cdf Value Invalid") # the main equation from scipy - Qth = expon.ppf(F, loc=loc, scale=scale) + Qth = expon.ppf(cdf, loc=loc, scale=scale) return Qth def ks(self): @@ -1998,43 +2003,10 @@ def ks(self): Pvalue : [numeric] IF Pvalue < signeficance level ------ reject the null hypotethis """ - if not hasattr(self, "loc") or not hasattr(self, "scale"): - raise ValueError( - "Value of loc/scale parameter is unknown please use " - "'EstimateParameter' to obtain them" - ) - Qth = self.theoretical_estimate(self.loc, self.scale, self.cdf_Weibul) - - test = ks_2samp(self.data, Qth) - self.Dstatic = test.statistic - self.KS_Pvalue = test.pvalue - print("-----KS Test--------") - print("Statistic = " + str(test.statistic)) - if self.Dstatic < self.KStable: - print("Accept Hypothesis") - else: - print("reject Hypothesis") - print("P value = " + str(test.pvalue)) - - return test.statistic, test.pvalue + return super().ks() def chisquare(self): - if not hasattr(self, "loc") or not hasattr(self, "scale"): - raise ValueError( - "Value of loc/scale parameter is unknown please use " - "'EstimateParameter' to obtain them" - ) - - Qth = self.theoretical_estimate(self.loc, self.scale, self.cdf_Weibul) - - test = chisquare(st.standardize(Qth), st.standardize(self.data)) - self.chistatic = test.statistic - self.chi_Pvalue = test.pvalue - print("-----chisquare Test-----") - print("Statistic = " + str(test.statistic)) - print("P value = " + str(test.pvalue)) - - return test.statistic, test.pvalue + return super().chisquare() class Normal: diff --git a/tests/test_distributions.py b/tests/test_distributions.py index aaf8ae2..4522b39 100644 --- a/tests/test_distributions.py +++ b/tests/test_distributions.py @@ -33,7 +33,7 @@ def test_plotting_position_rp( class TestGumbel: - def test_create_gumbel_instance( + def test_create_instance( self, time_series1: list, ): @@ -41,7 +41,7 @@ def test_create_gumbel_instance( assert isinstance(Gdist.data, np.ndarray) assert isinstance(Gdist.data_sorted, np.ndarray) - def test_gumbel_estimate_parameter( + def test_estimate_parameter( self, time_series2: list, dist_estimation_parameters: List[str], @@ -73,7 +73,7 @@ def test_parameter_estimation_optimization( assert Gdist.parameters.get("loc") is not None assert Gdist.parameters.get("scale") is not None - def test_gumbel_ks( + def test_ks( self, time_series2: list, dist_estimation_parameters_ks: str, @@ -84,7 +84,7 @@ def test_gumbel_ks( assert Gdist.Dstatic assert Gdist.KS_Pvalue - def test_gumbel_chisquare( + def test_chisquare( self, time_series2: list, dist_estimation_parameters_ks: str, @@ -95,7 +95,7 @@ def test_gumbel_chisquare( assert Gdist.chistatic assert Gdist.chi_Pvalue - def test_gumbel_pdf( + def test_pdf( self, time_series2: list, dist_estimation_parameters_ks: str, @@ -109,7 +109,7 @@ def test_gumbel_pdf( assert isinstance(pdf, np.ndarray) assert isinstance(fig, Figure) - def test_gumbel_cdf( + def test_cdf( self, time_series2: list, dist_estimation_parameters_ks: str, @@ -333,9 +333,10 @@ def test_estimate_parameter( param = Edist.estimate_parameter( method=dist_estimation_parameters[i], test=False ) - assert isinstance(param, list) - assert Edist.loc - assert Edist.scale + assert isinstance(param, dict) + assert all(i in param.keys() for i in ["loc", "scale"]) + assert Edist.parameters.get("loc") is not None + assert Edist.parameters.get("scale") is not None def test_pdf( self, @@ -346,7 +347,7 @@ def test_pdf( Param = Edist.estimate_parameter( method=dist_estimation_parameters_ks, test=False ) - pdf, fig, ax = Edist.pdf(Param[0], Param[1], plot_figure=True) + pdf, fig, ax = Edist.pdf(Param, plot_figure=True) assert isinstance(pdf, np.ndarray) assert isinstance(fig, Figure) @@ -359,7 +360,7 @@ def test_cdf( Param = Edist.estimate_parameter( method=dist_estimation_parameters_ks, test=False ) - cdf, fig, ax = Edist.cdf(Param[0], Param[1], plot_figure=True) + cdf, fig, ax = Edist.cdf(Param, plot_figure=True) assert isinstance(cdf, np.ndarray) assert isinstance(fig, Figure) @@ -373,7 +374,7 @@ def test_TheporeticalEstimate( Param = Edist.estimate_parameter( method=dist_estimation_parameters_ks, test=False ) - Qth = Edist.theoretical_estimate(Param[0], Param[1], cdf_Weibul) + Qth = Edist.theoretical_estimate(Param, cdf_Weibul) assert isinstance(Qth, np.ndarray) From 01222091358945d7d94fdc5dda023e8122e313fe Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Thu, 30 Nov 2023 17:31:31 +0100 Subject: [PATCH 12/44] refactor --- statista/__init__.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/statista/__init__.py b/statista/__init__.py index 55f2488..149a4ed 100644 --- a/statista/__init__.py +++ b/statista/__init__.py @@ -30,12 +30,6 @@ if missing_dependencies: raise ImportError("Missing required dependencies {0}".format(missing_dependencies)) -# import statista.distributions -# import statista.metrics -# import statista.parameters -# import statista.sensitivity -# import statista.tools - __doc__ = """ statista - statistics package """ From 7e71940c74ce9c6fae036c007dc4e319bcf29b2d Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Fri, 1 Dec 2023 20:48:07 +0100 Subject: [PATCH 13/44] first abstraction of the pdf to the factory method --- statista/distributions.py | 237 ++++++++++++++++++++---------------- tests/test_distributions.py | 19 +-- 2 files changed, 139 insertions(+), 117 deletions(-) diff --git a/statista/distributions.py b/statista/distributions.py index 2cb4dea..7bcccf2 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -1,5 +1,6 @@ """Statistical distributions.""" from typing import Any, List, Tuple, Union, Dict, Callable +from abc import ABC, abstractmethod import numpy as np import scipy.optimize as so from matplotlib.figure import Figure @@ -72,7 +73,7 @@ def weibul(data: Union[list, np.ndarray], return_period: int = False) -> np.ndar return T -class AbstractDistribution: +class AbstractDistribution(ABC): """ AbstractDistribution. """ @@ -113,6 +114,7 @@ def __init__( pass + @abstractmethod def pdf( self, parameters: Dict[str, Union[float, Any]], @@ -121,7 +123,7 @@ def pdf( xlabel: str = "Actual data", ylabel: str = "pdf", fontsize: Union[float, int] = 15, - actualdata: Union[bool, np.ndarray] = True, + actual_data: Union[bool, np.ndarray] = True, ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: """pdf. @@ -141,8 +143,14 @@ def pdf( pdf : [array] probability density function pdf. """ - pass + if actual_data is None: + ts = self.data + else: + ts = actual_data + return ts + + @abstractmethod def cdf( self, parameters: Dict[str, Union[float, Any]], @@ -151,7 +159,7 @@ def cdf( xlabel: str = "data", ylabel: str = "cdf", fontsize: int = 15, - actualdata: Union[bool, np.ndarray] = True, + actual_data: Union[bool, np.ndarray] = True, ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: """cdf. @@ -168,6 +176,7 @@ def cdf( """ pass + @abstractmethod def estimate_parameter( self, method: str = "mle", @@ -411,6 +420,19 @@ def __init__( super().__init__(data, parameters) pass + @staticmethod + def _pdf_eq( + data: Union[list, np.ndarray], parameters: Dict[str, Union[float, Any]] + ) -> np.ndarray: + loc = parameters.get("loc") + scale = parameters.get("scale") + if scale <= 0: + raise ValueError("Scale parameter is negative") + # z = (ts - loc) / scale + # pdf = (1.0 / scale) * (np.exp(-(z + (np.exp(-z))))) + pdf = gumbel_r.pdf(data, loc=loc, scale=scale) + return pdf + def pdf( self, parameters: Dict[str, Union[float, Any]], @@ -419,7 +441,7 @@ def pdf( xlabel: str = "Actual data", ylabel: str = "pdf", fontsize: Union[float, int] = 15, - actualdata: Union[bool, np.ndarray] = True, + actual_data: np.ndarray = None, ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: """pdf. @@ -439,27 +461,15 @@ def pdf( pdf : [array] probability density function pdf. """ - loc = parameters.get("loc") - scale = parameters.get("scale") - - if scale <= 0: - raise ValueError("Scale parameter is negative") - - if isinstance(actualdata, bool): - ts = self.data - else: - ts = actualdata - - # z = (ts - loc) / scale - # pdf = (1.0 / scale) * (np.exp(-(z + (np.exp(-z))))) + ts = super().pdf(parameters, actual_data=actual_data) - pdf = gumbel_r.pdf(ts, loc=loc, scale=scale) + pdf = self._pdf_eq(ts, parameters) if plot_figure: Qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 ) - pdf_fitted = self.pdf(parameters, actualdata=Qx) + pdf_fitted = self.pdf(parameters, actual_data=Qx) fig, ax = Plot.pdf( Qx, @@ -474,6 +484,19 @@ def pdf( else: return pdf + @staticmethod + def _cdf_eq( + data: Union[list, np.ndarray], parameters: Dict[str, Union[float, Any]] + ) -> np.ndarray: + loc = parameters.get("loc") + scale = parameters.get("scale") + if scale <= 0: + raise ValueError("Scale parameter is negative") + # z = (ts - loc) / scale + # cdf = np.exp(-np.exp(-z)) + cdf = gumbel_r.cdf(data, loc=loc, scale=scale) + return cdf + def cdf( self, parameters: Dict[str, Union[float, Any]], @@ -482,7 +505,7 @@ def cdf( xlabel: str = "data", ylabel: str = "cdf", fontsize: int = 15, - actualdata: Union[bool, np.ndarray] = True, + actual_data: Union[bool, np.ndarray] = True, ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: """cdf. @@ -497,25 +520,18 @@ def cdf( - scale: [numeric] scale parameter of the gumbel distribution. """ - loc = parameters.get("loc") - scale = parameters.get("scale") - if scale <= 0: - raise ValueError("Scale parameter is negative") - - if isinstance(actualdata, bool): + if isinstance(actual_data, bool): ts = self.data else: - ts = actualdata + ts = actual_data - # z = (ts - loc) / scale - # cdf = np.exp(-np.exp(-z)) - cdf = gumbel_r.cdf(ts, loc=loc, scale=scale) + cdf = self._cdf_eq(ts, parameters) if plot_figure: Qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 ) - cdf_fitted = self.cdf(parameters, actualdata=Qx) + cdf_fitted = self.cdf(parameters, actual_data=Qx) cdf_Weibul = PlottingPosition.weibul(self.data_sorted) @@ -554,7 +570,7 @@ def get_rp(self, loc, scale, data): return period """ # if isinstance(data, list) or isinstance(data, np.ndarray): - cdf = self.cdf(loc, scale, actualdata=data) + cdf = self.cdf(loc, scale, actual_data=data) # else: # cdf = gumbel_r.cdf(data, loc, scale) @@ -581,9 +597,11 @@ def ObjectiveFn(p, x): # pdf with a scaled pdf # L1 is pdf based parameters = {"loc": loc, "scale": scale} - L1 = (-np.log((Gumbel.pdf(0, parameters, actualdata=x1) / scale))).sum() + pdf = Gumbel._pdf_eq(x1, parameters) + cdf = Gumbel._cdf_eq(threshold, parameters) + L1 = (-np.log((pdf / scale))).sum() # L2 is cdf based - L2 = (-np.log(1 - Gumbel.cdf(0, parameters, actualdata=threshold))) * nx2 + L2 = (-np.log(1 - cdf)) * nx2 # print x1, nx2, L1, L2 return L1 + L2 @@ -594,7 +612,7 @@ def estimate_parameter( threshold: Union[None, float, int] = None, test: bool = True, ) -> Dict[str, str]: - """estimateParameter. + """estimate_parameter. EstimateParameter estimate the distribution parameter based on MLM (Maximum liklihood method), if an objective function is entered as an input @@ -655,6 +673,7 @@ def estimate_parameter( maxfun=500, ) Param = [Param[1], Param[2]] + Param = {"loc": Param[0], "scale": Param[1]} self.parameters = Param @@ -839,8 +858,8 @@ def probapility_plot( Qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 ) - pdf_fitted = self.pdf(parameters, actualdata=Qx) - cdf_fitted = self.cdf(parameters, actualdata=Qx) + pdf_fitted = self.pdf(parameters, actual_data=Qx) + cdf_fitted = self.cdf(parameters, actual_data=Qx) fig, ax = Plot.details( Qx, @@ -900,7 +919,7 @@ def pdf( xlabel: str = "Actual data", ylabel: str = "pdf", fontsize: int = 15, - actualdata: np.ndarray = None, + actual_data: np.ndarray = None, ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: """pdf. @@ -926,7 +945,7 @@ def pdf( Default is "pdf". fontsize: [int] Default is 15. - actualdata : [bool/array] + actual_data : [bool/array] true if you want to calculate the pdf for the actual time series, array if you want to calculate the pdf for a theoretical time series @@ -935,14 +954,10 @@ def pdf( TYPE DESCRIPTION. """ - if actualdata is None: - ts = self.data_sorted - else: - ts = actualdata loc = parameters.get("loc") scale = parameters.get("scale") shape = parameters.get("shape") - + ts = super().pdf(parameters, actual_data=actual_data) # pdf = [] # for ts_i in ts: # z = (ts_i - loc) / scale @@ -978,7 +993,7 @@ def pdf( Qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 ) - pdf_fitted = self.pdf(parameters, actualdata=Qx) + pdf_fitted = self.pdf(parameters, actual_data=Qx) fig, ax = Plot.pdf( Qx, @@ -1001,7 +1016,7 @@ def cdf( xlabel: str = "Actual data", ylabel: str = "cdf", fontsize: int = 11, - actualdata: Union[bool, np.ndarray] = True, + actual_data: Union[bool, np.ndarray] = True, ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: """cdf. @@ -1015,10 +1030,10 @@ def cdf( if scale <= 0: raise ValueError("Scale parameter is negative") - if isinstance(actualdata, bool): + if isinstance(actual_data, bool): ts = self.data else: - ts = actualdata + ts = actual_data # equation https://www.rdocumentation.org/packages/evd/versions/2.3-6/topics/fextreme # z = (ts - loc) / scale # if shape == 0: @@ -1042,7 +1057,7 @@ def cdf( Qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 ) - cdf_fitted = self.cdf(parameters, actualdata=Qx) + cdf_fitted = self.cdf(parameters, actual_data=Qx) cdf_Weibul = PlottingPosition.weibul(self.data_sorted) @@ -1082,7 +1097,7 @@ def get_rp(self, shape: float, loc: float, scale: float, data: np.ndarray): return period """ # if isinstance(data, list) or isinstance(data, np.ndarray): - cdf = self.cdf(shape, loc, scale, actualdata=data) + cdf = self.cdf(shape, loc, scale, actual_data=data) # else: # cdf = genextreme.cdf(data, shape, loc, scale) @@ -1369,8 +1384,8 @@ def probapility_plot( Qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 ) - pdf_fitted = self.pdf(shape, loc, scale, actualdata=Qx) - cdf_fitted = self.cdf(shape, loc, scale, actualdata=Qx) + pdf_fitted = self.pdf(shape, loc, scale, actual_data=Qx) + cdf_fitted = self.cdf(shape, loc, scale, actual_data=Qx) fig, ax = Plot.details( Qx, @@ -1479,7 +1494,7 @@ def ci_func(data: Union[list, np.ndarray], **kwargs): # xlabel: str = "Actual data", # ylabel: str = "pdf", # fontsize: Union[float, int] = 15, -# actualdata: Union[bool, np.ndarray] = True, +# actual_data: Union[bool, np.ndarray] = True, # ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: # """pdf. # @@ -1500,10 +1515,10 @@ def ci_func(data: Union[list, np.ndarray], **kwargs): # if scale <= 0: # raise ValueError("Scale parameter is negative") # -# if isinstance(actualdata, bool): +# if isinstance(actual_data, bool): # ts = self.data # else: -# ts = actualdata +# ts = actual_data # # # pdf = [] # # @@ -1522,7 +1537,7 @@ def ci_func(data: Union[list, np.ndarray], **kwargs): # Qx = np.linspace( # float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 # ) -# pdf_fitted = self.pdf(loc, scale, actualdata=Qx) +# pdf_fitted = self.pdf(loc, scale, actual_data=Qx) # # fig, ax = Plot.pdf( # Qx, @@ -1546,7 +1561,7 @@ def ci_func(data: Union[list, np.ndarray], **kwargs): # xlabel: str = "data", # ylabel: str = "cdf", # fontsize: int = 15, -# actualdata: Union[bool, np.ndarray] = True, +# actual_data: Union[bool, np.ndarray] = True, # ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: # """cdf. # @@ -1564,10 +1579,10 @@ def ci_func(data: Union[list, np.ndarray], **kwargs): # if loc <= 0: # raise ValueError("Threshold parameter should be greater than zero") # -# if isinstance(actualdata, bool): +# if isinstance(actual_data, bool): # ts = self.data # else: -# ts = actualdata +# ts = actual_data # # # Y = (ts - loc) / scale # # cdf = 1 - np.exp(-Y) @@ -1581,7 +1596,7 @@ def ci_func(data: Union[list, np.ndarray], **kwargs): # Qx = np.linspace( # float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 # ) -# cdf_fitted = self.cdf(loc, scale, actualdata=Qx) +# cdf_fitted = self.cdf(loc, scale, actual_data=Qx) # # cdf_Weibul = PlottingPosition.weibul(self.data_sorted) # @@ -1744,7 +1759,7 @@ def pdf( xlabel: str = "Actual data", ylabel: str = "pdf", fontsize: Union[float, int] = 15, - actualdata: Union[bool, np.ndarray] = True, + actual_data: np.ndarray = None, ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: """pdf. @@ -1770,10 +1785,7 @@ def pdf( if scale <= 0: raise ValueError("Scale parameter is negative") - if isinstance(actualdata, bool): - ts = self.data - else: - ts = actualdata + ts = super().pdf(parameters, actual_data=actual_data) # pdf = [] # @@ -1793,7 +1805,7 @@ def pdf( Qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 ) - pdf_fitted = self.pdf(parameters, actualdata=Qx) + pdf_fitted = self.pdf(parameters, actual_data=Qx) fig, ax = Plot.pdf( Qx, @@ -1816,7 +1828,7 @@ def cdf( xlabel: str = "data", ylabel: str = "cdf", fontsize: int = 15, - actualdata: Union[bool, np.ndarray] = True, + actual_data: Union[bool, np.ndarray] = True, ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: """cdf. @@ -1838,10 +1850,10 @@ def cdf( if loc <= 0: raise ValueError("Threshold parameter should be greater than zero") - if isinstance(actualdata, bool): + if isinstance(actual_data, bool): ts = self.data else: - ts = actualdata + ts = actual_data # Y = (ts - loc) / scale # cdf = 1 - np.exp(-Y) @@ -1855,7 +1867,7 @@ def cdf( Qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 ) - cdf_fitted = self.cdf(parameters, actualdata=Qx) + cdf_fitted = self.cdf(parameters, actual_data=Qx) cdf_Weibul = PlottingPosition.weibul(self.data_sorted) @@ -2009,11 +2021,9 @@ def chisquare(self): return super().chisquare() -class Normal: - +class Normal(AbstractDistribution): """ f(x: threshold, scale) = (1/scale) e **(- (x-threshold)/scale) - """ def __init__( @@ -2048,14 +2058,13 @@ def __init__( def pdf( self, - loc: Union[float, int], - scale: Union[float, int], + parameters: Dict[str, Union[float, Any]], plot_figure: bool = False, figsize: tuple = (6, 5), xlabel: str = "Actual data", ylabel: str = "pdf", fontsize: Union[float, int] = 15, - actualdata: Union[bool, np.ndarray] = True, + actual_data: np.ndarray = None, ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: """pdf. @@ -2063,30 +2072,32 @@ def pdf( Parameters: ----------- - loc : [numeric] - location parameter of the gumbel distribution. - scale : [numeric] - scale parameter of the gumbel distribution. + parameters: Dict[str, str] + {"loc": val, "scale": val, "shape": value} + - loc: [numeric] + location parameter of the GEV distribution. + - scale: [numeric] + scale parameter of the GEV distribution. Returns ------- pdf : [array] probability density function pdf. """ + loc = parameters.get("loc") + scale = parameters.get("scale") + if scale <= 0: raise ValueError("Scale parameter is negative") - if isinstance(actualdata, bool): - ts = self.data - else: - ts = actualdata + ts = super().pdf(parameters, actual_data=actual_data) pdf = norm.pdf(ts, loc=loc, scale=scale) if plot_figure: Qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 ) - pdf_fitted = self.pdf(loc, scale, actualdata=Qx) + pdf_fitted = self.pdf(parameters, actual_data=Qx) fig, ax = Plot.pdf( Qx, @@ -2103,35 +2114,39 @@ def pdf( def cdf( self, - loc: Union[float, int], - scale: Union[float, int], + parameters: Dict[str, Union[float, Any]], plot_figure: bool = False, figsize: tuple = (6, 5), xlabel: str = "data", ylabel: str = "cdf", fontsize: int = 15, - actualdata: Union[bool, np.ndarray] = True, + actual_data: Union[bool, np.ndarray] = True, ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: """cdf. - cdf calculates the value of Gumbel's cdf with parameters loc and scale at x. + cdf calculates the value of Normal distribution cdf with parameters loc and scale at x. parameter: ---------- - 1- loc : [numeric] - location parameter of the gumbel distribution. - 2- scale : [numeric] - scale parameter of the gumbel distribution. + parameters: Dict[str, str] + {"loc": val, "scale": val, "shape": value} + - loc: [numeric] + location parameter of the Normal distribution. + - scale: [numeric] + scale parameter of the Normal distribution. """ + loc = parameters.get("loc") + scale = parameters.get("scale") + if scale <= 0: raise ValueError("Scale parameter is negative") if loc <= 0: raise ValueError("Threshold parameter should be greater than zero") - if isinstance(actualdata, bool): + if isinstance(actual_data, bool): ts = self.data else: - ts = actualdata + ts = actual_data cdf = norm.cdf(ts, loc=loc, scale=scale) @@ -2139,7 +2154,7 @@ def cdf( Qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 ) - cdf_fitted = self.cdf(loc, scale, actualdata=Qx) + cdf_fitted = self.cdf(parameters, actual_data=Qx) cdf_Weibul = PlottingPosition.weibul(self.data_sorted) @@ -2224,8 +2239,8 @@ def estimate_parameter( ) Param = [Param[1], Param[2]] - self.loc = Param[0] - self.scale = Param[1] + Param = {"loc": Param[0], "scale": Param[1]} + self.parameters = Param if test: self.ks() @@ -2238,9 +2253,8 @@ def estimate_parameter( @staticmethod def theoretical_estimate( - loc: Union[float, int], - scale: Union[float, int], - F: np.ndarray, + parameters: Dict[str, Union[float, Any]], + cdf: np.ndarray, ) -> np.ndarray: """TheporeticalEstimate. @@ -2248,22 +2262,29 @@ def theoretical_estimate( Parameters: ----------- - param : [list] - location ans scale parameters of the gumbel distribution. - F : [list] + parameters: Dict[str, str] + {"loc": val, "scale": val} + - loc: [numeric] + location parameter of the Normal distribution. + - scale: [numeric] + scale parameter of the Normal distribution. + cdf: [list] cummulative distribution function/ Non Exceedence probability. Return: ------- - theoreticalvalue : [numeric] + numeric: Value based on the theoretical distribution """ + loc = parameters.get("loc") + scale = parameters.get("scale") + if scale <= 0: raise ValueError("Parameters Invalid") - if any(F) < 0 or any(F) > 1: + if any(cdf) < 0 or any(cdf) > 1: raise ValueError("cdf Value Invalid") # the main equation from scipy - Qth = norm.ppf(F, loc=loc, scale=scale) + Qth = norm.ppf(cdf, loc=loc, scale=scale) return Qth diff --git a/tests/test_distributions.py b/tests/test_distributions.py index 4522b39..8e6e613 100644 --- a/tests/test_distributions.py +++ b/tests/test_distributions.py @@ -3,9 +3,9 @@ import numpy as np from matplotlib.figure import Figure +from statista.confidence_interval import ConfidenceInterval from statista.distributions import ( GEV, - ConfidenceInterval, Gumbel, PlottingPosition, Exponential, @@ -123,7 +123,7 @@ def test_cdf( assert isinstance(cdf, np.ndarray) assert isinstance(fig, Figure) - def test_gumbel_TheporeticalEstimate( + def test_gumbel_theoretical_estimate( self, time_series2: list, dist_estimation_parameters_ks: str, @@ -246,7 +246,7 @@ def test_gev_cdf( assert isinstance(cdf, np.ndarray) assert isinstance(fig, Figure) - def test_gev_TheporeticalEstimate( + def test_gev_theoretical_estimate( self, time_series1: list, dist_estimation_parameters_ks: str, @@ -395,9 +395,10 @@ def test_estimate_parameter( Edist = Normal(time_series2) for method in dist_estimation_parameters: param = Edist.estimate_parameter(method=method, test=False) - assert isinstance(param, list) - assert Edist.loc - assert Edist.scale + assert isinstance(param, dict) + assert all(i in param.keys() for i in ["loc", "scale"]) + assert Edist.parameters.get("loc") is not None + assert Edist.parameters.get("scale") is not None def test_pdf( self, @@ -408,7 +409,7 @@ def test_pdf( Param = Edist.estimate_parameter( method=dist_estimation_parameters_ks, test=False ) - pdf, fig, ax = Edist.pdf(Param[0], Param[1], plot_figure=True) + pdf, fig, ax = Edist.pdf(Param, plot_figure=True) assert isinstance(pdf, np.ndarray) assert isinstance(fig, Figure) @@ -421,7 +422,7 @@ def test_cdf( Param = Edist.estimate_parameter( method=dist_estimation_parameters_ks, test=False ) - cdf, fig, ax = Edist.cdf(Param[0], Param[1], plot_figure=True) + cdf, fig, ax = Edist.cdf(Param, plot_figure=True) assert isinstance(cdf, np.ndarray) assert isinstance(fig, Figure) @@ -435,5 +436,5 @@ def test_TheporeticalEstimate( Param = Edist.estimate_parameter( method=dist_estimation_parameters_ks, test=False ) - Qth = Edist.theoretical_estimate(Param[0], Param[1], cdf_Weibul) + Qth = Edist.theoretical_estimate(Param, cdf_Weibul) assert isinstance(Qth, np.ndarray) From e008cae9b7938b40c5d037864e14a56c31d2a507 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Fri, 1 Dec 2023 21:01:50 +0100 Subject: [PATCH 14/44] abstract the pdf caclulation for the gev dist --- statista/distributions.py | 74 ++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/statista/distributions.py b/statista/distributions.py index 7bcccf2..00887e2 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -148,6 +148,7 @@ def pdf( ts = self.data else: ts = actual_data + return ts @abstractmethod @@ -911,6 +912,45 @@ def __init__( super().__init__(data, parameters) pass + @staticmethod + def _pdf_eq( + data: Union[list, np.ndarray], parameters: Dict[str, Union[float, Any]] + ) -> np.ndarray: + loc = parameters.get("loc") + scale = parameters.get("scale") + shape = parameters.get("shape") + # pdf = [] + # for ts_i in ts: + # z = (ts_i - loc) / scale + # + # # Gumbel + # if shape == 0: + # val = np.exp(-(z + np.exp(-z))) + # pdf.append((1 / scale) * val) + # continue + # + # # GEV + # y = 1 - shape * z + # if y > ninf: + # # np.log(y) = ln(y) + # # ln is the inverse of e + # lnY = (-1 / shape) * np.log(y) + # val = np.exp(-(1 - shape) * lnY - np.exp(-lnY)) + # pdf.append((1 / scale) * val) + # continue + # + # if shape < 0: + # pdf.append(0) + # continue + # pdf.append(0) + # + # if len(pdf) == 1: + # pdf = pdf[0] + + # pdf = np.array(pdf) + pdf = genextreme.pdf(data, loc=loc, scale=scale, c=shape) + return pdf + def pdf( self, parameters: Dict[str, Union[float, Any]], @@ -954,40 +994,8 @@ def pdf( TYPE DESCRIPTION. """ - loc = parameters.get("loc") - scale = parameters.get("scale") - shape = parameters.get("shape") ts = super().pdf(parameters, actual_data=actual_data) - # pdf = [] - # for ts_i in ts: - # z = (ts_i - loc) / scale - # - # # Gumbel - # if shape == 0: - # val = np.exp(-(z + np.exp(-z))) - # pdf.append((1 / scale) * val) - # continue - # - # # GEV - # y = 1 - shape * z - # if y > ninf: - # # np.log(y) = ln(y) - # # ln is the inverse of e - # lnY = (-1 / shape) * np.log(y) - # val = np.exp(-(1 - shape) * lnY - np.exp(-lnY)) - # pdf.append((1 / scale) * val) - # continue - # - # if shape < 0: - # pdf.append(0) - # continue - # pdf.append(0) - # - # if len(pdf) == 1: - # pdf = pdf[0] - - # pdf = np.array(pdf) - pdf = genextreme.pdf(ts, loc=loc, scale=scale, c=shape) + pdf = self._pdf_eq(ts, parameters) if plot_figure: Qx = np.linspace( From 181c7570a2ae0a108d54a916d2f23b7785109672 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Fri, 1 Dec 2023 21:09:19 +0100 Subject: [PATCH 15/44] abstract the cdf caclulation for the gev dist --- statista/distributions.py | 54 ++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/statista/distributions.py b/statista/distributions.py index 00887e2..e0d7640 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -1016,6 +1016,34 @@ def pdf( else: return pdf + @staticmethod + def _cdf_eq( + data: Union[list, np.ndarray], parameters: Dict[str, Union[float, Any]] + ) -> np.ndarray: + loc = parameters.get("loc") + scale = parameters.get("scale") + shape = parameters.get("shape") + # equation https://www.rdocumentation.org/packages/evd/versions/2.3-6/topics/fextreme + # z = (ts - loc) / scale + # if shape == 0: + # # GEV is Gumbel distribution + # cdf = np.exp(-np.exp(-z)) + # else: + # y = 1 - shape * z + # cdf = list() + # for y_i in y: + # if y_i > ninf: + # logY = -np.log(y_i) / shape + # cdf.append(np.exp(-np.exp(-logY))) + # elif shape < 0: + # cdf.append(0) + # else: + # cdf.append(1) + # + # cdf = np.array(cdf) + cdf = genextreme.cdf(data, c=shape, loc=loc, scale=scale) + return cdf + def cdf( self, parameters: Dict[str, Union[float, Any]], @@ -1031,9 +1059,9 @@ def cdf( Returns the value of Gumbel's cdf with parameters loc and scale at x. """ - loc = parameters.get("loc") + # loc = parameters.get("loc") scale = parameters.get("scale") - shape = parameters.get("shape") + # shape = parameters.get("shape") if scale <= 0: raise ValueError("Scale parameter is negative") @@ -1042,25 +1070,9 @@ def cdf( ts = self.data else: ts = actual_data - # equation https://www.rdocumentation.org/packages/evd/versions/2.3-6/topics/fextreme - # z = (ts - loc) / scale - # if shape == 0: - # # GEV is Gumbel distribution - # cdf = np.exp(-np.exp(-z)) - # else: - # y = 1 - shape * z - # cdf = list() - # for y_i in y: - # if y_i > ninf: - # logY = -np.log(y_i) / shape - # cdf.append(np.exp(-np.exp(-logY))) - # elif shape < 0: - # cdf.append(0) - # else: - # cdf.append(1) - # - # cdf = np.array(cdf) - cdf = genextreme.cdf(ts, c=shape, loc=loc, scale=scale) + + cdf = self._cdf_eq(ts, parameters) + if plot_figure: Qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 From 9b84585e8e1be2f94b2cd4ef7ee5d9d0505e635e Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Fri, 1 Dec 2023 21:18:03 +0100 Subject: [PATCH 16/44] abstract the pdf and cdf caclulation for the exponential dist --- statista/distributions.py | 70 +++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/statista/distributions.py b/statista/distributions.py index e0d7640..8670bf7 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -1771,6 +1771,27 @@ def __init__( """ super().__init__(data, parameters) + @staticmethod + def _pdf_eq( + data: Union[list, np.ndarray], parameters: Dict[str, Union[float, Any]] + ) -> np.ndarray: + loc = parameters.get("loc") + scale = parameters.get("scale") + # pdf = [] + # + # for i in ts: + # Y = (i - loc) / scale + # if Y <= 0: + # pdf.append(0) + # else: + # pdf.append(np.exp(-Y) / scale) + # + # if len(pdf) == 1: + # pdf = pdf[0] + + pdf = expon.pdf(data, loc=loc, scale=scale) + return pdf + def pdf( self, parameters: Dict[str, Union[float, Any]], @@ -1799,7 +1820,6 @@ def pdf( pdf : [array] probability density function pdf. """ - loc = parameters.get("loc") scale = parameters.get("scale") if scale <= 0: @@ -1807,19 +1827,7 @@ def pdf( ts = super().pdf(parameters, actual_data=actual_data) - # pdf = [] - # - # for i in ts: - # Y = (i - loc) / scale - # if Y <= 0: - # pdf.append(0) - # else: - # pdf.append(np.exp(-Y) / scale) - # - # if len(pdf) == 1: - # pdf = pdf[0] - - pdf = expon.pdf(ts, loc=loc, scale=scale) + pdf = self._pdf_eq(ts, parameters) if plot_figure: Qx = np.linspace( @@ -1840,6 +1848,25 @@ def pdf( else: return pdf + @staticmethod + def _cdf_eq( + data: Union[list, np.ndarray], parameters: Dict[str, Union[float, Any]] + ) -> np.ndarray: + loc = parameters.get("loc") + scale = parameters.get("scale") + if scale <= 0: + raise ValueError("Scale parameter is negative") + if loc <= 0: + raise ValueError("Threshold parameter should be greater than zero") + # Y = (ts - loc) / scale + # cdf = 1 - np.exp(-Y) + # + # for i in range(0, len(cdf)): + # if cdf[i] < 0: + # cdf[i] = 0 + cdf = expon.cdf(data, loc=loc, scale=scale) + return cdf + def cdf( self, parameters: Dict[str, Union[float, Any]], @@ -1863,25 +1890,12 @@ def cdf( - scale: [numeric] scale parameter of the gumbel distribution. """ - loc = parameters.get("loc") - scale = parameters.get("scale") - if scale <= 0: - raise ValueError("Scale parameter is negative") - if loc <= 0: - raise ValueError("Threshold parameter should be greater than zero") - if isinstance(actual_data, bool): ts = self.data else: ts = actual_data - # Y = (ts - loc) / scale - # cdf = 1 - np.exp(-Y) - # - # for i in range(0, len(cdf)): - # if cdf[i] < 0: - # cdf[i] = 0 - cdf = expon.cdf(ts, loc=loc, scale=scale) + cdf = self._cdf_eq(ts, parameters) if plot_figure: Qx = np.linspace( From 94aa5ab6b6fc4283727826b316c53f3a419c2cda Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Fri, 1 Dec 2023 21:24:52 +0100 Subject: [PATCH 17/44] abstract the pdf and cdf caclulation for the normal dist --- statista/distributions.py | 46 +++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/statista/distributions.py b/statista/distributions.py index 8670bf7..2f4d96c 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -2090,6 +2090,18 @@ def __init__( self.chistatic = None self.chi_Pvalue = None + @staticmethod + def _pdf_eq( + data: Union[list, np.ndarray], parameters: Dict[str, Union[float, Any]] + ) -> np.ndarray: + loc = parameters.get("loc") + scale = parameters.get("scale") + if scale <= 0: + raise ValueError("Scale parameter is negative") + pdf = norm.pdf(data, loc=loc, scale=scale) + + return pdf + def pdf( self, parameters: Dict[str, Union[float, Any]], @@ -2118,15 +2130,10 @@ def pdf( pdf : [array] probability density function pdf. """ - loc = parameters.get("loc") - scale = parameters.get("scale") - - if scale <= 0: - raise ValueError("Scale parameter is negative") - ts = super().pdf(parameters, actual_data=actual_data) - pdf = norm.pdf(ts, loc=loc, scale=scale) + pdf = self._pdf_eq(ts, parameters) + if plot_figure: Qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 @@ -2146,6 +2153,21 @@ def pdf( else: return pdf + @staticmethod + def _cdf_eq( + data: Union[list, np.ndarray], parameters: Dict[str, Union[float, Any]] + ) -> np.ndarray: + loc = parameters.get("loc") + scale = parameters.get("scale") + + if scale <= 0: + raise ValueError("Scale parameter is negative") + if loc <= 0: + raise ValueError("Threshold parameter should be greater than zero") + + cdf = norm.cdf(data, loc=loc, scale=scale) + return cdf + def cdf( self, parameters: Dict[str, Union[float, Any]], @@ -2169,20 +2191,12 @@ def cdf( - scale: [numeric] scale parameter of the Normal distribution. """ - loc = parameters.get("loc") - scale = parameters.get("scale") - - if scale <= 0: - raise ValueError("Scale parameter is negative") - if loc <= 0: - raise ValueError("Threshold parameter should be greater than zero") - if isinstance(actual_data, bool): ts = self.data else: ts = actual_data - cdf = norm.cdf(ts, loc=loc, scale=scale) + cdf = self._cdf_eq(ts, parameters) if plot_figure: Qx = np.linspace( From 58b0b8f938ced98a27ae175bf241bdc819e3f343 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Fri, 1 Dec 2023 22:46:07 +0100 Subject: [PATCH 18/44] the pdf method is abstracted in all distributions --- statista/distributions.py | 254 +++++++++++++++++++++----------------- 1 file changed, 138 insertions(+), 116 deletions(-) diff --git a/statista/distributions.py b/statista/distributions.py index 2f4d96c..80b5b10 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -114,6 +114,13 @@ def __init__( pass + @staticmethod + @abstractmethod + def _pdf_eq( + data: Union[list, np.ndarray], parameters: Dict[str, Union[float, Any]] + ) -> np.ndarray: + pass + @abstractmethod def pdf( self, @@ -138,6 +145,13 @@ def pdf( - scale: [numeric] scale parameter of the gumbel distribution. + kwargs: + figsize: tuple = (6, 5), + xlabel: str = "Actual data", + ylabel: str = "pdf", + fontsize: Union[float, int] = 15, + actual_data: np.ndarray = None, + Returns ------- pdf : [array] @@ -149,7 +163,33 @@ def pdf( else: ts = actual_data - return ts + pdf = self._pdf_eq(ts, parameters) + + if plot_figure: + Qx = np.linspace( + float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 + ) + pdf_fitted = self.pdf(parameters, actual_data=Qx) + + fig, ax = Plot.pdf( + Qx, + pdf_fitted, + self.data_sorted, + figsize=figsize, + xlabel=xlabel, + ylabel=ylabel, + fontsize=fontsize, + ) + return pdf, fig, ax + else: + return pdf + + @staticmethod + @abstractmethod + def _cdf_eq( + data: Union[list, np.ndarray], parameters: Dict[str, Union[float, Any]] + ) -> np.ndarray: + pass @abstractmethod def cdf( @@ -438,11 +478,9 @@ def pdf( self, parameters: Dict[str, Union[float, Any]], plot_figure: bool = False, - figsize: tuple = (6, 5), - xlabel: str = "Actual data", - ylabel: str = "pdf", - fontsize: Union[float, int] = 15, actual_data: np.ndarray = None, + *args, + **kwargs, ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: """pdf. @@ -456,34 +494,34 @@ def pdf( location parameter of the gumbel distribution. - scale: [numeric] scale parameter of the gumbel distribution. + actual_data : [bool/array] + true if you want to calculate the pdf for the actual time series, array + if you want to calculate the pdf for a theoretical time series + plot_figure: [bool] + Default is False. + kwargs: + figsize: [tuple] + Default is (6, 5). + xlabel: [str] + Default is "Actual data". + ylabel: [str] + Default is "pdf". + fontsize: [int] + Default is 15. Returns ------- pdf : [array] probability density function pdf. """ - ts = super().pdf(parameters, actual_data=actual_data) - - pdf = self._pdf_eq(ts, parameters) - - if plot_figure: - Qx = np.linspace( - float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 - ) - pdf_fitted = self.pdf(parameters, actual_data=Qx) - - fig, ax = Plot.pdf( - Qx, - pdf_fitted, - self.data_sorted, - figsize=figsize, - xlabel=xlabel, - ylabel=ylabel, - fontsize=fontsize, - ) - return pdf, fig, ax - else: - return pdf + result = super().pdf( + parameters, + actual_data=actual_data, + plot_figure=plot_figure, + *args, + **kwargs, + ) + return result @staticmethod def _cdf_eq( @@ -955,11 +993,9 @@ def pdf( self, parameters: Dict[str, Union[float, Any]], plot_figure: bool = False, - figsize: tuple = (6, 5), - xlabel: str = "Actual data", - ylabel: str = "pdf", - fontsize: int = 15, actual_data: np.ndarray = None, + *args, + **kwargs, ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: """pdf. @@ -975,46 +1011,35 @@ def pdf( scale parameter of the GEV distribution. - shape: [numeric] shape parameter of the GEV distribution. - plot_figure: [bool] - Default is False. - figsize: [tuple] - Default is (6, 5). - xlabel: [str] - Default is "Actual data". - ylabel: [str] - Default is "pdf". - fontsize: [int] - Default is 15. actual_data : [bool/array] true if you want to calculate the pdf for the actual time series, array if you want to calculate the pdf for a theoretical time series + plot_figure: [bool] + Default is False. + kwargs: + figsize: [tuple] + Default is (6, 5). + xlabel: [str] + Default is "Actual data". + ylabel: [str] + Default is "pdf". + fontsize: [int] + Default is 15 Returns ------- TYPE DESCRIPTION. """ - ts = super().pdf(parameters, actual_data=actual_data) - pdf = self._pdf_eq(ts, parameters) - - if plot_figure: - Qx = np.linspace( - float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 - ) - pdf_fitted = self.pdf(parameters, actual_data=Qx) + result = super().pdf( + parameters, + actual_data=actual_data, + plot_figure=plot_figure, + *args, + **kwargs, + ) - fig, ax = Plot.pdf( - Qx, - pdf_fitted, - self.data_sorted, - figsize=figsize, - xlabel=xlabel, - ylabel=ylabel, - fontsize=fontsize, - ) - return pdf, fig, ax - else: - return pdf + return result @staticmethod def _cdf_eq( @@ -1777,6 +1802,10 @@ def _pdf_eq( ) -> np.ndarray: loc = parameters.get("loc") scale = parameters.get("scale") + + if scale <= 0: + raise ValueError("Scale parameter is negative") + # pdf = [] # # for i in ts: @@ -1796,11 +1825,9 @@ def pdf( self, parameters: Dict[str, Union[float, Any]], plot_figure: bool = False, - figsize: tuple = (6, 5), - xlabel: str = "Actual data", - ylabel: str = "pdf", - fontsize: Union[float, int] = 15, actual_data: np.ndarray = None, + *args, + **kwargs, ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: """pdf. @@ -1814,39 +1841,35 @@ def pdf( location parameter of the gumbel distribution. - scale: [numeric] scale parameter of the gumbel distribution. + actual_data : [bool/array] + true if you want to calculate the pdf for the actual time series, array + if you want to calculate the pdf for a theoretical time series + plot_figure: [bool] + Default is False. + kwargs: + figsize: [tuple] + Default is (6, 5). + xlabel: [str] + Default is "Actual data". + ylabel: [str] + Default is "pdf". + fontsize: [int] + Default is 15 Returns ------- pdf : [array] probability density function pdf. """ - scale = parameters.get("scale") - - if scale <= 0: - raise ValueError("Scale parameter is negative") - - ts = super().pdf(parameters, actual_data=actual_data) - - pdf = self._pdf_eq(ts, parameters) + result = super().pdf( + parameters, + actual_data=actual_data, + plot_figure=plot_figure, + *args, + **kwargs, + ) - if plot_figure: - Qx = np.linspace( - float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 - ) - pdf_fitted = self.pdf(parameters, actual_data=Qx) - - fig, ax = Plot.pdf( - Qx, - pdf_fitted, - self.data_sorted, - figsize=figsize, - xlabel=xlabel, - ylabel=ylabel, - fontsize=fontsize, - ) - return pdf, fig, ax - else: - return pdf + return result @staticmethod def _cdf_eq( @@ -2106,11 +2129,9 @@ def pdf( self, parameters: Dict[str, Union[float, Any]], plot_figure: bool = False, - figsize: tuple = (6, 5), - xlabel: str = "Actual data", - ylabel: str = "pdf", - fontsize: Union[float, int] = 15, actual_data: np.ndarray = None, + *args, + **kwargs, ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: """pdf. @@ -2124,34 +2145,35 @@ def pdf( location parameter of the GEV distribution. - scale: [numeric] scale parameter of the GEV distribution. + actual_data : [bool/array] + true if you want to calculate the pdf for the actual time series, array + if you want to calculate the pdf for a theoretical time series + plot_figure: [bool] + Default is False. + kwargs: + figsize: [tuple] + Default is (6, 5). + xlabel: [str] + Default is "Actual data". + ylabel: [str] + Default is "pdf". + fontsize: [int] + Default is 15 Returns ------- pdf : [array] probability density function pdf. """ - ts = super().pdf(parameters, actual_data=actual_data) - - pdf = self._pdf_eq(ts, parameters) - - if plot_figure: - Qx = np.linspace( - float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 - ) - pdf_fitted = self.pdf(parameters, actual_data=Qx) + result = super().pdf( + parameters, + actual_data=actual_data, + plot_figure=plot_figure, + *args, + **kwargs, + ) - fig, ax = Plot.pdf( - Qx, - pdf_fitted, - self.data_sorted, - figsize=figsize, - xlabel=xlabel, - ylabel=ylabel, - fontsize=fontsize, - ) - return pdf, fig, ax - else: - return pdf + return result @staticmethod def _cdf_eq( From fff9487a323f0a9551a0df47988c7adb65a72716 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Fri, 1 Dec 2023 23:03:14 +0100 Subject: [PATCH 19/44] the cdf method is abstracted in all distributions --- statista/distributions.py | 276 +++++++++++++++++++------------------- 1 file changed, 135 insertions(+), 141 deletions(-) diff --git a/statista/distributions.py b/statista/distributions.py index 80b5b10..6085e2f 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -215,7 +215,35 @@ def cdf( - scale: [numeric] scale parameter of the gumbel distribution. """ - pass + if isinstance(actual_data, bool): + ts = self.data + else: + ts = actual_data + + cdf = self._cdf_eq(ts, parameters) + + if plot_figure: + Qx = np.linspace( + float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 + ) + cdf_fitted = self.cdf(parameters, actual_data=Qx) + + cdf_Weibul = PlottingPosition.weibul(self.data_sorted) + + fig, ax = Plot.cdf( + Qx, + cdf_fitted, + self.data_sorted, + cdf_Weibul, + figsize=figsize, + xlabel=xlabel, + ylabel=ylabel, + fontsize=fontsize, + ) + + return cdf, fig, ax + else: + return cdf @abstractmethod def estimate_parameter( @@ -540,11 +568,9 @@ def cdf( self, parameters: Dict[str, Union[float, Any]], plot_figure: bool = False, - figsize: tuple = (6, 5), - xlabel: str = "data", - ylabel: str = "cdf", - fontsize: int = 15, actual_data: Union[bool, np.ndarray] = True, + *args, + **kwargs, ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: """cdf. @@ -558,36 +584,29 @@ def cdf( location parameter of the gumbel distribution. - scale: [numeric] scale parameter of the gumbel distribution. + actual_data : [bool/array] + true if you want to calculate the pdf for the actual time series, array + if you want to calculate the pdf for a theoretical time series + plot_figure: [bool] + Default is False. + kwargs: + figsize: [tuple] + Default is (6, 5). + xlabel: [str] + Default is "Actual data". + ylabel: [str] + Default is "cdf". + fontsize: [int] + Default is 15. """ - if isinstance(actual_data, bool): - ts = self.data - else: - ts = actual_data - - cdf = self._cdf_eq(ts, parameters) - - if plot_figure: - Qx = np.linspace( - float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 - ) - cdf_fitted = self.cdf(parameters, actual_data=Qx) - - cdf_Weibul = PlottingPosition.weibul(self.data_sorted) - - fig, ax = Plot.cdf( - Qx, - cdf_fitted, - self.data_sorted, - cdf_Weibul, - figsize=figsize, - xlabel=xlabel, - ylabel=ylabel, - fontsize=fontsize, - ) - - return cdf, fig, ax - else: - return cdf + result = super().cdf( + parameters, + actual_data=actual_data, + plot_figure=plot_figure, + *args, + **kwargs, + ) + return result def get_rp(self, loc, scale, data): """getRP. @@ -1073,52 +1092,45 @@ def cdf( self, parameters: Dict[str, Union[float, Any]], plot_figure: bool = False, - figsize: tuple = (6, 5), - xlabel: str = "Actual data", - ylabel: str = "cdf", - fontsize: int = 11, actual_data: Union[bool, np.ndarray] = True, + *args, + **kwargs, ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: """cdf. - Returns the value of Gumbel's cdf with parameters loc and scale - at x. - """ - # loc = parameters.get("loc") - scale = parameters.get("scale") - # shape = parameters.get("shape") - - if scale <= 0: - raise ValueError("Scale parameter is negative") - - if isinstance(actual_data, bool): - ts = self.data - else: - ts = actual_data - - cdf = self._cdf_eq(ts, parameters) - - if plot_figure: - Qx = np.linspace( - float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 - ) - cdf_fitted = self.cdf(parameters, actual_data=Qx) - - cdf_Weibul = PlottingPosition.weibul(self.data_sorted) + cdf calculates the value of Gumbel's cdf with parameters loc and scale at x. - fig, ax = Plot.cdf( - Qx, - cdf_fitted, - self.data_sorted, - cdf_Weibul, - figsize=figsize, - xlabel=xlabel, - ylabel=ylabel, - fontsize=fontsize, - ) - return cdf, fig, ax - else: - return cdf + parameter: + ---------- + parameters: Dict[str, str] + {"loc": val, "scale": val} + - loc: [numeric] + location parameter of the gumbel distribution. + - scale: [numeric] + scale parameter of the gumbel distribution. + actual_data : [bool/array] + true if you want to calculate the pdf for the actual time series, array + if you want to calculate the pdf for a theoretical time series + plot_figure: [bool] + Default is False. + kwargs: + figsize: [tuple] + Default is (6, 5). + xlabel: [str] + Default is "Actual data". + ylabel: [str] + Default is "cdf". + fontsize: [int] + Default is 15. + """ + result = super().cdf( + parameters, + actual_data=actual_data, + plot_figure=plot_figure, + *args, + **kwargs, + ) + return result def get_rp(self, shape: float, loc: float, scale: float, data: np.ndarray): """getRP. @@ -1894,11 +1906,9 @@ def cdf( self, parameters: Dict[str, Union[float, Any]], plot_figure: bool = False, - figsize: tuple = (6, 5), - xlabel: str = "data", - ylabel: str = "cdf", - fontsize: int = 15, actual_data: Union[bool, np.ndarray] = True, + *args, + **kwargs, ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: """cdf. @@ -1912,36 +1922,29 @@ def cdf( location parameter of the gumbel distribution. - scale: [numeric] scale parameter of the gumbel distribution. + actual_data : [bool/array] + true if you want to calculate the pdf for the actual time series, array + if you want to calculate the pdf for a theoretical time series + plot_figure: [bool] + Default is False. + kwargs: + figsize: [tuple] + Default is (6, 5). + xlabel: [str] + Default is "Actual data". + ylabel: [str] + Default is "cdf". + fontsize: [int] + Default is 15. """ - if isinstance(actual_data, bool): - ts = self.data - else: - ts = actual_data - - cdf = self._cdf_eq(ts, parameters) - - if plot_figure: - Qx = np.linspace( - float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 - ) - cdf_fitted = self.cdf(parameters, actual_data=Qx) - - cdf_Weibul = PlottingPosition.weibul(self.data_sorted) - - fig, ax = Plot.cdf( - Qx, - cdf_fitted, - self.data_sorted, - cdf_Weibul, - figsize=figsize, - xlabel=xlabel, - ylabel=ylabel, - fontsize=fontsize, - ) - - return cdf, fig, ax - else: - return cdf + result = super().cdf( + parameters, + actual_data=actual_data, + plot_figure=plot_figure, + *args, + **kwargs, + ) + return result def estimate_parameter( self, @@ -2194,11 +2197,9 @@ def cdf( self, parameters: Dict[str, Union[float, Any]], plot_figure: bool = False, - figsize: tuple = (6, 5), - xlabel: str = "data", - ylabel: str = "cdf", - fontsize: int = 15, actual_data: Union[bool, np.ndarray] = True, + *args, + **kwargs, ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: """cdf. @@ -2212,36 +2213,29 @@ def cdf( location parameter of the Normal distribution. - scale: [numeric] scale parameter of the Normal distribution. + actual_data : [bool/array] + true if you want to calculate the pdf for the actual time series, array + if you want to calculate the pdf for a theoretical time series + plot_figure: [bool] + Default is False. + kwargs: + figsize: [tuple] + Default is (6, 5). + xlabel: [str] + Default is "Actual data". + ylabel: [str] + Default is "cdf". + fontsize: [int] + Default is 15. """ - if isinstance(actual_data, bool): - ts = self.data - else: - ts = actual_data - - cdf = self._cdf_eq(ts, parameters) - - if plot_figure: - Qx = np.linspace( - float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 - ) - cdf_fitted = self.cdf(parameters, actual_data=Qx) - - cdf_Weibul = PlottingPosition.weibul(self.data_sorted) - - fig, ax = Plot.cdf( - Qx, - cdf_fitted, - self.data_sorted, - cdf_Weibul, - figsize=figsize, - xlabel=xlabel, - ylabel=ylabel, - fontsize=fontsize, - ) - - return cdf, fig, ax - else: - return cdf + result = super().cdf( + parameters, + actual_data=actual_data, + plot_figure=plot_figure, + *args, + **kwargs, + ) + return result def estimate_parameter( self, From 9a6201fb63b72d7894a901524d0b4d8fc4da788b Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Fri, 1 Dec 2023 23:38:24 +0100 Subject: [PATCH 20/44] abstract fit_model --- examples/Extreme value statistics.py | 36 ++++++------ examples/heavy-tail-example.py | 4 +- examples/rhine_example.py | 8 +-- statista/distributions.py | 63 ++++++++++---------- statista/eva.py | 8 +-- tests/test_distributions.py | 88 ++++++++-------------------- 6 files changed, 83 insertions(+), 124 deletions(-) diff --git a/examples/Extreme value statistics.py b/examples/Extreme value statistics.py index 16653a7..9293dad 100644 --- a/examples/Extreme value statistics.py +++ b/examples/Extreme value statistics.py @@ -10,20 +10,18 @@ time_series1 = pd.read_csv("examples/data/time_series1.txt", header=None)[0].tolist() time_series2 = pd.read_csv("examples/data/time_series2.txt", header=None)[0].tolist() -#%% +# %% Gdist = Gumbel(time_series1) # defult parameter estimation method is maximum liklihood method -Param_mle = Gdist.estimate_parameter(method="mle") +Param_mle = Gdist.fit_model(method="mle") Gdist.ks() Gdist.chisquare() print(Param_mle) -loc = Param_mle[0] -scale = Param_mle[1] # calculate and plot the pdf -pdf = Gdist.pdf(loc, scale, plot_figure=True) -cdf, _, _ = Gdist.cdf(loc, scale, plot_figure=True) -#%% lmoments -Param_lmoments = Gdist.estimate_parameter(method="lmoments") +pdf = Gdist.pdf(Param_mle, plot_figure=True) +cdf, _, _ = Gdist.cdf(Param_mle, plot_figure=True) +# %% lmoments +Param_lmoments = Gdist.fit_model(method="lmoments") Gdist.ks() Gdist.chisquare() print(Param_lmoments) @@ -32,7 +30,7 @@ # calculate and plot the pdf pdf = Gdist.pdf(loc, scale, plot_figure=True) cdf, _, _ = Gdist.cdf(loc, scale, plot_figure=True) -#%% +# %% # calculate the CDF(Non Exceedance probability) using weibul plotting position time_series1.sort() # calculate the F (Non Exceedence probability based on weibul) @@ -44,32 +42,32 @@ upper, lower = Gdist.confidence_interval(loc, scale, cdf_Weibul, alpha=0.1) # ProbapilityPlot can estimate the Qth and the lower and upper confidence interval in the process of plotting fig, ax = Gdist.probapility_plot(loc, scale, cdf_Weibul, alpha=0.1) -#%% +# %% """ if you want to focus only on high values, you can use a threshold to make the code focus on what is higher this threshold. """ threshold = 17 -Param_dist = Gdist.estimate_parameter( +Param_dist = Gdist.fit_model( method="optimization", ObjFunc=Gumbel.ObjectiveFn, threshold=threshold ) print(Param_dist) loc = Param_dist[0] scale = Param_dist[1] Gdist.probapility_plot(loc, scale, cdf_Weibul, alpha=0.1) -#%% +# %% threshold = 18 -Param_dist = Gdist.estimate_parameter( +Param_dist = Gdist.fit_model( method="optimization", ObjFunc=Gumbel.ObjectiveFn, threshold=threshold ) print(Param_dist) loc = Param_dist[0] scale = Param_dist[1] Gdist.probapility_plot(loc, scale, cdf_Weibul, alpha=0.1) -#%% Generalized Extreme Value (GEV) +# %% Generalized Extreme Value (GEV) Gevdist = GEV(time_series2) # default parameter estimation method is maximum liklihood method -mle_param = Gevdist.estimate_parameter(method="mle") +mle_param = Gevdist.fit_model(method="mle") Gevdist.ks() Gevdist.chisquare() @@ -80,8 +78,8 @@ # calculate and plot the pdf pdf, fig, ax = Gevdist.pdf(shape, loc, scale, plot_figure=True) cdf, _, _ = Gevdist.cdf(shape, loc, scale, plot_figure=True) -#%% lmoment method -lmom_param = Gevdist.estimate_parameter(method="lmoments") +# %% lmoment method +lmom_param = Gevdist.fit_model(method="lmoments") print(lmom_param) shape = lmom_param[0] loc = lmom_param[1] @@ -107,7 +105,7 @@ statfunction=func, n_samples=len(time_series1), ) -#%% +# %% """ calculate the confidence interval using the boot strap method directly """ @@ -120,7 +118,7 @@ ) LB = CI["LB"] UB = CI["UB"] -#%% +# %% fig, ax = Gevdist.probapility_plot( shape, loc, scale, cdf_Weibul, func=func, n_samples=len(time_series1) ) diff --git a/examples/heavy-tail-example.py b/examples/heavy-tail-example.py index 5791849..d16a4bf 100644 --- a/examples/heavy-tail-example.py +++ b/examples/heavy-tail-example.py @@ -22,6 +22,6 @@ dung["scipy -ve"] = pdf #%% method = "lmoments" # "mle" -parameters_lm = dist_negative.estimate_parameter(method=method) -parameters_mle = dist_negative.estimate_parameter(method="mle") +parameters_lm = dist_negative.fit_model(method=method) +parameters_mle = dist_negative.fit_model(method="mle") #%% diff --git a/examples/rhine_example.py b/examples/rhine_example.py index 38619d5..1e0ad65 100644 --- a/examples/rhine_example.py +++ b/examples/rhine_example.py @@ -23,7 +23,7 @@ #%% Exponential distribution (mle) dist_obj = Exponential(cologne_gauge) # default parameter estimation method is maximum liklihood method -mle_param = dist_obj.estimate_parameter(method="mle") +mle_param = dist_obj.fit_model(method="mle") dist_obj.ks() dist_obj.chisquare() @@ -36,7 +36,7 @@ #%% exponential distribution (lmoments) dist_obj = Exponential(cologne_gauge) # default parameter estimation method is maximum liklihood method -mle_param = dist_obj.estimate_parameter(method="lmoments") +mle_param = dist_obj.fit_model(method="lmoments") dist_obj.ks() dist_obj.chisquare() @@ -49,7 +49,7 @@ #%% GEV (mle) gev_cologne = GEV(cologne_gauge) # default parameter estimation method is maximum liklihood method -mle_param = gev_cologne.estimate_parameter(method="mle") +mle_param = gev_cologne.fit_model(method="mle") gev_cologne.ks() gev_cologne.chisquare() @@ -64,7 +64,7 @@ #%% cologne (lmoment) gev_cologne = GEV(cologne_gauge) # default parameter estimation method is maximum liklihood method -lmom_param = gev_cologne.estimate_parameter(method="lmoments") +lmom_param = gev_cologne.fit_model(method="lmoments") gev_cologne.ks() gev_cologne.chisquare() diff --git a/statista/distributions.py b/statista/distributions.py index 6085e2f..fd84ab0 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -246,13 +246,13 @@ def cdf( return cdf @abstractmethod - def estimate_parameter( + def fit_model( self, method: str = "mle", ObjFunc: Callable = None, threshold: Union[None, float, int] = None, test: bool = True, - ) -> Dict[str, str]: + ) -> Union[Dict[str, str], Any]: """estimateParameter. EstimateParameter estimate the distribution parameter based on MLM @@ -286,7 +286,12 @@ def estimate_parameter( - scale: [numeric] scale parameter of the gumbel distribution. """ - pass + method = method.lower() + if method not in ["mle", "mm", "lmoments", "optimization"]: + raise ValueError( + f"{method} value should be 'mle', 'mm', 'lmoments' or 'optimization'" + ) + return method @staticmethod def theoretical_estimate( @@ -663,13 +668,13 @@ def ObjectiveFn(p, x): # print x1, nx2, L1, L2 return L1 + L2 - def estimate_parameter( + def fit_model( self, method: str = "mle", ObjFunc: Callable = None, threshold: Union[None, float, int] = None, test: bool = True, - ) -> Dict[str, str]: + ) -> Dict[str, float]: """estimate_parameter. EstimateParameter estimate the distribution parameter based on MLM @@ -706,11 +711,8 @@ def estimate_parameter( # obj_func = lambda p, x: (-np.log(Gumbel.pdf(x, p[0], p[1]))).sum() # #first we make a simple Gumbel fit # Par1 = so.fmin(obj_func, [0.5,0.5], args=(np.array(data),)) - method = method.lower() - if method not in ["mle", "mm", "lmoments", "optimization"]: - raise ValueError( - f"{method} value should be 'mle', 'mm', 'lmoments' or 'optimization'" - ) + method = super().fit_model(method=method) + if method == "mle" or method == "mm": Param = list(gumbel_r.fit(self.data, method=method)) elif method == "lmoments": @@ -731,6 +733,8 @@ def estimate_parameter( maxfun=500, ) Param = [Param[1], Param[2]] + else: + raise ValueError(f"The given: {method} does not exist") Param = {"loc": Param[0], "scale": Param[1]} self.parameters = Param @@ -1162,13 +1166,13 @@ def get_rp(self, shape: float, loc: float, scale: float, data: np.ndarray): return rp - def estimate_parameter( + def fit_model( self, method: str = "mle", ObjFunc=None, threshold: Union[int, float, None] = None, test: bool = True, - ) -> Dict[str, Any]: + ) -> Dict[str, float]: """estimateParameter. EstimateParameter estimate the distribution parameter based on MLM @@ -1201,11 +1205,8 @@ def estimate_parameter( # obj_func = lambda p, x: (-np.log(Gumbel.pdf(x, p[0], p[1]))).sum() # #first we make a simple Gumbel fit # Par1 = so.fmin(obj_func, [0.5,0.5], args=(np.array(data),)) - method = method.lower() - if method not in ["mle", "mm", "lmoments", "optimization"]: - raise ValueError( - method + "value should be 'mle', 'mm', 'lmoments' or 'optimization'" - ) + + method = super().fit_model(method=method) if method == "mle" or method == "mm": Param = list(genextreme.fit(self.data, method=method)) elif method == "lmoments": @@ -1226,6 +1227,8 @@ def estimate_parameter( maxfun=500, ) Param = [Param[1], Param[2], Param[3]] + else: + raise ValueError(f"The given: {method} does not exist") Param = {"loc": Param[1], "scale": Param[2], "shape": Param[0]} self.parameters = Param @@ -1490,7 +1493,7 @@ def ci_func(data: Union[list, np.ndarray], **kwargs): # get parameters based on the new generated sample Gdist = GEV(sample) - new_param = Gdist.estimate_parameter(method=method, test=False) + new_param = Gdist.fit_model(method=method, test=False) # return period # T = np.arange(0.1, 999.1, 0.1) + 1 @@ -1946,13 +1949,13 @@ def cdf( ) return result - def estimate_parameter( + def fit_model( self, method: str = "mle", ObjFunc=None, threshold: Union[int, float, None] = None, test: bool = True, - ) -> tuple: + ) -> Dict[str, float]: """estimateParameter. EstimateParameter estimate the distribution parameter based on MLM @@ -1985,11 +1988,7 @@ def estimate_parameter( # obj_func = lambda p, x: (-np.log(Gumbel.pdf(x, p[0], p[1]))).sum() # #first we make a simple Gumbel fit # Par1 = so.fmin(obj_func, [0.5,0.5], args=(np.array(data),)) - method = method.lower() - if method not in ["mle", "mm", "lmoments", "optimization"]: - raise ValueError( - method + "value should be 'mle', 'mm', 'lmoments' or 'optimization'" - ) + method = super().fit_model(method=method) if method == "mle" or method == "mm": Param = list(expon.fit(self.data, method=method)) @@ -2011,6 +2010,8 @@ def estimate_parameter( maxfun=500, ) Param = [Param[1], Param[2]] + else: + raise ValueError(f"The given: {method} does not exist") Param = {"loc": Param[0], "scale": Param[1]} self.parameters = Param @@ -2237,13 +2238,13 @@ def cdf( ) return result - def estimate_parameter( + def fit_model( self, method: str = "mle", ObjFunc=None, threshold: Union[int, float, None] = None, test: bool = True, - ) -> tuple: + ) -> Dict[str, float]: """estimateParameter. EstimateParameter estimate the distribution parameter based on MLM @@ -2276,11 +2277,7 @@ def estimate_parameter( # obj_func = lambda p, x: (-np.log(Gumbel.pdf(x, p[0], p[1]))).sum() # #first we make a simple Gumbel fit # Par1 = so.fmin(obj_func, [0.5,0.5], args=(np.array(data),)) - method = method.lower() - if method not in ["mle", "mm", "lmoments", "optimization"]: - raise ValueError( - method + "value should be 'mle', 'mm', 'lmoments' or 'optimization'" - ) + method = super().fit_model(method=method) if method == "mle" or method == "mm": Param = list(norm.fit(self.data, method=method)) @@ -2302,6 +2299,8 @@ def estimate_parameter( maxfun=500, ) Param = [Param[1], Param[2]] + else: + raise ValueError(f"The given: {method} does not exist") Param = {"loc": Param[0], "scale": Param[1]} self.parameters = Param diff --git a/statista/eva.py b/statista/eva.py index 2ec4e15..1a96af9 100644 --- a/statista/eva.py +++ b/statista/eva.py @@ -151,14 +151,14 @@ def ams_analysis( threshold = np.quantile(ams_df, quartile) if distribution == "GEV": dist = GEV(ams_df) - param_dist = dist.estimate_parameter( + param_dist = dist.fit_model( method="optimization", ObjFunc=Gumbel.ObjectiveFn, threshold=threshold, ) else: dist = Gumbel(ams_df) - param_dist = dist.estimate_parameter( + param_dist = dist.fit_model( method="optimization", ObjFunc=Gumbel.ObjectiveFn, threshold=threshold, @@ -169,12 +169,12 @@ def ams_analysis( if distribution == "GEV": dist = GEV(ams_df) # defult parameter estimation method is maximum liklihood method - param_dist = dist.estimate_parameter(method=method) + param_dist = dist.fit_model(method=method) else: # A gumbel distribution is fitted to the annual maxima dist = Gumbel(ams_df) # defult parameter estimation method is maximum liklihood method - param_dist = dist.estimate_parameter(method=method) + param_dist = dist.fit_model(method=method) except Exception as e: logger.warning( f"The gauge {i} parameters could not be estimated because of {e}" diff --git a/tests/test_distributions.py b/tests/test_distributions.py index 8e6e613..09fb457 100644 --- a/tests/test_distributions.py +++ b/tests/test_distributions.py @@ -48,9 +48,7 @@ def test_estimate_parameter( ): Gdist = Gumbel(time_series2) for i in range(len(dist_estimation_parameters)): - param = Gdist.estimate_parameter( - method=dist_estimation_parameters[i], test=False - ) + param = Gdist.fit_model(method=dist_estimation_parameters[i], test=False) assert isinstance(param, dict) assert all(i in param.keys() for i in ["loc", "scale"]) assert Gdist.parameters.get("loc") is not None @@ -63,7 +61,7 @@ def test_parameter_estimation_optimization( parameter_estimation_optimization_threshold: int, ): Gdist = Gumbel(time_series2) - param = Gdist.estimate_parameter( + param = Gdist.fit_model( method="optimization", ObjFunc=Gumbel.ObjectiveFn, threshold=parameter_estimation_optimization_threshold, @@ -79,7 +77,7 @@ def test_ks( dist_estimation_parameters_ks: str, ): Gdist = Gumbel(time_series2) - Gdist.estimate_parameter(method=dist_estimation_parameters_ks, test=False) + Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) Gdist.ks() assert Gdist.Dstatic assert Gdist.KS_Pvalue @@ -90,7 +88,7 @@ def test_chisquare( dist_estimation_parameters_ks: str, ): Gdist = Gumbel(time_series2) - Gdist.estimate_parameter(method=dist_estimation_parameters_ks, test=False) + Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) Gdist.chisquare() assert Gdist.chistatic assert Gdist.chi_Pvalue @@ -101,9 +99,7 @@ def test_pdf( dist_estimation_parameters_ks: str, ): Gdist = Gumbel(time_series2) - Param = Gdist.estimate_parameter( - method=dist_estimation_parameters_ks, test=False - ) + Param = Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) pdf, fig, ax = Gdist.pdf(Param, plot_figure=True) assert isinstance(pdf, np.ndarray) @@ -115,9 +111,7 @@ def test_cdf( dist_estimation_parameters_ks: str, ): Gdist = Gumbel(time_series2) - Param = Gdist.estimate_parameter( - method=dist_estimation_parameters_ks, test=False - ) + Param = Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) cdf, fig, ax = Gdist.cdf(Param, plot_figure=True) assert isinstance(cdf, np.ndarray) @@ -130,9 +124,7 @@ def test_gumbel_theoretical_estimate( ): Gdist = Gumbel(time_series2) cdf_Weibul = PlottingPosition.weibul(time_series2) - Param = Gdist.estimate_parameter( - method=dist_estimation_parameters_ks, test=False - ) + Param = Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) Qth = Gdist.theoretical_estimate(Param, cdf_Weibul) assert isinstance(Qth, np.ndarray) @@ -144,9 +136,7 @@ def test_gumbel_confidence_interval( ): Gdist = Gumbel(time_series2) cdf_Weibul = PlottingPosition.weibul(time_series2) - Param = Gdist.estimate_parameter( - method=dist_estimation_parameters_ks, test=False - ) + Param = Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) upper, lower = Gdist.confidence_interval( Param, cdf_Weibul, alpha=confidence_interval_alpha ) @@ -161,9 +151,7 @@ def test_gumbel_probapility_plot( ): Gdist = Gumbel(time_series2) cdf_Weibul = PlottingPosition.weibul(time_series2) - Param = Gdist.estimate_parameter( - method=dist_estimation_parameters_ks, test=False - ) + Param = Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) [fig1, fig2], [ax1, ax2] = Gdist.probapility_plot( Param, cdf_Weibul, alpha=confidence_interval_alpha ) @@ -187,9 +175,7 @@ def test_gev_estimate_parameter( ): Gdist = GEV(time_series1) for i in range(len(dist_estimation_parameters)): - param = Gdist.estimate_parameter( - method=dist_estimation_parameters[i], test=False - ) + param = Gdist.fit_model(method=dist_estimation_parameters[i], test=False) assert isinstance(param, dict) assert all(i in param.keys() for i in ["loc", "scale", "shape"]) @@ -203,7 +189,7 @@ def test_gev_ks( dist_estimation_parameters_ks: str, ): Gdist = GEV(time_series1) - Gdist.estimate_parameter(method=dist_estimation_parameters_ks, test=False) + Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) Gdist.ks() assert Gdist.Dstatic assert Gdist.KS_Pvalue @@ -214,7 +200,7 @@ def test_gev_chisquare( dist_estimation_parameters_ks: str, ): Gdist = GEV(time_series1) - Gdist.estimate_parameter(method=dist_estimation_parameters_ks, test=False) + Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) Gdist.chisquare() assert Gdist.chistatic assert Gdist.chi_Pvalue @@ -225,9 +211,7 @@ def test_gev_pdf( dist_estimation_parameters_ks: str, ): Gdist = GEV(time_series1) - Param = Gdist.estimate_parameter( - method=dist_estimation_parameters_ks, test=False - ) + Param = Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) pdf, fig, ax = Gdist.pdf(Param, plot_figure=True) assert isinstance(pdf, np.ndarray) @@ -239,9 +223,7 @@ def test_gev_cdf( dist_estimation_parameters_ks: str, ): Gdist = GEV(time_series1) - Param = Gdist.estimate_parameter( - method=dist_estimation_parameters_ks, test=False - ) + Param = Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) cdf, fig, ax = Gdist.cdf(Param, plot_figure=True) assert isinstance(cdf, np.ndarray) assert isinstance(fig, Figure) @@ -253,9 +235,7 @@ def test_gev_theoretical_estimate( ): Gdist = GEV(time_series1) cdf_Weibul = PlottingPosition.weibul(time_series1) - Param = Gdist.estimate_parameter( - method=dist_estimation_parameters_ks, test=False - ) + Param = Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) Qth = Gdist.theoretical_estimate(Param, cdf_Weibul) assert isinstance(Qth, np.ndarray) @@ -267,9 +247,7 @@ def test_gev_confidence_interval( ): Gdist = GEV(time_series1) cdf_Weibul = PlottingPosition.weibul(time_series1) - Param = Gdist.estimate_parameter( - method=dist_estimation_parameters_ks, test=False - ) + Param = Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) func = GEV.ci_func upper, lower = Gdist.confidence_interval( @@ -290,9 +268,7 @@ def test_confidence_interval_directly( ): Gdist = GEV(time_series1) cdf_Weibul = PlottingPosition.weibul(time_series1) - Param = Gdist.estimate_parameter( - method=dist_estimation_parameters_ks, test=False - ) + Param = Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) func = GEV.ci_func @@ -330,9 +306,7 @@ def test_estimate_parameter( ): Edist = Exponential(time_series2) for i in range(len(dist_estimation_parameters)): - param = Edist.estimate_parameter( - method=dist_estimation_parameters[i], test=False - ) + param = Edist.fit_model(method=dist_estimation_parameters[i], test=False) assert isinstance(param, dict) assert all(i in param.keys() for i in ["loc", "scale"]) assert Edist.parameters.get("loc") is not None @@ -344,9 +318,7 @@ def test_pdf( dist_estimation_parameters_ks: str, ): Edist = Exponential(time_series2) - Param = Edist.estimate_parameter( - method=dist_estimation_parameters_ks, test=False - ) + Param = Edist.fit_model(method=dist_estimation_parameters_ks, test=False) pdf, fig, ax = Edist.pdf(Param, plot_figure=True) assert isinstance(pdf, np.ndarray) assert isinstance(fig, Figure) @@ -357,9 +329,7 @@ def test_cdf( dist_estimation_parameters_ks: str, ): Edist = Exponential(time_series2) - Param = Edist.estimate_parameter( - method=dist_estimation_parameters_ks, test=False - ) + Param = Edist.fit_model(method=dist_estimation_parameters_ks, test=False) cdf, fig, ax = Edist.cdf(Param, plot_figure=True) assert isinstance(cdf, np.ndarray) assert isinstance(fig, Figure) @@ -371,9 +341,7 @@ def test_TheporeticalEstimate( ): Edist = Exponential(time_series2) cdf_Weibul = PlottingPosition.weibul(time_series2) - Param = Edist.estimate_parameter( - method=dist_estimation_parameters_ks, test=False - ) + Param = Edist.fit_model(method=dist_estimation_parameters_ks, test=False) Qth = Edist.theoretical_estimate(Param, cdf_Weibul) assert isinstance(Qth, np.ndarray) @@ -394,7 +362,7 @@ def test_estimate_parameter( ): Edist = Normal(time_series2) for method in dist_estimation_parameters: - param = Edist.estimate_parameter(method=method, test=False) + param = Edist.fit_model(method=method, test=False) assert isinstance(param, dict) assert all(i in param.keys() for i in ["loc", "scale"]) assert Edist.parameters.get("loc") is not None @@ -406,9 +374,7 @@ def test_pdf( dist_estimation_parameters_ks: str, ): Edist = Normal(time_series2) - Param = Edist.estimate_parameter( - method=dist_estimation_parameters_ks, test=False - ) + Param = Edist.fit_model(method=dist_estimation_parameters_ks, test=False) pdf, fig, ax = Edist.pdf(Param, plot_figure=True) assert isinstance(pdf, np.ndarray) assert isinstance(fig, Figure) @@ -419,9 +385,7 @@ def test_cdf( dist_estimation_parameters_ks: str, ): Edist = Normal(time_series2) - Param = Edist.estimate_parameter( - method=dist_estimation_parameters_ks, test=False - ) + Param = Edist.fit_model(method=dist_estimation_parameters_ks, test=False) cdf, fig, ax = Edist.cdf(Param, plot_figure=True) assert isinstance(cdf, np.ndarray) assert isinstance(fig, Figure) @@ -433,8 +397,6 @@ def test_TheporeticalEstimate( ): Edist = Normal(time_series2) cdf_Weibul = PlottingPosition.weibul(time_series2) - Param = Edist.estimate_parameter( - method=dist_estimation_parameters_ks, test=False - ) + Param = Edist.fit_model(method=dist_estimation_parameters_ks, test=False) Qth = Edist.theoretical_estimate(Param, cdf_Weibul) assert isinstance(Qth, np.ndarray) From cef769bc55d990f335320fd3d50293b399347f4e Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Fri, 1 Dec 2023 23:52:16 +0100 Subject: [PATCH 21/44] add ks and chisquare tests to all distributions --- statista/distributions.py | 66 ++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/statista/distributions.py b/statista/distributions.py index fd84ab0..0aa3922 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -319,6 +319,7 @@ def theoretical_estimate( """ pass + @abstractmethod def ks(self) -> tuple: """Kolmogorov-Smirnov (KS) test. @@ -352,12 +353,9 @@ def ks(self) -> tuple: print(f"P value = {test.pvalue}") return test.statistic, test.pvalue - def chisquare(self) -> tuple: + def chisquare(self) -> Union[tuple, None]: """ - - Returns - ------- - + chisquare test """ if self.parameters is None: raise ValueError( @@ -779,10 +777,10 @@ def theoretical_estimate( raise ValueError("cdf Value Invalid") cdf = np.array(cdf) - Qth = loc - scale * (np.log(-np.log(cdf))) + # Qth = loc - scale * (np.log(-np.log(cdf))) # the main equation form scipy - # Qth = gumbel_r.ppf(F, loc=loc, scale=scale) + Qth = gumbel_r.ppf(cdf, loc=loc, scale=scale) return Qth def ks(self) -> tuple: @@ -801,12 +799,7 @@ def ks(self) -> tuple: return super().ks() def chisquare(self) -> tuple: - """ - - Returns - ------- - - """ + """chisquare test""" return super().chisquare() def confidence_interval( @@ -1245,7 +1238,7 @@ def fit_model( @staticmethod def theoretical_estimate( parameters: Dict[str, Union[float, Any]], - F: np.ndarray, + cdf: np.ndarray, ) -> np.ndarray: """TheporeticalEstimate. @@ -1255,7 +1248,7 @@ def theoretical_estimate( ----------- param : [list] location ans scale parameters of the gumbel distribution. - F : [list] + cdf: [list] cummulative distribution function/ Non Exceedence probability. Return: @@ -1270,27 +1263,27 @@ def theoretical_estimate( if scale <= 0: raise ValueError("Parameters Invalid") - if any(F) < 0 or any(F) > 1: + if any(cdf) < 0 or any(cdf) > 1: raise ValueError("cdf Value Invalid") # Qth = list() - # for i in range(len(F)): - # if F[i] <= 0 or F[i] >= 1: - # if F[i] == 0 and shape < 0: + # for i in range(len(cdf)): + # if cdf[i] <= 0 or cdf[i] >= 1: + # if cdf[i] == 0 and shape < 0: # Qth.append(loc + scale / shape) - # elif F[i] == 1 and shape > 0: + # elif cdf[i] == 1 and shape > 0: # Qth.append(loc + scale / shape) # else: - # raise ValueError(str(F[i]) + " value of cdf is Invalid") - # # F = np.array(F) - # Y = -np.log(-np.log(F[i])) + # raise ValueError(str(cdf[i]) + " value of cdf is Invalid") + # # cdf = np.array(cdf) + # Y = -np.log(-np.log(cdf[i])) # if shape != 0: # Y = (1 - np.exp(-1 * shape * Y)) / shape # # Qth.append(loc + scale * Y) # Qth = np.array(Qth) # the main equation from scipy - Qth = genextreme.ppf(F, shape, loc=loc, scale=scale) + Qth = genextreme.ppf(cdf, shape, loc=loc, scale=scale) return Qth def ks(self): @@ -1308,7 +1301,8 @@ def ks(self): """ return super().ks() - def chisquare(self): + def chisquare(self) -> tuple: + """chisquare test""" return super().chisquare() def confidence_interval( @@ -2078,7 +2072,8 @@ def ks(self): """ return super().ks() - def chisquare(self): + def chisquare(self) -> tuple: + """chisquare test""" return super().chisquare() @@ -2351,3 +2346,22 @@ def theoretical_estimate( # the main equation from scipy Qth = norm.ppf(cdf, loc=loc, scale=scale) return Qth + + def ks(self): + """Kolmogorov-Smirnov (KS) test. + + The smaller the D static the more likely that the two samples are drawn from the same distribution + IF Pvalue < signeficance level ------ reject + + returns: + -------- + Dstatic: [numeric] + The smaller the D static the more likely that the two samples are drawn from the same distribution + Pvalue : [numeric] + IF Pvalue < signeficance level ------ reject the null hypotethis + """ + return super().ks() + + def chisquare(self) -> tuple: + """chisquare test""" + return super().chisquare() From 97f25b0b13e385ed74a33ba34d54f7bb54075588 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Fri, 1 Dec 2023 23:58:44 +0100 Subject: [PATCH 22/44] confirm abstract methods --- statista/distributions.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/statista/distributions.py b/statista/distributions.py index 0aa3922..11e4817 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -294,6 +294,7 @@ def fit_model( return method @staticmethod + @abstractmethod def theoretical_estimate( parameters: Dict[str, Union[float, Any]], cdf: np.ndarray ) -> np.ndarray: @@ -353,6 +354,7 @@ def ks(self) -> tuple: print(f"P value = {test.pvalue}") return test.statistic, test.pvalue + @abstractmethod def chisquare(self) -> Union[tuple, None]: """ chisquare test From b856a55e312006bd476b638e353bbba571a8ee00 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Sat, 2 Dec 2023 00:07:01 +0100 Subject: [PATCH 23/44] match numpy version in the requirements.txt and yaml file --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 7fe56c8..cb7a8db 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ loguru >=0.6.0 matplotlib >=3.6.3 -numpy ==1.25.2 +numpy >=1.25.2 pandas >=2.1.0 pip >=23.2.1 scikit-learn >=1.3.2 From 65a39f0a5221f7d158eaf7c3465c8de28cd1bfac Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Sun, 3 Dec 2023 23:54:02 +0100 Subject: [PATCH 24/44] create factory class Distributions --- statista/distributions.py | 54 ++++++++++++++++++++++++++++++++++--- tests/test_distributions.py | 24 +++++++++++++++++ 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/statista/distributions.py b/statista/distributions.py index 11e4817..1435f57 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -15,7 +15,7 @@ ninf = 1e-5 -__all__ = ["PlottingPosition", "Gumbel", "GEV", "Exponential", "Normal"] +__all__ = ["PlottingPosition", "Gumbel", "GEV", "Exponential", "Normal", "Distribution"] class PlottingPosition: @@ -384,7 +384,7 @@ def confidence_interval( F: np.ndarray, alpha: float = 0.1, ) -> Tuple[np.ndarray, np.ndarray]: - """confidenceInterval. + """confidence_interval. Parameters: ----------- @@ -810,7 +810,7 @@ def confidence_interval( F: np.ndarray, alpha: float = 0.1, ) -> Tuple[np.ndarray, np.ndarray]: - """confidenceInterval. + """confidence_interval. Parameters: ----------- @@ -1317,7 +1317,7 @@ def confidence_interval( method: str = "lmoments", **kargs, ): - """confidenceInterval. + """confidence_interval. Parameters: ----------- @@ -2367,3 +2367,49 @@ def ks(self): def chisquare(self) -> tuple: """chisquare test""" return super().chisquare() + + +class Distribution: + """Distributions.""" + + available_distributions = { + "GEV": GEV, + "Gumbel": Gumbel, + "Exponential": Exponential, + "Normal": Normal, + } + + def __init__( + self, + distribution: str, + data: Union[list, np.ndarray] = None, + parameters: Dict[str, str] = None, + ): + if distribution not in self.available_distributions.keys(): + raise ValueError(f"{distribution} not supported") + + self.distribution = self.available_distributions[distribution](data, parameters) + + def __getattr__(self, name): + """Delegate method calls to the sub-class""" + # Retrieve the attribute or method from the animal object + try: + # Retrieve the attribute or method from the animal object + attribute = getattr(self.distribution, name) + + # If the attribute is a method, return a callable function + if callable(attribute): + + def method(*args, **kwargs): + """A callable function that simply calls the attribute if it is a method""" + return attribute(*args, **kwargs) + + return method + + # If it's a regular attribute, return its value + return attribute + + except AttributeError: + raise AttributeError( + f"'{type(self).__name__}' object has no attribute '{name}'" + ) diff --git a/tests/test_distributions.py b/tests/test_distributions.py index 09fb457..7ae7bcf 100644 --- a/tests/test_distributions.py +++ b/tests/test_distributions.py @@ -10,6 +10,7 @@ PlottingPosition, Exponential, Normal, + Distribution, ) @@ -400,3 +401,26 @@ def test_TheporeticalEstimate( Param = Edist.fit_model(method=dist_estimation_parameters_ks, test=False) Qth = Edist.theoretical_estimate(Param, cdf_Weibul) assert isinstance(Qth, np.ndarray) + + +class TestDistribution: + def test_create_instance( + self, + time_series1: list, + ): + Gdist = Distribution("Gumbel", data=time_series1) + assert isinstance(Gdist.data, np.ndarray) + assert isinstance(Gdist.data_sorted, np.ndarray) + + def test_getter_method( + self, + time_series2: list, + dist_estimation_parameters: List[str], + ): + Gdist = Distribution("Gumbel", data=time_series2) + for i in range(len(dist_estimation_parameters)): + param = Gdist.fit_model(method=dist_estimation_parameters[i], test=False) + assert isinstance(param, dict) + assert all(i in param.keys() for i in ["loc", "scale"]) + assert Gdist.parameters.get("loc") is not None + assert Gdist.parameters.get("scale") is not None From 1135b9e4e63115852bd5f42727bfa1268e431f42 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Sun, 3 Dec 2023 23:55:57 +0100 Subject: [PATCH 25/44] correct typo --- statista/distributions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/statista/distributions.py b/statista/distributions.py index 1435f57..c5fe0a0 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -2394,7 +2394,7 @@ def __getattr__(self, name): """Delegate method calls to the sub-class""" # Retrieve the attribute or method from the animal object try: - # Retrieve the attribute or method from the animal object + # Retrieve the attribute or method from the sub-classes attribute = getattr(self.distribution, name) # If the attribute is a method, return a callable function From 9c069436a7efde2b58667f28a17f4da55ee8af0d Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Mon, 4 Dec 2023 01:28:33 +0100 Subject: [PATCH 26/44] test bootstrap method --- statista/confidence_interval.py | 5 +++- statista/distributions.py | 18 +++++++------ tests/conftest.py | 43 ++++++++++++++++++++++++++++++- tests/test_confidence_interval.py | 29 +++++++++++++++++++++ 4 files changed, 85 insertions(+), 10 deletions(-) create mode 100644 tests/test_confidence_interval.py diff --git a/statista/confidence_interval.py b/statista/confidence_interval.py index bb4ddfd..ac38064 100644 --- a/statista/confidence_interval.py +++ b/statista/confidence_interval.py @@ -50,7 +50,10 @@ def BootStrap( n_samples: int = 100, **kargs, ): # -> Dict[str, OrderedDict[str, Tuple[Any, Any]]] - """Calculate confidence intervals using parametric bootstrap and the percentil interval method This is used to obtain confidence intervals for the estimators and the return values for several return values. + """BootStrap + + Calculate confidence intervals using parametric bootstrap and the percentil interval method This is used to + obtain confidence intervals for the estimators and the return values for several return values. More info about bootstrapping can be found on: - Efron: "An Introduction to the Bootstrap", Chapman & Hall (1993) diff --git a/statista/distributions.py b/statista/distributions.py index c5fe0a0..fedc670 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -1384,12 +1384,14 @@ def probapility_plot( Parameters ---------- - loc : [numeric] - Location parameter of the GEV distribution. - scale : [numeric] - Scale parameter of the GEV distribution. - shape: [float, int] - Shape parameter for the GEV distribution. + parameters: Dict[str, str] + {"loc": val, "scale": val, shape: val} + - loc : [numeric] + Location parameter of the GEV distribution. + - scale : [numeric] + Scale parameter of the GEV distribution. + - shape: [float, int] + Shape parameter for the GEV distribution. F : [list] Theoretical cdf calculated using weibul or using the distribution cdf function. method: [str] @@ -1488,8 +1490,8 @@ def ci_func(data: Union[list, np.ndarray], **kwargs): sample = GEV.theoretical_estimate(gevfit, np.random.rand(len(data))) # get parameters based on the new generated sample - Gdist = GEV(sample) - new_param = Gdist.fit_model(method=method, test=False) + dist = GEV(sample) + new_param = dist.fit_model(method=method, test=False) # return period # T = np.arange(0.1, 999.1, 0.1) + 1 diff --git a/tests/conftest.py b/tests/conftest.py index 4f4fed2..537d660 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,6 @@ -from typing import List +from typing import List, Dict +import numpy as np import pandas as pd import pytest @@ -32,3 +33,43 @@ def confidence_interval_alpha() -> float: @pytest.fixture(scope="module") def parameter_estimation_optimization_threshold() -> int: return 800 # 17 + + +@pytest.fixture(scope="module") +def ci_cdf() -> np.ndarray: + return np.array( + [ + 0.03571429, + 0.07142857, + 0.10714286, + 0.14285714, + 0.17857143, + 0.21428571, + 0.25, + 0.28571429, + 0.32142857, + 0.35714286, + 0.39285714, + 0.42857143, + 0.46428571, + 0.5, + 0.53571429, + 0.57142857, + 0.60714286, + 0.64285714, + 0.67857143, + 0.71428571, + 0.75, + 0.78571429, + 0.82142857, + 0.85714286, + 0.89285714, + 0.92857143, + 0.96428571, + ] + ) + + +@pytest.fixture(scope="module") +def ci_param() -> Dict[str, float]: + return {"loc": 464.825, "scale": 222.120, "shape": 0.01012} diff --git a/tests/test_confidence_interval.py b/tests/test_confidence_interval.py new file mode 100644 index 0000000..e7ad895 --- /dev/null +++ b/tests/test_confidence_interval.py @@ -0,0 +1,29 @@ +"""Confidence Interval Tests""" +from typing import Dict +import numpy as np +from statista.confidence_interval import ConfidenceInterval +from statista.distributions import GEV + + +def test_boot_strap( + time_series1: list, + ci_cdf: np.ndarray, + ci_param: Dict[str, float], +): + """ + - The test function for the boot strap method in the ConfidenceInterval class. + - the test can not compare the generated LB and UB as they are randomly generated. + """ + CI = ConfidenceInterval.BootStrap( + time_series1, + statfunction=GEV.ci_func, + gevfit=ci_param, + n_samples=len(time_series1), + F=ci_cdf, + method="lmoments", + ) + LB = CI["LB"] + UB = CI["UB"] + assert isinstance(LB, np.ndarray) + assert isinstance(UB, np.ndarray) + assert LB.shape == UB.shape == (len(time_series1),) From cd95142b3306467db328edffc567f8088cce5524 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Wed, 6 Dec 2023 22:45:37 +0100 Subject: [PATCH 27/44] refactor --- examples/Extreme value statistics.py | 106 +++---- statista/confidence_interval.py | 18 +- statista/distributions.py | 425 ++++++++++++++------------- statista/eva.py | 4 +- statista/plot.py | 64 ++-- tests/test_confidence_interval.py | 12 +- tests/test_distributions.py | 281 +++++++++--------- 7 files changed, 457 insertions(+), 453 deletions(-) diff --git a/examples/Extreme value statistics.py b/examples/Extreme value statistics.py index 9293dad..60b237e 100644 --- a/examples/Extreme value statistics.py +++ b/examples/Extreme value statistics.py @@ -6,119 +6,109 @@ matplotlib.use("TkAgg") import pandas as pd -from statista.distributions import GEV, ConfidenceInterval, Gumbel, PlottingPosition + +from statista.distributions import GEV, Gumbel, PlottingPosition +from statista.confidence_interval import ConfidenceInterval time_series1 = pd.read_csv("examples/data/time_series1.txt", header=None)[0].tolist() time_series2 = pd.read_csv("examples/data/time_series2.txt", header=None)[0].tolist() # %% -Gdist = Gumbel(time_series1) +gumbel_dist = Gumbel(time_series1) # defult parameter estimation method is maximum liklihood method -Param_mle = Gdist.fit_model(method="mle") -Gdist.ks() -Gdist.chisquare() -print(Param_mle) +param_mle = gumbel_dist.fit_model(method="mle") +gumbel_dist.ks() +gumbel_dist.chisquare() +print(param_mle) # calculate and plot the pdf -pdf = Gdist.pdf(Param_mle, plot_figure=True) -cdf, _, _ = Gdist.cdf(Param_mle, plot_figure=True) +pdf = gumbel_dist.pdf(param_mle, plot_figure=True) +cdf, _, _ = gumbel_dist.cdf(param_mle, plot_figure=True) # %% lmoments -Param_lmoments = Gdist.fit_model(method="lmoments") -Gdist.ks() -Gdist.chisquare() -print(Param_lmoments) -loc = Param_lmoments[0] -scale = Param_lmoments[1] +param_lmoments = gumbel_dist.fit_model(method="lmoments") +gumbel_dist.ks() +gumbel_dist.chisquare() +print(param_lmoments) # calculate and plot the pdf -pdf = Gdist.pdf(loc, scale, plot_figure=True) -cdf, _, _ = Gdist.cdf(loc, scale, plot_figure=True) +pdf = gumbel_dist.pdf(param_lmoments, plot_figure=True) +cdf, _, _ = gumbel_dist.cdf(param_lmoments, plot_figure=True) # %% # calculate the CDF(Non Exceedance probability) using weibul plotting position time_series1.sort() # calculate the F (Non Exceedence probability based on weibul) cdf_Weibul = PlottingPosition.weibul(time_series1) # TheporeticalEstimate method calculates the theoretical values based on the Gumbel distribution -Qth = Gdist.theoretical_estimate(loc, scale, cdf_Weibul) +Qth = gumbel_dist.theoretical_estimate(param_lmoments, cdf_Weibul) # test = stats.chisquare(st.Standardize(Qth), st.Standardize(time_series1),ddof=5) # calculate the confidence interval -upper, lower = Gdist.confidence_interval(loc, scale, cdf_Weibul, alpha=0.1) +upper, lower = gumbel_dist.confidence_interval(param_lmoments, cdf_Weibul, alpha=0.1) # ProbapilityPlot can estimate the Qth and the lower and upper confidence interval in the process of plotting -fig, ax = Gdist.probapility_plot(loc, scale, cdf_Weibul, alpha=0.1) +fig, ax = gumbel_dist.probapility_plot(param_lmoments, cdf_Weibul, alpha=0.1) # %% """ if you want to focus only on high values, you can use a threshold to make the code focus on what is higher this threshold. """ threshold = 17 -Param_dist = Gdist.fit_model( - method="optimization", ObjFunc=Gumbel.ObjectiveFn, threshold=threshold +param_dist = gumbel_dist.fit_model( + method="optimization", ObjFunc=Gumbel.objective_fn, threshold=threshold ) -print(Param_dist) -loc = Param_dist[0] -scale = Param_dist[1] -Gdist.probapility_plot(loc, scale, cdf_Weibul, alpha=0.1) +print(param_dist) +gumbel_dist.probapility_plot(param_dist, cdf_Weibul, alpha=0.1) # %% threshold = 18 -Param_dist = Gdist.fit_model( - method="optimization", ObjFunc=Gumbel.ObjectiveFn, threshold=threshold +param_dist = gumbel_dist.fit_model( + method="optimization", ObjFunc=Gumbel.objective_fn, threshold=threshold ) -print(Param_dist) -loc = Param_dist[0] -scale = Param_dist[1] -Gdist.probapility_plot(loc, scale, cdf_Weibul, alpha=0.1) +print(param_dist) +gumbel_dist.probapility_plot(param_dist, cdf_Weibul, alpha=0.1) # %% Generalized Extreme Value (GEV) -Gevdist = GEV(time_series2) +gev_dist = GEV(time_series2) # default parameter estimation method is maximum liklihood method -mle_param = Gevdist.fit_model(method="mle") -Gevdist.ks() -Gevdist.chisquare() +gev_mle_param = gev_dist.fit_model(method="mle") +gev_dist.ks() +gev_dist.chisquare() -print(mle_param) -shape = mle_param[0] -loc = mle_param[1] -scale = mle_param[2] +print(gev_mle_param) # calculate and plot the pdf -pdf, fig, ax = Gevdist.pdf(shape, loc, scale, plot_figure=True) -cdf, _, _ = Gevdist.cdf(shape, loc, scale, plot_figure=True) +pdf, fig, ax = gev_dist.pdf(gev_mle_param, plot_figure=True) +cdf, _, _ = gev_dist.cdf(gev_mle_param, plot_figure=True) # %% lmoment method -lmom_param = Gevdist.fit_model(method="lmoments") -print(lmom_param) -shape = lmom_param[0] -loc = lmom_param[1] -scale = lmom_param[2] +gev_lmom_param = gev_dist.fit_model(method="lmoments") +print(gev_lmom_param) # calculate and plot the pdf -pdf, fig, ax = Gevdist.pdf(shape, loc, scale, plot_figure=True) -cdf, _, _ = Gevdist.cdf(shape, loc, scale, plot_figure=True) +pdf, fig, ax = gev_dist.pdf(gev_lmom_param, plot_figure=True) +cdf, _, _ = gev_dist.cdf(gev_lmom_param, plot_figure=True) #%% time_series1.sort() # calculate the F (Non Exceedence probability based on weibul) cdf_Weibul = PlottingPosition.weibul(time_series1) -T = PlottingPosition.weibul(time_series1, option=2) +T = PlottingPosition.weibul(time_series1, return_period=True) # TheporeticalEstimate method calculates the theoretical values based on the Gumbel distribution -Qth = Gevdist.theoretical_estimate(shape, loc, scale, cdf_Weibul) +Qth = gev_dist.theoretical_estimate(gev_lmom_param, cdf_Weibul) func = GEV.ci_func -upper, lower = Gevdist.confidence_interval( - shape, - loc, - scale, +upper, lower = gev_dist.confidence_interval( + gev_lmom_param, F=cdf_Weibul, alpha=0.1, statfunction=func, n_samples=len(time_series1), + method="lmoments", ) # %% """ calculate the confidence interval using the boot strap method directly """ -CI = ConfidenceInterval.BootStrap( +CI = ConfidenceInterval.boot_strap( time_series1, statfunction=func, - gevfit=Param_dist, + gevfit=gev_lmom_param, n_samples=len(time_series1), F=cdf_Weibul, + method="lmoments", ) LB = CI["LB"] UB = CI["UB"] # %% -fig, ax = Gevdist.probapility_plot( - shape, loc, scale, cdf_Weibul, func=func, n_samples=len(time_series1) +fig, ax = gev_dist.probapility_plot( + gev_lmom_param, cdf_Weibul, func=func, n_samples=len(time_series1) ) diff --git a/statista/confidence_interval.py b/statista/confidence_interval.py index ac38064..a61a407 100644 --- a/statista/confidence_interval.py +++ b/statista/confidence_interval.py @@ -13,8 +13,8 @@ def __init__(self): pass @staticmethod - def BSIndexes(data, n_samples=10000) -> np.ndarray: - """BSIndexes. + def bs_indexes(data, n_samples=10000) -> np.ndarray: + """bs_indexes. - generate random indeces to shuffle the data of the given array. - using the indeces, you can access the given data array and obtain randomly generated data from the @@ -33,7 +33,7 @@ def BSIndexes(data, n_samples=10000) -> np.ndarray: Examples -------- >>> data = [3.1, 2.4, 5.6, 8.4] - >>> indeces = ConfidenceInterval.BSIndexes(data, n_samples=2) + >>> indeces = ConfidenceInterval.bs_indexes(data, n_samples=2) >>> print(indeces) >>> [1, 4, 4, 3] >>> print(indeces) @@ -43,14 +43,14 @@ def BSIndexes(data, n_samples=10000) -> np.ndarray: yield randint(data.shape[0], size=(data.shape[0],)) @staticmethod - def BootStrap( + def boot_strap( data: Union[list, np.ndarray], statfunction, alpha: float = 0.05, n_samples: int = 100, **kargs, ): # -> Dict[str, OrderedDict[str, Tuple[Any, Any]]] - """BootStrap + """boot_strap Calculate confidence intervals using parametric bootstrap and the percentil interval method This is used to obtain confidence intervals for the estimators and the return values for several return values. @@ -78,7 +78,7 @@ def BootStrap( # We don't need to generate actual samples; that would take more memory. # Instead, we can generate just the indexes, and then apply the statfun # to those indexes. - bootindexes = ConfidenceInterval.BSIndexes(tdata[0], n_samples) + bootindexes = ConfidenceInterval.bs_indexes(tdata[0], n_samples) stat = np.array( [ statfunction(*(x[indexes] for x in tdata), **kargs) @@ -117,11 +117,11 @@ def BootStrap( # point in other axes. out = stat[(nvals, np.indices(nvals.shape)[1:].squeeze())] - UB = out[0, 3:] - LB = out[1, 3:] + ub = out[0, 3:] + lb = out[1, 3:] params = OrderedDict() params["shape"] = (out[0, 0], out[1, 0]) params["location"] = (out[0, 1], out[1, 1]) params["scale"] = (out[0, 2], out[1, 3]) - return {"LB": LB, "UB": UB, "params": params} + return {"lb": lb, "ub": ub, "params": params} diff --git a/statista/distributions.py b/statista/distributions.py index fedc670..bdaa9f5 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -1,4 +1,5 @@ """Statistical distributions.""" +from numbers import Number from typing import Any, List, Tuple, Union, Dict, Callable from abc import ABC, abstractmethod import numpy as np @@ -15,7 +16,14 @@ ninf = 1e-5 -__all__ = ["PlottingPosition", "Gumbel", "GEV", "Exponential", "Normal", "Distribution"] +__all__ = [ + "PlottingPosition", + "Gumbel", + "GEV", + "Exponential", + "Normal", + "Distributions", +] class PlottingPosition: @@ -25,12 +33,12 @@ def __init__(self): pass @staticmethod - def return_period(F: Union[list, np.ndarray]) -> np.ndarray: + def return_period(prob_non_exceed: Union[list, np.ndarray]) -> np.ndarray: """returnPeriod. Parameters ---------- - F: [list/array] + prob_non_exceed: [list/array] non exceedence probability. Returns @@ -38,9 +46,9 @@ def return_period(F: Union[list, np.ndarray]) -> np.ndarray: array: return period. """ - F = np.array(F) - T = 1 / (1 - F) - return T + prob_non_exceed = np.array(prob_non_exceed) + t = 1 / (1 - prob_non_exceed) + return t @staticmethod def weibul(data: Union[list, np.ndarray], return_period: int = False) -> np.ndarray: @@ -69,8 +77,8 @@ def weibul(data: Union[list, np.ndarray], return_period: int = False) -> np.ndar if not return_period: return cdf else: - T = PlottingPosition.return_period(cdf) - return T + t = PlottingPosition.return_period(cdf) + return t class AbstractDistribution(ABC): @@ -166,13 +174,13 @@ def pdf( pdf = self._pdf_eq(ts, parameters) if plot_figure: - Qx = np.linspace( + qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 ) - pdf_fitted = self.pdf(parameters, actual_data=Qx) + pdf_fitted = self.pdf(parameters, actual_data=qx) fig, ax = Plot.pdf( - Qx, + qx, pdf_fitted, self.data_sorted, figsize=figsize, @@ -223,18 +231,18 @@ def cdf( cdf = self._cdf_eq(ts, parameters) if plot_figure: - Qx = np.linspace( + qx = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 ) - cdf_fitted = self.cdf(parameters, actual_data=Qx) + cdf_fitted = self.cdf(parameters, actual_data=qx) - cdf_Weibul = PlottingPosition.weibul(self.data_sorted) + cdf_weibul = PlottingPosition.weibul(self.data_sorted) fig, ax = Plot.cdf( - Qx, + qx, cdf_fitted, self.data_sorted, - cdf_Weibul, + cdf_weibul, figsize=figsize, xlabel=xlabel, ylabel=ylabel, @@ -249,7 +257,7 @@ def cdf( def fit_model( self, method: str = "mle", - ObjFunc: Callable = None, + obj_func: Callable = None, threshold: Union[None, float, int] = None, test: bool = True, ) -> Union[Dict[str, str], Any]: @@ -268,7 +276,7 @@ def fit_model( Parameters ---------- - ObjFunc : [function] + obj_func : [function] function to be used to get the distribution parameters. threshold : [numeric] Value you want to consider only the greater values. @@ -339,9 +347,9 @@ def ks(self) -> tuple: "Value of parameters is unknown please use " "'EstimateParameter' to obtain estimate the distribution parameters" ) - Qth = self.theoretical_estimate(self.parameters, self.cdf_Weibul) + qth = self.theoretical_estimate(self.parameters, self.cdf_Weibul) - test = ks_2samp(self.data, Qth) + test = ks_2samp(self.data, qth) self.Dstatic = test.statistic self.KS_Pvalue = test.pvalue @@ -365,9 +373,9 @@ def chisquare(self) -> Union[tuple, None]: "'EstimateParameter' to obtain them" ) - Qth = self.theoretical_estimate(self.parameters, self.cdf_Weibul) + qth = self.theoretical_estimate(self.parameters, self.cdf_Weibul) try: - test = chisquare(st.standardize(Qth), st.standardize(self.data)) + test = chisquare(st.standardize(qth), st.standardize(self.data)) self.chistatic = test.statistic self.chi_Pvalue = test.pvalue print("-----chisquare Test-----") @@ -381,7 +389,7 @@ def chisquare(self) -> Union[tuple, None]: def confidence_interval( self, parameters: Dict[str, Union[float, Any]], - F: np.ndarray, + prob_non_exceed: np.ndarray, alpha: float = 0.1, ) -> Tuple[np.ndarray, np.ndarray]: """confidence_interval. @@ -394,7 +402,7 @@ def confidence_interval( location parameter of the gumbel distribution. - scale: [numeric] scale parameter of the gumbel distribution. - F : [list] + prob_non_exceed : [list] Non Exceedence probability alpha : [numeric] alpha or SignificanceLevel is a value of the confidence interval. @@ -407,9 +415,9 @@ def confidence_interval( location parameter - scale: [numeric] scale parameter - Qupper : [list] + q_upper : [list] upper bound coresponding to the confidence interval. - Qlower : [list] + q_lower : [list] lower bound coresponding to the confidence interval. """ pass @@ -417,7 +425,7 @@ def confidence_interval( def probapility_plot( self, parameters: Dict[str, Union[float, Any]], - F: np.ndarray, + prob_non_exceed: np.ndarray, alpha: float = 0.1, fig1size: tuple = (10, 5), fig2size: tuple = (6, 6), @@ -438,7 +446,7 @@ def probapility_plot( location parameter of the gumbel distribution. - scale: [numeric] scale parameter of the gumbel distribution. - F : [np.ndarray] + prob_non_exceed : [np.ndarray] theoretical cdf calculated using weibul or using the distribution cdf function. alpha : [float] value between 0 and 1. @@ -458,9 +466,9 @@ def probapility_plot( Qth : [list] theoretical generated values based on the theoretical cdf calculated from weibul or the distribution parameters. - Qupper : [list] + q_upper : [list] upper bound coresponding to the confidence interval. - Qlower : [list] + q_lower : [list] lower bound coresponding to the confidence interval. """ pass @@ -642,10 +650,12 @@ def get_rp(self, loc, scale, data): return rp @staticmethod - def ObjectiveFn(p, x): + def objective_fn(p, x): """ObjectiveFn. - Link : https://stackoverflow.com/questions/23217484/how-to-find-parameters-of-gumbels-distribution-using-scipy-optimize + Link : + https://stackoverflow.com/questions/23217484/how-to-find-parameters-of-gumbels-distribution-using-scipy-optimize + Parameters ---------- p: @@ -662,16 +672,16 @@ def ObjectiveFn(p, x): parameters = {"loc": loc, "scale": scale} pdf = Gumbel._pdf_eq(x1, parameters) cdf = Gumbel._cdf_eq(threshold, parameters) - L1 = (-np.log((pdf / scale))).sum() + l1 = (-np.log((pdf / scale))).sum() # L2 is cdf based - L2 = (-np.log(1 - cdf)) * nx2 + l2 = (-np.log(1 - cdf)) * nx2 # print x1, nx2, L1, L2 - return L1 + L2 + return l1 + l2 def fit_model( self, method: str = "mle", - ObjFunc: Callable = None, + obj_func: Callable = None, threshold: Union[None, float, int] = None, test: bool = True, ) -> Dict[str, float]: @@ -690,7 +700,7 @@ def fit_model( Parameters ---------- - ObjFunc : [function] + obj_func : [function] function to be used to get the distribution parameters. threshold : [numeric] Value you want to consider only the greater values. @@ -714,36 +724,36 @@ def fit_model( method = super().fit_model(method=method) if method == "mle" or method == "mm": - Param = list(gumbel_r.fit(self.data, method=method)) + param = list(gumbel_r.fit(self.data, method=method)) elif method == "lmoments": - LM = Lmoments(self.data) - LMU = LM.Lmom() - Param = Lmoments.gumbel(LMU) + lm = Lmoments(self.data) + lmu = lm.Lmom() + param = Lmoments.gumbel(lmu) elif method == "optimization": - if ObjFunc is None or threshold is None: + if obj_func is None or threshold is None: raise TypeError("threshold should be numeric value") - Param = gumbel_r.fit(self.data, method="mle") + param = gumbel_r.fit(self.data, method="mle") # then we use the result as starting value for your truncated Gumbel fit - Param = so.fmin( - ObjFunc, - [threshold, Param[0], Param[1]], + param = so.fmin( + obj_func, + [threshold, param[0], param[1]], args=(self.data,), maxiter=500, maxfun=500, ) - Param = [Param[1], Param[2]] + param = [param[1], param[2]] else: raise ValueError(f"The given: {method} does not exist") - Param = {"loc": Param[0], "scale": Param[1]} - self.parameters = Param + param = {"loc": param[0], "scale": param[1]} + self.parameters = param if test: self.ks() self.chisquare() - return Param + return param @staticmethod def theoretical_estimate( @@ -782,8 +792,8 @@ def theoretical_estimate( # Qth = loc - scale * (np.log(-np.log(cdf))) # the main equation form scipy - Qth = gumbel_r.ppf(cdf, loc=loc, scale=scale) - return Qth + qth = gumbel_r.ppf(cdf, loc=loc, scale=scale) + return qth def ks(self) -> tuple: """Kolmogorov-Smirnov (KS) test. @@ -807,7 +817,7 @@ def chisquare(self) -> tuple: def confidence_interval( self, parameters: Dict[str, Union[float, Any]], - F: np.ndarray, + prob_non_exceed: np.ndarray, alpha: float = 0.1, ) -> Tuple[np.ndarray, np.ndarray]: """confidence_interval. @@ -820,7 +830,7 @@ def confidence_interval( location parameter of the gumbel distribution. - scale: [numeric] scale parameter of the gumbel distribution. - F : [list] + prob_non_exceed : [list] Non Exceedence probability alpha : [numeric] alpha or SignificanceLevel is a value of the confidence interval. @@ -833,9 +843,9 @@ def confidence_interval( location parameter - scale: [numeric] scale parameter - Qupper : [list] + q_upper : [list] upper bound coresponding to the confidence interval. - Qlower : [list] + q_lower : [list] lower bound coresponding to the confidence interval. """ scale = parameters.get("scale") @@ -843,29 +853,29 @@ def confidence_interval( if scale <= 0: raise ValueError("Scale parameter is negative") - Qth = self.theoretical_estimate(parameters, F) - Y = [-np.log(-np.log(j)) for j in F] - StdError = [ + qth = self.theoretical_estimate(parameters, prob_non_exceed) + y = [-np.log(-np.log(j)) for j in prob_non_exceed] + std_error = [ (scale / np.sqrt(len(self.data))) * np.sqrt(1.1087 + 0.5140 * j + 0.6079 * j**2) - for j in Y + for j in y ] v = norm.ppf(1 - alpha / 2) - Qupper = np.array([Qth[j] + v * StdError[j] for j in range(len(self.data))]) - Qlower = np.array([Qth[j] - v * StdError[j] for j in range(len(self.data))]) - return Qupper, Qlower + q_upper = np.array([qth[j] + v * std_error[j] for j in range(len(self.data))]) + q_lower = np.array([qth[j] - v * std_error[j] for j in range(len(self.data))]) + return q_upper, q_lower def probapility_plot( self, parameters: Dict[str, Union[float, Any]], - F: np.ndarray, + cdf: np.ndarray, alpha: float = 0.1, fig1size: tuple = (10, 5), fig2size: tuple = (6, 6), xlabel: str = "Actual data", ylabel: str = "cdf", fontsize: int = 15, - ) -> Tuple[List[Figure], list]: + ) -> tuple[list[Figure], list[Any]]: """probapilityPlot. ProbapilityPlot method calculates the theoretical values based on the Gumbel distribution @@ -879,7 +889,7 @@ def probapility_plot( location parameter of the gumbel distribution. - scale: [numeric] scale parameter of the gumbel distribution. - F : [np.ndarray] + cdf : [np.ndarray] theoretical cdf calculated using weibul or using the distribution cdf function. alpha : [float] value between 0 and 1. @@ -899,9 +909,9 @@ def probapility_plot( Qth : [list] theoretical generated values based on the theoretical cdf calculated from weibul or the distribution parameters. - Qupper : [list] + q_upper : [list] upper bound coresponding to the confidence interval. - Qlower : [list] + q_lower : [list] lower bound coresponding to the confidence interval. """ scale = parameters.get("scale") @@ -909,24 +919,24 @@ def probapility_plot( if scale <= 0: raise ValueError("Scale parameter is negative") - Qth = self.theoretical_estimate(parameters, F) - Qupper, Qlower = self.confidence_interval(parameters, F, alpha) + q_th = self.theoretical_estimate(parameters, cdf) + q_upper, q_lower = self.confidence_interval(parameters, cdf, alpha) - Qx = np.linspace( + q_x = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 ) - pdf_fitted = self.pdf(parameters, actual_data=Qx) - cdf_fitted = self.cdf(parameters, actual_data=Qx) + pdf_fitted = self.pdf(parameters, actual_data=q_x) + cdf_fitted = self.cdf(parameters, actual_data=q_x) fig, ax = Plot.details( - Qx, - Qth, + q_x, + q_th, self.data, pdf_fitted, cdf_fitted, - F, - Qlower, - Qupper, + cdf, + q_lower, + q_upper, alpha, fig1size=fig1size, fig2size=fig2size, @@ -1131,8 +1141,8 @@ def cdf( ) return result - def get_rp(self, shape: float, loc: float, scale: float, data: np.ndarray): - """getRP. + def get_rp(self, parameters: Dict[str, Union[float, Any]], data: np.ndarray): + """get_rp. getRP calculates the return period for a list/array of values or a single value. @@ -1140,22 +1150,21 @@ def get_rp(self, shape: float, loc: float, scale: float, data: np.ndarray): ---------- data:[list/array/float] value you want the coresponding return value for - shape: [float] - shape parameter - loc: [float] - location parameter - scale: [float] - scale parameter + parameters: Dict[str, str] + {"loc": val, "scale": val, "shape": value} + - shape: [float] + shape parameter + - loc: [float] + location parameter + - scale: [float] + scale parameter Returns ------- float: return period """ - # if isinstance(data, list) or isinstance(data, np.ndarray): - cdf = self.cdf(shape, loc, scale, actual_data=data) - # else: - # cdf = genextreme.cdf(data, shape, loc, scale) + cdf = self.cdf(parameters, actual_data=data) rp = 1 / (1 - cdf) @@ -1164,7 +1173,7 @@ def get_rp(self, shape: float, loc: float, scale: float, data: np.ndarray): def fit_model( self, method: str = "mle", - ObjFunc=None, + obj_func=None, threshold: Union[int, float, None] = None, test: bool = True, ) -> Dict[str, float]: @@ -1183,7 +1192,7 @@ def fit_model( Parameters ---------- - ObjFunc : [function] + obj_func : [function] function to be used to get the distribution parameters. threshold : [numeric] Value you want to consider only the greater values. @@ -1203,30 +1212,30 @@ def fit_model( method = super().fit_model(method=method) if method == "mle" or method == "mm": - Param = list(genextreme.fit(self.data, method=method)) + param = list(genextreme.fit(self.data, method=method)) elif method == "lmoments": - LM = Lmoments(self.data) - LMU = LM.Lmom() - Param = Lmoments.gev(LMU) + lm = Lmoments(self.data) + lmu = lm.Lmom() + param = Lmoments.gev(lmu) elif method == "optimization": - if ObjFunc is None or threshold is None: - raise TypeError("ObjFunc and threshold should be numeric value") + if obj_func is None or threshold is None: + raise TypeError("obj_func and threshold should be numeric value") - Param = genextreme.fit(self.data, method="mle") + param = genextreme.fit(self.data, method="mle") # then we use the result as starting value for your truncated Gumbel fit - Param = so.fmin( - ObjFunc, - [threshold, Param[0], Param[1], Param[2]], + param = so.fmin( + obj_func, + [threshold, param[0], param[1], param[2]], args=(self.data,), maxiter=500, maxfun=500, ) - Param = [Param[1], Param[2], Param[3]] + param = [param[1], param[2], param[3]] else: raise ValueError(f"The given: {method} does not exist") - Param = {"loc": Param[1], "scale": Param[2], "shape": Param[0]} - self.parameters = Param + param = {"loc": param[1], "scale": param[2], "shape": param[0]} + self.parameters = param if test: self.ks() @@ -1235,7 +1244,7 @@ def fit_model( except ValueError: print("chisquare test failed") - return Param + return param @staticmethod def theoretical_estimate( @@ -1265,16 +1274,19 @@ def theoretical_estimate( if scale <= 0: raise ValueError("Parameters Invalid") + if shape is None: + raise ValueError("Shape parameter should not be None") + if any(cdf) < 0 or any(cdf) > 1: raise ValueError("cdf Value Invalid") - # Qth = list() + # q_th = list() # for i in range(len(cdf)): # if cdf[i] <= 0 or cdf[i] >= 1: # if cdf[i] == 0 and shape < 0: - # Qth.append(loc + scale / shape) + # q_th.append(loc + scale / shape) # elif cdf[i] == 1 and shape > 0: - # Qth.append(loc + scale / shape) + # q_th.append(loc + scale / shape) # else: # raise ValueError(str(cdf[i]) + " value of cdf is Invalid") # # cdf = np.array(cdf) @@ -1282,11 +1294,11 @@ def theoretical_estimate( # if shape != 0: # Y = (1 - np.exp(-1 * shape * Y)) / shape # - # Qth.append(loc + scale * Y) - # Qth = np.array(Qth) + # q_th.append(loc + scale * Y) + # q_th = np.array(q_th) # the main equation from scipy - Qth = genextreme.ppf(cdf, shape, loc=loc, scale=scale) - return Qth + q_th = genextreme.ppf(cdf, shape, loc=loc, scale=scale) + return q_th def ks(self): """Kolmogorov-Smirnov (KS) test. @@ -1310,7 +1322,7 @@ def chisquare(self) -> tuple: def confidence_interval( self, parameters: Dict[str, Union[float, Any]], - F: np.ndarray, + prob_non_exceed: np.ndarray, alpha: float = 0.1, statfunction=np.average, n_samples: int = 100, @@ -1325,7 +1337,7 @@ def confidence_interval( location parameter of the gumbel distribution. scale : [numeric] scale parameter of the gumbel distribution. - F : [list] + prob_non_exceed : [list] Non Exceedence probability alpha : [numeric] alpha or SignificanceLevel is a value of the confidence interval. @@ -1339,40 +1351,40 @@ def confidence_interval( Return: ------- - Qupper : [list] + q_upper : [list] upper bound coresponding to the confidence interval. - Qlower : [list] + q_lower : [list] lower bound coresponding to the confidence interval. """ scale = parameters.get("scale") if scale <= 0: raise ValueError("Scale parameter is negative") - CI = ConfidenceInterval.BootStrap( + ci = ConfidenceInterval.boot_strap( self.data, statfunction=statfunction, gevfit=parameters, - F=F, + F=prob_non_exceed, alpha=alpha, n_samples=n_samples, method=method, **kargs, ) - Qlower = CI["LB"] - Qupper = CI["UB"] + q_lower = ci["lb"] + q_upper = ci["ub"] - return Qupper, Qlower + return q_upper, q_lower def probapility_plot( self, parameters: Dict[str, Union[float, Any]], - F, - alpha=0.1, - func=None, + prob_non_exceed, + alpha: Number = 0.1, + func: Callable = None, method: str = "lmoments", n_samples=100, - fig1size=(10, 5), - fig2size=(6, 6), + fig1_size=(10, 5), + fig2_size=(6, 6), xlabel="Actual data", ylabel="cdf", fontsize=15, @@ -1392,7 +1404,7 @@ def probapility_plot( Scale parameter of the GEV distribution. - shape: [float, int] Shape parameter for the GEV distribution. - F : [list] + prob_non_exceed : [list] Theoretical cdf calculated using weibul or using the distribution cdf function. method: [str] Method used to fit the generated samples from the bootstrap method ["lmoments", "mle", "mm"]. Default is @@ -1405,9 +1417,9 @@ def probapility_plot( y label string xlabel : [string] X label string - fig1size : [tuple] + fig1_size : [tuple] size of the pdf and cdf figure - fig2size : [tuple] + fig2_size : [tuple] size of the confidence interval figure n_samples : [integer] number of points in the condidence interval calculation @@ -1416,47 +1428,44 @@ def probapility_plot( func : [function] function to be used in the confidence interval calculation. """ - loc = parameters.get("loc") scale = parameters.get("scale") - shape = parameters.get("shape") if scale <= 0: raise ValueError("Scale parameter is negative") - Qth = self.theoretical_estimate(parameters, F) + q_th = self.theoretical_estimate(parameters, prob_non_exceed) if func is None: func = GEV.ci_func - Param_dist = [shape, loc, scale] - CI = ConfidenceInterval.BootStrap( + ci = ConfidenceInterval.boot_strap( self.data, statfunction=func, - gevfit=Param_dist, + gevfit=parameters, n_samples=n_samples, - F=F, + F=prob_non_exceed, method=method, ) - Qlower = CI["LB"] - Qupper = CI["UB"] + q_lower = ci["lb"] + q_upper = ci["ub"] - Qx = np.linspace( + q_x = np.linspace( float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 ) - pdf_fitted = self.pdf(shape, loc, scale, actual_data=Qx) - cdf_fitted = self.cdf(shape, loc, scale, actual_data=Qx) + pdf_fitted = self.pdf(parameters, actual_data=q_x) + cdf_fitted = self.cdf(parameters, actual_data=q_x) fig, ax = Plot.details( - Qx, - Qth, + q_x, + q_th, self.data, pdf_fitted, cdf_fitted, - F, - Qlower, - Qupper, + prob_non_exceed, + q_lower, + q_upper, alpha, - fig1size=fig1size, - fig2size=fig2size, + fig1size=fig1_size, + fig2size=fig2_size, xlabel=xlabel, ylabel=ylabel, fontsize=fontsize, @@ -1484,7 +1493,7 @@ def ci_func(data: Union[list, np.ndarray], **kwargs): "lmoments". """ gevfit = kwargs["gevfit"] - F = kwargs["F"] + prob_non_exceed = kwargs["F"] method = kwargs["method"] # generate theoretical estimates based on a random cdf, and the dist parameters sample = GEV.theoretical_estimate(gevfit, np.random.rand(len(data))) @@ -1498,11 +1507,11 @@ def ci_func(data: Union[list, np.ndarray], **kwargs): # +1 in order not to make 1- 1/0.1 = -9 # T = np.linspace(0.1, 999, len(data)) + 1 # coresponding theoretical estimate to T - # F = 1 - 1 / T - Qth = GEV.theoretical_estimate(new_param, F) + # prob_non_exceed = 1 - 1 / T + q_th = GEV.theoretical_estimate(new_param, prob_non_exceed) res = list(new_param.values()) - res.extend(Qth) + res.extend(q_th) return tuple(res) @@ -1592,13 +1601,13 @@ def ci_func(data: Union[list, np.ndarray], **kwargs): # # pdf = expon.pdf(ts, loc=loc, scale=scale) # if plot_figure: -# Qx = np.linspace( +# q_x = np.linspace( # float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 # ) -# pdf_fitted = self.pdf(loc, scale, actual_data=Qx) +# pdf_fitted = self.pdf(loc, scale, actual_data=q_x) # # fig, ax = Plot.pdf( -# Qx, +# q_x, # pdf_fitted, # self.data_sorted, # figsize=figsize, @@ -1651,15 +1660,15 @@ def ci_func(data: Union[list, np.ndarray], **kwargs): # cdf = expon.cdf(ts, loc=loc, scale=scale) # # if plot_figure: -# Qx = np.linspace( +# q_x = np.linspace( # float(self.data_sorted[0]), 1.5 * float(self.data_sorted[-1]), 10000 # ) -# cdf_fitted = self.cdf(loc, scale, actual_data=Qx) +# cdf_fitted = self.cdf(loc, scale, actual_data=q_x) # # cdf_Weibul = PlottingPosition.weibul(self.data_sorted) # # fig, ax = Plot.cdf( -# Qx, +# q_x, # cdf_fitted, # self.data_sorted, # cdf_Weibul, @@ -1676,7 +1685,7 @@ def ci_func(data: Union[list, np.ndarray], **kwargs): # def estimateParameter( # self, # method: str = "mle", -# ObjFunc=None, +# obj_func=None, # threshold: Union[int, float, None] = None, # test: bool = True, # ) -> tuple: @@ -1695,7 +1704,7 @@ def ci_func(data: Union[list, np.ndarray], **kwargs): # # Parameters # ---------- -# ObjFunc : [function] +# obj_func : [function] # function to be used to get the distribution parameters. # threshold : [numeric] # Value you want to consider only the greater values. @@ -1725,13 +1734,13 @@ def ci_func(data: Union[list, np.ndarray], **kwargs): # LMU = LM.Lmom() # Param = Lmoments.gev(LMU) # elif method == "optimization": -# if ObjFunc is None or threshold is None: -# raise TypeError("ObjFunc and threshold should be numeric value") +# if obj_func is None or threshold is None: +# raise TypeError("obj_func and threshold should be numeric value") # # Param = expon.fit(self.data, method="mle") # # then we use the result as starting value for your truncated Gumbel fit # Param = so.fmin( -# ObjFunc, +# obj_func, # [threshold, Param[0], Param[1]], # args=(self.data,), # maxiter=500, @@ -1755,7 +1764,7 @@ def ci_func(data: Union[list, np.ndarray], **kwargs): # def theporeticalEstimate( # loc: Union[float, int], # scale: Union[float, int], -# F: np.ndarray, +# prob_non_exceed: np.ndarray, # ) -> np.ndarray: # """TheporeticalEstimate. # @@ -1765,7 +1774,7 @@ def ci_func(data: Union[list, np.ndarray], **kwargs): # ----------- # param : [list] # location ans scale parameters of the gumbel distribution. -# F : [list] +# prob_non_exceed : [list] # cummulative distribution function/ Non Exceedence probability. # # Return: @@ -1776,12 +1785,12 @@ def ci_func(data: Union[list, np.ndarray], **kwargs): # if scale <= 0: # raise ValueError("Parameters Invalid") # -# if any(F) < 0 or any(F) > 1: +# if any(prob_non_exceed) < 0 or any(prob_non_exceed) > 1: # raise ValueError("cdf Value Invalid") # # # the main equation from scipy -# Qth = expon.ppf(F, loc=loc, scale=scale) -# return Qth +# q_th = expon.ppf(prob_non_exceed, loc=loc, scale=scale) +# return q_th class Exponential(AbstractDistribution): @@ -1950,7 +1959,7 @@ def cdf( def fit_model( self, method: str = "mle", - ObjFunc=None, + obj_func=None, threshold: Union[int, float, None] = None, test: bool = True, ) -> Dict[str, float]: @@ -1969,7 +1978,7 @@ def fit_model( Parameters ---------- - ObjFunc : [function] + obj_func : [function] function to be used to get the distribution parameters. threshold : [numeric] Value you want to consider only the greater values. @@ -1980,7 +1989,7 @@ def fit_model( Returns ------- - Param : [list] + param : [list] shape, loc, scale parameter of the gumbel distribution in that order. """ # obj_func = lambda p, x: (-np.log(Gumbel.pdf(x, p[0], p[1]))).sum() @@ -1989,30 +1998,30 @@ def fit_model( method = super().fit_model(method=method) if method == "mle" or method == "mm": - Param = list(expon.fit(self.data, method=method)) + param = list(expon.fit(self.data, method=method)) elif method == "lmoments": - LM = Lmoments(self.data) - LMU = LM.Lmom() - Param = Lmoments.exponential(LMU) + lm = Lmoments(self.data) + lmu = lm.Lmom() + param = Lmoments.exponential(lmu) elif method == "optimization": - if ObjFunc is None or threshold is None: - raise TypeError("ObjFunc and threshold should be numeric value") + if obj_func is None or threshold is None: + raise TypeError("obj_func and threshold should be numeric value") - Param = expon.fit(self.data, method="mle") + param = expon.fit(self.data, method="mle") # then we use the result as starting value for your truncated Gumbel fit - Param = so.fmin( - ObjFunc, - [threshold, Param[0], Param[1]], + param = so.fmin( + obj_func, + [threshold, param[0], param[1]], args=(self.data,), maxiter=500, maxfun=500, ) - Param = [Param[1], Param[2]] + param = [param[1], param[2]] else: raise ValueError(f"The given: {method} does not exist") - Param = {"loc": Param[0], "scale": Param[1]} - self.parameters = Param + param = {"loc": param[0], "scale": param[1]} + self.parameters = param if test: self.ks() @@ -2021,7 +2030,7 @@ def fit_model( except ValueError: print("chisquare test failed") - return Param + return param @staticmethod def theoretical_estimate( @@ -2058,8 +2067,8 @@ def theoretical_estimate( raise ValueError("cdf Value Invalid") # the main equation from scipy - Qth = expon.ppf(cdf, loc=loc, scale=scale) - return Qth + q_th = expon.ppf(cdf, loc=loc, scale=scale) + return q_th def ks(self): """Kolmogorov-Smirnov (KS) test. @@ -2240,7 +2249,7 @@ def cdf( def fit_model( self, method: str = "mle", - ObjFunc=None, + obj_func=None, threshold: Union[int, float, None] = None, test: bool = True, ) -> Dict[str, float]: @@ -2259,7 +2268,7 @@ def fit_model( Parameters ---------- - ObjFunc : [function] + obj_func : [function] function to be used to get the distribution parameters. threshold : [numeric] Value you want to consider only the greater values. @@ -2270,7 +2279,7 @@ def fit_model( Returns ------- - Param : [list] + param : [list] shape, loc, scale parameter of the gumbel distribution in that order. """ # obj_func = lambda p, x: (-np.log(Gumbel.pdf(x, p[0], p[1]))).sum() @@ -2279,30 +2288,30 @@ def fit_model( method = super().fit_model(method=method) if method == "mle" or method == "mm": - Param = list(norm.fit(self.data, method=method)) + param = list(norm.fit(self.data, method=method)) elif method == "lmoments": - LM = Lmoments(self.data) - LMU = LM.Lmom() - Param = Lmoments.normal(LMU) + lm = Lmoments(self.data) + lmu = lm.Lmom() + param = Lmoments.normal(lmu) elif method == "optimization": - if ObjFunc is None or threshold is None: - raise TypeError("ObjFunc and threshold should be numeric value") + if obj_func is None or threshold is None: + raise TypeError("obj_func and threshold should be numeric value") - Param = norm.fit(self.data, method="mle") + param = norm.fit(self.data, method="mle") # then we use the result as starting value for your truncated Gumbel fit - Param = so.fmin( - ObjFunc, - [threshold, Param[0], Param[1]], + param = so.fmin( + obj_func, + [threshold, param[0], param[1]], args=(self.data,), maxiter=500, maxfun=500, ) - Param = [Param[1], Param[2]] + param = [param[1], param[2]] else: raise ValueError(f"The given: {method} does not exist") - Param = {"loc": Param[0], "scale": Param[1]} - self.parameters = Param + param = {"loc": param[0], "scale": param[1]} + self.parameters = param if test: self.ks() @@ -2311,7 +2320,7 @@ def fit_model( except ValueError: print("chisquare test failed") - return Param + return param @staticmethod def theoretical_estimate( @@ -2348,8 +2357,8 @@ def theoretical_estimate( raise ValueError("cdf Value Invalid") # the main equation from scipy - Qth = norm.ppf(cdf, loc=loc, scale=scale) - return Qth + q_th = norm.ppf(cdf, loc=loc, scale=scale) + return q_th def ks(self): """Kolmogorov-Smirnov (KS) test. @@ -2371,7 +2380,7 @@ def chisquare(self) -> tuple: return super().chisquare() -class Distribution: +class Distributions: """Distributions.""" available_distributions = { diff --git a/statista/eva.py b/statista/eva.py index 1a96af9..3448c1b 100644 --- a/statista/eva.py +++ b/statista/eva.py @@ -153,14 +153,14 @@ def ams_analysis( dist = GEV(ams_df) param_dist = dist.fit_model( method="optimization", - ObjFunc=Gumbel.ObjectiveFn, + obj_func=Gumbel.objective_fn, threshold=threshold, ) else: dist = Gumbel(ams_df) param_dist = dist.fit_model( method="optimization", - ObjFunc=Gumbel.ObjectiveFn, + obj_func=Gumbel.objective_fn, threshold=threshold, ) else: diff --git a/statista/plot.py b/statista/plot.py index e087b18..95d8af1 100644 --- a/statista/plot.py +++ b/statista/plot.py @@ -1,4 +1,6 @@ +"""Plotting functions for statista package.""" from typing import Union, Tuple, List, Any +from numbers import Number import matplotlib.pyplot as plt from matplotlib import gridspec from matplotlib.figure import Figure @@ -13,7 +15,7 @@ def __init__(self): @staticmethod def pdf( - Qx: np.ndarray, + qx: np.ndarray, pdf_fitted, data_sorted: np.ndarray, figsize: tuple = (6, 5), @@ -25,7 +27,7 @@ def pdf( Parameters ---------- - Qx + qx pdf_fitted data_sorted figsize @@ -44,7 +46,7 @@ def pdf( # gs = gridspec.GridSpec(nrows=1, ncols=2, figure=fig) # Plot the histogram and the fitted distribution, save it for each gauge. ax = fig.add_subplot() - ax.plot(Qx, pdf_fitted, "-", color="#27408B", linewidth=2) + ax.plot(qx, pdf_fitted, "-", color="#27408B", linewidth=2) ax.hist( data_sorted, density=True, histtype="stepfilled", color="#DC143C" ) # , alpha=0.2 @@ -54,10 +56,10 @@ def pdf( @staticmethod def cdf( - Qx, + qx, cdf_fitted, data_sorted, - cdf_Weibul, + cdf_weibul, figsize=(6, 5), xlabel="Actual data", ylabel="cdf", @@ -67,10 +69,10 @@ def cdf( Parameters ---------- - Qx + qx cdf_fitted data_sorted - cdf_Weibul + cdf_weibul figsize xlabel ylabel @@ -86,11 +88,11 @@ def cdf( fig = plt.figure(figsize=figsize) ax = fig.add_subplot() ax.plot( - Qx, cdf_fitted, "-", label="Estimated CDF", color="#27408B", linewidth=2 + qx, cdf_fitted, "-", label="Estimated CDF", color="#27408B", linewidth=2 ) ax.scatter( data_sorted, - cdf_Weibul, + cdf_weibul, label="Empirical CDF", color="orangered", facecolors="none", @@ -102,15 +104,15 @@ def cdf( @staticmethod def details( - Qx: Union[np.ndarray, list], - Qth: Union[np.ndarray, list], - Qact: Union[np.ndarray, list], + qx: Union[np.ndarray, list], + qth: Union[np.ndarray, list], + q_act: Union[np.ndarray, list], pdf: Union[np.ndarray, list], cdf_fitted: Union[np.ndarray, list], F: Union[np.ndarray, list], - Qlower: Union[np.ndarray, list], - Qupper: Union[np.ndarray, list], - alpha: float, + q_lower: Union[np.ndarray, list], + q_upper: Union[np.ndarray, list], + alpha: Number, fig1size: tuple = (10, 5), fig2size: tuple = (6, 6), xlabel: str = "Actual data", @@ -121,14 +123,14 @@ def details( Parameters ---------- - Qx - Qth - Qact + qx + qth + q_act pdf cdf_fitted F - Qlower - Qupper + q_lower + q_upper alpha fig1size fig2size @@ -143,40 +145,40 @@ def details( gs = gridspec.GridSpec(nrows=1, ncols=2, figure=fig1) # Plot the histogram and the fitted distribution, save it for each gauge. ax1 = fig1.add_subplot(gs[0, 0]) - ax1.plot(Qx, pdf, "-", color="#27408B", linewidth=2) - ax1.hist(Qact, density=True, histtype="stepfilled", color="#DC143C") + ax1.plot(qx, pdf, "-", color="#27408B", linewidth=2) + ax1.hist(q_act, density=True, histtype="stepfilled", color="#DC143C") ax1.set_xlabel(xlabel, fontsize=fontsize) ax1.set_ylabel("pdf", fontsize=fontsize) ax2 = fig1.add_subplot(gs[0, 1]) - ax2.plot(Qx, cdf_fitted, "-", color="#27408B", linewidth=2) + ax2.plot(qx, cdf_fitted, "-", color="#27408B", linewidth=2) - Qact.sort() - ax2.scatter(Qact, F, color="#DC143C", facecolors="none") + q_act.sort() + ax2.scatter(q_act, F, color="#DC143C", facecolors="none") ax2.set_xlabel(xlabel, fontsize=fontsize) ax2.set_ylabel(ylabel, fontsize=15) fig2 = plt.figure(figsize=fig2size) - plt.plot(Qth, Qth, "-.", color="#3D59AB", linewidth=2, label="Theoretical Data") + plt.plot(qth, qth, "-.", color="#3D59AB", linewidth=2, label="Theoretical Data") # confidence interval plt.plot( - Qth, - Qlower, + qth, + q_lower, "*--", color="grey", markersize=10, label=f"Lower limit ({int((1 - alpha) * 100)} % CI)", ) plt.plot( - Qth, - Qupper, + qth, + q_upper, "*--", color="grey", markersize=10, label=f"Upper limit ({int((1 - alpha) * 100)} % CI)", ) plt.scatter( - Qth, Qact, color="#DC143C", facecolors="none", label="Actual Data" + qth, q_act, color="#DC143C", facecolors="none", label="Actual Data" ) # "d", markersize=12, plt.legend(fontsize=fontsize, framealpha=1) plt.xlabel("Theoretical Values", fontsize=fontsize) diff --git a/tests/test_confidence_interval.py b/tests/test_confidence_interval.py index e7ad895..d73092d 100644 --- a/tests/test_confidence_interval.py +++ b/tests/test_confidence_interval.py @@ -14,7 +14,7 @@ def test_boot_strap( - The test function for the boot strap method in the ConfidenceInterval class. - the test can not compare the generated LB and UB as they are randomly generated. """ - CI = ConfidenceInterval.BootStrap( + ci = ConfidenceInterval.boot_strap( time_series1, statfunction=GEV.ci_func, gevfit=ci_param, @@ -22,8 +22,8 @@ def test_boot_strap( F=ci_cdf, method="lmoments", ) - LB = CI["LB"] - UB = CI["UB"] - assert isinstance(LB, np.ndarray) - assert isinstance(UB, np.ndarray) - assert LB.shape == UB.shape == (len(time_series1),) + lb = ci["lb"] + ub = ci["ub"] + assert isinstance(lb, np.ndarray) + assert isinstance(ub, np.ndarray) + assert lb.shape == ub.shape == (len(time_series1),) diff --git a/tests/test_distributions.py b/tests/test_distributions.py index 7ae7bcf..2c03172 100644 --- a/tests/test_distributions.py +++ b/tests/test_distributions.py @@ -1,3 +1,4 @@ +"""Test distributions module.""" from typing import List import numpy as np @@ -10,7 +11,7 @@ PlottingPosition, Exponential, Normal, - Distribution, + Distributions, ) @@ -19,7 +20,7 @@ def test_plotting_position_weibul( self, time_series1: list, ): - cdf = PlottingPosition.weibul(time_series1, return_period=False) + cdf = PlottingPosition.weibul(time_series1) assert isinstance(cdf, np.ndarray) rp = PlottingPosition.weibul(time_series1, return_period=True) assert isinstance(rp, np.ndarray) @@ -28,7 +29,7 @@ def test_plotting_position_rp( self, time_series1: list, ): - cdf = PlottingPosition.weibul(time_series1, return_period=False) + cdf = PlottingPosition.weibul(time_series1) rp = PlottingPosition.return_period(cdf) assert isinstance(rp, np.ndarray) @@ -38,22 +39,22 @@ def test_create_instance( self, time_series1: list, ): - Gdist = Gumbel(time_series1) - assert isinstance(Gdist.data, np.ndarray) - assert isinstance(Gdist.data_sorted, np.ndarray) + dist = Gumbel(time_series1) + assert isinstance(dist.data, np.ndarray) + assert isinstance(dist.data_sorted, np.ndarray) def test_estimate_parameter( self, time_series2: list, dist_estimation_parameters: List[str], ): - Gdist = Gumbel(time_series2) + dist = Gumbel(time_series2) for i in range(len(dist_estimation_parameters)): - param = Gdist.fit_model(method=dist_estimation_parameters[i], test=False) + param = dist.fit_model(method=dist_estimation_parameters[i], test=False) assert isinstance(param, dict) assert all(i in param.keys() for i in ["loc", "scale"]) - assert Gdist.parameters.get("loc") is not None - assert Gdist.parameters.get("scale") is not None + assert dist.parameters.get("loc") is not None + assert dist.parameters.get("scale") is not None def test_parameter_estimation_optimization( self, @@ -61,48 +62,48 @@ def test_parameter_estimation_optimization( dist_estimation_parameters: List[str], parameter_estimation_optimization_threshold: int, ): - Gdist = Gumbel(time_series2) - param = Gdist.fit_model( + dist = Gumbel(time_series2) + param = dist.fit_model( method="optimization", - ObjFunc=Gumbel.ObjectiveFn, + obj_func=Gumbel.objective_fn, threshold=parameter_estimation_optimization_threshold, ) assert isinstance(param, dict) assert all(i in param.keys() for i in ["loc", "scale"]) - assert Gdist.parameters.get("loc") is not None - assert Gdist.parameters.get("scale") is not None + assert dist.parameters.get("loc") is not None + assert dist.parameters.get("scale") is not None def test_ks( self, time_series2: list, dist_estimation_parameters_ks: str, ): - Gdist = Gumbel(time_series2) - Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) - Gdist.ks() - assert Gdist.Dstatic - assert Gdist.KS_Pvalue + dist = Gumbel(time_series2) + dist.fit_model(method=dist_estimation_parameters_ks, test=False) + dist.ks() + assert dist.Dstatic + assert dist.KS_Pvalue def test_chisquare( self, time_series2: list, dist_estimation_parameters_ks: str, ): - Gdist = Gumbel(time_series2) - Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) - Gdist.chisquare() - assert Gdist.chistatic - assert Gdist.chi_Pvalue + dist = Gumbel(time_series2) + dist.fit_model(method=dist_estimation_parameters_ks, test=False) + dist.chisquare() + assert dist.chistatic + assert dist.chi_Pvalue def test_pdf( self, time_series2: list, dist_estimation_parameters_ks: str, ): - Gdist = Gumbel(time_series2) - Param = Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) + dist = Gumbel(time_series2) + param = dist.fit_model(method=dist_estimation_parameters_ks, test=False) - pdf, fig, ax = Gdist.pdf(Param, plot_figure=True) + pdf, fig, ax = dist.pdf(param, plot_figure=True) assert isinstance(pdf, np.ndarray) assert isinstance(fig, Figure) @@ -111,50 +112,50 @@ def test_cdf( time_series2: list, dist_estimation_parameters_ks: str, ): - Gdist = Gumbel(time_series2) - Param = Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) - cdf, fig, ax = Gdist.cdf(Param, plot_figure=True) + dist = Gumbel(time_series2) + param = dist.fit_model(method=dist_estimation_parameters_ks, test=False) + cdf, fig, ax = dist.cdf(param, plot_figure=True) assert isinstance(cdf, np.ndarray) assert isinstance(fig, Figure) - def test_gumbel_theoretical_estimate( + def test_theoretical_estimate( self, time_series2: list, dist_estimation_parameters_ks: str, ): - Gdist = Gumbel(time_series2) - cdf_Weibul = PlottingPosition.weibul(time_series2) - Param = Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) - Qth = Gdist.theoretical_estimate(Param, cdf_Weibul) - assert isinstance(Qth, np.ndarray) + dist = Gumbel(time_series2) + cdf_weibul = PlottingPosition.weibul(time_series2) + param = dist.fit_model(method=dist_estimation_parameters_ks, test=False) + qth = dist.theoretical_estimate(param, cdf_weibul) + assert isinstance(qth, np.ndarray) - def test_gumbel_confidence_interval( + def test_confidence_interval( self, time_series2: list, dist_estimation_parameters_ks: str, confidence_interval_alpha: float, ): - Gdist = Gumbel(time_series2) - cdf_Weibul = PlottingPosition.weibul(time_series2) - Param = Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) - upper, lower = Gdist.confidence_interval( - Param, cdf_Weibul, alpha=confidence_interval_alpha + dist = Gumbel(time_series2) + cdf_weibul = PlottingPosition.weibul(time_series2) + param = dist.fit_model(method=dist_estimation_parameters_ks, test=False) + upper, lower = dist.confidence_interval( + param, cdf_weibul, alpha=confidence_interval_alpha ) assert isinstance(upper, np.ndarray) assert isinstance(lower, np.ndarray) - def test_gumbel_probapility_plot( + def test_probapility_plot( self, time_series2: list, dist_estimation_parameters_ks: str, confidence_interval_alpha: float, ): - Gdist = Gumbel(time_series2) - cdf_Weibul = PlottingPosition.weibul(time_series2) - Param = Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) - [fig1, fig2], [ax1, ax2] = Gdist.probapility_plot( - Param, cdf_Weibul, alpha=confidence_interval_alpha + dist = Gumbel(time_series2) + cdf_weibul = PlottingPosition.weibul(time_series2) + param = dist.fit_model(method=dist_estimation_parameters_ks, test=False) + (fig1, fig2), (ax1, ax2) = dist.probapility_plot( + param, cdf_weibul, alpha=confidence_interval_alpha ) assert isinstance(fig1, Figure) assert isinstance(fig2, Figure) @@ -165,56 +166,56 @@ def test_create_gev_instance( self, time_series1: list, ): - Gdist = GEV(time_series1) - assert isinstance(Gdist.data, np.ndarray) - assert isinstance(Gdist.data_sorted, np.ndarray) + dist = GEV(time_series1) + assert isinstance(dist.data, np.ndarray) + assert isinstance(dist.data_sorted, np.ndarray) def test_gev_estimate_parameter( self, time_series1: list, dist_estimation_parameters: List[str], ): - Gdist = GEV(time_series1) + dist = GEV(time_series1) for i in range(len(dist_estimation_parameters)): - param = Gdist.fit_model(method=dist_estimation_parameters[i], test=False) + param = dist.fit_model(method=dist_estimation_parameters[i], test=False) assert isinstance(param, dict) assert all(i in param.keys() for i in ["loc", "scale", "shape"]) - assert Gdist.parameters.get("loc") is not None - assert Gdist.parameters.get("scale") is not None - assert Gdist.parameters.get("shape") is not None + assert dist.parameters.get("loc") is not None + assert dist.parameters.get("scale") is not None + assert dist.parameters.get("shape") is not None def test_gev_ks( self, time_series1: list, dist_estimation_parameters_ks: str, ): - Gdist = GEV(time_series1) - Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) - Gdist.ks() - assert Gdist.Dstatic - assert Gdist.KS_Pvalue + dist = GEV(time_series1) + dist.fit_model(method=dist_estimation_parameters_ks, test=False) + dist.ks() + assert dist.Dstatic + assert dist.KS_Pvalue def test_gev_chisquare( self, time_series1: list, dist_estimation_parameters_ks: str, ): - Gdist = GEV(time_series1) - Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) - Gdist.chisquare() - assert Gdist.chistatic - assert Gdist.chi_Pvalue + dist = GEV(time_series1) + dist.fit_model(method=dist_estimation_parameters_ks, test=False) + dist.chisquare() + assert dist.chistatic + assert dist.chi_Pvalue def test_gev_pdf( self, time_series1: list, dist_estimation_parameters_ks: str, ): - Gdist = GEV(time_series1) - Param = Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) + dist = GEV(time_series1) + param = dist.fit_model(method=dist_estimation_parameters_ks, test=False) - pdf, fig, ax = Gdist.pdf(Param, plot_figure=True) + pdf, fig, ax = dist.pdf(param, plot_figure=True) assert isinstance(pdf, np.ndarray) assert isinstance(fig, Figure) @@ -223,9 +224,9 @@ def test_gev_cdf( time_series1: list, dist_estimation_parameters_ks: str, ): - Gdist = GEV(time_series1) - Param = Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) - cdf, fig, ax = Gdist.cdf(Param, plot_figure=True) + dist = GEV(time_series1) + param = dist.fit_model(method=dist_estimation_parameters_ks, test=False) + cdf, fig, ax = dist.cdf(param, plot_figure=True) assert isinstance(cdf, np.ndarray) assert isinstance(fig, Figure) @@ -234,11 +235,11 @@ def test_gev_theoretical_estimate( time_series1: list, dist_estimation_parameters_ks: str, ): - Gdist = GEV(time_series1) - cdf_Weibul = PlottingPosition.weibul(time_series1) - Param = Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) - Qth = Gdist.theoretical_estimate(Param, cdf_Weibul) - assert isinstance(Qth, np.ndarray) + dist = GEV(time_series1) + cdf_weibul = PlottingPosition.weibul(time_series1) + param = dist.fit_model(method=dist_estimation_parameters_ks, test=False) + qth = dist.theoretical_estimate(param, cdf_weibul) + assert isinstance(qth, np.ndarray) def test_gev_confidence_interval( self, @@ -246,14 +247,14 @@ def test_gev_confidence_interval( dist_estimation_parameters_ks: str, confidence_interval_alpha: float, ): - Gdist = GEV(time_series1) - cdf_Weibul = PlottingPosition.weibul(time_series1) - Param = Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) + dist = GEV(time_series1) + cdf_weibul = PlottingPosition.weibul(time_series1) + param = dist.fit_model(method=dist_estimation_parameters_ks, test=False) func = GEV.ci_func - upper, lower = Gdist.confidence_interval( - Param, - F=cdf_Weibul, + upper, lower = dist.confidence_interval( + param, + prob_non_exceed=cdf_weibul, alpha=confidence_interval_alpha, statfunction=func, n_samples=len(time_series1), @@ -267,25 +268,25 @@ def test_confidence_interval_directly( dist_estimation_parameters_ks: str, confidence_interval_alpha: float, ): - Gdist = GEV(time_series1) - cdf_Weibul = PlottingPosition.weibul(time_series1) - Param = Gdist.fit_model(method=dist_estimation_parameters_ks, test=False) + dist = GEV(time_series1) + cdf_weibul = PlottingPosition.weibul(time_series1) + param = dist.fit_model(method=dist_estimation_parameters_ks, test=False) func = GEV.ci_func - CI = ConfidenceInterval.BootStrap( + ci = ConfidenceInterval.boot_strap( time_series1, statfunction=func, - gevfit=Param, + gevfit=param, n_samples=len(time_series1), - F=cdf_Weibul, + F=cdf_weibul, method="lmoments", ) - LB = CI["LB"] - UB = CI["UB"] + lb = ci["lb"] + ub = ci["ub"] - assert isinstance(LB, np.ndarray) - assert isinstance(UB, np.ndarray) + assert isinstance(lb, np.ndarray) + assert isinstance(ub, np.ndarray) # class TestAbstractDistrition: @@ -296,31 +297,33 @@ def test_create_instance( self, time_series1: list, ): - Edist = Exponential(time_series1) - assert isinstance(Edist.data, np.ndarray) - assert isinstance(Edist.data_sorted, np.ndarray) + expo_dist = Exponential(time_series1) + assert isinstance(expo_dist.data, np.ndarray) + assert isinstance(expo_dist.data_sorted, np.ndarray) def test_estimate_parameter( self, time_series2: list, dist_estimation_parameters: List[str], ): - Edist = Exponential(time_series2) + expo_dist = Exponential(time_series2) for i in range(len(dist_estimation_parameters)): - param = Edist.fit_model(method=dist_estimation_parameters[i], test=False) + param = expo_dist.fit_model( + method=dist_estimation_parameters[i], test=False + ) assert isinstance(param, dict) assert all(i in param.keys() for i in ["loc", "scale"]) - assert Edist.parameters.get("loc") is not None - assert Edist.parameters.get("scale") is not None + assert expo_dist.parameters.get("loc") is not None + assert expo_dist.parameters.get("scale") is not None def test_pdf( self, time_series2: list, dist_estimation_parameters_ks: str, ): - Edist = Exponential(time_series2) - Param = Edist.fit_model(method=dist_estimation_parameters_ks, test=False) - pdf, fig, ax = Edist.pdf(Param, plot_figure=True) + expo_dist = Exponential(time_series2) + param = expo_dist.fit_model(method=dist_estimation_parameters_ks, test=False) + pdf, fig, ax = expo_dist.pdf(param, plot_figure=True) assert isinstance(pdf, np.ndarray) assert isinstance(fig, Figure) @@ -329,22 +332,22 @@ def test_cdf( time_series2: list, dist_estimation_parameters_ks: str, ): - Edist = Exponential(time_series2) - Param = Edist.fit_model(method=dist_estimation_parameters_ks, test=False) - cdf, fig, ax = Edist.cdf(Param, plot_figure=True) + expo_dist = Exponential(time_series2) + param = expo_dist.fit_model(method=dist_estimation_parameters_ks, test=False) + cdf, fig, ax = expo_dist.cdf(param, plot_figure=True) assert isinstance(cdf, np.ndarray) assert isinstance(fig, Figure) - def test_TheporeticalEstimate( + def test_theoretical_estimate( self, time_series2: list, dist_estimation_parameters_ks: str, ): - Edist = Exponential(time_series2) - cdf_Weibul = PlottingPosition.weibul(time_series2) - Param = Edist.fit_model(method=dist_estimation_parameters_ks, test=False) - Qth = Edist.theoretical_estimate(Param, cdf_Weibul) - assert isinstance(Qth, np.ndarray) + expo_dist = Exponential(time_series2) + cdf_weibul = PlottingPosition.weibul(time_series2) + param = expo_dist.fit_model(method=dist_estimation_parameters_ks, test=False) + qth = expo_dist.theoretical_estimate(param, cdf_weibul) + assert isinstance(qth, np.ndarray) class TestNormal: @@ -352,31 +355,31 @@ def test_create_instance( self, time_series1: list, ): - Edist = Normal(time_series1) - assert isinstance(Edist.data, np.ndarray) - assert isinstance(Edist.data_sorted, np.ndarray) + norm_dist = Normal(time_series1) + assert isinstance(norm_dist.data, np.ndarray) + assert isinstance(norm_dist.data_sorted, np.ndarray) def test_estimate_parameter( self, time_series2: list, dist_estimation_parameters: List[str], ): - Edist = Normal(time_series2) + norm_dist = Normal(time_series2) for method in dist_estimation_parameters: - param = Edist.fit_model(method=method, test=False) + param = norm_dist.fit_model(method=method, test=False) assert isinstance(param, dict) assert all(i in param.keys() for i in ["loc", "scale"]) - assert Edist.parameters.get("loc") is not None - assert Edist.parameters.get("scale") is not None + assert norm_dist.parameters.get("loc") is not None + assert norm_dist.parameters.get("scale") is not None def test_pdf( self, time_series2: list, dist_estimation_parameters_ks: str, ): - Edist = Normal(time_series2) - Param = Edist.fit_model(method=dist_estimation_parameters_ks, test=False) - pdf, fig, ax = Edist.pdf(Param, plot_figure=True) + norm_dist = Normal(time_series2) + param = norm_dist.fit_model(method=dist_estimation_parameters_ks, test=False) + pdf, fig, ax = norm_dist.pdf(param, plot_figure=True) assert isinstance(pdf, np.ndarray) assert isinstance(fig, Figure) @@ -385,22 +388,22 @@ def test_cdf( time_series2: list, dist_estimation_parameters_ks: str, ): - Edist = Normal(time_series2) - Param = Edist.fit_model(method=dist_estimation_parameters_ks, test=False) - cdf, fig, ax = Edist.cdf(Param, plot_figure=True) + norm_dist = Normal(time_series2) + param = norm_dist.fit_model(method=dist_estimation_parameters_ks, test=False) + cdf, fig, ax = norm_dist.cdf(param, plot_figure=True) assert isinstance(cdf, np.ndarray) assert isinstance(fig, Figure) - def test_TheporeticalEstimate( + def test_theoretical_estimate( self, time_series2: list, dist_estimation_parameters_ks: str, ): - Edist = Normal(time_series2) - cdf_Weibul = PlottingPosition.weibul(time_series2) - Param = Edist.fit_model(method=dist_estimation_parameters_ks, test=False) - Qth = Edist.theoretical_estimate(Param, cdf_Weibul) - assert isinstance(Qth, np.ndarray) + norm_dist = Normal(time_series2) + cdf_weibul = PlottingPosition.weibul(time_series2) + param = norm_dist.fit_model(method=dist_estimation_parameters_ks, test=False) + qth = norm_dist.theoretical_estimate(param, cdf_weibul) + assert isinstance(qth, np.ndarray) class TestDistribution: @@ -408,19 +411,19 @@ def test_create_instance( self, time_series1: list, ): - Gdist = Distribution("Gumbel", data=time_series1) - assert isinstance(Gdist.data, np.ndarray) - assert isinstance(Gdist.data_sorted, np.ndarray) + dist = Distributions("Gumbel", data=time_series1) + assert isinstance(dist.data, np.ndarray) + assert isinstance(dist.data_sorted, np.ndarray) def test_getter_method( self, time_series2: list, dist_estimation_parameters: List[str], ): - Gdist = Distribution("Gumbel", data=time_series2) + dist = Distributions("Gumbel", data=time_series2) for i in range(len(dist_estimation_parameters)): - param = Gdist.fit_model(method=dist_estimation_parameters[i], test=False) + param = dist.fit_model(method=dist_estimation_parameters[i], test=False) assert isinstance(param, dict) assert all(i in param.keys() for i in ["loc", "scale"]) - assert Gdist.parameters.get("loc") is not None - assert Gdist.parameters.get("scale") is not None + assert dist.parameters.get("loc") is not None + assert dist.parameters.get("scale") is not None From 9a742d10f1435758078fb2a0a6de4d6f09d14c7c Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Wed, 6 Dec 2023 22:52:56 +0100 Subject: [PATCH 28/44] refactor --- statista/distributions.py | 26 ++++++++------------------ statista/plot.py | 6 +++--- tests/test_distributions.py | 2 +- 3 files changed, 12 insertions(+), 22 deletions(-) diff --git a/statista/distributions.py b/statista/distributions.py index bdaa9f5..d352ce6 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -2098,8 +2098,7 @@ class Normal(AbstractDistribution): def __init__( self, data: Union[list, np.ndarray] = None, - loc: Union[int, float] = None, - scale: Union[int, float] = None, + parameters: Dict[str, str] = None, ): """Gumbel. @@ -2107,23 +2106,14 @@ def __init__( ---------- data : [list] data time series. - loc: [numeric] - location parameter - scale: [numeric] - scale parameter + parameters: Dict[str, str] + {"loc": val, "scale": val} + - loc: [numeric] + location parameter of the exponential distribution. + - scale: [numeric] + scale parameter of the exponential distribution. """ - if isinstance(data, list) or isinstance(data, np.ndarray): - self.data = np.array(data) - self.data_sorted = np.sort(data) - self.cdf_Weibul = PlottingPosition.weibul(data) - self.KStable = 1.22 / np.sqrt(len(self.data)) - - self.loc = loc - self.scale = scale - self.Dstatic = None - self.KS_Pvalue = None - self.chistatic = None - self.chi_Pvalue = None + super().__init__(data, parameters) @staticmethod def _pdf_eq( diff --git a/statista/plot.py b/statista/plot.py index 95d8af1..cf493f1 100644 --- a/statista/plot.py +++ b/statista/plot.py @@ -18,7 +18,7 @@ def pdf( qx: np.ndarray, pdf_fitted, data_sorted: np.ndarray, - figsize: tuple = (6, 5), + figsize: Tuple[float, float] = (6, 5), xlabel: str = "Actual data", ylabel: str = "pdf", fontsize: int = 11, @@ -113,8 +113,8 @@ def details( q_lower: Union[np.ndarray, list], q_upper: Union[np.ndarray, list], alpha: Number, - fig1size: tuple = (10, 5), - fig2size: tuple = (6, 6), + fig1size: Tuple[float, float] = (10, 5), + fig2size: Tuple[float, float] = (6, 6), xlabel: str = "Actual data", ylabel: str = "cdf", fontsize: int = 11, diff --git a/tests/test_distributions.py b/tests/test_distributions.py index 2c03172..7bfcc07 100644 --- a/tests/test_distributions.py +++ b/tests/test_distributions.py @@ -154,7 +154,7 @@ def test_probapility_plot( dist = Gumbel(time_series2) cdf_weibul = PlottingPosition.weibul(time_series2) param = dist.fit_model(method=dist_estimation_parameters_ks, test=False) - (fig1, fig2), (ax1, ax2) = dist.probapility_plot( + (fig1, fig2), (_, _) = dist.probapility_plot( param, cdf_weibul, alpha=confidence_interval_alpha ) assert isinstance(fig1, Figure) From b847f4e100a486046ce8f67f268c9adb51682134 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Fri, 8 Dec 2023 00:54:37 +0100 Subject: [PATCH 29/44] test eva --- pytest.ini | 4 + statista/eva.py | 164 ++++++++++--------------- tests/conftest.py | 21 ++++ tests/data/ams-gauges.csv | 55 +++++++++ tests/data/distribution_properties.csv | 8 ++ tests/data/statistical_properties.csv | 8 ++ tests/test_eva.py | 51 ++++++++ 7 files changed, 211 insertions(+), 100 deletions(-) create mode 100644 pytest.ini create mode 100644 tests/data/ams-gauges.csv create mode 100644 tests/data/distribution_properties.csv create mode 100644 tests/data/statistical_properties.csv create mode 100644 tests/test_eva.py diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..f92e0ec --- /dev/null +++ b/pytest.ini @@ -0,0 +1,4 @@ +[pytest] +markers = + slow: mark test as slow. + fast: mark test as fast. diff --git a/statista/eva.py b/statista/eva.py index 3448c1b..ef44772 100644 --- a/statista/eva.py +++ b/statista/eva.py @@ -7,7 +7,7 @@ from loguru import logger from pandas import DataFrame -from statista.distributions import GEV, Gumbel, PlottingPosition +from statista.distributions import PlottingPosition, Distributions def ams_analysis( @@ -19,11 +19,12 @@ def ams_analysis( filter_out: Union[float, int] = None, distribution: str = "GEV", method: str = "lmoments", + obj_func: callable = None, estimate_parameters: bool = False, quartile: float = 0, significance_level: float = 0.1, ) -> Tuple[DataFrame, DataFrame]: - """StatisticalProperties. + """ams_analysis. ams analysis method reads resamples all the the time series in the given dataframe to annual maximum, then fits the time series to a given distribution and parameter estimation method. @@ -49,7 +50,10 @@ def ams_analysis( distribution: [str] Default is "GEV". method: [str] - available methods are 'mle', 'mm', 'lmoments', optimization. Default is "lmoments" + available methods are 'mle', 'mm', 'lmoments', 'optimization'. Default is "lmoments" + obj_func: [callable] + objective function to be used in the optimization method, default is None. for Gumbel distribution there is the + Gumbel.objective_fn and similarly for the GEV distribution there is the GEV.objective_fn. estimate_parameters: [bool] Default is False. quartile: [float] @@ -93,7 +97,7 @@ def ams_analysis( "q500", "q1000", ] - col_csv = col_csv + rp_name + col_csv += rp_name # In a table where duplicates are removed (np.unique), find the number of # gauges contained in the .csv file. @@ -101,132 +105,92 @@ def ams_analysis( # and as columns all the output names. statistical_properties = pd.DataFrame(np.nan, index=gauges, columns=col_csv) statistical_properties.index.name = "id" + if distribution == "GEV": - distribution_properties = pd.DataFrame( - np.nan, - index=gauges, - columns=["c", "loc", "scale", "D-static", "P-Value"], - ) + cols = ["c", "loc", "scale", "D-static", "P-Value"] else: - distribution_properties = pd.DataFrame( - np.nan, - index=gauges, - columns=["loc", "scale", "D-static", "P-Value"], - ) + cols = ["loc", "scale", "D-static", "P-Value"] + + distribution_properties = pd.DataFrame( + np.nan, + index=gauges, + columns=cols, + ) distribution_properties.index.name = "id" # required return periods - T = [1.5, 2, 5, 10, 25, 50, 50, 100, 200, 500, 1000] - T = np.array(T) + return_period = [1.5, 2, 5, 10, 25, 50, 50, 100, 200, 500, 1000] + return_period = np.array(return_period) # these values are the Non Exceedance probability (F) of the chosen - # return periods F = 1 - (1/T) + # return periods non_exceed_prop = 1 - (1/return_period) # Non Exceedance propabilities - # F = [1/3, 0.5, 0.8, 0.9, 0.96, 0.98, 0.99, 0.995, 0.998] - F = 1 - (1 / T) + # non_exceed_prop = [1/3, 0.5, 0.8, 0.9, 0.96, 0.98, 0.99, 0.995, 0.998] + non_exceed_prop = 1 - (1 / return_period) save_to = Path(save_to) # Iteration over all the gauge numbers. if save_plots: rpath = save_to.joinpath("figures") if not rpath.exists(): - # os.mkdir(rpath) rpath.mkdir(parents=True, exist_ok=True) for i in gauges: - QTS = time_series_df.loc[:, i] + q_ts = time_series_df.loc[:, i] # The time series is resampled to the annual maxima, and turned into a numpy array. # The hydrological year is 1-Nov/31-Oct (from Petrow and Merz, 2009, JoH). if not ams: - ams_df = QTS.resample(ams_start).max().values + ams_df = q_ts.resample(ams_start).max().values else: - ams_df = QTS.values + ams_df = q_ts.values if filter_out is not None: ams_df = ams_df[ams_df != filter_out] - if estimate_parameters: - # TODO: still to be tested and prepared for GEV - # estimate the parameters through an optimization - # alpha = (np.sqrt(6) / np.pi) * ams_df.std() - # beta = ams_df.mean() - 0.5772 * alpha - # param_dist = [beta, alpha] + dist = Distributions(distribution, data=ams_df) + # estimate the parameters through the given method + try: threshold = np.quantile(ams_df, quartile) - if distribution == "GEV": - dist = GEV(ams_df) - param_dist = dist.fit_model( - method="optimization", - obj_func=Gumbel.objective_fn, - threshold=threshold, - ) - else: - dist = Gumbel(ams_df) - param_dist = dist.fit_model( - method="optimization", - obj_func=Gumbel.objective_fn, - threshold=threshold, - ) - else: - # estimate the parameters through maximum liklehood method - try: - if distribution == "GEV": - dist = GEV(ams_df) - # defult parameter estimation method is maximum liklihood method - param_dist = dist.fit_model(method=method) - else: - # A gumbel distribution is fitted to the annual maxima - dist = Gumbel(ams_df) - # defult parameter estimation method is maximum liklihood method - param_dist = dist.fit_model(method=method) - except Exception as e: - logger.warning( - f"The gauge {i} parameters could not be estimated because of {e}" - ) - continue + param_dist = dist.fit_model( + method=method, + obj_func=obj_func, + threshold=threshold, + ) + except Exception as e: + logger.warning( + f"The gauge {i} parameters could not be estimated because of {e}" + ) + continue ( distribution_properties.loc[i, "D-static"], distribution_properties.loc[i, "P-Value"], ) = dist.ks() + if distribution == "GEV": - distribution_properties.loc[i, "c"] = param_dist[0] - distribution_properties.loc[i, "loc"] = param_dist[1] - distribution_properties.loc[i, "scale"] = param_dist[2] + distribution_properties.loc[i, "c"] = param_dist["shape"] + distribution_properties.loc[i, "loc"] = param_dist["loc"] + distribution_properties.loc[i, "scale"] = param_dist["scale"] else: - distribution_properties.loc[i, "loc"] = param_dist[0] - distribution_properties.loc[i, "scale"] = param_dist[1] + distribution_properties.loc[i, "loc"] = param_dist["loc"] + distribution_properties.loc[i, "scale"] = param_dist["scale"] # Return periods from the fitted distribution are stored. # get the Discharge coresponding to the return periods - if distribution == "GEV": - Qrp = dist.theoretical_estimate( - param_dist[0], param_dist[1], param_dist[2], F - ) - else: - Qrp = dist.theoretical_estimate(param_dist[0], param_dist[1], F) + q_rp = dist.theoretical_estimate(param_dist, non_exceed_prop) # to get the Non Exceedance probability for a specific Value # sort the ams_df ams_df.sort() # calculate the F (Exceedence probability based on weibul) - cdf_Weibul = PlottingPosition.weibul(ams_df) + cdf_weibul = PlottingPosition.weibul(ams_df) # Gumbel.probapilityPlot method calculates the theoretical values # based on the Gumbel distribution # parameters, theoretical cdf (or weibul), and calculate the confidence interval if save_plots: - if distribution == "GEV": - fig, ax = dist.probapility_plot( - param_dist[0], - param_dist[1], - param_dist[2], - cdf_Weibul, - alpha=significance_level, - method=method, - ) - else: - fig, ax = dist.probapility_plot( - param_dist[0], - param_dist[1], - cdf_Weibul, - alpha=significance_level, - ) + fig, ax = dist.probapility_plot( + param_dist, + cdf_weibul, + alpha=significance_level, + method=method, + ) fig[0].savefig(f"{save_to}/figures/{i}.png", format="png") plt.close() @@ -234,24 +198,24 @@ def ams_analysis( fig[1].savefig(f"{save_to}/figures/f-{i}.png", format="png") plt.close() - statistical_properties.loc[i, "mean"] = QTS.mean() - statistical_properties.loc[i, "std"] = QTS.std() - statistical_properties.loc[i, "min"] = QTS.min() - statistical_properties.loc[i, "5%"] = QTS.quantile(0.05) - statistical_properties.loc[i, "25%"] = QTS.quantile(0.25) - statistical_properties.loc[i, "median"] = QTS.quantile(0.50) - statistical_properties.loc[i, "75%"] = QTS.quantile(0.75) - statistical_properties.loc[i, "95%"] = QTS.quantile(0.95) - statistical_properties.loc[i, "max"] = QTS.max() - statistical_properties.loc[i, "t_beg"] = QTS.index.min() - statistical_properties.loc[i, "t_end"] = QTS.index.max() + statistical_properties.loc[i, "mean"] = q_ts.mean() + statistical_properties.loc[i, "std"] = q_ts.std() + statistical_properties.loc[i, "min"] = q_ts.min() + statistical_properties.loc[i, "5%"] = q_ts.quantile(0.05) + statistical_properties.loc[i, "25%"] = q_ts.quantile(0.25) + statistical_properties.loc[i, "median"] = q_ts.quantile(0.50) + statistical_properties.loc[i, "75%"] = q_ts.quantile(0.75) + statistical_properties.loc[i, "95%"] = q_ts.quantile(0.95) + statistical_properties.loc[i, "max"] = q_ts.max() + statistical_properties.loc[i, "t_beg"] = q_ts.index.min() + statistical_properties.loc[i, "t_end"] = q_ts.index.max() if not ams: statistical_properties.loc[i, "nyr"] = ( statistical_properties.loc[i, "t_end"] - statistical_properties.loc[i, "t_beg"] ).days / 365.25 - for irp, irp_name in zip(Qrp, rp_name): + for irp, irp_name in zip(q_rp, rp_name): statistical_properties.loc[i, irp_name] = irp # Print for prompt and check progress. diff --git a/tests/conftest.py b/tests/conftest.py index 537d660..3d8403c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,6 +2,7 @@ import numpy as np import pandas as pd +from pandas import DataFrame import pytest @@ -73,3 +74,23 @@ def ci_cdf() -> np.ndarray: @pytest.fixture(scope="module") def ci_param() -> Dict[str, float]: return {"loc": 464.825, "scale": 222.120, "shape": 0.01012} + + +@pytest.fixture(scope="module") +def ams_gauges() -> DataFrame: + """AMS gauges""" + ams = pd.read_csv(f"tests/data/ams-gauges.csv") + ams.index = ams["date"] + return ams + + +@pytest.fixture(scope="module") +def gauges_statistical_properties() -> DataFrame: + """AMS gauges""" + return pd.read_csv(f"tests/data/statistical_properties.csv", index_col="id") + + +@pytest.fixture(scope="module") +def gauges_distribution_properties() -> DataFrame: + """AMS gauges""" + return pd.read_csv(f"tests/data/distribution_properties.csv", index_col="id") diff --git a/tests/data/ams-gauges.csv b/tests/data/ams-gauges.csv new file mode 100644 index 0000000..306f8c4 --- /dev/null +++ b/tests/data/ams-gauges.csv @@ -0,0 +1,55 @@ +Frankfurt,Mainz,Kaub,Andernach,Cologne,Rees,date +-9,4250,4480,6080,6490,6830,1951 +-9,4490,4610,6970,7110,7340,1952 +-9,4270,4380,7300,7610,7970,1953 +-9,2850,2910,3440,3620,3840,1954 +-9,5940,6050,9460,9460,9500,1955 +-9,5000,5150,7140,7270,7540,1956 +-9,4500,4520,6650,6750,6950,1957 +-9,5020,5260,8480,8600,9080,1958 +-9,3050,3180,4950,5100,5420,1959 +-9,2560,2660,3310,3400,3550,1960 +-9,2940,3220,5000,5250,5840,1961 +-9,3460,3620,5270,5460,5880,1962 +-9,2360,2550,3300,3540,3820,1963 +432,2780,3090,5160,5480,5510,1964 +913,4430,4460,5890,6130,6350,1965 +967,4430,4560,6960,7410,7720,1966 +962,3950,4240,6920,7290,7570,1967 +1100,4130,4280,6970,7160,7520,1968 +797,3370,3540,5130,5270,5340,1969 +1760,6630,6670,9990,9690,9900,1970 +440,2410,2510,3220,3520,3810,1971 +292,2100,2040,2220,2270,2330,1972 +347,3680,3690,5220,5380,5290,1973 +470,2940,2910,3880,4050,4260,1974 +834,3740,3740,5440,5750,6190,1975 +447,2150,2180,3100,3270,3560,1976 +619,4120,4320,6460,6680,6560,1977 +540,5110,5310,6200,6340,6330,1978 +882,4490,4600,6580,6730,6900,1979 +1240,5470,5630,8450,8800,8760,1980 +1160,4490,4553,6271,6130,6500,1981 +1490,5480,5600,7793,7967,7787,1982 +890,5770,6090,9570,9801,9868,1983 +1230,4520,4880,7980,8433,8502,1984 +548,3040,3230,4420,4880,4780,1985 +795,3850,3980,5860,5890,6210,1986 +1280,4670,4870,6960,7130,7590,1987 +1760,6920,7160,9250,9550,10200,1988 +723,3480,3680,5420,5300,5480,1989 +830,4820,5130,7450,7250,6970,1990 +673,3400,3710,6190,6190,6590,1991 +489,3750,3930,5230,5210,5440,1992 +500,3640,3780,5400,5480,5810,1993 +1220,5490,6310,10400,10600,10600,1994 +1990,5900,6520,10100,10700,11300,1995 +669,3760,3860,4480,4280,4250,1996 +914,4120,4210,6960,7080,6970,1997 +1060,4720,4790,6910,6700,6150,1998 +1420,5480,5730,8160,8530,9240,1999 +625,3750,3900,6390,6370,6550,2000 +1140,5420,5710,8320,8410,8410,2001 +1170,4950,5140,7260,7240,7940,2002 +1800,5090,5350,8620,8840,9470,2003 +197,1150,1190,1470,1580,1810,2004 diff --git a/tests/data/distribution_properties.csv b/tests/data/distribution_properties.csv new file mode 100644 index 0000000..2d177b6 --- /dev/null +++ b/tests/data/distribution_properties.csv @@ -0,0 +1,8 @@ +id,c,loc,scale,D-static,P-Value +Frankfurt,0.051851826887363194,718.7207607719855,376.1886075385216,0.07317073170731707,0.9999427584427157 +Mainz,0.3072948665432741,3743.8060125160628,1214.6170423632827,0.05555555555555555,0.9999984404687655 +Kaub,0.28257953512255224,3881.573476779092,1262.4260864019852,0.05555555555555555,0.9999984404687655 +Andernach,0.3215125279410673,5649.076007828818,2084.3831316091128,0.07407407407407407,0.9987375782247235 +Cologne,0.3061460861379136,5783.017454258022,2090.224036968223,0.07407407407407407,0.9987375782247235 +Rees,0.2842269596672276,5960.022502574694,2107.1972100234184,0.07407407407407407,0.9987375782247235 +date,0.2837753,1971.8005910014972,16.185304148413852,0.05555555555555555,0.9999984404687655 diff --git a/tests/data/statistical_properties.csv b/tests/data/statistical_properties.csv new file mode 100644 index 0000000..b8f933b --- /dev/null +++ b/tests/data/statistical_properties.csv @@ -0,0 +1,8 @@ +id,mean,std,min,5%,25%,median,75%,95%,max,t_beg,t_end,nyr,q1.5,q2,q5,q10,q25,q50,q100,q200,q500,q1000 +Frankfurt,694.4074074074074,552.7567453832984,-9.0,-9.0,220.75,671.0,1090.0,1760.0,1990.0,1951.0,2004.0,,683.254633541981,855.2968644540772,1261.59649434511,1517.7587689069342,1827.4881315023772,2047.6221433340565,2047.6221433340565,2258.332885614113,2460.823382586069,2717.037039149113 +Mainz,4153.333333333333,1192.8038950621649,1150.0,2286.5,3415.0,4190.0,4987.5,5914.0,6920.0,1951.0,2004.0,,3627.907223538407,4164.8247438013,5203.502461613553,5716.905569818638,6217.243858574832,6504.77677815569,6504.77677815569,6734.883441589332,6919.948680476143,7110.76711483629 +Kaub,4327.092592592592,1254.6913665229047,1190.0,2394.5,3635.0,4350.0,5147.5,6383.499999999999,7160.0,1951.0,2004.0,,3761.2533136087277,4321.114689217054,5425.005521555241,5983.738153728853,6539.689757719358,6865.849995253274,6865.849995253274,7131.430892159442,7348.738113198606,7577.263513026446 +Andernach,6333.407407407408,2035.1432337383255,1470.0,3178.0,5175.0,6425.0,7412.5,9716.999999999998,10400.0,1951.0,2004.0,,5450.050443190599,6369.73494997472,8129.537878847686,8987.581310753912,9813.85630446624,10283.08467020549,10283.08467020549,10654.874461924472,10950.940916338675,11252.770123424481 +Cologne,6489.277777777777,2056.1328917541928,1580.0,3354.5,5277.5,6585.0,7560.0,9728.849999999999,10700.0,1951.0,2004.0,,5583.579049437877,6507.694660012967,8296.99616881387,9182.397798404068,10046.101957290637,10542.929863583495,10542.929863583495,10940.851299007954,11261.139355948999,11591.687059501717 +Rees,6701.425925925926,2094.47830764655,1810.0,3556.5,5450.0,6575.0,7901.75,10004.999999999998,11300.0,1951.0,2004.0,,5759.172691179417,6693.471602097722,8533.308506102763,9463.069144160174,10386.920556361936,10928.17130944753,10928.17130944753,11368.384249416642,11728.167907979188,12106.027638139985 +date,1977.5,15.732132722552274,1951.0,1953.65,1964.25,1977.5,1990.75,2001.35,2004.0,1951.0,2004.0,,1970.2579039098111,1977.4346447381406,1991.572128206143,1998.7195933109315,2005.824331043915,2009.9883077483444,2009.9883077483444,2013.3760478216004,2016.145701283059,2019.055555233493 diff --git a/tests/test_eva.py b/tests/test_eva.py new file mode 100644 index 0000000..74bfd6e --- /dev/null +++ b/tests/test_eva.py @@ -0,0 +1,51 @@ +""" Tests for the eva module. """ +import numpy as np +from pandas import DataFrame +import shutil +from pathlib import Path +import pytest +from statista.eva import ams_analysis + + +@pytest.mark.slow +def test_eva( + ams_gauges: DataFrame, + gauges_statistical_properties: DataFrame, + gauges_distribution_properties: DataFrame, +): + path = Path("tests/data/gauges/figures") + if path.exists(): + try: + path.rmdir() + except PermissionError: + print("PermissionError: files were not deleted") + + method = "lmoments" + save_to = "tests/data/gauges" + statistical_properties, distribution_properties = ams_analysis( + time_series_df=ams_gauges, + ams=True, + save_plots=True, + save_to=save_to, + filter_out=-9, + method=method, + significance_level=0.05, + ) + statistical_properties.drop(columns=["nyr"], inplace=True) + gauges_statistical_properties.drop(columns=["nyr"], inplace=True) + assert ( + np.isclose( + statistical_properties.values, + gauges_statistical_properties.values, + atol=0.01, + ) + ).all() + assert ( + np.isclose( + distribution_properties.values, + gauges_distribution_properties.values, + atol=0.01, + ) + ).all() + # try: + shutil.rmtree(path) From 594b560f2ae86ff833e0a481ed701aa2f994eb46 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Fri, 8 Dec 2023 01:12:58 +0100 Subject: [PATCH 30/44] update documentations --- statista/eva.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/statista/eva.py b/statista/eva.py index ef44772..ee9230c 100644 --- a/statista/eva.py +++ b/statista/eva.py @@ -20,7 +20,6 @@ def ams_analysis( distribution: str = "GEV", method: str = "lmoments", obj_func: callable = None, - estimate_parameters: bool = False, quartile: float = 0, significance_level: float = 0.1, ) -> Tuple[DataFrame, DataFrame]: @@ -54,8 +53,6 @@ def ams_analysis( obj_func: [callable] objective function to be used in the optimization method, default is None. for Gumbel distribution there is the Gumbel.objective_fn and similarly for the GEV distribution there is the GEV.objective_fn. - estimate_parameters: [bool] - Default is False. quartile: [float] the quartile is only used when estinating the distribution parameters based on optimization and a threshould value, the threshould value will be calculated as a the quartile coresponding to the value of this parameter. @@ -68,6 +65,27 @@ def ams_analysis( file containing some statistical properties like mean, std, min, 5%, 25%, median, 75%, 95%, max, t_beg, t_end, nyr, q1.5, q2, q5, q10, q25, q50, q100, q200, q500. + + id,mean,std,min,5%,25%,median,75%,95%,max,t_beg,t_end,nyr,q1.5,q2,q5,q10,q25,q50,q100,q200,q500,q1000 + Frankfurt,694.4,552.8,-9.0,-9.0,220.8,671.0,1090.0,1760.0,1990.0,1951.0,2004.0,,683.3,855.3,1261.6,1517.8,1827.5,2047.6,2047.6,2258.3,2460.8,2717.0 + Mainz,4153.3,1192.8,1150.0,2286.5,3415.0,4190.0,4987.5,5914.0,6920.0,1951.0,2004.0,,3627.9,4164.8,5203.5,5716.9,6217.2,6504.8,6504.8,6734.9,6919.9,7110.8 + Kaub,4327.1,1254.7,1190.0,2394.5,3635.0,4350.0,5147.5,6383.5,7160.0,1951.0,2004.0,,3761.3,4321.1,5425.0,5983.7,6539.7,6865.8,6865.8,7131.4,7348.7,7577.3 + Andernach,6333.4,2035.1,1470.0,3178.0,5175.0,6425.0,7412.5,9717.0,10400.0,1951.0,2004.0,,5450.1,6369.7,8129.5,8987.6,9813.9,10283.1,10283.1,10654.9,10950.9,11252.8 + Cologne,6489.3,2056.1,1580.0,3354.5,5277.5,6585.0,7560.0,9728.9,10700.0,1951.0,2004.0,,5583.6,6507.7,8297.0,9182.4,10046.1,10542.9,10542.9,10940.9,11261.1,11591.7 + Rees,6701.4,2094.5,1810.0,3556.5,5450.0,6575.0,7901.8,10005.0,11300.0,1951.0,2004.0,,5759.2,6693.5,8533.3,9463.1,10386.9,10928.2,10928.2,11368.4,11728.2,12106.0 + date,1977.5,15.7,1951.0,1953.7,1964.2,1977.5,1990.8,2001.3,2004.0,1951.0,2004.0,,1970.3,1977.4,1991.6,1998.7,2005.8,2010.0,2010.0,2013.4,2016.1,2019.1 + Distribution Properties.csv: + the shape, location, and scale parameters of the fitted distribution, plus the D-static and P-Value of the KS + test. + + id,c,loc,scale,D-static,P-Value + Frankfurt,0.1,718.7,376.2,0.1,1.0 + Mainz,0.3,3743.8,1214.6,0.1,1.0 + Kaub,0.3,3881.6,1262.4,0.1,1.0 + Andernach,0.3,5649.1,2084.4,0.1,1.0 + Cologne,0.3,5783.0,2090.2,0.1,1.0 + Rees,0.3,5960.0,2107.2,0.1,1.0 + date,0.3,1971.8,16.2,0.1,1.0 """ gauges = time_series_df.columns.tolist() # List of the table output, including some general data and the return periods. From 813794a26f65fe0009b1bce20eb199ab03fb3d88 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Fri, 8 Dec 2023 01:15:47 +0100 Subject: [PATCH 31/44] update documentations --- statista/eva.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/statista/eva.py b/statista/eva.py index ee9230c..979070b 100644 --- a/statista/eva.py +++ b/statista/eva.py @@ -61,8 +61,8 @@ def ams_analysis( Returns ------- - Statistical Properties.csv: - file containing some statistical properties like mean, std, min, 5%, 25%, + DataFrame: + Statistical properties like mean, std, min, 5%, 25%, median, 75%, 95%, max, t_beg, t_end, nyr, q1.5, q2, q5, q10, q25, q50, q100, q200, q500. @@ -74,9 +74,9 @@ def ams_analysis( Cologne,6489.3,2056.1,1580.0,3354.5,5277.5,6585.0,7560.0,9728.9,10700.0,1951.0,2004.0,,5583.6,6507.7,8297.0,9182.4,10046.1,10542.9,10542.9,10940.9,11261.1,11591.7 Rees,6701.4,2094.5,1810.0,3556.5,5450.0,6575.0,7901.8,10005.0,11300.0,1951.0,2004.0,,5759.2,6693.5,8533.3,9463.1,10386.9,10928.2,10928.2,11368.4,11728.2,12106.0 date,1977.5,15.7,1951.0,1953.7,1964.2,1977.5,1990.8,2001.3,2004.0,1951.0,2004.0,,1970.3,1977.4,1991.6,1998.7,2005.8,2010.0,2010.0,2013.4,2016.1,2019.1 - Distribution Properties.csv: - the shape, location, and scale parameters of the fitted distribution, plus the D-static and P-Value of the KS - test. + DataFrame: + Distribution properties like the shape, location, and scale parameters of the fitted distribution, plus the + D-static and P-Value of the KS test. id,c,loc,scale,D-static,P-Value Frankfurt,0.1,718.7,376.2,0.1,1.0 From 64350b5927d6d897618f0edc462654b167a1a0e7 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Sun, 10 Dec 2023 22:44:06 +0100 Subject: [PATCH 32/44] refactor --- examples/Extreme value statistics.py | 5 +- examples/SensitivityAnalysis.py | 14 +-- statista/metrics.py | 150 +++++++++++++++------------ 3 files changed, 92 insertions(+), 77 deletions(-) diff --git a/examples/Extreme value statistics.py b/examples/Extreme value statistics.py index 60b237e..e141bb6 100644 --- a/examples/Extreme value statistics.py +++ b/examples/Extreme value statistics.py @@ -1,7 +1,4 @@ -"""Created on Wed Sep 9 23:31:11 2020. - -@author: mofarrag -""" +"""Extreme value statistics""" import matplotlib matplotlib.use("TkAgg") diff --git a/examples/SensitivityAnalysis.py b/examples/SensitivityAnalysis.py index ae095a4..34f03a0 100644 --- a/examples/SensitivityAnalysis.py +++ b/examples/SensitivityAnalysis.py @@ -67,11 +67,11 @@ Qobs = Coello.QGauges[Coello.QGauges.columns[0]] -Metrics["RMSE"] = PC.RMSE(Qobs, Coello.Qsim["q"]) -Metrics["NSE"] = PC.NSE(Qobs, Coello.Qsim["q"]) -Metrics["NSEhf"] = PC.NSEHF(Qobs, Coello.Qsim["q"]) -Metrics["KGE"] = PC.KGE(Qobs, Coello.Qsim["q"]) -Metrics["WB"] = PC.WB(Qobs, Coello.Qsim["q"]) +Metrics["RMSE"] = PC.rmse(Qobs, Coello.Qsim["q"]) +Metrics["NSE"] = PC.nse(Qobs, Coello.Qsim["q"]) +Metrics["NSEhf"] = PC.nse_hf(Qobs, Coello.Qsim["q"]) +Metrics["KGE"] = PC.kge(Qobs, Coello.Qsim["q"]) +Metrics["WB"] = PC.wb(Qobs, Coello.Qsim["q"]) print("RMSE= " + str(round(Metrics["RMSE"], 2))) print("NSE= " + str(round(Metrics["NSE"], 2))) @@ -120,7 +120,7 @@ def WrapperType1(Randpar, Route, RoutingFn, Qobs): Coello.Parameters = Randpar Run.RunLumped(Coello, Route, RoutingFn) - rmse = PC.RMSE(Qobs, Coello.Qsim["q"]) + rmse = PC.rmse(Qobs, Coello.Qsim["q"]) return rmse @@ -129,7 +129,7 @@ def WrapperType2(Randpar, Route, RoutingFn, Qobs): Coello.Parameters = Randpar Run.RunLumped(Coello, Route, RoutingFn) - rmse = PC.RMSE(Qobs, Coello.Qsim["q"]) + rmse = PC.rmse(Qobs, Coello.Qsim["q"]) return rmse, Coello.Qsim["q"] diff --git a/statista/metrics.py b/statista/metrics.py index 8f69c0a..df67a8d 100644 --- a/statista/metrics.py +++ b/statista/metrics.py @@ -1,3 +1,4 @@ +""" Performance Metrics """ from numbers import Number from typing import Union @@ -5,7 +6,7 @@ from sklearn.metrics import r2_score -def RMSE(obs: Union[list, np.ndarray], sim: Union[list, np.ndarray]) -> float: +def rmse(obs: Union[list, np.ndarray], sim: Union[list, np.ndarray]) -> float: """Root Mean Squared Error. Metric for the estimation of performance of the hydrological model. Parameters @@ -29,11 +30,11 @@ def RMSE(obs: Union[list, np.ndarray], sim: Union[list, np.ndarray]) -> float: return rmse -def RMSEHF( +def rmse_hf( obs: Union[list, np.ndarray], sim: Union[list, np.ndarray], - WStype: int, - N: int, + ws_type: int, + n: int, alpha: Union[int, float], ) -> float: """Weighted Root mean square Error for High flow. @@ -44,9 +45,9 @@ def RMSEHF( observed flow sim: [list/array] simulated flow - WStype: + ws_type: Weighting scheme (1,2,3,4) - N: + n: power alpha: Upper limit for low flow weight @@ -55,44 +56,51 @@ def RMSEHF( ------- error values """ - # input data validation - # data type - assert isinstance( - WStype, int - ), f"Weighting scheme should be an integer number between 1 and 4 and you entered {WStype}" - assert isinstance(alpha, int) or isinstance( - alpha, float - ), "alpha should be a number and between 0 & 1" - assert isinstance(N, Number), "N should be a number and between 0 & 1" + if not isinstance(ws_type, int): + raise TypeError( + f"Weighting scheme should be an integer number between 1 and 4 and you entered {ws_type}" + ) + + if not isinstance(alpha, int) or not isinstance(alpha, float): + raise ValueError("alpha should be a number and between 0 & 1") + + if not isinstance(n, Number): + raise TypeError("N should be a number and between 0 & 1") + # Input values - assert ( - 1 <= WStype <= 4 - ), f"Weighting scheme should be an integer number between 1 and 4 you have enters {WStype}" - assert ( - N >= 0 - ), f"Weighting scheme Power should be positive number you have entered {N}" - assert ( - 0 < alpha < 1 - ), f"alpha should be float number and between 0 & 1 you have entered {alpha}" + if not (1 <= ws_type <= 4): + raise ValueError( + f"Weighting scheme should be an integer number between 1 and 4 you have enters {ws_type}" + ) + + if not (n >= 0): + raise ValueError( + f"Weighting scheme Power should be positive number you have entered {n}" + ) + + if not (0 < alpha < 1): + raise ValueError( + f"alpha should be float number and between 0 & 1 you have entered {alpha}" + ) # convert obs & sim into arrays obs = np.array(obs) sim = np.array(sim) - Qmax = max(obs) - h = obs / Qmax # rational Discharge + qmax = max(obs) + h = obs / qmax # rational Discharge - if WStype == 1: - w = h**N # rational Discharge power N + if ws_type == 1: + w = h**n # rational Discharge power N elif ( - WStype == 2 + ws_type == 2 ): # -------------------------------------------------------------N is not in the equation - w = (h / alpha) ** N + w = (h / alpha) ** n w[h > alpha] = 1 - elif WStype == 3: + elif ws_type == 3: w = np.zeros(np.size(h)) # zero for h < alpha and 1 for h > alpha w[h > alpha] = 1 - elif WStype == 4: + elif ws_type == 4: w = np.zeros(np.size(h)) # zero for h < alpha and 1 for h > alpha w[h > alpha] = 1 else: # sigmoid function @@ -106,11 +114,11 @@ def RMSEHF( return error -def RMSELF( +def rmse_lf( obs: Union[list, np.ndarray], - Qsim: Union[list, np.ndarray], - WStype: int, - N: int, + qsim: Union[list, np.ndarray], + ws_type: int, + n: int, alpha: Union[int, float], ) -> float: """Weighted Root mean square Error for low flow. @@ -132,26 +140,26 @@ def RMSELF( ------- error values """ - if not isinstance(WStype, int): + if not isinstance(ws_type, int): raise TypeError( - f"Weighting scheme should be an integer number between 1 and 4 and you entered {WStype}" + f"Weighting scheme should be an integer number between 1 and 4 and you entered {ws_type}" ) if not (isinstance(alpha, int) or isinstance(alpha, float)): raise TypeError("alpha should be a number and between 0 & 1") - if not isinstance(N, Number): + if not isinstance(n, Number): raise TypeError("N should be a number and between 0 & 1") # Input values - if not 1 <= WStype <= 4: + if not 1 <= ws_type <= 4: raise ValueError( - f"Weighting scheme should be an integer number between 1 and 4 you have enters {WStype}" + f"Weighting scheme should be an integer number between 1 and 4 you have enters {ws_type}" ) - if not N >= 0: + if not n >= 0: raise ValueError( - f"Weighting scheme Power should be positive number you have entered {N}" + f"Weighting scheme Power should be positive number you have entered {n}" ) if not 0 < alpha < 1: @@ -161,22 +169,22 @@ def RMSELF( # convert obs & sim into arrays obs = np.array(obs) - Qsim = np.array(Qsim) + qsim = np.array(qsim) - Qmax = max(obs) # rational Discharge power N - qr = (Qmax - obs) / Qmax + qmax = max(obs) # rational Discharge power N + qr = (qmax - obs) / qmax - if WStype == 1: - w = qr**N - elif WStype == 2: # ------------------------------- N is not in the equation + if ws_type == 1: + w = qr**n + elif ws_type == 2: # ------------------------------- N is not in the equation # w=1-qr*((0.50 - alpha)**N) w = ((1 / (alpha**2)) * (1 - qr) ** 2) - ((2 / alpha) * (1 - qr)) + 1 w[1 - qr > alpha] = 0 - elif WStype == 3: # the same like WStype 2 + elif ws_type == 3: # the same like WStype 2 # w=1-qr*((0.50 - alpha)**N) w = ((1 / (alpha**2)) * (1 - qr) ** 2) - ((2 / alpha) * (1 - qr)) + 1 w[1 - qr > alpha] = 0 - elif WStype == 4: + elif ws_type == 4: # w = 1-qr*(0.50 - alpha) w = 1 - ((1 - qr) / alpha) w[1 - qr > alpha] = 0 @@ -184,7 +192,7 @@ def RMSELF( # w=1/(1+np.exp(10*h-5)) w = 1 / (1 + np.exp(-10 * qr + 5)) - a = (obs - Qsim) ** 2 + a = (obs - qsim) ** 2 b = a * w c = sum(b) error = np.sqrt(c / len(obs)) @@ -192,8 +200,13 @@ def RMSELF( return error -def KGE(obs: Union[list, np.ndarray], sim: Union[list, np.ndarray]): - """(Gupta et al. 2009) have showed the limitation of using a single error function to measure the efficiency of calculated flow and showed that Nash-Sutcliff efficiency (NSE) or RMSE can be decomposed into three component correlation, variability and bias. +def kge(obs: Union[list, np.ndarray], sim: Union[list, np.ndarray]): + """kge. + + ling–Gupta efficiency + (Gupta et al. 2009) have showed the limitation of using a single error function to measure the efficiency of + calculated flow and showed that Nash-Sutcliff efficiency (NSE) or RMSE can be decomposed into three component + correlation, variability and bias. Parameters ---------- @@ -219,8 +232,13 @@ def KGE(obs: Union[list, np.ndarray], sim: Union[list, np.ndarray]): return kge -def WB(obs, Qsim): - """The mean cumulative error measures how much the model succeed to reproduce the stream flow volume correctly. This error allows error compensation from time step to another and it is not an indication on how accurate is the model in the simulated flow. the naive model of Nash-Sutcliffe (simulated flow is as accurate as average observed flow) will result in WB error equals to 100 %. (Oudin et al. 2006) +def wb(obs, qsim): + """wb. + Water balance error. + The mean cumulative error measures how much the model succeed to reproduce the stream flow volume correctly. + This error allows error compensation from time step to another and it is not an indication on how accurate is the + model in the simulated flow. the naive model of Nash-Sutcliffe (simulated flow is as accurate as average observed + flow) will result in WB error equals to 100 %. (Oudin et al. 2006) inputs: ---------- @@ -233,14 +251,14 @@ def WB(obs, Qsim): ------- error values """ - Qobssum = np.sum(obs) - Qsimsum = np.sum(Qsim) - wb = 100 * (1 - np.abs(1 - (Qsimsum / Qobssum))) + qobs_sum = np.sum(obs) + qsim_sum = np.sum(qsim) + wb = 100 * (1 - np.abs(1 - (qsim_sum / qobs_sum))) return wb -def NSE(obs: np.ndarray, sim: np.ndarray): +def nse(obs: np.ndarray, sim: np.ndarray): """Nash-Sutcliffe efficiency. Metric for the estimation of performance of the hydrological model. Parameters @@ -266,7 +284,7 @@ def NSE(obs: np.ndarray, sim: np.ndarray): return e -def NSEHF(obs: Union[list, np.ndarray], sim: Union[list, np.ndarray]): +def nse_hf(obs: Union[list, np.ndarray], sim: Union[list, np.ndarray]): """NSEHF. Modified Nash-Sutcliffe efficiency. Metric for the estimation of performance of the @@ -301,7 +319,7 @@ def NSEHF(obs: Union[list, np.ndarray], sim: Union[list, np.ndarray]): return e -def NSELF(obs: Union[list, np.ndarray], sim: Union[list, np.ndarray]): +def nse_lf(obs: Union[list, np.ndarray], sim: Union[list, np.ndarray]): """NSELF. Modified Nash-Sutcliffe efficiency. Metric for the estimation of performance of the @@ -336,7 +354,7 @@ def NSELF(obs: Union[list, np.ndarray], sim: Union[list, np.ndarray]): return e -def MBE(obs: Union[list, np.ndarray], sim: Union[list, np.ndarray]): +def mbe(obs: Union[list, np.ndarray], sim: Union[list, np.ndarray]): """MBE (mean bias error) MBE = (sim - obs)/n @@ -357,7 +375,7 @@ def MBE(obs: Union[list, np.ndarray], sim: Union[list, np.ndarray]): return (np.array(sim) - np.array(obs)).mean() -def MAE(obs: Union[list, np.ndarray], sim: Union[list, np.ndarray]): +def mae(obs: Union[list, np.ndarray], sim: Union[list, np.ndarray]): """MAE (mean absolute error) MAE = |(obs - sim)|/n @@ -378,7 +396,7 @@ def MAE(obs: Union[list, np.ndarray], sim: Union[list, np.ndarray]): return np.abs(np.array(obs) - np.array(sim)).mean() -def PearsonCorre(x: Union[list, np.ndarray], y: Union[list, np.ndarray]) -> Number: +def pearson_corre(x: Union[list, np.ndarray], y: Union[list, np.ndarray]) -> Number: """Pearson correlation coefficient. - Pearson correlation coefficient is independent of the magnitude of the numbers. @@ -405,7 +423,7 @@ def PearsonCorre(x: Union[list, np.ndarray], y: Union[list, np.ndarray]) -> Numb return np.corrcoef(np.array(x), np.array(y))[0][1] -def R2(obs: Union[list, np.ndarray], sim: Union[list, np.ndarray]): +def r2(obs: Union[list, np.ndarray], sim: Union[list, np.ndarray]): """R2. the coefficient of determination measures how well the predicted From 696888e783fd279e9445cecb79d747155b7e21b2 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Sun, 10 Dec 2023 22:53:35 +0100 Subject: [PATCH 33/44] refactor --- examples/Extreme value statistics.py | 30 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/examples/Extreme value statistics.py b/examples/Extreme value statistics.py index e141bb6..2bfb4a7 100644 --- a/examples/Extreme value statistics.py +++ b/examples/Extreme value statistics.py @@ -31,14 +31,14 @@ # calculate the CDF(Non Exceedance probability) using weibul plotting position time_series1.sort() # calculate the F (Non Exceedence probability based on weibul) -cdf_Weibul = PlottingPosition.weibul(time_series1) +cdf_weibul = PlottingPosition.weibul(time_series1) # TheporeticalEstimate method calculates the theoretical values based on the Gumbel distribution -Qth = gumbel_dist.theoretical_estimate(param_lmoments, cdf_Weibul) +Qth = gumbel_dist.theoretical_estimate(param_lmoments, cdf_weibul) # test = stats.chisquare(st.Standardize(Qth), st.Standardize(time_series1),ddof=5) # calculate the confidence interval -upper, lower = gumbel_dist.confidence_interval(param_lmoments, cdf_Weibul, alpha=0.1) +upper, lower = gumbel_dist.confidence_interval(param_lmoments, cdf_weibul, alpha=0.1) # ProbapilityPlot can estimate the Qth and the lower and upper confidence interval in the process of plotting -fig, ax = gumbel_dist.probapility_plot(param_lmoments, cdf_Weibul, alpha=0.1) +fig, ax = gumbel_dist.probapility_plot(param_lmoments, cdf_weibul, alpha=0.1) # %% """ if you want to focus only on high values, you can use a threshold to make the code focus on what is higher @@ -46,17 +46,17 @@ """ threshold = 17 param_dist = gumbel_dist.fit_model( - method="optimization", ObjFunc=Gumbel.objective_fn, threshold=threshold + method="optimization", obj_func=Gumbel.objective_fn, threshold=threshold ) print(param_dist) -gumbel_dist.probapility_plot(param_dist, cdf_Weibul, alpha=0.1) +gumbel_dist.probapility_plot(param_dist, cdf_weibul, alpha=0.1) # %% threshold = 18 param_dist = gumbel_dist.fit_model( - method="optimization", ObjFunc=Gumbel.objective_fn, threshold=threshold + method="optimization", obj_func=Gumbel.objective_fn, threshold=threshold ) print(param_dist) -gumbel_dist.probapility_plot(param_dist, cdf_Weibul, alpha=0.1) +gumbel_dist.probapility_plot(param_dist, cdf_weibul, alpha=0.1) # %% Generalized Extreme Value (GEV) gev_dist = GEV(time_series2) # default parameter estimation method is maximum liklihood method @@ -77,15 +77,15 @@ #%% time_series1.sort() # calculate the F (Non Exceedence probability based on weibul) -cdf_Weibul = PlottingPosition.weibul(time_series1) +cdf_weibul = PlottingPosition.weibul(time_series1) T = PlottingPosition.weibul(time_series1, return_period=True) # TheporeticalEstimate method calculates the theoretical values based on the Gumbel distribution -Qth = gev_dist.theoretical_estimate(gev_lmom_param, cdf_Weibul) +Qth = gev_dist.theoretical_estimate(gev_lmom_param, cdf_weibul) func = GEV.ci_func upper, lower = gev_dist.confidence_interval( gev_lmom_param, - F=cdf_Weibul, + prob_non_exceed=cdf_weibul, alpha=0.1, statfunction=func, n_samples=len(time_series1), @@ -100,12 +100,12 @@ statfunction=func, gevfit=gev_lmom_param, n_samples=len(time_series1), - F=cdf_Weibul, + F=cdf_weibul, method="lmoments", ) -LB = CI["LB"] -UB = CI["UB"] +LB = CI["lb"] +UB = CI["ub"] # %% fig, ax = gev_dist.probapility_plot( - gev_lmom_param, cdf_Weibul, func=func, n_samples=len(time_series1) + gev_lmom_param, cdf_weibul, func=func, n_samples=len(time_series1) ) From bf7670e2fa0e5fa72147834d8933413f3d7e7ce2 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Mon, 11 Dec 2023 20:31:41 +0100 Subject: [PATCH 34/44] update examples --- examples/data/pdf_obs.txt | 61 ++++++++++++++++++++++++++++++++++ examples/heavy-tail-example.py | 29 +++++++++------- 2 files changed, 78 insertions(+), 12 deletions(-) create mode 100644 examples/data/pdf_obs.txt diff --git a/examples/data/pdf_obs.txt b/examples/data/pdf_obs.txt new file mode 100644 index 0000000..4573412 --- /dev/null +++ b/examples/data/pdf_obs.txt @@ -0,0 +1,61 @@ +"ams" "pdf" +7550.433 0.000154642269711567 +8651.166 0.000117765584990689 +9380.397 9.33406205964961e-05 +9071.717 0.000103377700612861 +8354.173 0.000128159692079377 +6161.421 0.000170527780685648 +3544.866 2.77636664143863e-05 +7120.425 0.000165513917257198 +9298.242 9.59581061243758e-05 +4710.178 0.000103421285516972 +5380.688 0.000145317667468702 +8499.548 0.000123066996435036 +5617.157 0.000156011624908839 +3742.097 3.7808086513221e-05 +10274.362 6.78703210421545e-05 +6186.083 0.000170853335852759 +4552.435 9.20798127465615e-05 +8006.946 0.000140143254028843 +6790.353 0.000170872728246691 +5455.554 0.000148978662405294 +9361.352 9.39436873016158e-05 +5709.204 0.00015946742554235 +16825.49888 5.00789723424988e-06 +5363.839 0.000144459876612251 +12514.28 2.82532814190863e-05 +7225.553 0.000163202752532002 +12890.64 2.42739862374255e-05 +8045.471 0.000138838408679289 +18320.555 2.79830832979157e-06 +7339.839 0.000160415133366504 +7500.92 0.00015606542100079 +11532.695 4.18156642982465e-05 +6639.799 0.000172186064368232 +6341.556 0.000172279119179583 +6533.038 0.000172622478650322 +5113.036 0.000130326486583241 +3854.754 4.4283345872923e-05 +5477.022 0.000149982281171861 +7310.343 0.000161160143281715 +4670.991 0.000100626037052284 +10346.79 6.60642242605733e-05 +9039.356 0.000104459733167728 +6480.619 0.000172676431635955 +8425.722 0.000125654190498816 +10647.809 5.8974972602665e-05 +7565.567 0.000154199994168006 +5456.57 0.000149026629329571 +8713.613 0.000115593076636878 +9305.365 9.57295320374143e-05 +5948.87 0.000166548208934179 +7638.778 0.000152015488523764 +8576.919 0.000120358190580951 +4959.301 0.000120553356314615 +12426.522 2.9268918540962e-05 +6870.319 0.000169868029908526 +7838.047 0.000145744442504979 +6414.488 0.000172587367846412 +13121.738 2.21092580728735e-05 +9801.248 8.06319421593433e-05 +8745.997 0.00011447011440418 diff --git a/examples/heavy-tail-example.py b/examples/heavy-tail-example.py index d16a4bf..ad6560e 100644 --- a/examples/heavy-tail-example.py +++ b/examples/heavy-tail-example.py @@ -1,27 +1,32 @@ +"""Heavy tail example.""" import pandas as pd -rdir = rf"\\MYCLOUDEX2ULTRA\research\phd\heavy-tail-statistics" -from statista.distributions import GEV +rdir = rf"examples/data" +from statista.distributions import GEV, Distributions -#%% -dung = pd.read_csv(f"{rdir}/dung/pdf_obs.txt", delimiter=" ") +# %% +dung = pd.read_csv(f"{rdir}/pdf_obs.txt", delimiter=" ") dung.sort_values(by="ams", inplace=True) + scale = 2132.938715 loc = 6582.059315 shape = 0.0486556 +parameters = { + "loc": loc, + "scale": scale, + "shape": shape, +} ams = dung["ams"].values - -dist_positive = GEV(ams, shape, loc, scale) -pdf = dist_positive.pdf(shape, loc, scale, plot_figure=False) +gev_positive = Distributions("GEV", ams, parameters) +pdf = gev_positive.pdf(parameters, plot_figure=False) dung["scipy +ve"] = pdf -shape = -0.0486556 -dist_negative = GEV(ams, shape, loc, scale) -pdf = dist_negative.pdf(shape, loc, scale, plot_figure=False) +parameters["shape"] = -0.0486556 +dist_negative = Distributions("GEV", ams, parameters) +pdf = dist_negative.pdf(parameters, plot_figure=False) dung["scipy -ve"] = pdf -#%% +# %% method = "lmoments" # "mle" parameters_lm = dist_negative.fit_model(method=method) parameters_mle = dist_negative.fit_model(method="mle") -#%% From 15f3c1b6a971d0d81ca39a22c440702f0f0e7766 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Mon, 11 Dec 2023 20:43:18 +0100 Subject: [PATCH 35/44] update exampe --- examples/rhine_example.py | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/examples/rhine_example.py b/examples/rhine_example.py index 1e0ad65..e79f59f 100644 --- a/examples/rhine_example.py +++ b/examples/rhine_example.py @@ -1,16 +1,19 @@ +""" Rhine gauges example """ import matplotlib matplotlib.use("TkAgg") import numpy as np import pandas as pd from statista.distributions import ( + Distributions, GEV, Exponential, - ConfidenceInterval, Gumbel, PlottingPosition, ) +from statista.confidence_interval import ConfidenceInterval +# %% ams = pd.read_csv("examples/data/rhine.csv") ams.head() ams.replace(0, np.nan, inplace=True) @@ -21,33 +24,29 @@ maxau_gauge = ams.loc[:, "maxau"].values rockenau_gauge = ams.loc[:, "rockenau"].values #%% Exponential distribution (mle) -dist_obj = Exponential(cologne_gauge) +dist_obj = Distributions("Exponential", cologne_gauge) # default parameter estimation method is maximum liklihood method mle_param = dist_obj.fit_model(method="mle") dist_obj.ks() dist_obj.chisquare() print(mle_param) -loc = mle_param[0] -scale = mle_param[1] # calculate and plot the pdf -pdf, fig, ax = dist_obj.pdf(loc, scale, plot_figure=True) -cdf, _, _ = dist_obj.cdf(loc, scale, plot_figure=True) +pdf, fig, ax = dist_obj.pdf(mle_param, plot_figure=True) +cdf, _, _ = dist_obj.cdf(mle_param, plot_figure=True) #%% exponential distribution (lmoments) -dist_obj = Exponential(cologne_gauge) +dist_obj = Distributions("Exponential", cologne_gauge) # default parameter estimation method is maximum liklihood method mle_param = dist_obj.fit_model(method="lmoments") dist_obj.ks() dist_obj.chisquare() print(mle_param) -loc = mle_param[0] -scale = mle_param[1] # calculate and plot the pdf -pdf, fig, ax = dist_obj.pdf(loc, scale, plot_figure=True) -cdf, _, _ = dist_obj.cdf(loc, scale, plot_figure=True) +pdf, fig, ax = dist_obj.pdf(mle_param, plot_figure=True) +cdf, _, _ = dist_obj.cdf(mle_param, plot_figure=True) #%% GEV (mle) -gev_cologne = GEV(cologne_gauge) +gev_cologne = Distributions("GEV", cologne_gauge) # default parameter estimation method is maximum liklihood method mle_param = gev_cologne.fit_model(method="mle") gev_cologne.ks() @@ -55,14 +54,11 @@ print(mle_param) # shape = -1 * mle_param[0] -shape = mle_param[0] -loc = mle_param[1] -scale = mle_param[2] # calculate and plot the pdf -pdf, fig, ax = gev_cologne.pdf(shape, loc, scale, plot_figure=True) -cdf, _, _ = gev_cologne.cdf(shape, loc, scale, plot_figure=True) +pdf, fig, ax = gev_cologne.pdf(mle_param, plot_figure=True) +cdf, _, _ = gev_cologne.cdf(mle_param, plot_figure=True) #%% cologne (lmoment) -gev_cologne = GEV(cologne_gauge) +gev_cologne = Distributions("GEV", cologne_gauge) # default parameter estimation method is maximum liklihood method lmom_param = gev_cologne.fit_model(method="lmoments") gev_cologne.ks() @@ -70,9 +66,6 @@ print(lmom_param) # shape = -1 * `lmom_param[0] -shape = lmom_param[0] -loc = lmom_param[1] -scale = lmom_param[2] # calculate and plot the pdf -pdf, fig, ax = gev_cologne.pdf(shape, loc, scale, plot_figure=True) -cdf, _, _ = gev_cologne.cdf(shape, loc, scale, plot_figure=True) +pdf, fig, ax = gev_cologne.pdf(lmom_param, plot_figure=True) +cdf, _, _ = gev_cologne.cdf(lmom_param, plot_figure=True) From f3e55f9816067ee76e51c0db986c59d1cb81d869 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Mon, 11 Dec 2023 20:48:09 +0100 Subject: [PATCH 36/44] refactor --- examples/SensitivityAnalysis.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/examples/SensitivityAnalysis.py b/examples/SensitivityAnalysis.py index 34f03a0..eba0249 100644 --- a/examples/SensitivityAnalysis.py +++ b/examples/SensitivityAnalysis.py @@ -1,7 +1,3 @@ -"""Created on Sun Jun 21 01:55:25 2020. - -@author: mofarrag -""" # import os Path = "F:/01Algorithms/Hydrology/HAPI/examples" import matplotlib @@ -19,15 +15,14 @@ Parameterpath = Path + "/data/Lumped/Coello_Lumped2021-03-08_muskingum.txt" Path = Path + "/data/Lumped/" -#%% -### meteorological data +# %% meteorological data start = "2009-01-01" end = "2011-12-31" name = "Coello" Coello = Catchment(name, start, end) Coello.ReadLumpedInputs(Path + "meteo_data-MSWEP.csv") -### Basic_inputs +# %% Basic_inputs # catchment area CatArea = 1530 # temporal resolution From 988fdeeb6f896407cfe65f93172a24bc5454fa97 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Mon, 11 Dec 2023 20:48:40 +0100 Subject: [PATCH 37/44] refactor --- statista/distributions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/statista/distributions.py b/statista/distributions.py index d352ce6..4c5f258 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -2384,7 +2384,7 @@ def __init__( self, distribution: str, data: Union[list, np.ndarray] = None, - parameters: Dict[str, str] = None, + parameters: Dict[str, Number] = None, ): if distribution not in self.available_distributions.keys(): raise ValueError(f"{distribution} not supported") From 51226c14f6d271391027d61415339e1ae2ed0282 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Mon, 11 Dec 2023 21:18:33 +0100 Subject: [PATCH 38/44] ignore pylint arguments differ w0221 warning --- statista/distributions.py | 8 +++++--- statista/eva.py | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/statista/distributions.py b/statista/distributions.py index 4c5f258..47b9189 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -584,7 +584,9 @@ def cdf( actual_data: Union[bool, np.ndarray] = True, *args, **kwargs, - ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: + ) -> Union[ + Tuple[np.ndarray, Figure, Any], np.ndarray + ]: # pylint: disable=arguments-differ """cdf. cdf calculates the value of Gumbel's cdf with parameters loc and scale at x. @@ -875,7 +877,7 @@ def probapility_plot( xlabel: str = "Actual data", ylabel: str = "cdf", fontsize: int = 15, - ) -> tuple[list[Figure], list[Any]]: + ) -> tuple[list[Figure], list[Any]]: # pylint: disable=arguments-differ """probapilityPlot. ProbapilityPlot method calculates the theoretical values based on the Gumbel distribution @@ -1328,7 +1330,7 @@ def confidence_interval( n_samples: int = 100, method: str = "lmoments", **kargs, - ): + ): # pylint: disable=arguments-differ """confidence_interval. Parameters: diff --git a/statista/eva.py b/statista/eva.py index 979070b..af73ee8 100644 --- a/statista/eva.py +++ b/statista/eva.py @@ -203,7 +203,7 @@ def ams_analysis( # based on the Gumbel distribution # parameters, theoretical cdf (or weibul), and calculate the confidence interval if save_plots: - fig, ax = dist.probapility_plot( + fig, _ = dist.probapility_plot( param_dist, cdf_weibul, alpha=significance_level, From faf0d3b167ac03d21d90fde9e9cc9c6e48495fcd Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Mon, 11 Dec 2023 21:24:20 +0100 Subject: [PATCH 39/44] ignore pylint arguments differ w0221 warning --- statista/distributions.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/statista/distributions.py b/statista/distributions.py index 47b9189..4a74d82 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -1106,7 +1106,9 @@ def cdf( actual_data: Union[bool, np.ndarray] = True, *args, **kwargs, - ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: + ) -> Union[ + Tuple[np.ndarray, Figure, Any], np.ndarray + ]: # pylint: disable=arguments-differ """cdf. cdf calculates the value of Gumbel's cdf with parameters loc and scale at x. From 6e80138af086fb433bd41940ced45bba94fbbbf0 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Mon, 11 Dec 2023 21:30:33 +0100 Subject: [PATCH 40/44] use the new distributions class --- examples/Extreme value statistics.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/Extreme value statistics.py b/examples/Extreme value statistics.py index 2bfb4a7..49abe2c 100644 --- a/examples/Extreme value statistics.py +++ b/examples/Extreme value statistics.py @@ -4,13 +4,13 @@ matplotlib.use("TkAgg") import pandas as pd -from statista.distributions import GEV, Gumbel, PlottingPosition +from statista.distributions import GEV, Gumbel, PlottingPosition, Distributions from statista.confidence_interval import ConfidenceInterval time_series1 = pd.read_csv("examples/data/time_series1.txt", header=None)[0].tolist() time_series2 = pd.read_csv("examples/data/time_series2.txt", header=None)[0].tolist() # %% -gumbel_dist = Gumbel(time_series1) +gumbel_dist = Distributions("Gumbel", time_series1) # defult parameter estimation method is maximum liklihood method param_mle = gumbel_dist.fit_model(method="mle") gumbel_dist.ks() @@ -58,7 +58,7 @@ print(param_dist) gumbel_dist.probapility_plot(param_dist, cdf_weibul, alpha=0.1) # %% Generalized Extreme Value (GEV) -gev_dist = GEV(time_series2) +gev_dist = Distributions("GEV", time_series2) # default parameter estimation method is maximum liklihood method gev_mle_param = gev_dist.fit_model(method="mle") gev_dist.ks() From 4f9c8f3eae9f423d9460861bb07ad20444bcc21a Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Mon, 11 Dec 2023 21:41:18 +0100 Subject: [PATCH 41/44] update necessities --- HISTORY.rst | 10 +++++++++- README.md | 2 +- setup.py | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 6d809aa..25614eb 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -35,10 +35,18 @@ History * modify the pdf, cdf, and probability plot plots * create separate plot and confidence_interval modules. -0.4.0 (2023-011-23) +0.4.0 (2023-11-23) ------------------ * add Pearson 3 distribution * Use setup.py instead of pyproject.toml. * Correct pearson correlation coefficient and add documentation . * replace the pdf and cdf by the methods from scipy package. + +0.5.0 (2023-12-11) +------------------ + +* Unify the all the methods for the distributions. +* Use factory design pattern to create the distributions. +* add tests for the eva module. +* use snake_case for the methods and variables. diff --git a/README.md b/README.md index 55479bc..c3dabe7 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ pip install git+https://github.com/MAfarrag/statista ## pip to install the last release you can easly use pip ``` -pip install statista==0.4.0 +pip install statista==0.5.0 ``` Quick start diff --git a/setup.py b/setup.py index 2362cf8..0a7cc25 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ setup( name="statista", - version="0.4.0", + version="0.5.0", description="statistics package", author="Mostafa Farrag", author_email="moah.farag@gmail.come", From 0c64c0d38eefccda100fbdc6618f2c8ccb0110de Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Mon, 11 Dec 2023 21:50:29 +0100 Subject: [PATCH 42/44] correct typo in probability_plot method name --- examples/Extreme value statistics.py | 8 ++++---- statista/distributions.py | 12 +++++++----- statista/eva.py | 2 +- tests/test_distributions.py | 4 ++-- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/examples/Extreme value statistics.py b/examples/Extreme value statistics.py index 49abe2c..d91752a 100644 --- a/examples/Extreme value statistics.py +++ b/examples/Extreme value statistics.py @@ -38,7 +38,7 @@ # calculate the confidence interval upper, lower = gumbel_dist.confidence_interval(param_lmoments, cdf_weibul, alpha=0.1) # ProbapilityPlot can estimate the Qth and the lower and upper confidence interval in the process of plotting -fig, ax = gumbel_dist.probapility_plot(param_lmoments, cdf_weibul, alpha=0.1) +fig, ax = gumbel_dist.probability_plot(param_lmoments, cdf_weibul, alpha=0.1) # %% """ if you want to focus only on high values, you can use a threshold to make the code focus on what is higher @@ -49,14 +49,14 @@ method="optimization", obj_func=Gumbel.objective_fn, threshold=threshold ) print(param_dist) -gumbel_dist.probapility_plot(param_dist, cdf_weibul, alpha=0.1) +gumbel_dist.probability_plot(param_dist, cdf_weibul, alpha=0.1) # %% threshold = 18 param_dist = gumbel_dist.fit_model( method="optimization", obj_func=Gumbel.objective_fn, threshold=threshold ) print(param_dist) -gumbel_dist.probapility_plot(param_dist, cdf_weibul, alpha=0.1) +gumbel_dist.probability_plot(param_dist, cdf_weibul, alpha=0.1) # %% Generalized Extreme Value (GEV) gev_dist = Distributions("GEV", time_series2) # default parameter estimation method is maximum liklihood method @@ -106,6 +106,6 @@ LB = CI["lb"] UB = CI["ub"] # %% -fig, ax = gev_dist.probapility_plot( +fig, ax = gev_dist.probability_plot( gev_lmom_param, cdf_weibul, func=func, n_samples=len(time_series1) ) diff --git a/statista/distributions.py b/statista/distributions.py index 4a74d82..88719d7 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -422,7 +422,7 @@ def confidence_interval( """ pass - def probapility_plot( + def probability_plot( self, parameters: Dict[str, Union[float, Any]], prob_non_exceed: np.ndarray, @@ -867,7 +867,7 @@ def confidence_interval( q_lower = np.array([qth[j] - v * std_error[j] for j in range(len(self.data))]) return q_upper, q_lower - def probapility_plot( + def probability_plot( self, parameters: Dict[str, Union[float, Any]], cdf: np.ndarray, @@ -1379,7 +1379,7 @@ def confidence_interval( return q_upper, q_lower - def probapility_plot( + def probability_plot( self, parameters: Dict[str, Union[float, Any]], prob_non_exceed, @@ -1923,7 +1923,9 @@ def cdf( actual_data: Union[bool, np.ndarray] = True, *args, **kwargs, - ) -> Union[Tuple[np.ndarray, Figure, Any], np.ndarray]: + ) -> Union[ + Tuple[np.ndarray, Figure, Any], np.ndarray + ]: # pylint: disable=arguments-differ """cdf. cdf calculates the value of Gumbel's cdf with parameters loc and scale at x. @@ -2395,7 +2397,7 @@ def __init__( self.distribution = self.available_distributions[distribution](data, parameters) - def __getattr__(self, name): + def __getattr__(self, name: str): """Delegate method calls to the sub-class""" # Retrieve the attribute or method from the animal object try: diff --git a/statista/eva.py b/statista/eva.py index af73ee8..8a7ba47 100644 --- a/statista/eva.py +++ b/statista/eva.py @@ -203,7 +203,7 @@ def ams_analysis( # based on the Gumbel distribution # parameters, theoretical cdf (or weibul), and calculate the confidence interval if save_plots: - fig, _ = dist.probapility_plot( + fig, _ = dist.probability_plot( param_dist, cdf_weibul, alpha=significance_level, diff --git a/tests/test_distributions.py b/tests/test_distributions.py index 7bfcc07..f3a50c4 100644 --- a/tests/test_distributions.py +++ b/tests/test_distributions.py @@ -145,7 +145,7 @@ def test_confidence_interval( assert isinstance(upper, np.ndarray) assert isinstance(lower, np.ndarray) - def test_probapility_plot( + def test_probability_plot( self, time_series2: list, dist_estimation_parameters_ks: str, @@ -154,7 +154,7 @@ def test_probapility_plot( dist = Gumbel(time_series2) cdf_weibul = PlottingPosition.weibul(time_series2) param = dist.fit_model(method=dist_estimation_parameters_ks, test=False) - (fig1, fig2), (_, _) = dist.probapility_plot( + (fig1, fig2), (_, _) = dist.probability_plot( param, cdf_weibul, alpha=confidence_interval_alpha ) assert isinstance(fig1, Figure) From 9d41014b7dcbb47845f855161298bb150493a489 Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Mon, 11 Dec 2023 22:15:17 +0100 Subject: [PATCH 43/44] refactor F and prob_no_exceedence parameter name to cdf --- statista/distributions.py | 28 ++++++++++++++-------------- statista/plot.py | 18 +++++++++--------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/statista/distributions.py b/statista/distributions.py index 88719d7..3782bdd 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -870,10 +870,10 @@ def confidence_interval( def probability_plot( self, parameters: Dict[str, Union[float, Any]], - cdf: np.ndarray, + cdf: Union[np.ndarray, list], alpha: float = 0.1, - fig1size: tuple = (10, 5), - fig2size: tuple = (6, 6), + fig1_size: Tuple[float, float] = (10, 5), + fig2_size: Tuple[float, float] = (6, 6), xlabel: str = "Actual data", ylabel: str = "cdf", fontsize: int = 15, @@ -895,9 +895,9 @@ def probability_plot( theoretical cdf calculated using weibul or using the distribution cdf function. alpha : [float] value between 0 and 1. - fig1size: [tuple] + fig1_size: [tuple] Default is (10, 5) - fig2size: [tuple] + fig2_size: [tuple] Default is (6, 6) xlabel: [str] Default is "Actual data" @@ -940,8 +940,8 @@ def probability_plot( q_lower, q_upper, alpha, - fig1size=fig1size, - fig2size=fig2size, + fig1_size=fig1_size, + fig2_size=fig2_size, xlabel=xlabel, ylabel=ylabel, fontsize=fontsize, @@ -1382,7 +1382,7 @@ def confidence_interval( def probability_plot( self, parameters: Dict[str, Union[float, Any]], - prob_non_exceed, + cdf: Union[np.ndarray, list], alpha: Number = 0.1, func: Callable = None, method: str = "lmoments", @@ -1408,7 +1408,7 @@ def probability_plot( Scale parameter of the GEV distribution. - shape: [float, int] Shape parameter for the GEV distribution. - prob_non_exceed : [list] + cdf : [list] Theoretical cdf calculated using weibul or using the distribution cdf function. method: [str] Method used to fit the generated samples from the bootstrap method ["lmoments", "mle", "mm"]. Default is @@ -1437,7 +1437,7 @@ def probability_plot( if scale <= 0: raise ValueError("Scale parameter is negative") - q_th = self.theoretical_estimate(parameters, prob_non_exceed) + q_th = self.theoretical_estimate(parameters, cdf) if func is None: func = GEV.ci_func @@ -1446,7 +1446,7 @@ def probability_plot( statfunction=func, gevfit=parameters, n_samples=n_samples, - F=prob_non_exceed, + F=cdf, method=method, ) q_lower = ci["lb"] @@ -1464,12 +1464,12 @@ def probability_plot( self.data, pdf_fitted, cdf_fitted, - prob_non_exceed, + cdf, q_lower, q_upper, alpha, - fig1size=fig1_size, - fig2size=fig2_size, + fig1_size=fig1_size, + fig2_size=fig2_size, xlabel=xlabel, ylabel=ylabel, fontsize=fontsize, diff --git a/statista/plot.py b/statista/plot.py index cf493f1..5e2ce70 100644 --- a/statista/plot.py +++ b/statista/plot.py @@ -109,12 +109,12 @@ def details( q_act: Union[np.ndarray, list], pdf: Union[np.ndarray, list], cdf_fitted: Union[np.ndarray, list], - F: Union[np.ndarray, list], + cdf: Union[np.ndarray, list], q_lower: Union[np.ndarray, list], q_upper: Union[np.ndarray, list], alpha: Number, - fig1size: Tuple[float, float] = (10, 5), - fig2size: Tuple[float, float] = (6, 6), + fig1_size: Tuple[float, float] = (10, 5), + fig2_size: Tuple[float, float] = (6, 6), xlabel: str = "Actual data", ylabel: str = "cdf", fontsize: int = 11, @@ -128,12 +128,12 @@ def details( q_act pdf cdf_fitted - F + cdf q_lower q_upper alpha - fig1size - fig2size + fig1_size + fig2_size xlabel ylabel fontsize @@ -141,7 +141,7 @@ def details( Returns ------- """ - fig1 = plt.figure(figsize=fig1size) + fig1 = plt.figure(figsize=fig1_size) gs = gridspec.GridSpec(nrows=1, ncols=2, figure=fig1) # Plot the histogram and the fitted distribution, save it for each gauge. ax1 = fig1.add_subplot(gs[0, 0]) @@ -154,11 +154,11 @@ def details( ax2.plot(qx, cdf_fitted, "-", color="#27408B", linewidth=2) q_act.sort() - ax2.scatter(q_act, F, color="#DC143C", facecolors="none") + ax2.scatter(q_act, cdf, color="#DC143C", facecolors="none") ax2.set_xlabel(xlabel, fontsize=fontsize) ax2.set_ylabel(ylabel, fontsize=15) - fig2 = plt.figure(figsize=fig2size) + fig2 = plt.figure(figsize=fig2_size) plt.plot(qth, qth, "-.", color="#3D59AB", linewidth=2, label="Theoretical Data") # confidence interval plt.plot( From 83358a8b8284d7e5bdf232ed8d5ce117d79cc13d Mon Sep 17 00:00:00 2001 From: Mostafa Farrag Date: Mon, 11 Dec 2023 22:41:10 +0100 Subject: [PATCH 44/44] refactor --- statista/distributions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/statista/distributions.py b/statista/distributions.py index 3782bdd..62a8678 100644 --- a/statista/distributions.py +++ b/statista/distributions.py @@ -687,7 +687,7 @@ def fit_model( threshold: Union[None, float, int] = None, test: bool = True, ) -> Dict[str, float]: - """estimate_parameter. + """fit_model. EstimateParameter estimate the distribution parameter based on MLM (Maximum liklihood method), if an objective function is entered as an input