数据预处理后,我们生成了大量的新变量(比如独热编码生成了大量仅包含0或1的变量)。但实际上,部分新生成的变量可能是多余:一方面它们本身不一定包含有用的信息,故无法提高模型性能;另一方面过这些多余变量在构建模型时会消耗大量内存和计算能力。因此,我们应该进行特征选择并选择特征子集进行建模。
项目地址:
https://github.com/YC-Coder-Chen/feature-engineering-handbook
本文将介绍特征工程中的 Multivariate Filter Methods 多元特征过滤。
目录:
1.1.2 Multivariate Filter Methods 多元特征过滤
单变量特征过滤仅考虑了每一变量与目标变量之间的关系,而忽视了变量间的相关性。多元变量过滤则解决了这一问题,其考虑了变量之间的相互关系,基于整个特征空间选择最佳特征。因此多元特征过滤在删除冗余变量方面表现更好。这里利用亚利桑那州立大学开发的skfeature模块来进行多元特征过滤。
1.1.2.1 Max-Relevance Min-Redundancy (mRMR) 最大相关最小冗余
最大相关最小冗余试图寻找一个与目标变量有较高相关性(例如:MI)的变量子集,同时这个子集中的变量还应具有较低的相互关联性。通过解析源代码,我们发现,skfeature中最大相关最小冗余方法仅适用于分类问题中的离散特征,因为它计算过程中使用的是计算离散情形下的互信息 (MI)的公式。
公式:
假设数据集共包含m个特征,则基于mRMR公式,其中第n个特征的重要性可被表示为:
𝐼(𝑌,𝑋𝑖) 为变量𝑋𝑖与目标变量Y的互信息。1/|𝑆|∑𝑋𝑠∈𝑆𝐼(𝑋𝑠,𝑋𝑖)为变量𝑋𝑖与现有变量子集中所有变量的互信息的平均值。
mRMR其实是一个逐步(step-wise)的方法,在mRMR特征选择过程的每一步中,具有最高特征重要性𝑓𝑚𝑅𝑀𝑅(𝑋𝑖)的变量𝑋𝑖,(𝑋𝑖∉𝑆)将会被加入子集中,直至子集中的变量数达到用户要求。
import numpy as np from skfeature.function.information_theoretical_based import MRMR from sklearn.datasets import load_iris # 利用iris数据作为演示数据集 # 载入数据集 iris = load_iris() X, y = iris.data, iris.target # 选择前100个观测点作为训练集 # 剩下的50个观测点作为测试集 # 由于skfeature中的mRMR仅适用于离散变量 # 因此我们通过将float转换为int而把所有连续变量转换为离散变量 # 此转换仅用于演示目的 train_set = X[0:100,:].astype(int) test_set = X[100:,].astype(int) train_y = y[0:100].astype(int) feature_index,_,_ = MRMR.mrmr(train_set, train_y, n_selected_features=2) # 在训练集上训练 transformed_train = train_set[:,feature_index] # 转换训练集 assert np.array_equal(transformed_train, train_set[:,[2,3]]) # 其选择了第三个及第四个变量 transformed_test = test_set[:,feature_index] # 转换测试集 assert np.array_equal(transformed_test, test_set[:,[2,3]]) # 其选择了第三个及第四个变量
1.1.2.2 Correlation-based Feature Selection (CFS) 基于相关性的特征选择
与mRMR类似,基于相关性的特征选择(CFS)也基于一个类似的假设:一个好的特征子集应包含与目标高度相关且彼此不相关的特征。通过解析源代码,我们发现,skfeature中CFS的实现也仅适用于分类问题中的离散特征。因为其使用的是离散情形下的对称不确定性(symmetrical uncertainty)作为变量间相关性的衡量标准。
公式:
𝑆 为特征子集. 我们需要寻找最大化𝑀𝑒𝑟𝑖𝑡𝑆的最优子集𝑆∗。
𝑆𝑈(𝑋𝑖,𝑦)为离散变量𝑋𝑖与目标变量𝑦间的对称不确定性(SU)。
𝑆𝑈(𝑋𝑖,𝑋𝑗)为离散变量𝑋𝑖与离散变量𝑋𝑗间的对称不确定性(SU)。
import numpy as np from skfeature.function.statistical_based import CFS from sklearn.datasets import load_iris # 利用iris数据作为演示数据集 # 载入数据集 iris = load_iris() X, y = iris.data, iris.target # 选择前100个观测点作为训练集 # 剩下的50个观测点作为测试集 # 由于skfeature中的CFS仅适用于离散变量 # 因此我们通过将float转换为int而把所有连续变量转换为离散变量 # 此转换仅用于演示目的 train_set = X[0:100,:].astype(int) test_set = X[100:,].astype(int) train_y = y[0:100].astype(int) num_feature = 2 # 从原数据集中选择两个变量 feature_index = CFS.cfs(train_set, train_y) # 在训练集上训练 transformed_train = train_set[:,feature_index[0:num_feature]] # 转换训练集 assert np.array_equal(transformed_train, train_set[:,[3,2]]) # 其选择了第三个及第四个变量 transformed_test = test_set[:,feature_index[0:num_feature]] # 转换测试集 assert np.array_equal(transformed_test, test_set[:,[3,2]]) # 其选择了第三个及第四个变量
1.1.2.3 Fast Correlation-based Filter (FCBF) 基于相关性的快速特征选择
相比于CFS,FCBS能够更加高效的筛选变量。其同样为逐步(step-wise)的方法,具体步骤与mRMR非常类似,但FCBS使用对称不确定性(SU)衡量变量间的关联性。FCBF首先剔除与目标变量具有较低SU值的变量,并对剩下的变量按与目标变量的SU值从最高到最低排序,然后逐一删除冗余特征。与mRMR,CFS相似,在skfeature中实现的FCBF仅适用于具有离散变量的分类问题。
公式:
步骤:
1)计算每个特征变量 𝑋𝑖 与目标变量 𝑦 之间的相关性 𝑆𝑈(𝑋𝑖,𝑦)
2)仅保留 𝑆𝑈(𝑋𝑖,𝑦) 大于一定阈值 𝜎 的特征变量,组成候选列表 𝑆𝑙𝑖𝑠𝑡
3)按照 𝑆𝑈(𝑋𝑖,𝑦) 值的大小对 𝑆𝑙𝑖𝑠𝑡 中的变量从大到小排序
4)按顺序依次计算每一个特征 𝑋𝑖 与候选列表 𝑆𝑙𝑖𝑠𝑡 中顺序靠后的每一个特征 𝑋𝑗 的相关SU值 𝑆𝑈(𝑋𝑖,𝑋𝑗)
5)若 𝑆𝑈(𝑋𝑖,𝑋𝑗) 大于 𝑆𝑈(𝑋𝑗,𝑦) ,则从候选列表 𝑆𝑙𝑖𝑠𝑡 中删除 𝑋𝑗
import numpy as np from skfeature.function.information_theoretical_based import FCBF from sklearn.datasets import load_iris # 利用iris数据作为演示数据集 # 载入数据集 iris = load_iris() X, y = iris.data, iris.target # 选择前100个观测点作为训练集 # 剩下的50个观测点作为测试集 # 由于skfeature中的FCFS仅适用于离散变量 # 因此我们通过将float转换为int而把所有连续变量转换为离散变量 # 此转换仅用于演示目的 train_set = X[0:100,:].astype(int) test_set = X[100:,].astype(int) train_y = y[0:100].astype(int) num_feature = 2 # 从原数据集中选择两个变量 feature_index = FCBF.fcbf(train_set, train_y, n_selected_features = num_feature)[0] # 在训练集上训练 transformed_train = train_set[:,feature_index[0:num_feature]] # 转换训练集 assert np.array_equal(transformed_train, train_set[:,[3]]) # 其仅选择了第四个变量 # 这是由于其他变量目标变量𝑦之间的相关性过低造成的 transformed_test = test_set[:,feature_index[0:num_feature]] # 转换测试集 assert np.array_equal(transformed_test, test_set[:,[3]]) # 其仅选择了第四个变量
1.1.2.4 ReliefF
ReliefF方法是一种基于Relief方法的特征加权算法。在Relief方法中,其根据特征与目标变量的相关性强弱(二分类)给变量分配权重,并删除权重低于特定阈值的特征。其将相关性定义为变量区分邻近观测点的能力。
具体来说,在每一步中,Relief方法都会从训练集中随机选择一个观测点S,然后找到具有相同目标标签的S的最近邻观测点,称为NearHit。它还将找到具有不同目标标签的S的最近邻观测点,称为NearMiss。然后根据以下规则更新每个功能的权重:
1)若观测点S在某变量上与NearHit的距离大于与NearMiss的距离,则该变量的权重将增加,因为变量有助于区分最邻近情形下的目标标签。2)相反,若观测点S在某变量上与NearHit的距离小于与NearMiss的距离,则该变量的权重会降低。
将上述过程重复m次,最后我们会获得每个特征变量的平均权重。特征变量的权重越大,则特征的分类能力越强,越应该被留在最终的特征子集中。
在ReliefF中,其修改了权重更新的方式,因此ReliefF方法可以被应用于多类分类问题。另外,它随机采样K个最近的观测点而不是一个。
在skfeature中实现的ReliefF可用于分类问题中的连续特征或二元类别特征,因其使用的是L1范数来衡量差异。针对非二元特征,我们可以先将其独热编码,再使用ReliefF方法。
公式:
𝑅1 and 𝑅2 为任意两个观测点。𝑋𝑖为某一特征变量. S为我们选择的观测点. 𝐻𝑗为第j个NearHit,𝑀𝑗为第j个NearMiss. C为与我们所选的观测点不同的其他目标类别标签。
import numpy as np from skfeature.function.similarity_based import reliefF from sklearn.datasets import load_iris # 利用iris数据作为演示数据集 # 载入数据集 iris = load_iris() X, y = iris.data, iris.target # 选择前100个观测点作为训练集 # 剩下的50个观测点作为测试集 # skfeature中的reliefF直接适用于连续变量 train_set = X[0:100,:] test_set = X[100:,] train_y = y[0:100] num_feature = 2 # 从原数据集中选择两个变量 score = reliefF.reliefF(train_set, train_y) # 计算每一个变量的权重 feature_index = reliefF.feature_ranking(score) # 依据权重选择变量 transformed_train = train_set[:,feature_index[0:num_feature]] # 转换训练集 assert np.array_equal(transformed_train, train_set[:,[2, 3]]) # 其选择了第三个及第四个变量 transformed_test = test_set[:,feature_index[0:num_feature]] # 转换测试集 assert np.array_equal(transformed_test, test_set[:,[2, 3]]) # 其选择了第三个及第四个变量
1.1.2.5 Spectral Feature Selection (SPEC) 基于谱图的特征选择
基于谱图的特征选择(SPEC)方法是基于谱图理论的无监督方法。其首先建立变量相似度集合S,并建立其图表示。然后,其根据构造图的频谱评估特征。由于在skfeature中实现的SPEC方基于RBF(高斯)内核建立相似集,因此其可用于分类问题中的连续特征或二元类别特征。针对非二元特征,我们可以先将其独热编码,再使用ReliefF方法。
import numpy as np from skfeature.function.similarity_based import SPEC from sklearn.datasets import load_iris # 利用iris数据作为演示数据集 # 载入数据集 iris = load_iris() X, y = iris.data, iris.target # 选择前100个观测点作为训练集 # 剩下的50个观测点作为测试集 # skfeature中的SEPC方法直接适用于连续变量 train_set = X[0:100,:] test_set = X[100:,] train_y = y[0:100] num_feature = 2 # 从原数据集中选择两个变量 score = SPEC.spec(train_set) # 计算每一个变量的得分 feature_index = SPEC.feature_ranking(score) #依据变量得分选择变量 transformed_train = train_set[:,feature_index[0:num_feature]] # 转换训练集 assert np.array_equal(transformed_train, train_set[:,[1, 0]]) # 其选择了第一个及第二个变量 transformed_test = test_set[:,feature_index[0:num_feature]] # 转换测试集 assert np.array_equal(transformed_test, test_set[:,[1, 0]]) # 其选择了第一个及第二个变量
专栏系列:
专栏 | 基于 Jupyter 的特征工程手册:数据预处理(一)
专栏 | 基于 Jupyter 的特征工程手册:数据预处理(二)
专栏 | 基于 Jupyter 的特征工程手册:数据预处理(三)
专栏 | 基于 Jupyter 的特征工程手册:数据预处理(四)
专栏 | 基于 Jupyter 的特征工程手册:特征选择(一)
专栏 | 基于Jupyter 的特征工程手册:特征选择(二)
目前该项目完整中文版正在制作中,请持续关注哦~
中文版 Jupyter 地址:
https://github.com/YC-Coder-Chen/feature-engineering-handbook/blob/master/中文版/2.%20特征选择.ipynb