/edit: 现在进一步跟进你可以使用irlba::prcomp_irlba
/编辑:跟进我自己的帖子。 irlba
现在有 "center" 和 "scale" 参数,可让您使用它来计算主成分,例如:
pc <- M %*% irlba(M, nv=5, nu=0, center=colMeans(M), right_only=TRUE)$v
Matrix
我想在机器学习算法中使用大量稀疏的特征:
library(Matrix)
set.seed(42)
rows <- 500000
cols <- 10000
i <- unlist(lapply(1:rows, function(i) rep(i, sample(1:5,1))))
j <- sample(1:cols, length(i), replace=TRUE)
M <- sparseMatrix(i, j)
因为这个矩阵有很多列,所以我想将它的维数减少到更易于管理的程度。我可以使用出色的irlba 包来执行 SVD 并返回前 n 个主成分(此处显示 5;我可能会在我的实际数据集上使用 100 或 500):
library(irlba)
pc <- irlba(M, nu=5)$u
但是,我已经读过,在执行 PCA 之前,应该将矩阵居中(从每一列中减去列平均值)。这在我的数据集上很难做到,而且会破坏矩阵的稀疏性。
对未缩放的数据执行 SVD 并将其直接输入机器学习算法有多“糟糕”?有没有什么有效的方法可以缩放这些数据,同时保持矩阵的稀疏性?
/edit:B_miner 引起了我的注意,“PC”应该是:
pc <- M %*% irlba(M, nv=5, nu=0)$v
另外,我认为 whuber 的答案应该很容易通过crossprod
函数实现,这在稀疏矩阵上非常快:
system.time(M_Mt <- crossprod(M)) # 0.463 seconds
system.time(means <- colMeans(M)) #0.003 seconds
现在我不太确定means
在从 中减去之前要对向量做什么M_Mt
,但我一弄明白就会发布。
/edit3:这是 whuber 代码的修改版本,对过程的每个步骤使用稀疏矩阵运算。 如果您可以将整个稀疏矩阵存储在内存中,它的工作速度非常快:
library('Matrix')
library('irlba')
set.seed(42)
m <- 500000
n <- 100
i <- unlist(lapply(1:m, function(i) rep(i, sample(25:50,1))))
j <- sample(1:n, length(i), replace=TRUE)
x <- sparseMatrix(i, j, x=runif(length(i)))
n_comp <- 50
system.time({
xt.x <- crossprod(x)
x.means <- colMeans(x)
xt.x <- (xt.x - m * tcrossprod(x.means)) / (m-1)
svd.0 <- irlba(xt.x, nu=0, nv=n_comp, tol=1e-10)
})
#user system elapsed
#0.148 0.030 2.923
system.time(pca <- prcomp(x, center=TRUE))
#user system elapsed
#32.178 2.702 12.322
max(abs(pca$center - x.means))
max(abs(xt.x - cov(as.matrix(x))))
max(abs(abs(svd.0$v / pca$rotation[,1:n_comp]) - 1))
如果将列数设置为 10,000,主成分数设置为 25,则irlba
基于 - 的 PCA 大约需要 17 分钟来计算 50 个近似主成分,并且消耗大约 6GB 的 RAM,这还不错。