歡迎來到Scikit-learn教學系列的第七篇文章!在前幾篇中,我們學習了監督學習、非監督學習、模型選擇與超參數調優。這一篇將聚焦於管道(Pipeline)與模型組合(Ensemble Models),這些進階技術能簡化工作流程並提升模型表現。我們將介紹管道的設計、模型組合的應用,並通過實作範例展示如何構建高效的機器學習工作流。準備好優化你的機器學習項目吧!
什麼是管道?為什麼需要?
在機器學習中,資料處理與模型訓練通常包含多個步驟,例如:- 資料前處理(標準化、編碼缺失值等)。
- 特徵選擇或降維。
- 模型訓練與預測。
手動執行這些步驟容易出錯,且在交叉驗證或超參數調優時可能導致資料洩漏(Data Leakage)。Scikit-learn的管道(Pipeline)將這些步驟整合為一個物件,提供以下優勢:
- 簡化流程:將前處理與模型訓練封裝為單一流程。
- 防止資料洩漏:確保前處理僅基於訓練資料進行擬合。
- 便於調優:與網格搜尋結合,同時優化前處理與模型參數。
模型組合:提升預測能力
單一模型可能無法捕捉資料的所有模式。模型組合(Ensemble Methods)通過整合多個模型的預測來提升表現,常見方法包括:
- 投票分類器(Voting Classifier):多個分類器投票決定最終預測。
- 堆疊模型(Stacking):使用元模型(Meta-Model)整合多個基模型的預測。
Scikit-learn提供了簡單的API來實現這些組合技術。
實作:構建管道與投票分類器
我們將使用Scikit-learn的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, cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.impute import SimpleImputer
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.ensemble import VotingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
# 載入Wine資料集
wine = load_wine()
X = pd.DataFrame(wine.data, columns=wine.feature_names)
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)
# 定義前處理管道
numeric_features = X.columns.tolist() # 所有特徵均為數值型
numeric_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='median')),
('scaler', StandardScaler())
])
# 整合前處理
preprocessor = ColumnTransformer(transformers=[
('num', numeric_transformer, numeric_features)
])
# 定義基模型
log_reg = LogisticRegression(random_state=42)
knn = KNeighborsClassifier(n_neighbors=5)
svm = SVC(probability=True, random_state=42)
# 定義投票分類器
voting_clf = VotingClassifier(
estimators=[
('lr', log_reg),
('knn', knn),
('svm', svm)
],
voting='soft' # 使用概率加權投票
)
# 構建完整管道
pipeline = Pipeline(steps=[
('preprocessor', preprocessor),
('classifier', voting_clf)
])
# 訓練管道
pipeline.fit(X_train, y_train)
# 預測與評估
y_pred = pipeline.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print("測試集準確率:", accuracy)
print("\n分類報告:")
print(classification_report(y_test, y_pred, target_names=target_names))
# 交叉驗證
cv_scores = cross_val_score(pipeline, X, y, cv=5, scoring='accuracy')
print("\n交叉驗證準確率:", cv_scores)
print("平均交叉驗證準確率:", cv_scores.mean(), "±", cv_scores.std())
# 繪製混淆矩陣
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 - Voting Classifier')
plt.xlabel('Predicted')
plt.ylabel('True')
plt.savefig('wine_voting_cm.png')
plt.show()
# 比較單一模型與投票分類器
single_models = {
'Logistic Regression': LogisticRegression(random_state=42),
'K-Nearest Neighbors': KNeighborsClassifier(n_neighbors=5),
'SVM': SVC(random_state=42)
}
results = []
for name, model in single_models.items():
single_pipeline = Pipeline(steps=[
('preprocessor', preprocessor),
('classifier', model)
])
single_pipeline.fit(X_train, y_train)
y_pred_single = single_pipeline.predict(X_test)
acc = accuracy_score(y_test, y_pred_single)
results.append({'Model': name, 'Accuracy': acc})
results.append({'Model': 'Voting Classifier', 'Accuracy': accuracy})
# 視覺化模型比較
results_df = pd.DataFrame(results)
plt.figure(figsize=(8, 6))
sns.barplot(x='Accuracy', y='Model', data=results_df)
plt.title('Model Accuracy Comparison')
plt.xlabel('Accuracy')
plt.ylabel('Model')
plt.savefig('wine_model_comparison.png')
plt.show()
程式碼解釋
- 資料載入與分割: 載入Wine資料集,包含13個數值特徵與3個類別。 分割為70%訓練集與30%測試集。
- 前處理管道: 使用SimpleImputer填補缺失值(中位數策略)。 使用StandardScaler標準化特徵。 使用ColumnTransformer整合前處理步驟。
- 投票分類器: 定義三個基模型:邏輯回歸、KNN、SVM。 使用VotingClassifier以soft投票(基於概率加權)整合預測。
- 完整管道: 將前處理與投票分類器整合為單一Pipeline。 訓練管道並預測測試集。
- 評估與視覺化: 計算測試集準確率與分類報告。 進行5折交叉驗證,評估模型穩定性。 繪製混淆矩陣,展示預測表現。 比較投票分類器與單一模型的準確率,繪製柱狀圖。
運行程式碼後,你會看到測試集表現、交叉驗證結果、混淆矩陣以及模型比較圖。



練習:構建管道與堆疊模型
請完成以下練習:
- 使用Scikit-learn的load_breast_cancer()載入Breast Cancer資料集。
- 創建一個管道,包含以下前處理步驟: 數值特徵:SimpleImputer(均值策略)與StandardScaler。 (假設資料無類別特徵,若有,可加入OneHotEncoder)。
- 使用StackingClassifier整合以下基模型,並以邏輯回歸作為元模型: 基模型:KNN(n_neighbors=5)、SVM(probability=True)、決策樹(random_state=42)。
- 訓練管道,計算測試集準確率,繪製混淆矩陣,保存為breast_cancer_stacking_cm.png。
- 比較堆疊模型與單一KNN模型的準確率,繪製柱狀圖,保存為breast_cancer_model_comparison.png。
以下是起點程式碼:
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.impute import SimpleImputer
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.ensemble import StackingClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, confusion_matrix
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
# 載入Breast Cancer資料集
cancer = load_breast_cancer()
X = pd.DataFrame(cancer.data, columns=cancer.feature_names)
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資料集展示了如何構建高效的工作流程。你現在能夠簡化機器學習任務並通過模型組合提升預測能力。
在下一篇文章中,我們將探索實際專案 - 從資料到部署,學習如何完成一個完整的機器學習專案並部署模型。
資源與進階學習
- Scikit-learn管道與模型組合文件:https://scikit-learn.org/stable/modules/compose.html
- 練習平台:Kaggle(https://www.kaggle.com/competitions)