特征选择系列-01-过滤式详解-从原理到应用

做一个完整的机器学习GUI框架,需要考虑诸多可能出现的场景,未能及时更新,完整的算法构建与评估仍需后续展示。目前在做一些特征选择及可解释AI的一些相关工作,而后期这也将成为GUI的重要部分。本文将以过滤式特征为主线,对其原理及实战展开介绍,希望能提供理解。

为什么需要特征选择?

特征选择,也称特征子集选择,是指从M个特征中选择N个特征使得模型预测性能有所提升,同时,降低特征维度,使得模型的计算效率大幅度提升,提取更易于理解的特征,挖掘底层数据中隐藏的有用信息。特征越多,并不直接意味着其性能会变好,反之会使模型更复杂,训练时间更长,带来“维度灾难”。在机器学习实际建模当中,我们往往会根据先验或一些自动特征抽取工具(比如tsfresh)提取出众多特征,但往往大部分特征对模型提升毫无帮助,反之会增大模型训练代价,因此特征选择在机器学习中是比较关键的一环。

很显然,穷举法是最简单粗暴的方法,针对每种可能出现的特征组合进行建模评估,进而找到最优表现特征及模型。简单,但耗时(2n-1)个模型构建评估,随n增大,训练模型指数型增大。

过滤式特征选择

  • 方差过滤

  • 卡方过滤

  • F检验

  • 互信息

  • 皮尔森相关系数

  • Fisher得分

1、方差过滤

毫无疑问,方差过滤即是删除方差低于某个阈值的特征,这里的阈值人为定义。一个特征的方差较小,就意味着该特征没有区分度,可能大部分值是相同的,再极端一点,如果一个特征,其值相同,那该列特征方差为0,试想一下,一列全为相同值的特征对模型有影响吗?答案是否定的。
 

2、卡方过滤

卡方过滤是专门针对离散标签(分类问题)的相关性过滤,通过计算每个非负特征和标签之间的卡方统计量,并按照得分排名,选出top K个特征。卡方统计量反映的是实际频数和理论频数的吻合度,理论频数基于原假设计算结果,如果原假设成立则实际频数与理论频数的差值会很小,卡方小,反之原假设不成立,卡方会增大。

原假设:熬夜与变丑无任何关系,即相互独立无关

根据如上公式计算卡方值=(200-116.6)2/116.6+(80-46.64)2/46.64+……+(100-41.7)2/41.7后查表。

3、F检验

F检验,又称ANOVA,方差齐性检验,是用来捕捉每个特征与标签之间的线性关系的过滤方法。F检验既可以做回归,也可以做分类,和卡方过滤一样,选取p值小于0.05或者0.01的特征,这些特征与标签显著相关应该保留,反之删除。因此在sklearn中提供了faeture_selection.f_classif方法和feature_selection.f_regression方法。F检验是一类建立在F分布基础上的假设检验方法:其中X1X2服从自由度为d1d2的卡方分布,其中𝑋1和𝑋2分别服从自由度为𝑑1和𝑑2的卡方分布,即𝑋1∼𝜒2(𝑑1),𝑋2∼𝜒2(𝑑2),且𝑋1与𝑋2独立,则随机变量𝐹服从自由度为 (𝑑1,𝑑2)的F分布,记为𝐹∼F(𝑑1,𝑑2)。

4、互信息

互信息法是一种用来捕捉每个特征与标签之间的线性和非线性关系的过滤方法。sklearn提供了两个类feature_selection.mutual_info_classif和feature_selection.mutual_info_regression用以做分类和回归互信息特征选择。互信息法不返回p值或F值类似的统计量,它返回“每个特征与目标之间的互信息量的估计”,这个估计量在[0,1]之间取值,为0则表示两个变量独立,为1则表示两个变量完全相关。

5、皮尔森相关系数

Pearson相关系数是一种衡量特征与响应变量之间相关关系的方法,反映的是两个变量的相关性,因而只对线性关系敏感。取值范围在[-1,1之间],1表示完全正相关,0表示完全没有线性关系,-1表示完全负相关。通过下式得到的相关系数是基于一定样本的,并不能代表总体样本,所以同样需要进行假设检验以判定Conv(X,Y)是由于抽样误差所致还是两个变量之间确实存在相关关系。

6、Fisher得分

Fisher得分是一种基于距离的特征选择方法,Fisher得分越大,该特征的分类能力越强,说明该特征可以使得分类时类内部距离尽量小,类间距离尽可能大。

import os
import pandas as pd
from sklearn.datasets import make_classification
from sklearn.feature_selection import f_classif,f_regression
​
class featureSelect(object):
​
    def __init__(self,raw_data):
        self.raw_data = raw_data
​
    def pearsonr_selection(self, topN = 5):  # 皮尔逊pearsonr相关系数
        from scipy.stats import pearsonr
        data_x = self.raw_data.iloc[:, 1:-1]
        data_y = self.raw_data.iloc[:, -1]
        raw_features_list = self.raw_data.columns.to_list()
        fea_pear_list = []
        for col_name, data in data_x.iteritems():
            pears = pearsonr(data, data_y)[0]
            fea_pear_list.append([col_name, abs(pears)])
        # 对特征进行排序
        feature_df = pd.DataFrame(fea_pear_list)
        feature_df.columns = ["feature","pearson_score"]
        feature_df.sort_values(by="pearson_score", ascending=False, inplace=True)
        topn_fea = feature_df["feature"].iloc[0:topN].to_list()
        #筛选后的DataFrame可保存至csv文件以便后续建模输入
        return self.raw_data[[raw_features_list[0]]+topn_fea+[raw_features_list[-1]]]
​
    def variance_filter(self, threshold=0):
        from sklearn.feature_selection import VarianceThreshold
        X = self.raw_data.iloc[:, 1:-1]
        selector = VarianceThreshold(threshold)
        X_var_feature = selector.fit_transform(X)
        features_all = self.raw_data.columns.values.tolist()
        select_name_index = selector.get_support(indices=True)
        select_name = []
        for i in select_name_index:
            select_name.append(features_all[i])
        return self.raw_data[[features_all[0]]+select_name+[features_all[-1]]]
​
    #分类适用
    def chi2_select(self, k = 2):
        from sklearn.feature_selection import SelectKBest
        from sklearn.feature_selection import chi2
        X = self.raw_data.iloc[:, 0:-1]
        y = self.raw_data.iloc[:, -1]
        selector = SelectKBest(chi2, k = 2)
        selector.fit(X, y)
        features_all = self.raw_data.columns.values.tolist()
        select_name_index = selector.get_support(indices=True)
        select_name = []
        for i in select_name_index:
            select_name.append(features_all[i])
        return self.raw_data[[features_all[0]]+select_name+[features_all[-1]]]
​
        
    def f_classif_select(self,k):
        from sklearn.feature_selection import SelectKBest
        from sklearn.feature_selection import f_classif
        X = self.raw_data.iloc[:, 0:-1]
        y = self.raw_data.iloc[:, -1]
        F,pvalues_f = f_classif(X,y)
        features_all = self.raw_data.columns.values.tolist()
​
        selector = SelectKBest(f_classif, k=F.shape[0]-(pvalues_f>k).sum())
        selector.fit_transform(X, y)
        select_name_index = selector.get_support(indices=True)
        select_name = []
        for i in select_name_index:
            select_name.append(features_all[i])
        return self.raw_data[[features_all[0]]+select_name+[features_all[-1]]]
​
    def mutual_info_classif_select(self,k):
        from sklearn.feature_selection import SelectKBest
        from sklearn.feature_selection import mutual_info_classif as MIC
        X = self.raw_data.iloc[:, 0:-1]
        y = self.raw_data.iloc[:, -1]
        result = MIC(X, y)
        features_all = self.raw_data.columns.values.tolist()
​
        selector = SelectKBest(MIC, k=result.shape[0] - sum(result <= k))
        selector.fit_transform(X, y)
        select_name_index = selector.get_support(indices=True)
        select_name = []
        for i in select_name_index:
            select_name.append(features_all[i])
        return self.raw_data[[features_all[0]] + select_name + [features_all[-1]]]
​
​
if __name__ == '__main__':
    data = pd.read_csv("E:\\pycharm_project\\house_price-master\\house_price-master\\iris_training.csv",index_col=0)
    data.reset_index(inplace=True)
    data.columns = ["a","b","c","d","class"]
    fs = featureSelect(data)
​
    print(fs.chi2_select(k = 2))

 部分参考:https://www.bilibili.com/video/BV1Ch411x7xB/?spm_id_from=333.337.search-card.all.click&vd_source=12e876d9321bec4269ae1f826cf80ada

  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值