Menguasai data wrangling & cleaning: menangani missing values, mendeteksi dan menangani outlier, serta feature engineering dasar — dibangun dalam pipeline cleaning yang bisa dipakai ulang untuk proyek apa pun

Setelah di episode 4 kita menguasai Python data stack, pada episode ini kita menghadapi kenyataan pahit dunia nyata: data tidak pernah bersih. Ada kolom kosong, nilai aneh, duplikat, dan format yang tidak konsisten. Kalau diabaikan, semua ini merembet ke model dan menyesatkan insight.
Data wrangling adalah seni mengubah data mentah menjadi data yang siap dianalisis. Data scientist senior menghabiskan hingga 80% waktunya di sini — dan di sinilah keputusan paling berdampak dibuat. Mengisi missing value dengan cara yang salah bisa menciptakan pola yang tidak nyata; membuang outlier tanpa berpikir bisa membuang insight paling berharga. Episode ini membangun keterampilan tersebut secara sistematis.
Missing values adalah ketidakhadiran data di sebuah sel. Pertanyaan pertamanya bukan "isi dengan apa?", melainkan "mengapa data hilang?":
| Pola Missing | Arti | Penanganan |
|---|---|---|
| MCAR (acak sempurna) | Tidak terkait apa pun | Imputasi aman |
| MAR (acak, terkait variabel lain) | Dipengaruhi variabel yang teramati | Imputasi berbasis fitur lain |
| MNAR (tidak acak) | Hilang karena nilai itu sendiri | Paling berisiko; butuh pertimbangan domain |
Contoh MNAR: orang dengan pendapatan sangat rendah cenderung tidak mengisi kolom pendapatan. Mengisi median di sini akan bias ke atas.
df["income_fill_mean"] = df["income"].fillna(df["income"].mean())
df["income_fill_median"] = df["income"].fillna(df["income"].median())
df["income_fill_ffill"] = df["income"].ffill()
df["income_missing"] = df["income"].isna().astype(int)Yang sering terlupakan: tandai pola missing-nya. Kolom income_missing di atas bisa menjadi fitur prediktif yang justru membantu model — pola missing kadang mengandung sinyal.
Warning
Saat berurusan dengan data sensitif, jangan mengisi missing dengan mean lalu menyebut data "lengkap". Missing values adalah informasi, bukan sekadar lubang yang harus ditambal. Imputasi harus dicatat sebagai asumsi, dan diuji apakah mengubah hasil analisis.
Outlier adalah nilai yang menyimpang jauh dari pola mayoritas. Tapi tidak semua outlier sama:
-5 atau 999). Harus dibersihkan.import numpy as np
import pandas as pd
np.random.seed(11)
df = pd.DataFrame({"amount": np.concatenate([
np.random.normal(200, 40, 980),
np.array([2000, 2500]),
])})
q1, q3 = df["amount"].quantile([0.25, 0.75])
iqr = q3 - q1
lower, upper = q1 - 1.5 * iqr, q3 + 1.5 * iqr
outliers = df[(df["amount"] < lower) | (df["amount"] > upper)]
print("jumlah outlier:", len(outliers))
print(outliers["amount"].values)Metode lain: z-score (> 3), visualisasi boxplot, atau penilaian domain. Keputusan menangani outlier harus berbasis konteks: untuk regresi, outlier bisa mengganggu; untuk deteksi fraud, outlier justru targetnya.
Feature engineering adalah pembuatan fitur baru dari data mentah yang memudahkan model menemukan pola. Tiga contoh paling berdampak:
df["hour"] = df["timestamp"].dt.hour
df["is_weekend"] = df["timestamp"].dt.dayofweek >= 5
df["days_since_first"] = (df["timestamp"] - df["timestamp"].min()).dt.daysRFM adalah klasik customer analytics: Recency (terakhir belanja), Frequency (frekuensi), Monetary (total nilai). Tiga fitur ini saja sering mengalahkan puluhan fitur mentah.
ref_date = df["order_date"].max() + pd.Timedelta(days=1)
rfm = df.groupby("customer_id").agg(
recency=("order_date", lambda x: (ref_date - x.max()).days),
frequency=("order_id", "nunique"),
monetary=("amount", "sum"),
)
print(rfm.head())df["age_group"] = pd.cut(df["age"], bins=[0, 25, 35, 50, 100],
labels=["18-25", "26-35", "36-50", "50+"])
df["spend_per_item"] = df["total_spend"] / df["num_items"].clip(lower=1)Rasio antar kolom (spend_per_item) dan binning adalah fitur murah yang sering menaikkan performa signifikan. Episode 10 akan memperdalam encoding, scaling, dan selection.
Jangan menulis semua langkah cleaning inline di notebook. Bungkus menjadi fungsi pipeline yang bisa dipakai ulang dan diuji:
import numpy as np
import pandas as pd
def clean_pipeline(df: pd.DataFrame) -> pd.DataFrame:
df = df.copy()
df["date"] = pd.to_datetime(df["date"], errors="coerce")
df = df.drop_duplicates(subset=["customer_id"])
df["income_missing"] = df["income"].isna().astype(int)
df["income"] = df.groupby("region")["income"].transform(
lambda s: s.fillna(s.median())
)
df["age"] = df["age"].clip(18, 100)
return df
df_clean = clean_pipeline(raw_df)
print(df_clean.isna().sum())Kenapa pipeline terpisah? Karena (1) bisa dijalankan ulang konsisten, (2) bisa diuji unit, (3) mudah dipindahkan ke production — dan di episode 23-24 kalian akan melihat pola ini menjadi bagian dari pipeline produksi yang sesungguhnya.
| Pitfall | Dampak | Solusi |
|---|---|---|
| Mengisi missing sebelum memahami penyebabnya | Bias yang tidak terdeteksi | Investigasi pola missing dulu |
| Menghapus semua baris dengan missing | Kehilangan data berharga | Evaluasi proporsi missing per kolom |
| Menggunakan mean saat data skewed | Imputasi tidak mewakili mayoritas | Median / imputasi per grup |
| Menerapkan cleaning pada seluruh data sebelum split | Data leakage (episode 11) | Fit dulu, transform setelah split |
| Menghapus outlier tanpa konteks domain | Kehilangan insight/fraud | Bedakan error vs nilai ekstrem nyata |
Inti yang harus dibawa pulang:
Di episode 6 selanjutnya kita akan membahas Exploratory Data Analysis (EDA) — proses merangkum, memvisualisasikan, dan mengubah data menjadi insight awal sebelum modeling. Sampai jumpa di episode 6!