繁体   English   中英

R - `prcomp`将样本数据或协方差矩阵作为输入吗?

[英]R - does `prcomp` take sample data or covariance matrices as input?

如果你在网上搜索,有几个线程讨论在函数princomp使用covmat标志,该函数对其输入执行主成分分析。 如果covmat参数,则princomp首先计算输入的样本协方差矩阵。

另一方面,几乎没有讨论类似的函数prcomp实际上为完成数据的主成分分析任务做了什么,只讨论它是否比princomp更准确。 这引出了一个问题: prcomp将协方差矩阵或样本数据矩阵作为输入? 从帮助文档中可以看出哪些状态(在非公式上下文中):

默认S3方法:

prcomp(x, retx = TRUE, center = TRUE, scale. = FALSE, tol = NULL, ...)

x - 为主成分分析提供数据的数字或复杂矩阵(或数据框)。

帮助文件不包含此方法的任何示例,只是上面记录的一个示例,它适用于公式对象。 文档类型暗示预期输入是协方差矩阵,如下所示:

通过(居中的和可能缩放的)数据矩阵的奇异值分解来完成计算,而不是通过在协方差矩阵上使用eigen来完成。

但是,不清楚“数据矩阵”是否是“协方差矩阵”,“数据矩阵”是否表示文档前面部分给出的x

幸运的是,答案可以在两个函数的源代码中找到。

首先, prcomp的来源:

> stats:::prcomp.default
function (x, retx = TRUE, center = TRUE, scale. = FALSE, tol = NULL, 
    ...) 
{
    x <- as.matrix(x)
    x <- scale(x, center = center, scale = scale.)
    cen <- attr(x, "scaled:center")
    sc <- attr(x, "scaled:scale")
    if (any(sc == 0)) 
        stop("cannot rescale a constant/zero column to unit variance")
    s <- svd(x, nu = 0)
    s$d <- s$d/sqrt(max(1, nrow(x) - 1))
    if (!is.null(tol)) {
        rank <- sum(s$d > (s$d[1L] * tol))
        if (rank < ncol(x)) {
            s$v <- s$v[, 1L:rank, drop = FALSE]
            s$d <- s$d[1L:rank]
        }
    }
    dimnames(s$v) <- list(colnames(x), paste0("PC", seq_len(ncol(s$v))))
    r <- list(sdev = s$d, rotation = s$v, center = if (is.null(cen)) FALSE else cen, 
        scale = if (is.null(sc)) FALSE else sc)
    if (retx) 
        r$x <- x %*% s$v
    class(r) <- "prcomp"
    r
}

请注意,上部块中没有执行协方差计算。 对所提供的输入执行缩放和居中操作,此时对结果调用奇异值分解(SVD)函数。 下一步是根据结果对角化的等级检查结果的大小,以确保结果有效。 最后,输出格式化并设置为适当的类。

换句话说, prcomp是在协方差矩阵上简单调用SVD的一个很好的改进,但不会为你计算协方差矩阵。 prcomp不是在数据上调用的,它是在某些数据的协方差 一些提供的估计上调用的。

编辑:被删除的句子是错误的! 在这种情况下没有必要形成协方差矩阵,如果我戴上数学帽,我就会意识到这一点! 有关解释原因,请参阅此math.SO线程 在数据矩阵上使用SVD计算主成分在这里肯定更有效。

princomp的代码(仅显示部分)进行比较:

if (is.list(covmat)) {
    if (any(is.na(match(c("cov", "n.obs"), names(covmat))))) 
        stop("'covmat' is not a valid covariance list")
    cv <- covmat$cov
    n.obs <- covmat$n.obs
    cen <- covmat$center
}
else if (is.matrix(covmat)) {
    if (!missing(x)) 
        warning("both 'x' and 'covmat' were supplied: 'x' will be ignored")
    cv <- covmat
    n.obs <- NA
    cen <- NULL
}
else if (is.null(covmat)) {
    dn <- dim(z)
    if (dn[1L] < dn[2L]) 
        stop("'princomp' can only be used with more units than variables")
    covmat <- cov.wt(z)
    n.obs <- covmat$n.obs
    cv <- covmat$cov * (1 - 1/n.obs)
    cen <- covmat$center
}

正如您所看到的, princomp函数可以执行更多操作,具体取决于输入的传递方式,这需要更多的注意。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM