【机器学习】Selecting good features – Part IV: stability selection, RFE and everything side by side

Selecting good features – Part IV: stability selection, RFE and everything side by side


在我以前的文章中,我研究了单变量方法、线性模型和正则化以及随机森林的特征选择。

在本文中,我将研究另外两种方法:稳定性选择递归特征消除(RFE),这两种方法都可以考虑包装方法。它们都建立在其它(基于模型的)选择方法的基础上,如回归或SVM,在不同的数据子集上建立模型,并从集合中提取排名。

作为总结,我将运行前面讨论的所有方法,以突出它们彼此的优缺点和陷阱。

稳定性选择

稳定性选择是一种相对新颖的特征选择方法,它基于子采样并结合选择算法(可以是回归、支持向量机或其他类似的方法)。高层次的思想是在不同的数据子集和不同的特征子集上应用特征选择算法。在重复多次处理之后,选择结果可以被聚合,例如,通过检查一个特征在被检查的特征子集中被选择为重要特征的次数。我们可以期望强大的特性具有接近100%的分数,因为它们总是尽可能地被选择。较弱、但仍然相关的特征也将具有非零分数,因为当在当前选择的子集中不存在更强的特征时将选择它们,而无关的特征将具有分数(接近)零,因为它们永远不会在所选择的特征中。

Skleak实现了随机套索和随机物流回归类中的稳定性选择。

from sklearn.linear_model import RandomizedLasso
from sklearn.datasets import load_boston
boston = load_boston()
 
#using the Boston housing data. 
#Data gets scaled automatically by sklearn's implementation
X = boston["data"]
Y = boston["target"]
names = boston["feature_names"]
 
rlasso = RandomizedLasso(alpha=0.025)
rlasso.fit(X, Y)
 
print("Features sorted by their score:")
print(sorted(zip(map(lambda x: round(x, 4), rlasso.scores_), 
                 names), reverse=True))

Features sorted by their score:
[(1.0, 'RM'), (1.0, 'PTRATIO'), (1.0, 'LSTAT'), (0.66500000000000004, 'B'), (0.60499999999999998, 'CHAS'), (0.41499999999999998, 'CRIM'), (0.39000000000000001, 'TAX'), (0.23999999999999999, 'DIS'), (0.20999999999999999, 'NOX'), (0.095000000000000001, 'INDUS'), (0.040000000000000001, 'ZN'), (0.029999999999999999, 'RAD'), (0.014999999999999999, 'AGE')]

正如从示例中看到的,前三个特性的得分相等,为1.0,这意味着它们总是被选择为有用的特性(当然,当改变正则化参数时,这可能会改变,但是sklearning的随机lasso实现可以自动选择一个好的α参数)。分数从那里平稳地下降,但一般来说,下降并不像通常情况下的纯套索或随机森林。这意味着稳定性选择对于减少过拟合的纯特征选择是有用的,但是对于数据解释也是有用的:一般来说,好的特征不会因为数据集中有相似的、相关的特征而获得0作为系数(套索的情况就是这样)。对于特性选择,我发现对于许多不同的数据集和设置来说,它是性能最好的方法之一。

递归特征消除

递归特征消除是基于重复构建模型(例如SVM或回归模型)并选择性能最佳或最差的特征(例如基于系数),将特征置之不理,然后用其余特征重复该过程的思想。应用此过程直到数据集中的所有特性都用尽为止。然后根据特征被消除的时间对它们进行排序。因此,寻找性能最好的特征子集是一个贪婪的优化

RFE的稳定性在很大程度上取决于在每次迭代中用于特征排序的模型类型。正如非正则回归不稳定一样,RFE在利用它时也是不稳定的,而岭回归可以提供更稳定的结果。

Sklearning提供用于递归特征消除的RFE,以及用于通过交叉验证循环查找秩和最优特征数量的RFECV。

from sklearn.feature_selection import RFE
from sklearn.linear_model import LinearRegression
 
boston = load_boston()
X = boston["data"]
Y = boston["target"]
names = boston["feature_names"]
 
#use linear regression as the model
lr = LinearRegression()
#rank all features, i.e continue the elimination until the last one
rfe = RFE(lr, n_features_to_select=1)
rfe.fit(X,Y)
 
print("Features sorted by their rank:")
print(sorted(zip(map(lambda x: round(x, 4), rfe.ranking_), names)))

Features sorted by their rank:
[(1, 'NOX'), (2, 'RM'), (3, 'CHAS'), (4, 'PTRATIO'), (5, 'DIS'), (6, 'LSTAT'), (7, 'RAD'), (8, 'CRIM'), (9, 'INDUS'), (10, 'ZN'), (11, 'TAX'), (12, 'B'), (13, 'AGE')]

示例:并排运行方法

现在,我将从本文和前面的三个示例中获取所有示例,并在示例数据集上运行这些方法以并排进行比较。数据集将是所谓的Friedman #1回归数据集(来自Friedman’s Multivariate Adaptive Regression Splines paper)。数据是根据公式y=10sin(\pi x_1x_2)+20(x_3-0.5)^2+10X_4+5X_5+\varepsilon生成的,其中x_1x_5是均匀分布的,\varepsilon是标准正态偏差N(0,1)。此外,原始数据集具有五个独立于响应变量的噪声变量x_6,...,x_{10}。我们将进一步增加变量的数目,并添加四个变量x_{11},...,x_{14},每个变量分别与f(x)=x+N(0,0.01)生成的x_1,...,x_4有很强的相关性。这在变量之间产生大于0.999的相关系数。这将说明不同的特征排序方法如何处理数据中的相关性。

我们将在数据集上应用运行上面列出的每个方法,并对得分进行规范化,以使得分介于0(对于排名最低的特性)和1(对于排名最高的特性)之间。对于递归特征消除,前五个特征将全部得到分数1,其余秩根据它们的秩相等地间隔在0到1之间。

from sklearn.datasets import load_boston
from sklearn.linear_model import (LinearRegression, Ridge, 
                                  Lasso, RandomizedLasso)
from sklearn.feature_selection import RFE, f_regression
from sklearn.preprocessing import MinMaxScaler
from sklearn.ensemble import RandomForestRegressor
import numpy as np
from minepy import MINE
 
np.random.seed(0)
 
size = 750
X = np.random.uniform(0, 1, (size, 14))
 
#"Friedamn #1” regression problem
Y = (10 * np.sin(np.pi*X[:,0]*X[:,1]) + 20*(X[:,2] - .5)**2 +
     10*X[:,3] + 5*X[:,4] + np.random.normal(0,1))
#Add 3 additional correlated variables (correlated with X1-X3)
X[:,10:] = X[:,:4] + np.random.normal(0, .025, (size,4))
 
names = ["x%s" % i for i in range(1,15)]
 
ranks = {}
 
def rank_to_dict(ranks, names, order=1):
    minmax = MinMaxScaler()
    ranks = minmax.fit_transform(order*np.array([ranks]).T).T[0]
    ranks = map(lambda x: round(x, 2), ranks)
    return dict(zip(names, ranks ))
 
lr = LinearRegression(normalize=True)
lr.fit(X, Y)
ranks["Linear reg"] = rank_to_dict(np.abs(lr.coef_), names)
 
ridge = Ridge(alpha=7)
ridge.fit(X, Y)
ranks["Ridge"] = rank_to_dict(np.abs(ridge.coef_), names)
 
 
lasso = Lasso(alpha=.05)
lasso.fit(X, Y)
ranks["Lasso"] = rank_to_dict(np.abs(lasso.coef_), names)
 
 
rlasso = RandomizedLasso(alpha=0.04)
rlasso.fit(X, Y)
ranks["Stability"] = rank_to_dict(np.abs(rlasso.scores_), names)
 
#stop the search when 5 features are left (they will get equal scores)
rfe = RFE(lr, n_features_to_select=5)
rfe.fit(X,Y)
ranks["RFE"] = rank_to_dict(map(float, rfe.ranking_), names, order=-1)
 
rf = RandomForestRegressor()
rf.fit(X,Y)
ranks["RF"] = rank_to_dict(rf.feature_importances_, names)
 
 
f, pval  = f_regression(X, Y, center=True)
ranks["Corr."] = rank_to_dict(f, names)
 
mine = MINE()
mic_scores = []
for i in range(X.shape[1]):
    mine.compute_score(X[:,i], Y)
    m = mine.mic()
    mic_scores.append(m)
 
ranks["MIC"] = rank_to_dict(mic_scores, names) 
 
 
r = {}
for name in names:
    r[name] = round(np.mean([ranks[method][name] 
                             for method in ranks.keys()]), 2)
 
methods = sorted(ranks.keys())
ranks["Mean"] = r
methods.append("Mean")
 
print("\t%s" % "\t".join(methods))
for name in names:
    print("%s\t%s" % (name, "\t".join(map(str, 
                         [ranks[method][name] for method in methods]))))

下面是结果表(通过单击列标题进行排序)(截图示意),其中每个方法的结果+平均值

这个例子应该强调不同方法的一些有趣的特性。

利用线性相关(..Corr.),每个特征被独立评估,因此特征x1...x4的得分非常类似于x11...x14,而噪声特征x5...x10被正确地识别为与响应变量几乎没有关系。它不能识别x3与响应变量之间的任何关系,因为这种关系是二次的(实际上,除了MIC,这几乎适用于所有其他方法)。同样清楚的是,虽然该方法能够测量每个特征和响应变量之间的线性关系,但是选择性能最好的特征来改进模型的泛化并不是最佳的,因为所有性能最好的特征基本上都会被选择两次

Lasso挑选出性能最好的特性,同时强制其他特性接近于零。当需要减少特征的数量时,这显然是有用的,但不一定是数据解释所必需的(因为这可能导致人们相信特征x11...x13与输出变量没有强的关系)。

MIC与相关系数在处理所有特征时“相等”相似,而且能够发现x3与响应之间的非线性关系。

基于杂质的随机森林的排名通常具有攻击性,因为在前几名之后得分急剧下降。这可以从第三等级的特征已经比顶级特征小4倍的示例中看出(而对于其他排序方法,下拉显然没有那么积极)。

岭回归迫使回归系数在相关变量之间类似地展开。这在x11...x14在得分方面接近x1...x4的示例中清晰可见。

稳定性选择通常能够在数据解释和顶部特征选择之间作出有用的折衷,用于模型改进。这个例子很好地说明了这一点。就像拉索一样,它能够识别出最上面的特征(x1,x2,x4,x5)。同时,相关阴影变量也得到较高的分数,说明它们与反应的关系。

结论

特征排序在许多机器学习和数据挖掘场景中可能非常有用。但关键是要清楚地记住最终目标,并理解哪种方法最适合实现它。在选择用于模型性能改进的顶部特征时,很容易通过简单地进行交叉验证来验证特定方法是否对替代方案工作良好。当使用特征排序进行数据解释时,这并不是简单的,因为排序方法的稳定性是至关重要的,并且不具有这种性质的方法(如套索)很容易导致错误的结论。有什么可以帮助对数据进行子采样,并在子集上运行选择算法。如果结果在子集之间是一致的,则相对安全地信任方法在这个特定数据上的稳定性,并且因此直接根据排序来解释数据。

原文链接:http://blog.datadive.net/selecting-good-features-part-iv-stability-selection-rfe-and-everything-side-by-side/

猜你喜欢

转载自blog.csdn.net/ARPOSPF/article/details/85036849