三种常见的特征选择方法

article/2025/11/5 16:21:37

特征选择

特征选择是特征工程里的一个重要问题,其目标是寻找最优特征子集。特征选择能剔除不相关(irrelevant)或冗余(redundant )的特征,从而达到减少特征个数,提高模型精确度,减少运行时间的目的。并且常能听到“数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已”,由此可见其重要性。
特征选择有以下三种常见的方法:
导入数据:

import pandas as pd
data = pd.read_csv(r"C:\Users\18700\Desktop\03数据预处理和特征工程\digit recognizor.csv")
data.head()X = data.iloc[:,1:] #特征矩阵
y = data.iloc[:,0] #标签
X.shape #维度指的是特征的数量,这个数据维度太高
#(42000, 784)
"""
这个数据量相对夸张,如果使用支持向量机和神经网络,很可能会直接跑不出来。使用KNN跑一次大概需要半个小时。
用这个数据举例,能更够体现特征工程的重要性。
"""

Wrapper(包装法)

基本思想:基于hold-out方法,对于每一个待选的特征子集,都在训练集上训练一遍模型,然后在测试集上根据误差大小选择出特征子集。需要先选定特定算法,通常选用普遍效果较好的算法, 例如Random Forest, SVM, kNN等等。
但是遍历所有可能的组合达到全局最优级,计算复杂度是2^n,一般是不太实际的算法。

Filter(过滤法)

Filter(过滤法):按照发散性或相关性对各个特征进行评分,设定阈值或者待选择特征的个数进行筛选
基本想法是:分别对每个特征x,计算x相对于标签y的信息量S。然后将S按照从大到小排序,输出前k个特征。关键的问题是使用什么样的方法来度量 S?下面给出几种常见的度量方式:

Pearson相关系数

Pearson相关系数
皮尔森相关系数是一种最简单的,能帮助理解特征和变量之间关系的方法,衡量的是变量之间的线性相关性,结果的取值区间为[-1,1] , -1 表示完全的负相关(这个变量下降,那个就会上升), +1 表示完全的正相关, 0 表示没有线性相关性。Pearson Correlation速度快、易于计算,经常在拿到数据(经过清洗和特征提取之后的)之后第一时间就执行。Scipy的pearsonr方法能够同时计算相关系数和p-value

import numpy as np
from scipy.stats import pearsonrnp.random.seed(0)
size = 300
x = np.random.normal(0, 1, size)
print("Lower noise:", pearsonr(x, x + np.random.normal(0, 1, size)))
print("Higher noise:", pearsonr(x, x + np.random.normal(0, 10, size)))from sklearn.feature_selection import SelectKBest
# 选择K个最好的特征,返回选择特征后的数据
# 第一个参数为计算评估特征是否好的函数,该函数输入特征矩阵和目标向量,输出二元组(评分,P值)的数组,数组第i项为第i个特征的评分和P值。在此定义为计算相关系数
# 参数k为选择的特征个数
SelectKBest(lambda X, Y: array(map(lambda x:pearsonr(x, Y), X.T)).T, k=2).fit_transform(iris.data, iris.target)

Pearson相关系数的一个明显缺陷是,作为特征排序机制,他只对线性关系敏感。如果关系是非线性的,即便两个变量具有一一对应的关系,Pearson相关性也可能会接近 0 。

卡方验证

卡方过滤是专门针对离散型标签(即分类问题)的相关性过滤。卡方检验类feature_selection.chi2计算每个非负特征和标签之间的卡方统计量,并依照卡方统计量由高到低为特征排名。再结合feature_selection.SelectKBest这个可以输入”评分标准“来选出前K个分数最高的特征的类,我们可以借此除去最可能独立于标签,与我们分类目的无关的特征。

from sklearn.ensemble import RandomForestClassifier as RFC
from sklearn.model_selection import cross_val_score
from sklearn.feature_selection import SelectKBest #选择k个分数最高的特征
from sklearn.feature_selection import chi2 #卡方检验#假设在这里我需要300个特征
X_fschi = SelectKBest(chi2, k=300).fit_transform(X_fsvar, y) #选择前300个卡方值的特征
X_fschi.shape
#(42000, 300)

验证模型的效果如何

cross_val_score(RFC(n_estimators=10,random_state=0),X_fschi,y,cv=5).mean()

输出结果:

0.9344761904761905
'''
如果模型的效果降低了,这说明我们在设定k=300的时候删除了与模型相关且有效的特征,
我们的K值设置得太小,要么我们需要调整K值,要么我们必须放弃相关性过滤。
'''

互信息法

互信息法是用来捕捉每个特征与标签之间的任意关系(包括线性和非线性关系)的过滤方法。和F检验相似,它既可以做回归也可以做分类,并且包含两个类feature_selection.mutual_info_classif(互信息分类)和feature_selection.mutual_info_regression(互信息回归)。
它返回“每个特征与目标之间的互信息量的估计”,这个估计量在[0,1]之间取值,为0则表示两个变量独立,为1则表示两个变量完全相关。

from sklearn.feature_selection import mutual_info_classif as MIC
result = MIC(X_fsvar,y)
k = result.shape[0] - sum(result <= 0)
#X_fsmic = SelectKBest(MIC, k=填写具体的k).fit_transform(X_fsvar, y)
#cross_val_score(RFC(n_estimators=10,random_state=0),X_fsmic,y,cv=5).mean()

方差选择法

过滤特征选择法还有一种方法不需要度量特征 x 和标签 y 的信息量。这种方法先要计算各个特征的方差,然后根据阈值,选择方差大于阈值的特征。优先消除方差为0的特征。VarianceThreshold有重要参数threshold,表示方差的阈值,表示舍弃所有方差小于threshold的特征,不填默认为0,即删除所有的记录都相同的特征。
VarianceThreshold:

from sklearn.feature_selection import VarianceThreshold
selector = VarianceThreshold() #实例化,不填参数默认方差为0
X_var0 = selector.fit_transform(X) #获取删除不合格特征之后的新特征矩阵
#也可以直接写成 X = VairanceThreshold().fit_transform(X)
X_var0.shape #是一个ndarray
#(42000, 708) #可将特征变少了,删除了方差为0的特征#X_var0.head() #会报错
pd.DataFrame(X_var0).head() #所以需要转换为dataframe

根据方差的中位数进行过滤

#通过var的中位数进行过滤
import numpy as np
X_fsvar = VarianceThreshold(np.median(X.var().values)).fit_transform(X) #就是舍弃方差小于中位数方差的特征
#X.var()是一个series,.values提取对应的值
X.var().values
np.median(X.var().values)
X_fsvar.shape
#(42000, 392)

特征是伯努利随机变量(二分类)

#若特征是伯努利随机变量,假设p=0.8,即二分类特征中某种分类占到80%以上的时候删除特征
X_bvar = VarianceThreshold(.8 * (1 - .8)).fit_transform(X)
X_bvar.shape
#(42000, 685)

方差选择的逻辑并不是很合理,这个是基于各特征分布较为接近的时候,才能以方差的逻辑来衡量信息量。但是如果是离散的或是仅集中在几个数值上,如果分布过于集中,其信息量则较小。而对于连续变量,由于阈值可以连续变化,所以信息量不随方差而变。 实际使用时,可以结合cross-validate进行检验

Embedded(嵌入法)

Embedded(嵌入法):先使用某些机器学习的模型进行训练,得到各个特征的权值系数,根据系数从大到小选择特征(类似于Filter,只不过系数是通过训练得来的)
基于惩罚项的特征选择法 通过L1正则项来选择特征:L1正则方法具有稀疏解的特性,因此天然具备特征选择的特性。
在这里插入图片描述
feature_selection.SelectFromModel

class sklearn.feature_selection.SelectFromModel (estimator, threshold=None, prefit=False, norm_order=1,max_features=None)
#estimator:使用的模型评估器,只要是带feature_importances_或者coef_属性,或带有l1和l2惩罚项的模型都可以使用。
#threshold:特征重要性的阈值,重要性低于这个阈值的特征都将被删除。
from sklearn.feature_selection import SelectFromModel 
from sklearn.ensemble import RandomForestClassifier as RFCRFC_ = RFC(n_estimators =10,random_state=0) #需要先实例化随机森林,再带入SelectFromModel。
X_embedded = SelectFromModel(RFC_,threshold=0.005).fit_transform(X,y) #这个是嵌入法的实例化
#在这里我只想取出来有限的特征。0.005这个阈值对于有780个特征的数据来说,是非常高的阈值,因为平均每个特征只能够分到大约0.001的feature_importances_
X_embedded.shape
#(42000, 47)  模型的维度明显被降低了

绘制threshold的学习曲线

import numpy as np
import matplotlib.pyplot as pltRFC_.fit(X,y).feature_importances_ #看特征重要性
#linspace(小值,大值,个数) 在最大值和最小值之间取20个数
threshold = np.linspace(0,(RFC_.fit(X,y).feature_importances_).max(),20) #让阈值的取值在0到最大值之间取出20个数score = []
for i in threshold:X_embedded = SelectFromModel(RFC_,threshold=i).fit_transform(X,y)once = cross_val_score(RFC_,X_embedded,y,cv=5).mean()score.append(once)plt.plot(threshold,score)
plt.show()

在这里插入图片描述

X_embedded = SelectFromModel(RFC_,threshold=0.00067).fit_transform(X,y)
X_embedded.shape
#(42000, 324)cross_val_score(RFC_,X_embedded,y,cv=5).mean()
#0.9391190476190475

http://chatgpt.dhexx.cn/article/KpDLbf3K.shtml

相关文章

特征选择方法最全总结!

上个月扫读完《阿里云天池大赛赛题解析》[1]后&#xff0c;看到书中对特征选择的讲述&#xff0c;于是便打算借此机会&#xff0c;系统梳理下各种特征选择方法。如有不足&#xff0c;还望指正。 一、背景介绍 在处理结构型数据时&#xff0c;特征工程中的特征选择是很重要的一个…

运行时错误 '-2147467259 (80004005)'

运行时错误 -2147467259 (80004005)方法 getFooterColor 作用于对象 IFPLayoutRegion 时失败遇到这样的错误主要是因为在 VBA 访问布局表格时&#xff0c;没有启用表尾。解决方法&#xff1a;在布局表格设置中启用表尾。注&#xff1a;同样的错误和解决方法也适用于表首。

win12服务器之常见错误:运行时错误(/应用程序中的服务器错误)

阿里云解答参考&#xff1a;https://www.cnblogs.com/xrtd/p/3704532.html 原因1: 这是由于配置中 Asp.Net 程序 没有显示详细的错误信息. 解决: 您必须修改 web.config 文件 将 <customErrors mode"On"/> 设置为mode "Off", 上传到网站根目录.然后…

问题:当运行exe程序时遇到错误0000007时如何解决

这里我是需要用的一个DDS库安装程序&#xff0c;但是经过一系列安装操作后&#xff0c;最后一步验证是否成功时出现了问题&#xff1a; 点击 该exe应用程序提示&#xff1a;应用程序错误0xc000007b 给出我使用后成功了的解决方法&#xff1a; 首先下载All in One Runtimes 简…

C++编译错误与运行时错误

笔试题里经常会有这样的题目&#xff0c;让你判断运行时错误还是编译错误。在这里将它总结一下。 在调试过程中&#xff0c;运行时错误是最麻烦的问题。因为编译错误可以由编译器检查出来&#xff0c;而大多数编译器对运行时错误却无能为力。查错和纠错的工作完全由用户自己来…

下面的程序运行时哪里会出现错误

1、下面的程序运行时哪里会出现错误&#xff1a;struct S { int i; int * p; }; int main() { S s; int * p &s.i; p[0] 4; p[1] 3; s.p p; s.p[1] 1; s.p[0] 2; return 0; } 【题目解析】 这道题考的是对结构体内存使用情况的理解。在32位的操作系统中&#xff0c;i…

Word粘贴文字时遇到报错:运行时错误‘53’:文件未找到:mathpage.WLL 解决方案

Word粘贴文字时遇到报错&#xff1a; 运行时错误‘53’&#xff1a; 文件未找到&#xff1a;mathpage.WLL 问题&#xff1a; 每次装完MathType后&#xff0c;在word里面进行粘贴操作时&#xff0c;总是出现“运行时错误‘53’&#xff1a;文件未找到&#xff1a;MathPage.WLL…

MathType 运行时错误‘53’:文件未找到:MathPage.WLL

问题描述 环境 MathType7.4Microsoft Office 365Windows 11 问题 情景1. Microsoft Word 启动时显示 Please reload Word to load MathType addin properly 情景2. 安装MathType后在 Microsoft Word 中使用复制粘贴时报错 运行时错误‘53’ 情景3. 在 Microsoft Word 中使…

JAVA的编译时错误和运行时错误

1. 要区分编译时错误和运行时错误&#xff0c;就应该先明白什么是编译&#xff1f;什么是运行&#xff1f; 首先&#xff0c;先看一下这张图&#xff1a; 编译期就是将我们写的java源代码交给编译器执行的过程&#xff0c;起翻译的作用&#xff0c;该过程主要对java源代码的…

【Word】MathType 运行时错误‘53’:文件未找到:MathPage.WLL

问题描述 1. 环境&#xff1a; MathType7.4Microsoft Office 365Windows 11 2. 问题 情景1. Microsoft Word 启动时显示 Please reload Word to load MathType addin properly 情景2. 安装MathType后在 Microsoft Word 中使用复制粘贴时报错 运行时错误‘53’ 情景3. 在 M…

运行程序报错怎么办?

Dev c中常见的报错有几种 一. ld return 1 exit status 这种报错是最常见的&#xff0c;下面是可能的原因 1.库函数拼写错误。如&#xff1a;printf&#xff0c;scanf,等 2.定义的函数名在调用时&#xff0c;函数名拼写错误&#xff08;这个主要自定义函数啊啥的可能比较多…

java clh队列_J.U.C|同步队列(CLH)

一、写在前面 在上篇我们聊到AQS的原理&#xff0c;具体参见《J.U.C|AQS原理》。 这篇我们来给大家聊聊AQS中核心同步队列(CLH)。 二、什么是同步队列(CLH) 同步队列 一个FIFO双向队列&#xff0c;队列中每个节点等待前驱节点释放共享状态(锁)被唤醒就可以了。 AQS如何使用它&a…

Java CLH队列

一、SMP和NUMA简要介绍 1.1 SMP SMP&#xff08;Symmetric MultiProcessing&#xff09;对称多处理是一种包括软硬件的多核计算机架构&#xff0c;会有两个或以上的相同的核心共享一块主存&#xff0c;这些核心在操作系统中地位相同&#xff0c;可以访问所有I/O设备。它的优点…

AQS-CLH同步队列

1:什么是同步队列&#xff08;CLH&#xff09; 同步队列 一个FIFO双向队列&#xff0c;队列中每个节点等待前驱节点释放共享状态&#xff08;锁&#xff09;被唤醒就可以了。 AQS如何使用它&#xff1f; AQS依赖它来完成同步状态的管理&#xff0c;当前线程如果获取同步状态…

java clh_【死磕Java并发】-J.U.C之AQS:CLH同步队列 - Java 技术驿站-Java 技术驿站

在上篇博客【死磕Java并发】-----J.U.C之AQS&#xff1a;AQS简介中提到了AQS内部维护着一个FIFO队列&#xff0c;该队列就是CLH同步队列。 CLH同步队列是一个FIFO双向队列&#xff0c;AQS依赖它来完成同步状态的管理&#xff0c;当前线程如果获取同步状态失败时&#xff0c;AQS…

J.U.C之AQS:CLH同步队列

此篇博客所有源码均来自JDK 1.8 在上篇博客中提到了AQS内部维护着一个FIFO队列&#xff0c;该队列就是CLH同步队列。 CLH同步队列是一个FIFO双向队列&#xff0c;AQS依赖它来完成同步状态的管理&#xff0c;当前线程如果获取同步状态失败时&#xff0c;AQS则会将当前线程已经等…

CLH Lock 原理

背景 SMP(Symmetric Multi-Processor) 对称多处理器结构&#xff0c;它是相对非对称多处理技术而言的、应用十分广泛的并行技术。在这种架构中&#xff0c;一台计算机由多个CPU组成&#xff0c;并共享内存和其他资源&#xff0c;所有的CPU都可以平等地访问内存、I/O和外部中断…

AQS: CLH 介绍

AQS内部维护着一个FIFO队列&#xff0c;该队列就是CLH同步队列。 CLH同步队列是一个FIFO双向队列&#xff0c;AQS依赖它来完成同步状态的管理&#xff0c;当前线程如果获取同步状态失败时&#xff0c;AQS则会将当前线程已经等待状态等信息构造成一个节点&#xff08;Node&…

【算法数据结构专题】「线程锁算法专项」初探CLH队列锁机制原理分析

技术扩展 SMP&#xff08;对称多处理器架构&#xff09; SMP(Symmetric Multi-Processor)&#xff0c;即对称多处理器结构&#xff0c;指服务器中多个CPU对称工作&#xff0c;每个CPU访问内存地址所需时间相同。其主要特征是共享&#xff0c;包含对CPU&#xff0c;内存&#…

java clh_【Java并发编程实战】—– AQS(四):CLH同步队列

在【Java并发编程实战】—–“J.U.C”&#xff1a;CLH队列锁提过&#xff0c;AQS里面的CLH队列是CLH同步锁的一种变形。 其主要从双方面进行了改造&#xff1a;节点的结构与节点等待机制。在结构上引入了头结点和尾节点&#xff0c;他们分别指向队列的头和尾&#xff0c;尝试获…