01 β ML Workflow End-to-End
Estimasi: 4 jam Tujuan: Paham pipeline ML lengkap dari raw data sampai deployment. Saat kelas bahas detail tiap step, kamu sudah punya gambaran besar.
Kenapa Materi Ini Penting?
Banyak pemula langsung loncat ke model training tanpa paham pipeline lengkapnya β lalu bingung kenapa hasilnya jelek. Memahami workflow end-to-end (dari data cleaning sampai deployment) memberi kamu gambaran besar yang akan membuat setiap materi detail di bootcamp langsung "klik" di tempatnya. Di kelas nanti, saat instruktur bahas cross-validation atau feature engineering, kamu sudah tahu di mana posisinya dalam pipeline dan kenapa step itu penting. Ini bedanya siswa yang cuma ikut alur vs yang benar-benar paham apa yang sedang dibangun.
ML Pipeline (Big Picture)
Analogi: Jalur Perakitan Pabrik
Bayangkan kamu punya pabrik mobil. Bahan mentah (besi, plastik, kaca) tidak bisa langsung jadi mobil. Harus lewat banyak stasiun: bahan dipotong, dibentuk, dirakit, dicat, diuji, baru dikirim ke dealer. Kalau salah satu stasiun rusak, mobil keluar cacat. ML pipeline persis sama. Raw data tidak bisa langsung jadi prediksi. Harus lewat data cleaning, feature engineering, training, evaluation, baru deploy. Tiap stasiun penting, tiap stasiun bisa jadi titik kegagalan.
Diagram statis Mermaid sebagai fallback:
flowchart LR
A["π₯ Raw<br/>Data"] --> B["π§Ή Data<br/>Cleaning"]
B --> C["π EDA<br/>Fase 4"]
C --> D["βοΈ Feature<br/>Engineering"]
D --> E["βοΈ Split<br/>Train/Val/Test"]
E --> F["π― Model<br/>Selection"]
F --> G["π€ Training"]
G --> H["π Evaluation"]
H --> I{"Bagus?"}
I -->|Tidak| J["π§ Hyperparameter<br/>Tuning"]
J --> G
I -->|Ya| K["πΎ Final<br/>Model"]
K --> L["π Deployment"]
Setiap step ada teknik dan tools. Kita walkthrough cepat.
Analogi Tiap Step
| Step | Analogi |
|---|---|
| Data Cleaning | Cuci sayur sebelum dimasak β buang yang busuk, bersihkan kotoran |
| Feature Engineering | Chef memotong, memarinasi, menyiapkan bahan agar siap masuk wajan |
| Train/Val/Test Split | Bagi soal latihan: ada untuk belajar, untuk simulasi, untuk ujian |
| Model Selection | Pilih alat masak: wok, oven, atau microwave? Tergantung masakan |
| Training | Murid belajar dari contoh soal beserta jawabannya |
| Evaluation | Ujian β cek murid benar-benar paham atau cuma menghafal |
| Hyperparameter Tuning | Atur api kompor: terlalu kecil tidak matang, terlalu besar gosong |
| Deployment | Buka restoran β masakan siap dijual ke pelanggan |
Step 1: Data Cleaning
(Sudah di Fase 4)
- Handle missing data (drop / impute)
- Handle outliers
- Fix type errors
- Drop duplicates
Step 2: Feature Engineering
Transform raw data jadi fitur yang bisa dipelajari model.
Encoding Categorical
import pandas as pd
df = pd.DataFrame({"kota": ["Bandung", "Jakarta", "Surabaya"]})
# One-hot
encoded = pd.get_dummies(df["kota"], prefix="kota")
# kota_Bandung kota_Jakarta kota_Surabaya
# True False False
# False True False
# False False True
# Label encoding (untuk ordinal)
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
df["kota_le"] = le.fit_transform(df["kota"])
Scaling Numerical
from sklearn.preprocessing import StandardScaler, MinMaxScaler
scaler = StandardScaler() # mean=0, std=1
X_scaled = scaler.fit_transform(X)
scaler = MinMaxScaler() # range 0-1
X_scaled = scaler.fit_transform(X)
Aturan: scaling penting untuk algoritma yang sensitive ke scale (KNN, SVM, neural network). Tidak penting untuk tree-based (decision tree, random forest).
Feature Creation
# Domain knowledge
df["bmi"] = df["weight"] / df["height"]**2
df["age_squared"] = df["age"] ** 2
# Interaction
df["price_per_sqm"] = df["price"] / df["area"]
# Datetime
df["day_of_week"] = pd.to_datetime(df["date"]).dt.dayofweek
Feature Selection
# Correlation threshold
corr_with_target = df.corrwith(df["target"]).abs().sort_values(ascending=False)
top_features = corr_with_target.head(10).index
# sklearn
from sklearn.feature_selection import SelectKBest, f_classif
selector = SelectKBest(f_classif, k=10)
X_selected = selector.fit_transform(X, y)
Step 3: Train/Test Split
Analogi: Buku Latihan vs Soal Ujian
Murid yang belajar pakai buku latihan, lalu ujian pakai soal yang sama persis, tidak benar-benar paham, dia cuma hafal. Makanya guru selalu pisahkan: soal latihan untuk belajar, soal ujian disembunyikan sampai hari-H. ML sama. Train data = buku latihan, test data = soal ujian. Model tidak boleh lihat test data sampai evaluasi final.
Cara Membaca Diagram:
- Atas: full dataset 100%
- Tengah:
train_test_splitmembagi jadi 3 set - Bawah: tiap set punya peran berbeda β Train untuk belajar, Val untuk tuning, Test (yang merah/locked) hanya disentuh sekali untuk evaluasi final
Walkthrough Step-by-Step:
- Load full dataset
- Split jadi train (60%) + temp (40%)
- Split temp jadi val (50%) + test (50%) β 20% val + 20% test
- Pakai train untuk
fit()model - Pakai val untuk tuning hyperparameter (boleh diulang berkali-kali)
- Setelah model final, sentuh test SEKALI untuk laporan akurasi sebenarnya
Analogi Sehari-hari: Belajar UN. Buku latihan = train. Try-out = validation. UN asli = test (disegel sampai hari H, tidak boleh diintip).
Diagram statis Mermaid sebagai fallback:
flowchart TD
A["π¦ Full Dataset<br/>(100%)"] --> B["βοΈ train_test_split"]
B --> C["π Train Set<br/>(60%)"]
B --> D["π Validation Set<br/>(20%)"]
B --> E["π Test Set<br/>(20%)"]
C --> F["π€ Latih model<br/>fit()"]
D --> G["π§ Tuning<br/>hyperparameter"]
E --> H["π Evaluasi final<br/>(SEKALI saja)"]
style E fill:#ffe0e0
style H fill:#ffe0e0
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
X, y,
test_size=0.2,
random_state=42, # reproducibility!
stratify=y # untuk classification β pertahankan class proportion
)
Train/Val/Test (Lebih Robust)
# 60% train, 20% val, 20% test
X_temp, X_test, y_temp, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
X_train, X_val, y_train, y_val = train_test_split(X_temp, y_temp, test_size=0.25, random_state=42)
Step 4: Model Selection
Pilih algoritma berdasarkan masalah:
Supervised Classification
| Dataset | Recommended |
|---|---|
| Small, simple | Logistic Regression, KNN |
| Tabular medium | Random Forest, XGBoost |
| Image | CNN (Fase 6) |
| Text | LSTM, Transformer (Fase 6) |
Supervised Regression
| Dataset | Recommended |
|---|---|
| Linear relationship | Linear Regression |
| Non-linear, tabular | Random Forest, XGBoost |
| High-dim, small | Ridge, Lasso |
Unsupervised
- Clustering β K-Means, DBSCAN
- Dim reduction β PCA, t-SNE, UMAP
Step 5: Training (sklearn API)
sklearn API konsisten untuk semua model:
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
# Pilih model
model = LogisticRegression(max_iter=1000)
# atau
model = RandomForestClassifier(n_estimators=100, random_state=42)
# Train
model.fit(X_train, y_train)
# Predict
y_pred = model.predict(X_test)
# Probability (kalau classification)
y_proba = model.predict_proba(X_test)
# Score (default metric)
accuracy = model.score(X_test, y_test)
Pattern emas:
model.fit(X, y)βmodel.predict(X_new). Berlaku untuk SEMUA sklearn model.
Step 6: Evaluation
Classification
from sklearn.metrics import (
accuracy_score, precision_score, recall_score, f1_score,
confusion_matrix, classification_report,
roc_auc_score, roc_curve
)
print(f"Accuracy: {accuracy_score(y_test, y_pred):.4f}")
print(f"Precision: {precision_score(y_test, y_pred):.4f}")
print(f"Recall: {recall_score(y_test, y_pred):.4f}")
print(f"F1: {f1_score(y_test, y_pred):.4f}")
print(classification_report(y_test, y_pred))
# Confusion matrix
cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot=True, fmt="d")
Regression
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
import numpy as np
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
mae = mean_absolute_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
Step 7: Hyperparameter Tuning
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV
# Define grid
param_grid = {
"n_estimators": [100, 200, 500],
"max_depth": [None, 10, 20, 30],
"min_samples_split": [2, 5, 10],
}
# Grid search dengan cross-validation
grid = GridSearchCV(
RandomForestClassifier(random_state=42),
param_grid,
cv=5, # 5-fold CV
scoring="f1",
n_jobs=-1 # parallelize
)
grid.fit(X_train, y_train)
print(f"Best params: {grid.best_params_}")
print(f"Best score: {grid.best_score_:.4f}")
# Best model
best_model = grid.best_estimator_
Random Search (Lebih Cepat untuk Banyak Param)
from scipy.stats import randint
param_distributions = {
"n_estimators": randint(100, 1000),
"max_depth": [None] + list(range(5, 50)),
}
random_search = RandomizedSearchCV(
RandomForestClassifier(random_state=42),
param_distributions,
n_iter=50,
cv=5,
n_jobs=-1
)
random_search.fit(X_train, y_train)
Step 8: Cross-Validation
Analogi: Ujian Beberapa Kali dengan Soal Beda
Kalau murid cuma diuji sekali pakai 1 set soal, hasilnya bisa kebetulan. Bisa jadi soalnya kebetulan mudah, atau kebetulan dia hafal. Untuk benar-benar tahu kemampuannya, beri ujian 5 kali dengan soal beda-beda lalu rata-ratakan. Cross-validation begitu: bagi data jadi 5 fold, train pakai 4 fold, test pakai 1 fold yang berbeda tiap iterasi.
Cara Membaca Diagram:
- Atas: dataset β split jadi 5 fold ukuran sama
- Tengah: 5 iterasi, tiap iterasi pakai 1 fold sebagai test (rotasi)
- Bawah: 5 score dirata-ratakan Β± std deviasi
Walkthrough Step-by-Step:
- Bagi data jadi 5 chunk equal
- Iter 1: train dengan fold 2-5, test dengan fold 1 β scoreβ
- Iter 2: train dengan fold 1, 3-5, test dengan fold 2 β scoreβ
- Lanjut sampai iter 5
- Hitung mean(scores) Β± std(scores) β estimasi performa lebih reliable
Analogi Sehari-hari: Mau tahu seberapa kuat seorang pemanah? Jangan suruh tembak sekali β suruh tembak 5 kali dengan target berbeda, ambil rata-rata. Kalau std rendah berarti konsisten.
Diagram statis Mermaid sebagai fallback:
flowchart TD
A["π¦ Dataset"] --> B["Bagi 5 Fold"]
B --> C1["Iter 1: Test=Fold1, Train=2,3,4,5 β scoreβ"]
B --> C2["Iter 2: Test=Fold2, Train=1,3,4,5 β scoreβ"]
B --> C3["Iter 3: Test=Fold3, Train=1,2,4,5 β scoreβ"]
B --> C4["Iter 4: Test=Fold4, Train=1,2,3,5 β scoreβ"]
B --> C5["Iter 5: Test=Fold5, Train=1,2,3,4 β scoreβ
"]
C1 --> D["π Mean Β± Std<br/>(skor lebih reliable)"]
C2 --> D
C3 --> D
C4 --> D
C5 --> D
from sklearn.model_selection import cross_val_score, KFold
# 5-fold CV
scores = cross_val_score(model, X, y, cv=5, scoring="accuracy")
print(f"CV scores: {scores}")
print(f"Mean: {scores.mean():.4f} Β± {scores.std():.4f}")
Wajib pakai CV untuk dataset kecil-medium. Single split bisa misleading.
Step 9: Pipeline (Best Practice)
Analogi: Resep yang Otomatis
Pipeline adalah resep masak yang sudah ditulis lengkap urutannya. Kamu cukup pipeline.fit(data) dan dia akan otomatis: cuci β potong β tumis β bumbui β siap saji. Tanpa pipeline, kamu harus manual urut tiap step setiap kali β gampang lupa atau salah urutan, terutama saat di production.
flowchart LR
A["π₯ X_train"] --> B["βοΈ StandardScaler<br/>(fit + transform)"]
B --> C["π’ OneHotEncoder<br/>(fit + transform)"]
C --> D["π€ Model<br/>(fit)"]
D --> E["β
Pipeline siap"]
F["π₯ X_new"] --> G["pipeline.predict()"]
G --> H["βοΈ Scale<br/>(transform saja)"]
H --> I["π’ Encode<br/>(transform saja)"]
I --> J["π― Predict"]
style E fill:#d4f4dd
style J fill:#d4f4dd
Gabungkan preprocessing + model dalam Pipeline:
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
pipeline = Pipeline([
("scaler", StandardScaler()),
("classifier", LogisticRegression(max_iter=1000)),
])
pipeline.fit(X_train, y_train)
y_pred = pipeline.predict(X_test)
Keuntungan:
- Atomic β train/predict consistent
- Tidak ada data leakage (scaler fit di train saja)
- Easy untuk grid search
# Grid search di pipeline
param_grid = {
"classifier__C": [0.1, 1, 10], # double underscore!
"scaler": [StandardScaler(), MinMaxScaler()],
}
grid = GridSearchCV(pipeline, param_grid, cv=5)
ColumnTransformer (Numeric + Categorical)
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder
numeric_features = ["age", "income"]
categorical_features = ["city", "education"]
preprocessor = ColumnTransformer([
("num", StandardScaler(), numeric_features),
("cat", OneHotEncoder(handle_unknown="ignore"), categorical_features),
])
pipeline = Pipeline([
("preprocessor", preprocessor),
("classifier", LogisticRegression()),
])
pipeline.fit(X_train, y_train)
Step 10: Save Model
import joblib
# Save
joblib.dump(pipeline, "model.pkl")
# Load
model = joblib.load("model.pkl")
y_pred = model.predict(X_new)
Common Pitfalls
Analogi: Kesalahan Klasik Pemula
flowchart TD
A["β οΈ Common Pitfalls"] --> B["π§ Data Leakage"]
A --> C["βοΈ Imbalanced Class<br/>diabaikan"]
A --> D["π― Tune di Test Set"]
A --> E["π² Tidak set<br/>random_state"]
A --> F["π Lupa<br/>feature scaling"]
A --> G["π Evaluate di<br/>training set"]
style A fill:#ffe0e0
1. Data Leakage
β Fit scaler di seluruh dataset sebelum split:
scaler.fit(X) # leaks test info ke scaler
X_scaled = scaler.transform(X)
X_train, X_test = train_test_split(X_scaled, ...)
β Fit di train saja:
X_train, X_test = train_test_split(X, ...)
scaler.fit(X_train)
X_train_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)
# Atau pakai pipeline (auto correct)
2. Tidak Stratify Classification
β train_test_split(X, y) tanpa stratify untuk imbalanced data β split bisa skip class minor.
β
train_test_split(X, y, stratify=y).
3. Optimasi pada Test Set
β Tune hyperparameter pakai test set β kamu fit ke test data β overfitting.
β Pakai validation set atau CV. Test set hanya untuk evaluasi final sekali.
4. Tidak Set random_state
β Hasil tidak reproducible.
β
random_state=42 di mana-mana.
5. Class Imbalance Tidak Di-handle
Kalau 95% class A, 5% class B β model predict A doang dapat 95% accuracy tapi useless.
β Pakai:
class_weight="balanced"di model- Resampling (SMOTE, undersampling)
- Lihat F1, ROC-AUC bukan accuracy
6. Evaluasi di Training Set
β model.fit(X_train, y_train) lalu model.score(X_train, y_train) β score selalu tinggi tapi misleading. Model bisa hafalkan training, tapi gagal di data baru.
β Selalu evaluasi di test set atau pakai cross-validation.
7. Lupa Feature Scaling
Untuk algoritma berbasis jarak (KNN, SVM, K-Means) atau gradient (Logistic Regression, Neural Network), feature dengan skala besar mendominasi. Misal gaji (jutaan) vs umur (puluhan) β gaji mendominasi padahal umur juga penting.
β
Pakai StandardScaler atau MinMaxScaler sebelum fit.
FAQ β Pertanyaan yang Sering Muncul
Q: Kenapa hasil saya beda tiap run?
A: Belum set random_state. Banyak step di sklearn pakai randomness (split, init model, bootstrap). Set random_state=42 di mana-mana.
Q: Train accuracy 99%, test accuracy 70%. Kenapa? A: Klasik overfitting. Model menghafal training. Solusi: regularization, kurangi complexity, lebih banyak data, atau cross-validation.
Q: Train accuracy 60%, test accuracy 60%. Kenapa? A: Underfitting. Model terlalu sederhana atau feature tidak cukup informatif. Solusi: model lebih kompleks, feature engineering lebih agresif.
Q: Pipeline atau langkah manual? A: Selalu pipeline kalau bisa. Mencegah data leakage, memudahkan deployment, dan kompatibel dengan GridSearchCV.
Q: Saya harus pilih K-Fold yang berapa? A: 5 atau 10 fold standar. Dataset kecil β 10 fold (lebih reliable). Dataset besar β 5 fold (lebih cepat).
Cek Pemahaman
- Tahu 10 step ML pipeline?
- Bisa pakai sklearn
fit/predictAPI? - Bisa bikin Pipeline dengan preprocessing?
- Tahu beda accuracy vs F1 vs AUC?
- Bisa GridSearchCV untuk tuning?
- Tahu bahaya data leakage?
Challenge 5.1
Challenge β Build Your First Pipeline
Pakai dataset Iris atau Titanic:
- Load + EDA cepat
- Preprocess (encoding + scaling)
- Split data
- Train 3 model: Logistic Regression, Random Forest, KNN
- Bandingkan score
- Tune Random Forest dengan GridSearchCV
- Final evaluation di test set
Notebook lengkap, push ke GitHub.
Selanjutnya: 02-supervised-classification.md