diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 35a6cde9953..57151563165 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -6,7 +6,7 @@ Contributors
-[![All Contributors](https://img.shields.io/badge/all_contributors-275-orange.svg)](#contributors)
+[![All Contributors](https://img.shields.io/badge/all_contributors-278-orange.svg)](#contributors)
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
@@ -75,6 +75,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Carlos Ramos CarreΓ±o π |
+ Cedric DoniΓ© π π» |
Chang Wei Tan π» |
Cheuk Ting Ho π» |
Christian Kastner π» π |
@@ -82,9 +83,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Christopher Dahlin π» |
Christopher Lo π» π€ |
Chung-Fan Tsai β οΈ |
- Ciaran Gilbert π π» π β οΈ π€ |
+ Ciaran Gilbert π π» π β οΈ π€ |
ClaudiaSanches π» β οΈ |
Colin Fallon π |
Corvin Paul π |
@@ -93,9 +94,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Daniel MartΓn MartΓnez π π |
Darya Petrashka π |
Dave Hirschfeld π |
- David Buchaca Prats π» |
+ David Buchaca Prats π» |
David Gilbertson π» π |
David Guijo Rubio π» π€ |
David Manowitz π π§ |
@@ -104,9 +105,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Drishti Bhasin π» |
Dylan Sherry π |
Eddy Oyieko π» π |
- Emilia Rose π» β οΈ |
+ Emilia Rose π» β οΈ |
Er Jie Yong π π» |
Evan Miller β
|
Eyal Shafran π» |
@@ -115,9 +116,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Felipe Angelim π» π |
Felix Claessen π» π β οΈ π |
Felix Hirwa Nshuti π» π§ |
- Florian Stinner π» β οΈ |
+ Florian Stinner π» β οΈ |
Francesco Spinnato π» |
Franz Kiraly π π πΌ π» π π¨ π π‘ π΅ π π€ π§ π§βπ« π π¬ π π’ β οΈ β
πΉ |
Freddy A Boulton π β οΈ |
@@ -126,9 +127,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Geronimo Bergk π π» |
Grace Gao π» π |
Guzal Bulatova π π» π π§βπ« π π β οΈ |
- HYang1996 π» β οΈ π β
|
+ HYang1996 π» β οΈ π β
|
Hamza Benslimane π π» |
Hazrul Akmal π» π π β οΈ |
Helge Liebert π π» |
@@ -137,20 +138,21 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Ian Spektor π» π |
Ifeanyi30 π» |
Ilja Maurer π» |
- Ilyas Moutawwakil π» π |
+ Ilyas Moutawwakil π» π |
Ireoluwatomiwa π |
Ishan Nangia π€ |
+ Ishan Paidhungat π» π |
Jack Russon π» |
James Large π» π β οΈ π π§ |
James Morrill π» |
Jan Pipek π» |
Jasmine Liaw π» |
- Jason Lines π» πΌ π π¨ π π π€ π π¬ π π’ π‘ |
- Jason Pong π» β οΈ |
+ Jason Lines π» πΌ π π¨ π π π€ π π¬ π π’ π‘ |
+ Jason Pong π» β οΈ |
Jaume Mateu π» |
Javier Berneche π» π |
Jonas Pirner π |
@@ -158,197 +160,198 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Joren Hammudoglu π |
Juan Orduz β
π |
Julia Kraus π π» β οΈ |
- Julian Cooper π» π€ |
- Julian Nowak π π» |
+ Julian Cooper π» π€ |
+ Julian Haderlein π |
+ Julian Nowak π π» |
Juliana π» |
Justin Shenk π |
Kai Lion π» β οΈ π |
Kavin Anand π |
Kejsi Take π» |
Kevin Lam π» π‘ β οΈ |
+
+
Kirstie Whitaker π€ π |
Kishan Manani π» π β οΈ π π€ |
Krum Arnaudov π π» |
-
-
Kutay Koralturk π» π |
Leonidas Tsaprounis π» π π§βπ« π |
Lielle Ravid π» π |
Logan Duffy π» π β οΈ π π€ |
Lorena Pantano π€ |
Lorenzo Toniazzi π» |
+
+
Lovkush π» β οΈ π€ π§βπ« π |
Luca Miniati π» π |
Luis Ventura π» |
-
-
Luis Zugasti π |
Lukasz Mentel π» π π β οΈ π π§ π§βπ« |
Manuel MuΓ±oz Aguirre π |
Marc Rovira π |
Marcelo Trylesinski π |
Marco Gorelli π |
+
+
Margaret Gorlin π» π‘ β οΈ |
Mariam Jabara π» |
Marielle π π» π€ |
-
-
Markus LΓΆning π» β οΈ π§ π¦ π π π‘ π β
πΌ π π¨ π π π€ π π¬ π’ π§βπ« πΉ |
Martin Walter π» π π π π§βπ« π€ π¨ π π π’ |
Martina G. Vilas π π€ |
Mathias Creemers π π» |
Matthew Middlehurst π» π β οΈ β
π π |
Mavs π» |
- Max Frohlich π» π€ π§ |
- Max Patzelt π» |
- Meraldo Antonio π |
+ Max Frohlich π» π€ π§ |
+ Max Patzelt π» |
+ Meraldo Antonio π π |
Miao Cai π π» |
Michael Feil π» β οΈ π€ |
Michael Gaziani π |
Michael Mwimali π» |
Michal Chromcak π» π β οΈ β
|
Mirae Parker π» β οΈ |
+
+
Mirko Bristle π β οΈ π |
Mohammed Saif Kazamel π |
Morad :) π» β οΈ π |
-
-
Multivin12 π» β οΈ |
MΓ‘rcio A. Freitas Jr π |
Niek van der Laan π» |
Nikhil Gupta π» π π |
Nikola Shahpazov π |
Nilesh Kumar π» |
+
+
Ninnart Fuengfusin π» |
Noa Ben Ami π» β οΈ π |
Oleksandr Shchur π π» |
-
-
Oleksii Kachaiev π» β οΈ |
Oliver Matthews π» |
Patrick Rockenschaub π» π¨ π€ β οΈ |
Patrick SchΓ€fer π» β
|
Paul π |
Paul Yim π» π‘ β οΈ |
+
+
Philipp Kortmann π» π |
Piyush Gade π» π |
Poruri Sai Rahul π |
-
-
Pranav Prajapati π» β οΈ π |
Pulkit Verma π |
Quaterion π |
Rakshitha Godahewa π» π |
Ramon Bussing π π» π β οΈ |
RavenRudi π» |
+
+
Rick van Hattem π |
Rishabh Bali π» |
Rishi Kumar Ray π |
-
-
Riya Elizabeth John π» |
Riya Elizabeth John π» β οΈ π |
Roman Lutz π |
Ronnie Llamado π |
Ryan Kuhns π» π β
π‘ π€ π β οΈ |
Sagar Mishra π π» β οΈ |
+
+
Sajaysurya Ganesh π» π π¨ π‘ π€ β οΈ β
|
Sami Alavi π» π§ |
Samruddhi Navale π |
-
-
Sanjay Kumar β οΈ |
Sanjeeb Dey π§ |
Santiago Smith Silva π» |
Saransh Chopra π π |
Satya Prakash Pattnaik π |
Saurabh Dasgupta π» |
+
+
Sebastiaan Koel π» π |
Sebastian Hagn π |
Shivam Pathak π |
-
-
Shivansh Subramanian π π» |
Shlok Sabarwal π» |
Shreesha M π π» β οΈ |
Simon B. π» |
Slava Shpitalny π§ |
Solomon Botchway π§ |
+
+
Stanislav Khrapov π» |
Stijn J. Rotman π» π |
Svea Marie Meyer π π» |
-
-
TNTran92 π» |
Taisei Yamamoto π» |
Taiwo Owoseni π» |
Thach Le Nguyen π» β οΈ |
TheMathcompay Widget Factory Team π |
Thomas Buckley-Houston π |
+
+
Tom Xu π» π |
Tomas P. de Vasconcelos π π» |
Tomasz Chodakowski π» π π |
-
-
Tony Bagnall π» πΌ π π¨ π π π€ π π¬ π π’ π£ |
Utsav Kumar Tiwari π» π |
Vandit Tyagi π |
Vasudeva Kilaru π» π |
Viktor Dremov π» |
ViktorKaz π» π π¨ |
+
+
Vincent Nicholson π» |
Vyomkesh Vyas π» π π‘ β οΈ |
Wayne Adams π |
-
-
William Templier π |
William Zheng π» β οΈ |
Xinyu Wu π π» β οΈ |
Yair Beer π» |
Yann Hallouard π» β οΈ |
Yash Edake π§ π |
+
+
Yash Khare π» π |
Yash Lamba π» |
Yi-Xuan Xu π» β οΈ π§ π |
-
-
Zhen Shao π» |
Ziyao Wei π» |
aa25desh π» π |
abandus π€ π» |
adoherty21 π |
bethrice44 π π» π β οΈ |
+
+
big-o π» β οΈ π¨ π€ π β
π§βπ« |
bobbys π» |
brett koonce π |
-
-
btrtts π |
chizzi25 π |
chrisholder π» β οΈ π π¨ π‘ |
ctl π |
danbartl π π» π π’ β οΈ β
πΉ |
hamzahiqb π |
+
+
hiqbal2 π |
jesellier π» |
jschemm π» |
-
-
kkoziara π» π |
matteogales π» π¨ π€ |
oleskiewicz π» π β οΈ |
pabworks π» β οΈ |
patiently pending world peace π» |
raishubham1 π |
+
+
simone-pignotti π» π |
sophijka π π§ |
sri1419 π» |
-
-
tensorflow-as-tf π» |
vedazeren π» β οΈ |
vincent-nich12 π» |
diff --git a/sktime/base/_base_panel.py b/sktime/base/_base_panel.py
index 0c04f3eaa2d..76dd7230a65 100644
--- a/sktime/base/_base_panel.py
+++ b/sktime/base/_base_panel.py
@@ -102,7 +102,15 @@ def _vectorize(self, methodname, **kwargs):
return y_pred
- def _fit_predict_boilerplate(self, X, y, cv, change_state, method):
+ def _fit_predict_boilerplate(
+ self,
+ X,
+ y,
+ cv,
+ change_state,
+ method,
+ return_type="single_y_pred",
+ ):
"""Boilerplate logic for fit_predict and fit_predict_proba."""
from sklearn.model_selection import KFold
@@ -147,31 +155,86 @@ def _fit_predict_boilerplate(self, X, y, cv, change_state, method):
X = convert(
X,
from_type=X_mtype,
- to_type="nested_univ",
+ to_type=["pd-multiindex", "nested_univ"],
as_scitype="Panel",
store_behaviour="freeze",
)
- if method == "predict_proba":
- y_pred = np.empty([len(y), len(np.unique(y))])
+ y_preds = []
+ tt_ixx = []
+
+ if isinstance(X.index, pd.MultiIndex):
+ X_ix = X.index.get_level_values(0).unique()
else:
- y_pred = np.empty_like(y)
- y_pred[:] = -1
- if isinstance(X, np.ndarray):
- for tr_idx, tt_idx in cv.split(X):
- X_train = X[tr_idx]
- X_test = X[tt_idx]
- y_train = y[tr_idx]
- fitted_est = self.clone().fit(X_train, y_train)
- y_pred[tt_idx] = getattr(fitted_est, method)(X_test)
+ X_ix = np.arange(len(X))
+
+ for tr_idx, tt_idx in cv.split(X_ix):
+ X_train = self._subset(X, tr_idx)
+ X_test = self._subset(X, tt_idx)
+ y_train = self._subset(y, tr_idx)
+ fitted_est = self.clone().fit(X_train, y_train)
+ y_preds.append(getattr(fitted_est, method)(X_test))
+ tt_ixx.append(tt_idx)
+
+ if return_type == "single_y_pred":
+ return self._pool(y_preds, tt_ixx, y)
+ else:
+ return y_preds
+
+ def _subset(self, obj, ix):
+ """Subset input data by ix, for use in fit_predict_boilerplate.
+
+ Parameters
+ ----------
+ obj : pd.DataFrame or np.ndarray
+ if pd.DataFrame, instance index = first level of pd.MultiIndex
+ if np.ndarray, instance index = 0-th axis
+ ix : sklearn splitter index, e.g., ix, _ from KFold.split(X)
+
+ Returns
+ -------
+ obj_ix : obj subset by ix
+ """
+ if isinstance(obj, np.ndarray):
+ return obj[ix]
+ if not isinstance(obj, (pd.DataFrame, pd.Series)):
+ raise ValueError("obj must be a pd.DataFrame, pd.Series, or np.ndarray")
+ if not isinstance(obj.index, pd.MultiIndex):
+ return obj.iloc[ix]
else:
- for tr_idx, tt_idx in cv.split(X):
- X_train = X.iloc[tr_idx]
- X_test = X.iloc[tt_idx]
- y_train = y[tr_idx]
- fitted_est = self.clone().fit(X_train, y_train)
- y_pred[tt_idx] = getattr(fitted_est, method)(X_test)
+ ix_loc = obj.index.get_level_values(0).unique()[ix]
+ return obj.loc[ix_loc]
+
+ def _pool(self, y_preds, tt_ixx, y):
+ """Pool predictions from cv splits, for use in fit_predict_boilerplate.
+
+ Parameters
+ ----------
+ y_preds : list of np.ndarray or pd.DataFrame
+ list of predictions from cv splits
+ tt_ixx : list of np.ndarray or pd.DataFrame
+ list of test indices from cv splits
+ Returns
+ -------
+ y_pred : np.ndarray, pooled predictions
+ """
+ y_pred = y_preds[0]
+ if isinstance(y_pred, (pd.DataFrame, pd.Series)):
+ for i in range(1, len(y_preds)):
+ y_pred = y_pred.combine_first(y_preds[i])
+ y_pred = y_pred.reindex(y.index).fillna(-1)
+ else:
+ if y_pred.ndim == 1:
+ sh = y.shape
+ else:
+ sh = (y.shape[0], y_pred.shape[1])
+ y_pred = -np.ones(sh, dtype=y.dtype)
+ for i, ix in enumerate(tt_ixx):
+ y_preds_i = y_preds[i]
+ if y_pred.ndim == 1:
+ y_preds_i = y_preds_i.reshape(-1)
+ y_pred[ix] = y_preds_i
return y_pred
def _check_convert_X_for_predict(self, X):
diff --git a/sktime/classification/base.py b/sktime/classification/base.py
index 4f09ca6da9e..032fc8a94b1 100644
--- a/sktime/classification/base.py
+++ b/sktime/classification/base.py
@@ -25,10 +25,9 @@ class name: BaseClassifier
import time
import numpy as np
-import pandas as pd
from sktime.base import BasePanelMixin
-from sktime.datatypes import VectorizedDF, check_is_scitype, convert
+from sktime.datatypes import VectorizedDF, check_is_scitype
from sktime.utils.sklearn import is_sklearn_transformer
from sktime.utils.validation import check_n_jobs
from sktime.utils.validation._dependencies import _check_estimator_deps
@@ -374,6 +373,7 @@ def fit_predict(self, X, y, cv=None, change_state=True):
or of any other supported Panel mtype
for list of mtypes, see datatypes.SCITYPE_REGISTER
for specifications, see examples/AA_datatypes_and_datasets.ipynb
+
y : sktime compatible tabular data container, Table scitype
1D iterable, of shape [n_instances]
or 2D iterable, of shape [n_instances, n_dimensions]
@@ -381,20 +381,26 @@ class labels for fitting
0-th indices correspond to instance indices in X
1-st indices (if applicable) correspond to multioutput vector indices in X
supported sktime types: np.ndarray (1D, 2D), pd.Series, pd.DataFrame
+
cv : None, int, or sklearn cross-validation object, optional, default=None
- None : predictions are in-sample, equivalent to fit(X, y).predict(X)
- cv : predictions are equivalent to fit(X_train, y_train).predict(X_test)
- where multiple X_train, y_train, X_test are obtained from cv folds
- returned y is union over all test fold predictions
- cv test folds must be non-intersecting
- int : equivalent to cv=KFold(cv, shuffle=True, random_state=x),
- i.e., k-fold cross-validation predictions out-of-sample
- random_state x is taken from self if exists, otherwise x=None
+
+ * None : predictions are in-sample, equivalent to ``fit(X, y).predict(X)``
+ * cv : predictions are equivalent to
+ ``fit(X_train, y_train).predict(X_test)``, where multiple
+ ``X_train``, ``y_train``, ``X_test`` are obtained from ``cv`` folds.
+ returned ``y`` is union over all test fold predictions,
+ ``cv`` test folds must be non-intersecting
+ * int : equivalent to ``cv=KFold(cv, shuffle=True, random_state=x)``,
+ i.e., k-fold cross-validation predictions out-of-sample, and where
+ ``random_state`` ``x`` is taken from ``self`` if exists,
+ otherwise ``x=None``
+
change_state : bool, optional (default=True)
- if False, will not change the state of the classifier,
- i.e., fit/predict sequence is run with a copy, self does not change
- if True, will fit self to the full X and y,
- end state will be equivalent to running fit(X, y)
+
+ * if False, will not change the state of the classifier,
+ i.e., fit/predict sequence is run with a copy, self does not change
+ * if True, will fit self to the full X and y,
+ end state will be equivalent to running fit(X, y)
Returns
-------
@@ -411,136 +417,6 @@ class labels for fitting
X=X, y=y, cv=cv, change_state=change_state, method="predict"
)
- def _fit_predict_boilerplate(
- self,
- X,
- y,
- cv,
- change_state,
- method,
- return_type="single_y_pred",
- ):
- """Boilerplate logic for fit_predict and fit_predict_proba."""
- from sklearn.model_selection import KFold
-
- if isinstance(cv, int):
- random_state = getattr(self, "random_state", None)
- cv = KFold(cv, random_state=random_state, shuffle=True)
-
- if change_state:
- self.reset()
- est = self
- else:
- est = self.clone()
-
- if cv is None:
- return getattr(est.fit(X, y), method)(X)
- elif change_state:
- self.fit(X, y)
-
- # we now know that cv is an sklearn splitter
- X, y = self._internal_convert(X, y)
- X_metadata = self._check_input(
- X, y, return_metadata=self.METADATA_REQ_IN_CHECKS
- )
- X_mtype = X_metadata["mtype"]
- # Check this classifier can handle characteristics
- self._check_capabilities(X_metadata)
-
- # handle single class case
- if len(self._class_dictionary) == 1:
- return self._single_class_y_pred(X)
-
- # Convert data to format easily usable for applying cv
- if isinstance(X, np.ndarray):
- X = convert(
- X,
- from_type=X_mtype,
- to_type="numpy3D",
- as_scitype="Panel",
- store_behaviour="freeze",
- )
- else:
- X = convert(
- X,
- from_type=X_mtype,
- to_type=["pd-multiindex", "nested_univ"],
- as_scitype="Panel",
- store_behaviour="freeze",
- )
-
- y_preds = []
- tt_ixx = []
-
- for tr_idx, tt_idx in cv.split(X):
- X_train = self._subset(X, tr_idx)
- X_test = self._subset(X, tt_idx)
- y_train = self._subset(y, tr_idx)
- fitted_est = self.clone().fit(X_train, y_train)
- y_preds.append(getattr(fitted_est, method)(X_test))
- tt_ixx.append(tt_idx)
-
- if return_type == "single_y_pred":
- return self._pool(y_preds, tt_ixx, y)
- else:
- return y_preds
-
- def _subset(self, obj, ix):
- """Subset input data by ix, for use in fit_predict_boilerplate.
-
- Parameters
- ----------
- obj : pd.DataFrame or np.ndarray
- if pd.DataFrame, instance index = first level of pd.MultiIndex
- if np.ndarray, instance index = 0-th axis
- ix : sklearn splitter index, e.g., ix, _ from KFold.split(X)
-
- Returns
- -------
- obj_ix : obj subset by ix
- """
- if isinstance(obj, np.ndarray):
- return obj[ix]
- if not isinstance(obj, (pd.DataFrame, pd.Series)):
- raise ValueError("obj must be a pd.DataFrame, pd.Series, or np.ndarray")
- if not isinstance(obj.index, pd.MultiIndex):
- return obj.iloc[ix]
- else:
- ix_loc = obj.index.get_level_values(0).unique()[ix]
- return obj.loc[ix_loc]
-
- def _pool(self, y_preds, tt_ixx, y):
- """Pool predictions from cv splits, for use in fit_predict_boilerplate.
-
- Parameters
- ----------
- y_preds : list of np.ndarray or pd.DataFrame
- list of predictions from cv splits
- tt_ixx : list of np.ndarray or pd.DataFrame
- list of test indices from cv splits
-
- Returns
- -------
- y_pred : np.ndarray, pooled predictions
- """
- y_pred = y_preds[0]
- if isinstance(y_pred, (pd.DataFrame, pd.Series)):
- for i in range(1, len(y_preds)):
- y_pred = y_pred.combine_first(y_preds[i])
- y_pred = y_pred.reindex(y.index).fillna(-1)
- else:
- if y_pred.ndim == 1:
- sh = y.shape
- else:
- sh = (y.shape[0], y_pred.shape[1])
- y_pred = -np.ones(sh, dtype=y.dtype)
- for i, ix in enumerate(tt_ixx):
- y_preds_i = y_preds[i]
- if y_pred.ndim == 1:
- y_preds_i = y_preds_i.reshape(-1)
- y_pred[ix] = y_preds_i
- return y_pred
-
def fit_predict_proba(self, X, y, cv=None, change_state=True):
"""Fit and predict labels probabilities for sequences in X.
@@ -564,6 +440,7 @@ def fit_predict_proba(self, X, y, cv=None, change_state=True):
or of any other supported Panel mtype
for list of mtypes, see datatypes.SCITYPE_REGISTER
for specifications, see examples/AA_datatypes_and_datasets.ipynb
+
y : sktime compatible tabular data container, Table scitype
1D iterable, of shape [n_instances]
or 2D iterable, of shape [n_instances, n_dimensions]
@@ -571,18 +448,26 @@ class labels for fitting
0-th indices correspond to instance indices in X
1-st indices (if applicable) correspond to multioutput vector indices in X
supported sktime types: np.ndarray (1D, 2D), pd.Series, pd.DataFrame
+
cv : None, int, or sklearn cross-validation object, optional, default=None
- None : predictions are in-sample, equivalent to fit(X, y).predict(X)
- cv : predictions are equivalent to fit(X_train, y_train).predict(X_test)
- where multiple X_train, y_train, X_test are obtained from cv folds
- returned y is union over all test fold predictions
- cv test folds must be non-intersecting
- int : equivalent to cv=Kfold(int), i.e., k-fold cross-validation predictions
+
+ * None : predictions are in-sample, equivalent to ``fit(X, y).predict(X)``
+ * cv : predictions are equivalent to
+ ``fit(X_train, y_train).predict(X_test)``, where multiple
+ ``X_train``, ``y_train``, ``X_test`` are obtained from ``cv`` folds.
+ returned ``y`` is union over all test fold predictions,
+ ``cv`` test folds must be non-intersecting
+ * int : equivalent to ``cv=KFold(cv, shuffle=True, random_state=x)``,
+ i.e., k-fold cross-validation predictions out-of-sample, and where
+ ``random_state`` ``x`` is taken from ``self`` if exists,
+ otherwise ``x=None``
+
change_state : bool, optional (default=True)
- if False, will not change the state of the classifier,
- i.e., fit/predict sequence is run with a copy, self does not change
- if True, will fit self to the full X and y,
- end state will be equivalent to running fit(X, y)
+
+ * if False, will not change the state of the classifier,
+ i.e., fit/predict sequence is run with a copy, self does not change
+ * if True, will fit self to the full X and y,
+ end state will be equivalent to running fit(X, y)
Returns
-------
diff --git a/sktime/classification/tests/test_all_classifiers.py b/sktime/classification/tests/test_all_classifiers.py
index cd16cdfb552..f42b1637f4a 100644
--- a/sktime/classification/tests/test_all_classifiers.py
+++ b/sktime/classification/tests/test_all_classifiers.py
@@ -109,6 +109,11 @@ def test_classifier_output(self, estimator_instance, scenario):
)
X_train_len = X_train_metadata["n_instances"]
+ # temp hack until _get_train_probs is implemented for all mtypes
+ if hasattr(X_train_len, "index"):
+ if isinstance(X_train_len.index, pd.MultiIndex):
+ return None
+
train_proba = estimator_instance._get_train_probs(X_train, y_train)
assert isinstance(train_proba, np.ndarray)
diff --git a/sktime/utils/_testing/scenarios_classification.py b/sktime/utils/_testing/scenarios_classification.py
index 2274bdb06c5..796be310981 100644
--- a/sktime/utils/_testing/scenarios_classification.py
+++ b/sktime/utils/_testing/scenarios_classification.py
@@ -16,7 +16,11 @@
from sktime.base import BaseObject
from sktime.registry import scitype
from sktime.utils._testing.hierarchical import _make_hierarchical
-from sktime.utils._testing.panel import _make_classification_y, _make_panel_X
+from sktime.utils._testing.panel import (
+ _make_classification_y,
+ _make_panel,
+ _make_panel_X,
+)
from sktime.utils._testing.scenarios import TestScenario
# random seed for generating data to keep scenarios exactly reproducible
@@ -117,6 +121,31 @@ def args(self):
default_arg_sequence = ["fit", "predict", "predict", "predict"]
+class ClassifierFitPredictThreeClasses(ClassifierTestScenario):
+ """Fit/predict with univariate panel X, pd-multiindex mtype, and three classes."""
+
+ _tags = {
+ "X_univariate": True,
+ "X_unequal_length": False,
+ "is_enabled": True,
+ "n_classes": 3,
+ }
+
+ @property
+ def args(self):
+ y = _make_classification_y(n_instances=18, n_classes=3, random_state=RAND_SEED)
+ X = _make_panel(n_instances=18, n_timepoints=20, random_state=RAND_SEED, y=y)
+ X_test = _make_panel_X(n_instances=5, n_timepoints=20, random_state=RAND_SEED)
+
+ return {
+ "fit": {"y": y, "X": X},
+ "predict": {"X": X_test},
+ }
+
+ default_method_sequence = ["fit", "predict", "predict_proba", "decision_function"]
+ default_arg_sequence = ["fit", "predict", "predict", "predict"]
+
+
class ClassifierFitPredictNumpy(ClassifierTestScenario):
"""Fit/predict with univariate panel X, numpy3D mtype, and labels y."""
@@ -216,6 +245,7 @@ def args(self):
scenarios_classification = [
ClassifierFitPredict,
+ ClassifierFitPredictThreeClasses,
ClassifierFitPredictNumpy,
ClassifierFitPredictMultivariate,
ClassifierFitPredictUnequalLength,
@@ -224,6 +254,7 @@ def args(self):
# same scenarios used for early classification
scenarios_early_classification = [
ClassifierFitPredict,
+ ClassifierFitPredictThreeClasses,
ClassifierFitPredictNumpy,
ClassifierFitPredictMultivariate,
ClassifierFitPredictUnequalLength,