Setiap transformer pada scikit-learn mengikuti satu disiplin yang sama, yaitu statistik transformasi dipelajari hanya dari data latih, kemudian diterapkan ke data latih dan data uji. Melanggar aturan itu berarti membawa informasi data uji ke dalam proses pelatihan, praktik yang dikenal sebagai kebocoran data (data leakage). Topik ini menetapkan pola kanonik bagi semua transformer dan mengukur akibat pelanggarannya dengan angka.
Pola kanonik untuk semua transformer#
Aturannya terdiri atas tiga baris kerja yang berlaku untuk scaler, encoder, imputer, maupun transformer lainnya. Pertama, fit dipanggil hanya pada data latih. Kedua, transform dipanggil pada data latih untuk menghasilkan data latih tertransformasi. Ketiga, transform yang sama dipanggil pada data uji, tanpa fit ulang maupun fit_transform. Contoh berikut menampilkan pola tersebut pada StandardScaler dengan dua matriks kecil.
import numpy as np
from sklearn.preprocessing import StandardScaler
X_train = np.array([[1.0, 1000.0], [2.0, 1200.0], [3.0, 1400.0]])
X_test = np.array([[1.5, 1100.0]])
scaler = StandardScaler()
scaler.fit(X_train)
X_train_t = scaler.transform(X_train)
X_test_t = scaler.transform(X_test)
print("Rata-rata tiap fitur dari data latih:", np.round(scaler.mean_, 2))
print("Baris pertama X_train tertransformasi:", np.round(X_train_t[0], 3))
print("Baris pertama X_test tertransformasi :", np.round(X_test_t[0], 3))Rata-rata tiap fitur dari data latih: [ 2. 1200.]
Baris pertama X_train tertransformasi: [-1.225 -1.225]
Baris pertama X_test tertransformasi : [-0.612 -0.612]Rata-rata yang tersimpan adalah rata-rata data latih, bukan rata-rata gabungan, dan itulah satu-satunya statistik yang digunakan untuk mentransformasi kedua himpunan. Pola ini melindungi evaluasi karena data uji diperlakukan sebagaimana data yang baru datang nanti, yaitu diolah dengan parameter yang dipelajari sebelum data uji itu dilihat. Transformer yang dilatih pada seluruh data adalah salah satu jalur masuk kebocoran data yang dibahas pada topik Kebocoran Data.
Metode fit_transform menimbulkan keraguan tersendiri. Metode itu setara dengan memanggil fit kemudian transform, sehingga aman digunakan pada data latih dan menjadi bentuk yang paling umum. Pada data uji, fit_transform justru melanggar aturan karena menyesuaikan ulang statistiknya terhadap data uji, sehingga hanya transform yang boleh dipanggil di sana. Keringkasan penulisan tidak boleh digunakan sebagai alasan melanggar aturan.
Pola ini juga menetapkan urutan pekerjaan. Pemecahan data dilakukan lebih dahulu, kemudian semua transformer baru dilatih pada hasil pemecahan itu. Dengan urutan demikian, keputusan apa pun tentang data uji tidak pernah menyusup ke parameter transformasi, dan skor evaluasi mengukur kemampuan menghadapi data yang benar-benar baru.
Demonstrasi dua jalur#
Akibat pelanggaran aturan dapat diukur pada data sintetis dengan skala fitur yang dibuat timpang. make_classification menghasilkan 200 sampel, kemudian dua kolom pertamanya dikalikan faktor besar sehingga skalanya timpang seperti data nyata. Dua jalur dijalankan pada pemecahan data yang sama, yaitu jalur bocor dengan scaler yang mempelajari statistik seluruh data dan jalur benar dengan scaler yang hanya melihat data latih.
import numpy as np
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
X, y = make_classification(
n_samples=200, n_features=8, n_informative=5,
weights=[0.8, 0.2], random_state=42,
)
X[:, 0] *= 500
X[:, 1] *= 80
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, stratify=y, random_state=42
)
# jalur bocor: scaler mempelajari statistik dari seluruh data, termasuk data uji
scaler_bocor = StandardScaler().fit(X)
knn_bocor = KNeighborsClassifier(n_neighbors=3).fit(scaler_bocor.transform(X_train), y_train)
skor_bocor = knn_bocor.score(scaler_bocor.transform(X_test), y_test)
# jalur benar: scaler mempelajari statistik dari data latih saja
scaler_benar = StandardScaler().fit(X_train)
knn_benar = KNeighborsClassifier(n_neighbors=3).fit(scaler_benar.transform(X_train), y_train)
skor_benar = knn_benar.score(scaler_benar.transform(X_test), y_test)
print("Rata-rata fitur kolom 0 dari seluruh data :", round(scaler_bocor.mean_[0], 2))
print("Rata-rata fitur kolom 0 dari data latih :", round(scaler_benar.mean_[0], 2))
print("Akurasi KNN pada jalur bocor:", round(skor_bocor, 3))
print("Akurasi KNN pada jalur benar:", round(skor_benar, 3))Rata-rata fitur kolom 0 dari seluruh data : -442.96
Rata-rata fitur kolom 0 dari data latih : -376.18
Akurasi KNN pada jalur bocor: 0.92
Akurasi KNN pada jalur benar: 0.88Dua keluaran pertama membuktikan bahwa statistiknya benar-benar berbeda, yaitu -442,96 untuk seluruh data dan -376,18 untuk data latih, sehingga transformasi kedua jalur tidak identik. Akurasinya pun berbeda dengan selisih 0,04, dan jalur bocor menghasilkan angka yang lebih tinggi. Angka yang lebih tinggi dari prosedur yang lebih salah merupakan ciri kebocoran data yang menjebak.
Keadaan menjadi lebih rumit saat evaluasi menggunakan cross-validation, yaitu pengukuran berulang dengan pembagian lipatan data latih dan data uji yang berbeda. Setiap pembagian lipatan menghasilkan statistik latih yang berbeda, sehingga scaler yang dilatih pada seluruh data mencemari setiap lipatan sekaligus, dan selisih antarjalur dapat membesar. Pipeline kembali menjadi jawaban yang paling ringkas, karena pasangan fit dan transform diulang dengan benar pada setiap lipatan tanpa kode tambahan.
Membaca hasilnya dengan jujur#
Selisih 0,04 terlihat kecil, tetapi arah dan besarnya tidak dijamin. Pada pemecahan lain, jalur bocor bisa saja menghasilkan skor yang lebih rendah. Satu hal yang pasti, skor jalur bocor memuat informasi yang tidak akan tersedia saat sistem berjalan, sehingga angkanya tidak dapat dipercaya sebagai perkiraan performa. Model pada jalur bocor tidak menyimpan rata-rata dari data latih saja, melainkan rata-rata yang tercemar data uji.
Aturan yang sama mengikat transformer mana pun di luar scaler. SimpleImputer menghitung median dari data yang diberikan, OneHotEncoder mengumpulkan daftar kategori, dan PCA menghitung komponen utama, sehingga ketiganya wajib dilatih hanya pada data latih. Struktur bernama pipeline, yaitu rangkaian transformer dan estimator yang dieksekusi berurutan dalam satu objek, menegakkan aturan ini secara otomatis karena fit pipeline hanya menerima data latih.
Kesalahan umum#
Kesalahan pertama adalah menuliskan fit_transform terhadap seluruh data sebelum pemecahan, pola yang terlihat ringkas namun persis seperti jalur bocor pada demonstrasi. Perbaikannya sederhana, yaitu memanggil fit pada data latih saja, lalu transform pada kedua himpunan.
Kesalahan kedua adalah melatih ulang transformer pada data uji karena hasil transformasinya terlihat berbeda. Setiap fit ulang menimpa statistik yang sudah dipelajari, sehingga data uji diproses dengan parameter yang berbeda dari data latih dan perbandingan keduanya kehilangan makna.
Kesalahan ketiga adalah menyimpan model tanpa menyimpan transformernya. Saat prediksi berjalan, data baru harus melalui scaler, imputer, dan encoder yang sama dengan parameter yang tersimpan, sehingga transformer wajib disimpan bersama model sebagai satu kesatuan.
Ringkasan#
- Semua transformer mengikuti pola yang sama, yaitu
fithanya pada data latih, lalutransformpada data latih dan data uji. - Pada data dengan skala timpang, jalur bocor menghasilkan akurasi 0,92 sedangkan jalur benar 0,88, dengan statistik rata-rata yang berbeda nyata.
- Skor jalur bocor tidak dapat dipercaya karena memuat informasi data uji yang tidak tersedia saat prediksi.
- Pipeline menegakkan aturan ini secara otomatis karena
fit-nya hanya menerima data latih.
Referensi#
- Common pitfalls and recommended practices — scikit-learn documentation — Mengulas kebocoran data melalui praproses dan rekomendasi penanganannya.
- 6.1. Pipelines and composite estimators — scikit-learn documentation — Menjelaskan pipeline sebagai alat yang menegakkan disiplin fit dan transform.
- 6.3. Preprocessing and normalization — scikit-learn documentation — Bagian user guide yang mencakup seluruh transformer pada modul ini.