13、特征重要性评估与数据降维方法

特征重要性评估与数据降维方法

1. 使用随机森林评估特征重要性

在特征选择方面,随机森林是一种实用的集成技术。它可以通过计算森林中所有决策树的平均杂质减少量来衡量特征的重要性,且无需假设数据是否线性可分。在 scikit-learn 中,随机森林的实现会自动收集特征重要性值,我们可以在拟合 RandomForestClassifier 后通过 feature_importances_ 属性访问这些值。

1.1 代码示例

以下代码展示了如何在 Wine 数据集上训练一个包含 500 棵树的随机森林,并对 13 个特征的重要性进行排序:

from sklearn.ensemble import RandomForestClassifier
import numpy as np
import matplotlib.pyplot as plt

# 假设 df_wine 是 Wine 数据集的 DataFrame
feat_labels = df_wine.columns[1:]
forest = RandomForestClassifier(n_estimators=500, random_state=1)
forest.fit(X_train, y_train)
importances = forest.feature_importances_
indices = np.argsort(importances)[::-1]

for f in range(X_train.shape[1]):
    print("%2d) %-*s %f" % (f + 1, 30, feat_labels[indices[f]], importances[indices[f]]))

plt.title('Feature Importance')
plt.bar(range(X_train.shape[1]), importances[indices], align='center')
plt.xticks(range(X_train.shape[1]), feat_labels[indices], rotation=90)
plt.xlim([-1, X_train.shape[1]])
plt.tight_layout()
plt.show()

1.2 特征重要性排序结果

运行上述代码后,得到的特征重要性排序结果如下:
| 排名 | 特征名称 | 重要性值 |
| ---- | ---- | ---- |
| 1 | Proline | 0.185453 |
| 2 | Flavanoids | 0.174751 |
| 3 | Color intensity | 0.143920 |
| 4 | OD280/OD315 of diluted wines | 0.136162 |
| 5 | Alcohol | 0.118529 |
| 6 | Hue | 0.058739 |
| 7 | Total phenols | 0.050872 |
| 8 | Magnesium | 0.031357 |
| 9 | Malic acid | 0.025648 |
| 10 | Proanthocyanins | 0.025570 |
| 11 | Alcalinity of ash | 0.022366 |
| 12 | Nonflavanoid phenols | 0.013354 |
| 13 | Ash | 0.013279 |

从结果可以看出,脯氨酸(Proline)、类黄酮(Flavanoids)、颜色强度(Color intensity)、稀释葡萄酒的 OD280/OD315 比值(OD280/OD315 of diluted wines)和酒精浓度(Alcohol)是数据集中最具区分性的特征。

1.3 随机森林的局限性

需要注意的是,当两个或多个特征高度相关时,随机森林可能会将其中一个特征排名很高,而另一个特征的信息可能无法被充分捕捉。但如果我们只关注模型的预测性能,而不是特征重要性值的解释,就无需担心这个问题。

1.4 使用 SelectFromModel 进行特征选择

scikit-learn 还提供了 SelectFromModel 对象,可在模型拟合后根据用户指定的阈值选择特征。例如,我们可以将阈值设置为 0.1,以将数据集缩减为最重要的 5 个特征:

from sklearn.feature_selection import SelectFromModel

sfm = SelectFromModel(forest, threshold=0.1, prefit=True)
X_selected = sfm.transform(X_train)
print('Number of features that meet this threshold criterion:', X_selected.shape[1])

for f in range(X_selected.shape[1]):
    print("%2d) %-*s %f" % (f + 1, 30, feat_labels[indices[f]], importances[indices[f]]))

筛选后的 5 个特征与前面排名前 5 的特征一致。

2. 主成分分析(PCA)进行无监督数据压缩

除了特征选择,特征提取也是一种有效的降维方法。主成分分析(PCA)是一种无监督的线性变换技术,广泛应用于特征提取和降维。

2.1 PCA 的基本原理

PCA 旨在找到高维数据中最大方差的方向,并将数据投影到一个新的子空间,该子空间的维度等于或小于原始空间。新子空间的正交轴(主成分)可以解释为在新特征轴相互正交的约束下,具有最大方差的方向。

2.2 PCA 的主要步骤

PCA 算法的主要步骤如下:
1. 标准化 d 维数据集。
2. 构建协方差矩阵。
3. 将协方差矩阵分解为特征向量和特征值。
4. 按特征值降序排序,对相应的特征向量进行排名。
5. 选择对应 k 个最大特征值的 k 个特征向量,其中 k 是新特征子空间的维度($k\leq d$)。
6. 从“前” k 个特征向量构建投影矩阵 W。
7. 使用投影矩阵 W 变换 d 维输入数据集 X,以获得新的 k 维特征子空间。

2.3 逐步提取主成分

2.3.1 加载和预处理数据

首先,我们加载 Wine 数据集,并将其分为训练集和测试集,然后对特征进行标准化处理:

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

df_wine = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data', header=None)
X, y = df_wine.iloc[:, 1:].values, df_wine.iloc[:, 0].values
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, stratify=y, random_state=0)

sc = StandardScaler()
X_train_std = sc.fit_transform(X_train)
X_test_std = sc.transform(X_test)
2.3.2 构建协方差矩阵

协方差矩阵是一个对称的 $d\times d$ 矩阵,其中 d 是数据集中的维度数,它存储了不同特征之间的成对协方差。以两个特征 $x_j$ 和 $x_k$ 为例,它们在总体水平上的协方差可以通过以下公式计算:
$\sigma_{jk}=\frac{1}{n - 1}\sum_{i = 1}^{n}(x_j^{(i)} - \mu_j)(x_k^{(i)} - \mu_k)$
其中,$\mu_j$ 和 $\mu_k$ 分别是特征 j 和 k 的样本均值。如果数据集已经标准化,样本均值为零。正协方差表示两个特征同时增加或减少,负协方差表示它们朝相反方向变化。例如,三个特征的协方差矩阵可以写成:
$\Sigma = \begin{bmatrix}
\sigma_1^2 & \sigma_{12} & \sigma_{13} \
\sigma_{21} & \sigma_2^2 & \sigma_{23} \
\sigma_{31} & \sigma_{32} & \sigma_3^2
\end{bmatrix}$
在 Python 中,我们可以使用 numpy.cov 函数计算标准化训练数据集的协方差矩阵:

import numpy as np

cov_mat = np.cov(X_train_std.T)
2.3.3 计算特征值和特征向量

我们使用 NumPy 的 linalg.eig 函数对协方差矩阵进行特征分解,得到特征值和特征向量:

eigen_vals, eigen_vecs = np.linalg.eig(cov_mat)
print('\nEigenvalues \n%s' % eigen_vals)

需要注意的是, numpy.linalg.eig 函数适用于对称和非对称方阵,但在某些情况下可能会返回复特征值。对于对称矩阵,如协方差矩阵, numpy.linalg.eigh 是一个数值上更稳定的选择,它总是返回实特征值。

2.4 总方差和解释方差

为了选择包含大部分信息(方差)的特征向量子集,我们需要计算特征值的解释方差比。解释方差比是指单个特征值与所有特征值总和的比值:
$Explained\ variance\ ratio = \frac{\lambda_j}{\sum_{j = 1}^{d}\lambda_j}$
我们可以使用 NumPy 的 cumsum 函数计算累积解释方差,并使用 Matplotlib 绘制图形:

import matplotlib.pyplot as plt

tot = sum(eigen_vals)
var_exp = [(i / tot) for i in sorted(eigen_vals, reverse=True)]
cum_var_exp = np.cumsum(var_exp)

plt.bar(range(1, 14), var_exp, alpha=0.5, align='center', label='Individual explained variance')
plt.step(range(1, 14), cum_var_exp, where='mid', label='Cumulative explained variance')
plt.ylabel('Explained variance ratio')
plt.xlabel('Principal component index')
plt.legend(loc='best')
plt.tight_layout()
plt.show()

从绘制的图形中可以看出,第一个主成分单独解释了约 40% 的方差,前两个主成分组合解释了近 60% 的方差。

2.5 特征变换

接下来,我们将执行 PCA 的最后三个步骤,将 Wine 数据集转换到新的主成分轴上。具体步骤如下:
1. 按特征值降序对特征对进行排序。
2. 从选定的特征向量构建投影矩阵。
3. 使用投影矩阵将数据转换到低维子空间。

# 按特征值降序排序特征对
eigen_pairs = [(np.abs(eigen_vals[i]), eigen_vecs[:, i]) for i in range(len(eigen_vals))]
eigen_pairs.sort(key=lambda k: k[0], reverse=True)

# 选择对应两个最大特征值的特征向量
w = np.hstack((eigen_pairs[0][1][:, np.newaxis], eigen_pairs[1][1][:, np.newaxis]))
print('Matrix W:\n', w)

# 转换单个示例
print(X_train_std[0].dot(w))

# 转换整个训练数据集
X_train_pca = X_train_std.dot(w)

最后,我们可以将转换后的 Wine 训练数据集可视化,它现在存储为一个 $124\times 2$ 维的矩阵:

# 可视化转换后的数据集
plt.scatter(X_train_pca[:, 0], X_train_pca[:, 1], c=y_train)
plt.xlabel('Principal Component 1')
plt.ylabel('Principal Component 2')
plt.show()

2.6 镜像投影问题

需要注意的是,根据所使用的 NumPy 和 LAPACK 版本,投影矩阵 W 的符号可能会翻转。但这不是问题,因为如果 v 是矩阵 $\Sigma$ 的特征向量,那么 -v 也是它的特征向量。

综上所述,随机森林可以帮助我们评估特征的重要性,而 PCA 则是一种有效的无监督降维方法。通过这些技术,我们可以减少数据的维度,提高模型的计算效率和预测性能。

3. 线性判别分析(LDA):有监督的降维技术

线性判别分析(LDA)是一种有监督的降维技术,其目标是最大化类间可分性。与 PCA 不同,LDA 会考虑类标签信息,旨在找到能够最好区分不同类别的特征子空间。

3.1 LDA 的基本原理

LDA 试图找到投影方向,使得不同类别的数据在投影后尽可能分开,而同一类别的数据尽可能聚集。具体来说,LDA 会计算类间散布矩阵和类内散布矩阵,然后通过求解广义特征值问题来确定投影方向。

3.2 LDA 的主要步骤

LDA 算法的主要步骤如下:
1. 计算每个类别的均值向量。
2. 计算类间散布矩阵 $S_B$ 和类内散布矩阵 $S_W$。
3. 计算矩阵 $S_W^{-1}S_B$ 的特征值和特征向量。
4. 按特征值降序排序,选择前 k 个特征向量。
5. 使用选定的特征向量构建投影矩阵。
6. 将原始数据投影到新的特征子空间。

3.3 LDA 代码示例

以下是使用 scikit-learn 实现 LDA 的代码示例:

from sklearn.discriminant_analysis import LinearDiscriminantAnalysis

# 创建 LDA 对象
lda = LinearDiscriminantAnalysis(n_components=2)

# 拟合数据并进行转换
X_train_lda = lda.fit_transform(X_train_std, y_train)
X_test_lda = lda.transform(X_test_std)

# 可视化转换后的数据
plt.scatter(X_train_lda[:, 0], X_train_lda[:, 1], c=y_train)
plt.xlabel('LD 1')
plt.ylabel('LD 2')
plt.show()

3.4 LDA 与 PCA 的比较

方法 监督性 目标 应用场景
PCA 无监督 最大化数据方差 数据压缩、去除噪声
LDA 有监督 最大化类间可分性 分类任务、特征提取

4. 核主成分分析(KPCA):非线性降维

核主成分分析(KPCA)是 PCA 的扩展,用于处理非线性数据。它通过核函数将数据映射到高维特征空间,然后在该空间中进行 PCA。

4.1 KPCA 的基本原理

KPCA 利用核技巧,避免了在高维空间中显式计算映射。常见的核函数包括线性核、多项式核和高斯核等。通过选择合适的核函数,KPCA 可以捕捉数据中的非线性结构。

4.2 KPCA 的主要步骤

KPCA 算法的主要步骤如下:
1. 选择核函数并计算核矩阵。
2. 对核矩阵进行中心化处理。
3. 计算核矩阵的特征值和特征向量。
4. 按特征值降序排序,选择前 k 个特征向量。
5. 将数据投影到新的特征子空间。

4.3 KPCA 代码示例

以下是使用 scikit-learn 实现 KPCA 的代码示例:

from sklearn.decomposition import KernelPCA

# 创建 KPCA 对象
kpca = KernelPCA(n_components=2, kernel='rbf', gamma=15)

# 进行转换
X_train_kpca = kpca.fit_transform(X_train_std)
X_test_kpca = kpca.transform(X_test_std)

# 可视化转换后的数据
plt.scatter(X_train_kpca[:, 0], X_train_kpca[:, 1], c=y_train)
plt.xlabel('KPC 1')
plt.ylabel('KPC 2')
plt.show()

4.4 不同降维方法的选择

在实际应用中,我们需要根据数据的特点和任务的需求选择合适的降维方法。以下是一些选择建议:
- 如果数据是线性可分的,且不需要考虑类标签信息,PCA 是一个不错的选择。
- 如果需要最大化类间可分性,LDA 更适合。
- 如果数据具有非线性结构,KPCA 可能会取得更好的效果。

4.5 总结

综上所述,随机森林可用于评估特征重要性,PCA 是无监督的线性降维方法,LDA 是有监督的线性降维方法,而 KPCA 则适用于处理非线性数据。这些方法各有优缺点,在实际应用中需要根据具体情况进行选择。通过合理使用这些降维技术,我们可以减少数据的维度,提高模型的计算效率和预测性能,同时更好地理解和分析数据。

下面是一个 mermaid 流程图,展示了不同降维方法的选择过程:

graph LR
    A[数据特点] --> B{线性可分?}
    B -- 是 --> C{需要考虑类标签?}
    C -- 否 --> D(PCA)
    C -- 是 --> E(LDA)
    B -- 否 --> F(KPCA)

通过以上介绍,我们对特征重要性评估和数据降维的多种方法有了更深入的了解。在实际应用中,我们可以根据具体问题选择合适的方法,以达到更好的效果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值