class_docstr: Grouping data by user or item then splitting data into training, validation, and test sets.
  
  Parameters
  ----------
  data: array-like, required
      Raw preference data in the triplet format [(user_id, item_id, rating_value, timestamp)].
  
  group_by: str, optional, default: 'user'
      Grouping by 'user' or 'item'.
  
  chrono: bool, optional, default False
      Data is ordered by reviewed time or not. If this option is True, data must be in 'UIRT' format.
  
  test_size: float, optional, default: 0.2
      The proportion of the test set,         if > 1 then it is treated as the size of the test set.
  
  val_size: float, optional, default: 0.0
      The proportion of the validation set,         if > 1 then it is treated as the size of the validation set.
  
  rating_threshold: float, optional, default: 1.0
      Threshold used to binarize rating values into positive or negative feedback for
      model evaluation using ranking metrics (rating metrics are not affected).
  
  seed: int, optional, default: None
      Random seed for reproducibility.
  
  exclude_unknowns: bool, optional, default: True
      If `True`, unknown users and items will be ignored during model evaluation.
  
  verbose: bool, optional, default: False
      Output running log.
code: def _split(self):
      data = (
          sorted(self.data, key=lambda x: x[3])
          if self.chrono
          else self.data
      )  # sort data chronologically
  
      grouped_indices = defaultdict(list)
      for idx, (uid, iid, *_) in enumerate(data):
          if self.group_by == "user":
              grouped_indices[uid].append(idx)
          else:
              grouped_indices[iid].append(idx)
  
      train_idx = []
      test_idx = []
      val_idx = []
  
      for rating_indices in grouped_indices.values():
          n_ratings = len(rating_indices)
          n_train, _, n_test = RatioSplit.validate_size(
              self.val_size, self.test_size, n_ratings
          )
  
          if self.chrono:
              # training portion is chronologically sorted
              # validation and test portions are randomly selected
              rating_indices = (
                  rating_indices[:n_train]
                  + self.rng.permutation(
                      rating_indices[n_train:]
                  ).tolist()
              )
          else:
              rating_indices = self.rng.permutation(
                  rating_indices
              ).tolist()
  
          train_idx += rating_indices[:n_train]
          test_idx += rating_indices[-n_test:]
          val_idx += rating_indices[n_train:-n_test]
  
      train_data = safe_indexing(data, train_idx)
      test_data = safe_indexing(data, test_idx)
      val_data = (
          safe_indexing(data, val_idx) if len(val_idx) > 0 else None
      )
  
      self.build(
          train_data=train_data, test_data=test_data, val_data=val_data
      )
  
file_path: cornac/cornac/eval_methods/stratified_split.py
imports: from math import ceil
  from collections import defaultdict
  from .base_method import BaseMethod
  from .ratio_split import RatioSplit
  from ..utils import get_rng
  from ..utils.common import safe_indexing
label_desc: Use image node_id 2 for calling the StratifiedSplit obj's underlying member method code with example usage: obj._split() without return types