Combinatorial Purged K-Fold
Combinatorial Purged K-Fold (CPCV) (López de Prado 2018) generalises PurgedKFold by exhaustively testing all combinations of n_test_folds out of k time-ordered blocks rather than testing each block exactly once. This produces C(k, ntestfolds) train/test pairs and eliminates the path-dependency of standard walk-forward validation.
Motivation
Standard walk-forward CV (including PurgedKFold) evaluates the model on each temporal block exactly once, in a fixed order. The performance estimate is therefore a single path through the data — it depends on the specific temporal order in which the folds appear. Two practitioners using the same model and the same data can obtain different estimates simply by choosing different fold boundaries.
CPCV addresses this by averaging over all C(k, ntestfolds) possible test-set combinations. The result is a distribution of performance estimates (one per combination) rather than a single number, and the average is path-independent.
How it works
- Sort observations by
time=and assign them tokcontiguous temporal blocks. - Enumerate every combination of
n_test_foldsblocks out ofkusing the combinatorial formula C(k, ntestfolds). - For each combination:
- Test set: union of the observations in the selected blocks.
- Exclusion zone:
purgeobservations immediately before each test block andembargoobservations immediately after each test block are removed from train (same semantics asPurgedKFold). - Train set: all observations outside the test set and exclusion zone.
- Return a
CrossValidationSplitwith one fold per combination.
CPCV vs. PurgedKFold
PurgedKFold | CombinatorialPurgedKFold | |
|---|---|---|
| Number of folds | k | C(k, ntestfolds) |
| Each obs in test | Exactly once | C(k−1, ntestfolds−1) times |
| Path dependency | Yes | No |
| Provides performance distribution | No | Yes |
n_test_folds = 1 | Equivalent | — |
Setting n_test_folds = 1 recovers PurgedKFold exactly (same k folds, same purge and embargo).
Choosing k and ntestfolds
| Goal | Guidance |
|---|---|
| Eliminate path dependency, moderate cost | k=6, ntestfolds=2 → 15 folds |
| Richer performance distribution | k=8, ntestfolds=3 → 56 folds |
| Reproduce PurgedKFold | ntestfolds=1 |
| Largest test sets | ntestfolds close to k/2 |
The number of folds grows combinatorially. For k=10 and ntestfolds=4 you get C(10,4) = 210 folds — each is fast to evaluate but the total run time is proportional to the fold count.
API reference
References
López de Prado, M. Advances in Financial Machine Learning. Wiley, 2018, §12 ("Backtesting through Cross-Validation").