尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Python手撕PCA:从原理到实战,搞定高维数据降维与可视化

Python手撕PCA:从原理到实战,搞定高维数据降维与可视化 1. 项目概述从数据冗余到特征洞察如果你处理过一堆变量多到让人眼花缭乱的数据比如几十个维度的用户画像、上百个指标的财务报表或者光谱分析里成千上万个波长点那你肯定遇到过两个头疼的问题一是变量之间“勾肩搭背”相关性太强信息重复二是维度太高不仅计算慢画个图都费劲根本看不出数据的内在结构。这时候主成分分析法PCA就该登场了。它不是什么高深莫测的黑魔法而是一个极其优雅的“数据压缩与重构”工具核心目标就是用更少的、互不相关的“新变量”主成分来尽可能多地保留原始数据的信息。简单来说PCA就像给数据做一次“体检”和“瘦身”。它先找到数据波动最大的方向第一主成分再找与第一个方向垂直且波动次大的方向第二主成分依此类推。这些新方向就是主成分它们是原始变量的线性组合。通过只保留前几个最重要的主成分我们就能把高维数据降到二维或三维方便可视化或者剔除噪声、减少后续建模的计算量。在数学建模竞赛里无论是国赛、美赛还是亚太杯PCA都是处理高维数据、进行综合评价、消除多重共线性的经典武器。这次我们就抛开那些复杂的数学推导直接上手用Python从零开始实现一个PCA并把它用在一个经典的数据集上让你彻底搞懂每一步在干什么以及为什么要这么干。2. 核心原理与思路拆解PCA到底在做什么在动手写代码之前我们必须先弄清楚PCA的“灵魂三问”它要解决什么它的核心思想是什么实现路径是怎样的只有理解了这些写出的代码才不是机械的步骤堆砌。2.1 问题本质降维与去相关我们面对的数据矩阵通常是一个n_samples × n_features的表格。n_features特征数即维度过大时会引发“维度灾难”样本稀疏、计算复杂、模型容易过拟合。更麻烦的是特征之间往往存在相关性这意味着数据中存在大量冗余信息。PCA的目标就是降维将原始高维特征空间投影到一个低维子空间。去相关确保新的低维特征主成分之间线性无关协方差为零。保留信息使得降维后的数据尽可能保留原始数据的方差即信息量。2.2 核心思想最大方差理论PCA有一个非常直观的几何解释寻找一个超平面使得所有数据点到这个超平面的投影点的方差最大。方差大意味着数据在这个方向上的分布散得开信息量就大。第一个主成分就是这个方差最大的方向第二个主成分是在与第一个主成分正交垂直的所有方向中方差最大的那个以此类推。从线性代数的角度看这等价于对数据的协方差矩阵进行特征值分解。2.3 实现路径五步走战略一个完整的PCA实现流程可以清晰地分为五个步骤这也是我们代码实现的骨架数据标准化消除量纲影响让所有特征处于同一尺度。计算协方差矩阵刻画特征之间的相关性。特征值分解提取核心的“方向”和“重要性”。选择主成分决定保留几个维度。数据投影将原始数据转换到新的低维空间。接下来我们就沿着这个路径用Python一步步实现它并深入每个步骤的细节和“坑点”。3. 从零开始的Python实现手撕PCA代码我们不直接调用sklearn.decomposition.PCA而是自己实现一遍这样才能吃透每一个细节。我们将以经典的鸢尾花Iris数据集为例它包含150个样本4个特征花萼长度、花萼宽度、花瓣长度、花瓣宽度非常适合演示。3.1 环境准备与数据加载首先确保你的Python环境中有NumPy和Matplotlib。NumPy是数值计算的基石PCA的核心运算全靠它Matplotlib用于可视化让我们直观地看到降维效果。import numpy as np import matplotlib.pyplot as plt from sklearn.datasets import load_iris # 加载鸢尾花数据集 iris load_iris() X iris.data # 特征矩阵形状 (150, 4) y iris.target # 目标标签用于后续着色观察 feature_names iris.feature_names print(f数据形状: {X.shape}) print(f特征名: {feature_names})注意这里从sklearn中加载数据是为了方便。在实际数学建模中你的数据可能来自CSV、Excel或数据库使用pandas.read_csv()等工具加载即可。自己实现PCA时输入就是一个NumPy数组。3.2 第一步数据标准化中心化PCA对数据的尺度非常敏感。如果某个特征的量纲很大比如身高以米计数值在1-2之间而收入以元计数值在几千到几万那么该特征在计算方差时会占据主导地位这并非我们想看到的。因此我们需要对每个特征进行标准化通常是中心化减去均值有时也会进行缩放除以标准差。对于PCA中心化是必须的缩放则取决于数据特性。这里我们采用最常用的StandardScaler方式即中心化并缩放到单位方差。def standardize(X): 对数据矩阵X进行标准化Z-score标准化。 参数: X: numpy数组形状 (n_samples, n_features) 返回: X_std: 标准化后的数据 mean_vec: 各特征的均值向量 std_vec: 各特征的标准差向量 mean_vec np.mean(X, axis0) # 按列计算均值 std_vec np.std(X, axis0) # 按列计算标准差 # 防止标准差为0导致除零错误将其替换为1 std_vec[std_vec 0] 1.0 X_std (X - mean_vec) / std_vec return X_std, mean_vec, std_vec # 应用标准化 X_std, mean_vec, std_vec standardize(X) print(标准化后数据的前5行:\n, X_std[:5])实操心得np.std默认计算的是总体标准差分母为n而sklearn的StandardScaler默认计算的是样本标准差分母为n-1。在数学上PCA对这两种标准化方式都适用但使用样本标准差np.std(X, axis0, ddof1)更为常见因为它是对总体标准差的无偏估计。为了和主流库保持一致在实际应用中更推荐使用ddof1。这里为了代码清晰使用了默认方式你需要知道这个细微差别。3.3 第二步计算协方差矩阵协方差矩阵是PCA的核心。它是一个对称矩阵对角线上的元素是各个特征的方差非对角线上的元素是不同特征之间的协方差反映了特征间的线性相关性。def compute_covariance_matrix(X_std): 计算标准化后数据的协方差矩阵。 注意对于标准化后的数据均值为0标准差为1其协方差矩阵就是相关系数矩阵。 参数: X_std: 标准化后的数据形状 (n_samples, n_features) 返回: cov_mat: 协方差矩阵形状 (n_features, n_features) n_samples X_std.shape[0] # 公式: cov (X_std.T X_std) / (n_samples - 1) # 使用 进行矩阵乘法也可以使用 np.dot cov_mat (X_std.T X_std) / (n_samples - 1) return cov_mat cov_mat compute_covariance_matrix(X_std) print(协方差矩阵形状:, cov_mat.shape) print(协方差矩阵:\n, cov_mat)为什么是 (n-1) 这是样本协方差的标准计算方法贝塞尔校正用于获得总体协方差的无偏估计。如果使用n得到的是最大似然估计在样本量较小时会有偏差。在数据量很大时两者差异很小。3.4 第三步特征值分解这是PCA的“魔法”发生的地方。我们对协方差矩阵进行特征值分解。特征向量指明了主成分的方向而对应的特征值则代表了数据在该主成分方向上的方差大小。特征值越大该主成分携带的原始信息就越多。def eigen_decomposition(cov_mat): 对协方差矩阵进行特征值分解。 参数: cov_mat: 协方差矩阵 返回: eigenvalues: 特征值数组按从大到小排序 eigenvectors: 特征向量矩阵每一列是对应特征值的特征向量 # np.linalg.eig 返回的特征值和特征向量特征值未排序 eigenvalues, eigenvectors np.linalg.eig(cov_mat) # 将特征值和特征向量按特征值降序排序 # 获取排序索引 idx eigenvalues.argsort()[::-1] eigenvalues eigenvalues[idx] eigenvectors eigenvectors[:, idx] # 注意每一列是一个特征向量 return eigenvalues, eigenvectors eigenvalues, eigenvectors eigen_decomposition(cov_mat) print(特征值方差:, eigenvalues) print(特征向量矩阵形状每一列是一个主成分方向:, eigenvectors.shape)关键点解析np.linalg.eig返回的eigenvectors的每一列eigenvectors[:, i]是对应于eigenvalues[i]的特征向量。这个特征向量是单位向量模长为1它定义了第i个主成分轴的方向。排序至关重要因为我们总是从携带信息最多的成分开始选取。3.5 第四步选择主成分个数我们不可能保留所有主成分那样就失去降维的意义了。如何选择保留前k个主成分有两个主流方法方差贡献率累计解释方差比这是最直观的方法。每个特征值λ_i的方差贡献率为λ_i / sum(λ)。我们计算前k个特征值的累计贡献率通常选择使累计贡献率达到某个阈值如80%90%95%的最小k值。碎石图Scree Plot绘制特征值按大小排序后的折线图。图形通常会出现一个“肘部”肘部之前的主成分携带了大部分信息肘部之后特征值下降变得平缓这些成分可能更多是噪声。选择肘部对应的k值。def select_principal_components(eigenvalues, variance_threshold0.95): 根据方差贡献率选择主成分个数。 参数: eigenvalues: 排序后的特征值数组 variance_threshold: 累计方差贡献率阈值默认0.95 返回: k: 选择的主成分个数 explained_variance_ratio: 各主成分方差贡献率 cumulative_variance_ratio: 累计方差贡献率 total_variance np.sum(eigenvalues) explained_variance_ratio eigenvalues / total_variance cumulative_variance_ratio np.cumsum(explained_variance_ratio) # 找到累计贡献率首次超过阈值的索引 k np.argmax(cumulative_variance_ratio variance_threshold) 1 # 如果所有累计贡献率都小于阈值理论上不会则选择所有成分 k min(k, len(eigenvalues)) return k, explained_variance_ratio, cumulative_variance_ratio # 选择主成分 k, explained_var_ratio, cum_var_ratio select_principal_components(eigenvalues, 0.95) print(f特征值: {eigenvalues}) print(f方差贡献率: {explained_var_ratio}) print(f累计方差贡献率: {cum_var_ratio}) print(f选择保留 {k} 个主成分可解释 {cum_var_ratio[k-1]:.2%} 的总方差) # 绘制碎石图与累计贡献率图 fig, (ax1, ax2) plt.subplots(1, 2, figsize(12, 4)) # 碎石图 ax1.plot(range(1, len(eigenvalues)1), eigenvalues, bo-, linewidth2) ax1.set_title(Scree Plot) ax1.set_xlabel(Principal Component) ax1.set_ylabel(Eigenvalue (Variance)) ax1.grid(True) # 累计贡献率图 ax2.plot(range(1, len(cum_var_ratio)1), cum_var_ratio, ro-, linewidth2) ax2.axhline(y0.95, colorg, linestyle--, label95% threshold) ax2.axvline(xk, colororange, linestyle--, labelfSelected k{k}) ax2.set_title(Cumulative Explained Variance Ratio) ax2.set_xlabel(Number of Principal Components) ax2.set_ylabel(Cumulative Explained Variance Ratio) ax2.legend() ax2.grid(True) plt.tight_layout() plt.show()从鸢尾花数据的输出和图中我们通常会看到前两个主成分已经解释了超过95%的方差。这意味着4维数据的信息几乎完全可以由2维来承载这是一个非常理想的降维案例。3.6 第五步数据投影降维转换选择了前k个特征向量主成分方向后我们将原始标准化数据投影到这些方向上得到降维后的新数据。def transform_data(X_std, eigenvectors, k): 将标准化数据投影到前k个主成分上实现降维。 参数: X_std: 标准化后的原始数据形状 (n_samples, n_features) eigenvectors: 特征向量矩阵每一列是一个主成分方向 k: 要保留的主成分个数 返回: X_pca: 降维后的数据形状 (n_samples, k) # 选取前k个特征向量主成分 projection_matrix eigenvectors[:, :k] # 形状 (n_features, k) # 数据投影X_pca X_std projection_matrix X_pca X_std projection_matrix return X_pca, projection_matrix # 执行投影转换 X_pca, W transform_data(X_std, eigenvectors, k2) # 我们选择降到2维以便可视化 print(降维后数据形状:, X_pca.shape) print(投影矩阵W形状:, W.shape) print(降维后数据前5行:\n, X_pca[:5])至此我们完成了PCA的核心流程。X_pca就是我们得到的降维后的数据。对于鸢尾花数据我们从4维降到了2维。3.7 可视化与结果分析让我们看看降维后的数据在二维平面上是什么样子并用原始类别标签着色观察PCA是否保留了数据的分类结构。# 可视化降维结果 plt.figure(figsize(8, 6)) scatter plt.scatter(X_pca[:, 0], X_pca[:, 1], cy, cmapviridis, edgecolork, s70) plt.xlabel(fPrincipal Component 1 ({explained_var_ratio[0]:.2%} variance)) plt.ylabel(fPrincipal Component 2 ({explained_var_ratio[1]:.2%} variance)) plt.title(PCA of Iris Dataset (2 Components)) plt.colorbar(scatter, labelIris Species) plt.grid(True, alpha0.3) plt.show()你会看到三个不同品种的鸢尾花在二维平面上被清晰地分成了三个簇。这说明前两个主成分成功捕获了数据中最重要的分类信息。我们还可以查看主成分的构成即特征向量了解每个原始特征对主成分的贡献。# 查看主成分的载荷特征向量 pc_loadings eigenvectors[:, :2] # 前两个主成分的载荷 print(主成分载荷矩阵前两列:) for i, feature in enumerate(feature_names): print(f{feature:15}: PC1{pc_loadings[i, 0]:.3f}, PC2{pc_loadings[i, 1]:.3f}) # 可以绘制一个载荷图Loading Plot fig, ax plt.subplots(figsize(8, 6)) for i, feature in enumerate(feature_names): ax.arrow(0, 0, pc_loadings[i, 0], pc_loadings[i, 1], head_width0.03, head_length0.03, fcr, ecr) ax.text(pc_loadings[i, 0]*1.15, pc_loadings[i, 1]*1.15, feature, colorb, fontsize12) ax.set_xlim(-1, 1) ax.set_ylim(-1, 1) ax.axhline(y0, colork, linestyle--, linewidth0.5) ax.axvline(x0, colork, linestyle--, linewidth0.5) ax.set_xlabel(Principal Component 1 Loadings) ax.set_ylabel(Principal Component 2 Loadings) ax.set_title(Loading Plot of Features on the First Two PCs) ax.grid(True, alpha0.3) plt.show()从载荷图中可以看出**花瓣长度petal length和花瓣宽度petal width在第一个主成分PC1上有很高的正向载荷且方向接近说明它们高度相关共同主导了PC1。而花萼宽度sepal width**在PC2上有较高的负向载荷与其他特征方向差异较大。这解释了为什么PC1能很好地区分Setosa花瓣小和其他两类而PC2则有助于进一步区分Versicolor和Virginica。4. 封装与对比打造自己的PCA类为了方便复用我们将上述步骤封装成一个类并对比sklearn的实现结果验证正确性。class MyPCA: 自定义PCA实现类 def __init__(self, n_componentsNone, variance_threshold0.95): 初始化。 参数: n_components: 指定保留的主成分个数。若为None则根据variance_threshold自动选择。 variance_threshold: 自动选择主成分时的累计方差阈值。 self.n_components n_components self.variance_threshold variance_threshold self.mean_ None self.std_ None self.eigenvalues_ None self.eigenvectors_ None self.explained_variance_ratio_ None self.cumulative_variance_ratio_ None self.projection_matrix_ None def fit(self, X): 拟合模型计算PCA所需的所有参数。 # 1. 标准化 self.mean_ np.mean(X, axis0) self.std_ np.std(X, axis0, ddof1) # 使用样本标准差 self.std_[self.std_ 0] 1.0 X_std (X - self.mean_) / self.std_ # 2. 计算协方差矩阵 n_samples X.shape[0] cov_mat (X_std.T X_std) / (n_samples - 1) # 3. 特征值分解 eigenvalues, eigenvectors np.linalg.eig(cov_mat) idx eigenvalues.argsort()[::-1] self.eigenvalues_ eigenvalues[idx] self.eigenvectors_ eigenvectors[:, idx] # 4. 计算方差贡献率 total_variance np.sum(self.eigenvalues_) self.explained_variance_ratio_ self.eigenvalues_ / total_variance self.cumulative_variance_ratio_ np.cumsum(self.explained_variance_ratio_) # 5. 确定要保留的主成分数 n_components if self.n_components is None: # 根据阈值自动选择 k np.argmax(self.cumulative_variance_ratio_ self.variance_threshold) 1 self.n_components min(k, len(self.eigenvalues_)) else: # 用户指定但确保不超过特征总数 self.n_components min(self.n_components, X.shape[1]) # 6. 构建投影矩阵 self.projection_matrix_ self.eigenvectors_[:, :self.n_components] return self def transform(self, X): 将数据转换到主成分空间。 if self.mean_ is None or self.projection_matrix_ is None: raise ValueError(Please fit the model before transforming data.) X_std (X - self.mean_) / self.std_ X_pca X_std self.projection_matrix_ return X_pca def fit_transform(self, X): 拟合模型并转换数据。 self.fit(X) return self.transform(X) # 使用自定义PCA类 my_pca MyPCA(n_components2) # 或者 MyPCA(variance_threshold0.95) X_my_pca my_pca.fit_transform(X) print(自定义PCA结果前5行:\n, X_my_pca[:5]) # 使用sklearn的PCA进行对比 from sklearn.decomposition import PCA from sklearn.preprocessing import StandardScaler scaler StandardScaler(with_stdTrue) # ddof1 X_scaled scaler.fit_transform(X) sklearn_pca PCA(n_components2) X_sklearn_pca sklearn_pca.fit_transform(X_scaled) print(\nSklearn PCA结果前5行:\n, X_sklearn_pca[:5]) # 比较结果允许符号相反因为特征向量方向可以反向 print(\n比较第一个样本的降维结果:) print(f自定义PCA: {X_my_pca[0]}) print(fSklearn PCA: {X_sklearn_pca[0]}) print(f两者绝对值是否接近: {np.allclose(np.abs(X_my_pca), np.abs(X_sklearn_pca), atol1e-10)})运行后你会发现除了可能的符号差异特征向量方向可以取反这不会影响主成分空间我们的结果与sklearn的结果在数值上基本一致。符号差异是线性代数中特征向量定义的固有歧义不影响使用。5. 数学建模实战技巧与避坑指南在数学建模竞赛中应用PCA远不止调用一个函数那么简单。以下几个实战技巧和常见“坑点”是我从多次比赛中总结出来的血泪经验。5.1 技巧一数据预处理是成败关键PCA基于方差最大化因此对异常值极其敏感。一个巨大的异常值会拉高整个特征的方差导致主成分方向被它“带偏”。必做步骤在标准化之前务必进行异常值检测和处理。可以使用箱线图、3σ原则或孤立森林等方法。量纲统一对于量纲差异大的数据必须进行标准化Z-score。如果数据分布近似正态用Z-score如果数据有偏或者存在极端值可以考虑使用RobustScaler基于中位数和四分位数来减少异常值影响。缺失值处理PCA不能直接处理缺失值。需要先使用均值、中位数、插值或模型预测等方法填补缺失值。5.2 技巧二主成分个数选择策略不要盲目追求95%或99%的方差贡献率。可视化辅助一定要画碎石图和累计贡献率图。如果碎石图在某个点后变得非常平缓肘部那么肘部对应的k值通常是一个好的选择。结合业务目标如果你降维是为了后续的分类或聚类可以尝试不同的k值观察模型性能如分类准确率、聚类轮廓系数的变化选择一个性能开始稳定或达到最佳的k。避免过度降维保留的主成分过少可能会丢失重要信息导致后续模型性能下降。尤其是在特征间相关性不强时每个成分携带的信息可能都比较独特。5.3 技巧三主成分的解释与命名降维后我们得到了PC1, PC2...但它们是什么这就需要解释主成分载荷。载荷分析查看projection_matrix_即特征向量的每一列。对第i个主成分绝对值大的载荷对应的原始特征对该主成分贡献大。你可以尝试为这个主成分起一个名字例如“规模因子”、“盈利效率因子”等这能极大提升论文的可读性。载荷图就像我们之前画的那样可以直观看到各个原始特征在主成分平面上的“投影”理解特征之间的关系。5.4 常见问题与排查结果与sklearn不一致符号相反这是正常现象。特征向量v和-v对应同一个特征值都是有效的。只要主成分空间即这些向量张成的子空间一致即可。比较时可以比较数据的绝对值或平方。特征值出现复数或非常小的负数由于浮点计算误差对称矩阵的特征值分解可能产生极小的虚部或负值接近0。通常用np.real()取实部并将绝对值极小如1e-10的负值视为0。协方差矩阵计算慢当特征数n非常大如10000时计算n×n的协方差矩阵和其特征值分解会非常耗时。此时应考虑使用随机PCA或增量PCA它们通过迭代方法近似计算主成分适用于大数据。降维后效果不好PCA是线性降维方法。如果数据的内在结构是非线性的如“瑞士卷”型数据PCA效果会很差。此时应考虑t-SNE、UMAP或**核PCAKernel PCA**等非线性降维方法。信息丢失评估降维后可以用降维数据重构原始数据X_reconstructed X_pca projection_matrix.T * std mean计算重构误差如均方误差MSE量化信息丢失的程度。5.5 在建模中的典型应用场景数据可视化将高维数据降至2D或3D进行绘图是探索数据结构的首要步骤。特征工程用提取出的主成分作为新的特征输入到回归、分类模型如逻辑回归、随机森林中可以消除多重共线性提高模型稳定性和训练速度。综合评价在国赛/美赛的“评价类”问题中常用PCA确定各指标的权重。第一主成分的载荷向量经过归一化处理后可以作为各原始指标的权重进而计算综合得分。切记这要求第一主成分的方差贡献率足够高通常40%且所有载荷系数符号一致最好全为正否则解释性会很差。噪声过滤假设后几个主成分主要代表噪声那么只使用前k个主成分重构数据可以实现数据去噪。6. 超越基础PCA的进阶话题与扩展实现基础PCA只是第一步。在实际研究和应用中你可能会遇到更复杂的情况。6.1 核PCAKernel PCA处理非线性数据当数据存在非线性结构时可以先将数据通过一个非线性函数映射到更高维的特征空间然后在这个高维空间进行线性PCA。这等价于在原始空间使用一个核函数Kernel来隐式计算高维空间的内积。sklearn提供了KernelPCA类常用的核函数有径向基函数RBF、多项式核等。# 示例使用RBF核的KernelPCA from sklearn.decomposition import KernelPCA kpca KernelPCA(n_components2, kernelrbf, gamma0.1) # gamma是RBF核的参数 X_kpca kpca.fit_transform(X_scaled) # 可视化比较线性PCA与核PCA的结果6.2 稀疏PCASparse PCA与可解释性标准PCA得到的主成分是所有原始特征的线性组合载荷通常非零这使得主成分的解释有时比较困难。稀疏PCA通过添加L1正则化约束迫使载荷向量变得稀疏很多系数为0从而让每个主成分只由少数几个关键原始特征决定大大增强了可解释性。6.3 增量PCAIncremental PCA处理大数据当数据量太大无法一次性读入内存时可以使用增量PCA。它将数据分批读入逐步更新主成分的估计非常适合流式数据或大规模数据集。from sklearn.decomposition import IncrementalPCA n_batches 10 inc_pca IncrementalPCA(n_components2) for X_batch in np.array_split(X_scaled, n_batches): inc_pca.partial_fit(X_batch) X_ipca inc_pca.transform(X_scaled)6.4 PCA与因子分析FA的区别初学者常混淆PCA和因子分析。两者都用于降维但目的不同PCA目标是解释方差寻找能够最大程度解释数据变动的方向。主成分是原始变量的线性组合。因子分析FA目标是解释相关性假设观测变量是由少数几个潜在的、无法直接观测的“公共因子”和唯一的“特殊因子”线性组合而成。它更侧重于挖掘变量背后的潜在结构。在数学建模中如果你需要为观测到的变量寻找潜在的、有意义的“因子”并且愿意接受一个概率模型那么FA可能更合适。如果单纯是为了减少变量数量、消除共线性或可视化PCA更简单直接。7. 一个完整的建模案例思路城市发展水平综合评价假设2026年亚太杯数学建模A题是关于“城市可持续发展综合评价”给出了几十个经济、社会、环境指标。我们可以运用PCA来构建综合指数。数据预处理收集各城市多年份的指标数据处理缺失值和异常值。对所有指标进行正向化将负向指标如“失业率”转化为正向和无量纲化Z-score标准化。适用性检验计算KMO检验和Bartlett球形检验判断数据是否适合做PCA/因子分析。KMO0.6Bartlett检验p0.05则认为适合。执行PCA对标准化后的数据计算相关系数矩阵等同于标准化后的协方差矩阵进行特征值分解。确定主成分绘制碎石图观察拐点。计算累计方差贡献率选择使累计贡献率超过85%的前k个主成分。计算成分得分与综合得分成分得分F_i X_std * W_iW_i是第i个主成分的载荷向量。综合得分S Σ(λ_i / Σλ) * F_i即以方差贡献率为权重对各主成分得分进行加权求和。结果分析根据综合得分对城市排序。分析第一主成分的载荷看哪些指标贡献大尝试将其命名为“综合经济发展因子”或“社会发展水平因子”等并撰写分析报告。在整个过程中PCA不仅帮助我们压缩了数据更揭示了指标间的内在结构为决策提供了比简单加权平均更客观、更稳健的综合评价方法。
返回列表