Train/test split

Memecah data dengan train_test_split, stratify, dan disiplin random_state.

Daftar isi

Topik ini membahas pemecahan data menjadi data latih dan data uji dengan fungsi train_test_split. Pembahasan mencakup alasan data uji tidak boleh digunakan saat pelatihan, pengaturan test_size dan random_state, penjagaan proporsi kelas melalui argumen stratify, serta disiplin menetapkan random_state agar hasil eksperimen dapat direproduksi. Pemecahan yang benar menjadi fondasi bagi setiap pengukuran kinerja model.

Mengapa evaluasi menuntut data yang belum terlihat#

Ukuran kinerja model yang sebenarnya dibutuhkan adalah generalisasi, yakni kemampuan model memberi prediksi benar pada data baru yang tidak ikut digunakan saat pelatihan. Model yang dinilai pada data latihnya sendiri menghasilkan skor terlalu optimistis karena jawaban setiap sampel sudah ikut menentukan pembelajarannya. Skor semacam itu tidak menjawab hal yang ditanyakan, yaitu bagaimana kinerja model ketika bertemu data yang belum pernah dilihatnya.

Data yang belum terlihat ini disimulasikan dengan menyimpan sebagian data secara terpisah sebelum pelatihan dimulai. Bagian yang besar digunakan sebagai data latih dan bagian yang kecil disimpan sebagai data uji, lalu data uji baru dipakai pada saat pengukuran. Disiplin sederhana ini memastikan pengukuran menggunakan sampel yang tidak berperan dalam pembelajaran, dan seluruh kejujuran evaluasi model bergantung pada pemisahan tersebut. Bagian yang tadinya disimpan sebagai data uji dapat kembali digunakan untuk melatih model final setelah pengukuran selesai, tetapi urutan tahapannya tetap tidak boleh dibalik. Skor tinggi pada data latih memberi rasa aman yang keliru karena angkanya tidak menyatakan apa pun tentang data baru.

Pemecahan dasar dengan train_test_split#

Fungsi train_test_split memecah baris data menjadi dua bagian secara acak. Argumen test_size menetapkan porsi data uji, baik sebagai proporsi seperti 0.2 maupun sebagai jumlah baris seperti 30. Pemecahannya diacak secara default sehingga kedua bagian berasal dari seluruh rentang data dan bukan sekadar potongan awal atau akhir tabel. Fungsi ini mengembalikan empat keluaran dengan urutan tetap, yaitu X data latih, X data uji, y data latih, dan y data uji.

Fungsi ini menerima array maupun daftar Python dengan jumlah baris yang sama, dan pemecahannya dilakukan berpasangan sehingga X dan y tetap sejajar baris demi baris. Keselarasan ini penting karena label yang bergeser satu posisi saja merusak seluruh pelatihan tanpa memunculkan error apa pun. Argumen train_size juga tersedia bila porsi data latih ingin ditetapkan secara eksplisit.

Kode berikut memecah data iris dengan porsi uji 20 persen.

python pemisahan-dasar.py
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
import numpy as np

X, y = load_iris(return_X_y=True)

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

print("Bentuk X_train:", X_train.shape)
print("Bentuk X_test:", X_test.shape)
print("Jumlah data latih per kelas:", np.bincount(y_train))
print("Jumlah data uji per kelas:", np.bincount(y_test))
text Keluaran
Bentuk X_train: (120, 4)
Bentuk X_test: (30, 4)
Jumlah data latih per kelas: [40 40 40]
Jumlah data uji per kelas: [10 10 10]

Keluaran menunjukkan 120 baris data latih dan 30 baris data uji, sesuai porsi 80 banding 20 dari 150 baris. Jumlah per kelas terbaca lewat np.bincount, yaitu 40 baris per kelas pada data latih dan 10 baris per kelas pada data uji. Keseimbangan per kelas ini bukan kebetulan, melainkan efek argumen stratify=y.

Pilihan porsi data uji merupakan pertukaran yang nyata. Porsi yang terlalu kecil membuat pengukuran mudah goyah karena sedikit prediksi salah langsung menggeser skornya, sedangkan porsi yang terlalu besar mengurangi bahan belajar model. Porsi antara 20 dan 30 persen menjadi pilihan lazim untuk data berukuran kecil hingga menengah.

Menjaga proporsi kelas dengan stratify#

Argumen stratify=y menjaga proporsi setiap kelas pada data latih dan data uji agar mendekati proporsi data penuh. Tanpa stratifikasi, pemecahan acak pada data yang tidak seimbang dapat menggeser porsi kelas minoritas secara berarti. Geseran ini berdampak langsung pada pengukuran karena data uji yang berbeda komposisinya menghasilkan penilaian yang berbeda pula.

Kode berikut menggunakan data sintetis 600 baris dengan kelas minoritas sekitar 5 persen, lalu membandingkan jumlah kelas minoritas pada kedua cara pemecahan.

python Contoh: perbandingan pemecahan dengan dan tanpa stratify
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
import numpy as np

X, y = make_classification(
    n_samples=600, n_features=4, n_informative=2, n_redundant=0,
    weights=[0.95, 0.05], random_state=42
)

X_latih_t, X_uji_t, y_latih_t, y_uji_t = train_test_split(
    X, y, test_size=0.2, random_state=42
)
X_latih_s, X_uji_s, y_latih_s, y_uji_s = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

print("Total kelas minoritas di seluruh data:", int(np.bincount(y)[1]))
print("Tanpa stratify, kelas minoritas di latih:", int(np.bincount(y_latih_t)[1]),
      "dan di uji:", int(np.bincount(y_uji_t)[1]))
print("Dengan stratify, kelas minoritas di latih:", int(np.bincount(y_latih_s)[1]),
      "dan di uji:", int(np.bincount(y_uji_s)[1]))
text Keluaran
Total kelas minoritas di seluruh data: 34
Tanpa stratify, kelas minoritas di latih: 25 dan di uji: 9
Dengan stratify, kelas minoritas di latih: 27 dan di uji: 7

Data penuh memuat 34 baris kelas minoritas, sehingga pemecahan 80 banding 20 idealnya menyisakan sekitar 27.2 baris untuk data latih dan 6.8 baris untuk data uji. Dengan stratify=y, pembagiannya jatuh pada 27 baris data latih dan 7 baris data uji, sesuai pembulatan yang mungkin. Tanpa stratifikasi, hasilnya 25 baris pada data latih dan 9 baris pada data uji, yang berarti data uji kelebihan kelas minoritas hampir 30 persen secara relatif.

Pada data yang seimbang, efek stratifikasi nyaris tidak terlihat, tetapi pemakaiannya tetap aman dan menjadi kebiasaan yang baik untuk masalah klasifikasi. Biayanya hanya satu argumen tambahan, sedangkan manfaatnya adalah data uji yang komposisinya dapat dipercaya pada berbagai ukuran data.

Reproduksibilitas melalui random_state#

Pemecahan acak menghasilkan susunan baris yang berbeda pada setiap kali dijalankan, dan perbedaan ini membuat perbandingan antareksperimen menjadi tidak adil. Argumen random_state menetapkan benih acak (seed), yaitu titik awal deret angka acak, sehingga pemecahan dengan nilai yang sama menghasilkan pembagian yang identik. Nilai 42 digunakan secara konsisten pada contoh-contoh di jalur ini agar setiap keluaran dapat direproduksi.

Kode berikut menjalankan tiga pemisahan, dua di antaranya dengan benih yang sama.

python Contoh: pemisahan dengan random_state yang sama dan berbeda
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
import numpy as np

X, y = load_iris(return_X_y=True)

indeks = np.arange(len(X))

a_latih, _ = train_test_split(indeks, test_size=0.5, random_state=42)
b_latih, _ = train_test_split(indeks, test_size=0.5, random_state=42)
c_latih, _ = train_test_split(indeks, test_size=0.5, random_state=7)

print("Pemisahan 1 dan 2 identik:", np.array_equal(a_latih, b_latih))
print("Pemisahan 1 dan 3 identik:", np.array_equal(a_latih, c_latih))
text Keluaran
Pemisahan 1 dan 2 identik: True
Pemisahan 1 dan 3 identik: False

Keluaran menegaskan perilakunya. Dua pemisahan dengan random_state=42 menghasilkan susunan baris yang identik, sedangkan pemisahan dengan nilai 7 menghasilkan susunan yang berbeda. Karena itu, perbandingan dua model hanya bermakna bila keduanya dinilai pada pemecahan yang sama. Perlu dicatat pula bahwa random_state pada pemecahan data dan random_state pada model bersifat terpisah, sehingga keduanya perlu dicatat masing-masing.

Ringkasan#

  • train_test_split memecah data menjadi data latih dan data uji secara acak dan mengembalikan empat array dengan urutan tetap.
  • Pengukuran kinerja dilakukan pada data uji karena model yang dinilai pada data latihnya menghasilkan skor terlalu optimistis.
  • stratify=y menjaga proporsi kelas agar mendekati data penuh dan terutama penting pada data tidak seimbang.
  • random_state membuat pemecahan dapat direproduksi sehingga perbandingan antarmodel menjadi adil.

Referensi#