RandomizedSearchCV

Kapan pencarian acak mengalahkan grid penuh.

Daftar isi

Topik ini membahas RandomizedSearchCV sebagai alternatif pencarian hyperparameter ketika ruang nilainya luas dan anggaran komputasi terbatas. Pembahasan mencakup kondisi ketika pencarian acak lebih menguntungkan daripada grid, yaitu kisi kombinasi nilai yang dicoba seluruhnya oleh pencarian GridSearchCV, cara mendefinisikan ruang pencarian sebagai distribusi dari scipy.stats, serta perbandingan nyata antara grid kecil dan pencarian acak dengan anggaran kandidat yang sama pada pipeline yang sama.

Kapan pencarian acak lebih menguntungkan#

Grid penuh menjamin tidak ada kombinasi yang terlewat, tetapi biayanya tumbuh mengikuti hasil kali ukuran setiap sumbu kisi. Ruang dengan sepuluh nilai per sumbu dan tiga sumbu memerlukan seribu kombinasi, sementara anggaran pelatihan yang tersedia sering kali hanya memuat puluhan. Kondisi ini memaksa salah satu pilihan, yaitu grid yang menyempitkan setiap sumbunya agar muat dalam anggaran, atau pencarian acak yang menarik sejumlah kandidat dari ruang yang tetap luas.

Pencarian acak mengungguli grid yang menyempit karena strukturnya. Grid seragam membelanjakan anggarannya secara merata pada nilai-nilai tetap per sumbu, sehingga memperluas cakupan satu sumbu berarti melipatgandakan seluruh kisi, sedangkan pencarian acak memperluas cakupan dengan tetap menggunakan anggaran yang sama melalui argumen n_iter. Kandidat acak yang lebih beragam memberi peluang lebih besar menemukan wilayah skor baik daripada nilai tetap yang melompat jauh di antara dekade nilai.

Kedua pendekatan tetap menggunakan mekanisme penilaian yang sama, yaitu cross-validation pada data latih untuk setiap kandidatnya. Perbedaannya hanya pada cara kandidat dibangkitkan, sehingga hasil keduanya dapat diperbandingkan secara adil apabila lipatan yang digunakan identik.

Ruang pencarian sebagai distribusi#

Ruang pencarian pada RandomizedSearchCV dinyatakan melalui argumen param_distributions, yaitu dictionary yang nilainya berupa daftar pilihan atau objek distribusi dari scipy.stats. Daftar pilihan ditarik secara acak sebagaimana grid, sedangkan distribusi kontinu memungkinkan setiap nilai di antara batasnya terpilih. Distribusi loguniform menarik nilai dengan peluang yang merata pada skala logaritmik sehingga 0.001 dan 1000 mendapat perhatian yang setara, sedangkan randint menarik bilangan bulat seragam pada rentang yang diberikan.

Kode berikut membandingkan delapan titik grid pada skala logaritmik dengan delapan sampel dari kedua distribusi tersebut.

python Contoh: nilai yang dihasilkan grid log-space, loguniform, dan randint
from scipy.stats import loguniform, randint
import numpy as np

c_grid = np.logspace(-3, 3, 8)
c_acak = loguniform.rvs(1e-3, 1e3, size=8, random_state=42)
n_acak = randint.rvs(1, 101, size=8, random_state=42)

print("Grid log-space, 8 titik    :", ", ".join(f"{v:.4f}" for v in c_grid))
print("Sampel loguniform, 8 nilai :", ", ".join(f"{v:.4f}" for v in c_acak))
print("Sampel randint, 8 nilai    :", ", ".join(str(v) for v in n_acak))
text Keluaran
Grid log-space, 8 titik    : 0.0010, 0.0072, 0.0518, 0.3728, 2.6827, 19.3070, 138.9495, 1000.0000
Sampel loguniform, 8 nilai : 0.1767, 506.1577, 24.6583, 3.9080, 0.0086, 0.0086, 0.0022, 157.4189
Sampel randint, 8 nilai    : 52, 93, 15, 72, 61, 21, 83, 87

Grid log-space menghasilkan titik yang teratur dengan jarak yang sama pada skala logaritmik, sedangkan sampel loguniform menyebar tanpa pola tetap di seluruh rentangnya. Kedua pendekatan menghabiskan delapan kandidat, tetapi sampel acaknya menjangkau posisi di antara titik grid yang tidak pernah dicoba. Untuk hyperparameter seperti C yang efeknya berjalan pada skala logaritmik, loguniform menjadi pilihan yang masuk akal karena regularisasi lemah dan kuat sama pentingnya untuk dijelajahi.

RandomizedSearchCV pada ruang yang lebih luas#

Kode berikut membandingkan dua pencarian dengan anggaran kandidat yang sama pada pipeline yang identik dengan topik GridSearchCV, yaitu StandardScaler dan LogisticRegression pada dataset breast cancer. Pencarian pertama adalah grid kecil berisi delapan kombinasi dari empat nilai C dan dua pilihan class_weight, sedangkan pencarian kedua menarik delapan sampel dari ruang yang lebih luas, yaitu C dari loguniform(1e-3, 1e3) dengan pilihan class_weight yang sama. Keduanya menggunakan objek StratifiedKFold lima lipatan yang identik sehingga skornya dapat diperbandingkan.

python penalaan-acak.py
import numpy as np
from scipy.stats import loguniform
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV, StratifiedKFold
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

X, y = load_breast_cancer(return_X_y=True)
pipeline = Pipeline([
    ("scaler", StandardScaler()),
    ("model", LogisticRegression(max_iter=1000)),
])
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)

# grid kecil: 4 nilai C x 2 pilihan class_weight = 8 kombinasi
param_grid = {
    "model__C": [0.01, 0.1, 1.0, 10.0],
    "model__class_weight": [None, "balanced"],
}
grid = GridSearchCV(pipeline, param_grid, cv=cv)
grid.fit(X, y)

# ruang C lebih luas, anggaran sama: 8 sampel acak
param_distributions = {
    "model__C": loguniform(1e-3, 1e3),
    "model__class_weight": [None, "balanced"],
}
acak = RandomizedSearchCV(
    pipeline, param_distributions, n_iter=8, cv=cv, random_state=42
)
acak.fit(X, y)

c_sampel = np.sort(acak.cv_results_["param_model__C"].astype(float))
print("Jumlah kandidat grid :", len(grid.cv_results_["params"]))
print("Jumlah kandidat acak :", len(acak.cv_results_["params"]))
print("C pada grid          : [0.01, 0.1, 1.0, 10.0]")
print("C sampel acak        :", ", ".join(f"{v:.4f}" for v in c_sampel))
print(f"best_score_ grid     : {grid.best_score_:.4f}")
print(f"best_score_ acak     : {acak.best_score_:.4f}")
print("best_params_ grid    :", grid.best_params_)
print("best_params_ acak    :",
      {k: (round(float(v), 4) if isinstance(v, float) else v)
       for k, v in acak.best_params_.items()})
text Keluaran
Jumlah kandidat grid : 8
Jumlah kandidat acak : 8
C pada grid          : [0.01, 0.1, 1.0, 10.0]
C sampel acak        : 0.0022, 0.0022, 0.0126, 0.1005, 0.1767, 0.4731, 3.9080, 17.7188
best_score_ grid     : 0.9754
best_score_ acak     : 0.9754
best_params_ grid    : {'model__C': 0.1, 'model__class_weight': 'balanced'}
best_params_ acak    : {'model__C': 0.1767, 'model__class_weight': None}

Sampel acak menjangkau nilai C dari 0.0022 hingga 17.7188, yaitu rentang hampir empat dekade, sedangkan grid hanya menempatkan empat titik pada rentang tiga dekade. Keduanya berakhir pada best_score_ 0.9754 dengan kombinasi yang berbeda, yaitu C=0.1 dengan class_weight='balanced' pada grid dan C=0.1767 tanpa class_weight pada pencarian acak. Persamaan skor dengan konfigurasi yang berbeda menandakan adanya dataran performa di sekitar nilai tersebut, dan pencarian acak menemukan dataran itu tanpa mencoba seluruh kombinasinya.

Pencarian acak bukan pengganti grid dalam semua keadaan. Ketika ruangnya kecil dan setiap kombinasi layak dicoba, grid tetap menjadi pilihan yang paling langsung, sedangkan pencarian acak menjadi lebih menguntungkan ketika jumlah kombinasi penuh melebihi anggaran atau ketika ruangnya memuat dimensi kontinu seperti loguniform.

Kesalahan umum#

  • Memperlakukan pencarian acak sebagai pengganti mutlak grid. Pada ruang kecil, grid lebih langsung dan biayanya masih terjangkau. Perbaikannya dengan menggunakan grid bila jumlah kombinasi penuhnya masih muat dalam anggaran.
  • Membandingkan best_score_ dua pencarian yang lipatannya berbeda. Selisih skornya bisa berasal dari komposisi lipatan dan bukan dari kualitas pencariannya. Perbaikannya dengan objek StratifiedKFold yang sama untuk semua pencarian yang diperbandingkan.
  • Menarik distribusi tanpa random_state. Kandidat yang terbangkit berubah pada setiap eksekusi sehingga hasilnya tidak dapat direproduksi. Perbaikannya dengan menetapkan random_state=42 pada RandomizedSearchCV.

Ringkasan#

  • Pencarian acak lebih menguntungkan ketika ruang nilainya luas dan anggaran kandidat terbatas, karena sampelnya lebih beragam pada biaya yang sama dengan grid yang menyempit.
  • param_distributions menerima daftar pilihan dan distribusi scipy.stats seperti loguniform untuk nilai kontinu pada skala logaritmik.
  • Pada dataset breast cancer, delapan sampel acak menjangkau C dari 0.0022 hingga 17.7188 dan mencapai best_score_ yang sama dengan grid delapan kombinasi.
  • random_state pada RandomizedSearchCV membuat kandidat yang ditarik dapat direproduksi, sehingga eksperimennya dapat diperbandingkan.

Referensi#