【机器学习】3万字总结常用的特征选择方法(含源代码示例)

一、分类

机器学习中特征选择的方法主要有以下几种:

  1. 过滤方法(Filter Methods):利用统计学方法,通过计算特征与目标变量之间的相关性或差异性,来评估特征的重要性,从而选择最佳特征子集。
  2. 包装方法(Wrapper Methods):使用机器学习算法来评估特征的重要性,从而选择最佳特征子集。这种方法的优点是可以捕获特征之间的相互作用,但是计算开销比较大。
  3. 嵌入方法(Embedded Methods):与Wrapper Methods类似,使用机器学习算法来评估特征的重要性,但是这种方法将特征选择和模型训练过程结合起来,因此可以在训练过程中同时选择最佳特征子集和训练最佳模型。
  4. PCA降维:通过线性变换将高维数据转化为低维数据,实现特征降维,这种方法可以去除高维数据中的冗余信息。
  5. L1正则化:在模型训练过程中,引入L1正则化惩罚项,可以使得一些特征的系数变为0,从而达到特征选择的效果。

需要注意的是,在选择特征的过程中,要避免过拟合问题,同时要保证选择的特征具有较好的泛化能力。因此,需要根据具体的应用场景和数据特点选择合适的特征选择方法。

二、具体分类

2.1 Filter Methods

2.1.1 Filter Methods的分类

Filter methods是机器学习中特征选择的一种方法,它们通过计算每个特征与目标变量之间的相关性来评估特征的重要性。这些方法不需要训练模型,而是在训练模型之前对特征进行筛选。

常用的过滤方法包括:

  1. 方差选择法(Variance Thresholding):根据特征的方差选择特征。方差较小的特征往往包含的信息较少,可以通过设置一个阈值选择方差大于阈值的特征。

  2. 相关系数法(Pearson Correlation):计算特征与目标变量之间的相关系数,选择与目标变量具有一定相关性的特征。通常,绝对值较大的相关系数代表特征与目标变量之间的相关性较强。

  3. 卡方检验(Chi-Square Test):计算每个特征与目标变量之间的卡方值,选择卡方值较大的特征。卡方检验适用于特征与目标变量都是离散变量的情况。

  4. 互信息法(Mutual Information):计算每个特征与目标变量之间的互信息量,选择互信息量较大的特征。互信息量反映了特征与目标变量之间的相关性,适用于特征和目标变量都可以是连续变量或离散变量的情况。

  5. L1 正则化(L1 Regularization):通过在目标函数中添加L1正则化项,促使模型选择更少的特征。L1正则化可以使一部分特征的系数变成0,从而实现特征选择的目的。

这些过滤方法通常很快,并且可以很容易地应用于大型数据集。但是,它们不能捕捉特征之间的相互作用,因此可能会忽略一些重要的特征。因此,过滤方法通常与其他特征选择方法结合使用,以提高模型性能。

2.1.2 Filter Methods的具体介绍

2.1.2.1 方差选择法

2.1.1.1.1 示例
1. 实验一

方差选择法是一种用于筛选数值型特征的特征选择方法,它通过计算特征的方差,去掉方差低于某个阈值的特征。

下面是一个使用方差选择法进行特征选择的示例:

import pandas as pd
import numpy as np
from sklearn.feature_selection import VarianceThreshold

# 生成一些随机数据
np.random.seed(42)
X = pd.DataFrame(np.random.rand(100, 5))
# 添加一列全为常数的特征
X[5] = 0.1

# 初始化方差选择器
selector = VarianceThreshold()

# 拟合选择器
selector.fit(X)

# 打印各个特征的方差
print(selector.variances_)

# 打印所选特征的下标
print(selector.get_support(indices=True))

运行上述代码会输出各个特征的方差和所选特征的下标。输出如下:

[0.08759921 0.08904356 0.0860504  0.08511813 0.09399481 0.        ]
[0 1 2 3 4]

可以看到,添加的全为常数的特征方差为0,因此被方差选择法所去除,只有前五列特征被保留。

2. 实验二

使用方差选择法从鸢尾花数据集中选择特征:

import pandas as pd
from sklearn.datasets import load_iris
from sklearn.feature_selection import VarianceThreshold

# 加载数据
iris = load_iris()
X = pd.DataFrame(iris.data, columns=iris.feature_names)

# 进行方差选择法特征选择
selector = VarianceThreshold(threshold=0.2)
X_new = selector.fit_transform(X)

# 输出选择的特征
print("原始特征数:", X.shape[1])
print("过滤后的特征数:", X_new.shape[1])
print("选择的特征:", X.columns[selector.get_support()])

输出结果为:

原始特征数: 4
过滤后的特征数: 3
选择的特征: Index(['sepal length (cm)', 'petal length (cm)', 'petal width (cm)'], dtype='object')
3. 实验三

使用方差选择法从乳腺癌数据集中选择特征:

import pandas as pd
from sklearn.datasets import load_breast_cancer
from sklearn.feature_selection import VarianceThreshold

# 加载数据
breast_cancer = load_breast_cancer()
X = pd.DataFrame(breast_cancer.data, columns=breast_cancer.feature_names)

# 进行方差选择法特征选择
selector = VarianceThreshold(threshold=0.01)
X_new = selector.fit_transform(X)

# 输出选择的特征
print("原始特征数:", X.shape[1])
print("过滤后的特征数:", X_new.shape[1])
print("选择的特征:", X.columns[selector.get_support()])

输出结果为:

原始特征数: 30
过滤后的特征数: 14
选择的特征: Index(['mean radius', 'mean texture', 'mean perimeter', 'mean area',
       'radius error', 'texture error', 'perimeter error', 'area error',
       'worst radius', 'worst texture', 'worst perimeter', 'worst area',
       'worst compactness', 'worst concavity'],
      dtype='object')
2.1.1.1.2 优缺点

方差选择法(Variance Threshold)是一种基于特征方差的特征选择方法,它通过计算特征的方差来评估特征的重要性,并且去除方差小于阈值的特征。

方差选择法的优点:

  1. 简单易懂,易于实现;
  2. 计算速度快;
  3. 适用于大规模特征数据集。

方差选择法的缺点:

  1. 只考虑了特征的单变量分布,而忽略了特征之间的相关性;
  2. 可能去除某些方差较小但是对目标变量有重要影响的特征。

适用场景:

  1. 特征是连续值;
  2. 特征与特征之间没有相关性;
  3. 数据集的特征数量很大,需要快速筛选出重要特征。

需要注意的是,方差选择法的阈值需要根据数据集的特征数量和特征方差的分布情况进行调整,一般需要进行实验来确定最优的阈值。此外,方差选择法只是特征选择的一种方法,不能保证选出的特征集是最优的。

2.1.2.2 相关系数法

2.1.1.2.1 示例
1. 实验一

下面是一个使用相关系数法选择特征的示例:

假设我们有一个包含四个特征的数据集,分别为x1, x2, x3, x4,以及一个目标变量y。我们可以通过计算每个特征与目标变量y之间的相关系数,来判断它们与目标变量的相关性大小,并选取相关性较强的特征作为模型的输入变量。

首先,我们可以生成一个随机数据集:

import numpy as np
import pandas as pd

np.random.seed(0)
data = pd.DataFrame(np.random.rand(100, 4), columns=['x1', 'x2', 'x3', 'x4'])
data['y'] = 2 * data['x1'] + 3 * data['x2'] + 4 * data['x3'] + 5 * data['x4'] + np.random.rand(100)
print(data.head())

输出结果为:

         x1        x2        x3        x4          y
0  0.548814  0.715189  0.602763  0.544883   8.779924
1  0.423655  0.645894  0.437587  0.891773   9.923497
2  0.963663  0.383442  0.791725  0.528895   8.988640
3  0.568045  0.925597  0.071036  0.087129   5.577971
4  0.020218  0.832620  0.778157  0.870012  10.870473

然后,我们可以计算每个特征与目标变量y之间的相关系数:

corr_matrix = data.corr()
corr_with_y = corr_matrix['y'].drop('y')
print(corr_with_y)

输出为:

x1    0.154676
x2    0.522695
x3    0.459629
x4    0.688350
Name: y, dtype: float64

根据相关系数的大小,我们可以选择相关性较强的特征作为模型的输入变量。在这个示例中,我们可以选择x2, x3, x4作为输入变量,因为它们与目标变量y之间的相关系数最大。

2. 实验二

以下是使用相关系数法选择特征的示例代码:(鸢尾花数据集上)

import pandas as pd
from sklearn.datasets import load_iris

# 加载数据集
iris = load_iris()
data = pd.DataFrame(data=iris.data, columns=iris.feature_names)
target = iris.target

# 计算特征之间的相关系数矩阵
corr_matrix = data.corr().abs()

# 选择相关系数大于0.5的特征
high_corr_features = set()
for i in range(len(corr_matrix.columns)):
    for j in range(i):
        if corr_matrix.iloc[i, j] > 0.5:
            colname_i = corr_matrix.columns[i]
            colname_j = corr_matrix.columns[j]
            high_corr_features.add(colname_i)
            high_corr_features.add(colname_j)

# 打印选择的特征
print(high_corr_features)

输出结果为:

{
    
    'sepal length (cm)', 'petal width (cm)', 'petal length (cm)'}
3. 实验三

下面是在乳腺癌数据集上使用相关系数法选择特征的示例:

import pandas as pd
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.feature_selection import SelectKBest, f_classif

# 加载数据
data = load_breast_cancer()
X = pd.DataFrame(data.data, columns=data.feature_names)
y = pd.Series(data.target)

# 使用相关系数法选择特征
selector = SelectKBest(f_classif, k=5)
selector.fit(X, y)

# 输出被选中的特征
selected_features = X.columns[selector.get_support()]
print("被选中的特征:", list(selected_features))

输出结果为:

被选中的特征: ['mean perimeter', 'mean concave points', 'worst radius', 'worst perimeter', 'worst concave points']

这里使用了 sklearn 中的 SelectKBest 类,使用方差分析(ANOVA)方法计算每个特征和目标变量之间的F值和p值,最终选择与目标变量最相关的 k k k 个特征,这里选择了 k = 5 k=5 k=5

2.1.1.2.2 优缺点

相关系数法通过评估特征与目标变量之间的相关性来选择特征。以下是相关系数法选择特征的优缺点和适用场景:

优点:

  1. 相关系数法在选择特征时考虑了特征与目标变量之间的相关性,因此选择的特征更加符合实际情况。
  2. 相关系数法选择特征的过程比较简单,易于实现和理解。

缺点:

  1. 相关系数法只能发现线性相关性,无法发现非线性相关性。
  2. 相关系数法只能选择单个特征,无法选择特征的组合。

适用场景:

  1. 相关系数法适用于特征与目标变量之间存在较强的线性相关性的情况。
  2. 相关系数法适用于特征较少的数据集,对于特征较多的数据集,相关系数法可能会选择出过多的特征,导致过拟合问题。

2.1.2.3 卡方检验

2.1.1.3.1 示例
1. 实验一

卡方检验(Chi-Squared Test)是一种常用的特征选择方法,可以用于选择分类问题中的特征。它基于卡方统计量(Chi-Squared Statistic),通过计算特征与标签之间的卡方值来判断特征对标签的相关性。卡方值越大,表示特征与标签之间的相关性越强,因此应该选择这个特征。

具体地,卡方检验的流程如下:

  1. 对数据进行离散化处理,将连续型数据转化为离散型数据。
  2. 将离散化后的数据按照特征和标签进行交叉统计,得到特征与标签之间的频数矩阵。
  3. 根据频数矩阵计算卡方值。
  4. 对所有特征进行卡方检验,选择卡方值较大的特征。

下面是一个使用卡方检验进行特征选择的示例:

import numpy as np
import pandas as pd
from sklearn.datasets import load_breast_cancer
from sklearn.feature_selection import SelectKBest, chi2

# 加载乳腺癌数据集
data = load_breast_cancer()
X = data.data
y = data.target

# 将数据离散化
X_discrete = np.apply_along_axis(pd.cut, axis=0, arr=X, bins=5, labels=False)

# 计算卡方值并选择最重要的前5个特征
selector = SelectKBest(score_func=chi2, k=5)
selector.fit(X_discrete, y)

# 获取选择的特征
selected_features = data.feature_names[selector.get_support()]

print(selected_features)

输出结果为:

['mean area' 'mean concavity' 'mean concave points' 'worst area'
 'worst concave points']
2. 实验二
from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2

# 加载数据集
iris = load_iris()
X, y = iris.data, iris.target

# 将特征离散化
X[X <= 5.0] = 0
X[(X > 5.0) & (X <= 6.0)] = 1
X[(X > 6.0) & (X <= 7.0)] = 2
X[(X > 7.0) & (X <= 8.0)] = 3
X[(X > 8.0) & (X <= 10.0)] = 4

# 使用卡方检验选择特征
selector = SelectKBest(chi2, k=2)
X_new = selector.fit_transform(X, y)

# 输出选择的特征
print(selector.get_support())

输出结果为:

[ True False  True False]
3. 实验三
import numpy as np
import pandas as pd
from sklearn.datasets import load_breast_cancer
from sklearn.feature_selection import chi2, SelectKBest

# 加载乳腺癌数据集
data = load_breast_cancer()

# 将数据集转化为pandas DataFrame格式
df = pd.DataFrame(data.data, columns=data.feature_names)
df['target'] = pd.Series(data.target)

# 将特征和目标变量分离
X = df.drop('target', axis=1)
y = df['target']

# 使用卡方检验选择最具有预测能力的10个特征
selector = SelectKBest(chi2, k=10)
selector.fit(X, y)

# 打印卡方值和P值
scores = selector.scores_
pvalues = selector.pvalues_
print('Feature scores:', scores)
print('Feature p-values:', pvalues)

# 打印选择的特征
selected_features = X.columns[selector.get_support()]
print('Selected features:', selected_features)

输出结果为:

Feature scores: [2.66104917e+02 9.38975081e+01 2.01110286e+03 5.39916559e+04
 1.49899264e-01 5.40307549e+00 1.97123536e+01 1.05440354e+01
 2.57379775e-01 7.43065536e-05 3.46752472e+01 9.79353970e-03
 2.50571896e+02 8.75850471e+03 3.26620664e-03 6.13785332e-01
 1.04471761e+00 3.05231563e-01 8.03633831e-05 6.37136566e-03
 4.91689157e+02 1.74449400e+02 3.66503542e+03 1.12598432e+05
 3.97365694e-01 1.93149220e+01 3.95169151e+01 1.34854195e+01
 1.29886140e+00 2.31522407e-01]
Feature p-values: [8.01397628e-060 3.32292194e-022 0.00000000e+000 0.00000000e+000
 6.98631644e-001 2.01012999e-002 9.00175712e-006 1.16563638e-003
 6.11926026e-001 9.93122221e-001 3.89553429e-009 9.21168192e-001
 1.94877489e-056 0.00000000e+000 9.54425121e-001 4.33366115e-001
 3.06726812e-001 5.80621137e-001 9.92847410e-001 9.36379753e-001
 6.11324751e-109 7.89668299e-040 0.00000000e+000 0.00000000e+000
 5.28452867e-001 1.10836762e-005 3.25230064e-010 2.40424384e-004
 2.54421307e-001 6.30397277e-001]
Selected features: Index(['mean radius', 'mean texture', 'mean perimeter', 'mean area',
       'perimeter error', 'area error', 'worst radius', 'worst texture',
       'worst perimeter', 'worst area'],
      dtype='object')
2.1.1.3.2 优缺点

卡方检验选择特征的优缺点如下:

优点:

  • 卡方检验是一种统计方法,可以进行严格的数学证明,具有较高的科学性和可信度。
  • 卡方检验可以考虑特征之间的相互作用,对于具有多个特征的数据集,比较适用。
  • 卡方检验的计算量较小,运行速度快。

缺点:

  • 卡方检验只能处理离散型变量,不能处理连续型变量。
  • 卡方检验的结果可能受到样本分布的影响,因此需要在样本充分的情况下使用。
  • 卡方检验只能检验特征之间是否存在相关性,不能确定其具体的相关程度。

适用场景:

卡方检验选择特征适用于分类问题,特别是在特征数较多的情况下,可以快速筛选出与目标变量相关性较高的特征,加快模型训练的速度和提高预测性能。但是,卡方检验本身也存在一些限制,比如对于连续型变量的处理比较困难,对于特征之间存在多重共线性的情况也可能出现误判,因此在实际应用中需要结合具体问题和数据特征进行综合考虑。

2.1.2.4 互信息

2.1.1.4.1 示例
1. 实验一

互信息(mutual information)是一种评估两个变量之间关联性的方法,可以用于特征选择。它可以衡量两个变量之间的信息交流程度,因此可以用来评估特征和目标之间的关系。

互信息度量的是特征与目标变量之间的相关性,也就是特征和目标变量之间的信息量。具体而言,互信息衡量的是知道一个特征值后,对目标变量产生的信息增益,即该特征能够提供多少关于目标变量的信息。

在特征选择中,可以使用互信息来评估每个特征与目标变量之间的关系,然后选择相关性较高的特征。通常采用以下步骤:

  1. 计算每个特征与目标变量之间的互信息。
  2. 对特征按照互信息大小进行排序。
  3. 选择排名靠前的特征作为输入特征。

在Python中,可以使用sklearn.feature_selection库中的mutual_info_classif函数来计算特征与目标变量之间的互信息。例如,可以使用以下代码对特征进行互信息选取:

from sklearn.feature_selection import mutual_info_classif

# X为输入特征,y为目标变量
scores = mutual_info_classif(X, y)

该函数返回每个特征与目标变量之间的互信息得分,得分越高表示特征与目标变量之间的相关性越强。根据得分大小可以选择相关性较高的特征进行特征选择。

import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.feature_selection import mutual_info_classif, SelectKBest

# 加载数据集
iris = load_iris()
X, y = iris.data, iris.target

# 计算每个特征与目标变量之间的互信息
scores = mutual_info_classif(X, y)

# 根据得分进行特征选择,选择得分排名前2的特征
k_best = SelectKBest(mutual_info_classif, k=2).fit(X, y)
X_new = k_best.transform(X)

# 输出选择的特征
print("Selected features: ", np.array(iris.feature_names)[k_best.get_support()])

输出结果为:

Selected features:  ['petal length (cm)' 'petal width (cm)']
2. 实验二
import numpy as np
import pandas as pd
from sklearn.datasets import load_breast_cancer
from sklearn.feature_selection import mutual_info_classif, SelectKBest

# 加载数据集
breast_cancer = load_breast_cancer()
X, y = breast_cancer.data, breast_cancer.target

# 计算每个特征与目标变量之间的互信息
scores = mutual_info_classif(X, y)

# 根据得分进行特征选择,选择得分排名前5的特征
k_best = SelectKBest(mutual_info_classif, k=5).fit(X, y)
X_new = k_best.transform(X)

# 输出选择的特征
print("Selected features: ", breast_cancer.feature_names[k_best.get_support()])

输出结果:

Selected features:  ['mean concave points' 'worst radius' 'worst perimeter' 'worst area'
 'worst concave points']
2.1.1.4.2 优缺点

互信息作为一种特征选择的方法,具有以下优点和缺点:

优点:

  • 相对于其他特征选择方法,互信息能够捕捉到更加复杂的特征之间的关系,因为它能够度量非线性关系和高阶关系。
  • 互信息是非参数方法,不需要假设变量之间的分布情况,因此在数据分布不明确或非常复杂的情况下也能有效工作。
  • 互信息的计算速度较快,适用于高维数据集。

缺点:

  • 互信息可能会捕捉到噪声特征,导致选择不可靠的特征。
  • 互信息不能处理数据集中存在的冗余特征,可能会选择不必要的特征,导致模型过拟合。
  • 互信息的计算对于大型数据集可能会受到计算机性能的限制。

适用场景:

  • 互信息特征选择适用于高维数据集,能够有效地减少特征的维度,提高模型的效率和准确率。
  • 互信息特征选择适用于需要考虑特征之间复杂关系的问题,例如生物信息学和自然语言处理领域的数据分析。
  • 对于数据分布复杂、特征之间关系不明显的数据集,互信息可以作为一种有效的特征选择方法。

2.1.2.5 L1正则化

2.1.1.5.1 示例
1. 实验一

以下是一个使用L1正则化进行特征选择的示例,使用的是sklearn库中的Lasso模型:

import numpy as np
from sklearn.datasets import make_regression
from sklearn.linear_model import Lasso

# 生成模拟数据集
X, y = make_regression(n_samples=100, n_features=10, n_informative=5, noise=0.1, random_state=42)

# 使用Lasso模型进行特征选择
lasso = Lasso(alpha=0.1)
lasso.fit(X, y)

# 输出选择的特征及其系数
selected_features = np.where(lasso.coef_ != 0)[0]
selected_coefs = lasso.coef_[selected_features]
print("Selected features: ", selected_features)
print("Selected coefficients: ", selected_coefs)

这段代码会生成一个包含100个样本和10个特征的模拟数据集,并使用Lasso模型进行特征选择。在这个例子中,我们将惩罚参数 α \alpha α设为0.1,根据L1正则化的特性,可以发现一些特征的系数被缩减为0,这些特征会被认为是不重要的,因此可以选择将它们删除。最后,我们输出了选择的特征及其系数。

输出结果为:

Selected features:  [0 3 5 7 8]
Selected coefficients:  [16.61667804 63.57170498 70.5360479  10.34875749  3.08067278]
2. 实验二
import numpy as np
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression

# 加载数据集
iris = load_iris()
X, y = iris.data, iris.target

# 创建模型
clf = LogisticRegression(penalty='l1', solver='liblinear', multi_class='ovr')

# 拟合模型
clf.fit(X, y)

# 输出选择的特征
print("Selected features: ", iris.feature_names[np.where(clf.coef_!=0)[1]])

解释一下代码:

  • 加载鸢尾花数据集
  • 创建L1正则化的逻辑回归模型,使用liblinear求解器
  • 拟合模型
  • 输出选择的特征,使用np.where()函数找到系数不为0的特征对应的索引,然后根据索引找到特征名

值得注意的是,L1正则化会导致某些特征的系数被压缩到0,因此只有系数不为0的特征才是被选中的特征。

代码报错:

在这里插入图片描述
修改后的代码:

# 使用 L1 正则化进行特征选择
from sklearn.linear_model import LogisticRegression

lr = LogisticRegression(penalty='l1', solver='liblinear', multi_class='auto')
lr.fit(X, y)

# 打印选择的特征
selected_features = np.array(iris.feature_names)[lr.coef_[0]!=0].tolist()
print("Selected features: ", selected_features)

输出结果为:

Selected features:  ['sepal width (cm)', 'petal length (cm)']
3. 实验三

以下是在乳腺癌数据集上使用L1正则化进行特征选择的示例代码:

from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegressionCV

# 加载数据集
data = load_breast_cancer()
X, y = data.data, data.target

# 构建L1正则化逻辑回归模型
clf = LogisticRegressionCV(Cs=10, penalty='l1', solver='liblinear', cv=10)

# 训练模型并输出选择的特征
clf.fit(X, y)
selected_features = data.feature_names[clf.coef_[0] != 0]
print("Selected features: ", selected_features)

输出结果:

Selected features:  ['mean radius' 'mean texture' 'mean perimeter' 'mean area'
 'mean smoothness' 'mean compactness' 'mean concavity'
 'mean concave points' 'mean symmetry' 'mean fractal dimension'
 'radius error' 'texture error' 'perimeter error' 'area error'
 'compactness error' 'concavity error' 'concave points error'
 'symmetry error' 'fractal dimension error' 'worst radius' 'worst texture'
 'worst perimeter' 'worst area' 'worst smoothness' 'worst compactness'
 'worst concavity' 'worst concave points' 'worst symmetry'
 'worst fractal dimension']
2.1.1.5.2 优缺点

L1正则化选取特征的优缺点和适用场景:

优点:

  • 可以进行特征选择,避免过拟合和降低模型复杂度
  • 可以降低模型的维度,加快训练速度
  • 适用于具有少量重要特征的数据集,可用于特征筛选

缺点:

  • 无法处理特征之间存在复杂关系的情况
  • 对噪声和冗余特征敏感,需要对数据进行预处理
  • 选择的特征可能不具有代表性,需要根据具体情况进行调整

适用场景:

  • 特征数目较多,需要进行特征选择的情况
  • 特征之间存在较强的相关性或冗余的情况
  • 数据集较小或特征比较稀疏的情况下,L1正则化可以帮助减小过拟合的风险

2.2 Wrapper Methods

2.2.1 Wrapper Methods分类

Wrapper methods(包装方法)是一种特征选择方法,它通过在特征子集上运行一个机器学习算法来评估该子集的性能,然后选择最好的子集作为最终特征集。

  • 与过滤方法和嵌入方法相比,包装方法是一种更加贪婪的方法,因为它直接在选择最终特征集时使用模型的性能作为目标函数。

Wrapper方法的基本思想是:选择一个特征子集,利用分类器训练,根据分类器的性能(如准确率)来评价这个特征子集的好坏,最终选出最好的特征子集。其中分类器可以是任何机器学习算法,如决策树、支持向量机、逻辑回归等。

  • 与嵌入方法相比,Wrapper方法通常能够提供更好的特征子集,因为Wrapper方法可以考虑特征之间的交互作用和相互依赖性,但是Wrapper方法也更加耗时,因为它需要在不同的特征子集上运行机器学习算法来评估性能。

Wrapper Methods主要有三种类别:

  1. Forward Selection(前向选择):从一个空的特征集开始,逐渐添加特征,直到达到预先定义的停止条件,例如达到特定数量的特征或改善模型性能的阈值。

  2. Backward Elimination(后向消元):从包含所有特征的特征集开始,逐渐删除特征,直到达到预先定义的停止条件。

  3. Recursive Feature Elimination(递归特征消除):基于模型的系数或特征的重要性来逐渐删除特征,直到达到预先定义的停止条件。在每次迭代中,模型都会重新拟合并重新评估特征的重要性。

2.2.2 Wrapper Methods的具体介绍

2.2.2.1 Forward Selection(前向选择)

2.2.2.1.1 示例

Forward Selection包含以下步骤:

  1. 从单个特征开始,分别对每个特征计算性能评分(如准确度、AUC、F1等),选择性能评分最高的特征作为初始特征。

  2. 从选择的初始特征开始,逐个加入其他特征,计算每个特征的性能评分,选择性能评分最高的特征加入已选择的特征集合中。

  3. 重复步骤2,直到达到预定的特征数目或无法增加性能评分为止。

Forward Selection是一种贪心算法,它每次选择当前最佳的特征。然而,它可能会陷入局部最优解中,因为某些特征可能在添加到特征集合中时并不显著,但它们在与其他特征组合时可能会产生更好的性能。

由于Forward Selection需要对每个特征进行多次训练,因此它在特征数较少的情况下适用。同时,它可能会受到特征间相互作用的影响。

from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from mlxtend.feature_selection import SequentialFeatureSelector as SFS

# 加载数据集
iris = load_iris()
X, y = iris.data, iris.target

# 定义模型
lr = LogisticRegression()

# 定义前向选择算法,选择3个特征
sfs = SFS(lr, k_features=3, forward=True, scoring='accuracy', cv=5)

# 运行前向选择算法
sfs.fit(X, y)

# 输出选择的特征
print("Selected features: ", sfs.k_feature_names_)

输出结果为:

Selected features:  ('0', '2', '3')

在这个示例中,我们使用了 SequentialFeatureSelector(SFS)库中的 SFS 类,来实现前向选择算法。首先我们定义了一个 LogisticRegression 的分类器,然后我们定义了 SFS 类来运行前向选择算法。在这个示例中,我们选择了3个特征作为输出。在运行 fit 函数后,我们可以通过 k_feature_names_ 属性来获取选择的特征名称。

2.2.2.1.2 优缺点和适用场景

Forward Selection(前向选择)的优点是,它能够找到一个相对较小的特征子集,该子集对于特定问题的解释和泛化能力都很强,因为它选择了最相关的特征。

然而,它的缺点是在大量特征的情况下,前向选择可能需要很长的时间才能找到最优特征子集,并且由于它是一种贪心算法,它可能会停留在局部最优解,而不是全局最优解。此外,如果特征之间存在相关性,前向选择可能会选择具有相似信息的特征,而忽略其他相关特征。

因此,Forward Selection适用于小型或中型数据集,特征之间的相关性较小或已知,并且算法运行时间较少的情况下,例如在基因组学或蛋白质组学领域的特征选择中。

2.2.2.2 Backward Elimination(后向消元)

2.2.2.2.1 示例

Backward Elimination是Wrapper Methods的一种,和Forward Selection相反,它是从所有特征开始,一步步地去除不重要的特征,直到剩下最重要的特征集合。

其步骤如下:

  1. 建立一个包含所有特征的模型,并进行拟合。

  2. 通过某种指标(比如p值)判断哪些特征的影响最小,将其删除。

  3. 重新建立模型并进行拟合。

  4. 重复步骤2和3,直到达到指定的特征数量或其他终止条件。

一般来说,Backward Elimination的终止条件包括:达到指定的特征数量、特征重要性排序达到某个阈值、特征间相关性超过某个阈值等。

以下是Backward Elimination的一般示例:

假设我们有一个数据集,包含20个特征和1个目标变量。我们可以使用Backward Elimination来选择最佳的特征子集。

首先,我们可以使用某种算法(如逻辑回归)来训练模型并计算所有特征的重要性得分。然后,我们可以按重要性得分对特征进行排序,按降序排列。

接下来,我们从包含所有特征的完整模型开始,逐步删除得分最低的特征,直到我们达到预设的目标。在每一步中,我们需要重新训练模型并计算性能指标(如准确率、精度、召回率等),以确定哪些特征应该被删除。当我们达到目标时,我们就可以得到最佳的特征子集。

假设我们希望选择5个最重要的特征。以下是一个示例代码:

import numpy as np
import pandas as pd
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# 加载数据集
data = load_breast_cancer()
X, y = data.data, data.target

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 训练逻辑回归模型
model = LogisticRegression()
model.fit(X_train, y_train)

# 计算所有特征的重要性得分
scores = np.abs(model.coef_[0])

# 按重要性得分排序
sorted_idx = np.argsort(scores)[::-1]

# 选择前5个特征进行后向消元
num_features = 5
for i in range(X_train.shape[1], num_features, -1):
    # 选择前i个特征
    idx = sorted_idx[:i]
    X_train_subset = X_train[:, idx]
    X_test_subset = X_test[:, idx]
    
    # 训练模型并计算准确率
    model.fit(X_train_subset, y_train)
    y_pred = model.predict(X_test_subset)
    acc = accuracy_score(y_test, y_pred)
    
    print(f"Selected features: {
      
      data.feature_names[idx]}")
    print(f"Accuracy: {
      
      acc:.4f}")
    
    # 找到最低得分的特征并删除
    if i > num_features:
        worst_idx = np.argmin(scores[idx])
        sorted_idx = np.delete(sorted_idx, np.where(sorted_idx == idx[worst_idx]))

# 最终选择的特征子集
final_idx = sorted_idx[:num_features]
final_features = data.feature_names[final_idx]
print(f"Final selected features: {
      
      final_features}")

我们的输出结果是:

Selected features: ['worst radius' 'mean radius' 'worst concavity' 'worst compactness'
 'texture error' 'worst texture' 'mean concavity' 'mean texture'
 'worst concave points' 'worst symmetry' 'mean compactness'
 'mean concave points' 'worst perimeter' 'worst smoothness' 'area error'
 'mean symmetry' 'worst fractal dimension' 'concavity error'
 'perimeter error' 'mean smoothness']
Accuracy: 0.9561
Selected features: ['worst radius' 'mean radius' 'worst concavity' 'worst compactness'
 'texture error' 'worst texture' 'mean concavity' 'mean texture'
 'worst concave points' 'worst symmetry' 'mean compactness'
 'mean concave points' 'worst perimeter' 'worst smoothness' 'area error'
 'mean symmetry' 'worst fractal dimension' 'concavity error'
 'perimeter error']
Accuracy: 0.9561
Selected features: ['worst radius' 'mean radius' 'worst concavity' 'worst compactness'
 'texture error' 'worst texture' 'mean concavity' 'mean texture'
 'worst concave points' 'worst symmetry' 'mean compactness'
 'mean concave points' 'worst perimeter' 'worst smoothness' 'area error'
 'mean symmetry' 'worst fractal dimension' 'concavity error']
Accuracy: 0.9561
Selected features: ['worst radius' 'mean radius' 'worst concavity' 'worst compactness'
 'texture error' 'worst texture' 'mean concavity' 'mean texture'
 'worst concave points' 'worst symmetry' 'mean compactness'
 'mean concave points' 'worst perimeter' 'worst smoothness' 'area error'
 'mean symmetry' 'worst fractal dimension']
Accuracy: 0.9737
Selected features: ['worst radius' 'mean radius' 'worst concavity' 'worst compactness'
 'texture error' 'worst texture' 'mean concavity' 'mean texture'
 'worst concave points' 'worst symmetry' 'mean compactness'
 'mean concave points' 'worst perimeter' 'worst smoothness' 'area error'
 'mean symmetry']
Accuracy: 0.9386
Selected features: ['worst radius' 'mean radius' 'worst concavity' 'worst compactness'
 'texture error' 'worst texture' 'mean concavity' 'mean texture'
 'worst concave points' 'worst symmetry' 'mean compactness'
 'mean concave points' 'worst perimeter' 'worst smoothness' 'area error']
Accuracy: 0.9649
Selected features: ['worst radius' 'mean radius' 'worst concavity' 'worst compactness'
 'texture error' 'worst texture' 'mean concavity' 'mean texture'
 'worst concave points' 'worst symmetry' 'mean compactness'
 'mean concave points' 'worst perimeter' 'worst smoothness']
Accuracy: 0.9561
Selected features: ['worst radius' 'mean radius' 'worst concavity' 'worst compactness'
 'texture error' 'worst texture' 'mean concavity' 'mean texture'
 'worst concave points' 'worst symmetry' 'mean compactness'
 'mean concave points' 'worst perimeter']
Accuracy: 0.9649
Selected features: ['worst radius' 'mean radius' 'worst concavity' 'worst compactness'
 'texture error' 'worst texture' 'mean concavity' 'mean texture'
 'worst concave points' 'worst symmetry' 'mean compactness'
 'mean concave points']
Accuracy: 0.9561
Selected features: ['worst radius' 'mean radius' 'worst concavity' 'worst compactness'
 'texture error' 'worst texture' 'mean concavity' 'mean texture'
 'worst concave points' 'worst symmetry' 'mean compactness']
Accuracy: 0.9561
Selected features: ['worst radius' 'mean radius' 'worst concavity' 'worst compactness'
 'texture error' 'worst texture' 'mean concavity' 'mean texture'
 'worst concave points' 'worst symmetry']
Accuracy: 0.9561
Selected features: ['worst radius' 'mean radius' 'worst concavity' 'worst compactness'
 'texture error' 'worst texture' 'mean concavity' 'mean texture'
 'worst concave points']
Accuracy: 0.9561
Selected features: ['worst radius' 'mean radius' 'worst concavity' 'worst compactness'
 'texture error' 'worst texture' 'mean concavity' 'mean texture']
Accuracy: 0.9561
Selected features: ['worst radius' 'mean radius' 'worst concavity' 'worst compactness'
 'texture error' 'worst texture' 'mean concavity']
Accuracy: 0.9561
Selected features: ['worst radius' 'mean radius' 'worst concavity' 'worst compactness'
 'texture error' 'worst texture']
Accuracy: 0.9561
Final selected features: ['worst radius' 'mean radius' 'worst concavity' 'worst compactness'
 'texture error']

这个例子使用乳腺癌数据集来选择5个最重要的特征。我们首先训练一个逻辑回归模型并计算每个特征的重要性得分。

2.2.2.2.2 优缺点和适用场景

Backward Elimination的优点:

  • 可以避免Forward Selection在选择特征时可能过度拟合的问题。
  • 由于一开始包含所有特征,因此初始模型具有较高的准确性和鲁棒性。
  • 可以用来选择特征数量最少的特征集,这对于需要在有限的特征维度中进行建模的问题特别有用。

Backward Elimination的缺点:

  • 每个步骤都需要重新训练模型,因此时间开销较大。
  • 在初始的特征集合中,一些不相关的特征可能会对模型性能产生负面影响,因此需要在初始特征集合中进行适当的特征选择。

适用场景:

  • 当样本数量不太多、特征维度不太高时,Backward Elimination是一个有效的特征选择方法。
  • 对于需要建立简单可解释的模型,且特征维度较少的问题,Backward Elimination也是一个好的选择。

2.2.2.3 Recursive Feature Elimination(递归特征消除)

2.2.2.3.1 示例

Recursive Feature Elimination (RFE)是一种Wrapper Method,通过递归地训练模型并反复选择要保留的特征来选择特征。具体来说,它反复进行以下步骤:

  1. 使用原始特征集训练模型;
  2. 通过某种特征重要性评估方法(例如,系数大小或决策树中的特征重要性)确定每个特征的重要性得分;
  3. 剔除得分最低的特征;
  4. 重复步骤1-3,直到达到预设的要保留特征数量。

递归特征消除有两种方法:自下而上和自上而下。自下而上的方法从单个特征开始,逐渐向上增加要选择的特征数量。自上而下的方法从原始特征集开始,逐渐减少要选择的特征数量。

递归特征消除的一般示例如下:

from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_iris

# 加载数据集
iris = load_iris()
X, y = iris.data, iris.target

# 初始化逻辑回归模型
model = LogisticRegression()

# 使用递归特征消除选择2个最佳特征
rfe = RFE(model, n_features_to_select=2)
X_new = rfe.fit_transform(X, y)

# 输出选择的特征
print("Selected features: ", np.array(iris.feature_names)[rfe.get_support()])

输出结果为:

Selected features:  ['petal length (cm)' 'petal width (cm)']

其中,LogisticRegression是用于分类的线性模型,n_features_to_select参数指定要选择的特征数量。RFE通过调用fit_transform()方法来执行特征选择,返回新的特征矩阵。get_support()方法用于获取选择的特征的布尔掩码。

RFE的优点是它可以通过使用嵌入式方法来进行特征选择,并且与其他Wrapper Methods相比,它具有较高的稳健性。然而,它的缺点是它相对于其他方法的计算成本较高。此外,如果模型本身的性能受到数据质量的限制,则递归特征消除可能无法获得很好的结果。因此,适用于递归特征消除的数据集应该具有相对较高的质量和数量。

自下而上的示例:

下面是一个自下而上的示例,使用递归特征消除算法对乳腺癌数据集中的特征进行选择:

import numpy as np
import pandas as pd
from sklearn.datasets import load_breast_cancer
from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression

# 加载数据集
breast_cancer = load_breast_cancer()
X, y = breast_cancer.data, breast_cancer.target

# 使用递归特征消除算法进行特征选择
lr = LogisticRegression(solver='liblinear')
rfe = RFE(lr, n_features_to_select=5)
X_new = rfe.fit_transform(X, y)

# 输出选择的特征
print("Selected features: ", breast_cancer.feature_names[rfe.get_support()]) 

输出结果为:

Selected features:  ['mean radius' 'mean concavity' 'worst radius' 'worst concavity'
 'worst concave points']

自上而下的示例:

下面是一个自上而下的递归特征消除的示例,使用的数据集是Sklearn自带的手写数字数据集:

import numpy as np
import pandas as pd
from sklearn.datasets import load_digits
from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression

# 加载数据集
digits = load_digits()
X, y = digits.data, digits.target

# 使用逻辑回归作为基模型,进行特征选择
model = LogisticRegression(solver='liblinear')
rfe = RFE(estimator=model, n_features_to_select=32, step=1)
X_new = rfe.fit_transform(X, y)

# 输出选择的特征
print("Selected features: ", rfe.support_)

输出结果为:

Selected features:  [False  True  True  True  True  True  True False  True  True False False
  True False  True False False False  True False  True  True  True  True
 False False  True  True  True False  True False False  True False False
  True False  True False False  True  True  True  True  True False False
 False False False False  True  True  True  True False False False False
 False False  True False]
2.2.2.3.2 优缺点及适用场景

递归特征消除(Recursive Feature Elimination,简称RFE)的优缺点如下:

优点:

  • 相较于前向选择和后向消元,递归特征消除更为精确,能够剔除无用的特征,提高模型的预测性能。
  • RFE能够自动进行特征选择,并能够根据特征重要性进行排序。
  • RFE可适用于各种类型的数据,包括数值型和类别型数据。

缺点:

  • RFE计算复杂度较高,时间和计算资源成本较高。
  • RFE的性能可能会受到数据集大小的影响。对于较大的数据集,RFE的效果可能不如其他的特征选择方法。

适用场景:

  • RFE适用于特征数目较多,且需要高精度预测的数据集,如图像识别、文本分类、基因表达等领域。
  • RFE适用于各种类型的机器学习算法,如支持向量机、逻辑回归、决策树等。

2.3 Embedded Methods

2.3.1 Embedded Methods的分类

Embedded Methods指的是将特征选择嵌入到模型训练过程中,即在模型的训练过程中同时完成特征选择和模型训练。这种方法可以使用不同的算法来进行特征选择,例如Lasso回归、Ridge回归、Elastic Net等,这些算法可以通过正则化来惩罚模型中的不重要特征,进而达到特征选择的目的。

在使用Embedded Methods进行特征选择时,一般将整个数据集划分为训练集和测试集。在训练集上训练模型并选择特征,在测试集上测试模型的性能。如果模型在测试集上的表现良好,则可以使用这些特征来构建最终模型。

常见的Embedded Methods包括:

  • Lasso回归(L1正则化)
  • Ridge回归(L2正则化)
  • Elastic Net(L1和L2正则化的组合)

这些方法都是通过正则化来惩罚模型中的不重要特征,从而达到特征选择的目的。其中,Lasso回归可以将一些系数变为0,因此可以实现特征选择;而Ridge回归和Elastic Net虽然不能将系数变为0,但是它们可以通过减小系数的大小来实现特征选择。

除此之外,还可以通过树模型来选取特征。

树模型是一种常用的Embedded Methods方法,可以通过建立决策树、随机森林等模型来评估特征的重要性并进行特征选择。这些模型中,特征的重要性是通过评估它们在构建树时对模型的影响来衡量的。

在树模型中,特征的重要性可以通过以下两种方法计算:

  1. 基于Gini不纯度的特征重要性

对于分类问题,树模型常常使用Gini不纯度来度量特征的重要性。每个节点的Gini不纯度可以通过以下公式计算:

在这里插入图片描述
其中, c c c是类别的数量, p i , j p_{i,j} pi,j是节点 i i i中属于类别 j j j的样本所占比例。假设节点 i i i被分为两个子节点 i L i_L iL i R i_R iR,则可以计算出它们的加权平均Gini不纯度:

在这里插入图片描述
其中, n i n_i ni是节点 i i i中的样本数量。

基于Gini不纯度的特征重要性可以通过计算每个特征对于整个模型Gini不纯度的减少量来衡量。这个量可以通过以下公式计算:

在这里插入图片描述
其中, G parent G_{\text{parent}} Gparent是父节点的Gini不纯度, G left G_{\text{left}} Gleft G right G_{\text{right}} Gright是左右子节点的Gini不纯度。特征 f f f的重要性可以通过计算所有节点上 Δ G f \Delta G_f ΔGf的平均值来得到。

  1. 基于信息增益的特征重要性

对于分类问题,树模型还可以使用信息增益来度量特征的重要性。每个节点的信息熵可以通过以下公式计算:

在这里插入图片描述
其中, p i , j p_{i,j} pi,j是节点 i i i中属于类别 j j j的样本所占比例。假设节点 i i i被分为两个子节点 i L i_L iL i R i_R iR,则可以计算出它们的加权平均信息熵:

在这里插入图片描述
其中, n i n_i ni是节点 i i i中的样本数量。

以决策树为例,可以通过特征的重要性指标(如Gini重要性、信息增益等)来评估每个特征对模型的贡献程度。然后,我们可以根据这些指标对特征进行排序,选取得分最高的前k个特征。

在随机森林模型中,可以使用每个特征对于所有树的平均袋外精度(OOB Score)或平均袋外Gini重要性来评估特征的重要性。然后,我们可以根据这些指标对特征进行排序,选取得分最高的前k个特征。

在梯度提升树(Gradient Boosting Tree)模型中,可以使用每个特征对于所有树的平均损失或平均Graident(梯度)来评估特征的重要性。然后,我们可以根据这些指标对特征进行排序,选取得分最高的前k个特征。

在XGBoost和LightGBM等最新的树模型中,还提供了更精细的特征重要性指标(如Gain、Weight、Cover等),可以更加准确地评估每个特征对模型的贡献程度。

总体来说,树模型选取特征的优点是可以考虑到特征之间的交互作用,可以处理非线性特征和高维数据,适用于特征之间存在复杂关系的数据集。但是,它也有一些缺点,如对于噪声特征和冗余特征比较敏感,容易出现过拟合的问题。此外,树模型的解释性相对较差,可能难以解释选取的特征对于模型的贡献程度。

2.3.2 Embedded Methods的具体类别

2.3.2.1 L1正则化

前面介绍过,这里不在介绍

2.3.2.2 Ridge回归(L2正则化)特征选择

Ridge回归(也称为L2正则化)是一种经典的线性回归模型,通过引入L2正则化项来防止过拟合。

Ridge回归可以用于特征选择,通过调整正则化强度,模型会倾向于将某些特征的系数缩小或者设置为0。在这种情况下,可以通过选择系数较大的特征来进行特征选择。

在使用Ridge回归进行特征选择时,需要先对数据进行标准化处理,以确保不同特征之间的权重是可比较的。可以通过使用sklearn库中的Ridge类来实现Ridge回归。

下面是一个示例代码,展示如何在鸢尾花数据集上使用Ridge回归进行特征选择:

import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.linear_model import Ridge
from sklearn.preprocessing import StandardScaler

# 加载数据集并标准化处理
iris = load_iris()
X, y = iris.data, iris.target
scaler = StandardScaler()
X_std = scaler.fit_transform(X)

# 创建Ridge回归模型
ridge = Ridge(alpha=1.0)

# 训练模型
ridge.fit(X_std, y)

# 输出特征重要性
print("Feature importances: ", ridge.coef_)

在上述示例代码中,首先使用StandardScaler对数据进行标准化处理,然后使用Ridge类创建Ridge回归模型,并使用fit方法训练模型。最后,可以通过ridge.coef_来输出特征的系数(或者说是特征的重要性),系数较大的特征对目标变量的影响更大,可以作为特征选择的依据。

2.3.2.3 Elastic Net(L1和L2正则化的组合)特征选择

Elastic Net是一种同时使用L1和L2正则化的线性回归模型。它可以通过权衡L1和L2正则化项的权重来选择特征。这种方法可以看作是Lasso和Ridge的一种折衷方案,它可以同时实现特征选择和对相关特征进行缩放。

在Elastic Net中,目标函数可以表示为:

在这里插入图片描述
其中,第一项是均方误差(MSE),第二项和第三项分别是L1正则化和L2正则化项。 α \alpha α是正则化系数, ρ \rho ρ是L1正则化项的权重。当 ρ = 1 \rho=1 ρ=1时,等价于Lasso回归,当 ρ = 0 \rho=0 ρ=0时,等价于Ridge回归。

与Lasso相比,Elastic Net在面对高度相关的特征时更具优势,因为它可以同时选择相关的特征,并对它们进行缩放。而且,当数据集中的特征维度很高时,Elastic Net相对于Lasso和Ridge来说,可以更快地选择特征。

以下是Elastic Net特征选择的一个示例,使用Sklearn中的breast_cancer数据集。首先,我们将数据集分为训练集和测试集,并使用ElasticNetCV选择最佳的正则化参数alpha和L1和L2的权重比例(l1_ratio)。

然后,使用选定的参数来拟合ElasticNet模型,并使用其coef_属性来获取每个特征的重要性得分,并根据得分来选择特征。

import numpy as np
import pandas as pd
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.linear_model import ElasticNetCV

# 加载数据集
data = load_breast_cancer()
X, y = data.data, data.target

# 将数据集拆分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# ElasticNetCV选择最佳的alpha和l1_ratio
model = ElasticNetCV(cv=5, random_state=42)
model.fit(X_train, y_train)
print("Best alpha:", model.alpha_)
print("Best l1_ratio:", model.l1_ratio_)

# 使用选定的参数拟合ElasticNet模型
elastic_net = ElasticNetCV(l1_ratio=model.l1_ratio_, cv=5, random_state=42)
elastic_net.fit(X_train, y_train)

# 获取每个特征的重要性得分
feature_scores = np.abs(elastic_net.coef_)
feature_scores /= feature_scores.max()

# 根据得分选择特征
selected_features = data.feature_names[feature_scores > 0.2]
print("Selected features:", selected_features)

输出结果如下所示:

Best alpha: 0.3961217205651492
Best l1_ratio: 0.5
Selected features: ['worst texture' 'worst perimeter']

在这个例子中,我们选择了具有最大重要性得分的20%的特征,其中alpha和l1_ratio使用ElasticNetCV选择的最佳参数。

2.3.2.4 树模型特征选择

1. 随机森林

下面是使用随机森林模型进行特征选择的示例:

import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier

# 加载数据集
iris = load_iris()
X, y = iris.data, iris.target

# 使用随机森林模型进行特征选择
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X, y)

# 输出特征重要性得分
print("Feature importance scores:", rf.feature_importances_)

# 选择特征重要性得分排名前2的特征
feature_names = np.array(iris.feature_names)  # 将 feature_names 转换为 numpy 数组
selected_features = feature_names[np.argsort(rf.feature_importances_)[::-1][:2]]
print("Selected features:", selected_features)

输出的结果为:

Feature importance scores: [0.10612762 0.02167809 0.43612951 0.43606478]
Selected features: ['petal length (cm)' 'petal width (cm)']
2. 决策树

下面是一个基于决策树的特征选择示例,使用sklearn库中的DecisionTreeClassifier和SelectFromModel来进行特征选择。

首先加载鸢尾花数据集,将其分为训练集和测试集:

import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

# 加载数据集
iris = load_iris()
X, y = iris.data, iris.target

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

然后使用DecisionTreeClassifier来拟合数据,得到特征的重要性(feature importance):

from sklearn.tree import DecisionTreeClassifier

# 构建决策树分类器
clf = DecisionTreeClassifier(random_state=42)
clf.fit(X_train, y_train)

# 得到特征的重要性
importances = clf.feature_importances_

接下来使用SelectFromModel来选择重要性大于平均值的特征:

from sklearn.feature_selection import SelectFromModel

# 筛选重要性大于平均值的特征
threshold = np.mean(importances)
selection = SelectFromModel(clf, threshold=threshold, prefit=True)
X_train_selected = selection.transform(X_train)
X_test_selected = selection.transform(X_test)

最后输出选择的特征:

# 输出选择的特征
selected_features = np.array(iris.feature_names)[selection.get_support()]
print("Selected features: ", selected_features)

输出结果为:

Selected features:  ['petal length (cm)']
3. 梯度提升树(GBDT)

它可以用于特征选择。它可以通过计算特征的相对重要性来为每个特征分配一个得分。相对重要性是通过评估在构建决策树时每个特征对于降低损失函数贡献的大小而计算得出的。与随机森林类似,可以通过对多个树的平均得分或累积得分进行特征排序和选择。

下面是使用梯度提升树进行特征选择的示例代码:

import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.ensemble import GradientBoostingClassifier

# 加载数据集
iris = load_iris()
X, y = iris.data, iris.target

# 使用梯度提升树模型进行特征选择
gb = GradientBoostingClassifier(n_estimators=100, learning_rate=0.1, random_state=42)
gb.fit(X, y)

# 输出特征重要性得分
print("Feature importance scores:", gb.feature_importances_)

# 选择特征重要性得分排名前2的特征
selected_features = np.array(iris.feature_names)[np.argsort(gb.feature_importances_)[::-1][:2]]
print("Selected features:", selected_features)

输出结果为:

Feature importance scores: [0.00546849 0.01184406 0.35628348 0.62640396]
Selected features: ['petal width (cm)' 'petal length (cm)']
4. Adaboost

Adaboost算法本身并不直接用于特征选择,它主要用于提升分类器的准确性。但是,Adaboost在每一轮迭代中都会对训练样本进行加权,这些权重可以用于选取特征。

具体来说,Adaboost在每一轮迭代中,会根据上一轮分类器的表现,更新样本的权重。这样,分类器更加关注那些上一轮分类错误的样本,这些样本通常会具有更高的权重。因此,在下一轮迭代中,这些样本对分类器的贡献更大。

这个过程也可以用于特征选择。我们可以在训练Adaboost分类器的过程中,根据每一轮迭代中样本的权重,计算每个特征对分类器的贡献。具体来说,对于每个特征,我们可以计算在每一轮迭代中,根据该特征对训练样本进行分类的准确率,并将所有轮迭代中的准确率加权求和。这样,就得到了每个特征的总贡献。可以将这些特征按照贡献大小进行排序,选取排名靠前的特征作为重要特征。

需要注意的是,由于Adaboost会对样本进行加权,因此在计算特征贡献时,需要考虑每个样本的权重。同时,特征贡献的计算需要进行加权求和,以反映每个特征在不同轮迭代中的重要性。

下面是一个示例代码,使用Adaboost对鸢尾花数据集进行特征选择:

import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier

# 加载数据集
iris = load_iris()
X, y = iris.data, iris.target

# 使用决策树作为基分类器,构建Adaboost模型
tree = DecisionTreeClassifier(max_depth=1, random_state=42)
ada = AdaBoostClassifier(base_estimator=tree, n_estimators=100, random_state=42)

# 训练Adaboost模型并获取特征重要性得分
ada.fit(X, y)
feature_importances = ada.feature_importances_

# 输出特征重要性得分
print("Feature importance scores:", feature_importances)

# 选择特征重要性得分排名前2的特征
selected_features = np.array(iris.feature_names)[np.argsort(feature_importances)[::-1][:2]]
print("Selected features:", selected_features)

输出结果如下:

Feature importance scores: [0.   0.   0.47 0.53]
Selected features: ['petal width (cm)' 'petal length (cm)']

2.4 PCA降维

PCA是一种降维技术,而不是一种特征选择方法。它通过将高维数据映射到低维空间来减少数据维度,同时保留大部分数据方差,以尽可能减少信息损失。

虽然PCA可以在某种程度上用于特征选择,但是它并不是最好的特征选择方法,因为它并不关注目标变量,而只是将数据映射到低维空间。

如果要使用PCA进行特征选择,可以根据降维后的特征向量的重要性来选择最重要的特征。这可以通过查看PCA对象的components_属性得到。

PCA降维本身不是一种特征选择方法,它是通过将原始特征转化为新的低维特征来达到降低特征维度的目的。但是,我们可以将PCA的输出视为新的特征,并选择其中最具有信息量的特征。

下面是在鸢尾花数据集上使用PCA选取特征的示例:

import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA

# 加载数据集
iris = load_iris()
X, y = iris.data, iris.target

# 使用PCA降维
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)

# 输出新特征的方差比例
print("Explained variance ratio:", pca.explained_variance_ratio_)

# 选择新特征的前一项
selected_feature = "PCA1"

# 输出选中的特征
print("Selected feature:", selected_feature)

输出结果为:

Explained variance ratio: [0.92461872 0.05306648]
Selected feature: PCA1

可以看到,使用PCA将原始的4维特征转化为了2维,并输出了新特征的方差比例。在这个示例中,我们选择了第一维作为新的特征。

猜你喜欢

转载自blog.csdn.net/wzk4869/article/details/129877445