#254Group / Time-Series CV SplitEasy

Group / Time-Series CV Split

Background

Random CV splits leak the future when data has a time axis OR when each entity contributes many rows. Group-time CV combines the two safeguards: sort groups by their last observation, split groups into folds, and ensure each fold's train precedes its val in time.

Problem statement

Implement time_group_split(group_to_max_time, n_splits):

  1. Sort group IDs by their max timestamp ascending.
  2. Split into n_splits contiguous folds.
  3. For fold ii: val = fold ii's groups; train = all groups in earlier folds (NOT the union of all other folds).

Return a list of (train_groups, val_groups) tuples.

Input

  • group_to_max_timedict[str, number], group id → latest timestamp.
  • n_splitsint >= 2.

Output

Returns list[tuple[list[str], list[str]]] of length n_splits.

Examples

Example 1 — chronologically separable

Input:  groups = {"a": 1, "b": 2, "c": 3, "d": 4}; n_splits = 2
Output: fold 0: train=[], val=["a", "b"]; fold 1: train=["a", "b"], val=["c", "d"]

Example 2 — every group appears in exactly one val fold

Input:  6 groups, n_splits=3
Output: union of all val sets == all groups

Constraints

  • Each train set must be strictly earlier in time than its val set (max time of any train group ≤ min time of any val group).
  • Empty train fold (fold 0) is allowed.
  • n_splits >= 2.

Notes

  • vs TimeSeriesSplit. Sklearn's TimeSeriesSplit works on rows, not groups; it allows a group to span the train/val boundary. Group-time CV is the right choice when each user/entity must be entirely on one side.
  • Embargo gap. Quantitative finance setups add a small "embargo" gap between train and val to avoid information bleed from clustered timestamps — out of scope here.
Python
Loading...

▶ Run executes the 3 visible sample tests below in your browser. Submit runs the full suite — including hidden tests — on the server for an official verdict.

  • Reference example: chronologically separable split
  • Sample: groups ordered by timestamp, not insertion order
  • Example: remainder goes to the last fold