Belajar AI #4: Data & Fitur — Bahan Bakar Machine Learning

Episode ini saya tulis agak pelan-pelan, karena topiknya ternyata yang paling menentukan berhasil-tidaknya proyek machine learning: data dan fitur. Semua tutorial bikin seolah bagian serunya itu memilih algoritma. Pengalaman membaca-baca praktisi (dan sedikit eksperimen sendiri) bilang lain: 80 persen pekerjaan aslinya ada di sini.

Garbage in, garbage out

Prinsip paling tua di dunia data tetap berlaku: model hanya sebagus data yang diberikan. Analogi programmer yang nempel buat saya: model itu seperti fungsi. Kalau inputnya kacau, output pasti kacau — tidak peduli seberapa elegan implementasinya. Tidak ada algoritma secanggih apa pun yang bisa menyelamatkan dataset yang salah atau bias.

Struktur data tabular yang biasa dipakai itu seperti tabel database: satu baris = satu contoh (satu email, satu transaksi), satu kolom = satu atribut. Kolom-kolom inilah yang disebut fitur (feature), dan kolom target yang mau diprediksi disebut label.

Fitur: informasi yang kita kasih ke model

Fitur adalah representasi numerik dari realitas yang relevan dengan masalah. Contoh untuk prediksi harga rumah: luas tanah, jumlah kamar, jarak ke stasiun, tahun dibangun. Model tidak pernah “melihat” rumah — dia cuma melihat angka-angka ini. Jadi kualitas fitur menentukan langit-langit performa; algoritma cuma menentukan seberapa dekat kita bisa mendekati langit-langit itu.

Proses membuat fitur dari data mentah disebut feature engineering, dan ini lebih seni daripada sains. Contoh klasik dari dataset Titanic: dari kolom nama yang terlihat tidak berguna, bisa diekstrak gelar (Mr, Mrs, Master) yang ternyata sangat prediktif. Data mentah jarang langsung siap pakai.

Pembersihan: bagian tidak glamor tapi wajib

  • Missing values — sel kosong. Pilihannya: buang barisnya, isi dengan rata-rata/median, atau jadikan “kosong” sebagai sinyal tersendiri.
  • Duplikat — baris ganda bikin model overconfident pada contoh itu.
  • Outlier — nilai ekstrem yang bisa menggeser model secara tidak wajar. Kadang error input, kadang justru kasus paling menarik.
  • Inkonsistensi format — “Jakarta” vs “JKT” vs “jakarta ” (dengan spasi). Klasik.

Satu hal yang saya pelajari cara susah: data leakage. Ini terjadi kalau informasi dari “masa depan” (atau dari label itu sendiri) bocor ke fitur. Contoh lucu tapi nyata yang sering dikutip: model “memprediksi pasien sakit” yang ternyata cuma belajar bahwa baris dengan bobot berat badan tinggi adalah pasien — karena kolom berat badan bayi baru lahir terisi nol. Akurasi latih bagus, produksi hancur.

Scaling: kenapa angka harus “sejajar”

Fitur penghasilan dalam rupiah (jutaan) dan umur (puluhan) punya skala yang timpang. Beberapa algoritma — terutama yang berbasis jarak seperti KNN, atau yang berbasis gradient descent — akan terdistorsi oleh fitur berskala besar. Solusinya standarisasi: ubah tiap fitur supaya punya rata-rata 0 dan deviasi standar 1.

Karena episode ini soal bahan bakar, sekalian saya catat pipeline kecil yang saya pakai untuk merapikan data dengan scikit-learn:

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

df = pd.read_csv("rumah.csv")
df = df.drop_duplicates().dropna(subset=["harga"])

X = df[["luas_m2", "kamar", "umur_bangunan"]]
y = df["harga"]

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)  # belajar dari train saja
X_test_scaled = scaler.transform(X_test)        # terapkan ke test

Perhatikan detail penting: fit_transform hanya di data latih, lalu transform saja di data uji. Kalau scaler ikut “belajar” dari data uji, itu juga bentuk kebocoran data. Kesalahan pemula yang katanya sangat umum — dan sekarang saya tahu kenapa.

MinMaxScaler vs StandardScaler: kapan pakai mana

Saya awalnya mengira StandardScaler adalah jawaban untuk semua situasi. Ternyata tidak. Dua scaler ini punya karakter berbeda:

  • StandardScaler mengubah distribusi jadi mean 0, standar deviasi 1. Cocok untuk data yang mendekati distribusi normal, atau saat algoritma asumsi distribusi itu (regresi linear, SVM, PCA). Tahan terhadap outlier karena tidak dibatasi range tertentu.
  • MinMaxScaler mengubah rentang ke [0, 1]. Cocok untuk neural network yang butuh input ternormalisasi, atau saat distribusi tidak normal dan ada batas alami (misalnya persentase, pixel gambar rentang 0-255). Tapi sensitif terhadap outlier — satu nilai ekstrem bisa menekan semua nilai lain ke range sangat sempit.
from sklearn.preprocessing import MinMaxScaler, StandardScaler

# StandardScaler: untuk data ~normal
std_scaler = StandardScaler()
X_std = std_scaler.fit_transform(X_train)

# MinMaxScaler: untuk neural network / data bounded
minmax = MinMaxScaler()
X_mm = minmax.fit_transform(X_train)

Encoding kategorikal: mengubah teks jadi angka

Model hanya bisa mengolah angka, tapi dataset nyata penuh kolom teks: kota, warna, kategori produk. Proses mengubahnya disebut encoding. Setiap metode punya trade-off sendiri:

  • One-Hot Encoding — membuat kolom baru per kategori. “Merah” jadi kolom warna_merah bernilai 1. Aman untuk kategori nominal tanpa urutan, tapi kalau kategorinya ribuan (kota di seluruh dunia), fitur jadi meledak.
  • Label Encoding — assign angka: “Merah”=0, “Biru”=1, “Hijau”=2. Ringkas, tapi algoritma bisa salah mengira ada urutan (1 < 2 berarti “Biru” < “Hijau”). Hanya aman untuk tree-based models yang tidak peduli magnitudo angka.
  • Target Encoding — ganti kategori dengan rata-rata targetnya. “Merah” diganti rata-rata harga rumah untuk yang warnanya merah. Sangat powerful untuk kategori dengan banyak level, tapi rawan overfitting kalau tidak pakai smoothing.
import pandas as pd
from sklearn.preprocessing import OneHotEncoder, LabelEncoder

df = pd.DataFrame({"kota": ["Jakarta", "Bandung", "Surabaya", "Jakarta"]})

# One-Hot Encoding
ohe = pd.get_dummies(df, columns=["kota"])

# Label Encoding
le = LabelEncoder()
df["kota_label"] = le.fit_transform(df["kota"])

print(ohe)
print(df[["kota", "kota_label"]])

Feature selection: memilih fitur yang benar-benar penting

Semua fitur yang ada bukan berarti semua harus dipakai. Fitur yang tidak relevan menambah noise dan bikin model overfitting. Ada tiga pendekatan utama yang saya catat:

PendekatanContoh MetodeKelebihanKekurangan
FilterCorrelation matrix, chi-square, mutual informationCepat, tidak butuh modelMengabaikan interaksi antar fitur
WrapperRecursive Feature Elimination (RFE), forward/backward selectionMemperhatikan kombinasi fiturLambat, butuh model referensi
EmbeddedL1 regularization (Lasso), feature importance dari treeBalik kecepatan dan kualitasTergantung model dasar
# Filter: korelasi dengan target
import seaborn as sns
import matplotlib.pyplot as plt

corr = df.corr(numeric_only=True)
print(corr["harga"].sort_values(ascending=False))

# Embedded: L1 Regularization
from sklearn.linear_model import LassoCV

lasso = LassoCV(cv=5).fit(X_train_scaled, y_train)
important = pd.Series(lasso.coef_, index=X.columns)
print(important[important != 0])  # fitur yang dipilih model

Dimensionality reduction: PCA sederhana

Kadang fitur terlalu banyak dan sebagian saling berkorelasi (redundan). Principal Component Analysis (PCA) merangkum banyak fitur jadi beberapa “komponen utama” yang menangkap mayoritas variansi. Analogi: foto berwarna 3 channel (RGB) bisa direduksi jadi 1 channel grayscale tanpa kehilangan makna utama gambar.

from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler

# PCA sensitif terhadap skala, jadi scale dulu
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X_train)

# Turunkan ke 2 dimensi untuk visualisasi
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)

print(f"Variance explained: {pca.explained_variance_ratio_}")
# Misal: [0.62, 0.25] → 2 komponen menangkap 87% informasi

Data augmentation: memperbanyak data secara sintetis

Ketika dataset kecil, teknik augmentation bisa memperbanyak data tanpa harus mengumpulkan dari lapangan. Strategi berbeda untuk tipe data berbeda:

  • Gambar — rotasi, flip, zoom, brightness shift, crop random. Library seperti albumentations atau Keras ImageDataGenerator mempermudah ini.
  • Teks — synonym replacement, back-translation (terjemah ke bahasa lain lalu balik), random insertion/deletion. library nlpaug atau TextAttack menyediakan ini.
  • Tabular — SMOTE (dijelaskan di bawah), atau menambahkan noise kecil secara acak pada fitur numerik.

Class imbalance: ketika data tidak seimbang

Dalam dataset deteksi fraud, mungkin hanya 0.1% transaksi yang fraud. Model yang tidak ditangani akan belajar “selalu prediksi tidak fraud” dan tetap dapat akurasi 99.9% — tapi sama sekali tidak berguna. Tiga strategi utama:

  • SMOTE (Synthetic Minority Over-sampling Technique) — membuat sampel sintetis baru untuk kelas minoritas dengan menginterpolasi antara sampel yang ada. Tidak sekadar menduplikat baris.
  • Class weights — memberi bobot lebih besar pada kelas minoritas saat training. Di scikit-learn, tinggal set class_weight='balanced'.
  • Undersampling — mengurangi sampel kelas mayoritas. Praktis kalau data sangat besar, tapi membuang informasi.
# Class weights — paling simpel, tanpa ubah data
from sklearn.ensemble import RandomForestClassifier

model = RandomForestClassifier(class_weight="balanced", random_state=42)
model.fit(X_train, y_train)

# SMOTE — butuh library imbalanced-learn
# pip install imbalanced-learn
from imblearn.over_sampling import SMOTE

smote = SMOTE(random_state=42)
X_resampled, y_resampled = smote.fit_resample(X_train, y_train)

EDA: peta sebelum mulai perjalanan

Exploratory Data Analysis (EDA) adalah langkah pertama sebelum bikin model. Saya pikir dulu ini hanya “lihat-lihat data”. Ternyata EDA adalah checklist sistematis yang mencegah banyak masalah di kemudian hari. Berikut yang selalu saya lakukan:

  • Cek dimensi data: df.shape, df.info()
  • Distribusi target: df["target"].value_counts() — seimbang atau tidak?
  • Statistik deskriptif: df.describe() — cari anomali pada min/max
  • Korelasi antar fitur: df.corr() — hindari multikolinearitas
  • Distribusi tiap fitur: histogram atau KDE plot
  • Missing values per kolom: df.isnull().sum()
  • Detect outlier: boxplot atau IQR method
# Quick EDA pipeline
import pandas as pd

df = pd.read_csv("dataset.csv")
print(f"Dimensi: {df.shape}")
print(f"\nInfo:")
df.info()
print(f"\nStatistik deskriptif:")
print(df.describe())
print(f"\nMissing values:")
print(df.isnull().sum()[df.isnull().sum() > 0])
print(f"\nDistribusi target:")
print(df.iloc[:, -1].value_counts(normalize=True))

# Korelasi dengan target
target_col = df.columns[-1]
corr = df.select_dtypes(include="number").corr()[target_col].sort_values(ascending=False)
print(f"\nKorelasi dengan {target_col}:")
print(corr)

Feature engineering checklist per tipe data

Tipe DataTeknik Feature EngineeringContoh
NumerikScaling, binning, log transform, polynomial featureslog(pendapatan), age_bucket (18-25, 26-35…)
KategorikalOne-hot, label, target encoding, frequency encodingkota → kota_jakarta (0/1)
TeksTF-IDF, word embeddings, n-grams, panjang teksTF-IDF 1000 kata paling sering
WaktuEkstrak jam, hari, bulan, libur, cyclical encodingsin(2π × jam/24), is_weekend
GeospasialHaversine distance, clustering, proximity featuresJarak ke pusat kota terdekat (km)

Catatan untuk diri sendiri

Mental model yang saya pegang mulai episode ini: kerjakan datanya sampai benar dulu, baru sentuh algoritma. Checklist pribadi sebelum training: cek missing values, cek duplikat, cek distribusi target, pisahkan train/test lebih awal, dan tanya sendiri “apakah ada informasi masa depan yang bocor ke fitur?” Lima pertanyaan ini sudah menyelamatkan saya dari minimal satu eksperimen yang bodoh.

Momen terbesar yang mengubah cara saya melihat machine learning: setelah berkali-kali gagal menaikkan akurasi dengan algoritma baru, ternyata satu jam spent di EDA — memperbaiki encoding kategorikal yang salah dan menghapus kolom leakage — mengangkat akurasi lebih dari 10 poin. Sejak itu saya yakin: data lebih penting dari algoritma. Seperti yang dikatakan Andrew Ng, “data-centric AI” bukan sekadar slogan — itu mentalitas yang harus dimiliki sejak awal belajar.

Sumber

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *

Situs ini menggunakan Akismet untuk mengurangi spam. Pelajari bagaimana data komentar Anda diproses