特徵選擇是特徵工程中的重要一環,其主要目的是從全部特徵中選出相關特徵 (relevant feature),或者說在不引發重要信息丟失的前提下去除掉無關特徵 (irrelevant feature) 和冗餘特徵 (redundant feature)。進行特徵選擇的好處主要有如下幾種:html
不一樣的模型對於無關特徵的容忍度不一樣,下圖來自《 Applied Predictive Modeling 》 (P489),顯示了逐漸增長無關特徵後不一樣模型的RMSE的變化。樹模型廣泛表現較好,而神經網絡因其模型的複雜性則很容易過擬合。Lasso 因其能夠產生稀疏特徵於是也有較好的表現。python
特徵選擇的方法主要分爲三大類:過濾式方法 (Filter Methods),包裹式方法 (Wrapper Methods) 和嵌入式方法 (Embedded Methods)。git
下面這張圖總結地更加全面,來自 《A review of feature selection techniques in bioinformatics 》github
本文接下來主要考察過濾式方法中經常使用的幾個方法:卡方檢驗、F 檢驗和互信息,並探討它們用於特徵選擇的內在機理。api
既然特徵選擇的目的是去除無關特徵,那麼什麼是無關特徵? 對於分類問題,在過濾式方法中通常假設與標籤獨立的特徵爲無關特徵,而卡方檢驗剛好能夠進行獨立性檢驗,因此其適用於特徵選擇。若是檢驗結果是某個特徵與標籤獨立,則能夠去除該特徵。說到卡方檢驗天然會用到卡方分佈,其定義以下:網絡
設隨機變量 \(x_1, x_2 ... x_n \,,\quad \text{i.i.d} \sim N(0,1)\) ,即獨立同分佈於標準正態分佈,那麼這 \(n\) 個隨機變量的平方和:
\[ X = \sum\limits_{i=1}^n x_i^2 \]
構成一個新的隨機變量,其服從自由度爲 \(n\) 的卡方分佈 ( \(\chi^2\) 分佈) ,記爲 \(X \sim \chi^2_n\) 。app
下圖顯示不一樣自由度下卡方分佈的機率密度曲線,能夠看到自由度越大,卡方分佈就越接近正態分佈:機器學習
下面舉個例子看卡方檢驗的通常流程:學習
假設我想檢驗一個男人有特殊着裝癖好與其變態與否的關係,若是檢驗的結果是兩者不獨立,那下次在街上看見女裝大佬我可能就要繞着走了。。。 因此該獨立性檢驗的假設以下:測試
零假設 ($H_0$):着裝偏好與變態傾向獨立 備選假設 ($H_1$) :着裝偏好與變態傾向不獨立
卡方檢驗通常須要先創建列聯表,表中每一個格子是觀察頻數,表示實際觀測到的同時知足兩個條件的數量:
同時須要計算每一個格子的指望頻數,由於零假設是兩個變量獨立,所以依獨立性的定義:\(P(A,B) = P(A)\, P(B)\),因而上表中每一個格子的指望頻數爲 \(N \times P(A,B) = N \times P(A) \times P(B)\) ,其中 \(N\) 爲總數量,那麼第一個格子的指望頻數爲 \(3100 \times \frac{750}{3100} \times \frac{500}{3100} = 121\) 。所以整體指望頻數表爲:
有了這兩個列聯表後,就能夠計算檢驗統計量 \(\chi^2\) ( \(\chi^2\) 表示卡方值) ,\(\chi^2\) 越大,表示觀測值和理論值相差越大,當 \(\chi^2\) 大於某一個臨界值時,就能得到統計顯著性的結論:
\[ \chi^2 = \sum\frac{(觀測頻數 - 指望頻數)^2}{指望頻數}= \sum_{i=1}^{r} \sum_{j=1}^{c} {(O_{i,j} - E_{i,j})^2 \over E_{i,j}} \tag{1} \]
其中 \(O_{ij}\) 爲觀測頻數表中單元格的數值,\(E_{ij}\) 爲指望頻數表中單元格的數值,\(r\) 爲行數,\(c\) 爲列數,自由度 \(df\) 爲 \((2-1)\times(3-1) = 2\) ,\(\chi^2\) 服從卡方分佈,則查卡方分佈表:
得 \(P(\chi^2 > 13.82) < 0.001\) ,而實際計算出的 \(\chi^2\) 爲 26.99,顯著性很高,意味着零假設成立的狀況下樣本結果出現的機率小於 \(0.1\%\),於是能夠拒絕零假設,接受備選假設。這意味着男性的特殊着裝偏好與變態傾向具備相關性。固然這裏得說明兩點:
再回到特徵選擇的問題,從嚴格的統計學角度來看,使用卡方檢驗進行特徵選擇可能會產生一些問題。假設選擇的顯著性水平 \(\alpha\) 爲 0.05,這說明犯第一類錯誤 (\(\text{type} \, \text{I} \, \text{error}\),兩個變量實際獨立卻被判爲相關) 的機率爲 5%,若進行了 1000 次卡方檢驗,則平均有 \(1000 \times 0.05 = 50\) 次會選擇與標籤不相關的特徵。機器學習問題中動輒就有幾千至上百萬的特徵,那麼這裏面漏過的特徵可能會至關多。不過好在搞機器學習並非在搞統計,咱們實際上比較關心的是特徵的相對重要性。依上面的卡方分佈表,檢驗統計量 \(\chi^2\)越大,越有信心拒絕零假設,接受兩個變量不獨立 的事實,於是能夠按每一個特徵 \(\chi^2\) 值的大小進行排序,去除 \(\chi^2\) 值小的特徵。
以上就是卡方檢驗用於特徵選擇的通常流程,而我看到在大部分資料中舉的例子都是離散型特徵的,以下圖:
這其中有幾個值得注意的點:
(1) 上面舉的卡方檢驗例子是判別 着裝癖好
與 變態傾向
具備相關性,然而 着裝癖好
是離散型特徵,而大部分機器學習模型是沒法直接處理離散型特徵的,若是按一般的做法進行 one-hot 轉換 (以下圖),就不能肯定其中單個的特徵 (如 着裝癖好_女裝
) 是否仍與 變態傾向
有相關性。
(2) 上面這一點也能夠反過來看,假設卡方檢驗的結果是 着裝癖好
與 變態傾向
獨立,也並不表明單個的特徵 (如着裝癖好_不定裝
)與變態傾向
獨立。因此綜合這兩點,應該先將離散型特徵進行轉換,再對每一個特徵進行卡方檢驗,而不是像這些資料中那樣直接對一個離散型特徵做檢驗。
(3) 若是是對 one-hot 轉換後的每一個特徵構建列聯表進行卡方檢驗,那將會是個巨大的工程,由於one-hot 轉換一般會使特徵維數成倍增長。所以咱們須要一個快速計算 \(\chi^2\) 的方法,而不是繁瑣地對每一個特徵計算列聯表頻數,所幸 scikit-learn
中就提供了這樣的快捷方法,同時也將看到這個方法也爲連續型變量的應用打開了一扇大門。下面看 feature_selection.chi2
的源碼 (有省略):
def chi2(X, y): Y = LabelBinarizer().fit_transform(y) # (1) if Y.shape[1] == 1: Y = np.append(1 - Y, Y, axis=1) observed = safe_sparse_dot(Y.T, X) # (2) feature_count = X.sum(axis=0).reshape(1, -1) # (3) class_prob = Y.mean(axis=0).reshape(1, -1) # (4) expected = np.dot(class_prob.T, feature_count) # (5) return _chisquare(observed, expected) def _chisquare(f_obs, f_exp): f_obs = np.asarray(f_obs, dtype=np.float64) k = len(f_obs) chisq = f_obs chisq -= f_exp chisq **= 2 with np.errstate(invalid="ignore"): chisq /= f_exp chisq = chisq.sum(axis=0) return chisq, special.chdtrc(k - 1, chisq)
這個實現並非傳統意義上的經過計算頻數構建列聯表,而是將屬於每個標籤類別的特徵取值總和做爲列聯表單元格的觀測值,即第 (2) 步 (須要先在第 (1) 步將標籤離散化)。而對於列聯表單元格的指望值的計算,則是基於這樣的假設:若是標籤與特徵獨立,則每一個標籤類別爲均勻分佈,即第 (4) 步中的 \(\rm{class\_prob} \Longrightarrow p\),則第 (5) 步中每一個單元格指望值的計算就與傳統意義上指望值相似了: \(\mathbb{E}[x] = \sum_i p_i x_i\) 。接下來的_chisuqare()
方法則是按照公式 \((1)\) 計算 \(\chi^2\) 值。
這樣實現的一大好處是能夠經過矩陣相乘快速得出全部特徵的觀測值和指望值,在計算出各特徵的 \(\chi^2\) 值後,如上文所述,能夠按每一個特徵的 \(\chi^2\) 值大小進行排序,方便地進行特徵選擇。另外一個好處是擴大了 chi2
的適用範圍,觀察上面的代碼,對於原始特徵的惟一處理就是第 (3) 步中的 sum
,而不是原來的計算頻數,這樣一些連續型特徵也可使用該方法進行特徵選擇了。
F 檢驗是一類創建在 F 分佈基礎上的假設檢驗方法,服從 F 分佈的隨機變量與上文中卡方分佈的關係以下:
\[ F = \frac{X_1 / d_1}{X_2 / d_2} \tag{2} \]
其中 \(X_1\) 和 \(X_2\) 分別服從自由度爲 \(d_1\) 和 \(d_2\) 的卡方分佈,即 \(X_1 \sim \chi^2(d_1), \;X_2 \sim \chi^2(d_2)\) ,且 \(X_1\) 與 \(X_2\) 獨立,則隨機變量 \(F\) 服從自由度爲 \((d_1, d_2)\) 的F分佈,記爲 \(F \sim \text{F}(d_1, d_2)\) 。
下圖顯示不一樣自由度下F分佈的機率密度曲線:
scikit-learn
中提供了兩種F檢驗方法 —— 適用於分類的 f_classif
和適用於迴歸的 f_regression
,分別對應單因素方差分析和線性相關分析,下面分別介紹。
在卡方檢驗中咱們要測試的是被檢驗的特徵與類別是否獨立,若拒絕零假設,則特徵與類別相關。而在方差分析中則採用了不一樣的思路: 按照不一樣的標籤類別將特徵劃分爲不一樣的整體,咱們想要檢驗的是不一樣整體之間均值是否相同 (或者是否有顯著性差別)。下面承接上文的例子,類別爲變態與否,由於方差分析只適用於連續型特徵,因此這裏採用了 「身高」 這個特徵:
上圖中紅框和籃框中的特徵值對應於兩個類別區分出的兩個不一樣的整體。方差分析用於特徵選擇的邏輯是這樣: 若是樣本中是變態的平均身高爲 1.7 米,非變態的平均身高也爲 1.7 米,憑身高沒法斷定一我的變態與否,那麼說明身高這個特徵對於類別沒有區分度,則能夠去除。反之,若前者的平均身高爲 1.6 米,後者的平均身高爲 1.9 米,那麼咱們有理由認爲身高很能區分變態與否。所以將問題形式化爲假設檢驗問題:
零假設 ($H_0$): $\mu_1 = \mu_2 = \cdots = \mu_k$ 備選假設 ($H_1$) : $k$ 個整體的均值不全相等
下面闡述方差分析的原理。設共有 \(k\) 個類別,總樣本數爲 \(n\) ,第 \(j\) 個類別的樣本數爲 \(n_j\) ,\(x_{ij}\) 表示第 \(j\) 個類別的第 \(i\) 個樣本,\(\bar{x_j}\) 表示第 \(j\) 個類別的樣本均值,即 \(\bar{x_j} = \frac{\sum_{i=1}^{n_j} x_{ij}}{n_j}\) ,\(\bar{x}\) 爲總樣本均值 \(\bar{x} = \frac{\sum_{j=1}^k \sum_{i=1}^{n_j}x_{ij}}{n}\) ,那麼樣本的整體變異爲:
\[ SST = \sum\limits_{j=1}^k \sum\limits_{i=1}^{n_j} (x_{ij} - \bar{x})^2 \]
\(SST\) 能夠分解爲兩部分 —— 類別內差別 \(SSE\) 和類別間差別 \(SSB\) :
\[ \begin{array} & SSE = \sum\limits_{j=1}^k \sum\limits_{i=1}^{n_j} (x_{ij} - \bar{x_j})^2 \\ SSB = SST - SSE = \sum\limits_{j=1}^k n_j (\bar{x_j} - \bar{x})^2 \end{array} \]
\(SSE\) 衡量每一個類別內部樣本之間的差別,能夠認爲是隨機偏差。\(SSB\) 則衡量不一樣類別之間的差別。方差分析的基本思想是將不一樣類別之間的變異與隨機偏差做比較,若是兩者之比大於某一臨界值,則可拒絕零假設接受備選假設,即不一樣類別間樣本均值不全相等,這也意味着樣本特徵對於類別有必定的區分度。
而對於如何肯定臨界值,則終於要用到傳說中的 F 分佈了。在 \((2)\) 式中已經定義了服從F分佈的隨機變量,注意到分子分母都要除以自由度,而 \(SSE\) 和 \(SSB\) 的自由度分別爲 \(k-1\) 和 \(n-k\) ,於是統計檢驗量 \(F\) :
\[ F = \frac{類別間方差}{類別內方差} = \frac{MSB}{MSE} = \frac{SSB \,/\, (k-1)}{SSE\, / \, (n-k)} \]
服從分子自由度爲 \(k-1\),分母自由度爲 \(n-k\) 爲的 F 分佈,即 \(\frac{MSB}{MSE} \sim F(k-1, \,n-k)\) 。看到這裏,敏感的同窗可能已經注意到了,方差分析的思想和線性判別分析 (Linear Discriminant Analysis,LDA) 很是相似 ( LDA 的思想可大體歸納爲 「投影后類內方差最小,類間方差最大」)。沒錯~,這兩個方法都是由英國大統計學家和生物學家 Ronald Fisher 爵士所創立。
因而按假設檢驗的套路,零假設成立的狀況下算出 F 值,查 F 分佈表,若p值小於0.05 (或0.01),則拒絕零假設接受備選假設,不一樣類別間均值不相等。在現實中使用軟件包能夠方便地輸出方差分析表,這裏使用 python 裏的統計包 statsmodels
:
import statsmodels import statsmodels.api as sm from statsmodels.formula.api import ols lm = ols('標籤 ~ 身高', data=data).fit() table = sm.stats.anova_lm(lm, typ=1) print(table) ####################################################### df sum_sq mean_sq F P(>F) 身高 1.0 0.188034 0.188034 0.622642 0.460102 Residual 6.0 1.811966 0.301994 NaN NaN
從上表能夠看出 \(p\) 值爲0.46,因此不能拒絕零假設,即身高這個特徵沒法區分變態與否。
方差分析可用於控制一個或多個自變量來檢驗其與因變量的關係,進而檢測某種實驗效果,於是與實驗設計有着千絲萬縷的關係,不過這裏面的水頗深。。。 甚至有不少專著,如 《 Design and Analysis of Experiments 》 等。 就通常的特徵選擇問題而言,和卡方檢驗同樣,咱們依然比較關心的是特徵的相對重要性,因此能夠按每一個特徵 F 值的大小進行排序,去除F值小的特徵。
上面的例子中檢驗身高與標籤之間的關係,由於只有身高一個因素,因此被稱爲單因素方差分析。固然其餘還有雙因素方差分析,能夠同時檢驗兩個特徵與標籤的關係,以及兩個特徵之間的相互關係,缺點是計算繁瑣,複雜度比單因素高。
單因素方差分析 (F檢驗) 與統計學中另外一大假設檢驗方法 —— \(t\) 檢驗也很有淵源,檢驗統計量 F 與 t 檢驗中的檢驗統計量 t 的關係爲: \(F = t^2\) ,因此對於只有兩個類別來講,F 檢驗和 t 檢驗會得出相同的結論,但對於多個類別的狀況,t檢驗只能兩兩進行比較,這會帶來一些問題:
因此對於多個類別的比較,方差分析是首選,其至關因而 t 檢驗對於多類別的擴展,我想 scikit-learn
的特徵選擇模塊中使用 F 檢驗而不是 t 檢驗是有這方面考慮的。
對於特徵和標籤皆爲連續值的迴歸問題,要檢測兩者的相關性,最直接的作法就是求相關係數 \(r_{xy}\):
\[ r_{xy} = \frac{cov(x,y)}{\sigma_x \sigma_y} =\frac{\sum_{i=1}^n (x_i - \bar{x})(y_i - \bar{y})}{\sqrt{\sum_{i=1}^n(x_i - \bar{x})^2} \sqrt{\sum_{i=1}^n (y_i - \bar{y})^2}} \]
但 scikit-learn
中的 f_regression
採用的是先計算相關係數,而後轉化爲F值。這又是個神奇的操做,到底是如何轉換的?在線性迴歸中常使用斷定係數 \(R^2\) 做爲迴歸方程擬合數據點的程度,或者說是因變量的整體方差能被自變量解釋的比例。\(R^2\) 的定義以及和相關係數 \(r_{xy}\) 的關係以下:
\[ R^2 = \frac{SSR}{SST} = 1- \frac{SSE}{SST} = r_{xy}^2 \]
其中 \(SSE\) 爲偏差平方和:\(SSE = \sum_{i=1}^n (y_i - \hat{y}_i)^2\) ,\(SSR\) 爲迴歸平方和:\(SSR = \sum_{i=1}^n (\hat{y}_i - \bar{y})^2\) ,\(SST\) 爲整體平方和:\(SST = \sum_{i=1}^n (y_i - \bar{y})^2\) 。能夠看到這些式子與方差分析中的式子很是相似,不過注意這裏計算的是都是標籤值 \(y\),而不是方差分析中的 \(x\) 。這其中的原理都是相通的,咱們一樣能夠用 \(SSR\) 和 \(SSE\) 來計算檢驗統計量 \(F\) (\(SSR\) 和 \(SSE\) 的自由度分別爲1和 n-2 ):
\[ F = \frac{MSR}{MSE} = \frac{SSR \,/\, 1}{SSE \,/\, (n-2)} = \frac{SSR / SST}{SSE / SST} \times (n-2) = \frac{r_{xy}^2}{1-r_{xy}^2} \times (n-2) \]
即 \(\frac{MSR}{MSE} \sim F(1, \,n-2)\) 。這樣就能夠方便地將相關係數轉化爲 F 值了,接下來的步驟與以前的假設檢驗同樣。該方法的缺點是隻能檢測線性相關關係,但不相關不表明獨立,多是非線性相關關係。
互信息 (mutual information) 用於特徵選擇,能夠從兩個角度進行解釋:(1)、基於 KL 散度和 (2)、基於信息增益。對於離散型隨機變量 \(X, \,Y\),互信息的計算公式以下:
\[ I(X;Y) = \sum\limits_{y \in \mathcal{Y}}\sum\limits_{x \in \mathcal{X}} p(x,y) \,\text{log}\left(\frac{p(x,y)}{p(x)p(y)}\right) \tag{3.1} \]
對於連續型變量:
\[ I(X;Y) = \int_{\mathcal{Y}}\int_{\mathcal{X}} p(x,y) \,\text{log}\left(\frac{p(x,y)}{p(x)p(y)}\right) dxdy \tag{3.2} \]
能夠看到連續型變量互信息的須要計算積分比較麻煩,一般先要進行離散化,因此這裏主要討論離散型變量的狀況。互信息能夠方便地轉換爲 KL 散度的形式:
\[ I(X;Y) = \sum\limits_{y \in \mathcal{Y}}\sum\limits_{x \in \mathcal{X}} p(x,y) \,\text{log}\left(\frac{p(x,y)}{p(x)p(y)}\right) = D_{KL}(p(x,y) || p(x)p(y)) \tag{3.3} \]
咱們知道 KL 散度能夠用來衡量兩個機率分佈之間的差別,而若是 \(x\) 和 \(y\) 是相互獨立的隨機變量,則 \(p(x,y) = p(x)\,p(y)\) ,那麼 \((3.3)\) 式爲 \(\huge{0}\)。所以若 \(I(X;Y)\) 越大,則表示兩個變量相關性越大,因而就能夠用互信息來篩選特徵。
而從信息增益的角度來看,互信息表示因爲 \(X\) 的引入而使 \(Y\) 的不肯定性減小的量。信息增益越大,意味着特徵 \(X\) 包含的有助於將 \(Y\) 分類的信息越多 (即 \(Y\) 的不肯定性越小)。決策樹就是一個典型的應用例子,其學習的主要過程就是利用信息增益來選擇最優劃分特徵,表示因爲特徵 \(A\) 而使得對數據集 \(D\) 的分類不肯定性減小的程度,信息增益大的特徵具備更強的分類能力。其計算公式爲:
\[ \begin{align} I(D\,;A) & = H(D) - H(D|A) = H(D) - \sum\limits_{v=1}^\mathcal{V}\frac{|D^v|}{|D|} H(D^v) \tag{3.4} \\ & = -\sum\limits_{k=1}^\mathcal{K}\frac{|C_k|}{|D|}\,\text{log}\frac{|C_k|}{|D|} -\left(\sum\limits_{v=1}^\mathcal{V} \frac{|D^v|}{|D|}\sum\limits_{k=1}^\mathcal{K}\frac{|D_{k}^v|}{|D^v|}\,\text{log}\frac{|D_{k}^v|}{|D^v|}\right) \tag{3.5} \end{align} \]
\((3.4)\) 式中 \(\mathcal{V}\) 表示特徵 \(A\) 有 \(\mathcal{V}\) 個可能的取值,\(|D^v|\) 表示第 \(v\) 個取值上的樣本數量。 \((3.5)\) 式中設總共有 \(\mathcal{K}\) 個類別,\(|C_k|\) 表示屬於第 \(k\) 類的樣本數量,\(\sum_{k=1}^\mathcal{K}|C_k| = |D|\)。 \(|D_k^v|\) 表示特徵 \(A\) 的取值爲 \(v\) 且類別爲 \(k\) 的樣本數量。
互信息和信息增益,兩者是等價的,下面咱們來看錶示互信息的 \((3.1)\) 式是如何推導出表示信息增益的 \((3.4)\) 和 \((3.5)\) 式的:
\[ \begin{align*} I(X;Y) = I(Y;X)&= \sum\limits_{y \in \mathcal{Y}}\sum\limits_{x \in \mathcal{X}} p(x,y) \,\text{log}\left(\frac{p(x,y)}{p(x)p(y)}\right) \\ & = -\sum\limits_y\sum\limits_x p(x,y)\,\text{log}\,p(y) + \sum\limits_x\sum\limits_y p(x,y)\text{log} \left(\frac{p(x,y)}{p(x)}\right) \\ & = -\sum\limits_y p(y)\,\text{log}\,p(y) + \sum\limits_x\sum\limits_y p(x)p(y|x)\text{log}\, p(y|x) \\ & = -\sum\limits_y p(y)\,\text{log}\,p(y) + \sum\limits_x p(x) \sum\limits_y p(y|x)\text{log}\, p(y|x) \tag{a} \\ & = H(Y) - \sum\limits_x p(x)H(Y|X=x) \tag{b}\\ & = H(Y) - H(Y|X) \end{align*} \]
上面的 \((a)\) 式就對應着 \((3.5)\) 式,而 \((b)\) 式對應 \((3.4)\) 式, \(p(y) \simeq \frac{|C_k|}{|D|}\;,\; p(x) \simeq \frac{|D^v|}{|D|}\;,\; p(y|x) \simeq \frac{|D_{k}^v|}{|D^v|}\) 。由此能夠看到決策樹的學習過程也是一種依賴於訓練數據的極大似然估計。
再來探究下 \((b)\) 式,\(H(Y)\) 爲熵,表示隨機變量 \(Y\) 的不肯定性。\(H(Y|X)=\sum\limits_{x}p(x) H(Y|X=x)\) 爲條件熵 (conditional entropy),表示在隨機變量 \(X\) 已知的狀況下隨機變量 \(Y\) 的不肯定性。那麼兩者的差 \(I(X;Y) = H(Y) - H(Y|X)\) 就表示因爲 \(X\) 的引入而使 \(Y\) 的不肯定性減小的量,維基裏有一張形象的圖:
放在特徵選擇的語境下,咱們但願 \(Y\) 的不肯定越小越好,這樣越有助於分類,那麼互信息越大,則特徵 \(X\) 使得 \(Y\) 的不肯定性減小地也越多,即 \(X\) 中包含的關於 \(Y\) 的信息越多。於是策略仍是和上文同樣,計算每一個特徵與類別的互信息值,排序後去除互信息小的特徵。
互信息的一大優勢是其能檢測出多種變量之間的關係,而相較而言 F 檢驗只能表示線性相關關係。Scikit-learn
的這個例子 (Comparison of F-test and mutual information) 中顯示了這一點,互信息能很好展示 \(x\) 和 \(y\) 之間的非線性關係:
/