在有了这么多种创建新特征的方法,你可能会想要增大数据的维度。使其远大于原始特征的数量。但是,添加更多特征会使所有模型变得更加复杂,从而增大过拟合的可能性。在添加新特征或处理一般高维数据集时,最好将特征的数量减少到只包含最有用的那些特征,并删除其余特征,这样才能得到泛化性能更好,更简单的模型。
如何判断每个特征的用处有多大呢?这里有三种基本策略:单变量统计(univariate statics)、基于模型的选择(model-based selection)和迭代选择(interative selection)。这些方法都是监督方法,即他们需要目标值来拟合模型,也就是说,我们需要将数据划分为训练集和测试集。
单变量统计:在单变量统计中,我们计算每个特征和目标值之间的关系是否存在统计显著属性,然后选择具有最高置信度特征。对于分类问题,这也被称为方差分析(analysis of variance,ANOVA)。这些测试的一个关键性质就是他们是单变量的(univariate),即他们只单独考虑每个特征。因此,如果一个特征只有在另一个特征合并时才具有信息量,那么这个特征将被舍弃。
单变量测试的计算速度通常非常快,且不需要构建模型,同时,他们完全独立于你可能想要在特征选择之后应用的模型。
在单变量特征选择的问题中,如果要选择一项测试——对分类问题通常f_classif(默认值),对回归问题通常是f_regression——然后基于测试中确定的p值来选择一种舍弃特征的方法。所有舍弃参数的方法都是用阈值来舍弃所有p值过大的特征(意味着他们不可能与目标值相关)。计算预制的方法各有不同,最简单的是SelectBest和SelectPercentile,前者选择固定数量的K个特征,后者选择固定的百分比特征。
下面我们将分类的特征应用于cancer数据集(为了使得任务难度增加,我们添加一些噪声特征:
from sklearn.datasets import load_breast_cancer
from sklearn.feature_selection import SelectPercentile
from sklearn.model_selection import train_test_split
cancer = load_breast_cancer()
#获得确定性的随机数
rng = np.random.RandomState(42)
noise = rng.normal(size=(len(cancer.data), 50))
#向数据中添加噪声特征,前30个特征来自数据集,后50个是噪声
x_w_noise = np.hstack([cancer.data, noise])
x_train, x_test, y_train, y_test = train_test_split(x_w_noise, cancer.target, random_state=0,
test_size=.5)
#使用f_classif(默认值)和selectpercentile来选择50%特征
select = SelectPercentile(percentile=50)
select.fit(x_train, y_train)
#对数据集进行变换
x_train_selected = select.transform(x_train)
print("x_train.shape: {}".format(x_train.shape))
print("x_train_selected.shape: {}".format(x_train_selected.shape))
运行上述代码,其结果如下:
x_train.shape: (569, 80)
x_train_selected.shape: (569, 40)
如你所见,特征数量经过percentile选择后,从80个变成40个,我们可以利用get_support方法来看看那些特征被选中,那些特征被遗弃(他会返回所有特征的布尔值,选中的为True,遗弃的为Flase)。
![3571a6fdeaa3d633182cc301f1259ef2.png](https://i-blog.csdnimg.cn/blog_migrate/c8b70da87b326bf8ab3274fe1bfa234c.jpeg)
SectPercentil选择特征
从图中可以看出,大多数所选择的特征都是原始特征,且大多数噪声特征都被删除,但是原始特征的还原并不完美,我们比较Logistic回归在所有特征上的性能与仅使用所选特征的性能。
from sklearn.linear_model import LogisticRegression
#对测试数据进行变换
x_test_selected = select.transform(x_test)
lr = LogisticRegression()
lr.fit(x_train, y_train)
print("Score with all features: {.3f}".format(lr.score(x_test, y_test)))
lr.fit(x_train_selected, y_train)
print("Score with only select features: {.3f}".format(lr.score(x_test_selected, y_test)))
运行后其结果为:
Score with all features: 0.930
Score with only select features: 0.940
在这个例子中,删除噪声特征可以提高性能,即使丢失了某些原始特征。
![ad568696490e1a7f46fbae76cdab94b9.png](https://i-blog.csdnimg.cn/blog_migrate/18081449e83373b2e4f4c54ee2a1443e.jpeg)
取特征值的对数直方图