专栏 | 基于 Jupyter 的特征工程手册:特征选择(二)

简介: 专栏 | 基于 Jupyter 的特征工程手册:特征选择(二)

数据预处理后,我们生成了大量的新变量(比如独热编码生成了大量仅包含0或1的变量)。但实际上,部分新生成的变量可能是多余:一方面它们本身不一定包含有用的信息,故无法提高模型性能;另一方面过这些多余变量在构建模型时会消耗大量内存和计算能力。因此,我们应该进行特征选择并选择特征子集进行建模。


项目地址:

https://github.com/YC-Coder-Chen/feature-engineering-handbook


本文将介绍特征工程第一种算法:Filter Methods 过滤法(下)。


目录:


image.png


1.1.1.5 Mutual Information (regression problem) 互信息 (回归问题)


互信息(Mutual Information)衡量变量间的相互依赖性。其本质为熵差,即 𝐻(𝑋)−𝐻(𝑋|𝑌),即知道另一个变量信息后混乱的降低程度 。当且仅当两个随机变量独立时MI等于零。MI值越高,两变量之间的相关性则越强。与Pearson相关和F统计量相比,它还捕获了非线性关系。


公式:


  • 若两个变量均为离散变量:


image.png


p(𝑋,𝑌)(𝑥,𝑦) 为x和y的联合概率质量函数 (PMF), p𝑋(𝑥)则为x的联合概率质量函数 (PMF)。


  • 若两个变量均为连续变量:


image.png


p(𝑋,𝑌)(𝑥,𝑦) 为x和y的联合概率密度函数 (PDF),p𝑋(𝑥)则为x的概率密度函数 (PDF)。连续变量情形下,在实际操作中,往往先对数据离散化分桶,然后逐个桶进行计算。


但是实际上,一种极有可能的情况是,x和y中的一个可能是离散变量,而另一个是连续变量。因此在sklearn中,它基于[1]和[2]中提出的基于k最临近算法的熵估计非参数方法。


[1] A. Kraskov, H. Stogbauer and P. Grassberger, “Estimating mutual information”. Phys. Rev. E 69, 2004.

[2] B. C. Ross “Mutual Information between Discrete and Continuous Data Sets”. PLoS ONE 9(2), 2014.

import numpy as np
from sklearn.feature_selection import mutual_info_regression
from sklearn.feature_selection import SelectKBest
# 直接载入数据集
from sklearn.datasets import fetch_california_housing
dataset = fetch_california_housing()
X, y = dataset.data, dataset.target # 利用 california_housing 数据集来演示
# 此数据集中,X,y均为连续变量,故此满足使用MI的条件
# 选择前15000个观测点作为训练集
# 剩下的作为测试集
train_set = X[0:15000,:].astype(float)
test_set = X[15000:,].astype(float)
train_y = y[0:15000].astype(float)
# KNN中的临近数是一个非常重要的参数
# 故我们重写了一个新的MI计算方程更好的来控制这一参数
def udf_MI(X, y):
    result = mutual_info_regression(X, y, n_neighbors = 5) # 用户可以输入想要的临近数
    return result
# SelectKBest 将会基于一个判别方程自动选择得分高的变量
# 这里的判别方程为F统计量
selector = SelectKBest(udf_MI, k=2) # k => 我们想要选择的变量数
selector.fit(train_set, train_y) # 在训练集上训练
transformed_train = selector.transform(train_set) # 转换训练集
transformed_train.shape #(15000, 2), 其选择了第一个及第八个变量
assert np.array_equal(transformed_train, train_set[:,[0,7]])
transformed_test = selector.transform(test_set) # 转换测试集
assert np.array_equal(transformed_test, test_set[:,[0,7]]);
# 可见对于测试集,其依然选择了第一个及第八个变量
# 验算上述结果
for idx in range(train_set.shape[1]):
    score = mutual_info_regression(train_set[:,idx].reshape(-1,1), train_y, n_neighbors = 5)
    print(f"第{idx + 1}个变量与因变量的互信息为{round(score[0],2)}")
# 故应选择第一个及第八个变量

第1个变量与因变量的互信息为0.37
第2个变量与因变量的互信息为0.03
第3个变量与因变量的互信息为0.1
第4个变量与因变量的互信息为0.03
第5个变量与因变量的互信息为0.02
第6个变量与因变量的互信息为0.09
第7个变量与因变量的互信息为0.37
第8个变量与因变量的互信息为0.46


1.1.1.6 Chi-squared Statistics (classification problem) 卡方统计量 (分类问题)


卡方统计量主要用于衡量两个类别特征之间的相关性。sklearn提供了chi2方程用于计算卡方统计量。其输入的特征变量必须为布尔值或频率(故对于类别变量应考虑独热编码)。卡方统计量的零假设为两个变量是独立的,因为卡方统计量值越高,则两个类别变量的相关性越强。因此,我们应该选择具有较高卡方统计量的特征。

image.png

其中, 𝑂𝑖,𝑗 为在变量X上具有i-th类别值且在变量Y上具有j-th类别值的实际观测点计数。𝐸𝑖,𝑗 为利用概率估计的应在在变量X上具有i-th类别值且在变量Y上具有j-th类别值的观测点数量。n为总观测数, 𝑝𝑖 为在变量X上具有i-th类别值的概率, 𝑝𝑗 为在变量Y上具有j-th类别值的概率。


值得注意的是,通过解析源代码,我们发现在sklearn中利用chi2计算出来的卡方统计量并不是统计意义上的卡方统计量。当输入变量为布尔变量时,chi2计算值为该布尔变量为True时候的卡方统计量(我们将会在下文举例说明)。这样的优势是,独热编码生成的所有布尔值变量的chi2值之和将等于原始变量统计意义上的卡方统计量。


举个简单的例子,假设一个变量I有0,1,2两种可能的值,则独特编码后一共会产生3个新的布尔值变量。这三个布尔值变量的chi2计算出来的值之和,将等于变量I与因变量直接计算得出的统计意义上的卡方统计量。


解析sklearn中chi2的计算


image.png

image.png

image.png

# 而chi2方程算出来的布尔值之和为即为原始变量的统计意义上的卡方统计量
chi2(sample.values[:,[1,2,3]],sample.values[:,[0]])[0].sum() == chi2_contingency(obs)[0]
# 那么sklearn中的chi2是如何计算的呢?
# 不妨以第一个生成的布尔值为例,即Type为B
# chi2出来的值为0.17777778
# 而这与利用scipy以下代码计算出的计算一致
from scipy.stats import chisquare
f_exp = np.array([5/11, 3/11, 3/11]) * 3 # 预期频数为 output的先验概率 * Type为B 的样本数
chisquare([1,1,1], f_exp=f_exp) # [1,1,1] 即Type为B 的样本实际频数
# 即sklearn 中的chi2 仅考虑了Type为B情形下的列连表

Power_divergenceResult(statistic=0.17777777777777778, pvalue=0.9149472287300311)


如何利用sklearn 来进行特征选择

import numpy as np
from sklearn.feature_selection import chi2
from sklearn.feature_selection import SelectKBest
# 直接载入数据集
from sklearn.datasets import load_iris # 利用iris数据作为演示数据集
iris = load_iris()
X, y = iris.data, iris.target
# 此数据集中,X为连续变量,y为类别变量
# 不满足chi2的使用条件
# 将连续变量变为布尔值变量以满足chi2使用条件
# 不妨利用其是否大于均值来生成布尔值(仅作为演示用)
X = X > X.mean(0)
# iris 数据集使用前需要被打乱顺序
np.random.seed(1234)
idx = np.random.permutation(len(X))
X = X[idx]
y = y[idx]
# 选择前100个观测点作为训练集
# 剩下的作为测试集
train_set = X[0:100,:]
test_set = X[100:,]
train_y = y[0:100]
# sklearn 中直接提供了方程用于计算卡方统计量
# SelectKBest 将会基于一个判别方程自动选择得分高的变量
# 这里的判别方程为F统计量
selector = SelectKBest(chi2, k=2) # k => 我们想要选择的变量数
selector.fit(train_set, train_y) # 在训练集上训练
transformed_train = selector.transform(train_set) # 转换训练集
transformed_train.shape #(100, 2), 其选择了第三个及第四个变量 
assert np.array_equal(transformed_train, train_set[:,[2,3]])
transformed_test = selector.transform(test_set) # 转换测试集
assert np.array_equal(transformed_test, test_set[:,[2,3]]);
# 可见对于测试集,其依然选择了第三个及第四个变量
# 验证上述结果
for idx in range(train_set.shape[1]):
    score, p_value = chi2(train_set[:,idx].reshape(-1,1), train_y)
    print(f"第{idx + 1}个变量与因变量的卡方统计量为{round(score[0],2)},p值为{round(p_value[0],3)}")
# 故应选择第三个及第四个变量

第1个变量与因变量的卡方统计量为29.69,p值为0.0
第2个变量与因变量的卡方统计量为19.42,p值为0.0
第3个变量与因变量的卡方统计量为31.97,p值为0.0
第4个变量与因变量的卡方统计量为31.71,p值为0.0


1.1.1.7 F-Score (classification problem) F-统计量 (分类问题)


在分类机器学习问题中,若变量特征为类别特征,则我们可以使用独热编码配合上述chi2方法选择最重要的特征。但若特征为连续变量,则我们可以使用ANOVA-F值。ANOVA F统计量的零假设是若按目标变量(类别)分组,则连续变量的总体均值是相同的。故我们应选择具有高ANOVA-F统计量的连续变量,因为这些连续变量与目标变量的关联性强。


公式:


image.png


其中,SS(between)为组间的平方和,即组均值和总体均值之间的平方和。SS(error)是组内的平方和,即数据与组均值之间的平方和。m是目标变量的总类别数,n是观测数。

import numpy as np
from sklearn.feature_selection import f_classif
from sklearn.feature_selection import SelectKBest
# 直接载入数据集
from sklearn.datasets import load_iris # 利用iris数据作为演示数据集
iris = load_iris()
X, y = iris.data, iris.target
# 此数据集中,X为连续变量,y为类别变量
# 满足ANOVA-F的使用条件
# iris 数据集使用前需要被打乱顺序
np.random.seed(1234)
idx = np.random.permutation(len(X))
X = X[idx]
y = y[idx]
# 选择前100个观测点作为训练集
# 剩下的作为测试集
train_set = X[0:100,:]
test_set = X[100:,]
train_y = y[0:100]
# sklearn 中直接提供了方程用于计算ANOVA-F
# SelectKBest 将会基于一个判别方程自动选择得分高的变量
# 这里的判别方程为F统计量
selector = SelectKBest(f_classif, k=2) # k => 我们想要选择的变量数
selector.fit(train_set, train_y) # 在训练集上训练
transformed_train = selector.transform(train_set) # 转换训练集
transformed_train.shape #(100, 2), 其选择了第三个及第四个变量 
assert np.array_equal(transformed_train, train_set[:,[2,3]])
transformed_test = selector.transform(test_set) # 转换测试集
assert np.array_equal(transformed_test, test_set[:,[2,3]]);
# 可见对于测试集,其依然选择了第三个及第四个变量
# 验证上述结果
for idx in range(train_set.shape[1]):
    score, p_value = f_classif(train_set[:,idx].reshape(-1,1), train_y)
    print(f"第{idx + 1}个变量与因变量的ANOVA-F统计量为{round(score[0],2)},p值为{round(p_value[0],3)}")
# 故应选择第三个及第四个变量

第1个变量与因变量的ANOVA-F统计量为91.39,p值为0.0
第2个变量与因变量的ANOVA-F统计量为33.18,p值为0.0
第3个变量与因变量的ANOVA-F统计量为733.94,p值为0.0
第4个变量与因变量的ANOVA-F统计量为608.95,p值为0.0


1.1.1.7 Mutual Information (classification problem) 互信息 (分类问题)


【与1.1.1.5一样】互信息(Mutual Information)衡量变量间的相互依赖性。其本质为熵差,即 𝐻(𝑋)−𝐻(𝑋|𝑌),即知道另一个变量信息后混乱的降低程度 。当且仅当两个随机变量独立时MI等于零。MI值越高,两变量之间的相关性则越强。与Pearson相关和F统计量相比,它还捕获了非线性关系。


公式:


  • 若两个变量均为离散变量:


image.png


p(𝑋,𝑌)(𝑥,𝑦) 为x和y的联合概率质量函数 (PMF), p𝑋(𝑥)则为x的的联合概率质量函数 (PMF)。


  • 若两个变量均为连续变量:


image.png


p(𝑋,𝑌)(𝑥,𝑦) 为x和y的联合概率密度函数 (PDF),p𝑋(𝑥)则为x的的联合概率密度函数 (PDF)。连续变量情形下,在实际操作中,往往先对数据离散化分桶,然后逐个桶进行计算。


但是实际上,一种极有可能的情况是,x和y中的一个可能是离散变量,而另一个是连续变量。因此在sklearn中,它基于[1]和[2]中提出的基于k最临近算法的熵估计非参数方法。


[1] A. Kraskov, H. Stogbauer and P. Grassberger, “Estimating mutual information”. Phys. Rev. E 69, 2004.

[2] B. C. Ross “Mutual Information between Discrete and Continuous Data Sets”. PLoS ONE 9(2), 2014.

import numpy as np
from sklearn.feature_selection import mutual_info_classif
from sklearn.feature_selection import SelectKBest
# 直接载入数据集
from sklearn.datasets import load_iris # 利用iris数据作为演示数据集
iris = load_iris()
X, y = iris.data, iris.target
# 此数据集中,X为连续变量,y为类别变量
# 满足MI的使用条件
# iris 数据集使用前需要被打乱顺序
np.random.seed(1234)
idx = np.random.permutation(len(X))
X = X[idx]
y = y[idx]
# 选择前100个观测点作为训练集
# 剩下的作为测试集
train_set = X[0:100,:]
test_set = X[100:,]
train_y = y[0:100]
# KNN中的临近数是一个非常重要的参数
# 故我们重写了一个新的MI计算方程更好的来控制这一参数
def udf_MI(X, y):
    result = mutual_info_classif(X, y, n_neighbors = 5) # 用户可以输入想要的临近数
    return result
# SelectKBest 将会基于一个判别方程自动选择得分高的变量
# 这里的判别方程为F统计量
selector = SelectKBest(udf_MI, k=2) # k => 我们想要选择的变量数
selector.fit(train_set, train_y) # 在训练集上训练
transformed_train = selector.transform(train_set) # 转换训练集
transformed_train.shape #(100, 2), 其选择了第三个及第四个变量 
assert np.array_equal(transformed_train, train_set[:,[2,3]])
transformed_test = selector.transform(test_set) # 转换测试集
assert np.array_equal(transformed_test, test_set[:,[2,3]]);
# 可见对于测试集,其依然选择了第三个及第四个变量
# 验算上述结果
for idx in range(train_set.shape[1]):
    score = mutual_info_classif(train_set[:,idx].reshape(-1,1), train_y, n_neighbors = 5)
    print(f"第{idx + 1}个变量与因变量的互信息为{round(score[0],2)}")
# 故应选择第三个及第四个变量

第1个变量与因变量的互信息为0.56
第2个变量与因变量的互信息为0.28
第3个变量与因变量的互信息为0.99
第4个变量与因变量的互信息为1.02

专栏系列:


专栏 | 基于 Jupyter 的特征工程手册:数据预处理(一)

专栏 | 基于 Jupyter 的特征工程手册:数据预处理(二)

专栏 | 基于 Jupyter 的特征工程手册:数据预处理(三)

专栏 | 基于 Jupyter 的特征工程手册:数据预处理(四)

专栏 | 基于 Jupyter 的特征工程手册:特征选择(一)


目前该项目完整中文版正在制作中,请持续关注哦~


中文版 Jupyter 地址:

https://github.com/YC-Coder-Chen/feature-engineering-handbook/blob/master/中文版/2.%20特征选择.ipynb

相关文章
|
4月前
|
机器学习/深度学习 数据采集 算法
如何使用机器学习神器sklearn做特征工程?
如何使用机器学习神器sklearn做特征工程?
|
7月前
|
机器学习/深度学习 算法 Python
【Python机器学习专栏】数据特征选择与降维技术
【4月更文挑战第30天】本文探讨了Python中数据特征选择与降维技术在机器学习和数据分析中的应用。特征选择包括单变量选择、递归特征消除(RFE)、树模型的特征重要性和相关性分析,有助于去除冗余和无关特征。降维技术涵盖PCA、LDA以及非线性方法如KPCA和ISOMAP,用于在低维空间保留信息。这些技术能简化数据、提升模型性能及可解释性。
137 0
|
7月前
|
机器学习/深度学习 算法 Python
【Python机器学习专栏】逻辑回归在分类问题中的应用
【4月更文挑战第30天】逻辑回归是用于二分类的统计方法,通过Sigmoid函数将线性输出映射到[0,1],以预测概率。优点包括易于理解、不需要线性关系、鲁棒且能输出概率。缺点是假设观测独立、易过拟合及需大样本量。在Python中,可使用`sklearn`的`LogisticRegression`实现模型。尽管有局限,但在适用场景下,逻辑回归是强大且有价值的分类工具。
96 0
|
7月前
|
机器学习/深度学习 Python
【Python机器学习专栏】时间序列数据的特征工程
【4月更文挑战第30天】本文探讨了时间序列数据的特征工程,强调其在捕捉季节性、揭示趋势、处理异常值和提升模型性能中的重要性。介绍了滞后特征、移动窗口统计特征、时间戳特征、频域特征和波动率特征等方法,并提供了Python实现示例。通过有效特征工程,可提高时间序列分析的准确性和预测可靠性。
383 0
|
7月前
|
机器学习/深度学习 Python
LightGBM高级教程:高级特征工程
LightGBM高级教程:高级特征工程【2月更文挑战第8天】
549 2
|
机器学习/深度学习 存储 算法
python机器学习课程——决策树全网最详解超详细笔记附代码
决策树算法是一种逼近离散函数值的方法。它是一种典型的分类方法,首先对数据进行处理,利用归纳算法生成可读的规则和决策树,然后使用决策对新数据进行分析。本质上决策树是通过一系列规则对数据进行分类的过程。决策树方法最早产生于上世纪60年代,到70年代末。由J Ross Quinlan提出了ID3算法,此算法的目的在于减少树的深度。但是忽略了叶子数目的研究。C4.5算法在ID3算法的基础上进行了改进,对于预测变量的缺值处理、剪枝技术、派生规则等方面作了较大改进,既适合于分类问题,又适合于回归问题。决策树算法构造决策
376 0
|
API Python
lightgbm入门学习第一笔记
lightgbm入门学习第一笔记
454 0
|
机器学习/深度学习 数据采集 算法
专栏 | 基于 Jupyter 的特征工程手册:特征选择(三)
专栏 | 基于 Jupyter 的特征工程手册:特征选择(三)
579 0
专栏 | 基于 Jupyter 的特征工程手册:特征选择(三)
|
机器学习/深度学习 数据采集 算法
专栏 | 基于 Jupyter 的特征工程手册:特征选择(四)
专栏 | 基于 Jupyter 的特征工程手册:特征选择(四)
220 0
专栏 | 基于 Jupyter 的特征工程手册:特征选择(四)
|
机器学习/深度学习 数据采集 算法
专栏 | 基于 Jupyter 的特征工程手册:特征选择(一)
专栏 | 基于 Jupyter 的特征工程手册:特征选择(一)
220 0
专栏 | 基于 Jupyter 的特征工程手册:特征选择(一)