专栏 | 基于 Jupyter 的特征工程手册:特征选择(二)
作者:陳穎祥、楊子晗
編譯:AI有道
數據預處理后,我們生成了大量的新變量(比如獨熱編碼生成了大量僅包含0或1的變量)。但實際上,部分新生成的變量可能是多余:一方面它們本身不一定包含有用的信息,故無法提高模型性能;另一方面過這些多余變量在構建模型時會消耗大量內存和計算能力。因此,我們應該進行特征選擇并選擇特征子集進行建模。
項目地址:
https://github.com/YC-Coder-Chen/feature-engineering-handbook
本文將介紹特征工程第一種算法:Filter Methods 過濾法(下)。
目錄:
1.1.1.5?Mutual Information (regression problem) 互信息 (回歸問題)
互信息(Mutual Information)衡量變量間的相互依賴性。其本質為熵差,即 ????(????)?????(????|????),即知道另一個變量信息后混亂的降低程度 。當且僅當兩個隨機變量獨立時MI等于零。MI值越高,兩變量之間的相關性則越強。與Pearson相關和F統計量相比,它還捕獲了非線性關系。
公式:
若兩個變量均為離散變量:
p(????,????)(????,????) 為x和y的聯合概率質量函數 (PMF), p????(????)則為x的聯合概率質量函數 (PMF)。?
若兩個變量均為連續變量:
p(????,????)(????,????) 為x和y的聯合概率密度函數 (PDF),p????(????)則為x的概率密度函數 (PDF)。連續變量情形下,在實際操作中,往往先對數據離散化分桶,然后逐個桶進行計算。?
但是實際上,一種極有可能的情況是,x和y中的一個可能是離散變量,而另一個是連續變量。因此在sklearn中,它基于[1]和[2]中提出的基于k最臨近算法的熵估計非參數方法。?
[1] A. Kraskov, H. Stogbauer and P. Grassberger, “Estimating mutual information”. Phys. Rev. E 69, 2004.?
[2] B. C. Ross “Mutual Information between Discrete and Continuous Data Sets”. PLoS ONE 9(2), 2014.
import numpy as np from sklearn.feature_selection import mutual_info_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均為連續變量,故此滿足使用MI的條件# 選擇前15000個觀測點作為訓練集 # 剩下的作為測試集 train_set = X[0:15000,:].astype(float) test_set = X[15000:,].astype(float) train_y = y[0:15000].astype(float)# KNN中的臨近數是一個非常重要的參數 # 故我們重寫了一個新的MI計算方程更好的來控制這一參數 def udf_MI(X, y):result = mutual_info_regression(X, y, n_neighbors = 5) # 用戶可以輸入想要的臨近數return result# SelectKBest 將會基于一個判別方程自動選擇得分高的變量 # 這里的判別方程為F統計量 selector = SelectKBest(udf_MI, 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,7]])transformed_test = selector.transform(test_set) # 轉換測試集 assert np.array_equal(transformed_test, test_set[:,[0,7]]); # 可見對于測試集,其依然選擇了第一個及第八個變量 # 驗算上述結果 for idx in range(train_set.shape[1]):score = mutual_info_regression(train_set[:,idx].reshape(-1,1), train_y, n_neighbors = 5)print(f"第{idx + 1}個變量與因變量的互信息為{round(score[0],2)}") # 故應選擇第一個及第八個變量 第1個變量與因變量的互信息為0.37 第2個變量與因變量的互信息為0.03 第3個變量與因變量的互信息為0.1 第4個變量與因變量的互信息為0.03 第5個變量與因變量的互信息為0.02 第6個變量與因變量的互信息為0.09 第7個變量與因變量的互信息為0.37 第8個變量與因變量的互信息為0.461.1.1.6?Chi-squared Statistics (classification problem) 卡方統計量 (分類問題)
卡方統計量主要用于衡量兩個類別特征之間的相關性。sklearn提供了chi2方程用于計算卡方統計量。其輸入的特征變量必須為布爾值或頻率(故對于類別變量應考慮獨熱編碼)。卡方統計量的零假設為兩個變量是獨立的,因為卡方統計量值越高,則兩個類別變量的相關性越強。因此,我們應該選擇具有較高卡方統計量的特征。
公式:
其中, ????????,???? 為在變量X上具有i-th類別值且在變量Y上具有j-th類別值的實際觀測點計數。????????,???? 為利用概率估計的應在在變量X上具有i-th類別值且在變量Y上具有j-th類別值的觀測點數量。n為總觀測數, ???????? 為在變量X上具有i-th類別值的概率, ???????? 為在變量Y上具有j-th類別值的概率。
值得注意的是,通過解析源代碼,我們發現在sklearn中利用chi2計算出來的卡方統計量并不是統計意義上的卡方統計量。當輸入變量為布爾變量時,chi2計算值為該布爾變量為True時候的卡方統計量(我們將會在下文舉例說明)。這樣的優勢是,獨熱編碼生成的所有布爾值變量的chi2值之和將等于原始變量統計意義上的卡方統計量。?
舉個簡單的例子,假設一個變量I有0,1,2兩種可能的值,則獨特編碼后一共會產生3個新的布爾值變量。這三個布爾值變量的chi2計算出來的值之和,將等于變量I與因變量直接計算得出的統計意義上的卡方統計量。
解析sklearn中chi2的計算
# 首先,隨機生成一個數據集 import pandas as pd sample_dict = {'Type': ['J','J','J','B','B','B','C','C','C','C','C'], 'Output': [0, 1, 0, 2, 0, 1, 0, 0, 1, 2, 2,]} sample_raw = pd.DataFrame(sample_dict) sample_raw #原始數據,Output是我們的目標變量,Type為類別變量 # 下面利用獨熱編碼生成布爾變量,并利用sklearn計算每一個布爾變量的chi2值 sample = pd.get_dummies(sample_raw) from sklearn.feature_selection import chi2 chi2(sample.values[:,[1,2,3]],sample.values[:,[0]]) # 第一行為每一個布爾變量的chi2值 (array([0.17777778, 0.42666667, 1.15555556]),array([0.91494723, 0.8078868 , 0.56114397]))# 下面直接計算原始變量Type與output統計學意義上的卡方統計量 # 首先,先統計每一個類別下出現的觀測數,用于創建列聯表 obs_df = sample_raw.groupby(['Type','Output']).size().reset_index() obs_df.columns = ['Type','Output','Count'] obs_df即列聯表(contingency table)為:
from scipy.stats import chi2_contingency obs = np.array([[1, 1, 1], [2, 1, 2],[2, 1, 0]]) chi2_contingency(obs) # 第一個值即為變量Type與output統計學意義上的卡方統計量 (1.7600000000000002,0.779791873961373,4,array([[1.36363636, 0.81818182, 0.81818182],[2.27272727, 1.36363636, 1.36363636],[1.36363636, 0.81818182, 0.81818182]]))# 而chi2方程算出來的布爾值之和為即為原始變量的統計意義上的卡方統計量 chi2(sample.values[:,[1,2,3]],sample.values[:,[0]])[0].sum() == chi2_contingency(obs)[0] True# 那么sklearn中的chi2是如何計算的呢? # 不妨以第一個生成的布爾值為例,即Type為B # chi2出來的值為0.17777778 # 而這與利用scipy以下代碼計算出的計算一致 from scipy.stats import chisquare f_exp = np.array([5/11, 3/11, 3/11]) * 3 # 預期頻數為 output的先驗概率 * Type為B 的樣本數 chisquare([1,1,1], f_exp=f_exp) # [1,1,1] 即Type為B 的樣本實際頻數 # 即sklearn 中的chi2 僅考慮了Type為B情形下的列連表 Power_divergenceResult(statistic=0.17777777777777778, pvalue=0.9149472287300311)如何利用sklearn 來進行特征選擇
import numpy as np from sklearn.feature_selection import chi2 from sklearn.feature_selection import SelectKBest# 直接載入數據集 from sklearn.datasets import load_iris # 利用iris數據作為演示數據集 iris = load_iris() X, y = iris.data, iris.target # 此數據集中,X為連續變量,y為類別變量 # 不滿足chi2的使用條件# 將連續變量變為布爾值變量以滿足chi2使用條件 # 不妨利用其是否大于均值來生成布爾值(僅作為演示用) X = X > X.mean(0)# iris 數據集使用前需要被打亂順序 np.random.seed(1234) idx = np.random.permutation(len(X)) X = X[idx] y = y[idx]# 選擇前100個觀測點作為訓練集 # 剩下的作為測試集 train_set = X[0:100,:] test_set = X[100:,] train_y = y[0:100]# sklearn 中直接提供了方程用于計算卡方統計量 # SelectKBest 將會基于一個判別方程自動選擇得分高的變量 # 這里的判別方程為F統計量 selector = SelectKBest(chi2, k=2) # k => 我們想要選擇的變量數 selector.fit(train_set, train_y) # 在訓練集上訓練 transformed_train = selector.transform(train_set) # 轉換訓練集 transformed_train.shape #(100, 2), 其選擇了第三個及第四個變量 assert np.array_equal(transformed_train, train_set[:,[2,3]])transformed_test = selector.transform(test_set) # 轉換測試集 assert np.array_equal(transformed_test, test_set[:,[2,3]]); # 可見對于測試集,其依然選擇了第三個及第四個變量 # 驗證上述結果 for idx in range(train_set.shape[1]):score, p_value = chi2(train_set[:,idx].reshape(-1,1), train_y)print(f"第{idx + 1}個變量與因變量的卡方統計量為{round(score[0],2)},p值為{round(p_value[0],3)}") # 故應選擇第三個及第四個變量 第1個變量與因變量的卡方統計量為29.69,p值為0.0 第2個變量與因變量的卡方統計量為19.42,p值為0.0 第3個變量與因變量的卡方統計量為31.97,p值為0.0 第4個變量與因變量的卡方統計量為31.71,p值為0.01.1.1.7?F-Score (classification problem) F-統計量 (分類問題)
在分類機器學習問題中,若變量特征為類別特征,則我們可以使用獨熱編碼配合上述chi2方法選擇最重要的特征。但若特征為連續變量,則我們可以使用ANOVA-F值。ANOVA F統計量的零假設是若按目標變量(類別)分組,則連續變量的總體均值是相同的。故我們應選擇具有高ANOVA-F統計量的連續變量,因為這些連續變量與目標變量的關聯性強。?
公式:
其中,SS(between)為組間的平方和,即組均值和總體均值之間的平方和。SS(error)是組內的平方和,即數據與組均值之間的平方和。m是目標變量的總類別數,n是觀測數。
import numpy as np from sklearn.feature_selection import f_classif from sklearn.feature_selection import SelectKBest# 直接載入數據集 from sklearn.datasets import load_iris # 利用iris數據作為演示數據集 iris = load_iris() X, y = iris.data, iris.target # 此數據集中,X為連續變量,y為類別變量 # 滿足ANOVA-F的使用條件# iris 數據集使用前需要被打亂順序 np.random.seed(1234) idx = np.random.permutation(len(X)) X = X[idx] y = y[idx]# 選擇前100個觀測點作為訓練集 # 剩下的作為測試集 train_set = X[0:100,:] test_set = X[100:,] train_y = y[0:100]# sklearn 中直接提供了方程用于計算ANOVA-F # SelectKBest 將會基于一個判別方程自動選擇得分高的變量 # 這里的判別方程為F統計量 selector = SelectKBest(f_classif, k=2) # k => 我們想要選擇的變量數 selector.fit(train_set, train_y) # 在訓練集上訓練 transformed_train = selector.transform(train_set) # 轉換訓練集 transformed_train.shape #(100, 2), 其選擇了第三個及第四個變量 assert np.array_equal(transformed_train, train_set[:,[2,3]])transformed_test = selector.transform(test_set) # 轉換測試集 assert np.array_equal(transformed_test, test_set[:,[2,3]]); # 可見對于測試集,其依然選擇了第三個及第四個變量 # 驗證上述結果 for idx in range(train_set.shape[1]):score, p_value = f_classif(train_set[:,idx].reshape(-1,1), train_y)print(f"第{idx + 1}個變量與因變量的ANOVA-F統計量為{round(score[0],2)},p值為{round(p_value[0],3)}") # 故應選擇第三個及第四個變量 第1個變量與因變量的ANOVA-F統計量為91.39,p值為0.0 第2個變量與因變量的ANOVA-F統計量為33.18,p值為0.0 第3個變量與因變量的ANOVA-F統計量為733.94,p值為0.0 第4個變量與因變量的ANOVA-F統計量為608.95,p值為0.01.1.1.7?Mutual Information (classification problem) 互信息 (分類問題)
【與1.1.1.5一樣】互信息(Mutual Information)衡量變量間的相互依賴性。其本質為熵差,即 ????(????)?????(????|????),即知道另一個變量信息后混亂的降低程度 。當且僅當兩個隨機變量獨立時MI等于零。MI值越高,兩變量之間的相關性則越強。與Pearson相關和F統計量相比,它還捕獲了非線性關系。?
公式:?
若兩個變量均為離散變量:
p(????,????)(????,????) 為x和y的聯合概率質量函數 (PMF), p????(????)則為x的的聯合概率質量函數 (PMF)。?
若兩個變量均為連續變量:
p(????,????)(????,????) 為x和y的聯合概率密度函數 (PDF),p????(????)則為x的的聯合概率密度函數 (PDF)。連續變量情形下,在實際操作中,往往先對數據離散化分桶,然后逐個桶進行計算。?
但是實際上,一種極有可能的情況是,x和y中的一個可能是離散變量,而另一個是連續變量。因此在sklearn中,它基于[1]和[2]中提出的基于k最臨近算法的熵估計非參數方法。?
[1] A. Kraskov, H. Stogbauer and P. Grassberger, “Estimating mutual information”. Phys. Rev. E 69, 2004.?
[2] B. C. Ross “Mutual Information between Discrete and Continuous Data Sets”. PLoS ONE 9(2), 2014.
import numpy as np from sklearn.feature_selection import mutual_info_classif from sklearn.feature_selection import SelectKBest# 直接載入數據集 from sklearn.datasets import load_iris # 利用iris數據作為演示數據集 iris = load_iris() X, y = iris.data, iris.target # 此數據集中,X為連續變量,y為類別變量 # 滿足MI的使用條件# iris 數據集使用前需要被打亂順序 np.random.seed(1234) idx = np.random.permutation(len(X)) X = X[idx] y = y[idx]# 選擇前100個觀測點作為訓練集 # 剩下的作為測試集 train_set = X[0:100,:] test_set = X[100:,] train_y = y[0:100]# KNN中的臨近數是一個非常重要的參數 # 故我們重寫了一個新的MI計算方程更好的來控制這一參數 def udf_MI(X, y):result = mutual_info_classif(X, y, n_neighbors = 5) # 用戶可以輸入想要的臨近數return result# SelectKBest 將會基于一個判別方程自動選擇得分高的變量 # 這里的判別方程為F統計量 selector = SelectKBest(udf_MI, k=2) # k => 我們想要選擇的變量數 selector.fit(train_set, train_y) # 在訓練集上訓練 transformed_train = selector.transform(train_set) # 轉換訓練集 transformed_train.shape #(100, 2), 其選擇了第三個及第四個變量 assert np.array_equal(transformed_train, train_set[:,[2,3]])transformed_test = selector.transform(test_set) # 轉換測試集 assert np.array_equal(transformed_test, test_set[:,[2,3]]); # 可見對于測試集,其依然選擇了第三個及第四個變量 # 驗算上述結果 for idx in range(train_set.shape[1]):score = mutual_info_classif(train_set[:,idx].reshape(-1,1), train_y, n_neighbors = 5)print(f"第{idx + 1}個變量與因變量的互信息為{round(score[0],2)}") # 故應選擇第三個及第四個變量 第1個變量與因變量的互信息為0.56 第2個變量與因變量的互信息為0.28 第3個變量與因變量的互信息為0.99 第4個變量與因變量的互信息為1.02專欄系列:
專欄 | 基于 Jupyter 的特征工程手冊:數據預處理(一)
專欄 | 基于 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 干貨,我在看?
總結
以上是生活随笔為你收集整理的专栏 | 基于 Jupyter 的特征工程手册:特征选择(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 专栏 | 基于 Jupyter 的特征工
- 下一篇: 135 页的《机器学习速查手册》,公式、