julia - 如何在不使用协方差矩阵的情况下快速找到第一个主成分(和载荷)?

标签 julia pca

我有一个矩阵 $X$,我想找到它的第一个主成分和相应的载荷。我想在不计算 $X$ 的协方差矩阵的情况下执行此操作。我怎样才能这样做?

这是标准版本,它使用协方差矩阵的特征分解。

using LinearAlgebra: eigen
using Statistics: mean

function find_principal_component(X)
    n = size(X, 1)
    B = X .- mapslices(mean, X, dims=[1])     # Center columns of X
    evalues, V = eigen(B'B / (n - 1))         # EigenDecomposition of Covariance Matrix     
    PC = V[:, argmax(evalues)]                # Grab principal component and compute loading
    return B * PC, PC
end

或者,可以使用幂方法,它仍然使用协方差矩阵

function power_method(X, niter=50)
    pc = randn(size(X, 2))
    pc /= norm(pc)
    M = X'X
    for i in 1:niter
        pc = M * pc
        pc /= norm(pc)
    end
    return X * pc, pc
end     

我想要类似幂方法的方法,但不需要计算协方差矩阵,这可能会非常昂贵。

可能的解决方案

我注意到一些有趣的事情。让r_tt 时刻的主分量向量。幂法的思想是从随机r_t开始并将其乘以 X' X多次将其拉伸(stretch)向主成分。换句话说r_{t+1} = X' X r_t 一旦我们有了主成分r_t那么负载就是\ell_t = X r_t 。这意味着我们可以写 r_{t+1} = X^\top \ell_t 因此,可以从 r_t 开始和\ell_t随机初始化然后执行

r_{t+1} = normalize(X^\top \ell_t)\\
\ell_{t+1} = X r_{t+1}

最佳答案

一般来说,您可能会发现奇异值分解对此更有用。

奇异值分解的定义为

B = U Σ V'

这意味着

B'B = V Σ² V'

因此,您的代码可以避免 B'B 的计算。更重要的是,奇异值始终是实数,因此您不必担心 B'B 是否完全对称。

更好的是,Arpack.svds 允许您计算最大的几个奇异值。

这是使用 SVD 而不是特征分解的代码版本:

using LinearAlgebra: eigen
using Statistics: mean
using Arpack: svds

function find_principal_component(X)
    n = size(X, 1)
    # Center columns of X
    B = X .- mapslices(mean, X, dims=[1]) 
    # Decomposition of Covariance Matrix
    svd,_ = svds(B / (n - 1), nsv=1)        
    # Grab principal component and compute loading
    PC = svd.V[:, 1]
    return B * PC, PC
end

在一个大型稀疏矩阵(100k x 1k,1M 非零)上运行它可以得到这样的速度:

julia> @time find_principal_component(sprandn(100_000, 1_000, 0.01))
 25.529426 seconds (18.45 k allocations: 3.015 GiB, 0.02% gc time)
([0.014242904195824286, 0.10635817357717596, -0.010142643763158442, ...])

在一个大型非稀疏示例(1M x 100 个条目)上:

julia> @time find_principal_component(randn(1_000_000, 100))
  4.922949 seconds (1.31 k allocations: 2.280 GiB, 0.02% gc time)
([-0.06629858174095249, 0.6996443876327108, -1.1783642870384952, ...])

关于julia - 如何在不使用协方差矩阵的情况下快速找到第一个主成分(和载荷)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70201987/

相关文章:

algorithm - 旅行商-限制长度

r - 如何使用 Tidymodels 获取 PCA 累积比例?

c++ - Julia 表演建议

julia - 使用非数值轴绘制数据集

r - 如何更改ggbiplot中椭圆的线型?

python - 对矩阵使用降维

python - 计算协方差矩阵——numpy.cov 和 numpy.dot 之间的区别?

python - 在 Python 中分解三阶张量

julia - 优化 : InexactError: Int64(0. 01) 使用 IPNewton 时

julia - Julia 中的复制和深复制有什么区别?