From 21ce7a371aeba1115027363d9e4310e17947c9f7 Mon Sep 17 00:00:00 2001 From: Mario Graff <11542693+mgraffg@users.noreply.github.com> Date: Fri, 21 Feb 2025 03:23:40 +0000 Subject: [PATCH 1/6] multiple (7) --- CompStats/__init__.py | 2 +- CompStats/interface.py | 45 ++++++++++++++++++++++++++++--- CompStats/tests/test_interface.py | 18 +++++++++++++ 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/CompStats/__init__.py b/CompStats/__init__.py index fbebf90..2e65c6d 100644 --- a/CompStats/__init__.py +++ b/CompStats/__init__.py @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -__version__ = '0.1.6' +__version__ = '0.1.7' from CompStats.bootstrap import StatisticSamples from CompStats.measurements import CI, SE, difference_p_value from CompStats.performance import performance, difference, all_differences, plot_performance, plot_difference diff --git a/CompStats/interface.py b/CompStats/interface.py index 6f07c67..b012414 100644 --- a/CompStats/interface.py +++ b/CompStats/interface.py @@ -18,6 +18,7 @@ import numpy as np from CompStats.bootstrap import StatisticSamples from CompStats.utils import progress_bar +from CompStats import measurements from CompStats.measurements import SE from CompStats.performance import plot_performance, plot_difference @@ -322,7 +323,8 @@ def se(self): return list(output.values())[0] return output - def plot(self, **kwargs): + def plot(self, CI:float=0.05, + **kwargs): """plot with seaborn >>> from sklearn.svm import LinearSVC @@ -341,13 +343,50 @@ def plot(self, **kwargs): forest=ens.predict(X_val)) >>> perf.plot() """ + import seaborn as sns if self.score_func is not None: value_name = 'Score' else: value_name = 'Error' _ = dict(value_name=value_name) - _.update(kwargs) - return plot_performance(self.statistic_samples, **_) + _.update(kwargs) + if isinstance(self.best, str): + return plot_performance(self.statistic_samples, **_) + kw = {} + for key in ['var_name', 'alg_legend', 'perf_names']: + if key in kwargs: + kw[key] = kwargs[key] + df = self.dataframe(value_name=value_name, **kw) + ci = lambda x: measurements.CI(x, alpha=CI) + f_grid = sns.catplot(df, x=value_name, + errorbar=ci, + y=kwargs.get('alg_legend', 'Algorithm'), + col=kwargs.get('var_name', 'Performance'), + kind=kwargs.get('kind', 'point'), + linestyle=kwargs.get('linestyle', 'none'), + col_wrap=kwargs.get('col_wrap', 3), + capsize=kwargs.get('capsize', 0.2)) + return f_grid + + + def dataframe(self, value_name:str='Score', + var_name:str='Performance', + alg_legend:str='Algorithm', + perf_names:str=None, + **kwargs): + """Dataframe""" + import pandas as pd + df = pd.DataFrame() + for key in self.statistic: + data = self.statistic_samples[key] + if perf_names is None: + perf_names = [f'Perf({i + 1})' + for i in range(data.shape[1])] + _df = pd.DataFrame(data, + columns=perf_names).melt(value_name=value_name, var_name=var_name) + _df[alg_legend] = key + df = pd.concat((df, _df)) + return df @property def n_jobs(self): diff --git a/CompStats/tests/test_interface.py b/CompStats/tests/test_interface.py index 6591aa4..a2616b6 100644 --- a/CompStats/tests/test_interface.py +++ b/CompStats/tests/test_interface.py @@ -23,6 +23,24 @@ from CompStats.tests.test_performance import DATA +def test_Perf_plot_multi(): + """Test Perf plot multiple""" + from CompStats.metrics import f1_score + + X, y = load_digits(return_X_y=True) + _ = train_test_split(X, y, test_size=0.3) + X_train, X_val, y_train, y_val = _ + ens = RandomForestClassifier().fit(X_train, y_train) + nb = GaussianNB().fit(X_train, y_train) + svm = LinearSVC().fit(X_train, y_train) + score = f1_score(y_val, ens.predict(X_val), + average=None, + num_samples=50) + score(nb.predict(X_val)) + score(svm.predict(X_val)) + f_grid = score.plot() + assert f_grid is not None + def test_Perf_statistic_one(): """Test Perf statistic one alg""" from CompStats.metrics import f1_score From 127dc216127e7585bcec9a9d8877babd20a7f456 Mon Sep 17 00:00:00 2001 From: Mario Graff <11542693+mgraffg@users.noreply.github.com> Date: Fri, 21 Feb 2025 13:43:27 +0000 Subject: [PATCH 2/6] dataframe (1) --- CompStats/interface.py | 20 ++++++-------------- CompStats/tests/test_interface.py | 27 ++++++++++++++++++++++++++- CompStats/utils.py | 26 +++++++++++++++++++++++++- 3 files changed, 57 insertions(+), 16 deletions(-) diff --git a/CompStats/interface.py b/CompStats/interface.py index b012414..4507528 100644 --- a/CompStats/interface.py +++ b/CompStats/interface.py @@ -21,6 +21,7 @@ from CompStats import measurements from CompStats.measurements import SE from CompStats.performance import plot_performance, plot_difference +from CompStats.utils import dataframe class Perf(object): @@ -372,21 +373,12 @@ def plot(self, CI:float=0.05, def dataframe(self, value_name:str='Score', var_name:str='Performance', alg_legend:str='Algorithm', - perf_names:str=None, - **kwargs): + perf_names:str=None): """Dataframe""" - import pandas as pd - df = pd.DataFrame() - for key in self.statistic: - data = self.statistic_samples[key] - if perf_names is None: - perf_names = [f'Perf({i + 1})' - for i in range(data.shape[1])] - _df = pd.DataFrame(data, - columns=perf_names).melt(value_name=value_name, var_name=var_name) - _df[alg_legend] = key - df = pd.concat((df, _df)) - return df + return dataframe(self, value_name=value_name, + var_name=var_name, + alg_legend=alg_legend, + perf_names=perf_names) @property def n_jobs(self): diff --git a/CompStats/tests/test_interface.py b/CompStats/tests/test_interface.py index a2616b6..b98c300 100644 --- a/CompStats/tests/test_interface.py +++ b/CompStats/tests/test_interface.py @@ -23,6 +23,31 @@ from CompStats.tests.test_performance import DATA +def test_Perf_dataframe(): + """Test Perf dataframe""" + from CompStats.metrics import f1_score + + X, y = load_digits(return_X_y=True) + _ = train_test_split(X, y, test_size=0.3) + X_train, X_val, y_train, y_val = _ + ens = RandomForestClassifier().fit(X_train, y_train) + nb = GaussianNB().fit(X_train, y_train) + svm = LinearSVC().fit(X_train, y_train) + score = f1_score(y_val, ens.predict(X_val), + average=None, + num_samples=50) + score(nb.predict(X_val)) + score(svm.predict(X_val)) + df = score.dataframe() + assert 'Performance' in df.columns + score = f1_score(y_val, ens.predict(X_val), + average='macro', + num_samples=50) + score(nb.predict(X_val)) + score(svm.predict(X_val)) + df = score.dataframe() + + def test_Perf_plot_multi(): """Test Perf plot multiple""" from CompStats.metrics import f1_score @@ -226,7 +251,7 @@ def test_Difference_plot(): diff.plot() -def test_Perf_dataframe(): +def test_Perf_input_dataframe(): """Test Perf with dataframe""" from CompStats.interface import Perf diff --git a/CompStats/utils.py b/CompStats/utils.py index c40edd7..6886f53 100644 --- a/CompStats/utils.py +++ b/CompStats/utils.py @@ -54,4 +54,28 @@ def inner(*args, **kwargs): return func(*args, **kwargs) return inner - return perf_docs \ No newline at end of file + return perf_docs + + +def dataframe(instance, value_name:str='Score', + var_name:str='Performance', + alg_legend:str='Algorithm', + perf_names:str=None, + **kwargs): + """Dataframe""" + import pandas as pd + if isinstance(instance.best, str): + df = pd.DataFrame(instance.statistic_samples.items()) + return df.melt(var_name=alg_legend, + value_name=value_name) + df = pd.DataFrame() + for key in instance.statistic: + data = instance.statistic_samples[key] + if perf_names is None: + perf_names = [f'Perf({i + 1})' + for i in range(data.shape[1])] + _df = pd.DataFrame(data, + columns=perf_names).melt(value_name=value_name, var_name=var_name) + _df[alg_legend] = key + df = pd.concat((df, _df)) + return df \ No newline at end of file From 438a8055b71bba437bad7bd1ef5427b29e0ed245 Mon Sep 17 00:00:00 2001 From: Mario Graff Date: Fri, 21 Feb 2025 18:19:43 +0000 Subject: [PATCH 3/6] multiple (8) --- CompStats/bootstrap.py | 4 +++ CompStats/interface.py | 45 ++++++++++++++++++++----------- CompStats/tests/test_interface.py | 2 ++ CompStats/utils.py | 19 ++++++------- 4 files changed, 45 insertions(+), 25 deletions(-) diff --git a/CompStats/bootstrap.py b/CompStats/bootstrap.py index 6b6968e..22b1994 100644 --- a/CompStats/bootstrap.py +++ b/CompStats/bootstrap.py @@ -142,6 +142,10 @@ def inner(N): return inner(N) except AttributeError: return inner(N) + + def keys(self): + """calls keys""" + return self.calls.keys() def __getitem__(self, key): return self.calls[key] diff --git a/CompStats/interface.py b/CompStats/interface.py index 4507528..2a446ff 100644 --- a/CompStats/interface.py +++ b/CompStats/interface.py @@ -241,6 +241,13 @@ def best(self): """System with best performance""" if hasattr(self, '_best') and self._best is not None: return self._best + if not isinstance(self.statistic, dict): + key, value = list(self.statistic_samples.calls.items())[0] + if value.ndim == 1: + self._best = key + else: + self._best = np.array([key] * value.shape[1]) + return self._best BiB = True if self.statistic_samples.BiB else False keys = np.array(list(self.statistic.keys())) data = np.asanyarray([self.statistic[k] @@ -324,7 +331,13 @@ def se(self): return list(output.values())[0] return output - def plot(self, CI:float=0.05, + def plot(self, value_name:str=None, + var_name:str='Performance', + alg_legend:str='Algorithm', + perf_names:list=None, + CI:float=0.05, + kind:str='point', linestyle:str='none', + col_wrap:int=3, capsize:float=0.2, **kwargs): """plot with seaborn @@ -349,24 +362,20 @@ def plot(self, CI:float=0.05, value_name = 'Score' else: value_name = 'Error' - _ = dict(value_name=value_name) - _.update(kwargs) - if isinstance(self.best, str): - return plot_performance(self.statistic_samples, **_) - kw = {} - for key in ['var_name', 'alg_legend', 'perf_names']: - if key in kwargs: - kw[key] = kwargs[key] - df = self.dataframe(value_name=value_name, **kw) + df = self.dataframe(value_name=value_name, var_name=var_name, + alg_legend=alg_legend, perf_names=perf_names) + if var_name not in df.columns: + var_name = None + col_wrap = None ci = lambda x: measurements.CI(x, alpha=CI) f_grid = sns.catplot(df, x=value_name, errorbar=ci, - y=kwargs.get('alg_legend', 'Algorithm'), - col=kwargs.get('var_name', 'Performance'), - kind=kwargs.get('kind', 'point'), - linestyle=kwargs.get('linestyle', 'none'), - col_wrap=kwargs.get('col_wrap', 3), - capsize=kwargs.get('capsize', 0.2)) + y=alg_legend, + col=var_name, + kind=kind, + linestyle=linestyle, + col_wrap=col_wrap, + capsize=capsize) return f_grid @@ -375,6 +384,10 @@ def dataframe(self, value_name:str='Score', alg_legend:str='Algorithm', perf_names:str=None): """Dataframe""" + if perf_names is None and isinstance(self.best, np.ndarray): + func_name = self.statistic_func.__name__ + perf_names = [f'{func_name}({i})' + for i, k in enumerate(self.best)] return dataframe(self, value_name=value_name, var_name=var_name, alg_legend=alg_legend, diff --git a/CompStats/tests/test_interface.py b/CompStats/tests/test_interface.py index b98c300..6d10305 100644 --- a/CompStats/tests/test_interface.py +++ b/CompStats/tests/test_interface.py @@ -36,6 +36,7 @@ def test_Perf_dataframe(): score = f1_score(y_val, ens.predict(X_val), average=None, num_samples=50) + df = score.dataframe() score(nb.predict(X_val)) score(svm.predict(X_val)) df = score.dataframe() @@ -46,6 +47,7 @@ def test_Perf_dataframe(): score(nb.predict(X_val)) score(svm.predict(X_val)) df = score.dataframe() + assert 'Performance' not in df.columns def test_Perf_plot_multi(): diff --git a/CompStats/utils.py b/CompStats/utils.py index 6886f53..0eac043 100644 --- a/CompStats/utils.py +++ b/CompStats/utils.py @@ -60,22 +60,23 @@ def inner(*args, **kwargs): def dataframe(instance, value_name:str='Score', var_name:str='Performance', alg_legend:str='Algorithm', - perf_names:str=None, - **kwargs): + perf_names:list=None): """Dataframe""" import pandas as pd if isinstance(instance.best, str): - df = pd.DataFrame(instance.statistic_samples.items()) + df = pd.DataFrame(dict(instance.statistic_samples.calls.items())) return df.melt(var_name=alg_legend, value_name=value_name) - df = pd.DataFrame() - for key in instance.statistic: + df = pd.DataFrame() + if not isinstance(instance.statistic, dict): + iter = instance.statistic_samples.keys() + else: + iter = instance.statistic + for key in iter: data = instance.statistic_samples[key] - if perf_names is None: - perf_names = [f'Perf({i + 1})' - for i in range(data.shape[1])] _df = pd.DataFrame(data, - columns=perf_names).melt(value_name=value_name, var_name=var_name) + columns=perf_names).melt(value_name=value_name, + var_name=var_name) _df[alg_legend] = key df = pd.concat((df, _df)) return df \ No newline at end of file From b80307e05a34f1d0a9270d0135574aad6f778fe0 Mon Sep 17 00:00:00 2001 From: Mario Graff Date: Fri, 21 Feb 2025 18:25:18 +0000 Subject: [PATCH 4/6] docs (multiple) --- docs/CompStats_metrics.ipynb | 136 ++++++++++++++---------------- docs/source/digits_difference.png | Bin 18430 -> 18318 bytes 2 files changed, 62 insertions(+), 74 deletions(-) diff --git a/docs/CompStats_metrics.ipynb b/docs/CompStats_metrics.ipynb index ad74cbb..2527d84 100644 --- a/docs/CompStats_metrics.ipynb +++ b/docs/CompStats_metrics.ipynb @@ -54,7 +54,7 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "f9fcdc39-dd55-4fb5-f296-8e16542da8ee" + "outputId": "b37f28d5-90d9-4d94-c28c-27f9054f1a23" }, "outputs": [ { @@ -62,41 +62,41 @@ "name": "stdout", "text": [ "Collecting git+https://github.com/INGEOTEC/CompStats@develop\n", - " Cloning https://github.com/INGEOTEC/CompStats (to revision develop) to /tmp/pip-req-build-0jzcmk2h\n", - " Running command git clone --filter=blob:none --quiet https://github.com/INGEOTEC/CompStats /tmp/pip-req-build-0jzcmk2h\n", + " Cloning https://github.com/INGEOTEC/CompStats (to revision develop) to /tmp/pip-req-build-yb73d9s4\n", + " Running command git clone --filter=blob:none --quiet https://github.com/INGEOTEC/CompStats /tmp/pip-req-build-yb73d9s4\n", " Running command git checkout -b develop --track origin/develop\n", " Switched to a new branch 'develop'\n", " Branch 'develop' set up to track remote branch 'develop' from 'origin'.\n", - " Resolved https://github.com/INGEOTEC/CompStats to commit ee9d6cd168b6c944722150afd5d6277ef60f8dd6\n", + " Resolved https://github.com/INGEOTEC/CompStats to commit 438a8055b71bba437bad7bd1ef5427b29e0ed245\n", " Installing build dependencies ... \u001b[?25l\u001b[?25hdone\n", " Getting requirements to build wheel ... \u001b[?25l\u001b[?25hdone\n", " Preparing metadata (pyproject.toml) ... \u001b[?25l\u001b[?25hdone\n", - "Requirement already satisfied: numpy in /usr/local/lib/python3.11/dist-packages (from CompStats==0.1.6) (1.26.4)\n", - "Requirement already satisfied: scikit-learn>=1.3.0 in /usr/local/lib/python3.11/dist-packages (from CompStats==0.1.6) (1.6.1)\n", - "Requirement already satisfied: pandas in /usr/local/lib/python3.11/dist-packages (from CompStats==0.1.6) (2.2.2)\n", - "Requirement already satisfied: seaborn>=0.13.0 in /usr/local/lib/python3.11/dist-packages (from CompStats==0.1.6) (0.13.2)\n", - "Requirement already satisfied: scipy>=1.6.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn>=1.3.0->CompStats==0.1.6) (1.13.1)\n", - "Requirement already satisfied: joblib>=1.2.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn>=1.3.0->CompStats==0.1.6) (1.4.2)\n", - "Requirement already satisfied: threadpoolctl>=3.1.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn>=1.3.0->CompStats==0.1.6) (3.5.0)\n", - "Requirement already satisfied: matplotlib!=3.6.1,>=3.4 in /usr/local/lib/python3.11/dist-packages (from seaborn>=0.13.0->CompStats==0.1.6) (3.10.0)\n", - "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.11/dist-packages (from pandas->CompStats==0.1.6) (2.8.2)\n", - "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.11/dist-packages (from pandas->CompStats==0.1.6) (2025.1)\n", - "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.11/dist-packages (from pandas->CompStats==0.1.6) (2025.1)\n", - "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib!=3.6.1,>=3.4->seaborn>=0.13.0->CompStats==0.1.6) (1.3.1)\n", - "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.11/dist-packages (from matplotlib!=3.6.1,>=3.4->seaborn>=0.13.0->CompStats==0.1.6) (0.12.1)\n", - "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib!=3.6.1,>=3.4->seaborn>=0.13.0->CompStats==0.1.6) (4.56.0)\n", - "Requirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib!=3.6.1,>=3.4->seaborn>=0.13.0->CompStats==0.1.6) (1.4.8)\n", - "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib!=3.6.1,>=3.4->seaborn>=0.13.0->CompStats==0.1.6) (24.2)\n", - "Requirement already satisfied: pillow>=8 in /usr/local/lib/python3.11/dist-packages (from matplotlib!=3.6.1,>=3.4->seaborn>=0.13.0->CompStats==0.1.6) (11.1.0)\n", - "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib!=3.6.1,>=3.4->seaborn>=0.13.0->CompStats==0.1.6) (3.2.1)\n", - "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.11/dist-packages (from python-dateutil>=2.8.2->pandas->CompStats==0.1.6) (1.17.0)\n", + "Requirement already satisfied: numpy in /usr/local/lib/python3.11/dist-packages (from CompStats==0.1.7) (1.26.4)\n", + "Requirement already satisfied: scikit-learn>=1.3.0 in /usr/local/lib/python3.11/dist-packages (from CompStats==0.1.7) (1.6.1)\n", + "Requirement already satisfied: pandas in /usr/local/lib/python3.11/dist-packages (from CompStats==0.1.7) (2.2.2)\n", + "Requirement already satisfied: seaborn>=0.13.0 in /usr/local/lib/python3.11/dist-packages (from CompStats==0.1.7) (0.13.2)\n", + "Requirement already satisfied: scipy>=1.6.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn>=1.3.0->CompStats==0.1.7) (1.13.1)\n", + "Requirement already satisfied: joblib>=1.2.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn>=1.3.0->CompStats==0.1.7) (1.4.2)\n", + "Requirement already satisfied: threadpoolctl>=3.1.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn>=1.3.0->CompStats==0.1.7) (3.5.0)\n", + "Requirement already satisfied: matplotlib!=3.6.1,>=3.4 in /usr/local/lib/python3.11/dist-packages (from seaborn>=0.13.0->CompStats==0.1.7) (3.10.0)\n", + "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.11/dist-packages (from pandas->CompStats==0.1.7) (2.8.2)\n", + "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.11/dist-packages (from pandas->CompStats==0.1.7) (2025.1)\n", + "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.11/dist-packages (from pandas->CompStats==0.1.7) (2025.1)\n", + "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib!=3.6.1,>=3.4->seaborn>=0.13.0->CompStats==0.1.7) (1.3.1)\n", + "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.11/dist-packages (from matplotlib!=3.6.1,>=3.4->seaborn>=0.13.0->CompStats==0.1.7) (0.12.1)\n", + "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib!=3.6.1,>=3.4->seaborn>=0.13.0->CompStats==0.1.7) (4.56.0)\n", + "Requirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib!=3.6.1,>=3.4->seaborn>=0.13.0->CompStats==0.1.7) (1.4.8)\n", + "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib!=3.6.1,>=3.4->seaborn>=0.13.0->CompStats==0.1.7) (24.2)\n", + "Requirement already satisfied: pillow>=8 in /usr/local/lib/python3.11/dist-packages (from matplotlib!=3.6.1,>=3.4->seaborn>=0.13.0->CompStats==0.1.7) (11.1.0)\n", + "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib!=3.6.1,>=3.4->seaborn>=0.13.0->CompStats==0.1.7) (3.2.1)\n", + "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.11/dist-packages (from python-dateutil>=2.8.2->pandas->CompStats==0.1.7) (1.17.0)\n", "Building wheels for collected packages: CompStats\n", " Building wheel for CompStats (pyproject.toml) ... \u001b[?25l\u001b[?25hdone\n", - " Created wheel for CompStats: filename=CompStats-0.1.6-py3-none-any.whl size=39606 sha256=9b0e0dcda958e7607006de68d599ef7ffbf692e8bf78c5da32dbf19cdacb2bab\n", - " Stored in directory: /tmp/pip-ephem-wheel-cache-auggsg4k/wheels/4f/d2/a1/8d1d30289bd99417ea947fc1e1f4587404d4e3a043b41f0289\n", + " Created wheel for CompStats: filename=CompStats-0.1.7-py3-none-any.whl size=41028 sha256=e70584ada7f0c49c8768febba12e978c4e122d93bf8452e2d42ea190cc5b1ece\n", + " Stored in directory: /tmp/pip-ephem-wheel-cache-sgv6titu/wheels/4f/d2/a1/8d1d30289bd99417ea947fc1e1f4587404d4e3a043b41f0289\n", "Successfully built CompStats\n", "Installing collected packages: CompStats\n", - "Successfully installed CompStats-0.1.6\n" + "Successfully installed CompStats-0.1.7\n" ] } ], @@ -142,7 +142,7 @@ "metadata": { "id": "jEpd52Kq214r" }, - "execution_count": 4, + "execution_count": 2, "outputs": [] }, { @@ -166,7 +166,7 @@ "metadata": { "id": "JGJczaOW3WeK" }, - "execution_count": 5, + "execution_count": 3, "outputs": [] }, { @@ -189,29 +189,26 @@ "base_uri": "https://localhost:8080/" }, "id": "Al0u9ZPB3cSj", - "outputId": "51c345bd-bb03-4469-f4f6-ed6399569539" + "outputId": "33d3dc5e-d7c7-4a2e-a3af-284a99935733" }, - "execution_count": 6, + "execution_count": 4, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ - "100%|██████████| 1/1 [00:11<00:00, 11.50s/it]\n" + "100%|██████████| 1/1 [00:05<00:00, 5.46s/it]\n" ] }, { "output_type": "execute_result", "data": { "text/plain": [ - "\n", - "Statistic with its standard error (se)\n", - "statistic (se)\n", - "0.9332 (0.0113) <= alg-1" + "" ] }, "metadata": {}, - "execution_count": 6 + "execution_count": 4 } ] }, @@ -234,19 +231,19 @@ "base_uri": "https://localhost:8080/" }, "id": "Ye1HH4pn3jde", - "outputId": "501c48e9-86fa-4095-85d8-9e68c8ebf39d" + "outputId": "a0f19b8f-eeb4-46ba-d0a1-8f3d59b67527" }, - "execution_count": 7, + "execution_count": 5, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ - "{'alg-1': 0.9332035615949114}" + "0.9434834454375508" ] }, "metadata": {}, - "execution_count": 7 + "execution_count": 5 } ] }, @@ -270,15 +267,15 @@ "base_uri": "https://localhost:8080/" }, "id": "vboh7N9B3pDr", - "outputId": "d7449f7e-d9c1-43aa-abe0-826806df4281" + "outputId": "980e3a62-1577-425d-ed59-69fbb93c4945" }, - "execution_count": 8, + "execution_count": 6, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ - "100%|██████████| 1/1 [00:01<00:00, 1.86s/it]\n" + "100%|██████████| 1/1 [00:01<00:00, 1.04s/it]\n" ] }, { @@ -288,12 +285,12 @@ "\n", "Statistic with its standard error (se)\n", "statistic (se)\n", - "0.9756 (0.0061) <= Random Forest\n", - "0.9332 (0.0113) <= alg-1" + "0.9655 (0.0077) <= Random Forest\n", + "0.9435 (0.0099) <= alg-1" ] }, "metadata": {}, - "execution_count": 8 + "execution_count": 6 } ] }, @@ -317,15 +314,15 @@ "base_uri": "https://localhost:8080/" }, "id": "pVOaQb0T3tyN", - "outputId": "15fbb215-d4e7-49c4-e56c-275aa1d59c1e" + "outputId": "258373fc-4afb-4442-9e5f-e9fb75d743ef" }, - "execution_count": 9, + "execution_count": 7, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ - "100%|██████████| 1/1 [00:02<00:00, 2.00s/it]\n" + "100%|██████████| 1/1 [00:01<00:00, 1.48s/it]\n" ] }, { @@ -335,13 +332,13 @@ "\n", "Statistic with its standard error (se)\n", "statistic (se)\n", - "0.9756 (0.0061) <= Random Forest\n", - "0.9332 (0.0113) <= alg-1\n", - "0.8198 (0.0144) <= Naive Bayes" + "0.9655 (0.0077) <= Random Forest\n", + "0.9435 (0.0099) <= alg-1\n", + "0.8549 (0.0153) <= Naive Bayes" ] }, "metadata": {}, - "execution_count": 9 + "execution_count": 7 } ] }, @@ -365,22 +362,22 @@ "base_uri": "https://localhost:8080/" }, "id": "XWAqUpYE3za2", - "outputId": "d92c436a-6aa9-41f3-cb9d-582ba2068b98" + "outputId": "3f108864-6a1f-41bf-dda3-ccab294444e5" }, - "execution_count": 10, + "execution_count": 8, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "\n", - "difference p-values w.r.t Random Forest\n", - "0.0000 <= alg-1\n", - "0.0000 <= Naive Bayes" + "difference p-values w.r.t Random Forest\n", + "0.0000 <= Naive Bayes\n", + "0.0120 <= alg-1" ] }, "metadata": {}, - "execution_count": 10 + "execution_count": 8 } ] }, @@ -401,22 +398,22 @@ "metadata": { "colab": { "base_uri": "https://localhost:8080/", - "height": 547 + "height": 546 }, "id": "Fai01O3q3-SN", - "outputId": "e7e89ba8-ab89-4ab7-d518-ae284dca35d3" + "outputId": "eae94c83-bac5-473d-b708-23f549b27b07" }, - "execution_count": 11, + "execution_count": 9, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ - "" + "" ] }, "metadata": {}, - "execution_count": 11 + "execution_count": 9 }, { "output_type": "display_data", @@ -424,20 +421,11 @@ "text/plain": [ "
" ], - "image/png": "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Xbt21aZNm+wTrC5YsEBvvvmmUlNTdf78eWVnZyssLMy+jV69eunJJ5/U4sWL9dBDDyklJUXt27dXjHnO/IcfftCqVasUGhqaZ/+pqanq1KmT7rjjDsXFxalz587q1KmT7r//fpUrVy5P+1GjRtnft5R7xqh69erXfI8ASg7zn5US7cwZqTAno8PCcm/jL+m88Wwd/lyJCUb/93//p86dO2vUqFF5Jip97bXXlJycrGnTpikuLk5lypTRsGHDlJWVVeD2+vTpo5EjR2rbtm26ePGiDh8+rAcffFBSbheYJM2cOVOtWrVyeJ2vr+816yxTpoxq165tfzxr1iyFh4dr5syZeumll7RhwwYlJCRo/Pjx6ty5s8LDwzV//ny9/vrr9tcEBAToscce0+zZs3Xvvffqo48+so8ofbm+u+66S5MnT86z/6ioKPn6+uqrr77S+vXr9eWXX+qtt97SCy+8oI0bN6pmzZoO7QMDAxV4I3TmA5CUG4QufyFHR0sHDni0HKd8/73UurXz7b/8Mndco5IuJsbxd4HSocQEI0maNGmSGjdurLp16zqsX7dunXr27KlHHnlEkmSz2fTf//5X9evXL3Bb1apVU3x8vObNm6eLFy/qzjvvVKVKlSRJlStXVtWqVfXLL78oISHhumq2WCzy8fHRxYsXJUnr169XdHS0XnjhBXubg/n82TFgwADdeuuteuedd5Sdna17773X/lzTpk316aefKiYmRn5++f+KLBaL2rRpozZt2mjMmDGKjo7W4sWLHc4OuZvVatXbb78tSXryySfl7+9fZPsCcONo1Sp3nKKCbtW/UosWUj6XhgIlRokKRnFxcUpISNCbb77psL5OnTr65JNPtH79epUrV05vvPGGjh8/fs1gJOV2p40dO1ZZWVmaOnWqw3Pjx4/XkCFDFB4eri5duigzM1NbtmzRmTNnrhkuMjMzdcy8cvDMmTOaPn26/QzP5VoPHTqk+fPnq0WLFlq2bJkWL16cZzv16tXTbbfdppEjR6p///4KDg62P/fkk09q5syZ6tOnj5599lmVL19e+/fv1/z58zVr1ixt2bJFK1euVKdOnVSpUiVt3LhRJ0+eVL169a59gK+TYRhKT0+3LwOAlDuidUpK7jhF17plPyJCmj2bEbBRsnl8HKOrTZgwQTabzWHdiy++qKZNm6pz585q166dqlSp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44475OvrWxQlAgDgMU53pT399NOaOHGiypQpo6effvqabd94443rLgwlT05OjjZs2CBJateuHcEIAOB1nA5G27dvl9VqlSRt27ZNFosl33YFrQcAACjpnA5Gq1atsi+vXr26KGoBAADwqEKPY2S1WuXn56edO3cWRT0AAAAeU+hg5O/vrxo1aignJ6co6gEAAPAYl0a+fuGFF/T888/r9OnT7q4HAADAY1wa4HH69Onav3+/qlatqujoaJUpU8bh+W3btrmlOAAAgOLkUjDq1auXm8vAjcDf319PPPGEfRkAAG/DAI+lDCNfA0DpY7FYtHjxYree2Bg3bpyWLFmiHTt2OKybMWOGTpw4ocWLF2vJkiU6e/aslixZ4rb9FjWCUSlDMAIA73Py5EmNGTNGy5Yt0/Hjx1WuXDk1atRIY8aMUZs2bXTs2DGVK1dOgYGBbtvn+fPnlZmZqQoVKkiS9uzZo/r162vx4sW67bbbVK5cOV26dEmGYRTrPJvt2rVT48aNNW3aNJde71JXWk5OjqZOnaqFCxfq0KFDysrKcniei7K9U05OjtasWSNJuv322xn5GgBKiPvuu09ZWVmaM2eOatWqpePHj2vlypU6deqUJKlKlSpu32doaKh9rlRJSk1NlST17NnTPtizO4NYcXHprrTx48frjTfe0IMPPqj09HQ9/fTTuvfee+Xj46Nx48a5uUSUFDk5Ofr222/17bffMlwDAJQQZ8+e1Zo1azR58mS1b99e0dHRatmypUaNGqW7775bUm5X2pXdWevXr1fjxo0VFBSk5s2ba8mSJbJYLPZusdWrV8tisWjlypVq3ry5QkJC9Je//EV79+61b2PcuHFq3Lixffmuu+6SJPn4+NiDUWJiokP3nc1m06uvvqratWsrMDBQNWrU0Msvv2x/fuTIkbr55psVEhKiWrVqafTo0fZZN67c5//7f/9PMTExCg8P10MPPaRz587Z9/ftt98qOTlZFotFFotFBw4cKNTxdCkYzZs3TzNnztQzzzwjPz8/9enTR7NmzdKYMWP0/fffu7JJAADggstnbpYsWaLMzMw/bZ+RkaG77rpLcXFx2rZtmyZOnKiRI0fm2/aFF17Q66+/ri1btsjPz0/9+/fPt92IESM0e/ZsSdLRo0d19OjRfNuNGjVKkyZN0ujRo7V792599NFHqly5sv35smXL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/v4Oz1ksFtlsNklScHDwn9Z21113afLkyXmei4qKuuZrAdy4CEYAXPLNN9/op59+0vDhw13eRtOmTbVgwQJVqlRJYWFhRf66K8XFxclms+nbb7+1d6VdvY9PP/1UMTEx8vPjn0qgtODiawB/KjMzU8eOHdNvv/2mbdu26ZVXXlHPnj3Vo0cPPfbYYy5vNyEhQRUrVlTPnj21Zs0apaWlafXq1RoyZIh+/fVXt7/uSjExMerbt6/69++vJUuW2LexcOFCSdKTTz6p06dPq0+fPtq8ebNSU1P1n//8R/369VNOTo7L7xlAyUYwAvCnVqxYoaioKMXExKhLly5atWqV3nzzTX3++ecO1/AUVkhIiL777jvVqFFD9957r+rVq6fHH39cly5duuaZIFdfd7UZM2bo/vvv19///nfdcsstGjhwoP744w9JUtWqVbVu3Trl5OSoU6dOiouL07BhwxQREWEf1BKA97EYhmF4uggAAICSgD97AAAATAQjAAAAE8EIAADARDACAAAwEYwAAABMBCMAAAATwQgAAMBEMAIAADARjAAAAEwEIwAAABPBCAAAwEQwAgAAMP1/bVkcgWhb1g4AAAAASUVORK5CYII=\n" + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkYAAAIACAYAAABn3KMdAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAARvpJREFUeJzt3XuczHX///Hn7HlZu4vWKew6JbTOh1x0LRJC6KS0yhKXq4scSkmFUC2l2CgVZX1/lEOFLq66kpBTziqHhJzKsWI3YXd25/37Yz/mMmZXjNmdZR73221vfeYz7/l8XjtG8/R+fz7vt80YYwQAAAAF+LoAAACAwoJgBAAAYCEYAQAAWAhGAAAAFoIRAACAhWAEAABgIRgBAABYCEYAAAAWghEAAICFYATgmtGiRQu1aNHC12UAuI4RjIB8kJqaKpvN5vJTqlQptWzZUp999lm+nffMmTN64YUXtHz58qs6zgsvvOBSe3BwsOLi4jRgwACdOnXKK7VeDy5+ny78efvtt31dnhtvfT6A61mQrwsArmejR49WpUqVZIzRsWPHlJqaqvbt2+vf//63Onbs6PXznTlzRqNGjZIkr/SsTJkyRREREfrzzz+1dOlSTZo0SZs3b9aqVauu+tjXk/Pv04WaNGnio2ry5u3PB3A9IhgB+ejOO+9Uw4YNnY8fffRRlS5dWh9++GG+BCNvu++++3TDDTdIkvr27asHH3xQc+bM0fr169W4cWMfV1d4XPg+edOff/6pokWLev24APLGUBpQgKKjoxUeHq6gINd/kzgcDk2cOFG1atVSWFiYSpcurb59++rkyZMu7TZu3Ki2bdvqhhtuUHh4uCpVqqRevXpJkvbv36+YmBhJ0qhRo5xDOi+88IIkyW6364cfftCRI0c8rv+2226TJO3du9e57/fff9eQIUMUHx+viIgIRUZG6s4779S3337r8trly5fLZrNp7ty5eumll1S+fHmFhYXp9ttv1549e9zO9e6776pKlSoKDw9X48aNtXLlylxrOn78uDNwhoWFqU6dOpoxY4ZLm/3798tms2n8+PF68803VblyZRUpUkRt2rTRoUOHZIzRmDFjVL58eYWHh6tz5876/fffPX6fLjZv3jw1aNBA4eHhuuGGG9S9e3f98ssvLm2SkpIUERGhvXv3qn379ipWrJgSExMlFcznA0AOeoyAfJSWlqZff/1VxhgdP35ckyZN0unTp9W9e3eXdn379lVqaqp69uypAQMGaN++fZo8ebK2bNmi1atXKzg4WMePH1ebNm0UExOjZ555RtHR0dq/f78++eQTSVJMTIymTJmixx57THfffbfuueceSVLt2rUlSb/88otq1KihHj16KDU11aPfZ//+/ZKk4sWLO/f99NNPWrBgge6//35VqlRJx44d0zvvvKOEhATt2LFD5cqVcznG2LFjFRAQoCFDhigtLU2vvPKKEhMTtW7dOmeb9957T3379tXf/vY3DRo0SD/99JM6deqkEiVKqEKFCs52Z8+eVYsWLbRnzx71799flSpV0rx585SUlKRTp05p4MCBLueeNWuWMjMz9fjjj+v333/XK6+8oq5du6pVq1Zavny5hg4dqj179mjSpEkaMmSI3n///ct6Xy4OUYGBgc736Pyfa6NGjZScnKxjx44pJSVFq1ev1pYtWxQdHe18XVZWltq2bavmzZtr/PjxKlKkiKSC+XwAsBgAXjd9+nQjye0nNDTUpKamurRduXKlkWRmzZrlsv/zzz932T9//nwjyWzYsCHP8544ccJIMiNHjnR7bt++fUaS6dGjx1/WP3LkSCPJ7Nq1y5w4ccLs37/fvP/++yY8PNzExMSYP//809n23LlzJjs72+1coaGhZvTo0c59y5YtM5JMjRo1TEZGhnN/SkqKkWS+//57Y4wxmZmZplSpUqZu3bou7d59910jySQkJDj3TZw40UgyM2fOdO7LzMw0TZs2NRERESY9Pd3ld4+JiTGnTp1yth02bJiRZOrUqWPsdrtzf7du3UxISIg5d+7cZb1PF//Exsa6/C633HKLOXv2rPN1ixYtMpLMiBEjnPt69OhhJJlnnnnG5RwF9fkAkIOhNCAfvfnmm1qyZImWLFmimTNnqmXLlurdu7fzX/FSzjBLVFSU7rjjDv3666/OnwYNGigiIkLLli2TJGfPwqJFi2S326+4lri4OBljrqi3qHr16oqJiVFcXJx69eqlqlWr6rPPPnP2ZEhSaGioAgJy/leSnZ2t3377TREREapevbo2b97sdsyePXsqJCTE+fj88NxPP/0kKWc46Pjx4/rnP//p0i4pKUlRUVEux/rPf/6jMmXKqFu3bs59wcHBGjBggE6fPq0VK1a4tL///vtdjnH+Aunu3bu7DG82adJEmZmZbsNdefn444+df85LlizRrFmzXH6Xf/3rXwoLC3O279Chg26++WYtXrzY7ViPPfaYy+OC+nwAyMFQGpCPGjdu7HLxdbdu3VSvXj31799fHTt2VEhIiHbv3q20tDSVKlUq12McP35ckpSQkKB7771Xo0aN0oQJE9SiRQt16dJFDz30kEJDQ/Ol/o8//liRkZE6ceKE3njjDe3bt0/h4eEubRwOh1JSUvTWW29p3759ys7Odj5XsmRJt2NWrFjR5fH5Iafz18scOHBAklStWjWXdsHBwapcubLLvgMHDqhatWrOYHZejRo1XI6V17nPh6QLh+cu3H/xNTx5+fvf/57rxdfnz1+9enW3526++Wa3u/uCgoJUvnx5l32F+fMBXI8IRkABCggIUMuWLZWSkqLdu3erVq1acjgcKlWqlLOX4WLnL5i12Wz66KOP9M033+jf//63/vvf/6pXr1567bXX9M0337jdLu4NF37h33XXXYqPj1diYqI2bdrkDCMvv/yyhg8frl69emnMmDEqUaKEAgICNGjQIDkcDrdjBgYG5nouY4zX67/cc/uypgtd2Pt2XmH+fADXI4IRUMCysrIkSadPn5YkValSRV9++aWaNWvm1huTm1tvvVW33nqrXnrpJX3wwQdKTEzU7Nmz1bt3b9lstnyrOyIiQiNHjlTPnj01d+5cPfjgg5Kkjz76SC1bttR7773n0v7UqVMe3cIeGxsrKaenpFWrVs79drtd+/btU506dVzafvfdd3I4HC6B4ocffnA5lq+cP/+uXbtcfpfz+y6nvmvl8wFcL7jGCChAdrtdX3zxhUJCQpzDPV27dlV2drbGjBnj1j4rK8s50/TJkyfdejDq1q0rScrIyJAk57U/uc1O7Y3b9RMTE1W+fHmNGzfOuS8wMNCtrnnz5l329TkXa9iwoWJiYvT2228rMzPTuT81NdXt92rfvr2OHj2qOXPmOPdlZWVp0qRJioiIUEJCgkc1eEvDhg1VqlQpvf32284/I0n67LPPtHPnTnXo0OEvj1FQnw8AOegxAvLRZ5995uy9OH78uD744APt3r1bzzzzjCIjIyXlXBvSt29fJScna+vWrWrTpo2Cg4O1e/duzZs3TykpKbrvvvs0Y8YMvfXWW7r77rtVpUoV/fHHH5o6daoiIyPVvn17SVJ4eLhq1qypOXPm6Kab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7t2r06dPKysrS5GRkc5jdOnSRf369dP8+fP14IMPKjU1VS1btlSc1W//7bffatmyZYqIiHA7/969e9WmTRvdfvvtio+PV9u2bdWmTRvdd999Kl68uFv7YcOGOX9vKafHqEKFCpf8HQHksP5KXzdOnpQuo9PYKTIy5zZ+f+XvPYb+qtAEo7///e9q27athg0b5raA6auvvqqUlBRNnDhR8fHxKlq0qAYNGqTMzMw8j9etWzcNHTpUmzdv1tmzZ3Xo0CE98MADknKGwCRp6tSpatKkicvrAgMDL1ln0aJFVbVqVefjadOmKSoqSlOnTtWLL76otWvXKjExUaNGjVLbtm0VFRWl2bNn67XXXnO+JiQkRI888oimT5+ue+65Rx988IFzpunz9d11110aN26c2/nLli2rwMBALVmyRGvWrNEXX3yhSZMm6bnnntO6detUqVIll/ahoaEK9eeLBIArEBv7vy/D2Fhp/36fluN133wjNW16+e2/+CJnXiN/FRfn+nmAfyg0wUiSxo4dq7p166p69eou+1evXq3OnTure/fukiSHw6Eff/xRNWvWzPNY5cuXV0JCgmbNmqWzZ8/qjjvuUKlSpSRJpUuXVrly5fTTTz8pMTHxqmq22WwKCAjQ2bNnJUlr1qxRbGysnnvuOWebA7n8s6N379665ZZb9NZbbykrK0v33HOP87n69evr448/VlxcnIKCcv8jstlsatasmZo1a6YRI0YoNjZW8+fPd+kd8pTdbtebb74pSerXr5+Cg4Ov+pgAfK9Jk5x5ivK6Vf9CjRpJuVzCCVz3ClUwio+PV2Jiot544w2X/dWqVdNHH32kNWvWqHjx4nr99dd17NixSwYjKWc4beTIkcrMzNSECRNcnhs1apQGDBigqKgotWvXThkZGdq4caNOnjx5yXCRkZGho9YViSdPntTkyZOdPTznaz148KBmz56tRo0aafHixZo/f77bcWrUqKFbb71VQ4cOVa9evRQeHu58rl+/fpo6daq6deump59+WiVKlNCePXs0e/ZsTZs2TRs3btTSpUvVpk0blSpVSuvWrdOJEydUo0aNS7/Bl8kYo7S0NOc2gOuDzZYzeWPz5pe+ZT86Wpo+nRmw4Z98Po/RxUaPHi2Hw+Gy7/nnn1f9+vXVtm1btWjRQmXKlFGXLl3+8lj33XeffvvtN505c8atfe/e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Ai1atEiLFi3SihUrNHbsWElSSkqKmjZtqj59+jjrqFChwl++JxfyaCjt6NGjio+Pl5TzB5KWliZJ6tixo4YPH+7JIQEAgAeCgoKUmpqqPn366O2331b9+vWVkJCgBx98ULVr13Zr/8EHH8hms2nq1KkKCwtTzZo19csvv6hPnz5ubV966SUlJCRIkp555hl16NBB586dU1hYmEu7iIgI53VEeQ3b/fHHH0pJSdHkyZPVo0cPSVKVKlXUvHlzZ5vnn3/euR0XF6chQ4Zo9uzZevrpp537HQ6HUlNTVaxYMUnSww8/rKVLl+qll15SVFSUQkJCVKRIEY+HDz3qMSpfvrwzDVapUkVffPGFJGnDhg3X5HgiAADXsnvvvVeHDx/Wp59+qnbt2mn58uWqX7++UlNT3dru2rVLtWvXdgk3jRs3zvW4FwarsmXLSpKOHz/uUY07d+5URkaGbr/99jzbzJkzR82aNVOZMmUUERGh559/XgcPHnRpExcX5wxF5+vytKbceBSM7r77bi1dulSS9Pjjj2v48OGqVq2aHnnkkTy72QAAQP4JCwvTHXfcoeHDh2vNmjVKSkrSyJEjr+qYF85ld/66IYfD4dGxwsPDL/n82rVrlZiYqPbt22vRokXasmWLnnvuObcbvC6eX89ms3lcU248Gko7P5YnSQ888IAqVqyotWvXqlq1as6LrwAAgO/UrFkz1/mDqlevrpkzZyojI8M5yrNhw4Z8r6datWoKDw/X0qVL1bt3b7fn16xZo9jYWD333HPOfQcOHLji84SEhFzVjUMeBaOLNW3aVE2bNvXGoQAAwBX47bffdP/996tXr16qXbu2ihUrpo0bN+qVV15R586d3do/9NBDeu655/SPf/xDzzzzjA4ePKjx48dL+l+vUH4ICwvT0KFD9fTTTyskJETNmjXTiRMntH37dj366KOqVq2aDh48qNmzZ6tRo0ZavHix5s+ff8XniYuL07p167R//35FRESoRIkSCgi4/AEyj4PRrl27NGnSJO3cuVOSVKNGDT3++OOqXr26p4dEIREUFORM80FBXsnOAIB8EhERoSZNmmjChAnau3ev7Ha7KlSooD59+ujZZ591ax8ZGal///vfeuyxx1S3bl3Fx8drxIgReuihh9wuqva24cOHKygoSCNGjNDhw4dVtmxZ/fOf/5QkderUSYMHD1b/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\n" }, "metadata": {} } ] - }, - { - "cell_type": "code", - "source": [], - "metadata": { - "id": "ol6Yo4k_4FdR" - }, - "execution_count": 11, - "outputs": [] } ] } \ No newline at end of file diff --git a/docs/source/digits_difference.png b/docs/source/digits_difference.png index f0c40d8938abf379be8079b58b0977e3a961c9d3..608e0b6211bef8ef94b427f31c47c18c6110c6df 100644 GIT binary patch literal 18318 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

TjfPZ3H32UC zo}5{VY9s*?lH~48$c-oP9t%jaY{Vfp0O631u4Z|^tIcuNK)4+K8LC!3y&(A(32?@M2JpGZQ?L3Q@A7!NDp^ziW0FKr@Fm}~5tfEOiywez; zJ4&_aIM?~(vNqD12!4cfTUAbN5<&UrO7_g;kaNL)K?K0XAK z&o#ecI5_l+t;|D)<0Qrs?c_;O37am#*|GOBCm?!?L%kO&@PkZMC5e1{(Fk0%y;u=F ztfd~Nf*vS!dP6+t)~zN;p&R5(_DGaLOLa)sYz(m0*VFR{&VLNoJOFR#4<~4!^PW9> zR_Yd}_m5~Ajw=lA3~{&!0l5&?jWLdSnxKbWLddod1-8n%9%f1e&PVD&L}@_+dV$5ToVBkK#^Uvq{UEN&Tr z$tKhzn<>4{W9ltx`vh>oNi4EqUD`_=%QXuuhR))L7Re z?(%sM$JADHO4oV8o4I-GmOqI@;hb`;JR=)%Z7yC$2qKlJP0Ob4^IqDbxiHEifVy|= z+VurlrT4Jl^I}C?kJaNCgAlS@5gO?h-MGVP%amFSIMC;vI1bQ6mp`fS$0^nceaHiO< zXOYY6n;cveXACPF62K?Fh@e<{@&q~h34B=bQs)>#RNz|K(l|*s?oW>Jm8PTQh$mESzYLphe`hm3N=VZdE(%8`Dw}ke^lkyzWynvEd;rdMAE)D{>P89! z#gzcFp-BQEKjJ27VXPwg9RXNo9124=i5#c{l;*eBggPv0H*g6Ob_cf08H`Ahg&A%y zJ4WUyLYlGY-%)c>LENf@^KBduh{bti`|)PqpveX(MZ^Rk-%BQSLXIzG&u{)LdlY0Zt zk>Juz*W%8x?bUK!XC8!K($QCiq&pnN?Vj4skiSURCI?-wQFrVpNY_LWdup+O1P%n^ zzTbR*!0mSX_N=Z6u^)j4TSqkTf&$~}6b6-Cp#u(>kT(^D-Q?-1fZ8lX;)39eOP4O? z9`c&ps!hAhIdtY& z6M$Jee#wI>wlwkRN&Vp9gL6fq{%Ku({cBSai+JjwuFsSb2@)fZ4@YvbgUj&8A$WTR z-(R~?8GRbjI1kc>!AVNhx>#y73Ym9%cnKg=>2f2B?Itqr68V^<%*pwuc2WXh07H0H zSvsC~B>9aR5)$WNjVU-dWC2l!!QE;N^P$Ac%xezlP;LumyTEMzuOqI1*USDPY7ERS Zxcq$WP`83NvLqA=?Z~Oa@dwYl{y)t6_5}a{ literal 18430 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 From 633ed5aab9bc7147a869b7e1f218504796cfcaf2 Mon Sep 17 00:00:00 2001 From: Mario Graff Date: Fri, 21 Feb 2025 19:14:00 +0000 Subject: [PATCH 5/6] Difference (1) --- CompStats/interface.py | 47 +++++++++++++++++++++++-------- CompStats/tests/test_interface.py | 28 ++++++++++++++++++ README.rst | 21 ++++++-------- 3 files changed, 73 insertions(+), 23 deletions(-) diff --git a/CompStats/interface.py b/CompStats/interface.py index 2a446ff..cae952f 100644 --- a/CompStats/interface.py +++ b/CompStats/interface.py @@ -368,14 +368,10 @@ def plot(self, value_name:str=None, var_name = None col_wrap = None ci = lambda x: measurements.CI(x, alpha=CI) - f_grid = sns.catplot(df, x=value_name, - errorbar=ci, - y=alg_legend, - col=var_name, - kind=kind, - linestyle=linestyle, - col_wrap=col_wrap, - capsize=capsize) + f_grid = sns.catplot(df, x=value_name, errorbar=ci, + y=alg_legend, col=var_name, + kind=kind, linestyle=linestyle, + col_wrap=col_wrap, capsize=capsize, **kwargs) return f_grid @@ -605,7 +601,26 @@ def p_value(self, right:bool=True): values.sort(key=lambda x: self.sorting_func(x[1])) return dict(values) - def plot(self, **kwargs): + def dataframe(self, value_name:str='Score', + var_name:str='Best', + alg_legend:str='Algorithm', + perf_names:str=None): + """Dataframe""" + if perf_names is None and isinstance(self.best, np.ndarray): + perf_names = self.best + return dataframe(self, value_name=value_name, + var_name=var_name, + alg_legend=alg_legend, + perf_names=perf_names) + + def plot(self, value_name:str='Difference', + var_name:str='Best', + alg_legend:str='Algorithm', + perf_names:list=None, + CI:float=0.05, + kind:str='point', linestyle:str='none', + col_wrap:int=3, capsize:float=0.2, + **kwargs): """Plot >>> from sklearn.svm import LinearSVC @@ -624,5 +639,15 @@ def plot(self, **kwargs): >>> diff = perf.difference() >>> diff.plot() """ - - return plot_difference(self.statistic_samples, **kwargs) + import seaborn as sns + df = self.dataframe(value_name=value_name, var_name=var_name, + alg_legend=alg_legend, perf_names=perf_names) + if var_name not in df.columns: + var_name = None + col_wrap = None + ci = lambda x: measurements.CI(x, alpha=CI) + f_grid = sns.catplot(df, x=value_name, errorbar=ci, + y=alg_legend, col=var_name, + kind=kind, linestyle=linestyle, + col_wrap=col_wrap, capsize=capsize, **kwargs) + return f_grid diff --git a/CompStats/tests/test_interface.py b/CompStats/tests/test_interface.py index 6d10305..feebee9 100644 --- a/CompStats/tests/test_interface.py +++ b/CompStats/tests/test_interface.py @@ -23,6 +23,34 @@ from CompStats.tests.test_performance import DATA +def test_Difference_dataframe(): + """Test Difference dataframe""" + from CompStats.metrics import f1_score + + X, y = load_digits(return_X_y=True) + _ = train_test_split(X, y, test_size=0.3) + X_train, X_val, y_train, y_val = _ + ens = RandomForestClassifier().fit(X_train, y_train) + nb = GaussianNB().fit(X_train, y_train) + svm = LinearSVC().fit(X_train, y_train) + score = f1_score(y_val, ens.predict(X_val), + average=None, + num_samples=50) + score(nb.predict(X_val)) + score(svm.predict(X_val)) + diff = score.difference() + df = diff.dataframe() + assert 'Best' in df.columns + score = f1_score(y_val, ens.predict(X_val), + average='macro', + num_samples=50) + score(nb.predict(X_val)) + score(svm.predict(X_val)) + diff = score.difference() + df = diff.dataframe() + assert 'Best' not in df.columns + + def test_Perf_dataframe(): """Test Perf dataframe""" from CompStats.metrics import f1_score diff --git a/README.rst b/README.rst index a5bc0d8..7e124c8 100644 --- a/README.rst +++ b/README.rst @@ -49,15 +49,12 @@ Once the predictions are available, it is time to measure the algorithm's perfor >>> score = f1_score(y_val, hy, average='macro') >>> score - -Statistic with its standard error (se) -statistic (se) -0.9332 (0.0113) <= alg-1 + The previous code shows the macro-f1 score and, in parenthesis, its standard error. The actual performance value is stored in the `statistic` function. >>> score.statistic -{'alg-1': 0.9332035615949114} +0.9434834454375508 Continuing with the example, let us assume that one wants to test another classifier on the same problem, in this case, a random forest, as can be seen in the following two lines. The second line predicts the validation set and sets it to the analysis. @@ -66,8 +63,8 @@ Continuing with the example, let us assume that one wants to test another classi Statistic with its standard error (se) statistic (se) -0.9756 (0.0061) <= Random Forest -0.9332 (0.0113) <= alg-1 +0.9655 (0.0077) <= Random Forest +0.9435 (0.0099) <= alg-1 Let us incorporate another prediction, now with the Naive Bayes classifier, as seen below. @@ -76,18 +73,18 @@ Let us incorporate another prediction, now with the Naive Bayes classifier, as s Statistic with its standard error (se) statistic (se) -0.9756 (0.0061) <= Random Forest -0.9332 (0.0113) <= alg-1 -0.8198 (0.0144) <= Naive Bayes +0.9655 (0.0077) <= Random Forest +0.9435 (0.0099) <= alg-1 +0.8549 (0.0153) <= Naive Bayes The final step is to compare the performance of the three classifiers, which can be done with the `difference` method, as seen next. >>> diff = score.difference() >>> diff -difference p-values w.r.t Random Forest -0.0000 <= alg-1 +difference p-values w.r.t Random Forest 0.0000 <= Naive Bayes +0.0120 <= alg-1 The class `Difference` has the `plot` method that can be used to depict the difference with respect to the best. From 7dc97665facbf393494d08732620e956d3ecd2ef Mon Sep 17 00:00:00 2001 From: Mario Graff <11542693+mgraffg@users.noreply.github.com> Date: Fri, 21 Feb 2025 20:35:15 +0000 Subject: [PATCH 6/6] Diff (2) --- CompStats/interface.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CompStats/interface.py b/CompStats/interface.py index cae952f..6e0b8b4 100644 --- a/CompStats/interface.py +++ b/CompStats/interface.py @@ -607,7 +607,8 @@ def dataframe(self, value_name:str='Score', perf_names:str=None): """Dataframe""" if perf_names is None and isinstance(self.best, np.ndarray): - perf_names = self.best + perf_names = [f'{alg}({k})' + for k, alg in enumerate(self.best)] return dataframe(self, value_name=value_name, var_name=var_name, alg_legend=alg_legend, @@ -620,6 +621,7 @@ def plot(self, value_name:str='Difference', CI:float=0.05, kind:str='point', linestyle:str='none', col_wrap:int=3, capsize:float=0.2, + set_refline:bool=True, **kwargs): """Plot @@ -640,8 +642,10 @@ def plot(self, value_name:str='Difference', >>> diff.plot() """ import seaborn as sns - df = self.dataframe(value_name=value_name, var_name=var_name, + df = self.dataframe(value_name=value_name, + var_name=var_name, alg_legend=alg_legend, perf_names=perf_names) + title = var_name if var_name not in df.columns: var_name = None col_wrap = None @@ -650,4 +654,8 @@ def plot(self, value_name:str='Difference', y=alg_legend, col=var_name, kind=kind, linestyle=linestyle, col_wrap=col_wrap, capsize=capsize, **kwargs) + if set_refline: + f_grid.refline(x=0) + if isinstance(self.best, str): + f_grid.facet_axis(0, 0).set_title(f'{title} = {self.best}') return f_grid