特征重要性评估与数据降维方法
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)
通过以上介绍,我们对特征重要性评估和数据降维的多种方法有了更深入的了解。在实际应用中,我们可以根据具体问题选择合适的方法,以达到更好的效果。
超级会员免费看

被折叠的 条评论
为什么被折叠?



