机器学习模型的高级特征选择技术

精通特征选择:监督和无监督机器学习模型的高级技术探究

无可否认,机器学习是新时代的明星。它是各种主要技术的支柱,这些技术已经成为我们日常生活中不可或缺的一部分,例如面部识别(由卷积神经网络或CNN支持)、语音识别(利用CNN和循环神经网络或RNN)以及越来越流行的聊天机器人如ChatGPT(由人类反馈的强化学习,RLHF支持)。

今天有许多方法可用于提高机器学习模型的性能。这些方法可以通过提供优越的性能为您的项目带来竞争优势。

在本讨论中,我们将深入探讨特征选择技术的领域。但在我们继续之前,让我们澄清一下:什么是特征选择?

什么是特征选择?

特征选择是选择模型最佳特征的过程。这个过程可能因技术而异,但主要目标是找出哪些特征对您的模型有更大的影响。

为什么应该进行特征选择?

因为有时候,拥有太多的特征可能会伤害您的机器学习模型。如何伤害?

可能有太多不同的原因。例如,这些特征可能相互关联,这可能会导致多重共线性,破坏您的模型性能。

另一个潜在问题与计算能力有关。存在太多的特征需要更多的计算能力来同时执行任务,这可能需要更多的资源,从而增加成本。

当然,也可能有其他原因。但这些例子应该给您一个潜在问题的一般概念。然而,在我们进一步探讨这个话题之前,还有一个更重要的方面需要理解。

哪种特征选择方法对我的模型更好?

是的,这是一个很好的问题,应该在开始项目之前回答。但很难给出一个通用的答案。

特征选择模型的选择取决于您拥有的数据类型和项目的目标。

例如,基于过滤器的方法,如卡方检验或互信息增益通常用于分类数据的特征选择。向前或向后选择等包装器方法适用于数值数据。

然而,需要知道的是,许多特征选择方法可以很好地处理分类和数值数据。

例如,套索回归、决策树和随机森林都可以很好地处理这两种类型的数据。

在监督和无监督特征选择方面,监督方法,如递归特征消除或决策树,适用于标记数据。无监督方法,如主成分分析(PCA)或独立成分分析(ICA),用于未标记数据。

最终,特征选择方法的选择应基于数据的特定特征和项目的目标。

看一下我们将在文章中讨论的主题概述。让自己熟悉它,让我们从监督特征选择技术开始。

1. 监督特征选择技术

监督学习中的特征选择策略旨在利用输入特征与目标变量之间的关系来发现用于预测目标变量的最相关特征。这些策略可能有助于改善模型性能、减少过拟合并降低训练模型的计算成本。

以下是我们将讨论的监督特征选择技术的概述。

1.1 基于过滤器的方法

基于过滤器的特征选择方法基于数据的内在属性,如特征相关性或统计学。这些方法单独或成对地评估每个特征的价值,而不考虑特定学习算法的性能。

基于过滤器的方法计算效率高,可以与各种学习算法一起使用。然而,由于它们不考虑特征与学习方法之间的相互作用,它们可能不能总是捕捉到某个算法的理想特征子集。

首先,让我们来看看基于过滤器的方法的总览,然后我们逐一讨论。

信息增益

信息增益是一种统计量,通过根据特定特征对数据进行划分来衡量熵(不确定性)的减少。它经常用于决策树算法,并具有有用的功能。特征的信息增益越高,对于决策制定就越有用。

现在,让我们通过使用预建的糖尿病数据集来应用信息增益。

糖尿病数据集包含与预测糖尿病进展相关的生理特征。

  • 年龄:年龄
  • 性别:性别(1 = 男性,0 = 女性)
  • BMI:身体质量指数,计算为体重(公斤)除以身高(米)的平方
  • bp:平均血压(毫米汞柱)
  • s1、s2、s3、s4、s5、s6:六种不同血化学物质的血清测量(包括葡萄糖)

以下代码演示了如何应用信息增益方法。此代码以sklearn库中的糖尿病数据集为例。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_diabetes
from sklearn.feature_selection import mutual_info_regression

# 加载糖尿病数据集
data = load_diabetes()

# 将数据集分为特征和目标
X = data.data
y = data.target

此代码的主要目标是基于信息增益计算特征重要性得分,有助于确定预测模型中最相关的特征。通过确定这些得分,您可以对包括或排除分析中的哪些特征做出明智的决策,最终实现改进的模型性能、减少过度拟合和更快的训练时间。

为了实现这一目标,此代码计算数据集中每个特征的信息增益得分,并将它们存储在一个字典中。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_diabetes
from sklearn.feature_selection import mutual_info_regression

# 加载糖尿病数据集
data = load_diabetes()

# 将数据集分为特征和目标
X = data.data
y = data.target

# 应用信息增益
ig = mutual_info_regression(X, y)

# 创建特征重要性得分的字典
feature_scores = {}
for i in range(len(data.feature_names)):
    feature_scores[data.feature_names[i]] = ig[i]

然后按得分排序特征。

# 按重要性得分按降序排序特征
sorted_features = sorted(feature_scores.items(), key=lambda x: x[1], reverse=True)

# 打印特征重要性得分和排序后的特征
for feature, score in sorted_features:
    print('特征:', feature, '得分:', score)

我们将将排序后的特征重要性得分可视化为一个水平条形图,从而可以轻松比较不同特征对于给定任务的相关性。

在构建机器学习模型时,此可视化特别有用,可帮助确定哪些特征保留或丢弃。

# 绘制特征重要性得分的水平条形图
fig, ax = plt.subplots()
y_pos = np.arange(len(sorted_features))
ax.barh(y_pos, [score for feature, score in sorted_features], align="center")
ax.set_yticks(y_pos)
ax.set_yticklabels([feature for feature, score in sorted_features])
ax.invert_yaxis()  # 标签从上到下阅读
ax.set_xlabel("重要性得分")
ax.set_title("特征重要性得分(信息增益)")

# 在水平条形图上添加重要性得分标签
for i, v in enumerate([score for feature, score in sorted_features]):
    ax.text(v + 0.01, i, str(round(v, 3)), color="black", fontweight="bold")
plt.show()

让我们看看整个代码。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_diabetes
from sklearn.feature_selection import mutual_info_regression

# 加载糖尿病数据集
data = load_diabetes()

# 将数据集分为特征和目标
X = data.data
y = data.target

# 应用信息增益
ig = mutual_info_regression(X, y)

# 创建特征重要性得分的字典
feature_scores = {}
for i in range(len(data.feature_names)):
    feature_scores[data.feature_names[i]] = ig[i]
# 按重要性得分按降序排序特征
sorted_features = sorted(feature_scores.items(), key=lambda x: x[1], reverse=True)

# 打印特征重要性得分和排序后的特征
for feature, score in sorted_features:
    print("特征:", feature, "得分:", score)
# 绘制特征重要性得分的水平条形图
fig, ax = plt.subplots()
y_pos = np.arange(len(sorted_features))
ax.barh(y_pos, [score for feature, score in sorted_features], align="center")
ax.set_yticks(y_pos)
ax.set_yticklabels([feature for feature, score in sorted_features])
ax.invert_yaxis()  # 标签从上到下阅读
ax.set_xlabel("重要性得分")
ax.set_title("特征重要性得分(信息增益)")

# 在水平条形图上添加重要性得分标签
for i, v in enumerate([score for feature, score in sorted_features]):
    ax.text(v + 0.01, i, str(round(v, 3)), color="black", fontweight="bold")
plt.show()

以下是输出结果。

输出结果显示使用信息增益方法计算的糖尿病数据集中每个特征的特征重要性得分。这些特征根据它们的分数以降序排列,分数表示它们在预测目标变量方面的相对重要性。

结果如下:

  • 身体质量指数(bmi)具有最高的重要性得分(0.174),表示它在糖尿病数据集中对目标变量具有最显著的影响。
  • 血清测量5(s5)紧随其后,得分为0.153,使其成为第二个最重要的特征。
  • 血清测量6(s6)、血清测量4(s4)和血压(bp)具有中等重要性得分,范围从0.104到0.065不等。
  • 其他特征,如血清测量1、2和3(s1,s2,s3)、性别和年龄,具有相对较低的重要性得分,表明它们对模型的预测能力作出的贡献较少。

通过分析这些特征重要性得分,您可以决定在分析中包含或排除哪些特征,以提高您的机器学习模型的性能。在这种情况下,您可以考虑保留具有较高重要性得分的特征,例如bmi和s5,同时可能删除或进一步调查具有较低得分的特征,例如年龄和s2。

卡方检验

卡方检验是一种用于评估两个分类变量之间关系的统计检验。在特征选择中,它用于分析分类特征与目标变量之间的关系。更高的卡方分数显示特征和目标之间的联系更强,表明该特征在分类任务中更重要。

虽然卡方检验是常用的特征选择方法,但通常用于分类数据,其中特征和目标变量是离散的。

费舍尔分数

费舍尔判别比,通常称为费舍尔分数,是一种根据它们在数据集中区分不同类别的能力对特征进行排名的特征选择方法。它可以用于分类问题中的连续特征。

费舍尔分数的计算是类间方差和类内方差之比。更高的费舍尔分数意味着该特征更具有区分性和分类价值。

要使用费舍尔分数进行特征选择,请计算每个连续特征的分数,并根据它们的分数对它们进行排名。模型认为具有更高费舍尔分数的特征更重要。

缺失值比率

缺失值比率是一种简单直接的特征选择方法,它根据特征中缺失值的数量做出决策。

具有大量缺失值的特征可能是不具信息量的,可能会影响模型的性能。您可以通过指定可接受的缺失值比率的阈值来过滤掉具有太多缺失值的特征。

要使用缺失值比率进行特征选择,请按以下步骤操作:

  1. 通过将缺失值的数量除以数据集中的总实例数来计算每个特征的缺失值比率。
  2. 为可接受的缺失值比率(例如0.8,表示特征应最多缺少80%的值才能被考虑)设置阈值。
  3. 过滤掉具有高于阈值的缺失值比率的特征。

1.2 基于包装器的方法

基于包装器的特征选择方法包括使用特定的机器学习算法评估特征的重要性。它们通过尝试各种特征组合并使用选择的方法评估它们的性能来寻求最佳的特征子集。

由于可用的特征子集数量巨大,因此基于包装器的方法可能会在使用高维数据集时计算成本很高。

但是,它们通常优于基于过滤器的方法,因为它们考虑特征和学习算法之间的关系。

前向选择

在前向选择中,您从一个空的特征集开始,并迭代地将特征添加到集合中。在每个步骤中,您使用当前特征集和额外的特征评估模型的性能。导致性能提高最好的特征被添加到集合中。

该过程会一直持续,直到性能没有显著改善,或者达到预定义的特征数量。

下面的代码演示了正向选择的应用,这是一种基于包装器的监督特征选择技术。

示例使用了来自sklearn库的乳腺癌数据集。乳腺癌数据集,也称为威斯康星州诊断性乳腺癌(WDBC)数据集,是一个常用的预建立数据集,用于分类。在这里,主要目标是构建预测模型,对乳腺癌进行诊断,无论是恶性(癌性)还是良性(非癌性)。

为了我们的模型,我们将选择不同数量的特征,以查看性能如何相应变化,但首先,让我们加载库、数据集和变量。

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 mlxtend.feature_selection import SequentialFeatureSelector as SFS

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

# 将数据集拆分为特征和目标
X = data.data
y = data.target

该代码的目标是使用正向选择为逻辑回归模型识别最佳特征子集。该技术从一个空的特征集开始,根据指定的评估指标迭代添加改进模型性能的特征。在这种情况下,使用的度量标准是准确性。

代码的下一部分利用来自mlxtend库的SequentialFeatureSelector进行正向选择。它配置了一个逻辑回归模型、所需的特征数量和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 mlxtend.feature_selection import SequentialFeatureSelector as SFS

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

# 将数据集拆分为特征和目标
X = data.data
y = data.target

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

# 定义逻辑回归模型
model = LogisticRegression()

# 定义正向选择对象
sfs = SFS(model,
          k_features=5,
          forward=True,
          floating=False,
          scoring='accuracy',
          cv=5)

# 对训练集进行正向选择
sfs.fit(X_train, y_train)

此外,我们需要评估所选特征在测试集上的性能,并使用线性图可视化模型在不同特征子集下的性能。

该图将显示交叉验证准确性作为特征数量的函数,提供有关模型复杂性和预测性能之间的权衡的见解。

通过分析输出和图表,您可以确定要包含在模型中的最佳特征数量,从而改善其性能并减少过度拟合。

# 打印所选特征
print('Selected Features:', sfs.k_feature_names_)

# 评估所选特征在测试集上的性能
accuracy = sfs.k_score_
print('Accuracy:', accuracy)

# 绘制不同特征子集下模型的性能
sfs_df = pd.DataFrame.from_dict(sfs.get_metric_dict()).T
sfs_df['avg_score'] = sfs_df['avg_score'].astype(float)
fig, ax = plt.subplots()
sfs_df.plot(kind='line', y='avg_score', ax=ax)
ax.set_xlabel('Number of Features')
ax.set_ylabel('Accuracy')
ax.set_title('Forward Selection Performance')
plt.show()

下面是完整的代码。

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 mlxtend.feature_selection import SequentialFeatureSelector as SFS

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

# 将数据集拆分为特征和目标
X = data.data
y = data.target

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

# 定义逻辑回归模型
model = LogisticRegression()

# 定义正向选择对象
sfs = SFS(model, k_features=5, forward=True, floating=False, scoring="accuracy", cv=5)

# 对训练集进行正向选择
sfs.fit(X_train, y_train)

# 打印所选特征
print("Selected Features:", sfs.k_feature_names_)

# 评估所选特征在测试集上的性能
accuracy = sfs.k_score_
print("Accuracy:", accuracy)

# 绘制不同特征子集下模型的性能
sfs_df = pd.DataFrame.from_dict(sfs.get_metric_dict()).T
sfs_df["avg_score"] = sfs_df["avg_score"].astype(float)
fig, ax = plt.subplots()
sfs_df.plot(kind="line", y="avg_score", ax=ax)
ax.set_xlabel("Number of Features")
ax.set_ylabel("Accuracy")
ax.set_title("Forward Selection Performance")
plt.show()

前向选择代码的输出表明,该算法已经识别出了一个包含5个特征的子集,该子集在乳腺癌数据集上的逻辑回归模型中产生了最佳准确性(0.9548)。这些所选特征由它们的索引号确定:0、1、4、21和22。

折线图提供了有关模型在不同特征数量下性能的额外见解。它表明:

  • 仅使用1个特征,模型的准确率约为91%。
  • 添加第二个特征将准确率提高到94%。
  • 使用3个特征,准确率进一步提高到95%。
  • 包括4个特征将准确率略微提高到95%以上。

超过4个特征后,准确性的提高变得不那么显著。这些信息可以帮助您在模型复杂度和预测性能之间做出明智的决策。基于这些结果,您可能会决定在您的模型中仅使用3或4个特征来平衡准确性和简单性。

后向选择

与前向选择相反,后向选择从整个特征集开始,并逐渐从中删除特征。

在每个阶段,您都要使用当前特征集减去要删除的特征来测量模型的性能。

导致性能降低最少的特征将从集合中删除。

该过程重复进行,直到性能没有实质性的提高或达到预设的特征数量为止。

前向选择和后向选择被归类为序列特征选择;您可以在此处了解更多。

穷举特征选择

穷举特征选择比较所有可能的特征子集的性能并选择最佳性能的子集。这种方法在大型数据集上需要计算量,但可以确保选择最佳特征子集。

递归特征消除

递归特征消除从整个特征集开始,并根据学习算法的判断重复消除特征。在每个步骤中,最不重要的特征将被删除,并重新训练模型。该方法重复进行,直到达到预定数量的特征为止。

1.3 嵌入式方法

嵌入式特征选择方法将特征选择过程作为学习算法的一部分。

这意味着在训练阶段中,学习算法不仅优化模型参数,而且还选择最重要的特征。嵌入式方法比包装器方法更有效,因为它们不需要外部特征选择过程。

Image by Author

正则化

正则化是一种方法,它向损失函数添加惩罚项,以防止机器学习模型过拟合。

正则化方法,如 Lasso(L1 正则化)和 Ridge(L2 正则化),可与特征选择一起使用,以将不太重要的特征系数降低到零,从而选择最相关的特征子集。

随机森林重要性

随机森林是一种集成学习方法,它将多个决策树的预测组合在一起。在构建树的过程中,随机森林计算每个特征的重要性得分,该得分可用于根据其相关性对特征进行排序。模型认为具有更高重要性评分的特征更为重要。

如果您想了解更多关于随机森林的内容,可以参考本文《决策树和随机森林算法》,其中还解释了决策树算法。

下面的示例使用 Covertype 数据集,该数据集包含有关不同类型森林覆盖的信息。

Covertype 数据集的目标是预测北科罗拉多州罗斯福国家森林内的森林覆盖类型(主导树种)。

下面代码的主要目标是使用随机森林分类器确定特征的重要性。通过评估每个特征对总体分类性能的贡献,该方法有助于确定建立预测模型所需的最相关特征。

import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt

# 加载 Covertype 数据集
data = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/covtype/covtype.data.gz", header=None)

# 分配列名
cols = ["Elevation", "Aspect", "Slope", "Horizontal_Distance_To_Hydrology",
        "Vertical_Distance_To_Hydrology", "Horizontal_Distance_To_Roadways",
        "Hillshade_9am", "Hillshade_Noon", "Hillshade_3pm",
        "Horizontal_Distance_To_Fire_Points"] + ["Wilderness_Area_"+str(i) for i in range(1,5)] + ["Soil_Type_"+str(i) for i in range(1,41)] + ["Cover_Type"]

data.columns = cols

然后,我们创建一个RandomForestClassifier对象并将其拟合到训练数据中。然后从训练后的模型中提取特征重要性并按重要性分数降序排序。基于它们的重要性分数选择前10个特征并以排名的形式显示出来。

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

# 创建随机森林分类器对象
rfc = RandomForestClassifier(n_estimators = 100,random_state = 42)

# 将模型拟合到训练数据中
rfc.fit(X_train,y_train)

# 从训练后的模型中获取特征重要性
importances = rfc.feature_importances_

# 按降序排序特征重要性
indices = np.argsort(importances)[:: -1]


# 选择前10个特征
num_features = 10
top_indices = indices [: num_features]
top_importances = importances [top_indices]


# 打印前10个特征排名
print(“前10个特征排名:”)
for f in range(num_features):  # 使用num_features而不是10
    print(f“{f + 1}。{X_train.columns [indices [f]]}:{importances [indices [f]]}”)

此外,该代码使用水平条形图可视化了前10个特征的重要性。

# 在水平条形图中绘制前10个特征重要性
plt.barh(range(num_features),top_importances,align ='center')
plt.yticks(range(num_features),X_train.columns [top_indices])
plt.xlabel(“特征重要性”)
plt.ylabel(“特征”)
plt.show()

此可视化允许轻松比较重要性分数,并有助于决定分析中包含或排除哪些特征。

通过检查输出和图表,您可以选择最相关的特征用于预测模型,这有助于提高其性能,减少过度拟合并加速训练时间。

以下是完整代码。

import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt

# 加载Covertype数据集
data = pd.read_csv(
    "https://archive.ics.uci.edu/ml/machine-learning-databases/covtype/covtype.data.gz",
    header=None,
)

# 指定列名
cols = (
    [
        "海拔",
        "朝向",
        "坡度",
        "到水源的水平距离",
        "到水源的垂直距离",
        "到道路的水平距离",
        "山阴9am",
        "山阴中午",
        "山阴下午3pm",
        "到火源的水平距离",
    ]
    + ["野外地区_" + str(i) for i in range(1, 5)]
    + ["土地类型_" + str(i) for i in range(1, 41)]
    + ["覆盖类型"]
)

data.columns = cols

# 将数据集拆分为特征和目标
X = data.iloc[:, :-1]
y = data.iloc[:, -1]

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

# 创建随机森林分类器对象
rfc = RandomForestClassifier(n_estimators = 100,random_state = 42)

# 将模型拟合到训练数据中
rfc.fit(X_train,y_train)

# 从训练后的模型中获取特征重要性
importances = rfc.feature_importances_

# 按降序排序特征重要性
indices = np.argsort(importances)[:: -1]


# 选择前10个特征
num_features = 10
top_indices = indices [: num_features]
top_importances = importances [top_indices]


# 打印前10个特征排名
print(“前10个特征排名:”)
for f in range(num_features):  # 使用num_features而不是10
    print(f“{f + 1}。{X_train.columns [indices [f]]}:{importances [indices [f]]}”)
# 在水平条形图中绘制前10个特征重要性
plt.barh(range(num_features),top_importances,align =“center”)
plt.yticks(range(num_features),X_train.columns [top_indices])
plt.xlabel(“特征重要性”)
plt.ylabel(“特征”)
plt.show()

以下是输出。

随机森林重要性方法的输出显示了在Covertype数据集中预测森林覆盖类型中排名前10的特征按其重要性排序。

它揭示了海拔在预测森林覆盖类型中具有最高的重要性分数(0.2423)。这表明海拔在确定罗斯福国家森林的主要树种方面发挥了关键作用。

其他具有相对较高重要性得分的特征包括水平距离道路(0.1158)和水平距离火点(0.1100)。这些表明道路和火点的接近程度也显著影响森林覆盖类型。

前10名列表中的其余特征具有相对较低的重要性得分,但它们仍然对模型的总体预测性能有所贡献。这些特征主要与水文因素、坡度、方位和山体阴影指数有关。

总之,结果突出显示了影响罗斯福国家森林森林覆盖类型分布的最重要因素,这可以用于构建更有效和高效的森林覆盖类型分类预测模型。

2. 无监督特征选择技术

当没有目标变量可用时,可以使用无监督特征选择方法来降低数据集的维数,同时保持其基本结构。这些方法通常包括将初始特征空间改变为一个新的低维空间,其中改变后的特征捕获了数据中的大部分变化。

图片来源:作者

2.1 主成分分析(PCA)

PCA是一种线性降维方法,它将原始特征空间转换为由主成分定义的新的正交空间。这些成分是选择的原始特征的线性组合,用于捕获数据中的最高变化水平。

PCA可以用来选择代表大部分变化的前k个主成分,从而降低数据集的维数。

为了向您展示这在实践中的工作原理,我们将使用Wine数据集进行工作。这是一个广泛用于机器学习中分类和特征选择任务的数据集,包含178个样本,每个样本代表来自同一地区意大利三个不同栽培品种的不同葡萄酒。

使用Wine数据集的目标通常是构建一个预测模型,该模型可以根据其化学特性准确地将葡萄酒样本分类为三个不同栽培品种中的一个。

以下代码演示了在Wine数据集上应用无监督特征选择技术——主成分分析(PCA)。

这些组件(主成分)捕获了数据中的大部分变化,同时最小化了信息损失。

代码首先加载Wine数据集,该数据集包含描述不同葡萄酒样本的化学特性的13个特征。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_wine
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler

# 加载Wine数据集
wine = load_wine()
X = wine.data
y = wine.target
feature_names = wine.feature_names

然后使用StandardScaler对这些特征进行标准化,以确保PCA不受输入特征的不同尺度的影响。

# 标准化特征
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

接下来,使用sklearn.decomposition模块中的PCA类对标准化数据执行PCA。

# 执行PCA
pca = PCA()
X_pca = pca.fit_transform(X_scaled)

计算每个主成分的解释方差比,指示每个成分解释数据中总方差的比例。

# 计算解释方差比
explained_variance_ratio = pca.explained_variance_ratio_

最后,生成两个图表以可视化主成分的解释方差比和累计解释方差。

第一个图表显示每个单独主成分的解释方差比,而第二个图表说明随着包含更多主成分,累计解释方差如何增加。

这些图表有助于确定在模型中使用的最佳主成分数量,平衡降维和信息保留之间的权衡。

# 创建一个2x1的子图网格
fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(16, 8))

# 在第一个子图中绘制解释方差比
ax1.bar(range(1, len(explained_variance_ratio) + 1), explained_variance_ratio)
ax1.set_xlabel('主成分')
ax1.set_ylabel('解释方差比')
ax1.set_title('主成分的解释方差比')

# 计算累计解释方差
cumulative_explained_variance = np.cumsum(explained_variance_ratio)

# 在第二个子图中绘制累计解释方差
ax2.plot(range(1, len(cumulative_explained_variance) + 1), cumulative_explained_variance, marker='o')
ax2.set_xlabel('主成分数量')
ax2.set_ylabel('累计解释方差')
ax2.set_title('主成分的累计解释方差')

# 显示图形
plt.tight_layout()
plt.show()

让我们来看看整个代码。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_wine
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler

# 加载Wine数据集
wine = load_wine()
X = wine.data
y = wine.target
feature_names = wine.feature_names

# 标准化特征
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 进行PCA
pca = PCA()
X_pca = pca.fit_transform(X_scaled)

# 计算解释的方差比
explained_variance_ratio = pca.explained_variance_ratio_

# 创建一个2x1子图网格
fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(16, 8))

# 在第一个子图中绘制解释的方差比
ax1.bar(range(1, len(explained_variance_ratio) + 1), explained_variance_ratio)
ax1.set_xlabel("主成分")
ax1.set_ylabel("解释的方差比")
ax1.set_title("按主成分解释的方差比")

# 计算累计解释方差
cumulative_explained_variance = np.cumsum(explained_variance_ratio)

# 在第二个子图中绘制累计解释方差
ax2.plot(
    range(1, len(cumulative_explained_variance) + 1),
    cumulative_explained_variance,
    marker="o",
)
ax2.set_xlabel("主成分数")
ax2.set_ylabel("累计解释方差")
ax2.set_title("按主成分累计解释方差")

# 显示图形
plt.tight_layout()
plt.show()

以下是输出结果。

左侧图表显示,随着主成分数量的增加,解释的方差比会降低。这是PCA中观察到的典型行为,因为主成分按照它们所解释的方差量进行排序。

第一个主成分(特征)捕获最高的方差,第二个主成分捕获第二高的方差量,以此类推。因此,随着每个后续主成分的加入,解释的方差比会降低。

这是PCA用于降维的主要原因之一。

右侧第二张图表显示了累计解释方差,帮助您确定选择多少主成分(特征)来表示您的数据的百分比。x轴表示主成分数量,y轴显示累计解释方差。随着沿着x轴移动,您可以看到在包括那么多主成分时保留的总方差量。

在这个例子中,您可以看到选择3或4个主成分已经捕获了超过80%的总方差,选择8个主成分则捕获了超过90%的总方差。

您可以根据所需的降维和所需保留的方差之间的权衡选择主成分数量。

在这个例子中,我们使用Sci-kit来学习应用PCA,您可以在这里找到官方文档。

2.2 独立成分分析(ICA)

ICA是一种将多维信号分解为其组成部分的方法。

在特征选择的上下文中,ICA可用于将原始特征空间转换为由统计独立成分特征描述的新空间。通过选择前k个独立成分,您可以减少数据集的维数而保持底层结构。

2.3 非负矩阵分解(NMF)

非负矩阵分解(NMF)是一种将非负数据矩阵近似为两个较低维非负矩阵的降维方法。

NMF可用于在特征选择的上下文中提取一组新的基础特征,以捕获原始数据的重要结构。通过选择前k个基础特征,您可以最小化数据集的维数,同时保持非负限制。

2.4 t分布随机邻居嵌入(t-SNE)

t-SNE是一种非线性降维方法,通过减少高维和低维位置中成对概率分布之间的差异来保留数据集的结构。

t-SNE可用于在特征选择的上下文中将原始特征空间投影到保持数据结构的低维空间,从而实现增强的可视化和评估。

您可以在此处找到关于无监督算法和t-SNE的更多信息:“无监督学习算法”。

2.5 自编码器

自编码器是一种人工神经网络,学习将输入数据编码为低维表示,然后解码回原始版本。自编码器的低维表示可用于生成捕获原始数据底层结构的另一组特征。

结束语

总之,在机器学习中,特征选择非常重要。它有助于减少数据的维度,最小化过度拟合的风险,并提高模型的整体性能。选择正确的特征选择方法取决于具体问题、数据集和建模要求。

本文涵盖了广泛的特征选择技术,包括监督和无监督方法。

监督技术,如基于过滤器、基于包装器和嵌入式方法,利用特征和目标变量之间的关系来识别最重要的特征。

无监督技术,如PCA、ICA、NMF、t-SNE和自编码器,侧重于数据的内在结构,以减少维度,而不考虑目标变量。

在为模型选择适当的特征选择方法时,必须考虑数据的特征、每种技术的基本假设以及涉及的计算复杂性。

通过精心选择和应用正确的特征选择技术,您可以显著提高性能,从而获得更好的洞察力和决策能力。 Nate Rosidi 是一位数据科学家和产品战略家。他还是一名兼职教授,教授分析学,并是 StrataScratch 的创始人,该平台帮助数据科学家通过来自顶级公司的真实面试问题准备面试。在 Twitter 上与他联系:StrataScratch 或 LinkedIn。