这是一个快速演练。首先,我们创建一个隐藏变量(或“因素”)的矩阵。它有 100 个观测值,有两个独立因素。
>> factors = randn(100, 2);
现在创建一个载荷矩阵。这会将隐藏变量映射到您观察到的变量上。假设您观察到的变量有四个特征。那么你的载荷矩阵需要是4 x 2
>> loadings = [
1 0
0 1
1 1
1 -1 ];
这告诉您第一个因子上的第一个观察到的变量负载,第二个因子上的第二个变量负载,因子之和上的第三个变量负载以及因子之差上的第四个变量负载。
现在创建您的观察结果:
>> observations = factors * loadings' + 0.1 * randn(100,4);
我添加了少量随机噪声来模拟实验误差。现在我们使用以下命令执行 PCApca
统计工具箱中的函数:
>> [coeff, score, latent, tsquared, explained, mu] = pca(observations);
变量score
是主成分分数的数组。这些将通过构造正交,您可以检查 -
>> corr(score)
ans =
1.0000 0.0000 0.0000 0.0000
0.0000 1.0000 0.0000 0.0000
0.0000 0.0000 1.0000 0.0000
0.0000 0.0000 0.0000 1.0000
组合score * coeff'
将重现您的观察结果的中心版本。均值mu
在执行 PCA 之前减去。要重现您的原始观察结果,您需要将其添加回来,
>> reconstructed = score * coeff' + repmat(mu, 100, 1);
>> sum((observations - reconstructed).^2)
ans =
1.0e-27 *
0.0311 0.0104 0.0440 0.3378
要获得原始数据的近似值,您可以开始从计算的主成分中删除列。为了了解要删除哪些列,我们检查explained
多变的
>> explained
explained =
58.0639
41.6302
0.1693
0.1366
这些条目告诉您每个主成分解释了多少方差百分比。我们可以清楚地看到前两个分量比后两个分量更显着(它们解释了它们之间 99% 以上的方差)。使用前两个分量重建观测值给出了 2 阶近似值,
>> approximationRank2 = score(:,1:2) * coeff(:,1:2)' + repmat(mu, 100, 1);
我们现在可以尝试绘制:
>> for k = 1:4
subplot(2, 2, k);
hold on;
grid on
plot(approximationRank2(:, k), observations(:, k), 'x');
plot([-4 4], [-4 4]);
xlim([-4 4]);
ylim([-4 4]);
title(sprintf('Variable %d', k));
end
我们几乎完美地再现了原始观察结果。如果我们想要更粗略的近似,我们可以只使用第一个主成分:
>> approximationRank1 = score(:,1) * coeff(:,1)' + repmat(mu, 100, 1);
并绘制它,
>> for k = 1:4
subplot(2, 2, k);
hold on;
grid on
plot(approximationRank1(:, k), observations(:, k), 'x');
plot([-4 4], [-4 4]);
xlim([-4 4]);
ylim([-4 4]);
title(sprintf('Variable %d', k));
end
这次重建的情况不太好。这是因为我们故意将数据构建为具有两个因素,而我们只是根据其中之一来重建数据。
请注意,尽管我们构建原始数据及其再现的方式之间存在暗示性相似性,
>> observations = factors * loadings' + 0.1 * randn(100,4);
>> reconstructed = score * coeff' + repmat(mu, 100, 1);
之间并不一定存在对应关系factors
and score
,或之间loadings
and coeff
。 PCA 算法对数据的构建方式一无所知 - 它只是尝试尽可能多地解释每个连续分量的总方差。
用户@Mari 在评论中询问她如何将重建误差绘制为主成分数量的函数。使用变量explained
上面这个就很简单了。我将生成一些具有更有趣的因子结构的数据来说明效果 -
>> factors = randn(100, 20);
>> loadings = chol(corr(factors * triu(ones(20))))';
>> observations = factors * loadings' + 0.1 * randn(100, 20);
现在,所有观察结果都集中在一个显着的公因子上,而其他因素的重要性逐渐降低。我们可以像之前一样得到PCA分解
>> [coeff, score, latent, tsquared, explained, mu] = pca(observations);
并绘制解释方差的百分比如下,
>> cumexplained = cumsum(explained);
cumunexplained = 100 - cumexplained;
plot(1:20, cumunexplained, 'x-');
grid on;
xlabel('Number of factors');
ylabel('Unexplained variance')