Optimasi Hyperparameter Pipeline dengan GridSearchCV
Pada materi sebelumnya, kita telah mempelajari bagaimana menggabungkan proses preprocessing dan model Machine Learning menggunakan Scikit-Learn Pipeline.
Pipeline memungkinkan kita membuat alur seperti:
Data
↓
Preprocessing
↓
Transformasi
↓
Model
↓
Prediksi
Kita juga telah mempelajari bahwa sebuah Pipeline dapat terdiri dari beberapa tahapan, misalnya:
SimpleImputerOneHotEncoderColumnTransformerRandomForestRegressor
Setelah Pipeline berhasil dibuat, langkah berikutnya adalah mencari konfigurasi hyperparameter yang lebih baik.
Untuk melakukan proses tersebut, kita dapat menggunakan GridSearchCV atau yang lainnya.
Pada materi ini kita akan mempelajari bagaimana menggunakan GridSearchCV untuk melakukan hyperparameter tuning langsung pada Pipeline.
Apa Itu Hyperparameter Tuning?
Hyperparameter tuning adalah proses mencari kombinasi hyperparameter yang memberikan performa terbaik untuk sebuah model.
Contohnya, Random Forest memiliki beberapa hyperparameter:
n_estimators
max_depth
max_features
min_samples_split
min_samples_leaf
Misalnya kita ingin mencoba:
n_estimators
→ 100
→ 500
→ 1000
dan:
max_depth
→ None
→ 5
→ 10
Daripada mencoba semuanya secara manual, kita dapat menggunakan GridSearchCV.
GridSearchCV
GridSearchCV merupakan fitur Scikit-Learn yang dapat mencoba berbagai kombinasi hyperparameter yang telah kita tentukan.
Misalnya kita memiliki:
param_grid = {
"n_estimators": [100, 500],
"max_depth": [None, 5]
}
Maka terdapat beberapa kombinasi:
n_estimators = 100
max_depth = None
n_estimators = 100
max_depth = 5
n_estimators = 500
max_depth = None
n_estimators = 500
max_depth = 5
GridSearchCV akan mencoba kombinasi tersebut sesuai konfigurasi yang kita berikan.
GridSearchCV pada Pipeline
Ketika menggunakan Pipeline, terdapat satu hal penting yang harus diperhatikan.
Misalnya Pipeline kita memiliki struktur:
Pipeline
│
├── preprocessor
│
│ ├── cat
│ ├── door
│ └── num
│
└── regressor
Kita mungkin ingin mengubah parameter pada:
- preprocessing
- imputer
- encoder
- model
Untuk mengakses parameter yang berada di dalam Pipeline, kita menggunakan tanda:
__
atau disebut double underscore.
Apa Itu Double Underscore?
Double underscore digunakan untuk menelusuri struktur step di dalam Pipeline.
Format dasarnya:
nama_step__nama_parameter
Jika terdapat beberapa tingkatan:
nama_step__sub_step__parameter
Bahkan jika strukturnya lebih dalam:
step__sub_step__sub_sub_step__parameter
Double underscore memungkinkan kita mengakses parameter yang berada di dalam struktur Pipeline.
Contoh Struktur Pipeline
Misalnya kita memiliki Pipeline utama:
model = Pipeline(
steps=[
(
"preprocessor",
preprocessor
),
(
"regressor",
RandomForestRegressor(
random_state=42
)
)
]
)
Pipeline memiliki dua step:
preprocessor
regressor
Kemudian preprocessor memiliki ColumnTransformer:
preprocessor
│
├── cat
├── door
└── num
Kemudian num memiliki Pipeline:
num
│
└── imputer
Sehingga struktur lengkapnya:
model
│
├── preprocessor
│ │
│ ├── cat
│ │
│ ├── door
│ │
│ └── num
│ │
│ └── imputer
│
└── regressor
Mengakses Parameter Preprocessing
Misalnya kita ingin mengubah strategi SimpleImputer pada feature numerik.
Pipeline memiliki struktur:
preprocessor
↓
num
↓
imputer
↓
strategy
Maka kita menggunakan:
"preprocessor__num__imputer__strategy"
Formatnya:
preprocessor
↓
num
↓
imputer
↓
strategy
Contohnya:
"preprocessor__num__imputer__strategy": [
"mean",
"median"
]
GridSearchCV kemudian akan mencoba:
strategy = mean
strategy = median
Mengakses Hyperparameter Model
Untuk mengakses hyperparameter model yang berada langsung di dalam Pipeline, kita menggunakan:
nama_step_model__hyperparameter
Misalnya step model kita bernama:
"regressor"
dan modelnya adalah:
RandomForestRegressor
Maka:
"regressor__n_estimators"
digunakan untuk mengakses n_estimators.
Contoh:
"regressor__n_estimators": [
100,
500,
1000
]
Begitu juga:
"regressor__max_depth": [
None,
5,
10
]
Contoh Parameter Grid
Misalnya kita ingin melakukan tuning terhadap:
- strategi imputasi numerik
- jumlah tree
- kedalaman tree
- jumlah feature yang digunakan
- minimum sample untuk split
Kita dapat membuat:
pipe_grid = {
"preprocessor__num__imputer__strategy": [
"mean",
"median"
],
"regressor__n_estimators": [
100,
500
],
"regressor__max_depth": [
None,
5
],
"regressor__max_features": [
1.0,
"sqrt"
],
"regressor__min_samples_split": [
2,
4
]
}
Perhatikan bahwa kita menggunakan:
"regressor__..."
karena nama step model pada Pipeline adalah:
"regressor"
Mengapa Menggunakan max_features=1.0?
Pada contoh materi lama, kita mungkin menemukan:
"max_features": ["auto"]
Namun, parameter tersebut tidak lagi menjadi pilihan yang tepat untuk contoh RandomForestRegressor pada versi Scikit-Learn modern.
Untuk Random Forest Regressor, kita dapat menggunakan misalnya:
1.0
atau:
"sqrt"
1.0 berarti seluruh feature dipertimbangkan ketika mencari split.
Sedangkan:
"sqrt"
menggunakan akar kuadrat dari jumlah feature.
Dengan demikian, contoh yang lebih aman untuk versi Scikit-Learn modern adalah:
"regressor__max_features": [
1.0,
"sqrt"
]
Menghitung Jumlah Kombinasi
Sebelum menjalankan GridSearchCV, penting untuk mengetahui berapa banyak kombinasi yang akan dicoba.
Misalnya:
pipe_grid = {
"preprocessor__num__imputer__strategy": [
"mean",
"median"
],
"regressor__n_estimators": [
100,
500
],
"regressor__max_depth": [
None,
5
],
"regressor__max_features": [
1.0,
"sqrt"
],
"regressor__min_samples_split": [
2,
4
]
}
Masing-masing memiliki 2 pilihan.
Maka jumlah kombinasi:
2 × 2 × 2 × 2 × 2
yaitu:
32 kombinasi
Jika kita menggunakan:
cv=5
maka setiap kombinasi akan dievaluasi menggunakan 5 fold.
Secara sederhana:
32 kombinasi × 5 fold
= 160 proses fitting
Semakin banyak parameter dan pilihan yang dimasukkan ke dalam grid, semakin besar waktu komputasi yang dibutuhkan.
Import GridSearchCV
Sekarang kita dapat mengimpor:
from sklearn.model_selection import GridSearchCV
Membuat GridSearchCV
Kita dapat membuat objek GridSearchCV:
gs_model = GridSearchCV(
estimator=model,
param_grid=pipe_grid,
cv=5,
verbose=2,
n_jobs=-1
)
Mari kita pahami setiap parameter.
estimator
estimator=model
model merupakan Pipeline yang telah kita buat sebelumnya.
Artinya GridSearchCV akan melakukan tuning terhadap seluruh Pipeline.
param_grid
param_grid=pipe_grid
Berisi daftar parameter yang ingin dicoba.
cv
cv=5
Menentukan jumlah fold yang digunakan dalam proses evaluasi internal GridSearchCV.
Pembahasan lebih mendalam mengenai Cross-Validation akan dibahas pada materi khusus berikutnya.
Untuk materi ini, cukup pahami bahwa cv=5 membuat setiap kombinasi parameter dievaluasi menggunakan 5 bagian data.
verbose
verbose=2
Digunakan untuk menampilkan informasi proses pencarian parameter.
Semakin tinggi nilainya, semakin banyak informasi yang ditampilkan.
n_jobs
n_jobs=-1
Memberitahu Scikit-Learn untuk menggunakan seluruh CPU core yang tersedia untuk proses paralel jika memungkinkan.
Hal ini dapat membantu mempercepat proses pencarian.
Melatih GridSearchCV
Setelah objek GridSearchCV dibuat, kita menjalankannya dengan:
gs_model.fit(
X_train,
y_train
)
GridSearchCV kemudian akan:
Pipeline
↓
Parameter Combination 1
↓
Evaluasi
Pipeline
↓
Parameter Combination 2
↓
Evaluasi
Pipeline
↓
Parameter Combination 3
↓
Evaluasi
...
Proses tersebut berlangsung hingga seluruh kombinasi yang terdapat pada pipe_grid selesai diuji.
Melihat Hyperparameter Terbaik
Setelah proses selesai, kita dapat melihat parameter terbaik menggunakan:
gs_model.best_params_
Contohnya dapat menghasilkan:
{
"preprocessor__num__imputer__strategy": "median",
"regressor__max_depth": 5,
"regressor__max_features": "sqrt",
"regressor__min_samples_split": 2,
"regressor__n_estimators": 500
}
Hasil tersebut menunjukkan kombinasi parameter yang menghasilkan skor terbaik berdasarkan konfigurasi pencarian.
Perhatikan bahwa hasil aktual dapat berbeda tergantung dataset, versi library, dan konfigurasi yang digunakan.
Melihat Skor Terbaik
Kita juga dapat melihat skor terbaik menggunakan:
gs_model.best_score_
Nilai tersebut merupakan skor terbaik yang diperoleh selama proses pencarian.
Penting untuk dipahami bahwa:
gs_model.best_score_
bukanlah skor dari data test akhir.
Skor tersebut merupakan hasil evaluasi internal selama proses pencarian parameter.
Mengevaluasi Model pada Data Test
Setelah parameter terbaik ditemukan, kita dapat mengevaluasi model pada data test yang sebelumnya tidak digunakan sebagai bagian dari pencarian.
test_score = gs_model.score(
X_test,
y_test
)
test_score
Karena model yang digunakan adalah:
RandomForestRegressor
maka:
score()
menghasilkan nilai:
R²
Memahami Alur GridSearchCV pada Pipeline
Secara keseluruhan, alurnya menjadi:
Dataset
↓
Train-Test Split
│
├───────────────┐
│ │
▼ ▼
X_train X_test
│ │
▼ │
Pipeline │
│ │
├── Preprocessor│
│ │
└── Model │
│ │
▼ │
GridSearchCV │
│ │
▼ │
Parameter Terbaik │
│ │
└───────────────┘
↓
Evaluasi Test
Dengan pendekatan ini, kita dapat melakukan tuning terhadap Pipeline sebagai satu kesatuan.
Contoh Lengkap
Berikut contoh lengkap berdasarkan Pipeline pada materi sebelumnya.
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder
from sklearn.ensemble import RandomForestRegressor
# Load dataset
data = pd.read_csv(
"car-sales-extended-missing-data.csv"
)
# Separate features and target
X = data.drop(
"Price",
axis=1
)
y = data["Price"]
# Split data
X_train, X_test, y_train, y_test = train_test_split(
X,
y,
test_size=0.2,
random_state=42
)
# Define feature groups
categorical_features = [
"Make",
"Colour"
]
door_feature = [
"Doors"
]
numeric_features = [
"Odometer (KM)"
]
# Categorical pipeline
categorical_transformer = Pipeline(
steps=[
(
"imputer",
SimpleImputer(
strategy="constant",
fill_value="missing"
)
),
(
"onehot",
OneHotEncoder(
handle_unknown="ignore"
)
)
]
)
# Door pipeline
door_transformer = Pipeline(
steps=[
(
"imputer",
SimpleImputer(
strategy="constant",
fill_value=4
)
)
]
)
# Numeric pipeline
numeric_transformer = Pipeline(
steps=[
(
"imputer",
SimpleImputer(
strategy="mean"
)
)
]
)
# ColumnTransformer
preprocessor = ColumnTransformer(
transformers=[
(
"cat",
categorical_transformer,
categorical_features
),
(
"door",
door_transformer,
door_feature
),
(
"num",
numeric_transformer,
numeric_features
)
]
)
# Pipeline
model = Pipeline(
steps=[
(
"preprocessor",
preprocessor
),
(
"regressor",
RandomForestRegressor(
random_state=42
)
)
]
)
# Parameter grid
pipe_grid = {
"preprocessor__num__imputer__strategy": [
"mean",
"median"
],
"regressor__n_estimators": [
100,
500
],
"regressor__max_depth": [
None,
5
],
"regressor__max_features": [
1.0,
"sqrt"
],
"regressor__min_samples_split": [
2,
4
]
}
# GridSearchCV
gs_model = GridSearchCV(
estimator=model,
param_grid=pipe_grid,
cv=5,
verbose=2,
n_jobs=-1
)
# Train GridSearchCV
gs_model.fit(
X_train,
y_train
)
# Best parameters
print("Best Parameters:")
print(gs_model.best_params_)
# Best CV score
print("Best Score:")
print(gs_model.best_score_)
# Test score
print("Test Score:")
print(gs_model.score(
X_test,
y_test
))
Mendapatkan Model Terbaik
GridSearchCV menyediakan atribut:
best_estimator_
yang berisi estimator terbaik yang ditemukan.
Kita dapat mengaksesnya:
best_model = gs_model.best_estimator_
Sekarang:
best_model
merupakan Pipeline dengan konfigurasi terbaik yang ditemukan oleh GridSearchCV.
Menggunakan Model Terbaik untuk Prediksi
Setelah mendapatkan model terbaik:
best_model = gs_model.best_estimator_
kita dapat membuat prediksi:
predictions = best_model.predict(
X_test
)
Pipeline terbaik akan tetap menjalankan preprocessing secara otomatis sebelum menghasilkan prediksi.
Melihat Struktur Model Terbaik
Kita dapat melihat step dalam model terbaik:
best_model.named_steps
Kita juga dapat mengakses model Random Forest:
best_model.named_steps["regressor"]
Dengan demikian, kita dapat melihat konfigurasi Random Forest yang terpilih.
Mengapa Double Underscore Sangat Penting?
Tanpa double underscore:
"regressor_n_estimators"
Scikit-Learn tidak akan memahami bahwa kita ingin mengakses parameter n_estimators dari step regressor.
Format yang benar:
"regressor__n_estimators"
Perhatikan perbedaannya:
Salah:
regressor_n_estimators
Benar:
regressor__n_estimators
Ada dua underscore di antara nama step dan nama parameter.
Parameter Bertingkat
Untuk parameter yang lebih dalam, jumlah level akan menentukan jumlah double underscore.
Misalnya:
model
↓
preprocessor
↓
num
↓
imputer
↓
strategy
Maka:
"preprocessor__num__imputer__strategy"
dapat dibaca:
preprocessor
↓
num
↓
imputer
↓
strategy
Sedangkan:
model
↓
regressor
↓
n_estimators
menjadi:
"regressor__n_estimators"
Melihat Semua Parameter Pipeline
Kita dapat menggunakan:
model.get_params()
untuk melihat seluruh parameter yang tersedia dalam Pipeline.
Contohnya:
model.get_params()
akan menampilkan berbagai parameter dari:
- Pipeline.
- ColumnTransformer.
- SimpleImputer.
- OneHotEncoder.
- RandomForestRegressor.
Cara ini sangat berguna untuk mengetahui nama parameter yang dapat digunakan dalam GridSearchCV.
Teknik Menemukan Nama Parameter
Jika kita tidak yakin dengan nama parameter yang harus dimasukkan ke param_grid, kita dapat menggunakan:
model.get_params().keys()
Contohnya:
for parameter in model.get_params().keys():
print(parameter)
Kita dapat menemukan nama seperti:
preprocessor__num__imputer__strategy
regressor__n_estimators
regressor__max_depth
regressor__max_features
regressor__min_samples_split
Nama-nama tersebut kemudian dapat digunakan di dalam pipe_grid.
Pipeline + GridSearchCV
Sekarang kita dapat melihat hubungan antara Pipeline dan GridSearchCV.
Pipeline
Pipeline menjawab pertanyaan:
Bagaimana proses preprocessing dan model dijalankan secara berurutan?
Data
↓
Preprocessing
↓
Model
GridSearchCV
GridSearchCV menjawab pertanyaan:
Kombinasi parameter mana yang memberikan hasil terbaik berdasarkan konfigurasi pencarian?
Parameter A
Parameter B
Parameter C
↓
GridSearchCV
↓
Kombinasi Terbaik
Digabungkan
Pipeline
│
┌────────────┴────────────┐
│ │
Preprocessing Model
│ │
└────────────┬────────────┘
│
GridSearchCV
│
▼
Parameter Terbaik
Keuntungan Menggunakan GridSearchCV pada Pipeline
1. Preprocessing dan Model Dikelola Bersama
Kita dapat melakukan tuning terhadap preprocessing dan model dalam satu workflow.
Contohnya:
"preprocessor__num__imputer__strategy"
dan:
"regressor__n_estimators"
dapat berada dalam parameter grid yang sama.
2. Workflow Lebih Terstruktur
Daripada melakukan tuning secara manual:
Imputer
↓
Encoder
↓
Model 1
↓
Model 2
↓
Model 3
kita dapat mengatur semuanya melalui Pipeline dan GridSearchCV.
3. Mengurangi Risiko Kesalahan
Pipeline memastikan preprocessing tetap menjadi bagian dari workflow model.
4. Mudah Dikembangkan
Ketika preprocessing bertambah kompleks, struktur Pipeline tetap dapat digunakan.
Misalnya:
Imputer
↓
Encoder
↓
Scaler
↓
Feature Selection
↓
Model
GridSearchCV dapat digunakan untuk mengatur parameter pada berbagai step tersebut.
Perbedaan Tuning Model dan Tuning Pipeline
Tuning model secara langsung:
grid = {
"n_estimators": [100, 500],
"max_depth": [None, 5]
}
Sedangkan ketika model berada dalam Pipeline:
pipe_grid = {
"regressor__n_estimators": [100, 500],
"regressor__max_depth": [None, 5]
}
Perbedaannya adalah kita harus menyebutkan nama step terlebih dahulu.
Jika parameter berada lebih dalam:
"preprocessor__num__imputer__strategy"
kita harus mengikuti seluruh struktur Pipeline.
Hal yang Perlu Diperhatikan
GridSearchCV dapat menjadi sangat berat jika parameter grid terlalu besar.
Misalnya:
n_estimators = [100, 200, 500, 1000]
max_depth = [None, 5, 10, 20]
max_features = [1.0, "sqrt"]
min_samples_split = [2, 4, 6]
Jumlah kombinasi:
4 × 4 × 2 × 3
= 96 kombinasi
Jika menggunakan:
cv=5
maka proses evaluasi internal menjadi:
96 × 5
= 480 fitting
Jika model membutuhkan waktu lama untuk dilatih, proses ini dapat memakan waktu cukup lama.
Karena itu, parameter grid sebaiknya dirancang secara masuk akal.
GridSearchCV Tidak Selalu Menghasilkan Model Terbaik Secara Absolut
GridSearchCV hanya mencari kombinasi parameter yang tersedia di dalam param_grid.
Misalnya:
"regressor__n_estimators": [
100,
500
]
GridSearchCV hanya membandingkan:
100
vs
500
Jika ternyata nilai terbaik adalah:
750
GridSearchCV tidak akan menemukannya karena angka tersebut tidak berada dalam grid.
Karena itu, kualitas hasil GridSearchCV juga dipengaruhi oleh kualitas parameter grid yang kita tentukan.
Menentukan Parameter Grid secara Bertahap
Salah satu pendekatan yang baik adalah tidak langsung membuat grid yang sangat besar.
Misalnya kita mulai dari:
pipe_grid = {
"regressor__n_estimators": [
100,
500
],
"regressor__max_depth": [
None,
5,
10
]
}
Setelah mendapatkan gambaran parameter yang baik, kita dapat mempersempit atau memperluas pencarian pada area tertentu.
Pendekatan seperti ini membantu mengurangi beban komputasi.
GridSearchCV sebagai Bagian dari Workflow Machine Learning
Workflow Machine Learning sekarang menjadi lebih lengkap:
1. Define Problem
↓
2. Collect Data
↓
3. Explore Data
↓
4. Prepare Data
↓
5. Build Pipeline
↓
6. Train Model
↓
7. Tune Hyperparameters
↓
8. Evaluate Model
↓
9. Save Model
↓
10. Deploy Model
Pada materi ini kita berfokus pada bagian:
Build Pipeline
↓
Tune Hyperparameters
↓
Evaluate Model
Ringkasan
Pada materi ini kita telah mempelajari bagaimana menggunakan GridSearchCV pada Scikit-Learn Pipeline.
Konsep utama yang perlu diingat:
GridSearchCVdigunakan untuk mencari kombinasi hyperparameter terbaik dari parameter yang telah ditentukan.- Pipeline dapat digunakan sebagai
estimatorpadaGridSearchCV. - Parameter dalam Pipeline diakses menggunakan double underscore.
- Parameter langsung pada model menggunakan format seperti:
"regressor__n_estimators"
- Parameter preprocessing yang lebih dalam dapat menggunakan format seperti:
"preprocessor__num__imputer__strategy"
best_params_digunakan untuk melihat kombinasi parameter terbaik.best_score_digunakan untuk melihat skor terbaik selama pencarian.best_estimator_digunakan untuk mendapatkan Pipeline dengan konfigurasi terbaik.get_params()dapat digunakan untuk mengetahui nama parameter yang tersedia.- Grid yang terlalu besar dapat menyebabkan proses komputasi menjadi berat.
Konsep paling penting dari materi ini adalah:
Pipeline
↓
Preprocessing + Model
↓
GridSearchCV
↓
Mencoba Kombinasi Parameter
↓
Parameter Terbaik
↓
Model Terbaik
Dengan memahami konsep ini, kita sudah dapat melakukan hyperparameter tuning pada workflow Machine Learning yang memiliki preprocessing dan model dalam satu Pipeline.