class_docstr: A rotation forest (RotF) vector classifier.
  
  Implementation of the Rotation Forest classifier described in Rodriguez et al
  (2013) [1]. Builds a forest of trees build on random portions of the data
  transformed using PCA.
  
  Intended as a benchmark for time series data and a base classifier for
  transformation based approaches such as ShapeletTransformClassifier, this sktime
  implementation only works with continuous attributes.
  
  Parameters
  ----------
  n_estimators : int, default=200
      Number of estimators to build for the ensemble.
  min_group : int, default=3
      The minimum size of an attribute subsample group.
  max_group : int, default=3
      The maximum size of an attribute subsample group.
  remove_proportion : float, default=0.5
      The proportion of cases to be removed per group.
  base_estimator : BaseEstimator or None, default="None"
      Base estimator for the ensemble. By default, uses the sklearn
      `DecisionTreeClassifier` using entropy as a splitting measure.
  time_limit_in_minutes : int, default=0
      Time contract to limit build time in minutes, overriding ``n_estimators``.
      Default of `0` means ``n_estimators`` is used.
  contract_max_n_estimators : int, default=500
      Max number of estimators to build when ``time_limit_in_minutes`` is set.
  save_transformed_data : bool, default=False
      Save the data transformed in fit in ``transformed_data_`` for use in
      ``_get_train_probs``.
  n_jobs : int, default=1
      The number of jobs to run in parallel for both ``fit`` and ``predict``.
      `-1` means using all processors.
  random_state : int, RandomState instance or None, default=None
      If `int`, random_state is the seed used by the random number generator;
      If `RandomState` instance, random_state is the random number generator;
      If `None`, the random number generator is the `RandomState` instance used
      by `np.random`.
  
  Attributes
  ----------
  classes_ : list
      The unique class labels in the training set.
  n_classes_ : int
      The number of unique classes in the training set.
  n_instances_ : int
      The number of train cases in the training set.
  n_atts_ : int
      The number of attributes in the training set.
  transformed_data_ : list of shape (n_estimators) of ndarray
      The transformed training dataset for all classifiers. Only saved when
      ``save_transformed_data`` is `True`.
  estimators_ : list of shape (n_estimators) of BaseEstimator
      The collections of estimators trained in fit.
  
  See Also
  --------
  ShapeletTransformClassifier: A shapelet-based classifier using Rotation Forest.
  
  Notes
  -----
  For the Java version, see
  `tsml <https://github.com/uea-machine-learning/tsml/blob/master/src/main/java
  /weka/classifiers/meta/RotationForest.java>`_.
  
  References
  ----------
  .. [1] Rodriguez, Juan José, Ludmila I. Kuncheva, and Carlos J. Alonso. "Rotation
     forest: A new classifier ensemble method." IEEE transactions on pattern analysis
     and machine intelligence 28.10 (2006).
  
  .. [2] Bagnall, A., et al. "Is rotation forest the best classifier for problems
     with continuous features?." arXiv preprint arXiv:1809.06705 (2018).
  
  Examples
  --------
  >>> from sktime.classification.sklearn import RotationForest
  >>> from sktime.datasets import load_unit_test
  >>> from sktime.datatypes._panel._convert import from_nested_to_3d_numpy
  >>> X_train, y_train = load_unit_test(split="train", return_X_y=True)
  >>> X_test, y_test = load_unit_test(split="test", return_X_y=True)
  >>> X_train = from_nested_to_3d_numpy(X_train)
  >>> X_test = from_nested_to_3d_numpy(X_test)
  >>> clf = RotationForest(n_estimators=10)
  >>> clf.fit(X_train, y_train)
  RotationForest(...)
  >>> y_pred = clf.predict(X_test)
docstr: Fit a forest of trees on cases (X,y), where y is the target variable.
  
  Parameters
  ----------
  X : 2d ndarray or DataFrame of shape = [n_instances, n_attributes]
      The training data.
  y : array-like, shape = [n_instances]
      The class labels.
  
  Returns
  -------
  self :
      Reference to self.
  
  Notes
  -----
  Changes state by creating a fitted model that updates attributes
  ending in "_".
docstr_tok: ["Fit","a","forest","of","trees","on","cases","(","X",",","y",")",",","where","y","is","the","target","variable",".","Parameters","--","--","--","--","--","X",":","2d","ndarray","or","DataFrame","of","shape","=","[","n_instances",",","n_attributes","]","The","training","data",".","y",":","array-like",",","shape","=","[","n_instances","]","The","class","labels",".","Returns","--","--","--","-","self",":","Reference","to","self",".","Notes","--","--","-","Changes","state","by","creating","a","fitted","model","that","updates","attributes","ending","in","``","_","''","."]
code: def fit(self, X, y):
      """Fit a forest of trees on cases (X,y), where y is the target variable.
  
      Parameters
      ----------
      X : 2d ndarray or DataFrame of shape = [n_instances, n_attributes]
          The training data.
      y : array-like, shape = [n_instances]
          The class labels.
  
      Returns
      -------
      self :
          Reference to self.
  
      Notes
      -----
      Changes state by creating a fitted model that updates attributes
      ending in "_".
      """
      if (
          isinstance(X, np.ndarray)
          and len(X.shape) == 3
          and X.shape[1] == 1
      ):
          X = np.reshape(X, (X.shape[0], -1))
      elif isinstance(X, pd.DataFrame) and len(X.shape) == 2:
          X = X.to_numpy()
      elif not isinstance(X, np.ndarray) or len(X.shape) > 2:
          raise ValueError(
              "RotationForest is not a time series classifier. "
              "A valid sklearn input such as a 2d numpy array is required."
              "Sparse input formats are currently not supported."
          )
      X, y = self._validate_data(X=X, y=y, ensure_min_samples=2)
  
      self._n_jobs = check_n_jobs(self.n_jobs)
  
      self.n_instances_, self.n_atts_ = X.shape
      self.classes_ = np.unique(y)
      self.n_classes_ = self.classes_.shape[0]
      self._class_dictionary = {}
      for index, classVal in enumerate(self.classes_):
          self._class_dictionary[classVal] = index
  
      # escape if only one class seen
      if self.n_classes_ == 1:
          self._is_fitted = True
          return self
  
      time_limit = self.time_limit_in_minutes * 60
      start_time = time.time()
      train_time = 0
  
      if self.base_estimator is None:
          self._base_estimator = DecisionTreeClassifier(
              criterion="entropy"
          )
  
      # remove useless attributes
      self._useful_atts = ~np.all(X[1:] == X[:-1], axis=0)
      X = X[:, self._useful_atts]
  
      self._n_atts = X.shape[1]
  
      # normalise attributes
      self._min = X.min(axis=0)
      self._ptp = X.max(axis=0) - self._min
      X = (X - self._min) / self._ptp
  
      X_cls_split = [X[np.where(y == i)] for i in self.classes_]
  
      if time_limit > 0:
          self._n_estimators = 0
          self.estimators_ = []
          self._pcas = []
          self._groups = []
          self.transformed_data_ = []
  
          while (
              train_time < time_limit
              and self._n_estimators < self.contract_max_n_estimators
          ):
              fit = Parallel(n_jobs=self._n_jobs)(
                  delayed(self._fit_estimator)(
                      X,
                      X_cls_split,
                      y,
                      i,
                  )
                  for i in range(self._n_jobs)
              )
  
              estimators, pcas, groups, transformed_data = zip(*fit)
  
              self.estimators_ += estimators
              self._pcas += pcas
              self._groups += groups
              self.transformed_data_ += transformed_data
  
              self._n_estimators += self._n_jobs
              train_time = time.time() - start_time
      else:
          self._n_estimators = self.n_estimators
  
          fit = Parallel(n_jobs=self._n_jobs)(
              delayed(self._fit_estimator)(
                  X,
                  X_cls_split,
                  y,
                  i,
              )
              for i in range(self._n_estimators)
          )
  
          (
              self.estimators_,
              self._pcas,
              self._groups,
              self.transformed_data_,
          ) = zip(*fit)
  
      self._is_fitted = True
      return self
  
imports: import time
  import numpy
  import pandas
  from joblib import Parallel, delayed
  from sklearn.base import BaseEstimator
  from sklearn.decomposition import PCA
  from sklearn.tree import DecisionTreeClassifier
  from sklearn.utils import check_random_state
  from sktime.base._base import _clone_estimator
  from sktime.exceptions import NotFittedError
  from sktime.utils.validation import check_n_jobs
label_desc: Use image node_id 2 for calling the RotationForest obj's underlying member method code with example usage: obj.fit(X, y) and returns: self, self