Kebocoran Data

Mengenali data leakage, mengapa skor menjadi menggelembung, dan jalur masuknya.

Daftar isi

Topik ini membahas kebocoran data (data leakage), yaitu masuknya informasi dari data uji ke dalam proses pelatihan sehingga skor evaluasi menjadi menggelembung. Dua jalur kebocoran yang paling umum dibahas satu per satu dengan angka nyata, yaitu transformer yang dipasang pada seluruh data dan fitur yang menyimpan informasi target. Pemahaman atas kedua jalur ini menjadi dasar untuk membaca setiap skor model secara kritis.

Apa yang terjadi ketika data bocor#

Kebocoran data adalah kondisi ketika informasi yang seharusnya hanya ada pada tahap evaluasi ikut memengaruhi proses pelatihan. Akibatnya, skor evaluasi terlihat baik padahal kemampuan model pada data baru tidak sebaik angkanya, karena sebagian karakter data uji sudah menyusup ke dalam pembelajaran. Kondisi ini berbahaya justru karena tidak memunculkan error sama sekali, dan angka yang menggelembung justru tampak sebagai keberhasilan.

Dua jalur yang paling umum adalah pemasangan transformer pada seluruh data sebelum data dipecah dan kehadiran fitur yang menampung informasi target. Diagram berikut menggambarkan jalur pertama.

Data latihData ujiScaler dan modeldipasang dengan fitEvaluasijalur sahjalur bocorpredict
Jalur kebocoran: informasi data uji ikut menentukan pemasangan scaler dan model

Pada jalur yang sah, hanya data latih yang menentukan pemasangan transformer dan model, lalu data uji dipakai pada tahap evaluasi. Jalur bocor menambahkan satu panah berbahaya, yaitu data uji yang ikut digunakan saat pemasangan. Model yang dipasang dengan cara ini telah menyesuaikan diri terhadap karakter data yang akan diujikan kepadanya, sehingga skornya tidak lagi mengukur kemampuan yang sesungguhnya.

Jalur pertama: transformer dipasang pada seluruh data#

StandardScaler menghitung rata-rata dan simpangan baku dari data yang diberikan, lalu menggunakan kedua statistik itu untuk mentransformasi data apa pun yang datang kemudian. Apabila fit dipanggil pada seluruh data sebelum pemecahan, rata-rata dan simpangan baku tersebut ikut dihitung dari baris-baris data uji. Transformasi data latih pun membawa jejak data uji, dan inilah bentuk kebocoran yang paling sering terjadi tanpa disadari. Angka yang diperbandingkan di sini adalah rata-rata per fitur, dan pola yang sama berlaku untuk simpangan baku serta seluruh statistik transformer lain.

Kode berikut membandingkan atribut mean_ milik dua scaler, satu dipasang pada seluruh data dan satu lagi hanya pada data latih.

python Contoh: mean_ scaler pada seluruh data dan data latih
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

X, y = load_breast_cancer(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
)

scaler_penuh = StandardScaler().fit(X)
scaler_latih = StandardScaler().fit(X_train)

print("mean_ tiga fitur pertama (seluruh data):", scaler_penuh.mean_[:3].round(3))
print("mean_ tiga fitur pertama (data latih)  :", scaler_latih.mean_[:3].round(3))
print("Selisihnya:", (scaler_penuh.mean_[:3] - scaler_latih.mean_[:3]).round(3))
text Keluaran
mean_ tiga fitur pertama (seluruh data): [14.127 19.29  91.969]
mean_ tiga fitur pertama (data latih)  : [14.067 19.247 91.557]
Selisihnya: [0.06  0.042 0.412]

Selisihnya kecil pada data sebesar ini, tetapi ukuran selisih tidak mengubah statusnya sebagai kebocoran. Pada data yang lebih kecil, fitur dengan skala ekstrem, atau pemecahan tanpa stratifikasi, geseran statistiknya bisa jauh lebih besar. Yang dinilai di sini bukan besaran selisihnya, melainkan sumber informasinya, yaitu data uji yang seharusnya belum boleh tersentuh.

Perbandingan skor jalur salah dan jalur benar#

Kode berikut mengukur dampaknya pada skor akhir. Model KNeighborsClassifier dengan n_neighbors=5 dijalankan dua kali pada dataset breast cancer bawaan scikit-learn, pertama dengan scaler yang dipasang pada seluruh data dan kedua dengan scaler yang hanya dipasang pada data latih. Kedua jalur menggunakan pemecahan, benih acak, dan model yang identik, sehingga satu-satunya perbedaan terletak pada data yang digunakan untuk memasang scaler.

python demo-kebocoran.py
from sklearn.datasets import load_breast_cancer
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import StandardScaler

X, y = load_breast_cancer(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
)

# Jalur salah: scaler dipasang pada seluruh data sebelum data dipecah
scaler_salah = StandardScaler().fit(X)
X_train_salah = scaler_salah.transform(X_train)
X_test_salah = scaler_salah.transform(X_test)
model_salah = KNeighborsClassifier(n_neighbors=5)
model_salah.fit(X_train_salah, y_train)
skor_salah = accuracy_score(y_test, model_salah.predict(X_test_salah))

# Jalur benar: scaler dipasang hanya pada data latih
scaler_benar = StandardScaler().fit(X_train)
X_train_benar = scaler_benar.transform(X_train)
X_test_benar = scaler_benar.transform(X_test)
model_benar = KNeighborsClassifier(n_neighbors=5)
model_benar.fit(X_train_benar, y_train)
skor_benar = accuracy_score(y_test, model_benar.predict(X_test_benar))

print("Akurasi jalur salah:", round(skor_salah, 4))
print("Akurasi jalur benar:", round(skor_benar, 4))
text Keluaran
Akurasi jalur salah: 0.9649
Akurasi jalur benar: 0.9561

Pada pemisahan ini jalur salah memperoleh skor 0.9649, sedangkan jalur benar 0.9561, dan selisihnya hanya sekitar satu persen. Arah selisih pada satu pemisahan tidak selalu konsisten dengan dugaan karena derau pemecahan kadang menutupi efek kebocorannya. Pokok persoalannya bukan besaran angkanya, melainkan ketidakabsahannya, karena skor jalur salah dihitung dari model yang pelatihannya menyerap statistik data uji. Pada dataset lain selisihnya dapat membesar, tetapi arah dan besarnya tidak pernah dapat diandalkan pada satu pemisahan tunggal.

Jalur kedua: fitur yang menyimpan informasi target#

Kebocoran juga masuk melalui fitur. Fitur yang dihitung dari target, diisi setelah target terjadi, atau menyimpan hasil akhir dari proses yang diprediksi membuat jawaban sudah tersedia bagi model pada saat pelatihan. Contoh kasusnya pada data tiket loket adalah kolom tanggal penyelesaian yang ikut menjadi fitur ketika targetnya adalah kecepatan penyelesaian. Kasus lain yang serupa adalah kolom total yang dihitung dari beberapa kolom jawaban dan kolom status yang baru terisi setelah proses selesai.

Kode berikut memperlihatkan versi paling ekstrem dari jalur ini, yaitu menambahkan label itu sendiri sebagai satu kolom fitur.

python Contoh: satu kolom fitur yang berisi label
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
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,
    random_state=42
)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

model = LogisticRegression(max_iter=1000)
model.fit(X_train, y_train)
print("Skor tanpa fitur bocor:", round(model.score(X_test, y_test), 4))

X_train_bocor = np.column_stack([X_train, y_train])
X_test_bocor = np.column_stack([X_test, y_test])
model_bocor = LogisticRegression(max_iter=1000)
model_bocor.fit(X_train_bocor, y_train)
print("Skor dengan fitur bocor:", round(model_bocor.score(X_test_bocor, y_test), 4))
text Keluaran
Skor tanpa fitur bocor: 0.95
Skor dengan fitur bocor: 1.0

Skor LogisticRegression naik dari 0.95 menjadi 1.0 setelah satu kolom yang berisi label ikut menjadi fitur. Skor sempurna semacam ini adalah tanda yang patut dicurigai karena model nyaris tidak pernah benar pada semua sampel tanpa alasan yang jelas. Kolom seperti ini biasanya lolos saat data disiapkan, sehingga telaah asal-usul setiap fitur menjadi bagian dari pekerjaan pemodelan. Karena itu, keanehan pada skor lebih bermanfaat diperlakukan sebagai sinyal untuk ditelusuri dan bukan sebagai keberhasilan yang langsung dirayakan.

Arahan perbaikan#

Aturan perbaikannya sederhana dan dapat dipegang, yaitu memasang setiap transformer hanya pada data latih, lalu mentransformasi data latih dan data uji dengan transformer yang sama. Pola ini berlaku untuk semua jenis transformer, termasuk scaler, encoder, dan pengisi nilai yang hilang. scikit-learn menyediakan Pipeline untuk mengotomatiskan disiplin ini karena pipeline memasang setiap transformer hanya dari data latih pada setiap pemecahan data.

Untuk kebocoran lewat fitur, otomatisasi semacam itu tidak tersedia karena penyebabnya ada pada isi data. Telaah asal-usul kolom menjadi kuncinya, yaitu memastikan setiap fitur memang tersedia pada saat prediksi sungguhan dilakukan. Kolom yang baru terisi setelah target terjadi harus dikeluarkan dari fitur, apa pun kontribusinya terhadap skor.

Pemeriksaan cepatnya mudah, yaitu memastikan tidak ada pemanggilan fit pada objek transformer yang menerima data gabungan latih dan uji. Bila seluruh praproses berada di dalam satu objek pipeline, evaluasi dengan pembagian lipatan pun otomatis mengulangi pemasangan transformer untuk setiap lipatan. Disiplin ini membuat satu skor yang dihasilkan dapat dipertanggungjawabkan isinya.

Ringkasan#

  • Kebocoran data adalah masuknya informasi data uji ke proses pelatihan, dan akibatnya skor evaluasi menggelembung tanpa memunculkan error.
  • Transformer wajib dipasang hanya pada data latih, karena pemasangan pada seluruh data membawa statistik data uji ke dalam pelatihan.
  • Fitur yang menyimpan informasi target menghasilkan skor sempurna yang tidak mencerminkan kemampuan nyata model.
  • Pipeline mengotomatiskan pemasangan transformer hanya dari data latih pada setiap pemecahan data.

Referensi#