Cross Validation: Memvalidasi Model Saat Datamu Sedikit
TL;DR
Cross validation adalah cara evaluasi model dengan membagi data jadi beberapa lipatan (fold), lalu melatih dan menguji model bergiliran sampai semua bagian pernah jadi data uji. Hasilnya rata-rata skor dari semua fold plus simpangan bakunya, jadi kamu tahu seberapa stabil model itu. Teknik ini paling berguna waktu datamu di bawah beberapa ribu baris dan satu kali train test split terlalu goyang.
Cross validation adalah cara ngukur performa model dengan membagi data jadi beberapa lipatan, lalu melatih dan menguji model bergiliran sampai tiap bagian pernah kebagian jadi data uji.
Hasilnya bukan satu angka, tapi kumpulan skor. Dari situ kamu dapat rata-rata plus ukuran seberapa goyang model kamu.
Ini yang bikin cross validation jadi penyelamat waktu datamu cuma ratusan baris. Satu kali train test split di data kecil gampang ngasih angka yang kebetulan bagus atau kebetulan jelek.
Apa itu cross validation?
Cross validation adalah teknik evaluasi model yang membagi dataset jadi k lipatan berukuran sama. Model dilatih pakai k dikurangi satu lipatan, lalu diuji di lipatan yang tersisa. Proses ini diulang k kali dengan lipatan uji yang berbeda, dan skor akhirnya rata-rata dari semua putaran.
Bentuk paling umum namanya k-fold cross validation. Kalau k sama dengan 5, artinya ada 5 putaran latih dan uji.
Tiap baris data kebagian jadi data uji tepat sekali, dan jadi data latih sebanyak k dikurangi satu kali. Nggak ada baris yang nganggur.
Fold 1: [UJI ][latih][latih][latih][latih]
Fold 2: [latih][UJI ][latih][latih][latih]
Fold 3: [latih][latih][UJI ][latih][latih]
Fold 4: [latih][latih][latih][UJI ][latih]
Fold 5: [latih][latih][latih][latih][UJI ]
Penjelasan lengkap tiap variannya ada di dokumentasi cross validation scikit-learn.
Kapan cross validation lebih tepat daripada train test split?
Pakai cross validation kalau datamu di bawah beberapa ribu baris, kalau kamu mau bandingin beberapa model, atau kalau kamu lagi nyari setelan hyperparameter terbaik. Split tunggal cukup kalau datamu ratusan ribu baris dan kamu butuh evaluasi cepat.
| Situasi | Pilihan | Alasan |
|---|---|---|
| Data di bawah 2.000 baris | Cross validation | Split tunggal terlalu goyang |
| Data di atas 100.000 baris | Split tunggal | Data uji udah cukup besar buat stabil |
| Bandingin 4 algoritma | Cross validation | Perbandingannya adil di data yang sama |
| Nyetel hyperparameter | Cross validation | Nggak perlu ngorbanin data buat validation set |
| Model butuh 3 jam latih | Split tunggal | 5 fold artinya 15 jam |
Gimana cara pakai cross validation di scikit-learn?
Panggil cross_val_score dengan model, fitur, target, dan jumlah fold. Fungsi ini ngurus pembagian, pelatihan, dan penilaian sekaligus, lalu balikin array berisi skor tiap fold. Rata-rata dan simpangan bakunya kamu hitung sendiri dari array itu.
- Siapkan
Xberisi kolom fitur danyberisi target. - Impor model yang mau kamu uji dan fungsi
cross_val_score. - Panggil fungsinya dengan
cv=5dan metrik yang kamu mau lewatscoring. - Baca rata-rata skornya lewat
.mean()dan sebaran skornya lewat.std(). - Kalau simpangan bakunya besar, cek dulu penyebabnya sebelum ambil kesimpulan.
import numpy as np
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier(max_depth=6, random_state=42)
skor = cross_val_score(model, X, y, cv=5, scoring="f1")
print("skor per fold:", np.round(skor, 3))
print("rata-rata :", round(skor.mean(), 3))
print("simpangan :", round(skor.std(), 3))
Buat model klasifikasi, cv=5 otomatis dipetakan ke StratifiedKFold di scikit-learn. Jadi proporsi kelasmu udah terjaga tanpa perlu diatur manual.
Kalau kamu butuh beberapa metrik sekaligus, ganti ke cross_validate.
from sklearn.model_selection import cross_validate
hasil = cross_validate(
model, X, y, cv=5,
scoring=["accuracy", "precision", "recall"],
return_train_score=True
)
print(hasil["test_recall"].mean())
print(hasil["train_accuracy"].mean())
Selisih besar antara train_accuracy dan test_accuracy tanda model kebanyakan hafalan. Gejalanya aku bahas di artikel overfitting dan underfitting.
Apa bedanya KFold, StratifiedKFold, dan TimeSeriesSplit?
KFold bagi data jadi potongan berurutan tanpa mikirin isi targetnya. StratifiedKFold jaga proporsi kelas tetap sama di tiap lipatan, cocok buat target yang timpang. TimeSeriesSplit selalu naruh data latih di periode sebelum data uji, jadi model nggak pernah belajar dari masa depan.
| Pembagi | Cocok buat | Catatan penting |
|---|---|---|
| KFold | Regresi, target seimbang | Setel shuffle=True kalau data terurut |
| StratifiedKFold | Klasifikasi, target timpang | Default buat classifier waktu cv diisi angka |
| TimeSeriesSplit | Data transaksi harian | Ukuran data latih nambah tiap fold |
| GroupKFold | Satu pelanggan banyak baris | Nyegah pelanggan sama muncul di dua sisi |
| LeaveOneOut | Data di bawah 200 baris | Jumlah fold sama dengan jumlah baris |
from sklearn.model_selection import TimeSeriesSplit
tscv = TimeSeriesSplit(n_splits=5)
skor = cross_val_score(model, X, y, cv=tscv, scoring="neg_mean_absolute_error")
Perhatikan satu hal di KFold. Nilai bawaan shuffle adalah False, jadi kalau datamu terurut menurut kelas atau tanggal, hasilnya bisa aneh. Setel shuffle=True dan isi random_state biar bisa diulang.
Gimana cara mencegah kebocoran data lewat Pipeline?
Bungkus semua langkah pemrosesan dan model dalam satu Pipeline, lalu kirim Pipeline itu ke cross_val_score. Dengan begitu scaler dan imputer dilatih ulang di tiap fold pakai data latih fold itu doang, jadi informasi dari data uji nggak pernah bocor ke tahap persiapan.
Ini kesalahan paling sering di cross validation. Orang nge-scale seluruh dataset dulu, baru manggil cross_val_score.
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.impute import SimpleImputer
from sklearn.linear_model import LogisticRegression
pipe = Pipeline([
("isi_kosong", SimpleImputer(strategy="median")),
("skala", StandardScaler()),
("model", LogisticRegression(max_iter=1000)),
])
skor = cross_val_score(pipe, X, y, cv=5, scoring="roc_auc")
print(round(skor.mean(), 3))
Perbedaannya nyata. Di dataset ngulikdata, versi tanpa Pipeline ngasih AUC 0,871 sementara versi Pipeline ngasih 0,842. Selisih 0,029 itu murni kebocoran, bukan kemampuan model.
Konsep ini bagian dari data quality yang efeknya baru kelihatan pas model masuk produksi.
Contoh kasus: prediksi keterlambatan pengiriman UMKM
Dataset latihan ngulikdata punya tabel pengiriman dari 4 UMKM binaan, isinya 312 baris. Targetnya satu kolom: paket sampai telat atau nggak. Fiturnya jarak kirim, berat paket, jam pesanan masuk, dan kurir yang dipakai.
Sebanyak 312 baris itu masuk kategori kecil. Bagusnya, ini contoh sempurna buat lihat kenapa split tunggal bikin salah kaprah.
Aku jalanin train test split biasa dengan lima nilai random_state berbeda. Akurasinya: 0,79, 0,71, 0,84, 0,68, dan 0,76.
Rentang 16 poin. Kalau aku kebetulan pakai random_state=2 dan lapor 0,84 ke tim operasional, angka itu terlalu optimistis 8 poin dari kenyataan.
from sklearn.model_selection import StratifiedKFold
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
skor = cross_val_score(pipe, X, y, cv=skf, scoring="accuracy")
print(np.round(skor, 3))
print(f"{skor.mean():.3f} +/- {skor.std():.3f}")
Hasil cross validation di dataset ngulikdata: 0,744 dengan simpangan 0,061.
Angka 0,744 ini yang aku laporin. Yang lebih berguna lagi, simpangan 0,061 ngasih tahu tim bahwa prediksi model masih goyang dan belum layak jadi dasar keputusan otomatis.
Tim akhirnya milih pakai model buat nyortir prioritas cek manual, bukan buat kirim notifikasi telat ke pelanggan. Keputusan itu lahir dari simpangan baku, bukan dari rata-rata.
Kesalahan umum saat pakai cross validation
- Scaling di luar Pipeline. Skornya kelihatan lebih bagus, tapi angkanya bohong.
- Cuma lapor rata-rata. Rata-rata 0,80 dengan simpangan 0,02 dan rata-rata 0,80 dengan simpangan 0,12 itu dua model yang beda banget.
- Pakai KFold buat data time series. Model belajar dari transaksi bulan depan lalu diuji ke bulan lalu.
- Lupa GroupKFold di data multi baris per pelanggan. Satu pelanggan bisa nongol di data latih dan data uji sekaligus.
- Nyetel model berdasarkan skor cross validation berkali-kali. Setelah puluhan percobaan, angkanya jadi terlalu optimistis. Sisakan satu test set yang belum pernah kamu sentuh.
- Pakai accuracy buat target timpang. Kalau cuma 8 persen kasus positif, model yang selalu jawab negatif dapat 92 persen. Ganti ke F1 atau ROC AUC.
Ringkasan dan langkah berikutnya
Cross validation ngasih dua angka yang saling melengkapi: rata-rata performa dan seberapa goyang performa itu. Angka kedua sering lebih menentukan keputusan bisnis daripada angka pertama.
Urutan kerjanya: bungkus semua langkah dalam Pipeline, pilih pembagi yang cocok sama bentuk datamu, lalu baca rata-rata bareng simpangan bakunya.
Kalau kamu belum kenal dasar pembagiannya, mulai dari train test split. Kalau skormu masih jelek di semua fold, kemungkinan masalahnya ada di kolom fitur, dan jawabannya ada di feature engineering.
Mau praktek langsung? Mulai latihan SQL gratis
Latihan interaktif, langsung di browser.
Artikel terkait
Pandas groupby: Agregasi Data ala Pivot di Python (2026)
groupby ngelompokin baris berdasarkan kolom, lalu ngitung ringkasan per grup kayak total atau rata-rata. Ini pivot-nya pandas.
Pandas to_excel: Ekspor DataFrame ke Excel (2026)
to_excel nyimpen DataFrame pandas jadi file Excel .xlsx. Ini cara pakainya, dari satu sheet sampai banyak sheet, plus setelan yang bikin hasilnya rapi.
Pandas read_excel: Baca File Excel di Python
pandas read_excel baca file Excel jadi DataFrame, bisa pilih sheet tertentu dan lompatin baris judul yang berantakan. Ini cara pakai plus parameter penting dengan contoh data toko.