【特徵選擇-包裝法】SFS序列特徵選擇法

麥特在攻讀研究所的時候,對於特徵工程領域有非常強烈的興趣,所以搜尋到Sequential Feature Selector序列特徵選擇法這項特徵選擇技術,而其中又有不同的改良方法,我在撰寫碩士論文的內容中,就有使用到序列特徵選擇法來進行特徵的挑選,也讓最後建立的模型有不錯的表現。

什麼是序列特徵選擇法(Sequential Feature Selector)

序列特徵選擇法(Sequential Feature Selector)是特徵選擇技術中的一種,它的特色是將特徵選擇與模型訓練同時進行。

在使用序列特徵選擇法時,模型會根據目標變數來進行特徵的篩選,從而保留重要的特徵並去除較不重要的特徵。這種方法的優點是能夠提升模型的泛化能力,同時減少過擬合問題。

序列特徵選擇法大致上分為四個類型,麥特會簡單的介紹原理,最後會介紹其中一種自己在實務上認為效果最好的方法進一步的範例說明。

序列前向選擇法 (Sequential Forward Selection, SFS)

原理:

  • 序列前向選擇法會從建立一個空的特徵子集開始,可以想像成要存放挑選特徵的容器,逐步添加對模型效果提升最大的特徵。
  • 在每次迭代中,選擇使模型效能,例如準確度(Accuracy)或其他評分指標(Metric),找到提升最大的特徵,直到達到預設的特徵數量或是模型的表現不再提升為止。

步驟

  1. 開始時,建立一個空的特徵子集。
  2. 每次迭代從剩餘的特徵中選擇一個能夠最大化模型表現的特徵加入子集。
  3. 重複此過程直到達到特徵數目的上限或模型表現不再顯著提升。

序列後向選擇法 (Sequential Backward Selection, SBS)

原理

  • 序列後向選擇法與前向選擇相反,從包含所有特徵的完整數量開始,每次迭代移除對模型效果影響最小的特徵,直到只剩下預設的特徵數量或模型效果不再顯著下降。

步驟

  1. 開始時,特徵子集包含所有的特徵數目。
  2. 每次迭代從當前子集中移除對模型效能影響最小的特徵。
  3. 重複此過程直到達到預設的特徵數目或是模型效果不再顯著下降即停止。

序列前向浮動選擇法 (Sequential Floating Forward Selection, SFFS)

原理

  • SFFS 是序列前向選擇法的改進版本,它允許在添加特徵的過程中能動態移除不合適的特徵。這樣可以避免傳統前進選擇法容易陷入局部最佳解(Local Optimal Solution)的問題。

步驟

  1. 開始時,特徵子集為空。
  2. 每次迭代從剩餘的特徵中選擇一個對模型表現提升最大的特徵加入子集。
  3. 在每次加入一個特徵後,會嘗試動態移除當前子集中對模型影響不大甚至負面的特徵。
  4. 重複該過程,直到達到預設的特徵數量或模型表現不再顯著提升。

序列後向浮動選擇法 (Sequential Floating Backward Selection, SFBS)

原理

  • SFBS 與 SFFS 類似,但過程是相反的。它從包含所有特徵的集合開始,逐步移除對模型表現影響最小的特徵,同時允許在移除特徵後動態地重新加入先前被移除的有用特徵。

步驟

  1. 開始時,特徵子集包含所有特徵。
  2. 每次迭代移除對模型影響最小的特徵。
  3. 在每次移除後,會檢查是否有先前移除的特徵值需要重新加入子集,以提升模型表現。
  4. 重複該過程,直到達到預設的特徵數量或模型表現穩定。

四種方法的優缺點

  • SFS:逐步添加特徵,直到選出最佳特徵組合。
  • SBS:逐步移除特徵,減少不重要的特徵。
  • SFFS:在前進選擇時動態調整,添加和移除特徵來找到最佳組合。
  • SFBS:在後退選擇時動態調整,允許重新加入移除的特徵。

為什麼使用SFFS?

在本次介紹中,我會特別聚焦於序列特徵選擇法-序列前向浮動選擇法(Sequential Floating Forward Selection, SFFS)

這種方法與介紹過的RFE遞迴特徵消除法不同,它會逐步增加與移除特徵,以找到對模型預測最有幫助的特徵組合。

SFFS相較於傳統的前向選擇法,能夠動態調整添加與移除的特徵數量,這樣的選擇法能在每一步都評估特徵組合的重要性,同時能夠避免前進選擇法中可能存在的局部最佳解(local optimal solution)的問題。

序列特徵選擇法的優勢

  1. 動態選擇特徵:序列前向浮動選擇法(SFFS)可以靈活地增加或移除特徵,相比於傳統的序列前向選擇法(SFS)更加靈活。
  2. 避免局部最優:傳統的序列向前選擇法(SFS)容易陷入局部最優解,而序列前向浮動選擇法(SFFS)在每一步都會檢查已經選擇過的特徵,進而減少這樣問題發生。
  3. 適用於各種模型:序列前向浮動選擇法(SFFS)可以配合各種監督式學習模型來做使用,例如線性回歸(Linear regression)、決策樹(decision tree)、隨機森林(random forest)等等。

SFFS模型參數介紹

下面會介紹主要需要調整到的參數:

  • estimator: 設定要使用的基學習器模型,例如線性回歸(Linear regression)、決策樹(decision tree)、隨機森林(random forest)等等。
  • k_features: 可以設定最後選擇的特徵數量,可以是一個整數(k_features=5) 或是一個範圍 k_features=(3, 5)),表示設定特徵數量在3到5之間。
  • forward: 主要是設定特徵挑選的方式是前向選擇(True)或是後向選擇(False)。
  • floating: 設定是否開啟浮動特徵選擇,如果設定為 True,模型在每次迭代中,就有可能會在添加新特徵之後移除一個已選擇的特徵,這邊建議設定為 True
  • scoring: 這是性能評估指標,如果是對應於回歸任務可以設置為"r2",分類任務則可以設定"accuracy",或是其他的評估參數。
  • cv: 交叉驗證的摺數(Folds),一般會設定為5,表示5摺的交叉驗證。
  • n_jobs: 設定為-1代表使用電腦上所有的CPU核心來並行運算。
  • verbose: 設置是否顯示選擇過程的詳細訊息,一般如果沒有要看訊息可以設定 verbose=0 就不會顯示訊息。

使用 SFFS 方法進行模型分類(乳癌資料集)

這裡使用的資料集是Scikit-learn的乳癌資料集,目標是預測腫瘤是良性或是惡性,使用的估計器模型是隨機森林分類器(RandomForestClassifier),並比較使用全部特徵與經過特徵選擇後(10項特徵)的分類結果,所有的程式碼放在Colab提供給大家。

首先,我們需要安裝mlxtend

!pip install mlxtend

一開始進行會使用資料集當中的全部特徵進行建模,後面會使用SFFS方法來挑選較好的特徵組合,重新訓練一個SFFS方法的模型,最後進行評估指標的比較。

# 匯入需要的套件
import time
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
from mlxtend.feature_selection import SequentialFeatureSelector as SFS
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_breast_cancer

# 讀取乳癌資料集
data = load_breast_cancer()

# 將資料集轉換為DataFrame
df = pd.DataFrame(data.data, columns=data.feature_names)

# 'target'是我們要預測的目標
df['target'] = data.target

# 確認資料集數量
print(df.shape)

# 檢查前5筆的資料
df.head()
# 將30項的特徵值與目標變量(target)分割開來
X = df.drop('target', axis=1)
y = df['target']

# 分割訓練和測試集,比例為80%:20%
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=28)

# 使用全部特徵進行隨機森林(RandomForestClassifier)模型訓練
clf = RandomForestClassifier(n_estimators=100, random_state=28)
clf.fit(X_train, y_train)

# 計算預測 y_test 的時間
start_time = time.time()  # 開始計時
y_pred_all = clf.predict(X_test)
end_time = time.time()  # 結束計時

# 計算模型預測所需時間
prediction_time = end_time - start_time

# 評估使用全部特徵的分類模型
accuracy_all = accuracy_score(y_test, y_pred_all)

# 打印預測時間和評估結果
print("使用全部30項特徵的隨機森林模型評估結果:")
print(f"預測 y_test 所需時間: {prediction_time:.4f} 秒")
print(f"Accuracy  (All Features): {accuracy_all}")

# 使用 classification_report 打印更詳細的分類報告
print("\n分類報告 (Classification Report):")
print(classification_report(y_test, y_pred_all))
# 使用 SFFS 進行特徵選擇(基於隨機森林模型的特徵選擇)
sffs = SFS(RandomForestClassifier(n_estimators=100, random_state=28, n_jobs=-1),
           k_features=10, # 設定特徵數量為10
           forward=True,
           floating=True,
           scoring='accuracy',
           cv=5,
           n_jobs=-1,
           verbose=0)

sffs = sffs.fit(X_train, y_train)

# 顯示選擇後的特徵
selected_features = list(sffs.k_feature_names_)
print(f"Selected Features:\n {selected_features}")

# 使用選擇後的特徵進行分類
X_train_selected = sffs.transform(X_train)
X_test_selected = sffs.transform(X_test)

# 重新訓練隨機森林模型
clf = RandomForestClassifier(n_estimators=100, random_state=28)
clf.fit(X_train_selected, y_train)

# 計算預測 y_test 的時間
start_time = time.time()  # 開始計時
y_pred_selected = clf.predict(X_test_selected)
end_time = time.time()  # 結束計時

# 計算預測時間
prediction_time_selected = end_time - start_time

# 評估使用選擇後特徵的分類模型
accuracy_selected = accuracy_score(y_test, y_pred_selected)

# 打印分類報告
classification_report_selected = classification_report(y_test, y_pred_selected)

# 打印結果
print(f"使用選擇後特徵進行預測的隨機森林模型評估結果:")
print(f"預測 y_test 所需時間: {prediction_time_selected:.4f} 秒")
print(f"Accuracy  (Selected Features): {accuracy_selected}")
print("\n分類報告 (Classification Report):")
print(classification_report_selected)
# 繪製使用所有特徵模型與特徵選擇後模型的混淆矩陣
conf_matrix_all = confusion_matrix(y_test, y_pred_all)
conf_matrix_selected = confusion_matrix(y_test, y_pred_selected)

plt.figure(figsize=(12, 6))

# 全部特徵模型的混淆矩陣
plt.subplot(1, 2, 1)
sns.heatmap(conf_matrix_all, annot=True, fmt='d', cmap='Blues')
plt.title('Confusion Matrix (All Features)')
plt.xlabel('Predicted Label')
plt.ylabel('True Label')

# 特徵選擇後模型的混淆矩陣
plt.subplot(1, 2, 2)
sns.heatmap(conf_matrix_selected, annot=True, fmt='d', cmap='Blues')
plt.title('Confusion Matrix (Selected Features)')
plt.xlabel('Predicted Label')
plt.ylabel('True Label')

plt.tight_layout()
plt.show()

結果與分析

在這個範例中,我們使用了SFFS方法進行特徵選擇,選擇10個特徵進行模型訓練;與直接使用所有特徵建立模型來說,SFFS能夠有效地減少不必要的特徵數量,同時保有原始所有特徵數量模型的準確度。

這也表示經過特徵選擇後的資料集有助於減少模型訓練的時間,提升模型的預測速度,由0.0227秒縮短為0.0050秒,新模型的預測速度只花費原始模型約2成左右的時間,另外還能提升模型的泛化預測能力。

結論

包裝法中的序列特徵選擇法,例如序列前向浮動選擇法(SFFS)是一種動態與靈活的方式進行特徵選擇,能夠顯著提升模型的泛化預測能力和預測效率。若是在資料量龐大、特徵數量眾多的情況下,這種方法會更加有效,並適用於多種的預測情境。

以上是麥特在探索特徵選擇工具的經驗上,發現到容易上手且相對高效的特徵選擇方式,希望能給予有興趣的讀者新的發現,讓我們一起在有趣的資料世界中,探索更多超厲害的技術吧!

參考資料

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *