code: def generate_train_test_split(
      X: DataFrame,
      y: Series,
      problem_type: str,
      test_size: Union[float, int] = 0.1,
      random_state=0,
      min_cls_count_train=1,
  ) -> Tuple[DataFrame, DataFrame, Series, Series]:
      """
      Generate a train test split from input X, y.
      If you have a combined X, y DataFrame, refer to `generate_train_test_split_combined` instead.
  
      Parameters
      ----------
      X : DataFrame
          pd.DataFrame containing the features minus the label column to split into train and test sets.
      y : Series
          pd.Series containing the label with matching indices to X.
          Used for stratification and to ensure all classes in multiclass classification are preserved in train data.
      problem_type : str
          The problem_type the label is used for. Determines if stratification is used.
          Options: ["binary", "multiclass", "regression", "softclass", "quantile"]
      test_size : float, default = 0.1
          The proportion of data to use for the test set.
          The remaining (1 - test_size) of data will be used for the training set.
      test_size : float or int, default = 0.1
          If float, should be between 0.0 and 1.0 and represent the proportion of the dataset to include in the test split.
          If int, represents the absolute number of test samples.
      random_state : int, default = 0
          Random seed to use during the split.
      min_cls_count_train : int, default = 1
          The minimum number of instances of each class that must occur in the training set (for classification).
          If not satisfied by the original split, instances of unsatisfied classes are
          taken from test and put into train until satisfied.
          Raises an exception if impossible to satisfy.
  
      Returns
      -------
      X_train, X_test, y_train, y_test : (DataFrame, DataFrame, Series, Series)
          The train_data and test_data after performing the split, separated into X and y.
  
      """
      if len(X) == 1:
          raise ValueError(
              f"Cannot split data into train/val as it contains only one sample."
          )
      if isinstance(test_size, float):
          if (test_size <= 0.0) or (test_size >= 1.0):
              raise ValueError(
                  "fraction of data to hold-out must be specified between 0 and 1"
              )
      elif isinstance(test_size, int):
          assert test_size > 0
      valid_problem_types = [
          BINARY,
          MULTICLASS,
          REGRESSION,
          SOFTCLASS,
          QUANTILE,
      ]
      assert (
          problem_type in valid_problem_types
      ), f'Unknown problem type "{problem_type}" | Valid problem types: {valid_problem_types}'
  
      X_split = X
      y_split = y
      if problem_type in [BINARY, MULTICLASS]:
          stratify = y
      else:
          stratify = None
  
      # This code block is necessary to avoid crashing when performing a stratified split and only 1 sample exists for a class.
      # This code will ensure that the sample will be part of the train split, meaning the test split will have 0 samples of the rare class.
      rare_indices = None
      if stratify is not None:
          cls_counts = y.value_counts()
          cls_counts_invalid = cls_counts[
              cls_counts < min_cls_count_train
          ]
  
          if len(cls_counts_invalid) > 0:
              logger.error(
                  f"ERROR: Classes have too few samples to split the data! At least {min_cls_count_train} are required."
              )
              logger.error(cls_counts_invalid)
              raise AssertionError(
                  "Not enough data to split data into train and val without dropping classes!"
              )
          elif min_cls_count_train < 2:
              cls_counts_rare = cls_counts[cls_counts < 2]
              if len(cls_counts_rare) > 0:
                  cls_counts_rare_val = set(cls_counts_rare.index)
                  y_rare = y[y.isin(cls_counts_rare_val)]
                  rare_indices = list(y_rare.index)
                  X_split = X.drop(index=rare_indices)
                  y_split = y.drop(index=rare_indices)
                  stratify = y_split
  
      try:
          X_train, X_test, y_train, y_test = train_test_split(
              X_split,
              y_split.values,
              test_size=test_size,
              shuffle=True,
              random_state=random_state,
              stratify=stratify,
          )
      except ValueError:
          # This logic is necessary to avoid an edge-case limitation of scikit-learn's train_test_split function that leads to the following error:
          #  ValueError: The test_size = FOO should be greater or equal to the number of classes = BAR
          # When the number of classes is greater than the resulting number of test rows, and stratification is enabled, it will raise an exception.
          #  Logically the code should still work, but for some reason scikit-learn doesn't allow this scenario.
          #  To handle it without erroring, we disable stratification in this case. This isn't ideal, but proper solutions involve patching scikit-learn.
          if stratify is None:
              raise
          X_train, X_test, y_train, y_test = train_test_split(
              X_split,
              y_split.values,
              test_size=test_size,
              shuffle=True,
              random_state=random_state,
              stratify=None,
          )
          if len(y_test) >= len(y_split.unique()):
              # This should never occur, otherwise the original exception is not an expected one
              raise
      if problem_type != SOFTCLASS:
          y_train = pd.Series(y_train, index=X_train.index)
          y_test = pd.Series(y_test, index=X_test.index)
      else:
          y_train = pd.DataFrame(y_train, index=X_train.index)
          y_test = pd.DataFrame(y_test, index=X_test.index)
  
      if rare_indices:
          X_train = pd.concat([X_train, X.loc[rare_indices]])
          y_train = pd.concat([y_train, y.loc[rare_indices]])
  
      if problem_type in [BINARY, MULTICLASS]:
          class_counts_dict_orig = y.value_counts().to_dict()
          class_counts_dict = y_train.value_counts().to_dict()
          class_counts_dict_test = y_test.value_counts().to_dict()
  
          indices_to_move = []
          random_state_init = random.getstate()
          random.seed(random_state)
          for cls in class_counts_dict_orig.keys():
              count = class_counts_dict.get(cls, 0)
              if count >= min_cls_count_train:
                  continue
              count_test = class_counts_dict_test.get(cls, 0)
              if count + count_test < min_cls_count_train:
                  raise AssertionError(
                      "Not enough data to split data into train and val without dropping classes!"
                  )
              count_to_move = min_cls_count_train - count
              indices_of_cls_test = list(y_test[y_test == cls].index)
              indices_to_move_cls = random.sample(
                  indices_of_cls_test, count_to_move
              )
              indices_to_move += indices_to_move_cls
          random.setstate(random_state_init)
          if indices_to_move:
              y_test_moved = y_test.loc[indices_to_move].copy()
              X_test_moved = X_test.loc[indices_to_move].copy()
              y_train = pd.concat([y_train, y_test_moved])
              X_train = pd.concat([X_train, X_test_moved])
              y_test = y_test.drop(index=indices_to_move)
              X_test = X_test.drop(index=indices_to_move)
          y_train.name = y_split.name
          y_test.name = y_split.name
      return X_train, X_test, y_train, y_test
  
imports: import logging
  import math
  import pickle
  import random
  import sys
  import time
  from typing import Callable, List, Tuple, Union
  import numpy
  import pandas
  import scipy.stats
  from numpy.typing import ArrayLike
  from pandas import DataFrame, Series
  from sklearn.model_selection import LeaveOneGroupOut, RepeatedKFold, RepeatedStratifiedKFold, train_test_split
  from autogluon.common.utils.resource_utils import ResourceManager
  from ..constants import BINARY, LARGE_DATA_THRESHOLD, MULTICLASS, MULTICLASS_UPPER_LIMIT, QUANTILE, REGRESS_THRESHOLD_LARGE_DATA, REGRESS_THRESHOLD_SMALL_DATA, REGRESSION, SOFTCLASS
  from ..metrics import Scorer, accuracy, pinball_loss, root_mean_squared_error
  from .miscs import warning_filter
label_desc: Use image node_id 14 for calling a global function with example usage: generate_train_test_split(X, y, problem_type, test_size, random_state, min_cls_count_train) and returns: X_train,  X_test,  y_train,  y_test