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

作者:陳穎祥、楊子晗

編譯:AI有道

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

項目地址:

https://github.com/YC-Coder-Chen/feature-engineering-handbook

本文將介紹特徵工程第一種算法:Filter Methods 過濾法(上)。

目錄:

1.1 Filter Methods 過濾法

過濾法通過使用一些統計量或假設檢驗結果爲每個變量打分。得分較高的功能往往更加重要,因此應被包含在子集中。以下爲一個簡單的基於過濾法的機器學習工作流(以最簡單的訓練-驗證-測試這種數據集劃分方法爲例)。

1.1.1 Univariate Filter Methods 單變量特徵過濾

單變量過濾方法依據單變量統計量或統計檢驗選擇最佳特徵。其僅僅考慮單個變量與目標變量的關係(方差選擇法僅基於單個變量)。

1.1.1.1 Variance Threshold 方差選擇法

方差選擇法刪除變量方差低於某個閾值的所有特徵。例如,我們應刪除方差爲零的特徵(所有觀測點中具有相同值的特徵),因爲該特徵無法解釋目標變量的任何變化。

import numpy as np
import pandas as pd
from sklearn.feature_selection import VarianceThreshold


# 合成一些數據集用於演示
train_set = np.array([[1,2,3],[1,4,7],[1,4,9]]) # 可見第一個變量方差爲0
# array([[1, 2, 3],
#        [1, 4, 7],
#        [1, 4, 9]])


test_set = np.array([[3,2,3],[1,2,7]]) # 故意將第二個變量方差設爲0
# array([[3, 2, 3],
#        [1, 2, 7]])


selector = VarianceThreshold()
selector.fit(train_set) # 在訓練集上訓練
transformed_train = selector.transform(train_set) # 轉換訓練集
# 下面爲返回結果,可見第一個變量已被刪除
# array([[2, 3],
#        [4, 7],
#        [4, 9]])


transformed_test = selector.transform(test_set) # 轉換測試集
# 下面爲返回結果,可見第一個變量已被刪除
# array([[2, 3],
#        [2, 7]])
# 雖然測試集中第二個變量的方差也爲0
# 但是我們的選擇是基於訓練集,所以我們依然刪除第一個變量

1.1.1.2 Pearson Correlation (regression problem) 皮爾森相關係數 (迴歸問題)

皮爾森相關係數一般用於衡量兩個連續變量之間的線性相關性,也可以用於衡量二元變量與目標變量的相關性。故可以將類別變量利用獨熱編碼轉換爲多個二元變量之後利用皮爾森相關係數進行篩選。

公式:

import numpy as np
from scipy.stats import pearsonr
from sklearn.feature_selection import SelectKBest


# 直接載入數據集
from sklearn.datasets import fetch_california_housing
dataset = fetch_california_housing()
X, y = dataset.data, dataset.target # 利用 california_housing 數據集來演示
# 此數據集中,X,y均爲連續變量,故此滿足使用皮爾森相關係數的條件


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


# sklearn 中沒有直接的方程可以使用
# 此處將用 scipy.stats.pearsonr方程來實現基於皮爾森相關係數的特徵過濾
# 注意 scipy.stats.pearsonr 計算的是兩個變量之間的相關係數
# 因sklearn SelectKBest需要,我們將基於scipy.stats.pearsonr 重寫允許多特徵同時輸入的方程 udf_pearsonr


def udf_pearsonr(X, y):
    # 將會分別計算每一個變量與目標變量的關係
    result = np.array([pearsonr(x, y) for x in X.T]) # 包含(皮爾森相關係數, p值) 的列表
    return np.absolute(result[:,0]), result[:,1]


# SelectKBest 將會基於一個判別方程自動選擇得分高的變量
# 這裏的判別方程爲皮爾森相關係數
selector = SelectKBest(udf_pearsonr, k=2) # k => 我們想要選擇的變量數
selector.fit(train_set, train_y) # 在訓練集上訓練
transformed_train = selector.transform(train_set) # 轉換訓練集
transformed_train.shape #(15000, 2), 其選擇了第一個及第七個變量 
assert np.array_equal(transformed_train, train_set[:,[0,6]])


transformed_test = selector.transform(test_set) # 轉換測試集
assert np.array_equal(transformed_test, test_set[:,[0,6]]);
# 可見對於測試集,其依然選擇了第一個及第七個變量
# 驗算一下我們的結果
for idx in range(train_set.shape[1]):
    pea_score, p_value = pearsonr(train_set[:,idx], train_y)
    print(f"第{idx + 1}個變量和目標的皮爾森相關係數的絕對值爲{round(np.abs(pea_score),2)}, p-值爲{round(p_value,3)}")
# 應選擇第一個及第七個變量
第1個變量和目標的皮爾森相關係數的絕對值爲0.7, p-值爲0.0
第2個變量和目標的皮爾森相關係數的絕對值爲0.07, p-值爲0.0
第3個變量和目標的皮爾森相關係數的絕對值爲0.14, p-值爲0.0
第4個變量和目標的皮爾森相關係數的絕對值爲0.04, p-值爲0.0
第5個變量和目標的皮爾森相關係數的絕對值爲0.02, p-值爲0.011
第6個變量和目標的皮爾森相關係數的絕對值爲0.05, p-值爲0.0
第7個變量和目標的皮爾森相關係數的絕對值爲0.23, p-值爲0.0
第8個變量和目標的皮爾森相關係數的絕對值爲0.08, p-值爲0.0

1.1.1.3 Distance Correlation (regression problem) 距離相關係數 (迴歸問題)

與皮爾森相關係數類似,距離相關係數也一般被用於衡量兩個連續變量之間的相關性。但與皮爾森相關係數不同的是,距離相關係數還衡量了兩個變量之間的非線性關聯。 

公式: 

首先,計算(n x n)距離矩陣dX。dX中的每一個元素爲???????????????? 。類似的,我們也可以計算距離矩陣dY,其中dY中的每個元素爲????????????????。????????????????是爲觀測點i與觀測點j之間的距離:

其次,我們計算如下雙中心距離並更新距離矩陣。其中, ????????¯ 爲距離矩陣dX的第i行平均值, ????????¯ 爲距離矩陣dX的第j列的平均值, ∑????????∑???????????????????????? 爲全局平均值:

隨後,我們便可以算出樣本距離協方差及距離方差:

最後,距離相關係數 ????????????????(????,????) 便爲如下:

import numpy as np
from dcor import distance_correlation
from dcor.independence import distance_covariance_test
from sklearn.feature_selection import SelectKBest


# 直接載入數據集
from sklearn.datasets import fetch_california_housing
dataset = fetch_california_housing()
X, y = dataset.data, dataset.target # 利用 california_housing 數據集來演示
# 此數據集中,X,y均爲連續變量,故此滿足使用距離相關係數的條件


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


# sklearn 中沒有直接的方程可以使用
# 此處將用 dcor.distance_correlation方程來實現基於距離相關係數的特徵過濾
# 注意 dcor.distance_correlation 計算的是兩個變量之間的相關係數
# 因sklearn SelectKBest需要,我們將基於dcor.distance_correlation 重寫允許多特徵同時輸入的方程 udf_dcorr


def udf_dcorr(X, y):
    # 將會分別計算每一個變量與目標變量的關係
    result = np.array([[distance_correlation(x, y), 
                        distance_covariance_test(x,y)[0]]for x in X.T]) # 包含(距離相關係數, p值) 的列表
    return result[:,0], result[:,1]


# SelectKBest 將會基於一個判別方程自動選擇得分高的變量
# 這裏的判別方程爲距離相關係數
selector = SelectKBest(udf_dcorr, k=2) # k => 我們想要選擇的變量數
selector.fit(train_set, train_y) # 在訓練集上訓練
transformed_train = selector.transform(train_set) # 轉換訓練集
transformed_train.shape #(15000, 2), 其選擇了第一個及第三個變量 
assert np.array_equal(transformed_train, train_set[:,[0,2]])


transformed_test = selector.transform(test_set) # 轉換測試集
assert np.array_equal(transformed_test, test_set[:,[0,2]]);
# 可見對於測試集,其依然選擇了第一個及第三個變量
# 驗算一下我們的結果
for idx in range(train_set.shape[1]):
    d_score = distance_correlation(train_set[:,idx], train_y)
    p_value = distance_covariance_test(train_set[:,idx], train_y)[0]
    print(f"第{idx + 1}個變量和目標的距離相關係數爲{round(d_score,2)}, p-值爲{round(p_value,3)}")
# 應選擇第一個及第三個變量
第1個變量和目標的距離相關係數爲0.66, p-值爲1.0
第2個變量和目標的距離相關係數爲0.07, p-值爲1.0
第3個變量和目標的距離相關係數爲0.31, p-值爲1.0
第4個變量和目標的距離相關係數爲0.12, p-值爲1.0
第5個變量和目標的距離相關係數爲0.08, p-值爲1.0
第6個變量和目標的距離相關係數爲0.29, p-值爲1.0
第7個變量和目標的距離相關係數爲0.25, p-值爲1.0
第8個變量和目標的距離相關係數爲0.19, p-值爲1.0

1.1.1.4 F-Score (regression problem) F-統計量 (迴歸問題)

F統計量(F-Score)用於檢驗線性迴歸模型的整體顯著性。在sklearn中,其將對每一個變量分別建立一個一元的線性迴歸模型,然後分別報告每一個對應模型的F統計量。F-統計量的零假設是該線性模型係數不顯著,在一元模型中,該統計量能夠反映各變量與目標變量之間的線性關係。因此,我們應該選擇具有較高F統計量的特徵(更有可能拒絕原假設)。

公式:

SST爲總平方和,SSR爲迴歸平方和,p爲線性迴歸自變量數(包括常數項,故在上述的一元線性模型中,p=2), ???? 爲自變量與因變量的線性相關係數,n爲總觀測數。因上述線性模型爲一元線性模型,故可證 ????2=????2 。

import numpy as np
from sklearn.feature_selection import f_regression
from sklearn.feature_selection import SelectKBest


# 直接載入數據集
from sklearn.datasets import fetch_california_housing
dataset = fetch_california_housing()
X, y = dataset.data, dataset.target # 利用 california_housing 數據集來演示
# 此數據集中,X,y均爲連續變量,故此滿足使用F統計量的條件


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


# sklearn 中直接提供了方程用於計算F統計量
# SelectKBest 將會基於一個判別方程自動選擇得分高的變量
# 這裏的判別方程爲F統計量
selector = SelectKBest(f_regression, k=2) # k => 我們想要選擇的變量數
selector.fit(train_set, train_y) # 在訓練集上訓練
transformed_train = selector.transform(train_set) # 轉換訓練集
transformed_train.shape #(15000, 2), 其選擇了第一個及第七個變量 
assert np.array_equal(transformed_train, train_set[:,[0,6]])


transformed_test = selector.transform(test_set) # 轉換測試集
assert np.array_equal(transformed_test, test_set[:,[0,6]]);
# 可見對於測試集,其依然選擇了第一個及第七個變量
# 驗算一下我們的結果
for idx in range(train_set.shape[1]):
    score, p_value = f_regression(train_set[:,idx].reshape(-1,1), train_y)
    print(f"第{idx + 1}個變量的F統計量爲{round(score[0],2)}, p-值爲{round(p_value[0],3)}")
# 故應選擇第一個及第七個變量
第1個變量的F統計量爲14111.79, p-值爲0.0
第2個變量的F統計量爲71.99, p-值爲0.0
第3個變量的F統計量爲317.04, p-值爲0.0
第4個變量的F統計量爲23.93, p-值爲0.0
第5個變量的F統計量爲6.54, p-值爲0.011
第6個變量的F統計量爲35.93, p-值爲0.0
第7個變量的F統計量爲846.61, p-值爲0.0
第8個變量的F統計量爲98.06, p-值爲0.0

專欄系列:

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

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

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

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

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

中文版 Jupyter 地址:

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


推薦閱讀

(點擊標題可跳轉閱讀)

乾貨 | 公衆號歷史文章精選

我的深度學習入門路線

我的機器學習入門路線圖

算法工程師必備

AI有道年度技術文章電子版PDF來啦!

掃描下方二維碼,添加 AI有道小助手微信,可申請入羣,並獲得2020完整技術文章合集PDF(一定要備註:入羣 + 地點 + 學校/公司。例如:入羣+上海+復旦。 

長按掃碼,申請入羣

(添加人數較多,請耐心等待)

 

最新 AI 乾貨,我在看 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章