Mengukur performa model pada data yang dipakai melatihnya sama seperti menguji siswa dengan soal yang persis sama dengan latihan semalam — skornya tinggi, tetapi tidak membuktikan apa pun tentang kemampuan menghadapi soal baru. Karena tujuan model adalah memprediksi data baru, penilaiannya harus memakai data yang belum pernah dilihat model. Pada chapter ini kita bahas alasan pemisahan dataset, cara memakai train_test_split dengan tiga parameter kuncinya, dan proporsi pembagian yang lazim beserta peran khusus data validasi.
Mengapa Data Harus Dibagi #
Model punya dua tugas yang saling bertentangan: menghafal data latih sebaik mungkin, dan menangkap pola umum yang berlaku untuk data mana pun. Semakin fleksibel modelnya, semakin mudah ia menghafal — termasuk detail khusus yang tidak berlaku di luar data latih. Satu-satunya cara jujur membedakan “paham pola” dari “hafalan” adalah mengujinya pada data yang tidak ikut dilatih.
Dari sinilah dua subset lahir: data latih (training set) untuk melatih model, dan data uji (test set) untuk menilainya. Data uji berperan sebagai perwakilan masa depan: email yang belum masuk, member yang baru mendaftar. Prinsip kerjanya satu kalimat: data uji disimpan layaknya amplop tersegel — dibuka sekali, di akhir, untuk pengukuran final.
train_test_split dan Tiga Parameter Kuncinya #
Fungsi train_test_split dari scikit-learn membelah tabel secara acak namun terkendali. Kita pakai data 20 member Toko Kopi Kita dengan dua fitur perilaku dan label churn (5 member berhenti, 15 bertahan):
import pandas as pd
from sklearn.model_selection import train_test_split
member = pd.DataFrame({
"frekuensi_belanja": [2, 1, 7, 3, 6, 3, 8, 5, 2, 6, 4, 1, 7, 5, 8, 4, 6, 5, 7, 6],
"lama_member_bulan": [3, 2, 24, 5, 20, 6, 30, 15, 4, 26, 12, 3, 22, 16, 28, 10, 18, 14, 19, 13],
"churn": [1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
})
X = member[["frekuensi_belanja", "lama_member_bulan"]]
y = member["churn"]
print("Semua data: %d baris, %d churn (%.0f%%)" % (len(y), y.sum(), 100 * y.mean()))
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, random_state=42
)
print("Tanpa stratify : train churn %d/%d, test churn %d/%d"
% (y_train.sum(), len(y_train), y_test.sum(), len(y_test)))
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, random_state=42, stratify=y
)
print("Dengan stratify : train churn %d/%d, test churn %d/%d"
% (y_train.sum(), len(y_train), y_test.sum(), len(y_test)))
X2_train, X2_test, y2_train, y2_test = train_test_split(
X, y, test_size=0.25, random_state=42, stratify=y
)
print("Pembagian ulang identik:", list(y_test.index) == list(y2_test.index))Output yang Dihasilkan:
Semua data: 20 baris, 5 churn (25%)
Tanpa stratify : train churn 2/15, test churn 3/5
Dengan stratify : train churn 4/15, test churn 1/5
Pembagian ulang identik: TrueMari kita telaah baris-baris kode di atas:
test_size=0.25memesan 25% data (5 dari 20 baris) sebagai data uji; sisanya 15 baris melatih model. Angkanya bisa pecahan maupun jumlah baris utuh.random_state=42membekukan sisi acak pembagian. Tanpa parameter ini, setiap eksekusi menghasilkan pembagian berbeda — hasil eksperimen jadi tidak bisa direproduksi. Angka 42 sendiri tidak istimewa; yang penting konsisten dalam satu proyek.stratify=ymeminta komposisi kelas di kedua subset meniru data aslinya.- Empat keluaran
X_train, X_test, y_train, y_testselalu berpasangan: fitur dan target dari baris yang sama ditempatkan di subset yang sama.
Keluarannya memperlihatkan mengapa stratify penting pada data kecil yang timpang. Tanpa stratify, keberuntungan acak menempatkan 3 dari 5 baris data uji sebagai churn (60%) — padahal keseluruhan data hanya berisi 25% churn. Model dilatih pada 2 churn saja dan diuji pada komposisi yang menyimpang jauh; hasilnya tidak mewakili kenyataan. Dengan stratify, data uji memuat 1 churn dari 5 (20%, terdekat ke proporsi asli) dan data latih tetap menyimpan 4 churn. Baris terakhir membuktikan reproduksibilitas: dua pemanggilan dengan random_state yang sama menghasilkan pembagian identik.
Proporsi yang Umum Dipakai #
Tidak ada angka baku yang wajib diikuti, tetapi ada patokan praktis. Kombinasi paling populer adalah 80/20 — mayoritas untuk melatih, sebagian kecil untuk menguji. Data yang kecil (ribuan baris ke bawah) sering memakai 70/30 supaya data uji cukup banyak barisnya; data yang besar ratusan ribu baris bisa memakai 90/10 atau 95/5 karena 5% saja sudah beribu-ribu sampel uji. Sisanya, stratify nyaris selalu layak dipakai untuk masalah klasifikasi.
| Subset | Peran | Kapan disentuh |
|---|---|---|
| Data latih (train) | Melatih model, menyetel pola | Sesering mungkin selama eksperimen |
| Data validasi (validation) | Memilih model dan menyetel hyperparameter | Saat membandingkan kandidat |
| Data uji (test) | Pengukuran final, simulasi data baru | Sekali saja, di akhir |
Pembagian dua subset yang kita kerjakan sekarang menyatukan peran validasi dan uji. Saat eksperimen membandingkan banyak model, ketiganya perlu dipisah — atau memakai cross-validation yang memutar peran data latih dan validasi secara bergilir; pembahasannya kita simpan untuk Section Evaluasi dan Validasi Model .
Rangkuman #
- Model wajib diuji pada data yang tidak ikut dilatih; data uji adalah perwakilan data baru yang menjadi tujuan sesungguhnya.
train_test_splitmembagi data dengan tiga parameter kunci:test_size(porsi data uji),random_state(reproduksibilitas), danstratify(komposisi kelas terjaga).- Demo 20 member memperlihatkan pembagian acak bisa menghasilkan data uji berisi 60% churn padahal data aslinya 25%;
stratifymembetulkannya. - Proporsi umum 80/20 (atau 70/30 untuk data kecil); peran train, validation, dan test berbeda dan tidak boleh tertukar.
- Data uji dibuka sekali untuk pengukuran final — pemakaian berulang adalah kebocoran yang menggelembungkan skor.
Dengan data yang terbagi rapi, pertanyaan berikutnya alami muncul: seberapa bagus sebenarnya model kita — dan dibandingkan dengan apa? Jawabannya dimulai dari model paling sederhana yang bisa dibangun, pokok bahasan chapter Baseline Model .