專欄 | 基於 Jupyter 的特徵工程手冊:特徵選擇(三)

紅色石頭發表於2020-04-24

資料預處理後,我們生成了大量的新變數(比如獨熱編碼生成了大量僅包含0或1的變數)。但實際上,部分新生成的變數可能是多餘:一方面它們本身不一定包含有用的資訊,故無法提高模型效能;另一方面過這些多餘變數在構建模型時會消耗大量記憶體和計算能力。因此,我們應該進行特徵選擇並選擇特徵子集進行建模。

專案地址:

本文將介紹特徵工程中的 Multivariate Filter Methods 多元特徵過濾。

目錄:

1.1.2 Multivariate Filter Methods 多元特徵過濾

單變數特徵過濾僅考慮了每一變數與目標變數之間的關係,而忽視了變數間的相關性。多元變數過濾則解決了這一問題,其考慮了變數之間的相互關係,基於整個特徵空間選擇最佳特徵。因此多元特徵過濾在刪除冗餘變數方面表現更好。這裡利用亞利桑那州立大學開發的skfeature模組來進行多元特徵過濾。

1.1.2.1 Max-Relevance Min-Redundancy (mRMR) 最大相關最小冗餘

最大相關最小冗餘試圖尋找一個與目標變數有較高相關性(例如:MI)的變數子集,同時這個子集中的變數還應具有較低的相互關聯性。通過解析原始碼,我們發現,skfeature中最大相關最小冗餘方法僅適用於分類問題中的離散特徵,因為它計算過程中使用的是計算離散情形下的互資訊 (MI)的公式。

公式:

假設資料集共包含m個特徵,則基於mRMR公式,其中第n個特徵的重要性可被表示為:

( , ) 為變數 與目標變數Y的互資訊。1/| |∑ ∈ ( , )為變數 與現有變數子集中所有變數的互資訊的平均值。

mRMR其實是一個逐步(step-wise)的方法,在mRMR特徵選擇過程的每一步中,具有最高特徵重要性 ( )的變數 ,( ∉ )將會被加入子集中,直至子集中的變數數達到使用者要求。

import numpy as np
from skfeature.function.information_theoretical_based import MRMR
from sklearn.datasets import load_iris  # 利用iris資料作為演示資料集

# 載入資料集
iris = load_iris()
X, y = iris.data, iris.target

# 選擇前100個觀測點作為訓練集
# 剩下的50個觀測點作為測試集
# 由於skfeature中的mRMR僅適用於離散變數
# 因此我們通過將float轉換為int而把所有連續變數轉換為離散變數
# 此轉換僅用於演示目的

train_set = X[0:100,:].astype(int)
test_set = X[100:,].astype(int)
train_y = y[0:100].astype(int)

feature_index,_,_ = MRMR.mrmr(train_set, train_y, n_selected_features=2) # 在訓練集上訓練
transformed_train = train_set[:,feature_index] # 轉換訓練集
assert np.array_equal(transformed_train, train_set[:,[2,3]])  # 其選擇了第三個及第四個變數

transformed_test = test_set[:,feature_index] # 轉換測試集
assert np.array_equal(transformed_test, test_set[:,[2,3]]) # 其選擇了第三個及第四個變數

1.1.2.2 Correlation-based Feature Selection (CFS) 基於相關性的特徵選擇

與mRMR類似,基於相關性的特徵選擇(CFS)也基於一個類似的假設:一個好的特徵子集應包含與目標高度相關且彼此不相關的特徵。通過解析原始碼,我們發現,skfeature中CFS的實現也僅適用於分類問題中的離散特徵。因為其使用的是離散情形下的對稱不確定性(symmetrical uncertainty)作為變數間相關性的衡量標準。

公式:

為特徵子集. 我們需要尋找最大化 的最優子集 ∗。

( , )為離散變數 與目標變數 間的對稱不確定性(SU)。

( , )為離散變數 與離散變數 間的對稱不確定性(SU)。

import numpy as np
from skfeature.function.statistical_based import CFS
from sklearn.datasets import load_iris  # 利用iris資料作為演示資料集

# 載入資料集
iris = load_iris()
X, y = iris.data, iris.target

# 選擇前100個觀測點作為訓練集
# 剩下的50個觀測點作為測試集
# 由於skfeature中的CFS僅適用於離散變數
# 因此我們通過將float轉換為int而把所有連續變數轉換為離散變數
# 此轉換僅用於演示目的

train_set = X[0:100,:].astype(int)
test_set = X[100:,].astype(int)
train_y = y[0:100].astype(int)

num_feature = 2 # 從原資料集中選擇兩個變數

feature_index = CFS.cfs(train_set, train_y) # 在訓練集上訓練
transformed_train = train_set[:,feature_index[0:num_feature]] # 轉換訓練集
assert np.array_equal(transformed_train, train_set[:,[3,2]])  # 其選擇了第三個及第四個變數

transformed_test = test_set[:,feature_index[0:num_feature]] # 轉換測試集
assert np.array_equal(transformed_test, test_set[:,[3,2]]) # 其選擇了第三個及第四個變數

1.1.2.3 Fast Correlation-based Filter (FCBF) 基於相關性的快速特徵選擇

相比於CFS,FCBS能夠更加高效的篩選變數。其同樣為逐步(step-wise)的方法,具體步驟與mRMR非常類似,但FCBS使用對稱不確定性(SU)衡量變數間的關聯性。FCBF首先剔除與目標變數具有較低SU值的變數,並對剩下的變數按與目標變數的SU值從最高到最低排序,然後逐一刪除冗餘特徵。與mRMR,CFS相似,在skfeature中實現的FCBF僅適用於具有離散變數的分類問題。

公式:

步驟:

1)計算每個特徵變數 與目標變數 之間的相關性 ( , )

2)僅保留 ( , ) 大於一定閾值 的特徵變數,組成候選列表

3)按照 ( , ) 值的大小對 中的變數從大到小排序

4)按順序依次計算每一個特徵 與候選列表 中順序靠後的每一個特徵 的相關SU值 ( , )

5)若 ( , ) 大於 ( , ) ,則從候選列表 中刪除

import numpy as np
from skfeature.function.information_theoretical_based import FCBF
from sklearn.datasets import load_iris  # 利用iris資料作為演示資料集

# 載入資料集
iris = load_iris()
X, y = iris.data, iris.target

# 選擇前100個觀測點作為訓練集
# 剩下的50個觀測點作為測試集
# 由於skfeature中的FCFS僅適用於離散變數
# 因此我們通過將float轉換為int而把所有連續變數轉換為離散變數
# 此轉換僅用於演示目的

train_set = X[0:100,:].astype(int)
test_set = X[100:,].astype(int)
train_y = y[0:100].astype(int)

num_feature = 2 # 從原資料集中選擇兩個變數

feature_index = FCBF.fcbf(train_set, train_y, n_selected_features = num_feature)[0] # 在訓練集上訓練
transformed_train = train_set[:,feature_index[0:num_feature]] # 轉換訓練集
assert np.array_equal(transformed_train, train_set[:,[3]])  # 其僅選擇了第四個變數 
# 這是由於其他變數目標變數 之間的相關性過低造成的

transformed_test = test_set[:,feature_index[0:num_feature]] # 轉換測試集
assert np.array_equal(transformed_test, test_set[:,[3]]) # 其僅選擇了第四個變數

1.1.2.4 ReliefF

ReliefF方法是一種基於Relief方法的特徵加權演算法。在Relief方法中,其根據特徵與目標變數的相關性強弱(二分類)給變數分配權重,並刪除權重低於特定閾值的特徵。其將相關性定義為變數區分鄰近觀測點的能力。

具體來說,在每一步中,Relief方法都會從訓練集中隨機選擇一個觀測點S,然後找到具有相同目標標籤的S的最近鄰觀測點,稱為NearHit。它還將找到具有不同目標標籤的S的最近鄰觀測點,稱為NearMiss。然後根據以下規則更新每個功能的權重:

1)若觀測點S在某變數上與NearHit的距離大於與NearMiss的距離,則該變數的權重將增加,因為變數有助於區分最鄰近情形下的目標標籤。2)相反,若觀測點S在某變數上與NearHit的距離小於與NearMiss的距離,則該變數的權重會降低。

將上述過程重複m次,最後我們會獲得每個特徵變數的平均權重。特徵變數的權重越大,則特徵的分類能力越強,越應該被留在最終的特徵子集中。

在ReliefF中,其修改了權重更新的方式,因此ReliefF方法可以被應用於多類分類問題。另外,它隨機取樣K個最近的觀測點而不是一個。

在skfeature中實現的ReliefF可用於分類問題中的連續特徵或二元類別特徵,因其使用的是L1範數來衡量差異。針對非二元特徵,我們可以先將其獨熱編碼,再使用ReliefF方法。

公式:

1 and 2 為任意兩個觀測點。 為某一特徵變數. S為我們選擇的觀測點. 為第j個NearHit, 為第j個NearMiss. C為與我們所選的觀測點不同的其他目標類別標籤。

import numpy as np
from skfeature.function.similarity_based import reliefF
from sklearn.datasets import load_iris  # 利用iris資料作為演示資料集

# 載入資料集
iris = load_iris()
X, y = iris.data, iris.target

# 選擇前100個觀測點作為訓練集
# 剩下的50個觀測點作為測試集
# skfeature中的reliefF直接適用於連續變數

train_set = X[0:100,:]
test_set = X[100:,]
train_y = y[0:100]

num_feature = 2 # 從原資料集中選擇兩個變數

score = reliefF.reliefF(train_set, train_y) # 計算每一個變數的權重
feature_index = reliefF.feature_ranking(score) # 依據權重選擇變數
transformed_train = train_set[:,feature_index[0:num_feature]] # 轉換訓練集
assert np.array_equal(transformed_train, train_set[:,[2, 3]])  # 其選擇了第三個及第四個變數

transformed_test = test_set[:,feature_index[0:num_feature]] # 轉換測試集
assert np.array_equal(transformed_test, test_set[:,[2, 3]]) # 其選擇了第三個及第四個變數

1.1.2.5 Spectral Feature Selection (SPEC) 基於譜圖的特徵選擇

基於譜圖的特徵選擇(SPEC)方法是基於譜圖理論的無監督方法。其首先建立變數相似度集合S,並建立其圖表示。然後,其根據構造圖的頻譜評估特徵。由於在skfeature中實現的SPEC方基於RBF(高斯)核心建立相似集,因此其可用於分類問題中的連續特徵或二元類別特徵。針對非二元特徵,我們可以先將其獨熱編碼,再使用ReliefF方法。

import numpy as np
from skfeature.function.similarity_based import SPEC
from sklearn.datasets import load_iris  # 利用iris資料作為演示資料集

# 載入資料集
iris = load_iris()
X, y = iris.data, iris.target

# 選擇前100個觀測點作為訓練集
# 剩下的50個觀測點作為測試集
# skfeature中的SEPC方法直接適用於連續變數

train_set = X[0:100,:]
test_set = X[100:,]
train_y = y[0:100]

num_feature = 2 # 從原資料集中選擇兩個變數

score = SPEC.spec(train_set) # 計算每一個變數的得分
feature_index = SPEC.feature_ranking(score) #依據變數得分選擇變數
transformed_train = train_set[:,feature_index[0:num_feature]] # 轉換訓練集
assert np.array_equal(transformed_train, train_set[:,[1, 0]])  # 其選擇了第一個及第二個變數

transformed_test = test_set[:,feature_index[0:num_feature]] # 轉換測試集
assert np.array_equal(transformed_test, test_set[:,[1, 0]]) # 其選擇了第一個及第二個變數

https://i.iter01.com/images/1926f8188118b4989596a882cb2d4dff27c7e0572fddab7a9553a5803e0f9295.jpg

專欄 | 基於 Jupyter 的特徵工程手冊:資料預處理(一)

專欄 | 基於 Jupyter 的特徵工程手冊:資料預處理(二)

專欄 | 基於 Jupyter 的特徵工程手冊:資料預處理(三)

專欄 | 基於 Jupyter 的特徵工程手冊:資料預處理(四)

專欄 | 基於 Jupyter 的特徵工程手冊:特徵選擇(一)

專欄 | 基於Jupyter 的特徵工程手冊:特徵選擇(二)

目前該專案完整中文版正在製作中,請持續關注哦~

中文版 Jupyter 地址:

https://github.com/YC-Coder-Chen/feature-engineering-handbook/blob/master/中文版/2.%20特徵選擇.ipynb


本文首發於公眾號:AI有道(ID: redstonewill),歡迎關注!

相關文章