ML Workflow End-to-End

4 jam12 min baca
Tujuan

Paham pipeline ML lengkap dari raw data sampai deployment. Saat kelas bahas detail tiap step, kamu sudah punya gambaran besar.

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_split membagi 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:

  1. Load full dataset
  2. Split jadi train (60%) + temp (40%)
  3. Split temp jadi val (50%) + test (50%) β†’ 20% val + 20% test
  4. Pakai train untuk fit() model
  5. Pakai val untuk tuning hyperparameter (boleh diulang berkali-kali)
  6. 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:

  1. Bagi data jadi 5 chunk equal
  2. Iter 1: train dengan fold 2-5, test dengan fold 1 β†’ score₁
  3. Iter 2: train dengan fold 1, 3-5, test dengan fold 2 β†’ scoreβ‚‚
  4. Lanjut sampai iter 5
  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/predict API?
  • 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:

  1. Load + EDA cepat
  2. Preprocess (encoding + scaling)
  3. Split data
  4. Train 3 model: Logistic Regression, Random Forest, KNN
  5. Bandingkan score
  6. Tune Random Forest dengan GridSearchCV
  7. Final evaluation di test set

Notebook lengkap, push ke GitHub.


Selanjutnya: 02-supervised-classification.md