/ редагувати: подальше спостереження зараз ви можете використовувати irlba :: prcomp_irlba
/ редагувати: слідкувати за моєю власною публікацією. irlba
тепер є аргументи "центр" і "шкала", які дозволяють використовувати його для обчислення основних компонентів, наприклад:
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 на немасштабованих даних і подавати їх прямо в алгоритм машинного навчання? Чи є якісь ефективні способи я міг масштабувати ці дані, зберігаючи рідкість матриці?
/ редагувати: До мене звернув увагу B_miner, "ПК" справді має бути:
pc <- M %*% irlba(M, nv=5, nu=0)$v
Крім того, я вважаю, що відповідь Ваубера має бути досить простою у здійсненні за допомогою 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 приблизних основних компонентів і витрачає близько 6 ГБ оперативної пам’яті, що не так вже й погано.
X %*% v %*% diag(d, ncol=length(d))
. Матриця v в svd еквівалентна елементу "обертання" prcomp
об'єкта та X %*% v
або X %*% v %*% diag(d, ncol=length(d))
являє собою x
елемент prcomp
об'єкта. Погляньте а stats:::prcomp.default
.