遞歸式特征消除:Recursive feature elimination(RFE)
簡述
特征的選取方式一共有三種,在 sklearn 實現了的包裹式 (wrapper) 特診選取只有兩個遞歸式特征消除的方法,如下:
recursive feature elimination ( RFE )
通過學習器返回的 coef_ 屬性 或者 feature_importances_ 屬性來獲得每個特征的重要程度。 然后,從當前的特征集合中移除最不重要的特征。在特征集合上不斷的重復遞歸這個步驟,直到最終達到所需要的特征數量為止。RFECV
通過交叉驗證來找到最優的特征數量。如果減少特征會造成性能損失,那么將不會去除任何特征。這個方法用以選取單模型特征相當不錯,但是有兩個缺陷,一,計算量大。二,隨着學習器(評估器)的改變,最佳特征組合也會改變,有些時候會造成不利影響。
RFE
性能升降問題
PFE 自身的特性,使得我們可以比較好的進行手動的特征選擇,但是同樣的他也存在原模型在去除特征后的數據集上的性能表現要差於原數據集,這和方差過濾一樣,同樣是因為去除的特征中保留有有效信息的原因。下面的代碼就很好的展示了這種現象。
from sklearn.feature_selection import RFE, RFECV
from sklearn.svm import LinearSVC
from sklearn.datasets import load_iris
from sklearn import model_selection
iris = load_iris()
X, y = iris.data, iris.target
## 特征提取
estimator = LinearSVC()
selector = RFE(estimator=estimator, n_features_to_select=2)
X_t = selector.fit_transform(X, y)
### 切分測試集與驗證集
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y,
test_size=0.25, random_state=0, stratify=y)
X_train_t, X_test_t, y_train_t, y_test_t = model_selection.train_test_split(X_t, y,
test_size=0.25, random_state=0,
stratify=y)
## 測試與驗證
clf = LinearSVC()
clf_t = LinearSVC()
clf.fit(X_train, y_train)
clf_t.fit(X_train_t, y_train_t)
print("Original DataSet: test score=%s" % (clf.score(X_test, y_test)))
print("Selected DataSet: test score=%s" % (clf_t.score(X_test_t, y_test_t)))
Original DataSet: test score=0.973684210526
Selected DataSet: test score=0.947368421053
從上面的代碼我們可以看出,原模型的性能在使用 RFE 后確實下降了,如同方差過濾,單變量特征選取一樣,這種方式看來使用這個方法我們也需要謹慎一些啊。
一些重要的屬性與參數
- n_features_to_select :選出的特征。整數時為選出特征的個數,None 時選取一半
- step : 整數時,每次去除的特征個數,小於 1 時,每次去除權重最小的特征
print("N_features %s" % selector.n_features_) # 保留的特征數
print("Support is %s" % selector.support_) # 是否保留
print("Ranking %s" % selector.ranking_) # 重要程度排名
N_features 2
Support is [False True False True]
Ranking [3 1 2 1]
RFECV
原理與特性
使用交叉驗證來保留最佳性能的特征。在 REF 的基礎上對不同的特征組合進行交叉驗證,學習器本身不變,通過計算其決策系數之和,最終得到不同特征對於 score 的重要程度,然后保留最佳的特征組合。其分割方式類似於隨機森林中的列上子采樣。
一些重要的屬性與參數
- step : 整數時,每次去除的特征個數,小於 1 時,每次去除權重最小的特征
- scoring : 字符串類型,選擇 sklearn 中的
scorer
作為輸入對象 - cv :
- 默認為 3 折
- 整數為 cv 數
- object:用作交叉驗證生成器的對象
- An iterable yielding train/test splits.
對於 迭代器或者沒有輸入(None), 如果 y 是 二進制 或者 多類, 則使用 sklearn.model_selection.StratifiedKFold
. 如果學習器是個分類器 或者 如果 y 不是 二進制 或者 多類,使用 sklearn.model_selection.KFold
.
如果你對於前面的花不太理解,那么你可以看一下下面的例子,或者自己動手嘗試一下
例子一
對於前面 RFE 中的數據集進行驗證,應當應該保留那些特征:
iris = load_iris()
X = iris.data
y = iris.target
estimator = LinearSVC()
selector = RFECV(estimator=estimator, cv=3)
selector.fit(X, y)
print("N_features %s" % selector.n_features_)
print("Support is %s" % selector.support_)
print("Ranking %s" % selector.ranking_)
print("Grid Scores %s" % selector.grid_scores_)
N_features 4
Support is [ True True True True]
Ranking [1 1 1 1]
Grid Scores [ 0.91421569 0.94689542 0.95383987 0.96691176]
好吧,看來都應該保留
例子二
RFECV 的強大作用:
import matplotlib.pyplot as plt
from sklearn.svm import SVC
from sklearn.model_selection import StratifiedKFold
from sklearn.feature_selection import RFECV
from sklearn.datasets import make_classification
# Build a classification task using 3 informative features
X, y = make_classification(n_samples=1000, n_features=25, n_informative=3,
n_redundant=2, n_repeated=0, n_classes=8,
n_clusters_per_class=1, random_state=0)
# Create the RFE object and compute a cross-validated score.
svc = SVC(kernel="linear")
# The "accuracy" scoring is proportional to the number of correct
# classifications
rfecv = RFECV(estimator=svc, step=1, cv=StratifiedKFold(2),
scoring='accuracy')
rfecv.fit(X, y)
print("Optimal number of features : %d" % rfecv.n_features_)
print("Ranking of features : %s" % rfecv.ranking_)
# Plot number of features VS. cross-validation scores
plt.figure()
plt.xlabel("Number of features selected")
plt.ylabel("Cross validation score (nb of correct classifications)")
plt.plot(range(1, len(rfecv.grid_scores_) + 1), rfecv.grid_scores_)
plt.show()
Optimal number of features : 3
Ranking of features : [ 5 1 12 19 15 6 17 1 2 21 23 11 16 10 13 22 8 14 1 20 7 9 3 4 18]
(划重點了,咳咳)
通過 RFECV 我們得知,原來只需要三個特征就好了,首先這確實符合我們構造的數據,同時這也向我們展示了 RFECV 的強大潛力,看來它將成為我們之后進行特征選取的一個重要助手 (o)/~
三個特殊的多類比較特征選擇
假陽性率(false positive rate) SelectFpr
偽發現率(false discovery rate) SelectFdr
或者族系誤差(family wise error) SelectFwe
其實際意義請參考 wiki:Multiple_comparisons_problem
下面是代碼展示
from sklearn.feature_selection import SelectFdr,f_classif,SelectFpr,SelectFwe,chi2,mutual_info_classif
iris = load_iris()
X = iris.data
y = iris.target
selector1 = SelectFpr(score_func = mutual_info_classif,alpha=0.5)
# alpha是預期錯誤發現率的上限,默認是0.5,score_func 默認為 f_classif
selector1.fit(X, y)
print("\nScores of features %s" % selector1.scores_)
print("p-values of feature scores is %s" % selector1.pvalues_)
# print("Shape after transform is ",selector1.transform(X).shape)
selector2 = SelectFdr(score_func = f_classif,alpha=4.37695696e-80) # alpha是預期錯誤發現率的上限
selector2.fit(X, y)
print("\nScores of features %s" % selector2.scores_)
print("p-values of feature scores is %s" % selector2.pvalues_)
print("Shape after transform is ",selector2.transform(X).shape)
selector3 = SelectFwe(score_func = chi2,alpha=1) # alpha是預期錯誤發現率的上限
selector3.fit(X, y)
print("\nScores of features %s" % selector3.scores_)
print("p-values of feature scores is %s" % selector3.pvalues_)
print("Shape after transform is ",selector3.transform(X).shape)
輸出:
Scores of features [ 0.54158942 0.21711645 0.99669173 0.99043692]
p-values of feature scores is None
Scores of features [ 119.26450218 47.3644614 1179.0343277 959.32440573]
p-values of feature scores is [ 1.66966919e-31 1.32791652e-16 3.05197580e-91 4.37695696e-85]
Shape after transform is (150, 2)
Scores of features [ 10.81782088 3.59449902 116.16984746 67.24482759]
p-values of feature scores is [ 4.47651499e-03 1.65754167e-01 5.94344354e-26 2.50017968e-15]
Shape after transform is (150, 4)
通用 RFE:GenericUnivariateSelect
在學習了前面的 RFE 之后, sklearn 還封裝了一個通用的 RFE:GenericUnivariateSelect, 它可以通過超參數來設置我們需要的 RFE, 一共是三個超參數灰常簡單易用。
- score_func : 評價函數(和前面的意思一樣)
- mode : sklearn 封裝的模型
- param : 之前 sklearn 中封裝的模型都有一個相應的控制閾值的超參數 param,此處意義相同
下面是一個簡單的小例子
from sklearn.feature_selection import GenericUnivariateSelect
iris = load_iris()
X = iris.data
y = iris.target
estimator = LinearSVC()
selector = GenericUnivariateSelect(score_func=f_classif,mode='fpr',param= 0.5)
# mode : {'percentile', 'k_best', 'fpr', 'fdr', 'fwe'}
selector.fit(X, y)
print("\nScores of features %s" % selector.scores_)
print("p-values of feature scores is %s" % selector.pvalues_)
print("Shape after transform is ",selector.transform(X).shape)
print("Support is ",selector.get_support())
print("Params is ",selector.get_params())
Scores of features [ 119.26450218 47.3644614 1179.0343277 959.32440573]
p-values of feature scores is [ 1.66966919e-31 1.32791652e-16 3.05197580e-91 4.37695696e-85]
Shape after transform is (150, 4)
Support is [ True True True True]
Params is {'mode': 'fpr', 'param': 0.5, 'score_func': <function f_classif at 0x7f6ecee7d7b8>}