Date-aware time series cross-validator for deterministic train/test splits.
Project description
TimeSeriesSplitByDate
Date-aware cross-validation for machine learning on irregularly timestamped data.
Installation
pip install timeseriessplitbydate
Motivation / Problem Statement
Many ML pipelines split by row index, not by actual event time. That can be misleading when timestamps are irregular (bursts, long gaps, uneven logging), because a fold with 500 rows may represent 2 days while another fold with 500 rows may represent 3 weeks.
sklearn.model_selection.TimeSeriesSplit is excellent for many cases, but its documentation explicitly assumes equally spaced samples for comparable fold durations. See: https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.TimeSeriesSplit.html
TimeSeriesSplitByDate addresses this by splitting on real dates (days, weeks, months) while preserving sklearn-style usage.
When should I use this?
- Your observations are time-indexed but not equally spaced.
- You need validation windows aligned to calendar units (day/week/month).
- You want a strict chronological split with explicit date boundaries.
- You still want an sklearn-compatible CV object for model selection workflows.
- You want a fallback to
TimeSeriesSplitwhen date data is not provided.
Comparison vs sklearn TimeSeriesSplit
| Capability | TimeSeriesSplit |
TimeSeriesSplitByDate |
|---|---|---|
| Split basis | Sample index order | Datetime boundaries (days, weeks, months) |
| Assumption for comparable fold duration | Equally spaced samples | No equal-spacing assumption |
| Handles irregular timestamps directly | Limited | Yes |
| Calendar-aligned weekly/monthly folds | No | Yes |
| Week start control | No | Yes (week_start='monday' or 'sunday') |
| Gap meaning in date-based mode | Samples | Calendar days |
sklearn-style API (split, get_n_splits) |
Yes | Yes |
Quickstart
import pandas as pd
from timeseriessplitbydate import TimeSeriesSplitByDate
X = pd.DataFrame(
{
"feature": range(8),
"event_date": pd.date_range("2024-01-01", periods=8, freq="D"),
}
)
splitter = TimeSeriesSplitByDate(
n_splits=3,
date_col="event_date",
split_by="weeks",
week_start="monday",
)
for train_idx, test_idx in splitter.split(X):
print(train_idx, test_idx)
Realistic ML Examples
1) Healthcare: irregular patient encounters
Patients rarely generate observations at fixed intervals. Encounters cluster around acute events and then become sparse. Date-based folds prevent evaluation leakage where training accidentally includes data too close in time to validation encounters.
2) Finance: uneven market/event cadence
Signals around earnings, macro releases, or volatility spikes are not uniformly spaced in event time. Date-based weekly/monthly folds let you evaluate stability across comparable calendar periods rather than equal row counts.
FAQ / Gotchas
Do I need to sort rows by date first?
No. Splits are built from datetime values, not row order. Chronological boundaries are date-based even if your DataFrame is shuffled.
What happens with duplicate timestamps?
Duplicates are handled deterministically by date masks. Multiple rows sharing the same timestamp are kept together according to the fold boundaries for that mode.
Are timezone-aware datetimes supported?
Yes, as long as your datetime column is consistently parseable by pandas. Avoid mixing incompatible timezone formats within the same column.
What exactly does gap mean in date-based modes?
split_by='days':gapis calendar days between train and test windows.split_by='weeks'/split_by='months':gapis calendar days added to the start of the test period.- Fallback
TimeSeriesSplit:gapis in number of samples (sklearn behavior).
Documentation and Demo
- Usage guide: https://github.com/theyou21/timeseriessplitbydate/blob/main/docs/usage.md
- Runnable example: https://github.com/theyou21/timeseriessplitbydate/blob/main/examples/basic_usage.py
- Notebook demo: https://github.com/theyou21/timeseriessplitbydate/blob/main/notebooks/demo.ipynb
Citing
If you use this in academic work, please cite:
@software{timeseriessplitbydate_2026,
author = {Bai, Zeyu},
title = {TimeSeriesSplitByDate},
year = {2026},
version = {0.1.1},
url = {https://github.com/theyou21/timeseriessplitbydate}
}
Development
pip install -e .[dev]
ruff check .
pytest
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file timeseriessplitbydate-0.1.1.tar.gz.
File metadata
- Download URL: timeseriessplitbydate-0.1.1.tar.gz
- Upload date:
- Size: 14.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
45b4304c047ede9010bc4481c4d77082cef08bd87c50bfbb07dcf4146bc6885c
|
|
| MD5 |
19c3f5164f6c854ea2de75cf16763954
|
|
| BLAKE2b-256 |
57f0d434331c98775ea1e3295854d28609ce06d4c187452e26363dc47a25563a
|
Provenance
The following attestation bundles were made for timeseriessplitbydate-0.1.1.tar.gz:
Publisher:
release.yml on theyou21/timeseriessplitbydate
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
timeseriessplitbydate-0.1.1.tar.gz -
Subject digest:
45b4304c047ede9010bc4481c4d77082cef08bd87c50bfbb07dcf4146bc6885c - Sigstore transparency entry: 956055317
- Sigstore integration time:
-
Permalink:
theyou21/timeseriessplitbydate@4cd0de45b6e25453406ff7d468c0ae900732bc7e -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/theyou21
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4cd0de45b6e25453406ff7d468c0ae900732bc7e -
Trigger Event:
push
-
Statement type:
File details
Details for the file timeseriessplitbydate-0.1.1-py3-none-any.whl.
File metadata
- Download URL: timeseriessplitbydate-0.1.1-py3-none-any.whl
- Upload date:
- Size: 10.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
de2431d953fe00e9cbc538b4288a79eeaa85d9ecb88a4f1cd86774281254a31f
|
|
| MD5 |
690032c84d6d5142281af5d91b03a89e
|
|
| BLAKE2b-256 |
aa37c04bc8c7745f0404794757d88aceeba98216583fa5096f916be3b62518d5
|
Provenance
The following attestation bundles were made for timeseriessplitbydate-0.1.1-py3-none-any.whl:
Publisher:
release.yml on theyou21/timeseriessplitbydate
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
timeseriessplitbydate-0.1.1-py3-none-any.whl -
Subject digest:
de2431d953fe00e9cbc538b4288a79eeaa85d9ecb88a4f1cd86774281254a31f - Sigstore transparency entry: 956055319
- Sigstore integration time:
-
Permalink:
theyou21/timeseriessplitbydate@4cd0de45b6e25453406ff7d468c0ae900732bc7e -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/theyou21
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4cd0de45b6e25453406ff7d468c0ae900732bc7e -
Trigger Event:
push
-
Statement type: