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.
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.
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 |
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.
X berisi kolom fitur dan y berisi target.cross_val_score.cv=5 dan metrik yang kamu mau lewat scoring..mean() dan sebaran skornya lewat .std().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.
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.
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.
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.
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.
Kolom datetime nyimpen tanggal, jam, hari, semuanya nempel jadi satu. Accessor .dt di pandas ngeluarin tiap bagian jadi kolom sendiri buat dianalisa.
Nama toko ketik campur huruf besar-kecil, spasi nyasar di ujung, atau kode produk nempel jadi satu. Accessor .str di pandas ngerapiin semua itu tanpa loop.
Model machine learning cuma ngerti angka, bukan teks kayak merah atau biru. get_dummies ngubah kolom kategori jadi kolom 0/1 dalam satu baris kode.