code: def _split_by_fh(
      y: ACCEPTED_Y_TYPES,
      fh: FORECASTING_HORIZON_TYPES,
      X: Optional[pd.DataFrame] = None,
  ) -> SPLIT_TYPE:
      """Split time series with forecasting horizon.
  
      Handles both relative and absolute horizons.
      """
      if X is not None:
          check_equal_time_index(y, X)
      index = y.index
      fh = check_fh(fh, freq=index)
      idx = fh.to_pandas()
  
      if fh.is_relative:
          if not fh.is_all_out_of_sample():
              raise ValueError(
                  "`fh` must only contain out-of-sample values"
              )
          max_step = idx.max()
          steps = fh.to_indexer()
          train = index[:-max_step]
          test = index[-max_step:]
  
          y_test = y.loc[test[steps]]
  
      else:
          min_step, max_step = idx.min(), idx.max()
          train = index[index < min_step]
          test = index[(index <= max_step) & (min_step <= index)]
  
          y_test = y.loc[idx]
  
      y_train = y.loc[train]
      if X is None:
          return y_train, y_test
  
      X_train = X.loc[train]
      X_test = X.loc[test]
      return y_train, y_test, X_train, X_test
  
file_path: sktime/sktime/split/base/_common.py
imports: from typing import Iterator, Optional, Tuple, Union
  import numpy
  import pandas
  from sktime.datatypes._utilities import get_window
  from sktime.forecasting.base import ForecastingHorizon
  from sktime.forecasting.base._fh import VALID_FORECASTING_HORIZON_TYPES
  from sktime.utils.validation import all_inputs_are_iloc_like, all_inputs_are_time_like, array_is_int, is_int
  from sktime.utils.validation.forecasting import check_fh
  from sktime.utils.validation.series import check_equal_time_index
label_desc: Use image node_id 5 for calling a global function with example usage: _split_by_fh(y, fh, X) and returns: y_train,  y_test,  X_train,  X_test, y_train,  y_test