2024-08-27|閱讀時間 ‧ 約 24 分鐘

【資料分析】python機器學習-找到模型的最佳超參數

raw-image

在機器學習中,超參數(Hyperparameters)是指在訓練過程中需要手動設定、而非通過模型學習獲得的參數,例如隨機森林(Random Forest)中的n_estimators, max_depth, min_samples_split支持向量機(SVM)中的C, kernel, gamma,都是該模型中的超參數。這些參數通常會影響模型的訓練過程和最終性能,需要在模型訓練之前設置。


# 可使用目錄功能快速確認要閱覽的主題


方法選擇參考

1. 網格搜索(Grid Search)

  • 當參數空間相對較小且可以接受較長的計算時間時。
  • 適合對每一個超參數組合進行精確搜索的場景,尤其是當確信某些參數範圍可能包含最佳值時。

2. 隨機搜索(Random Search)

  • 當參數空間較大且不確定哪個範圍內包含最佳參數時。
  • 適合資源有限的情況,或者在計算資源受限的場景中需要快速找到一個“足夠好”的超參數組合。

3. 貝葉斯優化(Bayesian Optimization)

  • 當參數空間非常大或計算資源有限,需要更智能的搜索方法時。
  • 適合高維度參數空間,且需要更有效地利用每一次搜索結果的場景。

4. 交叉驗證(Cross-Validation)與超參數調整結合

  • 當需要確保模型的泛化能力,並且希望在進行超參數調整時避免過度擬合時。
  • 適合需要在有限數據上進行可靠性能評估的場景。

5. 自適應搜索算法(例如Optuna, Hyperopt)

  • 當需要在高度靈活且複雜的參數空間中進行優化,並且希望通過自適應學習來加速優化過程時。
  • 適合需要在計算成本和搜索效率之間找到最佳平衡的場景。


網格搜索(Grid Search)

網格搜索是一種窮舉搜尋方法,通過對給定參數空間中的每一個可能組合進行評估,找到表現最好的超參數組合。

from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

# 載入數據集
iris = load_iris()
X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.3, random_state=42)

# 定義模型
rf = RandomForestClassifier(random_state=42)

# 定義參數網格
param_grid = {
'n_estimators': [50, 100, 200],
'max_depth': [None, 10, 20, 30],
'min_samples_split': [2, 5, 10]
}

# 使用GridSearchCV
grid_search = GridSearchCV(estimator=rf, param_grid=param_grid, cv=5, scoring='accuracy')
grid_search.fit(X_train, y_train)

# 最佳參數
print(f"Best Parameters: {grid_search.best_params_}")

# 最佳模型
best_rf = grid_search.best_estimator_
print(f"Best Model Score: {best_rf.score(X_test, y_test)}")


網格搜索優點

  • 全面探索:對所有可能的參數組合進行測試,保證找到全局最優解。
  • 易於理解:實現簡單,適合理解機器學習的初學者。

網格搜索缺點

  • 計算成本高:隨著參數空間的增大,計算量呈指數級增長,可能非常耗時。
  • 無效率:可能在無關緊要的參數組合上浪費大量計算資源。


隨機搜索(Random Search)

隨機搜索通過在參數空間中隨機採樣來找到優化的超參數組合。這種方法通常比網格搜索更快,尤其是在參數空間較大時。

from sklearn.model_selection import RandomizedSearchCV
from sklearn.ensemble import RandomForestClassifier

# 定義隨機搜索的參數分佈
param_dist = {
'n_estimators': [50, 100, 200],
'max_depth': [None, 10, 20, 30],
'min_samples_split': [2, 5, 10],
'min_samples_leaf': [1, 2, 4]
}

# 使用RandomizedSearchCV
random_search = RandomizedSearchCV(estimator=rf, param_distributions=param_dist, n_iter=10, cv=5, scoring='accuracy', random_state=42)
random_search.fit(X_train, y_train)

# 最佳參數
print(f"Best Parameters: {random_search.best_params_}")

# 最佳模型
best_rf = random_search.best_estimator_
print(f"Best Model Score: {best_rf.score(X_test, y_test)}")


隨機搜索優點

  • 計算效率高:相比網格搜索,隨機搜索對於大參數空間更具效率。
  • 靈活性強:能夠適應高維度的參數空間,可能找到接近最佳解的組合。

隨機搜索缺點

  • 不保證找到全局最優解:隨機性意味著可能會錯過最佳參數組合。
  • 結果不穩定:不同的隨機種子可能導致不同的結果。


貝葉斯優化(Bayesian Optimization)

貝葉斯優化是一種更加智能的超參數調整方法。它通過構建超參數與模型性能之間的概率模型(如高斯過程),根據這一模型進行探索和利用,從而更有效地找到最優的超參數組合。

使用hyperopt庫進行貝葉斯優化:

from hyperopt import fmin, tpe, hp, Trials
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestClassifier

# 定義目標函數
def objective(params):
clf = RandomForestClassifier(**params, random_state=42)
score = cross_val_score(clf, X_train, y_train, cv=5, scoring='accuracy').mean()
return -score

# 定義參數空間
space = {
'n_estimators': hp.choice('n_estimators', [50, 100, 200]),
'max_depth': hp.choice('max_depth', [None, 10, 20, 30]),
'min_samples_split': hp.uniform('min_samples_split', 2, 10),
'min_samples_leaf': hp.uniform('min_samples_leaf', 1, 4)
}

# 使用貝葉斯優化
trials = Trials()
best = fmin(fn=objective, space=space, algo=tpe.suggest, max_evals=50, trials=trials)

print(f"Best Parameters: {best}")


貝葉斯優化優點

  • 效率高:貝葉斯優化通過構建超參數與模型性能之間的關係模型,使搜索過程更加高效。
  • 適合高維空間:能夠有效處理高維度的參數空間,找到最佳解的可能性更高。

貝葉斯優化缺點

  • 實現複雜:相較於網格搜索和隨機搜索,貝葉斯優化的實現更為複雜,可能需要額外的庫和知識。
  • 依賴初始點:初始選擇的點可能會影響最終結果。


交叉驗證(Cross-Validation)與超參數調整結合

在進行超參數搜索的同時,可以使用交叉驗證來評估模型的泛化能力,避免過度擬合。

from sklearn.model_selection import cross_val_score

# 使用交叉驗證來評估模型性能
scores = cross_val_score(rf, X_train, y_train, cv=5, scoring='accuracy')
print(f"Cross-Validation Scores: {scores}")
print(f"Mean Accuracy: {scores.mean()}")


交叉驗證優點

  • 避免過度擬合:通過交叉驗證,可以確保模型在不同的數據子集上表現良好,提升泛化能力。
  • 穩定性高:交叉驗證結果更加穩定,可以提高模型的可靠性。

交叉驗證缺點

  • 計算成本高:需要多次訓練和測試模型,特別是在大數據集或複雜模型上,可能非常耗時。
  • 複雜性增加:實現起來比單次訓練模型更為複雜。


自適應搜索算法

一些先進的搜尋算法如 OptunaBayesianOptimizationScikit-Optimize 等,可以在更高維度的參數空間中找到最優參數。這些工具通過探索和利用當前找到的最佳參數來進行自適應調整。

import optuna
from sklearn.ensemble import RandomForestClassifier

# 定義目標函數
def objective(trial):
n_estimators = trial.suggest_int('n_estimators', 50, 200)
max_depth = trial.suggest_int('max_depth', 10, 30)
min_samples_split = trial.suggest_uniform('min_samples_split', 2, 10)

clf = RandomForestClassifier(n_estimators=n_estimators, max_depth=max_depth, min_samples_split=min_samples_split, random_state=42)
return cross_val_score(clf, X_train, y_train, cv=5, scoring='accuracy').mean()

# 使用Optuna進行優化
study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=50)

# 最佳參數
print(f"Best Parameters: {study.best_params}")


自適應搜索算法優點

  • 智能搜索:自適應搜索算法可以根據當前的搜索結果動態調整未來的搜索路徑,提高效率。
  • 靈活性:支持各種複雜的搜索空間和約束條件,適應性強。

自適應搜索算法缺點

  • 實現較複雜:相較於網格搜索和隨機搜索,自適應搜索算法的設置和調試更為複雜。
  • 依賴於算法的質量:不同的自適應算法有不同的性能表現,需要對其特性有一定了解。


好的機器學習模型訓練和驗證流程參考

1. 交叉驗證階段

  • 目標:利用交叉驗證來選擇最優的模型和超參數組合。
  • 步驟
    1. 將數據集劃分為訓練集和測試集。
    2. 在訓練集上應用交叉驗證,通過多次分割和訓練來評估不同的模型和超參數組合的表現。
    3. 根據交叉驗證的結果,選擇平均準確率最高的模型及其超參數組合。

2. 最終測試集評估階段

  • 目標:使用獨立的測試集來評估選定模型的最終性能,確保模型在未見過的新數據上具有良好的泛化能力。
  • 步驟
    1. 使用交叉驗證中選出的最佳模型和超參數組合,在完整的訓練集上進行最終訓練。
    2. 在獨立的測試集上進行預測,並計算測試集上的準確率或其他性能指標。
    3. 根據測試集的表現來評估模型是否過擬合,並檢查其在新數據上的泛化能力。

3. 結果解讀

  • 如果測試集上的表現與交叉驗證結果相近,說明模型的超參數調整是合理的,並且模型有良好的泛化能力。
  • 如果測試集上的表現明顯低於交叉驗證結果,則可能需要進一步調整模型,考慮過擬合問題或數據質量問題。

總結

這種流程通過交叉驗證來選擇最佳模型,然後在獨立的測試集上進行最終檢驗,能夠最大程度地保證模型的穩定性和泛化能力,是機器學習建模的最佳實踐之一。


以下是使用交叉驗證找出最佳超參數,然後用獨立測試集來評估模型的範例。這裡將使用隨機森林模型作為例子。

1. 導入必要的庫

import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split, GridSearchCV, cross_val_score
from sklearn.metrics import accuracy_score

# 假設你有一個 DataFrame 叫做 df_analysis,其中包含 Titanic 資料

2. 資料準備

將數據分成特徵(X)和目標(y),然後進行訓練集和測試集的分割。

df_train = df_analysis[0:891]  # 取前 891 行作為訓練資料
train_valid_X = df_train.drop(columns=['Survived']) # 所有特徵
train_valid_y = df_train['Survived'] # 目標變數 'Survived'

test_X = df_analysis[891:].drop(columns=['Survived']) # 剩下的行作為測試資料

# 將訓練集再進行訓練/驗證集的分割
train_X, valid_X, train_y, valid_y = train_test_split(train_valid_X, train_valid_y, train_size=0.7, random_state=42)

3. 使用交叉驗證來找出最佳超參數

# 設定隨機森林的超參數範圍
param_grid = {
'n_estimators': [50, 100, 200],
'max_depth': [None, 10, 20, 30],
'min_samples_split': [2, 5, 10],
'min_samples_leaf': [1, 2, 4]
}

# 建立隨機森林模型
rf = RandomForestClassifier(random_state=42)

# 使用 GridSearchCV 來尋找最佳超參數組合
grid_search = GridSearchCV(estimator=rf, param_grid=param_grid, cv=5, scoring='accuracy', n_jobs=-1, verbose=2)
grid_search.fit(train_X, train_y)

# 輸出最佳的超參數
print("最佳超參數組合:", grid_search.best_params_)

4. 使用最佳超參數重新訓練模型並在測試集上進行評估

# 使用最佳超參數訓練模型
best_rf = grid_search.best_estimator_
best_rf.fit(train_X, train_y)

# 在驗證集上評估模型
valid_accuracy = accuracy_score(valid_y, best_rf.predict(valid_X))
print(f"驗證集準確率: {valid_accuracy:.2f}")

# 在測試集上評估模型
test_predictions = best_rf.predict(test_X)
# 因為 Kaggle 的 Titanic 比賽中沒有測試集的 Survived 標籤,這裡假設測試集是有標籤的
# 如果測試集沒有標籤,只能保存預測結果然後提交到 Kaggle 平台進行評分
test_accuracy = accuracy_score(test_y, test_predictions)
print(f"測試集準確率: {test_accuracy:.2f}")

5. 保存預測結果(如果測試集無標籤)

# 將預測結果保存到 CSV 文件
submission = pd.DataFrame({
"PassengerId": df_analysis[891:]['PassengerId'],
"Survived": test_predictions
})
submission.to_csv("titanic_submission.csv", index=False)

6. 解釋

  • 交叉驗證:在 GridSearchCV 中使用 5 折交叉驗證來評估每個超參數組合的表現,從而找出最佳的超參數組合。
  • 最終模型評估:使用最佳超參數在訓練集上重新訓練模型,並在測試集上進行最終的性能評估,確認模型的泛化能力。

這樣可以幫助你找到最好的模型設定,並確認它是否在未見過的數據上也有良好的表現,從而避免過擬合。

分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.