歡迎來到Scikit-learn教學系列的第五篇文章!在前幾篇中,我們學習了分類與回歸模型,並掌握了資料前處理與模型評估。這一篇將聚焦於模型選擇與超參數調優,這是提升機器學習模型表現的關鍵步驟。我們將介紹交叉驗證、超參數調優方法(網格搜尋與隨機搜尋),以及如何避免過擬合,幫助你選擇最佳模型並優化其參數。準備好讓你的模型更上一層樓吧!
為什麼需要模型選擇與超參數調優?
機器學習模型的表現不僅取決於演算法,還與超參數(Hyperparameters)設置密切相關。例如:- K近鄰(KNN)的鄰居數量n_neighbors。
- 隨機森林的樹數量n_estimators或樹的最大深度max_depth。
- 嶺回歸的正則化強度alpha。
超參數無法通過訓練資料直接學習,需人工設置或通過系統性方法尋找。此外,不同演算法在不同資料集上的表現差異很大,因此需要模型選擇來確定最適合的演算法。
關鍵技術
我們將介紹以下三個核心技術,並使用Scikit-learn實現:
- 交叉驗證(Cross-Validation):評估模型的泛化能力。
- 超參數調優:網格搜尋(GridSearchCV)與隨機搜尋(RandomizedSearchCV)。
- 避免過擬合:正則化與控制模型複雜度。
1. 交叉驗證:K折交叉驗證
單次訓練-測試分割可能導致評估結果不穩定。K折交叉驗證(K-Fold Cross-Validation)將資料分為K份,輪流使用一份作為測試集,其餘作為訓練集,計算K次評估的平均表現。
範例程式碼:
from sklearn.model_selection import cross_val_score
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import load_iris
# 載入資料
iris = load_iris()
X, y = iris.data, iris.target
# 定義模型
knn = KNeighborsClassifier(n_neighbors=5)
# 進行5折交叉驗證
scores = cross_val_score(knn, X, y, cv=5, scoring='accuracy')
print("交叉驗證準確率:", scores)
print("平均準確率:", scores.mean(), "±", scores.std())
說明:cv=5
表示5折交叉驗證,scoring='accuracy'
指定評估指標。結果顯示每次驗證的準確率及其均值與標準差。

2. 超參數調優:網格搜尋與隨機搜尋
超參數調優的目標是找到最佳參數組合。Scikit-learn提供兩種方法:
- 網格搜尋(GridSearchCV):遍歷所有指定的參數組合。
- 隨機搜尋(RandomizedSearchCV):從參數空間中隨機抽樣,適合大規模參數空間。
範例程式碼(網格搜尋):
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.datasets import load_iris
# 載入 Iris 資料集
iris = load_iris()
X, y = iris.data, iris.target
# 定義管道(前處理 + 模型)
pipeline = Pipeline([
('scaler', StandardScaler()),
('svm', SVC())
])
# 定義參數網格
param_grid = {
'svm__C': [0.1, 1, 10],
'svm__kernel': ['linear', 'rbf'],
'svm__gamma': ['scale', 'auto']
}
# 執行網格搜尋
grid_search = GridSearchCV(pipeline, param_grid, cv=5, scoring='accuracy', n_jobs=-1)
grid_search.fit(X, y)
# 輸出最佳結果
print("最佳參數:", grid_search.best_params_)
print("最佳交叉驗證準確率:", grid_search.best_score_)
說明:param_grid
定義參數組合,cv=5
表示5折交叉驗證,n_jobs=-1
使用所有CPU核心加速計算。

範例程式碼(隨機搜尋):
from sklearn.model_selection import RandomizedSearchCV
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.datasets import load_iris
from scipy.stats import uniform
# 載入 Iris 資料集
iris = load_iris()
X, y = iris.data, iris.target
# 定義管道(前處理 + 模型)
pipeline = Pipeline([
('scaler', StandardScaler()),
('svm', SVC())
])
# 定義參數分佈
param_dist = {
'svm__C': uniform(0.1, 10), # 在 [0.1, 10.1) 範圍內隨機取值
'svm__kernel': ['linear', 'rbf'],
'svm__gamma': ['scale', 'auto']
}
# 進行隨機搜尋
random_search = RandomizedSearchCV(pipeline, param_dist, n_iter=10, cv=5, scoring='accuracy', n_jobs=-1, random_state=42)
random_search.fit(X, y)
# 輸出最佳結果
print("最佳參數:", random_search.best_params_)
print("最佳交叉驗證準確率:", random_search.best_score_)
說明:n_iter=10
表示隨機抽樣10組參數,uniform(0.1, 10)
定義連續分佈的參數範圍。

3. 避免過擬合:正則化與模型複雜度
過擬合(Overfitting)是指模型在訓練集上表現很好,但在測試集上表現差。以下方法有助於避免過擬合:
- 正則化:例如嶺回歸的
alpha
或SVM的C
,限制模型複雜度。 - 控制模型複雜度:例如限制決策樹的
max_depth
或隨機森林的min_samples_split
。 - 更多資料:若可行,增加訓練資料量。
實作:對支持向量機(SVM)進行超參數調優
讓我們使用 Wine 資料集對 SVM 分類器執行超參數調整,包括預處理、交叉驗證和網格搜尋。
程式碼範例
以下程式碼展示如何對Wine資料集進行超參數調優:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.pipeline import Pipeline
from sklearn.metrics import classification_report, confusion_matrix
# 載入Wine資料集
wine = load_wine()
X = wine.data
y = wine.target
target_names = wine.target_names
# 分割訓練集與測試集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 定義管道
pipeline = Pipeline([
('scaler', StandardScaler()),
('svm', SVC())
])
# 定義參數網格
param_grid = {
'svm__C': [0.1,1,10,100],
'svm__kernel': ['linear', 'rbf'],
'svm__gamma': ['scale', 'auto', 0.1, 1]
}
# 進行網格搜尋
grid_search = GridSearchCV(pipeline, param_grid, cv=5, scoring='accuracy', n_jobs=-1)
grid_search.fit(X_train, y_train)
# 輸出最佳結果
print("最佳參數:", grid_search.best_params_)
print("最佳交叉驗證準確率:", grid_search.best_score_)
# 使用最佳模型進行預測
best_model = grid_search.best_estimator_
y_pred = best_model.predict(X_test)
# 評估模型
print("\n測試集結果:")
print("準確率:", grid_search.score(X_test, y_test))
print("分類報告:")
print(classification_report(y_test, y_pred, target_names=target_names))
# 繪製混淆矩陣
cm = confusion_matrix(y_test, y_pred)
plt.figure(figsize=(6, 4))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=target_names, yticklabels=target_names)
plt.title('Confusion Matrix - Best SVM Model')
plt.xlabel('Predicted')
plt.ylabel('True')
plt.savefig('wine_svm_cm.png')
plt.show()
# 視覺化網格搜尋結果
results = pd.DataFrame(grid_search.cv_results_)
pivot_table = results.pivot_table(values='mean_test_score', index='param_svm__C', columns='param_svm__kernel')
plt.figure(figsize=(8, 6))
sns.heatmap(pivot_table, annot=True, cmap='viridis')
plt.title('Grid Search Accuracy for Different C and Kernel')
plt.xlabel('Kernel')
plt.ylabel('C')
plt.savefig('wine_grid_search_heatmap.png')
plt.show()
程式碼解釋
- 資料載入與分割: 載入Wine資料集,包含13個特徵與3個類別。 分割為70%訓練集與30%測試集。
- 管道設置: 使用Pipeline整合StandardScaler與SVC(支持向量機分類器)。
- 網格搜尋: 定義參數網格,涵蓋C(正則化強度)、kernel(核函數)與gamma(核參數)。 使用GridSearchCV進行5折交叉驗證,尋找最佳參數。
- 模型評估: 使用最佳模型預測測試集,計算準確率並輸出分類報告。 繪製混淆矩陣,展示預測表現。
- 視覺化: 繪製熱圖,展示不同C與kernel組合的交叉驗證準確率。
運行程式碼後,你會看到最佳參數、測試集表現、混淆矩陣與網格搜尋結果的熱圖。



練習:對決策樹進行隨機搜尋
請完成以下練習:
- 使用Scikit-learn的load_breast_cancer()載入Breast Cancer資料集。
- 創建一個管道,包含StandardScaler與DecisionTreeClassifier。
- 使用RandomizedSearchCV進行超參數調優,參數分佈如下: max_depth: 整數範圍1到10。 min_samples_split: 整數範圍2到20。 min_samples_leaf: 整數範圍1到10。
- 進行10次隨機搜尋,使用5折交叉驗證,評估指標為準確率。
- 輸出最佳參數與測試集準確率,繪製混淆矩陣,保存為breast_cancer_dt_cm.png。
以下是起點程式碼:
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split, RandomizedSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.tree import DecisionTreeClassifier
from sklearn.pipeline import Pipeline
from sklearn.metrics import confusion_matrix
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.stats import randint
# 載入Breast Cancer資料集
cancer = load_breast_cancer()
X = cancer.data
y = cancer.target
target_names = cancer.target_names
# 分割訓練集與測試集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 你的程式碼從這裡開始...

總結
恭喜你學會了模型選擇與超參數調優!本篇文章介紹了交叉驗證、網格搜尋、隨機搜尋與避免過擬合的方法,並通過Wine資料集展示了SVM的超參數調優流程。你現在能夠系統性地優化模型,提升其泛化能力。
在下一篇文章中,我們將探索非監督學習 - 聚類與降維,學習如何處理無標籤資料。請完成練習,並在留言區分享你的Breast Cancer資料集混淆矩陣!
資源與進階學習
- Scikit-learn模型選擇文件:https://scikit-learn.org/stable/model_selection.html
- 練習平台:Kaggle(https://www.kaggle.com/competitions)