Mengolah data mentah menjadi feature yang benar-benar dipakai model: encoding kategorikal, scaling numerik, feature selection, dan menyusun feature pipeline yang konsisten antara training dan serving, termasuk praktik menjalankan transformasi di skala produksi

Setelah di episode 3 kita merapikan kode Python menjadi modul produksi, pada episode ini kita bekerja pada bagian yang paling menentukan performa model: feature engineering. Model hanya sebagus feature yang diberi makan — seorang MLE senior akan berkata "garbage features in, garbage model out", dan ungkapan itu benar.
Bagian tersulit feature engineering di produksi bukanlah membuat transformasi yang bagus — itu bagian yang menyenangkan. Bagian tersulitnya adalah menjamin transformasi yang sama diterapkan saat training dan saat serving, agar data yang diterima model di produksi persis seperti data yang dilihatnya saat dilatih. Episode ini membahas tiga transformasi inti plus arsitektur feature pipeline yang konsisten.
Model matematika hanya mengerti angka. Data kategorikal harus diubah, dan pilihan metode encoding sangat menentukan kualitas model.
| Metode | Cocok untuk | Catatan |
|---|---|---|
| Label encoding | Data ordinal (misal rendah → 0, tinggi → 2) | Jangan dipakai untuk data nominal |
| One-hot encoding | Data nominal dengan sedikit kategori | Explode dimensi jika banyak kategori |
| Target/mean encoding | Kategori banyak & ada hubungan target | Rentan target leakage — butuh cross-validation |
| Frequency/hash encoding | Kategori sangat banyak (ID user, URL) | Hemat memori, trade-off collision |
import pandas as pd
from sklearn.preprocessing import OneHotEncoder
df = pd.DataFrame({"tier": ["gold", "silver", "gold", "bronze"]})
encoder = OneHotEncoder(handle_unknown="ignore", sparse_output=False)
encoded = encoder.fit_transform(df[["tier"]])
print(encoded)Perhatikan handle_unknown="ignore": kategori baru yang muncul saat serving (misal "diamond") tidak boleh membuat pipeline crash — ia akan di-encode sebagai nol.
Model yang sensitif terhadap skala (logistic regression, kNN, SVM, neural network) butuh feature pada rentang yang sebanding. Dua pilihan utama:
0..1. Bagus untuk data terbatas tanpa outlier ekstrem.from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
pipe = Pipeline([
("scaler", StandardScaler()),
("clf", LogisticRegression(max_iter=1000)),
])
pipe.fit(X_train, y_train)Aturan yang tidak bisa ditawar: fit hanya boleh terjadi di data training. Transformasi untuk validation/test/serving harus memakai transform dari scaler yang sama. Menyalahi aturan ini = data leakage yang membuat metrik kalian tidak jujur.
Tidak semua feature berguna. Terlalu banyak feature membuat model lambat, lebih sulit dijelaskan, dan rawan overfit. Tiga strategi umum:
from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import RandomForestClassifier
selector = SelectFromModel(RandomForestClassifier(n_estimators=200, random_state=42), threshold="median")
X_selected = selector.fit_transform(X_train, y_train)
print("fitur terpilih:", selector.get_feature_names_out())Feature selection juga berfungsi sebagai biasa kita perlu menjaga: pipeline produksi idealnya tidak membawa ratusan feature yang tidak dipakai — setiap feature ekstra adalah potensi sumber drift dan biaya compute.
Ini adalah core episode ini. Transformasi feature harus hidup di satu tempat dan dipakai di kedua sisi:
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
preprocessor = ColumnTransformer([
("num", StandardScaler(), ["age", "event_count"]),
("cat", OneHotEncoder(handle_unknown="ignore"), ["tier"]),
])
train_pipeline = Pipeline([
("preprocess", preprocessor),
("clf", LogisticRegression(max_iter=1000)),
])
train_pipeline.fit(X_train, y_train)Saat serving, pipeline yang sama dipakai untuk transformasi request:
import pickle
with open("model.pkl", "wb") as f:
pickle.dump(train_pipeline, f)
# di service lain, load dan predict
with open("model.pkl", "rb") as f:
model = pickle.load(f)
pred = model.predict_proba([{"age": 34, "event_count": 12, "tier": "gold"}])Karena transformasi dan model tersimpan dalam satu object, training-serving skew hilang secara struktural — bukan karena disiplin tim.
Saat data besar atau transformasi berat, pipeline naik skala dengan dua pola:
Pola yang harus dihindari adalah menghitung feature dengan dua implementasi berbeda (satu di notebook untuk training, satu di service untuk serving) — ini bom waktu.
Important
Aturan praktis feature pipeline: satu kode, dua mode. Simpan transformasi sebagai artifact (pickle/joblib/MLflow) yang di-versioning. Jika transformasi berubah, model harus dilatih ulang dengan transformasi baru — jangan pernah mencampur versi.
| Pitfall | Dampak | Pencegahan |
|---|---|---|
| Fit scaler/encoder pada seluruh data | Data leakage, metrik tidak jujur | Fit hanya di training set |
handle_unknown tidak diset | Serving crash saat kategori baru | Set ignore pada encoder |
| Transformasi ganda (notebook + service) | Training-serving skew | Satu artifact pipeline |
| One-hot untuk kategori ribuan | Dimensi meledak, memori boros | Frequency/hash encoding |
| Feature selection tanpa baseline | Terlalu banyak feature, overfit | Uji terhadap baseline sederhana |
Pada episode 4 ini, kalian telah menguasai transformasi feature:
Di episode 5 selanjutnya kita akan membahas Training & Validation Best Practices — train/val/test split yang benar, cross-validation, hyperparameter tuning, dan cara menyusun pipeline training yang terstruktur dan jujur terhadap target bisnis. Sampai jumpa di episode 5!