Metadata-Version: 2.4
Name: walkforwardsplit
Version: 0.2.0
Summary: Expanding-window walk-forward time series cross-validator, scikit-learn compatible.
Project-URL: Homepage, https://github.com/tarantula-research-labs-open/walkforwardsplit
Project-URL: Repository, https://github.com/tarantula-research-labs-open/walkforwardsplit
Author: Luv Ratan
License: MIT
License-File: LICENSE
Keywords: cross-validation,finance,machine-learning,scikit-learn,time-series,walk-forward
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.8
Requires-Dist: numpy>=1.20
Requires-Dist: scikit-learn>=1.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == 'dev'
Description-Content-Type: text/markdown

# walkforwardsplit

An expanding-window, walk-forward time series cross-validator, compatible with
scikit-learn's CV interface (`split`, `get_n_splits`) and built on top of
`sklearn.model_selection.BaseCrossValidator`.

Unlike `sklearn.model_selection.TimeSeriesSplit`, this splitter always starts
training from a fixed initial block (the first half of the data) and walks
forward through equal-sized test folds carved out of the second half — a
common setup for walk-forward validation in quantitative finance and other
sequential-data settings.

```
Fold 1: #########################=====....................
Fold 2: ##############################=====...............
Fold 3: ###################################=====..........
Fold 4: ########################################=====.....
Fold 5: #############################################=====

Legend: # train   = test   . not yet used
```

Training expands forward each fold while the test block moves ahead in lockstep,
always immediately after the training data. Rows further in the future than the
current test block ("not yet used") are excluded from both — a fold should never
see data from beyond its own test window, even in training.

## Install

```bash
pip install walkforwardsplit
```

## Usage

```python
import numpy as np
from walkforwardsplit import WalkForwardSplit

X = np.arange(100)
cv = WalkForwardSplit(5)
for train_idx, test_idx in cv.split(X):
    print(train_idx, test_idx)
```

```
[ 0  1  2 ... 47 48 49] [50 51 52 53 54 55 56 57 58 59]
[ 0  1  2 ... 57 58 59] [60 61 62 63 64 65 66 67 68 69]
[ 0  1  2 ... 67 68 69] [70 71 72 73 74 75 76 77 78 79]
[ 0  1  2 ... 77 78 79] [80 81 82 83 84 85 86 87 88 89]
[ 0  1  2 ... 87 88 89] [90 91 92 93 94 95 96 97 98 99]
```

### With a scikit-learn dataset

Because it implements `split()` and `get_n_splits()`, it drops into any
sklearn API that accepts a `cv` object — here it's used with
`cross_val_score` on a simple synthetic regression dataset:

```python
import numpy as np
from sklearn.datasets import make_regression
from sklearn.linear_model import Ridge
from sklearn.model_selection import cross_val_score
from walkforwardsplit import WalkForwardSplit

X, y = make_regression(n_samples=200, n_features=5, noise=10, random_state=42)

cv = WalkForwardSplit(n_folds=5)
model = Ridge()

scores = cross_val_score(model, X, y, cv=cv, scoring="r2")
print("R2 per fold:", scores)
print("Mean R2:", scores.mean())
```

```
R2 per fold: [0.984 0.989 0.987 0.987 0.976]
Mean R2: 0.985
```

## How the split works

1. The first `len(X) // 2` rows form the initial training block.
2. The remaining rows are divided into `n_folds` equal-sized test blocks
   (the last fold absorbs any remainder).
3. On each iteration, the training set expands to include everything up to
   the start of the current test block; the test block never overlaps with
   training.
4. Rows beyond the current test block are excluded from both train and test
   for that fold — they belong to later folds.

If `n_folds` is too large for the dataset (each test block would be empty),
`split()` raises a `ValueError` rather than silently yielding empty folds.

## Migrating from `CustomTimeSeriesSplit`

Earlier versions exposed this class as `CustomTimeSeriesSplit`. It's still
importable as a deprecated alias of `WalkForwardSplit` with identical
behavior, but emits a `DeprecationWarning` and will be removed in a future
release:

```python
# old (still works, but warns)
from walkforwardsplit import CustomTimeSeriesSplit

# new
from walkforwardsplit import WalkForwardSplit
```

## License

MIT
