天天看點

專欄 | 基于 Jupyter 的特征工程手冊:特征選擇(四)

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

項目位址:

https://github.com/YC-Coder-Chen/feature-engineering-handbook/blob/master/%E4%B8%AD%E6%96%87%E7%89%88.md

本文将介紹特征工程中的 Wrapper Methods 封裝方法。

目錄:

專欄 | 基于 Jupyter 的特征工程手冊:特征選擇(四)
封裝方法将特征選擇問題視作搜尋問題,即其目标為從特征子集集合中搜尋出一個最佳的子集,而這一子集在模型中表現最佳。在每一步中,其在特征子集上訓練模型,然後對其進行評估,并在下一步繼續調整特征子集,重新訓練評估,直到找到最佳子集或達到最大疊代次數為止。窮盡搜尋在封裝方法中為NP-Hard,故人們提出了一些方法來降低封裝方法所需要的疊代次數,以便可以在有限的時間内達到一個較好的效果。
專欄 | 基于 Jupyter 的特征工程手冊:特征選擇(四)

1.2.1 Deterministic Algorithms 确定性算法

在不考慮模型随機性的情況下,給定相同的資料輸入,确定性算法将始終輸出相同的最優特征子集。

順序向前選擇(SFS),順序向後選擇(SBS)均為确定性算法。順序向前選擇(SFS)方法将從最優單變量模型開始,然後在疊代中,其會在上一步變量子集的基礎上,以窮舉的方法在現有變量子集中增加一個新變量,使得新增一個變量後的變量子集可以獲得最大的模型表現提升。疊代将持續直到所選變量的數量滿足要求為止。

順序向後選擇(SBS)則從适合一個包含所有變量的模型開始,然後在疊代中,其會在上一步變量子集的基礎上,以窮舉的方法在現有變量子集中删除一個對模型負影響最低的變量,直到所選特征的數量滿足要求為止。

但是順序向前選擇(SFS)方法和順序向後選擇(SBS)均為逐漸(step-wise)的方法,都可能會陷入局部最優狀态。

1.2.1.1 Recursive Feature Elimination (SBS) 遞歸式特征消除

在sklearn中,它僅實作遞歸特征消除(SBS)方法。其提供了兩個函數來實作這一方法,一個是RFE,另一個是RFECV。與RFE函數相比,REFCV使用交叉驗證的結果來選擇最優的特征數量,而在RFE中,要選擇的特征數量由使用者預定義。

# RFE函數 示範
import numpy as np
from sklearn.feature_selection import RFE

# 直接載入資料集
from sklearn.datasets import fetch_california_housing
dataset = fetch_california_housing()
X, y = dataset.data, dataset.target # 利用 california_housing 資料集來示範

# 選擇前15000個觀測點作為訓練集
# 剩下的作為測試集
train_set = X[0:15000,:]
test_set = X[15000:,]
train_y = y[0:15000]

# 選擇用于衡量子集表現的有監督的機器學習模型
from sklearn.ensemble import ExtraTreesRegressor # 使用ExtraTrees 模型作為示範
clf = ExtraTreesRegressor(n_estimators=25)
selector = RFE(estimator = clf, n_features_to_select = 4, step = 1) 
# 與RFECV不同,此處RFE函數需要使用者定義選擇的變量數量,此處設定為選擇4個最好的變量,每一步我們僅删除一個變量

selector = selector.fit(train_set, train_y) # 在訓練集上訓練

transformed_train = train_set[:,selector.support_]  # 轉換訓練集
assert np.array_equal(transformed_train, train_set[:,[0,5,6,7]]) # 選擇了第一個,第六個,第七個及第八個變量

transformed_test = test_set[:,selector.support_] # 轉換訓練集
assert np.array_equal(transformed_test, test_set[:,[0,5,6,7]]) # 選擇了第一個,第六個,第七個及第八個變量      
# RFECV 函數 示範
import numpy as np
from sklearn.feature_selection import RFECV

# 直接載入資料集
from sklearn.datasets import fetch_california_housing
dataset = fetch_california_housing()
X, y = dataset.data, dataset.target # 利用 california_housing 資料集來示範

# 選擇前15000個觀測點作為訓練集
# 剩下的作為測試集
train_set = X[0:15000,:]
test_set = X[15000:,]
train_y = y[0:15000]

# 選擇用于衡量子集表現的有監督的機器學習模型
from sklearn.ensemble import ExtraTreesRegressor # 使用ExtraTrees 模型作為示範
clf = ExtraTreesRegressor(n_estimators=25)
selector = RFECV(estimator = clf, step = 1, cv = 5) # 使用5折交叉驗證
# 每一步我們僅删除一個變量
selector = selector.fit(train_set, train_y)

transformed_train = train_set[:,selector.support_]  # 轉換訓練集
assert np.array_equal(transformed_train, train_set) # 選擇了所有的變量

transformed_test = test_set[:,selector.support_] # 轉換訓練集
assert np.array_equal(transformed_test, test_set) # 選擇了所有的變量      

1.2.2 Randomized Algorithms 随機方法

與确定性算法相比,随機方法在搜尋最佳特征子集時引入了一定程度的随機性。是以,在相同資料輸入的情形下,它可能會輸出不同的最優特征子集結果,但此方法中的随機性将有助于避免模型陷入局部最優結果。

1.2.2.1 Simulated Annealing (SA) 基于模拟退火特征選擇

模拟退火是一種随機最優化方法,近年來被引入到特征選擇領域。在每一步中,我們将根據目前的最優特征子集随機選擇一個特征子集。若新的特征子集效果更好,那麼我們将采用它并更新目前最優特征子集。若新特征子集的表現不佳,我們仍會以一定的機率接受它,這個接受機率取決于目前的狀态(溫度)。

以一定的機率接受變現不佳的特征子集對于模拟退火算法至關重要,因為這有助于算法避免陷入局部最優狀态。随着疊代的進行,模拟退火算法可收斂為良好且穩定的最終結果。

由于未發現能較好實作SA算法的函數,是以我編寫了一個python腳本來實作SA算法,以供您參考。其能夠很好地相容sklearn中的模型,支援分類及回歸問題。它還提供了内置交叉驗證方法。

公式:

在每一步中,接受表現不佳的特征子集的機率為:

專欄 | 基于 Jupyter 的特征工程手冊:特征選擇(四)

Prob為接受表現不佳的特征子集的機率, 𝑙𝑜𝑠𝑠𝑛 為新特征子集的損失(loss), 𝑙𝑜𝑠𝑠𝑜 為新特征子集建立前的最優(最低)損失(loss), 𝐶𝑢𝑟_𝑇𝑒𝑚𝑝𝑒𝑟𝑎𝑡𝑢𝑟𝑒 為目前的溫度。模拟退火的僞代碼為:

專欄 | 基于 Jupyter 的特征工程手冊:特征選擇(四)

回歸問題示範

import sys 
sys.path.append("..") 
from SA import Simulated_Annealing # 導入我們撰寫的子產品

# 直接載入資料集
from sklearn.datasets import fetch_california_housing
dataset = fetch_california_housing()
X, y = dataset.data, dataset.target # 利用 california_housing 資料集來示範

# 選擇前15000個觀測點作為訓練集
# 剩下的作為測試集
train_set = X[0:15000,:]
test_set = X[15000:,]
train_y = y[0:15000]

# 選擇用于衡量子集表現的有監督的機器學習模型
from sklearn.ensemble import ExtraTreesRegressor # 使用ExtraTrees 模型作為示範

# 選擇模拟退火中評價特征子集的的損失函數
from sklearn.metrics import mean_squared_error # 回歸問題我們使用MSE

clf = ExtraTreesRegressor(n_estimators=25)
selector = Simulated_Annealing(loss_func = mean_squared_error, estimator = clf, 
                               init_temp = 0.2, min_temp = 0.005, iteration = 10, alpha = 0.9)
# 在訓練集中訓練
# SA.py中有具體每個參數的含義,此處不贅述

selector.fit(X_train = train_set, y_train = train_y, cv = 5) # 使用5折交叉驗證

transformed_train = selector.transform(train_set) # 轉換訓練集
transformed_test = selector.transform(test_set)  # 轉換測試集      
專欄 | 基于 Jupyter 的特征工程手冊:特征選擇(四)
import sys 
sys.path.append("..") 
import numpy as np
import random
from SA import Simulated_Annealing # 導入我們撰寫的子產品

from sklearn.datasets import load_iris  # 利用iris資料作為示範資料集

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

# iris 資料集使用前需要被打亂順序
np.random.seed(1234)
idx = np.random.permutation(len(X))
X = X[idx]
y = y[idx]

# 選擇前100個觀測點作為訓練集
# 剩下的前20個觀測點作為驗證集,剩下的30個觀測作為測試集
train_set = X[0:100,:]
val_set = X[100:120,:]
test_set = X[120:,:]

train_y = y[0:100]
val_y = y[100:120]
test_y = y[120:]

# 重制随機種子 
# 随機方法需要随機性的存在
random.seed()
np.random.seed()

# 選擇用于衡量子集表現的有監督的機器學習模型
from sklearn.ensemble import ExtraTreesClassifier # we use extratree as predictive model

# 選擇模拟退火中評價特征子集的的損失函數
from sklearn.metrics import log_loss # 回歸問題中,我們使用交叉熵損失函數

clf = ExtraTreesClassifier(n_estimators=25)
selector = Simulated_Annealing(loss_func = log_loss, estimator = clf, 
                               init_temp = 0.2, min_temp = 0.005, iteration = 10, 
                               alpha = 0.9, predict_type = 'predict_proba')
# 在訓練集中訓練
# SA.py中有具體每個參數的含義,此處不贅述

selector.fit(X_train = train_set, y_train = train_y, X_val = val_set, 
             y_val = val_y, stop_point = 15) 
# 此函數允許使用者導入自己定義的驗證集,此處嘗試一下

transformed_train = selector.transform(train_set)  # 轉換訓練集
transformed_test = selector.transform(test_set)  # 轉換測試集      
selector.best_sol # 傳回最優特征的索引
selector.best_loss; # 傳回最優特征子集對應的損失      

1.2.2.2 Genetic Algorithm (GA) 基于基因算法特征選擇

遺傳算法是一種基于進化生物學概念的最優化搜尋算法。它借鑒了自然界中的進化過程,并通過允許個體候選解通過“交叉”和“變異”來進化得到更優的候選解及種群。其還結合了自然界中的競争理念,即僅允許最合适或最優的幾個候選解“生存”下來并“繁殖”其後代。經過種群及個體候選解的持續疊代,基因算法(GA)會收斂到優化解決方案。 

與模拟退火類似,我也編寫了一個python腳本來實作GA算法,以供您參考。它提供了兩種算法,包括“one-max”和“ NSGA2”。“one-max”為傳統的單目标GA算法,“NSGA2”則為一個多目标GA算法。在特征選擇中,“one-max”的目标是減少模拟在驗證集上的損失,而“NSGA2”的目标一是減少損失,二是同時要最小化特征子集中特征的數量。 

此python腳本能夠很好地相容sklearn中的模型,支援分類及回歸問題。它還提供了内置交叉驗證方法。 

基因算法的僞代碼如下:

專欄 | 基于 Jupyter 的特征工程手冊:特征選擇(四)
import sys 
sys.path.append("..") 
from GA import Genetic_Algorithm # 導入我們撰寫的子產品

# 直接載入資料集
from sklearn.datasets import fetch_california_housing
dataset = fetch_california_housing()
X, y = dataset.data, dataset.target # 利用 california_housing 資料集來示範

# 選擇前15000個觀測點作為訓練集
# 剩下的作為測試集
train_set = X[0:15000,:]
test_set = X[15000:,]
train_y = y[0:15000]

# 選擇用于衡量子集表現的有監督的機器學習模型
from sklearn.ensemble import ExtraTreesRegressor # 使用ExtraTrees 模型作為示範

# 選擇模拟退火中評價特征子集的的損失函數
from sklearn.metrics import mean_squared_error # 回歸問題我們使用MSE

clf = ExtraTreesRegressor(n_estimators=25)
selector = Genetic_Algorithm(loss_func = mean_squared_error, estimator = clf, 
                             n_gen = 10, n_pop = 20, algorithm = 'NSGA2')
# 在訓練集中訓練
# GA.py中有具體每個參數的含義,此處不贅述

selector.fit(X_train = train_set, y_train = train_y, cv = 5) # 使用5折交叉驗證

transformed_train = selector.transform(train_set) # 轉換訓練集
transformed_test = selector.transform(test_set)  # 轉換測試集      
專欄 | 基于 Jupyter 的特征工程手冊:特征選擇(四)
import sys 
sys.path.append("..") 
import numpy as np
import random
from GA import Genetic_Algorithm # 導入我們撰寫的子產品

from sklearn.datasets import load_iris  # 利用iris資料作為示範資料集

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

# iris 資料集使用前需要被打亂順序
np.random.seed(1234)
idx = np.random.permutation(len(X))
X = X[idx]
y = y[idx]

# 選擇前100個觀測點作為訓練集
# 剩下的前20個觀測點作為驗證集,剩下的30個觀測作為測試集
train_set = X[0:100,:]
val_set = X[100:120,:]
test_set = X[120:,:]

train_y = y[0:100]
val_y = y[100:120]
test_y = y[120:]

# 重制随機種子 
# 随機方法需要随機性的存在
random.seed()
np.random.seed()

# 選擇用于衡量子集表現的有監督的機器學習模型
from sklearn.ensemble import ExtraTreesClassifier # we use extratree as predictive model

# 選擇模拟退火中評價特征子集的的損失函數
from sklearn.metrics import log_loss # 回歸問題中,我們使用交叉熵損失函數

clf = ExtraTreesClassifier(n_estimators=25)
selector = Genetic_Algorithm(loss_func = log_loss, estimator = clf, 
                             n_gen = 15, n_pop = 10, predict_type = 'predict_proba')
# 在訓練集中訓練
# GA.py中有具體每個參數的含義,此處不贅述

selector.fit(X_train = train_set, y_train = train_y, X_val = val_set, 
             y_val = val_y, stop_point = 15) 
# 此函數允許使用者導入自己定義的驗證集,此處嘗試一下

transformed_train = selector.transform(train_set)  # 轉換訓練集
transformed_test = selector.transform(test_set)  # 轉換測試集      
selector.best_sol # 傳回最優特征的索引
selector.best_loss; # 傳回最優特征子集對應的損失      

基于 Jupyter 的特征工程手冊:特征選擇:

專欄 | 基于 Jupyter 的特征工程手冊:特征選擇(一) 專欄 | 基于 Jupyter 的特征工程手冊:特征選擇(二) 專欄 | 基于 Jupyter 的特征工程手冊:特征選擇(三)

中文版 Jupyter 位址:

https://github.com/YC-Coder-Chen/feature-engineering-handbook/tree/master/%E4%B8%AD%E6%96%87%E7%89%88