Notebook Bab 5 - Missing Values & Outliers

Open In Colab

Notebook Bab 5 ini punya dua bagian. Bagian Demo tinggal Anda jalankan lalu amati keluarannya; bagian Mini Project berisi soal dan data yang Anda kerjakan sendiri.

Penanganan nilai hilang dibuat reproducible dengan menaruh imputasi sebagai transformer di dalam pipeline, bukan suntingan manual. Saat fitur berkorelasi, imputasi berbasis model memanfaatkan kolom lain untuk menebak nilai yang hilang.

Persiapan

import numpy as np
from sklearn.experimental import enable_iterative_imputer  # noqa: F401
from sklearn.impute import SimpleImputer, IterativeImputer, KNNImputer
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.linear_model import Ridge
from sklearn.model_selection import cross_val_score

RANDOM_STATE = 42
rng = np.random.default_rng(RANDOM_STATE)
print('Setup selesai.')
Setup selesai.

Section 1 - Demo: Imputasi Reproducible di Dalam Pipeline

Data: fitur berkorelasi dengan nilai hilang

Enam fitur dibangun dari dua faktor laten (z1, z2), jadi tiap kelompok fitur saling berkorelasi kuat. Sekitar 25 persen sel dikosongkan secara acak.

n = 1200
z1 = rng.normal(size=n)
z2 = rng.normal(size=n)
X = np.column_stack([
    z1 + 0.10 * rng.normal(size=n),
    z1 + 0.10 * rng.normal(size=n),
    z1 + 0.10 * rng.normal(size=n),
    z2 + 0.10 * rng.normal(size=n),
    z2 + 0.10 * rng.normal(size=n),
    z2 + 0.10 * rng.normal(size=n),
])
y = 3.0 * z1 - 2.0 * z2 + rng.normal(scale=0.5, size=n)
Xmiss = X.copy()
Xmiss[rng.random(X.shape) < 0.25] = np.nan
print('Bentuk data:', Xmiss.shape, '| nilai hilang:', int(np.isnan(Xmiss).sum()))
Bentuk data: (1200, 6) | nilai hilang: 1823

Bandingkan tiga strategi imputasi

Semua di dalam pipeline (imputasi + StandardScaler + Ridge), jadi parameter imputasi di-fit ulang pada tiap fold latih saja.

def eval_imp(imputer):
    pipe = Pipeline([('imp', imputer), ('sc', StandardScaler()), ('m', Ridge())])
    return cross_val_score(pipe, Xmiss, y, cv=5, scoring='r2').mean()

r_median = eval_imp(SimpleImputer(strategy='median'))
r_knn = eval_imp(KNNImputer(n_neighbors=5))
r_iter = eval_imp(IterativeImputer(random_state=RANDOM_STATE, max_iter=10))
print(f'Median imputation    : R2 = {r_median:.3f}')
print(f'KNN imputation       : R2 = {r_knn:.3f}')
print(f'Iterative imputation : R2 = {r_iter:.3f}')
Median imputation    : R2 = 0.875
KNN imputation       : R2 = 0.895
Iterative imputation : R2 = 0.957

🔎 Amati. Karena tiap kelompok fitur berasal dari faktor laten yang sama, imputasi berbasis model (KNN dan Iterative) menebak nilai hilang dari kolom sekelompoknya dan mengungguli median per-kolom yang mengabaikan korelasi. Untuk data ber-outlier, ganti StandardScaler dengan RobustScaler (median dan IQR). Semua langkah di dalam pipeline, jadi parameter imputasi di-fit hanya pada data latih.

Section 2 - Mini Project

Soal

Anda diberi data numerik yang mengandung nilai hilang dan outlier. Targetnya nilai (regresi).

Tugas:

  1. Bangun pipeline reproducible: imputasi + penanganan outlier (RobustScaler) + model.
  2. Tambahkan missing-indicator (SimpleImputer(add_indicator=True)) dan cek apakah menaikkan skor.
  3. Laporkan R2 dengan cross-validation.

Luaran: kode pipeline, R2 CV dengan dan tanpa missing-indicator, plus 2-3 kalimat analisis.

Kriteria penilaian: (a) seluruh transformasi di dalam pipeline; (b) penanganan outlier eksplisit; (c) evaluasi memakai cross-validation.

# DATA AWAL (jangan diubah) - fitur berkorelasi dengan nilai hilang dan outlier.
m = 900
g1 = np.random.default_rng(11).normal(size=m)
g2 = np.random.default_rng(22).normal(size=m)
eps = np.random.default_rng(33)
Xp = np.column_stack([
    g1 + 0.15 * eps.normal(size=m),
    g1 + 0.15 * eps.normal(size=m),
    g2 + 0.15 * eps.normal(size=m),
    g2 + 0.15 * eps.normal(size=m),
    eps.normal(size=m),
])
yp = 2.5 * g1 - 1.5 * g2 + eps.normal(scale=0.6, size=m)
Xp[np.random.default_rng(44).random(Xp.shape) < 0.01] *= 8      # outlier
Xp[np.random.default_rng(55).random(Xp.shape) < 0.20] = np.nan  # nilai hilang
print('Data:', Xp.shape, '| nilai hilang:', int(np.isnan(Xp).sum()))
Data: (900, 5) | nilai hilang: 863
# Kerjakan di sini.
# Petunjuk: Pipeline([('imp', SimpleImputer(add_indicator=True)), ('sc', RobustScaler()), ('m', Ridge())]).