为什么稀疏 PCA R 包的结果如此糟糕?

机器算法验证 r 主成分分析
2022-04-06 00:11:35

我正准备使用 R 对我的数据进行稀疏分析。我试图从一个特别的例子开始,但重建结果真的很差。我想知道我是否在代码中犯了任何错误,或者我是否遇到了该方法的任何内在缺陷?

数据是临时的:

> prod
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    1    1    1    2
[2,]    1    2    1    2    3
[3,]    0    1    0    1    1
[4,]    0    0    1    1    1
[5,]    0    1    0    1    1

我用这个

rst = nsprcomp(prod, retx=T, nneg=T)

执行非负稀疏 PCA。

我像这样重建数据:

recon = rst$x %*% t(rst$rotation) + matrix(1,5,1) %*% rst$center

最后的结果真的很差:

> abs(prod - recon)
            [,1]      [,2]      [,3]      [,4]      [,5]
[1,] 0.386523767 0.2432819 0.1186152 0.3535836 0.3770144
[2,] 0.184944985 1.1214659 0.6230812 1.2173770 1.8819417
[3,] 0.096185913 0.4301642 0.2249522 0.4825192 0.6942987
[4,] 0.009206957 0.5044193 0.2917920 0.6059221 0.8703587
[5,] 0.096185913 0.4301642 0.2249522 0.4825192 0.6942987

任何想法或评论表示赞赏。

编辑

该软件包称为nsprcomp

2个回答

nsprcomp计算分数矩阵 Z (rst$x在您的示例中)为Z=XW, 在哪里X是数据矩阵(prod在您的示例中)和W是主轴矩阵(rst$rotation在您的示例中)。这符合标准 PCA 和predict.prcomp接口。

然而,非负稀疏 PCA 通常会导致主轴不是成对正交的,因此重建

X^=ZWt=XWWt

没有恢复X即使W有满秩,因为W不是正交矩阵。如果您使用伪逆进行重构W=(WtW)1Wt反而,

X^2=ZW=XW(WtW)1Wt

对应于的正交投影X到跨越的主子空间W, 并恢复X如果W满级:

library(MASS)
recon2 = predict(rst) %*% ginv(rst$rotation) + matrix(1,5,1) %*% rst$center
abs(prod - recon2)
             [,1]         [,2]         [,3]         [,4]         [,5]
[1,] 4.440892e-16 4.440892e-16 2.220446e-16 8.881784e-16 2.220446e-16
[2,] 4.440892e-16 1.332268e-15 0.000000e+00 1.998401e-15 4.440892e-16
[3,] 1.110223e-16 4.440892e-16 2.220446e-16 4.440892e-16 2.220446e-16
[4,] 3.330669e-16 4.440892e-16 2.220446e-16 2.220446e-16 0.000000e+00
[5,] 1.110223e-16 4.440892e-16 2.220446e-16 4.440892e-16 2.220446e-16

我将相应地修改文档。

@Marc:nneg=TRUE强制执行非负载荷,即主轴被限制为非负正数。

nneg=TRUE您的代码看起来可以重构,但是当参数(“指示主轴是否应约束为非负正数的逻辑值”)时,这似乎不合适当此参数设置为 FALSE 时,重建将以典型方式进行:

rst.f = nsprcomp(prod, retx=T, nneg=FALSE)
recon = rst.f$x %*% t(rst.f$rotation) + matrix(1,5,1) %*% rst.f$center
abs(prod - recon)
             [,1]         [,2]         [,3]         [,4] [,5]
[1,] 1.110223e-16 1.110223e-16 0.000000e+00 2.220446e-16    0
[2,] 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00    0
[3,] 5.551115e-17 0.000000e+00 2.220446e-16 2.220446e-16    0
[4,] 0.000000e+00 4.440892e-16 0.000000e+00 2.220446e-16    0
[5,] 5.551115e-17 0.000000e+00 2.220446e-16 2.220446e-16    0

抱歉,我不能对“非负正弦”选项的使用发表更多评论。

我还可能会指出,您的示例并未真正使用“稀疏”矩阵。但是这种方法确实可以很好地处理这些对象:

require(Matrix)
prod <- replace(prod, prod==0, NaN)
tmp <- cbind(expand.grid(i=seq(nrow(prod)), j=seq(ncol(prod))), p=c(prod))[-which(is.na(c(prod))),]
prod2 <- sparseMatrix(i=tmp$i, j=tmp$j, x=tmp$p)
    rst.f = nsprcomp(prod2, retx=T, nneg=FALSE)
    recon = rst.f$x %*% t(rst.f$rotation) + matrix(1,5,1) %*% rst.f$center
abs(prod2 - recon)
5 x 5 sparse Matrix of class "dgCMatrix"

[1,] 2.220446e-16 1.110223e-16 .            .            .
[2,] 2.220446e-16 4.440892e-16 .            .            .
[3,] 1.110223e-16 2.220446e-16 2.220446e-16 2.220446e-16 .
[4,] .            .            .            .            .
[5,] 1.110223e-16 2.220446e-16 2.220446e-16 2.220446e-16 .