Validasi Silang Terstratifikasi dan Deret Waktu
Peserta akan menerapkan StratifiedKFold untuk mempertahankan rasio kelas dan TimeSeriesSplit agar data masa depan tidak bocor ke fold masa lalu pada dataset yang tersusun berdasarkan waktu.
Validasi Silang Terstratifikasi dan Deret Waktu adalah pelajaran Machine Learning Academy gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Machine Learning Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Machine Learning Academy mencakup 4 pelajaran total.
Bagian dari pelajaran ini belum diterjemahkan dan ditampilkan dalam bahasa Inggris.
When Standard K-Fold Fails
Standard KFold splits data randomly without regard for class distribution or temporal order. This creates two serious problems: (1) for imbalanced datasets, some folds may have very few or no minority class examples, making fold-to-fold variation extreme; (2) for time-ordered data, training on future examples to predict the past creates data leakage that inflates CV scores far beyond real-world performance. Specialised CV strategies solve these problems without sacrificing honest evaluation.
Stratified K-Fold: Preserving Class Ratios
StratifiedKFold ensures that each fold contains approximately the same proportion of each class as the full dataset. For example, if 10% of your data is fraudulent, each fold will have approximately 10% fraud cases. This prevents the scenario where one fold has no fraud cases, making it impossible for the classifier to learn to detect fraud in that round. Use StratifiedKFold whenever you have more than 2 classes or significant class imbalance.
from sklearn.model_selection import StratifiedKFold, cross_val_score
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_breast_cancer
import numpy as np
X, y = load_breast_cancer(return_X_y=True)
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(RandomForestClassifier(random_state=42), X, y, cv=skf)
print('Stratified 5-fold:', np.round(scores, 4))
print('Mean:', round(scores.mean(), 4), 'Std:', round(scores.std(), 4))Verifying Stratification
You can verify that StratifiedKFold maintains class ratios by inspecting the target distribution in each fold. For each test fold, the proportion of positive examples should match the overall positive rate. Comparing the class distributions from standard KFold and StratifiedKFold on an imbalanced dataset clearly shows why stratification matters — fold class ratios can differ by 20%+ without stratification.
from sklearn.model_selection import StratifiedKFold, KFold
import numpy as np
# Imbalanced data: 90% negative, 10% positive
np.random.seed(42)
y = np.array([0]*90 + [1]*10)
X = np.random.randn(100, 5)
for name, cv in [('KFold', KFold(n_splits=5, shuffle=True, random_state=42)),
('StratifiedKFold', StratifiedKFold(n_splits=5, shuffle=True, random_state=42))]:
ratios = [y[test].mean() for _, test in cv.split(X, y)]
print(f'{name} positive rates per fold:', np.round(ratios, 2))cross_val_score Uses Stratification Automatically
When you pass cv=5 (an integer) to cross_val_score for classification tasks, scikit-learn automatically uses StratifiedKFold. For regression, it uses plain KFold. This means most users get stratification for free without explicitly constructing a StratifiedKFold object. Only override this default when you need custom split behaviour (e.g., group splits, time-series splits, or a different number of folds with shuffling).
Time Series Data: The Unique Challenge
Financial, sensor, weather, and many other real-world datasets are ordered in time. A key property of time-series models: predictions must be made using only past data. If you train a model on data from April and use it to predict January values, you are training on the future — this is called temporal data leakage. Even standard K-Fold CV violates this: when fold 3 is the test set and fold 4 is in the training set, future data predicts the past. TimeSeriesSplit prevents this.
TimeSeriesSplit: Always Train on the Past
TimeSeriesSplit creates folds where training data always precedes test data chronologically. In each split, the training set expands by including the previous test fold. For example, with 5 splits: split 1 trains on the first 20% and tests on the next 20%, split 2 trains on the first 40% and tests on the next 20%, and so on. This ensures no future information enters the training set and the CV score reflects realistic temporal generalisation.
from sklearn.model_selection import TimeSeriesSplit
import numpy as np
n = 100
X = np.random.randn(n, 5)
y = np.random.randn(n)
tscv = TimeSeriesSplit(n_splits=5)
for fold, (train_idx, test_idx) in enumerate(tscv.split(X, y), 1):
print(f'Fold {fold}: train [{train_idx[0]}-{train_idx[-1]}], '
f'test [{test_idx[0]}-{test_idx[-1]}]')Using TimeSeriesSplit with cross_val_score
Pass a TimeSeriesSplit object directly to the cv parameter of cross_val_score. The resulting scores measure how well the model generalises when trained on earlier data and evaluated on later data — which is exactly the real-world use case. Note that the training sets grow in size across folds, so earlier folds have fewer training examples and may show lower scores — this is expected, not a bug.
from sklearn.model_selection import TimeSeriesSplit, cross_val_score
from sklearn.ensemble import GradientBoostingRegressor
import numpy as np
# Simulated time-series: price = trend + noise
np.random.seed(42)
n = 200
X = np.arange(n).reshape(-1, 1) + np.random.randn(n, 1) * 5
y = 0.5 * np.arange(n) + np.random.randn(n) * 10
tscv = TimeSeriesSplit(n_splits=5)
scores = cross_val_score(GradientBoostingRegressor(n_estimators=50, random_state=42),
X, y, cv=tscv, scoring='r2')
print('TimeSeriesSplit R² scores:', np.round(scores, 4))
print('Mean R²:', round(scores.mean(), 4))GroupKFold: Preventing Sample Leakage
Some datasets have multiple samples per entity — multiple ECGs per patient, multiple transactions per user, multiple images per scene. If the same patient appears in both training and test folds, the model learns patient-specific patterns rather than general patterns. GroupKFold ensures all samples from the same group (patient, user, scene) are in the same fold, preventing this within-group leakage. Pass group identifiers to the groups parameter of cross_val_score.
from sklearn.model_selection import GroupKFold, cross_val_score
from sklearn.linear_model import LogisticRegression
import numpy as np
np.random.seed(42)
n = 100
X = np.random.randn(n, 5)
y = np.random.randint(0, 2, n)
groups = np.repeat(np.arange(10), 10) # 10 patients, 10 samples each
gkf = GroupKFold(n_splits=5)
scores = cross_val_score(LogisticRegression(max_iter=1000), X, y, cv=gkf, groups=groups)
print('GroupKFold scores:', np.round(scores, 4))
print('Mean:', round(scores.mean(), 4))Expanding Window vs Sliding Window for Time Series
TimeSeriesSplit uses an expanding window: the training set grows with each split. An alternative is a sliding window: use only the most recent N days/months for training, discarding older data. Sliding windows are better when the relationship between features and target changes over time (concept drift) and older data is no longer representative. scikit-learn does not provide a sliding window CV out of the box, but you can implement it using a custom CV generator or TimeSeriesSplit with max_train_size.
from sklearn.model_selection import TimeSeriesSplit
import numpy as np
# Sliding window: fix the training size
tscv = TimeSeriesSplit(n_splits=4, max_train_size=50) # max 50 training samples
X = np.random.randn(200, 3)
for fold, (train_idx, test_idx) in enumerate(tscv.split(X), 1):
print(f'Fold {fold}: train size={len(train_idx)}, '
f'test [{test_idx[0]}-{test_idx[-1]}]')Choosing the Right CV Strategy
A simple decision guide: (1) Classification with balanced classes → standard KFold or cross_val_score integer (auto-stratified); (2) Classification with imbalance → StratifiedKFold explicitly; (3) Time-ordered data → TimeSeriesSplit; (4) Multiple samples per entity → GroupKFold; (5) Imbalanced + grouped → StratifiedGroupKFold (scikit-learn 0.24+). Getting the CV strategy wrong can make a poorly generalising model look great or a good model look mediocre — always match the CV method to your real-world deployment scenario.
Walk-Forward Validation for Production
In real production time-series systems, models are retrained periodically and evaluated on the subsequent period. Walk-forward validation simulates this: train on months 1-6, evaluate on month 7; train on months 1-7, evaluate on month 8; and so on. This is equivalent to TimeSeriesSplit with gap parameter to add a buffer between train end and test start (to avoid leakage from closely adjacent time points). The resulting score sequence also reveals whether model performance is stable over time or degrading.
from sklearn.model_selection import TimeSeriesSplit
import numpy as np
# Simulate 24 months of data
n_months = 24
np.random.seed(42)
X = np.random.randn(n_months, 5)
y = np.random.randn(n_months)
# Walk-forward: 12 train periods, 1 test each
tscv = TimeSeriesSplit(n_splits=12, test_size=1)
for fold, (tr, te) in enumerate(tscv.split(X), 1):
if fold <= 3 or fold == 12:
print(f'Fold {fold:2d}: train months 1-{len(tr)}, test month {te[0]+1}')Quick Check
Test your understanding of Stratified and Time-Series cross-validation from this lesson.
Lesson Recap
In this lesson you learned: StratifiedKFold preserves class proportions across folds for imbalanced classification, TimeSeriesSplit prevents temporal leakage by always training on past data, and GroupKFold prevents within-group leakage when multiple samples belong to the same entity. Next up we compare Grid Search and Random Search for hyperparameter optimisation.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Validasi Silang Terstratifikasi dan Deret Waktu” gratis?
Ya — teks lengkap “Validasi Silang Terstratifikasi dan Deret Waktu” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Machine Learning Academy, upgrade ke CoddyKit PRO. Kursus Machine Learning Academy mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Validasi Silang Terstratifikasi dan Deret Waktu”?
Peserta akan menerapkan StratifiedKFold untuk mempertahankan rasio kelas dan TimeSeriesSplit agar data masa depan tidak bocor ke fold masa lalu pada dataset yang tersusun berdasarkan waktu. Kamu berlatih Machine Learning Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai Machine Learning Academy?
Tidak diperlukan pengalaman sebelumnya. Machine Learning Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.
Berapa lama pelajaran “Validasi Silang Terstratifikasi dan Deret Waktu” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran Machine Learning Academy ini?
Ya. Setiap pelajaran Machine Learning Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Validasi Silang K-Fold: Membagi Data Tanpa Kebocoran
- Validasi Silang Terstratifikasi dan Deret Waktu
- Pencarian Grid vs Pencarian Acak
- Validasi Silang Bertingkat: Memilih dan Mengevaluasi Secara Bersamaan