之前我们介绍了数据预处理的多个前置步骤,包括缺失值处理,异常值处理,特征构造等,感兴趣可以点击下方链接支持一下:
在进行了数据预处理以及特征构造后,我们需要对所有特征做一个选择,选择其中对模型更重要的特征。
特征选择的方法主要分为三大类的方法,分别是过滤法,包裹法,嵌入法。
接下来我将使用天池学习赛中二手车数据集做示例数据,编写代码,若需要该数据集可以点击主页查看我的其它文章,也可以私信我。
该类方法主要是根据不同的特征的不同表现,不讨论其对模型的影响,主要从其与目标的相关性或自相关性等属性来观察其是否是有用的特征。
当使用过滤法进行特征选择的时候,我们可以从其自身角度或者其与其他特征相关性的角度分别来看。
这部分主要是从变量本身的出现频次,及其自身能够反映变化的量来决定观察其是否能够作为有效的特征。
若某一特征存在过多缺失值,则可以考虑直接将该特征删除。
读取数据后直接调用isnull().sum()两个方法既可以观察到所有特征的缺失数目,若缺失的比例过大既可以考虑删除。
train_data.isnull().sum()
若某连续变量的方差过小,说明该特征值趋向于单一的状态,变化幅度不大,所以可以考虑删除。
在使用pandas读取数据后,直接调用函数就能查看所有列的方差,代码如下。
train_data.std()
结果如下:
上述结果中,方差较小的特征已经被红圈标出,此时就可以把方差为0的特征直接删除,因为他没有变化对我们没有意义,其他的可以酌情删除。
若某特征的样本分布更多的偏向于某一值,则可以考虑删除。
在下面的代码示例中,我随机选择了两个特征作为图的数据:
for col in ['seller', 'fuelType']:
plt.figure()
plt.title(col)
train_data[col].value_counts().plot.bar()
结果如下:
我们可以看到,seller特征的频数上来看,为1的条目相对于为0的少很多,所以可以考虑删除此列。
多变量之间的关系,主要存在两种:
于此同时,由于变量又有连续性和类别型两种类型,所以根据不同种类型的变量我们要使用不同的方法:
使用pandas中的函数即可满足我们此需求,代码如下所示:
train_data.loc[:,'v_1':].corr('pearson')
correlation = train_data.loc[:,'v_1':].corr('pearson')
f , ax = plt.subplots(figsize = (9, 9))
plt.title('Correlation of Numeric Features with Price',y=1,size=16)
sns.heatmap(correlation,square = True, vmax=0.8)
- 斯皮尔曼相关系数
该相关系数不假设变量服从何种分布,其基于等级的概念计算变量的相关性,更适合顺序变量。
代码如下所示:
correlation = train_data.loc[:,'v_1':].corr('spearman')
结果如下:
可视化结果如下所示,其中代码和上述皮尔逊相关系数类似:
pandas里也提供了相关方法:
print(train_data['price'].corr(train_data['gearbox'], method='kendall'))
print(train_data['fuelType'].corr(train_data['price'], method='kendall'))
print(train_data['bodyType'].corr(train_data['price'], method='kendall'))
stats.chisquare(train_data['fuelType'],train_data['gearbox'],)
我在执行这部分代码的时候遇到了以下错误: For each axis slice, the sum of the observed
frequencies must agree with the sum of the expected frequencies to a
relative tolerance of 1e-08, but the percent differences are:
0.6395233979503643
mutual_info_score(train_data['gearbox'], train_data['fuelType'])
包裹法利用学习器的性能当作特征的评价标准,根据学习器的学习结果作为特征的选择标准。
便利所有特征子集的组合情况,然后让模型学习。这种方法开销较大,会花费非常长的时间。
不断改变搜索的空间,根据模型的最终得分作为评分权重。
向前搜索和向后搜索是两个完全相反的方向,向前搜索将从空集开始不断地加入新的特征,若评分提高则保留,否则删去。向后搜索从所有特征开始,不断地删除特征迭代。
from sklearn.linear_model import LinearRegression
lr = LinearRegression()
from sklearn.feature_selection import RFE
rfe = RFE(estimator = lr, # 基分类器
n_features_to_select = 5, # 选择特征个数
step = 1, # 每次迭代移除的特征个数
verbose = 1 # 显示中间过程
).fit(train_data.loc[:1000,'v_0':],train_data.loc[:1000,'price'])
X_RFE = rfe.transform(train_data.loc[:1000,'v_0':])
print("-----RFE特征选择结果-----")
print("有效特征个数 : %d" % rfe.n_features_)
print("全部特征等级 : %s" % list(rfe.ranking_))
PRECV在PRE的基础上加入了模型表现得考虑,使得选择的模型更具有说服力。
代码实现如下所示:
from sklearn.model_selection import StratifiedKFold
from sklearn.feature_selection import RFECV
rfecv = RFECV(estimator=lr, # 学习器
min_features_to_select=5, # 最小选择的特征数量
step=1, # 移除特征个数
cv=StratifiedKFold(3), # 交叉验证次数
scoring='r2', # 学习器的评价标准
verbose = 1,
n_jobs = 1
).fit(train_data.loc[:100000,'v_0':],train_data.loc[:100000,'price'])
X_RFECV = rfecv.transform(train_data.loc[:100000,'v_0':])
print("RFECV特征选择结果——————————————————————————————————————————————————")
print("有效特征个数 : %d" % rfecv.n_features_)
print("全部特征等级 : %s" % list(rfecv.ranking_))
特征选择的过程直接在学习器中完成,把特征选择作为学习器的一部分。
代码如下:
from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import GradientBoostingClassifier
iris = load_iris()
# 将待L1惩罚项的逻辑回归作为基模型的特征选择
selected_data_lr = SelectFromModel(LogisticRegression(penalty='l1', C = 0.1, solver = 'liblinear'), max_features = 3).fit_transform(iris.data, iris.target)
# 将GBDT作为基模型的特征选择
selected_data_gbdt = SelectFromModel(GradientBoostingClassifier(), max_features = 3).fit_transform(iris.data, iris.target)
print(iris.data.shape)
print(selected_data_lr.shape)
print(selected_data_gbdt.shape)
本篇文章列举了常见的特征选择方式和方法,还有一部分代码在更新中。本文部分内容来源于Datawhale中,我再也持续的学习其内容并进行一定的总结,如若侵权请联系删除。