主成分分析(PCA)原理与实战:从数据降维到Python/Matlab实现
1. 项目概述主成分分析的核心价值与应用场景主成分分析也就是我们常说的PCA是我在数据分析、机器学习甚至是信号处理领域里用得最顺手的工具之一。它本质上是一种数据降维技术但它的魅力远不止“压缩数据”这么简单。想象一下你手头有一份包含几十个甚至上百个变量的数据集比如一份用户画像里面有年龄、收入、浏览时长、点击次数、购买频率等等。这些变量之间往往相互关联信息冗余严重直接分析不仅计算量大而且容易受到“维度灾难”的干扰模型也容易过拟合。PCA的作用就是帮你从这一大堆相互纠缠的变量中提炼出几个全新的、互不相关的“综合指标”这些指标被称为主成分它们能够最大程度地保留原始数据中的变异信息。我第一次深入使用PCA是在处理一份高维的传感器数据时。当时有几十个传感器同时采集设备运行状态数据维度高直接看波形图眼花缭乱。用了PCA之后我发现前三个主成分就解释了超过85%的数据波动。这意味着我可以用三个维度的图表就清晰地观察到设备大部分的核心运行模式异常点也一目了然。这比盯着几十条曲线高效太多了。无论是学生做数模竞赛还是工程师做故障诊断亦或是金融从业者做风险因子分析PCA都是一个能帮你化繁为简、抓住主要矛盾的利器。它不要求你有太深的数学背景但理解其背后的几何和统计思想能让你用得更得心应手。2. 主成分分析的数学原理与几何直观要玩转PCA不能只停留在调包理解其背后的思想至关重要。我们可以从两个最直观的角度来看最大方差和最小投影误差。2.1 从最大方差视角理解PCAPCA的第一个目标是寻找数据方差最大的方向。方差代表了数据在该方向上的分散程度分散程度越大说明这个方向承载的信息量可能就越多。我们寻找的第一主成分就是这样一个单位向量当所有数据点投影到这个向量上时投影值的方差达到最大。你可以想象在二维平面上有一群散点第一主成分就是那条能让所有点投影上去之后沿着这条线“拉开”得最开的直线。找到第一主成分后我们找第二主成分。第二主成分必须与第一主成分正交垂直并且在满足这个约束的条件下使得投影方差第二大。以此类推每一个后续的主成分都与之前的所有主成分正交。这样得到的一系列主成分不仅保证了携带信息量方差的从大到小排序还保证了彼此之间完全不相关因为正交。数学上这等价于求解数据协方差矩阵的特征值和特征向量。特征值的大小对应了主成分所携带的方差信息量特征向量则指明了主成分的方向。2.2 从最小重构误差视角理解PCA另一个等价的视角是最小化重构误差。假设我们想用一组新的、更少的坐标轴即主成分来重新表示原始数据。PCA要做的就是当我们用前k个主成分来重构近似原始数据时希望重构后的数据与原始数据之间的均方误差最小。这个视角在数据压缩和可视化中非常实用。它告诉我们PCA是在寻找一个最优的、更低维度的子空间使得数据在这个子空间上的投影能最好地代表原始数据。这两个视角是统一的最大化保留方差同时也就最小化了丢弃方差所带来的重构误差。在实际操作中我们通常通过计算协方差矩阵或相关矩阵的特征分解或者对数据中心化后的数据矩阵进行奇异值分解SVD来实现PCA。SVD是更数值稳定的方法也是很多软件库如Python的scikit-learn背后的默认实现。注意在进行PCA之前一个关键但常被忽略的步骤是数据标准化。如果原始变量的量纲差异巨大比如年龄是20-60收入是5000-200000那么方差大的变量如收入会完全主导主成分的方向导致分析结果失真。通常我们需要对每个特征进行Z-score标准化使其均值为0标准差为1。这一步在sklearn中通过StandardScaler轻松实现但思想上绝不能省略。3. 基于Python的PCA完整实战流程纸上得来终觉浅我们直接上代码用Python把PCA的整个流程走一遍。这里我会使用scikit-learn和matplotlib库它们是目前最主流、最易用的组合。3.1 环境准备与数据模拟首先我们创建一个模拟的高维数据集这样结果可控便于理解。import numpy as np import matplotlib.pyplot as plt from sklearn.decomposition import PCA from sklearn.preprocessing import StandardScaler from sklearn.datasets import make_blobs # 设置随机种子保证结果可复现 np.random.seed(42) # 模拟一个三维数据集但其中两个维度高度相关另一个相对独立 n_samples 300 # 创建一个二维的“基础”数据 X_base np.random.randn(n_samples, 2) # 构造三维数据第一维是基础第一维第二维与第一维强相关并加噪声第三维独立 X np.column_stack([ X_base[:, 0], # 特征1 X_base[:, 0] * 1.5 0.5 * X_base[:, 1] np.random.randn(n_samples) * 0.1, # 特征2与特征1强相关 X_base[:, 1] np.random.randn(n_samples) * 0.5 # 特征3相对独立 ]) print(f原始数据形状: {X.shape}) print(f前5行数据:\n{X[:5]})这段代码生成了一个300行、3列的数据集X。其中第2列索引1与第1列索引0具有很强的线性相关性而第3列相对独立。我们的目标是看PCA能否发现这种数据结构。3.2 数据标准化与PCA拟合接下来进行关键的数据标准化和PCA模型拟合。# 1. 数据标准化至关重要的一步 scaler StandardScaler() X_scaled scaler.fit_transform(X) print(数据已标准化均值为0标准差为1) # 2. 创建PCA对象并拟合数据 # 我们可以先不指定主成分数量查看所有成分的方差解释率 pca_full PCA() pca_full.fit(X_scaled) # 3. 查看各主成分的方差解释率及累计解释率 explained_variance_ratio pca_full.explained_variance_ratio_ cumulative_variance_ratio np.cumsum(explained_variance_ratio) print(\n各主成分方差解释率:) for i, ratio in enumerate(explained_variance_ratio): print(f 主成分 {i1}: {ratio:.4f} ({ratio*100:.2f}%)) print(\n累计方差解释率:) for i, cum_ratio in enumerate(cumulative_variance_ratio): print(f 前 {i1} 个主成分: {cum_ratio:.4f} ({cum_ratio*100:.2f}%))运行后你可能会看到类似这样的输出各主成分方差解释率: 主成分 1: 0.7215 (72.15%) 主成分 2: 0.2455 (24.55%) 主成分 3: 0.0330 (3.30%) 累计方差解释率: 前 1 个主成分: 0.7215 (72.15%) 前 2 个主成分: 0.9670 (96.70%) 前 3 个主成分: 1.0000 (100.00%)这个结果非常漂亮地印证了我们的数据构造第一个主成分携带了超过72%的信息这很可能对应了原始数据中那两个强相关特征特征1和特征2所共同指向的主要变异方向。前两个主成分一起解释了超过96%的方差这意味着我们完全可以用两个维度来近似表示原来的三维数据而且信息损失极小约3.3%。3.3 降维、可视化与结果解读现在我们指定降维到2维进行转换并可视化。# 4. 指定降维到2维进行数据转换 pca PCA(n_components2) X_pca pca.fit_transform(X_scaled) # fit_transform 一步完成拟合和转换 print(f\n降维后数据形状: {X_pca.shape}) # 5. 可视化原始三维数据在两个视角下的散点图以及降维后的二维数据 fig plt.figure(figsize(15, 5)) # 子图1原始数据三维展示两个视角 ax1 fig.add_subplot(131, projection3d) ax1.scatter(X[:, 0], X[:, 1], X[:, 2], alpha0.6, cblue) ax1.set_xlabel(Feature 1 (Original)) ax1.set_ylabel(Feature 2 (Original)) ax1.set_zlabel(Feature 3 (Original)) ax1.set_title(Original 3D Data (View 1)) ax2 fig.add_subplot(132, projection3d) # 换个视角 ax2.scatter(X[:, 1], X[:, 2], X[:, 0], alpha0.6, cgreen) ax2.set_xlabel(Feature 2 (Original)) ax2.set_ylabel(Feature 3 (Original)) ax2.set_zlabel(Feature 1 (Original)) ax2.set_title(Original 3D Data (View 2)) ax2.view_init(elev20., azim-35) # 子图3PCA降维后的二维数据 ax3 fig.add_subplot(133) scatter ax3.scatter(X_pca[:, 0], X_pca[:, 1], alpha0.6, cred) ax3.set_xlabel(Principal Component 1 ({:.1f}% Var).format(pca.explained_variance_ratio_[0]*100)) ax3.set_ylabel(Principal Component 2 ({:.1f}% Var).format(pca.explained_variance_ratio_[1]*100)) ax3.set_title(Data after PCA (2D)) ax3.grid(True, linestyle--, alpha0.5) ax3.axhline(y0, colork, linestyle-, alpha0.2) ax3.axvline(x0, colork, linestyle-, alpha0.2) plt.tight_layout() plt.show() # 6. 查看主成分的构成载荷Loadings print(\n主成分载荷矩阵每个原始特征对主成分的贡献:) print(行主成分 列原始特征) print(pca.components_)通过载荷矩阵我们可以解读每个主成分的物理意义。例如如果pca.components_[0] [0.7, 0.65, 0.1]这意味着第一主成分主要由第一个和第二个原始特征正向贡献且贡献度相当而第三个特征贡献很小。这正好对应了我们数据中特征1和特征2强相关的设定。实操心得在解释主成分时载荷矩阵的绝对值大小比符号更重要。一个特征在某个主成分上载荷的绝对值越大说明该特征对这个主成分的贡献越大。正负号表示该特征与主成分方向是同向还是反向变化。有时为了更容易解释可以对载荷矩阵进行“旋转”如方差最大化旋转但这会破坏主成分之间互不相关的性质需根据分析目的权衡。4. 基于MATLAB的PCA实现与对比虽然Python在数据科学领域风头正劲但MATLAB在工程、信号处理和教学领域依然有深厚的根基其内置的PCA函数也非常强大易用。这里我们实现同样的分析并对比两者异同。4.1 MATLAB核心代码实现在MATLAB中pca函数是核心。同样我们先模拟数据然后进行标准化和PCA分析。%% 1. 模拟数据 (与Python部分保持一致) rng(42); % 设置随机种子保证可复现 n_samples 300; X_base randn(n_samples, 2); X [X_base(:,1), ... 1.5 * X_base(:,1) 0.5 * X_base(:,2) 0.1 * randn(n_samples,1), ... X_base(:,2) 0.5 * randn(n_samples,1)]; fprintf(原始数据形状: %d x %d\n, size(X)); %% 2. 数据标准化 X_mean mean(X); X_std std(X); X_scaled (X - X_mean) ./ X_std; % Z-score标准化 %% 3. 执行PCA % coeff: 主成分系数载荷矩阵每一列是一个主成分的系数向量 % score: 主成分得分转换后的数据即原始数据在主成分上的投影 % latent: 主成分的方差特征值 % explained: 每个主成分解释的方差百分比 % ~: 忽略原始数据的均值因为我们已中心化 [coeff, score, latent, ~, explained] pca(X_scaled); fprintf(\n各主成分方差解释率:\n); for i 1:length(explained) fprintf( 主成分 %d: %.4f (%.2f%%)\n, i, latent(i)/sum(latent), explained(i)); end fprintf(\n累计方差解释率:\n); cum_explained cumsum(explained); for i 1:length(cum_explained) fprintf( 前 %d 个主成分: %.4f (%.2f%%)\n, i, cum_explained(i)/100, cum_explained(i)); end %% 4. 可视化 figure(Position, [100, 100, 1200, 400]); % 子图1原始三维数据 subplot(1,3,1); scatter3(X(:,1), X(:,2), X(:,3), 36, b, filled, MarkerFaceAlpha, 0.6); xlabel(Feature 1); ylabel(Feature 2); zlabel(Feature 3); title(Original 3D Data); grid on; view(30, 20); % 子图2PCA降维后的二维数据 subplot(1,3,2); scatter(score(:,1), score(:,2), 36, r, filled, MarkerFaceAlpha, 0.6); xlabel(sprintf(PC1 (%.1f%% Var), explained(1))); ylabel(sprintf(PC2 (%.1f%% Var), explained(2))); title(Data after PCA (2D)); grid on; axis equal; hline refline(0,0); hline.Color [.5 .5 .5 .3]; hline.LineStyle -; vline line([0 0], ylim); vline.Color [.5 .5 .5 .3]; vline.LineStyle -; % 子图3方差解释率碎石图 subplot(1,3,3); pareto(explained); xlabel(主成分); ylabel(方差解释率 (%)); title(Scree Plot (Variance Explained)); grid on; %% 5. 显示载荷矩阵 fprintf(\n主成分载荷矩阵coeff:\n); disp(每一列代表一个主成分每一行对应一个原始特征:); disp(coeff);4.2 Python与MATLAB的关键差异与注意事项虽然两者结果在数学上等价但在使用细节上有些差异需要注意数据标准化处理Python的StandardScaler和手动(X - mean)/std与MATLAB的zscore函数或手动计算效果一致。关键在于必须做。MATLAB的pca函数虽然提供了Centered选项但通常我们传入已标准化的数据更稳妥。输出结构的对应关系MATLAB的coeff对应Python的pca.components_.T。注意转置MATLAB的coeff是p x p矩阵每一列是一个主成分的系数向量。而sklearn的components_是n_components x n_features每一行是一个主成分。所以coeff(:,1)对应pca.components_[0, :]。MATLAB的score对应Python的X_pca即fit_transform的结果。这就是降维后的数据。MATLAB的latent对应Python的pca.explained_variance_。是特征值不是百分比。MATLAB的explained对应Python的pca.explained_variance_ratio_ * 100。是方差解释百分比。默认行为MATLAB的pca默认对数据中心化Centered为true但不进行标准化。Python的sklearn.decomposition.PCA默认只进行数据中心化通过svd_solver同样不进行缩放。因此在两者中显式地先进行标准化都是最佳实践。可视化工具MATLAB的绘图函数如scatter3,pareto集成度高语法简洁。Python的matplotlib功能强大但稍显繁琐不过结合seaborn等库可以做出更美观的图表。踩坑记录我曾在一个跨平台项目中将Python中训练好的PCA模型包含components_用于MATLAB环境下的推理。最大的坑就在于系数矩阵的朝向行主序 vs 列主序以及components_的格式。最后统一约定在接口处始终将主成分向量保存为列向量组成的矩阵并在文档中明确说明避免了后续很多麻烦。5. 主成分数量选择理论与实用方法到底保留几个主成分这是一个没有标准答案但必须回答的问题。保留太少信息损失大保留太多则降维意义不大。下面介绍几种常用方法。5.1 碎石图法碎石图是最直观的方法。它将每个主成分的方差或方差解释率从大到小绘制成折线图形状像一座“山”和一条长长的“尾巴”。我们寻找“肘部”点即折线从陡峭突然变得平缓的转折点。这个点之前的主成分被认为携带了大部分信息。# Python 碎石图 plt.figure(figsize(8,5)) plt.plot(range(1, len(explained_variance_ratio)1), explained_variance_ratio, bo-, linewidth2, markersize8) plt.plot(range(1, len(cumulative_variance_ratio)1), cumulative_variance_ratio, rs--, linewidth2, markersize8) plt.xlabel(主成分数量) plt.ylabel(方差解释率) plt.title(PCA Scree Plot) plt.legend([各成分解释率, 累计解释率]) plt.grid(True, alpha0.3) plt.axhline(y0.95, colorg, linestyle:, alpha0.7, label95%阈值) plt.axhline(y0.85, colory, linestyle:, alpha0.7, label85%阈值) plt.legend() plt.show()在MATLAB中使用pareto(explained)可以快速绘制类似的帕累托图。5.2 累计方差贡献率阈值法这是最常用的经验法则。设定一个阈值如80%、90%或95%然后选择累计方差贡献率大于等于该阈值的最小主成分数量k。在我们的模拟数据中要达到95%的累计解释率需要2个主成分。这种方法简单粗暴在工程上很受欢迎因为它给出了一个明确的目标。# Python 计算达到阈值所需的主成分数 threshold 0.95 n_components_threshold np.argmax(cumulative_variance_ratio threshold) 1 print(f要达到 {threshold*100:.0f}% 的累计方差解释率需要 {n_components_threshold} 个主成分。)5.3 特征值大于1准则在基于相关矩阵进行PCA时即数据已标准化Kaiser准则建议保留特征值大于1的主成分。因为标准化后每个原始变量的方差为1如果一个主成分的特征值小于1说明它解释的方差还不如一个原始变量保留的意义不大。这个方法在心理学、社会学等领域的因子分析中常用但在纯PCA中也可作为参考。# 假设我们基于相关矩阵标准化数据等价于相关矩阵特征值就是 latent (Python中是 explained_variance_) eigenvalues pca_full.explained_variance_ # 这是特征值 n_components_kaiser np.sum(eigenvalues 1) print(f根据特征值1准则(Kaiser)建议保留 {n_components_kaiser} 个主成分。)5.4 交叉验证法对于后续要将降维数据用于预测模型如回归、分类的场景最严谨的方法是使用交叉验证。将数据分为训练集和验证集在训练集上做PCA降维用不同数量的主成分训练模型然后在验证集上评估模型性能如准确率、均方误差选择性能最佳或性能不再显著提升时对应的主成分数量。sklearn的Pipeline可以很方便地实现这一点。个人经验在实际项目中我通常会综合使用以上方法。首先看碎石图找“肘点”然后看累计贡献率通常85%-95%是个合理范围再结合特征值1准则。最重要的是一定要结合业务目标。如果降维是为了三维可视化那k显然只能是2或3。如果是为了给后续模型输入特征我会用交叉验证来最终确定。没有最好的方法只有最适合当前场景的方法。6. PCA的常见应用场景与高级技巧PCA远不止是降维工具理解其应用场景能让你在更多地方想到它、用好它。6.1 数据可视化这是PCA最经典的应用。将高维数据降至2维或3维用散点图展示可以直观观察数据分布、聚类情况或异常点。在探索性数据分析阶段无比有用。6.2 数据压缩与去噪PCA通过保留主要成分、舍弃次要成分实现了有损压缩。被舍弃的成分往往包含大量噪声。因此PCA也是一种有效的去噪方法。在图像处理中对图像块进行PCA可以去除随机噪声在信号处理中可以滤除高频干扰。# Python 示例使用PCA进行图像压缩/重建 from sklearn.datasets import fetch_olivetti_faces from sklearn.decomposition import PCA # 加载人脸数据集 faces_data fetch_olivetti_faces(shuffleTrue, random_state42) X_faces faces_data.data # 形状 (400, 4096)400张64x64的人脸图 # 使用不同数量的主成分进行重建 n_components_list [10, 50, 100, 200] fig, axes plt.subplots(2, 5, figsize(12, 6)) original_face X_faces[0].reshape(64, 64) # 显示原图 axes[0, 0].imshow(original_face, cmapgray) axes[0, 0].set_title(Original) axes[0, 0].axis(off) for idx, n_comp in enumerate(n_components_list): pca_face PCA(n_componentsn_comp, random_state42) X_faces_pca pca_face.fit_transform(X_faces) X_faces_reconstructed pca_face.inverse_transform(X_faces_pca) reconstructed_face X_faces_reconstructed[0].reshape(64, 64) row (idx 1) // 5 col (idx 1) % 5 axes[row, col].imshow(reconstructed_face, cmapgray) axes[row, col].set_title(fn{n_comp}\n({pca_face.explained_variance_ratio_.sum():.1%})) axes[row, col].axis(off) plt.suptitle(PCA Image Reconstruction with Different Components, fontsize14) plt.tight_layout() plt.show()6.3 特征工程与共线性消除在建立回归或分类模型前如果特征间存在多重共线性会导致模型不稳定、系数难以解释。PCA可以将相关的原始特征转换为一组不相关的主成分作为新的特征输入模型。这能稳定模型但代价是主成分失去了原始特征的实际意义可解释性变差。6.4 异常检测在主成分空间中正常数据点通常会聚集在由前几个主成分张成的子空间附近。如果一个数据点在某个次要主成分通常代表噪声或特殊变异上有异常大的投影得分即该主成分的得分绝对值很大那么这个点很可能是一个异常点。这种方法在工业过程监控、金融欺诈检测中很有效。6.5 核PCA处理非线性问题标准PCA只能捕捉数据的线性结构。如果数据存在于非线性流形上比如瑞士卷数据集线性PCA就无能为力了。这时可以使用核PCA。它通过一个核函数先将数据隐式地映射到一个高维特征空间然后在这个高维空间中进行线性PCA从而在原始空间中实现非线性的降维。# Python 示例对比线性PCA与核PCA在非线性数据上的效果 from sklearn.decomposition import KernelPCA from sklearn.datasets import make_swiss_roll # 生成瑞士卷数据 X_swiss, _ make_swiss_roll(n_samples1000, noise0.1, random_state42) # 线性PCA pca_linear PCA(n_components2) X_swiss_pca_linear pca_linear.fit_transform(X_swiss) # 核PCA (使用RBF核) kpca_rbf KernelPCA(n_components2, kernelrbf, gamma0.04, fit_inverse_transformTrue) X_swiss_kpca_rbf kpca_rbf.fit_transform(X_swiss) # 可视化 fig, (ax1, ax2) plt.subplots(1, 2, figsize(12, 5)) ax1.scatter(X_swiss_pca_linear[:, 0], X_swiss_pca_linear[:, 1], c_/10, cmapplt.cm.Spectral, alpha0.7) ax1.set_title(Linear PCA on Swiss Roll) ax1.set_xlabel(PC1) ax1.set_ylabel(PC2) ax2.scatter(X_swiss_kpca_rbf[:, 0], X_swiss_kpca_rbf[:, 1], c_/10, cmapplt.cm.Spectral, alpha0.7) ax2.set_title(Kernel PCA (RBF) on Swiss Roll) ax2.set_xlabel(PC1) ax2.set_ylabel(PC2) plt.tight_layout() plt.show()你会看到线性PCA只是将三维的瑞士卷“压扁”成一个二维椭圆丢失了卷状结构。而核PCA则成功地将卷“展开”成了一个二维平面更好地保留了数据的本质结构。7. 实战避坑指南与高级注意事项掌握了基本流程后一些细节和陷阱决定了你是“会用”还是“精通”PCA。7.1 标准化何时用何时不用必须标准化使用相关矩阵的情况当特征的单位或量纲不同时。例如数据集包含“年龄岁”和“收入元”。收入的方差会远远大于年龄导致PCA完全被收入主导。标准化使所有特征处于同一尺度。可以考虑不标准化使用协方差矩阵的情况当所有特征单位相同且你希望保留各特征原始方差的重要性时。例如所有特征都是同一传感器在不同位置测得的同一种物理量如温度单位都是摄氏度。这时方差大的特征可能确实代表了更重要的变异源。7.2 缺失值处理PCA要求数据矩阵是完整的。常见的处理方法有直接删除如果缺失值很少可以直接删除含有缺失值的样本或特征。均值/中位数填补用该特征的均值或中位数填补缺失值。简单但可能扭曲特征分布。迭代插补更稳健的方法如使用sklearn.impute.IterativeImputer它通过其他特征来建模并预测缺失值。适用于PCA的特定方法有些算法如Probabilistic PCA或SVD的变体可以处理缺失值但实现更复杂。7.3 主成分的解释与命名难题这是PCA最大的弱点之一。主成分是原始特征的线性组合失去了直接物理意义。例如一个主成分可能是0.6*身高 0.5*体重 - 0.3*年龄这很难赋予一个直观的名字。为了改善可解释性可以检查载荷矩阵找出对某个主成分贡献最大绝对值最大的几个原始特征用它们来命名该主成分如“体型因子”。进行因子旋转如方差最大化旋转使载荷矩阵的系数更趋向于0或±1简化结构便于解释。但这会牺牲主成分之间不相关的性质。在Python中可以使用factor_analyzer库的Rotator类。7.4 样本量要求一个经验法则是样本数n应至少是变量数p的5到10倍。如果p远大于n高维小样本问题协方差矩阵的估计会非常不准确PCA结果可能不稳定。此时可以考虑正则化方法或者使用专门针对高维数据的算法。7.5 PCA不是聚类分析虽然PCA降维后的图经常能显示出数据的聚类结构但PCA本身不是聚类算法。它的目标是最大化方差而不是最小化类内距离。如果目的是聚类应该在降维后使用K-Means、DBSCAN等真正的聚类算法或者直接在高维数据上聚类。7.6 逆变换与数据重构sklearn的PCA对象提供了inverse_transform方法可以将降维后的数据X_pca近似地重构回原始空间。这在数据压缩、去噪后查看效果时非常有用。但记住这是有损重构信息已经丢失。# 重构数据 X_reconstructed pca.inverse_transform(X_pca) # 计算重构误差 reconstruction_error np.mean((X_scaled - X_reconstructed) ** 2) print(f均方重构误差: {reconstruction_error:.6f})7.7 在大数据集上的应用对于海量数据完整的SVD计算可能非常慢。此时可以使用sklearn.decomposition.PCA的svd_solverrandomized参数。它使用随机算法来近似计算前k个主成分速度更快尤其适用于n_samples或n_features很大的情况。考虑增量PCAIncrementalPCA用于无法一次性装入内存的数据集。一个真实的坑我曾经用PCA处理一批光谱数据有500个样本每个样本有3000个波长特征。我忘了标准化结果前两个主成分几乎完全由两个噪声较大的高频波段主导整个分析结果毫无意义。重新标准化后前几个主成分才对应了有化学意义的基团吸收峰。这个教训让我至今在做PCA前都会条件反射般地检查数据尺度。