From 445a078445610d40452a7917f9c51b6832d13683 Mon Sep 17 00:00:00 2001 From: MothNik Date: Tue, 9 Apr 2024 17:11:53 +0200 Subject: [PATCH 1/9] fix: adapted `.gitignore` for VSCode --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b6e4761..ede5338 100644 --- a/.gitignore +++ b/.gitignore @@ -103,12 +103,13 @@ celerybeat.pid # Environments .env -.venv +.venv* env/ venv/ ENV/ env.bak/ venv.bak/ +.vscode/ # Spyder project settings .spyderproject From 978e03cfbe4be4135e58ddf1694ed1c046fa327e Mon Sep 17 00:00:00 2001 From: MothNik Date: Tue, 9 Apr 2024 17:12:29 +0200 Subject: [PATCH 2/9] fix: separated development requirements --- requirements-dev.txt | 1 + requirements.txt | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 requirements-dev.txt diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..b0ae1a0 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1 @@ +pytest>=8.1.1 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 85461e5..b302344 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,3 @@ certifi>=2019.11.28 docutils>=0.15.2 numpy>=1.18.0 statistics>=1.0.3.5 -pytest>=8.1.1 From ef78804ecbfdf9966aa34e73bc2f8eeafd770572 Mon Sep 17 00:00:00 2001 From: MothNik Date: Tue, 9 Apr 2024 17:15:19 +0200 Subject: [PATCH 3/9] fix: removed sorting from median computation --- robustbase/utils/median.py | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/robustbase/utils/median.py b/robustbase/utils/median.py index a888613..eea3ce2 100644 --- a/robustbase/utils/median.py +++ b/robustbase/utils/median.py @@ -7,22 +7,29 @@ def median(x, low=False, high=False): Parameters: - x: list or array-like, numeric vector of observations. - - low: bool, if True, return the low median for even sample size. + - low: bool, if True, return the low median for even sample size. If ``True``, ``high`` is ignored. - high: bool, if True, return the high median for even sample size. Returns: - float: Median value. """ - sorted_x = np.sort(x) - n = len(sorted_x) + + n = len(x) if n == 0: raise ValueError("Empty list provided.") - + + # for odd sample size, all three medians are the same if n % 2 == 1: - return sorted_x[n // 2] - elif low: - return sorted_x[n // 2 - 1] - elif high: - return sorted_x[n // 2] - else: - return (sorted_x[n // 2 - 1] + sorted_x[n // 2]) / 2 \ No newline at end of file + return np.median(a=x) + + # for even sample sizes, the median is the average of the two middle values if + # neither the low nor high median is requested + if not (low or high): + return np.median(a=x) + + # otherwise, either the low or the high median are found via introselect + median_idx = n // 2 + if low: + median_idx -= 1 + + return np.partition(a=x, kth=median_idx)[median_idx] From 3c158b5573a4f0b906f061546879dc08f7253080 Mon Sep 17 00:00:00 2001 From: MothNik Date: Tue, 9 Apr 2024 17:16:30 +0200 Subject: [PATCH 4/9] test: added median tests --- tests/test_median.py | 47 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 tests/test_median.py diff --git a/tests/test_median.py b/tests/test_median.py new file mode 100644 index 0000000..8a7e1ee --- /dev/null +++ b/tests/test_median.py @@ -0,0 +1,47 @@ +from typing import Optional, Union + +import numpy as np +import pytest + +from robustbase.utils.median import median + +X_EMPTY = [] +X_ODD_N = [5.5, 3.2, -10.0, -2.1, 8.4] +X_EVEN_N = [5.5, 3.2, -10.0, -2.1, 8.4, 0.0] + + +@pytest.mark.parametrize("as_array", [False, True]) +@pytest.mark.parametrize( + "comb", + [ + (X_EMPTY, False, False, None), + (X_EMPTY, True, False, None), + (X_EMPTY, False, True, None), + (X_EMPTY, True, True, None), + (X_ODD_N, False, False, 3.2), + (X_ODD_N, True, False, 3.2), + (X_ODD_N, False, True, 3.2), + (X_ODD_N, True, True, 3.2), + (X_EVEN_N, False, False, 1.6), + (X_EVEN_N, True, False, 0.0), + (X_EVEN_N, False, True, 3.2), + (X_EVEN_N, True, True, 0.0), + ], +) +def test_median( + comb: tuple[Union[list, np.ndarray], bool, bool, Optional[float]], + as_array: bool, +): + x, low, high, expected = comb + if as_array: + x = np.array(x) + + # for empty samples, an error should be raised + if expected is None: + with pytest.raises(ValueError): + median(x, low=low, high=high) + + return + + # otherwise, the expected median should be returned + assert median(x, low=low, high=high) == expected From dc46914c467e87169e9554f8bd08324cc95ebe5f Mon Sep 17 00:00:00 2001 From: MothNik Date: Tue, 9 Apr 2024 17:21:17 +0200 Subject: [PATCH 5/9] fix: linted `__init__.py` --- robustbase/utils/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/robustbase/utils/__init__.py b/robustbase/utils/__init__.py index cc3ff0f..77a4cd2 100644 --- a/robustbase/utils/__init__.py +++ b/robustbase/utils/__init__.py @@ -1,2 +1,2 @@ -from .mean import mean -from .median import median \ No newline at end of file +from .mean import mean # noqa: F401 +from .median import median # noqa: F401S \ No newline at end of file From 299ef0fe3e98ff9d777a9105a592dd599c0adc41 Mon Sep 17 00:00:00 2001 From: MothNik Date: Tue, 9 Apr 2024 17:23:30 +0200 Subject: [PATCH 6/9] fix: fixed CI with split dependencies --- .github/workflows/python-package.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 8241b8b..f2c3cc1 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -27,6 +27,7 @@ jobs: run: | python -m pip install --upgrade pip if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + if [ -f requirements-dev.txt ]; then pip install -r requirements-dev.txt; fi - name: Run tests run: | export PYTHONPATH="${PYTHONPATH}:/robustbase/" From 00df83b57c4b5293cc6a4064c983f3dcc9fdb0b1 Mon Sep 17 00:00:00 2001 From: MothNik Date: Tue, 9 Apr 2024 17:27:47 +0200 Subject: [PATCH 7/9] fix: fixed Python `<3.10` backwards compatibility issue in type hint --- tests/test_median.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_median.py b/tests/test_median.py index 8a7e1ee..dc42e59 100644 --- a/tests/test_median.py +++ b/tests/test_median.py @@ -1,4 +1,4 @@ -from typing import Optional, Union +from typing import Optional, Tuple, Union import numpy as np import pytest @@ -29,7 +29,7 @@ ], ) def test_median( - comb: tuple[Union[list, np.ndarray], bool, bool, Optional[float]], + comb: Tuple[Union[list, np.ndarray], bool, bool, Optional[float]], as_array: bool, ): x, low, high, expected = comb From 4052ad9bb7f97036e19006b90e73423c73fe46b7 Mon Sep 17 00:00:00 2001 From: MothNik Date: Tue, 9 Apr 2024 17:32:04 +0200 Subject: [PATCH 8/9] fix: linted all `__init__.py` --- robustbase/__init__.py | 8 ++++---- robustbase/stats/__init__.py | 8 ++++---- robustbase/utils/__init__.py | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/robustbase/__init__.py b/robustbase/__init__.py index 08c9801..99127aa 100644 --- a/robustbase/__init__.py +++ b/robustbase/__init__.py @@ -1,6 +1,6 @@ -from .robustbase import Qn -from .robustbase import Sn -from .robustbase import iqr -from .robustbase import mad +from .robustbase import Qn # noqa: F401 +from .robustbase import Sn # noqa: F401 +from .robustbase import iqr # noqa: F401 +from .robustbase import mad # noqa: F401 diff --git a/robustbase/stats/__init__.py b/robustbase/stats/__init__.py index 24e21c4..e8bc011 100644 --- a/robustbase/stats/__init__.py +++ b/robustbase/stats/__init__.py @@ -1,4 +1,4 @@ -from .Qn import Qn -from .Sn import Sn -from .iqr import iqr -from .mad import mad +from .iqr import iqr # noqa: F401 +from .mad import mad # noqa: F401 +from .Qn import Qn # noqa: F401 +from .Sn import Sn # noqa: F401 diff --git a/robustbase/utils/__init__.py b/robustbase/utils/__init__.py index 77a4cd2..64eb114 100644 --- a/robustbase/utils/__init__.py +++ b/robustbase/utils/__init__.py @@ -1,2 +1,2 @@ -from .mean import mean # noqa: F401 -from .median import median # noqa: F401S \ No newline at end of file +from .mean import mean # noqa: F401 +from .median import median # noqa: F401 From b805ff777cd6969d8530288cba4632aa58ece66f Mon Sep 17 00:00:00 2001 From: MothNik Date: Tue, 9 Apr 2024 18:09:15 +0200 Subject: [PATCH 9/9] fix: Updated `README` --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index cc74a11..4334096 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ This package provides functions to calculate the following robust statistical es ```python from robustbase.stats import Qn - + x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # With bias correction @@ -37,11 +37,11 @@ res = Qn(x, finite_corr=False) # result: 4.43828 ```python from robustbase.stats import Sn - + x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # With bias correction -res = Sn(x) # result: 3.5778 +res = Sn(x) # result: 3.5778 # Without bias correction res = Sn(x, finite_corr=False) # result: 3.5778 @@ -75,7 +75,7 @@ For local development setup: ```sh git clone https://github.com/deepak7376/robustbase cd robustbase -pip install -r requirements.txt +pip install -r requirements.txt -r requirements-dev.txt ``` ## Recent Changes