Jebakan Feature dan Leakage

Mode kegagalan klasik data science: kebocoran target dan preprocessing yang salah urutan.

Daftar isi

Model yang tampak hebat dan gagal di lapangan hampir selalu mengalami kebocoran (leakage), yaitu informasi yang tidak akan tersedia saat prediksi sungguhan ikut masuk ke latihannya. Topik ini memperagakan kebocoran yang paling sering terjadi, yaitu feature yang diturunkan dari target, serta menetapkan disiplin preprocessing yang urutannya benar. Setelah membacanya, selisih skor yang terlalu bagus untuk benar dapat didiagnosis, dan pipa kerja yang jujur tersusun sejak awal.

Feature yang menyelundupkan target#

Kebocoran feature terjadi ketika sebuah kolom menurunkan isinya dari target, langsung maupun tidak langsung, dan model pun belajar membaca jawabannya alih-alih polanya. Kolom seperti ini aman saat dilatih karena memang ada di data, dan rusak saat dipakai karena tidak akan pernah tersedia sebelum target terjadi.

Dataset latihan menyediakan contohnya secara alami, yaitu kolom kualitas yang diturunkan dari ambang pm25, sedangkan pm25 itulah target regresinya. Skrip berikut membandingkan model yang sama tanpa dan dengan kolom tersebut, dalam pembagian latih-uji yang sama.

python leakage.py
"""Leakage: feature yang diturunkan dari target membuat skor jujur jadi ilusi."""
import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
from sklearn.model_selection import train_test_split

data = pd.read_csv(
    "ukuran_udara.csv",
    na_values=["kosong", "-999.0"],
    dtype={"pm25": "string", "kelembapan": "string", "kualitas": "string"},
)
data["pm25"] = data["pm25"].astype("float")
data["kelembapan"] = data["kelembapan"].str.replace(",", ".", regex=False).astype("float")
data["kualitas"] = data["kualitas"].str.title()
sah = data[data["pm25"] < 500].dropna(
    subset=["pm25", "suhu_c", "kelembapan", "kualitas"]
)

# kolom bocor: kualitas adalah hasil ambang pm25, dan pm25 adalah targetnya
bocor = sah[["suhu_c", "kelembapan"]].copy()
bocor["kualitas_sedang"] = (sah["kualitas"] == "Sedang").astype(int)
jujur = sah[["suhu_c", "kelembapan"]]
y = sah["pm25"]

X_latih, X_uji, y_latih, y_uji = train_test_split(
    jujur, y, test_size=0.25, random_state=42
)
X_latih_b, X_uji_b, _, _ = train_test_split(
    bocor, y, test_size=0.25, random_state=42
)

model_jujur = LinearRegression().fit(X_latih, y_latih)
model_bocor = LinearRegression().fit(X_latih_b, y_latih)

print(f"R2 uji tanpa feature bocor : {r2_score(y_uji, model_jujur.predict(X_uji)):.3f}")
print(f"R2 uji dengan feature bocor: {r2_score(y_uji, model_bocor.predict(X_uji_b)):.3f}")
print("koefisien feature bocor    :", dict(zip(X_uji_b.columns, model_bocor.coef_.round(1))))
text Keluaran
R2 uji tanpa feature bocor : -0.042
R2 uji dengan feature bocor: 0.873
koefisien feature bocor    : {'suhu_c': np.float64(1.1), 'kelembapan': np.float64(0.6), 'kualitas_sedang': np.float64(17.9)}

Dua keadaan pada keluaran di atas berasal dari eksekusi yang sama, dan lonjakannya drastis, yaitu dari -0.042 menjadi 0.873 hanya karena satu kolom. Koefisien 17.9 pada kolom bocor menyatakan model menaikkan perkiraan 17.9 satuan ketika kualitasnya Sedang, dan informasi itu adalah bayangan langsung dari targetnya, bukan pola yang dapat dipakai di masa depan.

Preprocessing yang salah urutan#

Bentuk kedua kebocoran adalah statistik preprocessing yang dihitung dari seluruh data sebelum pembagian, misalnya penskalaan yang mean dan simpangannya menghitung data uji juga. Informasi dari data uji pun menyusup ke latihan, dan skor uji menjadi terlalu optimis tanpa terlihat.

Disiplin yang benar menetapkan urutan, yaitu pembagian data terlebih dahulu, lalu statistik apa pun hanya dihitung dari data latih, dan penerapannya ke data uji memakai statistik itu. Pipeline milik scikit-learn memakai disiplin ini secara otomatis, yaitu setiap langkah pra-pemrosesan difit ulang pada setiap pembagian, sehingga kesalahan urutannya sulit terjadi.

Aturan yang sama berlaku untuk semua transformasi yang menghitung statistik, termasuk imputasi rata-rata, penyandian kategori, dan pemilihan feature berdasarkan korelasi dengan target, dan yang terakhir ini adalah bentuk kebocoran yang paling sering lolos karena dijalankan dengan niat baik.

Memeriksa diri dari kebocoran#

Pemeriksaan pertama adalah pertanyaan waktu, yaitu apakah setiap kolom tersedia pada saat prediksi sungguhan dilakukan. Kolom yang isinya baru terjadi setelah peristiwa, seperti status akhir antrean untuk memprediksi durasi antrean, dicurigai terlebih dahulu.

Pemeriksaan kedua adalah pertanyaan sumber, yaitu menelusuri asal kolom ke dokumentasi atau pemilik datanya, dan kolom turunan yang tidak jelas asal-usulnya tidak masuk model sebelum dijelaskan. Pemeriksaan ketiga adalah kecurigaan terhadap skor, karena model dengan kinerja yang jauh di atas kemampuan datanya lebih sering bocor daripada jenius.

Kebiasaan yang menopang ketiganya adalah pipa kerja yang tertata, yaitu Pipeline untuk preprocessing, split sebelum apa pun yang menghitung statistik, dan catatan asal-usul setiap kolom pada dokumentasi EDA, sehingga pemeriksaannya membaca catatan, bukan menebak kode.

Kesalahan umum#

Kesalahan pertama adalah memasukkan kolom yang dihitung setelah peristiwa selesai, seperti durasi kunjungan untuk memprediksi durasi itu sendiri. Skornya melonjak dan modelnya gagal di lapangan, sedangkan pertanyaan tersedia-pada-saat-prediksi menangkapnya sebelum melatih.

Kesalahan kedua adalah memilih feature berdasarkan korelasi dengan target pada seluruh data sebelum pembagian. Pemilihan yang memakai target adalah bagian dari pelatihan, dan ia ditempatkan di dalam Pipeline agar hanya melihat data latih.

Kesalahan ketiga adalah menyalahartikan skor tinggi sebagai kesuksesan. Skor yang jauh melampaui pemahaman domain memicu penyelidikan, dan pada dataset latihan ini, lompatan 0.873 yang diperiksa asal-usulnya berakhir pada satu kolom yang dihapus.

Ringkasan#

  • Kebocoran feature menyelundupkan target ke latihan, dan dataset latihan memperlihatkan lonjakan dari -0.042 ke 0.873 lewat satu kolom turunan.
  • Preprocessing yang menghitung statistik dari seluruh data sebelum split membocorkan data uji, dan Pipeline menegakkan urutannya.
  • Tiga pemeriksaan, yaitu tersedia saat prediksi, jelas asal-usulnya, dan curiga pada skor yang terlalu bagus, menjadi kebiasaan sebelum melatih.
  • Pipa kerja yang jujur menempatkan split paling awal dan memandu setiap transformasi statistik sebagai bagian pelatihan.

Referensi#