【解决(几乎)任何机器学习问题】:特征选择

news2024/11/13 15:18:21
当你创建了成千上万个特征后,就该从中挑选出⼏个了。但是,我们绝不应该创建成百上千个⽆⽤的特征。特征过多会带来⼀个众所周知的问题,即 "维度诅咒"。如果你有很多特征,你也必须有很多训练样本来捕捉所有特征。什么是 "⼤量 "并没有正确的定义,这需要您通过正确验证您的模型和检查训练模型所需的时间来确定。
选择特征的最简单⽅法是 删除⽅差⾮常⼩的特征 。如果特征的⽅差⾮常⼩(即⾮常接近于 0),它们就接近于常量,因此根本不会给任何模型增加任何价值。最好的办法就是去掉它们,从⽽降低复杂度。请注意,⽅差也取决于数据的缩放。 Scikit-learn 的 VarianceThreshold 实现了这⼀点。
from sklearn.feature_selection import VarianceThreshold
data = .
var_thresh = VarianceThreshold(threshold=0.1)
transformed_data = var_thresh.fit_transform(data)
我们还可以删除相关性较⾼的特征。要计算不同数字特征之间的相关性,可以使⽤⽪尔逊相关性。
import pandas as pd
from sklearn.datasets import fetch_california_housing
data = fetch_california_housing()
X = data["data"]
col_names = data["feature_names"]
y = data["target"]
df = pd.DataFrame(X, columns=col_names)
df.loc[:, "MedInc_Sqrt"] = df.MedInc.apply(np.sqrt)
df.corr()

得出相关矩阵,如图 1 所⽰。 

我们看到,MedInc_Sqrt 与 MedInc 的相关性⾮常⾼。因此,我们可以删除其中⼀个特征。
现在我们可以转向⼀些 单变量特征选择⽅法 。单变量特征选择只不过是针对给定⽬标对每个特征进⾏评分。 互信息 ⽅差分析 F 检验和 chi2 是⼀些最常⽤的单变量特征选择⽅法。在 scikit-learn 中,有两种⽅法可以使⽤这些⽅法。
SelectKBest:保留得分最⾼的 k 个特征
SelectPercentile:保留⽤⼾指定百分⽐内的顶级特征。
必须注意的是,只有⾮负数据才能使⽤ chi2。在⾃然语⾔处理中,当我们有⼀些单词或基于 tf-idf 的特征时,这是⼀种特别有⽤的特征选择技术。最好为单变量特征选择创建⼀个包装器,⼏乎可以⽤于任何新问题。

from sklearn.feature_selection import chi2
from sklearn.feature_selection import f_classif
from sklearn.feature_selection import f_regression
from sklearn.feature_selection import mutual_info_classif
from sklearn.feature_selection import mutual_info_regression
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import SelectPercentile

class UnivariateFeatureSelction:
    def __init__(self, n_features, problem_type, scoring):
        if problem_type == "classification":
            valid_scoring = {
                "f_classif": f_classif,
                "chi2": chi2,
                "mutual_info_classif": mutual_info_classif
            }
        else:
            valid_scoring = {
                "f_regression": f_regression,
                "mutual_info_regression": mutual_info_regression
            }
        if scoring not in valid_scoring:
            raise Exception("Invalid scoring function")
        if isinstance(n_features, int):
            self.selection = SelectKBest(
                valid_scoring[scoring],
                k=n_features
            )
        elif isinstance(n_features, float):
            self.selection = SelectPercentile(
                valid_scoring[scoring],
                percentile=int(n_features * 100)
            )
        else:
            raise Exception("Invalid type of feature")
    
    def fit(self, X, y):
        return self.selection.fit(X, y)
    
    def transform(self, X):
        return self.selection.transform(X)
    
    def fit_transform(self, X, y):
        return self.selection.fit_transform(X, y)

使⽤该类⾮常简单。

# Example usage:
ufs = UnivariateFeatureSelction(
    n_features=0.1,
    problem_type="regression",
    scoring="f_regression"
)
ufs.fit(X, y)
X_transformed = ufs.transform(X)
这样就能满⾜⼤部分单变量特征选择的需求。请注意,创建较少⽽重要的特征通常⽐创建数以百计的特征要好。单变量特征选择不⼀定总是表现良好。⼤多数情况下,⼈们更喜欢使⽤机器学习模型进⾏特征选择。让我们来看看如何做到这⼀点。
使⽤模型进⾏特征选择的最简单形式被称为贪婪特征选择。在贪婪特征选择中,第⼀步是选择⼀个模型。第⼆步是选择损失/评分函数。第三步也是最后⼀步是反复评估每个特征,如果能提⾼损失/评分,就将其添加到 "好 "特征列表中。没有⽐这更简单的了。但你必须记住,这被称为贪婪特征选择是有原因的。这种特征选择过程在每次评估特征时都会适合给定的模型。这种⽅法的计算成本⾮常⾼。完成这种特征选择也需要⼤量时间。如果不正确使⽤这种特征选择,甚⾄会导致模型过度拟合。让我们来看看它是如何实现的。

import pandas as pd
from sklearn import linear_model
from sklearn import metrics
from sklearn.datasets import make_classification

class GreedyFeatureSelection:
    def evaluate_score(self, X, y):
        model = linear_model.LogisticRegression()
        model.fit(X, y)
        predictions = model.predict_proba(X)[:, 1]
        auc = metrics.roc_auc_score(y, predictions)
        return auc
    
    def _feature_selection(self, X, y):
        good_features = []
        best_scores = []
        num_features = X.shape[1]
        while True:
            this_feature = None
            best_score = 0
            for feature in range(num_features):
                if feature in good_features:
                    continue
                selected_features = good_features + [feature]
                xtrain = X[:, selected_features]
                score = self.evaluate_score(xtrain, y)
                if score > best_score:
                    this_feature = feature
                    best_score = score
            if this_feature is None:
                break
            good_features.append(this_feature)
            best_scores.append(best_score)
            if len(best_scores) > 1:
                if best_scores[-1] < best_scores[-2]:
                    break
        return best_scores[:-1], good_features[:-1]
    
    def __call__(self, X, y):
        scores, features = self._feature_selection(X, y)
        return X[:, features], scores

if __name__ == "__main__":
    X, y = make_classification(n_samples=1000, n_features=100)
    X_transformed, scores = GreedyFeatureSelection()(X, y)
这种贪婪特征选择⽅法会返回分数和特征索引列表。图 2 显⽰了在每次迭代中增加⼀个新特征后,分数是如何提⾼的。我们可以看到,在某⼀点之后,我们就⽆法提⾼分数了,这就是我们停⽌的地⽅。
另⼀种贪婪的⽅法被称为递归特征消除法(RFE)。在前⼀种⽅法中,我们从⼀个特征开始,然后不断添加新的特征,但在 RFE 中,我们从所有特征开始,在每次迭代中不断去除⼀个对给定模型提供最⼩值的特征。但我们如何知道哪个特征的价值最⼩呢?如果我们使⽤线性⽀持(SVM)或逻辑回归等模型,我们会为每个特征得到⼀个系数,该系数决定了特征的重要性。⽽对于任何基于树的模型,我们得到的是特征重要性,⽽不是系数。在每次迭代中,我们都可以剔除最不重要的特征,直到达到所需的特征数量为⽌。因此,我们可以决定要保留多少特征。

当我们进⾏递归特征剔除时,在每次迭代中,我们都会剔除特征重要性较⾼的特征或系数接近 0 的特征。请记住,当你使⽤逻辑回归这样的模型进⾏⼆元分类时,如果特征对正分类很重要,其系数就会更正,⽽如果特征对负分类很重要,其系数就会更负。修改我们的贪婪特征选择类,创建⼀个新的递归特征消除类⾮常容易,但 scikit-learn 也提供了 RFE。下⾯的⽰例展⽰了⼀个简单的法。

import pandas as pd
from sklearn.feature_selection import RFE
from sklearn.linear_model import LinearRegression
from sklearn.datasets import fetch_california_housing

data = fetch_california_housing()
X = data["data"]
col_names = data["feature_names"]
y = data["target"]

model = LinearRegression()
rfe = RFE(
    estimator=model,
    n_features_to_select=3
)
rfe.fit(X, y)
X_transformed = rfe.transform(X)
我们看到了从模型中选择特征的两种不同的贪婪⽅法。但也可以根据数据拟合模型,然后通过特征系数或特征的重要性从模型中选择特征。如果使⽤系数,则可以选择⼀个阈值,如果系数⾼于该阈值,则可以保留该特征,否则将其剔除。
让我们看看如何从随机森林这样的模型中获取特征重要性。

import pandas as pd
from sklearn.datasets import load_diabetes
from sklearn.ensemble import RandomForestRegressor
data = load_diabetes()
X = data["data"]
col_names = data["feature_names"]
y = data["target"]
model = RandomForestRegressor()
model.fit(X, y)

随机森林(或任何模型)的特征重要性可按如下⽅式绘制。

importances = model.feature_importances_
idxs = np.argsort(importances)
plt.title('Feature Importances')
plt.barh(range(len(idxs)), importances[idxs], align='center')
plt.yticks(range(len(idxs)), [col_names[i] for i in idxs])
plt.xlabel('Random Forest Feature Importance')
plt.show()

 结果如图 3 所⽰。

从模型中选择最佳特征并不是什么新鲜事。您可以从⼀个模型中选择特征,然后使⽤另⼀个模型进⾏训练。例如,你可以使⽤逻辑回归系数来选择特征,然后使⽤随机森林(Random Forest)对所选特征进⾏模型训练。Scikit-learn 还提供了 SelectFromModel 类,可以帮助你直接从给定的模型中选择特征。您还可以根据需要指定系数或特征重要性的阈值,以及要选择的特征的最⼤数量。
请看下⾯的代码段,我们使⽤ SelectFromModel 中的默认参数来选择特征。
import pandas as pd
from sklearn.datasets import load_diabetes
from sklearn.ensemble import RandomForestRegressor
from sklearn.feature_selection import SelectFromModel
data = load_diabetes()
X = data["data"]
col_names = data["feature_names"]
y = data["target"]
model = RandomForestRegressor()
sfm = SelectFromModel(estimator=model)
X_transformed = sfm.fit_transform(X, y)
support = sfm.get_support()
print([x for x, y in zip(col_names, support) if y = True ])
上⾯程序打印结果: ['bmi','s5']。我们再看图 3,就会发现这是最重要的两个特征。因此,我们也可以直接从随机森林提供的特征重要性中进⾏选择。我们还缺少⼀件事,那就是使⽤ L1 Lasso )惩罚模型 进⾏特征选择。当我们使⽤ L1 惩罚进⾏正则化时,⼤部分系数都将为 0(或接近 0),因此我们要选择系数不为 0 的特征。只需将模型选择⽚段中的随机森林替换为⽀持 L1 惩罚的模型(如 lasso 回归)即可。所有基于树的模型都提供特征重要性,因此本章中展⽰的所有基于模型的⽚段都可⽤于 XGBoost、LightGBM 或 CatBoost。特征重要性函数的名称可能不同,产⽣结果的格式也可能不同,但⽤法是⼀样的。最后,在进⾏特征选择时必须⼩⼼谨慎。在训练数据上选择特征,并在验证数据上验证模型,以便在不过度拟合模型的情况下正确选择特征。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1468673.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Guitar Pro8.2吉他乐谱软件功能测评评价

Guitar Pro 8.2吉他乐谱软件全面评价 Guitar Pro 8.2作为一款吉他乐谱软件&#xff0c;已经得到了广大吉他手和音乐制作人的认可。作为软件评价专家&#xff0c;我对这款软件进行了全面的体验和分析&#xff0c;以下是我在易用性、功能丰富性、用户界面设计、稳定性以及性价比…

【MATLAB源码-第146期】基于matlab的信源编码仿真GUI,对比霍夫曼编码,算术编码和LZ编码。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 霍夫曼编码、算术编码和LZ编码是三种广泛应用于数据压缩领域的编码技术。它们各自拥有独特的设计哲学、实现方式和适用场景&#xff0c;因此在压缩效率、编解码速度和内存使用等方面表现出不同的特点。接下来详细描述这三种编…

open3d 将点云投影到平面

open3d 将点云投影到平面 一、算法原理二、代码三、结果展示1.原点云2.点云数据向x z 0投影 四、相关数据 一、算法原理 假设点&#xff08;x0, y0, z0&#xff09;, 平面方程为 mx ny sz d 0 过点&#xff08;x0, y0, z0&#xff09;&#xff0c;且垂直平面的直线方程…

TensorRT及CUDA自学笔记006 PTX、PTX兼容性及二进制兼容性

TensorRT及CUDA自学笔记006 PTX、PTX兼容性及二进制兼容性 PTX定义 PTX是CUDA平台的一种虚拟机器和指令集&#xff0c;可以理解为一种CUDA平台的汇编语言使用C编写的CUDA程序首先被转换成PTX指令集&#xff0c;PTX指令在经过优化后再转换为特定GPU架构对应的指令集&#xff0…

关于Arrays类中asList(T... a)泛型参数辨析

前提 我们需要知道两点 &#xff08;1&#xff09;T指的是泛型类型&#xff0c;它只能是引用类型&#xff0c;何为引用类型&#xff1f;在java中除了基本数据类型&#xff08;如byte、short、int、long、float、double、boolean、char&#xff09;之外的所有类型都是引用类型…

STL - 并查集

1、并查集原理 在一些应用问题中&#xff0c;需要将n个不同的元素划分成一些不相交的集合&#xff1b;开始时&#xff0c;每个元素自成一个 单元素集合&#xff0c;然后按一定的规律将归于同一组元素的集合合并&#xff1b;在此过程中要反复用到查询某一 个元素归属于那个集合的…

YOLOv5改进 | SPPF篇 | 利用YOLOv9最新的SPPELAN模块改进SPPF(全网独家创新,附手撕结构图)

一、本文介绍 本文给大家带来的改进机制是利用2024/02/21号最新发布的YOLOv9其中提出的SPPELAN模块来改进SPPF&#xff0c;其中YOLOv9针对于这个模块并没有介绍&#xff0c;只是在其项目文件中用到了&#xff0c;我将其整理出来用于我们的YOLOv5的项目&#xff0c;同时空间金字…

vue3中ref创建变量取值时自动补充 .value 插件 volar

插件 TypeScript Vue Plugin (Volar) 设置中配置

自然语言处理中关键概念——词嵌入(Word Embedding)

词嵌入&#xff08;Word Embedding&#xff09;是一种在自然语言处理中广泛使用的表示方法&#xff0c;它将离散的词汇表中的每个词转换为一个连续向量空间中的稠密向量。这种低维度实数向量能够捕捉词语之间的语义和句法关系。 通过训练神经网络模型&#xff08;如word2vec、G…

一周学会Django5 Python Web开发-Http请求HttpRequest请求类

锋哥原创的Python Web开发 Django5视频教程&#xff1a; 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计25条视频&#xff0c;包括&#xff1a;2024版 Django5 Python we…

open3d KD-Tree K近邻点搜索

open3d KD-Tree K近邻点搜索 一、算法原理1.KD-Tree 介绍2.原理 二、代码三、结果1.原点云2.k近邻点搜索后的点云 四、相关数据 一、算法原理 1.KD-Tree 介绍 kd 树或 k 维树是计算机科学中使用的一种数据结构&#xff0c;用于在具有 k 维的空间中组织一定数量的点。它是一个…

【Django开发】0到1开发美多shop项目:短信验证码和RabbitMQ。全md文档笔记(附代码 文档)

本系列文章md笔记&#xff08;已分享&#xff09;主要讨论django商城项目相关知识。项目利用Django框架开发一套前后端不分离的商城项目&#xff08;4.0版本&#xff09;含代码和文档。功能包括前后端不分离&#xff0c;方便SEO。采用Django Jinja2模板引擎 Vue.js实现前后端…

开源世界的学术问题

自由软件基金会是1983年成立的&#xff0c;到现在是41年。正好很有意思的是&#xff0c;在去年还有一篇文章&#xff08;CSDN 的翻译&#xff09;&#xff0c;专门在质疑说成立 40 年的自由软件基金会是不是已经快不行了&#xff0c;所以我们会用这个标题叫做兴衰发展历程来介绍…

Windows安装HBuilderX

下载 HBuilderX下载地址: 下载地址 解压安装包 HBuilderX&#xff0c;Windows为zip包&#xff0c;解压后才能使用。 首先&#xff0c;选中下载的zip包&#xff0c;点击右键菜单&#xff0c;点击解压到当前文件夹进入解压后的文件夹&#xff0c;找到HBuilderX.exe&#xff0…

OpenFeign整合Sentinel

OpenFeign 整合 Sentinel 实现服务降级 引入依赖 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- nacos服务发现 --><depen…

抖音数据抓取工具|短视频下载工具|视频内容提取软件

一、开发背景&#xff1a; 随着抖音平台的流行&#xff0c;越来越多的人希望能够下载抖音视频以进行个人收藏或分享。然而&#xff0c;目前在网上找到的抖音视频下载工具功能单一&#xff0c;操作繁琐&#xff0c;无法满足用户的需求。因此&#xff0c;我们决定开发一款功能强大…

unity Aaimation Rigging使用多个约束导致部分约束失去作用

在应用多个约束时&#xff0c;在Hierarchy的顺序可能会影响最终的效果。例如先应用了Aim Constraint&#xff0c;然后再应用Two Bone Constraint&#xff0c;可能会导致Two Bone Constraint受到Aim Constraint的影响而失效。因此&#xff0c;在使用多个约束时&#xff0c;应该仔…

代码随想录刷题笔记-Day23

1. 组合 77. 组合https://leetcode.cn/problems/combinations/ 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;n 4, k 2 输出&#xff1a; [[2,4],[3,4],[2,3],[1,2],…

R3F(React Three Fiber)经验篇

之前一直在做ThreeJS方向&#xff0c;整理了两篇R3F&#xff08;React Three Fiber&#xff09;的文档&#xff0c;这是经验篇&#xff0c;如果您的业务场景需要使用R3F&#xff0c;可以参考一下这个文档。下面是目录&#xff0c;按照需求自取。 基础篇 ⬇️ R3F&#xff08;…

buuctf_N1BOOK_粗心的小李

题目&#xff1a; 看完题目&#xff0c;git下载文件&#xff1f;然后将.git文件传到线上环境&#xff1f;&#xff08;which 会造成git泄露的安全威胁&#xff09;<这个背景抱歉我不太了解哈&#xff0c;可能后续有补充> 这里主要记录做法过程&#xff1a; 工具&#xf…