Title: | The Variational Bayesian Method for Sparse PCA |
---|---|
Description: | Contains functions for a variational Bayesian method for sparse PCA proposed by Ning (2020) <arXiv:2102.00305>. There are two algorithms: the PX-CAVI algorithm (if assuming the loadings matrix is jointly row-sparse) and the batch PX-CAVI algorithm (if without this assumption). The outputs of the main function, VBsparsePCA(), include the mean and covariance of the loadings matrix, the score functions, the variable selection results, and the estimated variance of the random noise. |
Authors: | Bo (Yu-Chien) Ning |
Maintainer: | Bo (Yu-Chien) Ning <[email protected]> |
License: | GPL-3 |
Version: | 0.1.0 |
Built: | 2024-11-05 03:11:07 UTC |
Source: | https://github.com/bo-ning/vbsparsepca |
This function calculates the mean of the folded normal distribution given its location and scale parameters.
foldednorm.mean(mean, var)
foldednorm.mean(mean, var)
mean |
Location parameter of the folded normal distribution. |
var |
Scale parameter of the folded normal distribution. |
The mean of the folded normal distribution with location and scale
is
.
foldednorm.mean |
The mean of the folded normal distribution of iterations to reach convergence. |
#Calculates the mean of the folded normal distribution with mean 0 and var 1 mean <- foldednorm.mean(0, 1) print(mean)
#Calculates the mean of the folded normal distribution with mean 0 and var 1 mean <- foldednorm.mean(0, 1) print(mean)
This function employs the PX-CAVI algorithm proposed in Ning (2020).
The in the slab density of the spike and slab prior is chosen to be the Laplace density, i.e.,
.
Details of the model and the prior can be found in the Details section in the description of the 'VBsparsePCA()' function.
This function is not capable of handling the case when r > 1. In that case, we recommend to use the multivariate distribution instead.
spca.cavi.Laplace( x, r = 1, lambda = 1, max.iter = 100, eps = 0.001, sig2.true = NA, threshold = 0.5, theta.int = NA, theta.var.int = NA, kappa.para1 = NA, kappa.para2 = NA, sigma.a = NA, sigma.b = NA )
spca.cavi.Laplace( x, r = 1, lambda = 1, max.iter = 100, eps = 0.001, sig2.true = NA, threshold = 0.5, theta.int = NA, theta.var.int = NA, kappa.para1 = NA, kappa.para2 = NA, sigma.a = NA, sigma.b = NA )
x |
Data an |
r |
Rank. |
lambda |
Tuning parameter for the density |
max.iter |
The maximum number of iterations for running the algorithm. |
eps |
The convergence threshold; the default is |
sig2.true |
The default is false, |
threshold |
The threshold to determine whether |
theta.int |
The initial value of theta mean; if not provided, the algorithm will estimate it using PCA. |
theta.var.int |
The initial value of theta.var; if not provided, the algorithm will set it to be 1e-3*diag(r). |
kappa.para1 |
The value of |
kappa.para2 |
The value of |
sigma.a |
The value of |
sigma.b |
The value of |
iter |
The number of iterations to reach convergence. |
selection |
A vector (if |
theta.mean |
The loadings matrix. |
theta.var |
The covariance of each non-zero rows in the loadings matrix. |
sig2 |
Variance of the noise. |
obj.fn |
A vector contains the value of the objective function of each iteration. It can be used to check whether the algorithm converges |
#In this example, the first 20 rows in the loadings matrix are nonzero, the rank is 1 set.seed(2021) library(MASS) library(pracma) n <- 200 p <- 1000 s <- 20 r <- 1 sig2 <- 0.1 # generate eigenvectors U.s <- randortho(s, type = c("orthonormal")) U <- rep(0, p) U[1:s] <- as.vector(U.s[, 1:r]) s.star <- rep(0, p) s.star[1:s] <- 1 eigenvalue <- seq(20, 10, length.out = r) # generate Sigma theta.true <- U * sqrt(eigenvalue) Sigma <- tcrossprod(theta.true) + sig2*diag(p) # generate n*p dataset X <- t(mvrnorm(n, mu = rep(0, p), Sigma = Sigma)) result <- spca.cavi.Laplace(x = X, r = 1) loadings <- result$theta.mean
#In this example, the first 20 rows in the loadings matrix are nonzero, the rank is 1 set.seed(2021) library(MASS) library(pracma) n <- 200 p <- 1000 s <- 20 r <- 1 sig2 <- 0.1 # generate eigenvectors U.s <- randortho(s, type = c("orthonormal")) U <- rep(0, p) U[1:s] <- as.vector(U.s[, 1:r]) s.star <- rep(0, p) s.star[1:s] <- 1 eigenvalue <- seq(20, 10, length.out = r) # generate Sigma theta.true <- U * sqrt(eigenvalue) Sigma <- tcrossprod(theta.true) + sig2*diag(p) # generate n*p dataset X <- t(mvrnorm(n, mu = rep(0, p), Sigma = Sigma)) result <- spca.cavi.Laplace(x = X, r = 1) loadings <- result$theta.mean
This function employs the PX-CAVI algorithm proposed in Ning (2020).
The in the slab density of the spike and slab prior is chosen to be the multivariate normal distribution, i.e.,
.
Details of the model and the prior can be found in the Details section in the description of the 'VBsparsePCA()' function.
spca.cavi.mvn( x, r, lambda = 1, max.iter = 100, eps = 1e-04, jointly.row.sparse = TRUE, sig2.true = NA, threshold = 0.5, theta.int = NA, theta.var.int = NA, kappa.para1 = NA, kappa.para2 = NA, sigma.a = NA, sigma.b = NA )
spca.cavi.mvn( x, r, lambda = 1, max.iter = 100, eps = 1e-04, jointly.row.sparse = TRUE, sig2.true = NA, threshold = 0.5, theta.int = NA, theta.var.int = NA, kappa.para1 = NA, kappa.para2 = NA, sigma.a = NA, sigma.b = NA )
x |
Data an |
r |
Rank. |
lambda |
Tuning parameter for the density |
max.iter |
The maximum number of iterations for running the algorithm. |
eps |
The convergence threshold; the default is |
jointly.row.sparse |
The default is true, which means that the jointly row sparsity assumption is used; one could not use this assumptio by changing it to false. |
sig2.true |
The default is false, |
threshold |
The threshold to determine whether |
theta.int |
The initial value of theta mean; if not provided, the algorithm will estimate it using PCA. |
theta.var.int |
The initial value of theta.var; if not provided, the algorithm will set it to be 1e-3*diag(r). |
kappa.para1 |
The value of |
kappa.para2 |
The value of |
sigma.a |
The value of |
sigma.b |
The value of |
iter |
The number of iterations to reach convergence. |
selection |
A vector (if |
theta.mean |
The loadings matrix. |
theta.var |
The covariance of each non-zero rows in the loadings matrix. |
sig2 |
Variance of the noise. |
obj.fn |
A vector contains the value of the objective function of each iteration. It can be used to check whether the algorithm converges |
#In this example, the first 20 rows in the loadings matrix are nonzero, the rank is 1 set.seed(2021) library(MASS) library(pracma) n <- 200 p <- 1000 s <- 20 r <- 1 sig2 <- 0.1 # generate eigenvectors U.s <- randortho(s, type = c("orthonormal")) U <- rep(0, p) U[1:s] <- as.vector(U.s[, 1:r]) s.star <- rep(0, p) s.star[1:s] <- 1 eigenvalue <- seq(20, 10, length.out = r) # generate Sigma theta.true <- U * sqrt(eigenvalue) Sigma <- tcrossprod(theta.true) + sig2*diag(p) # generate n*p dataset X <- t(mvrnorm(n, mu = rep(0, p), Sigma = Sigma)) result <- spca.cavi.mvn(x = X, r = 1) loadings <- result$theta.mean
#In this example, the first 20 rows in the loadings matrix are nonzero, the rank is 1 set.seed(2021) library(MASS) library(pracma) n <- 200 p <- 1000 s <- 20 r <- 1 sig2 <- 0.1 # generate eigenvectors U.s <- randortho(s, type = c("orthonormal")) U <- rep(0, p) U[1:s] <- as.vector(U.s[, 1:r]) s.star <- rep(0, p) s.star[1:s] <- 1 eigenvalue <- seq(20, 10, length.out = r) # generate Sigma theta.true <- U * sqrt(eigenvalue) Sigma <- tcrossprod(theta.true) + sig2*diag(p) # generate n*p dataset X <- t(mvrnorm(n, mu = rep(0, p), Sigma = Sigma)) result <- spca.cavi.mvn(x = X, r = 1) loadings <- result$theta.mean
This function employs the PX-CAVI algorithm proposed in Ning (2021). The method uses the sparse spiked-covariance model and the spike and slab prior (see below). Two different slab densities can be used: independent Laplace densities and a multivariate normal density. In Ning (2021), it recommends choosing the multivariate normal distribution. The algorithm allows the user to decide whether she/he wants to center and scale their data. The user is also allowed to change the default values of the parameters of each prior.
VBsparsePCA( dat, r, lambda = 1, slab.prior = "MVN", max.iter = 100, eps = 0.001, jointly.row.sparse = TRUE, center.scale = FALSE, sig2.true = NA, threshold = 0.5, theta.int = NA, theta.var.int = NA, kappa.para1 = NA, kappa.para2 = NA, sigma.a = NA, sigma.b = NA )
VBsparsePCA( dat, r, lambda = 1, slab.prior = "MVN", max.iter = 100, eps = 0.001, jointly.row.sparse = TRUE, center.scale = FALSE, sig2.true = NA, threshold = 0.5, theta.int = NA, theta.var.int = NA, kappa.para1 = NA, kappa.para2 = NA, sigma.a = NA, sigma.b = NA )
dat |
Data an |
r |
Rank. |
lambda |
Tuning parameter for the density |
slab.prior |
The density |
max.iter |
The maximum number of iterations for running the algorithm. |
eps |
The convergence threshold; the default is |
jointly.row.sparse |
The default is true, which means that the jointly row sparsity assumption is used; one could not use this assumptio by changing it to false. |
center.scale |
The default if false. If true, then the input date will be centered and scaled. |
sig2.true |
The default is false, |
threshold |
The threshold to determine whether |
theta.int |
The initial value of theta mean; if not provided, the algorithm will estimate it using PCA. |
theta.var.int |
The initial value of theta.var; if not provided, the algorithm will set it to be 1e-3*diag(r). |
kappa.para1 |
The value of |
kappa.para2 |
The value of |
sigma.a |
The value of |
sigma.b |
The value of |
The model is
where .
The spike and slab prior is given by
where and
is the Dirac measure at zero.
The density
can be chosen to be the product of independent Laplace distribution (i.e.,
) or the multivariate normal distribution (i.e.,
).
iter |
The number of iterations to reach convergence. |
selection |
A vector (if |
loadings |
The loadings matrix. |
uncertainty |
The covariance of each non-zero rows in the loadings matrix. |
scores |
Score functions for the |
sig2 |
Variance of the noise. |
obj.fn |
A vector contains the value of the objective function of each iteration. It can be used to check whether the algorithm converges |
Ning, B. (2021). Spike and slab Bayesian sparse principal component analysis. arXiv:2102.00305.
#In this example, the first 20 rows in the loadings matrix are nonzero, the rank is 2 set.seed(2021) library(MASS) library(pracma) n <- 200 p <- 1000 s <- 20 r <- 2 sig2 <- 0.1 # generate eigenvectors U.s <- randortho(s, type = c("orthonormal")) if (r == 1) { U <- rep(0, p) U[1:s] <- as.vector(U.s[, 1:r]) } else { U <- matrix(0, p, r) U[1:s, ] <- U.s[, 1:r] } s.star <- rep(0, p) s.star[1:s] <- 1 eigenvalue <- seq(20, 10, length.out = r) # generate Sigma if (r == 1) { theta.true <- U * sqrt(eigenvalue) Sigma <- tcrossprod(theta.true) + sig2*diag(p) } else { theta.true <- U %*% sqrt(diag(eigenvalue)) Sigma <- tcrossprod(theta.true) + sig2 * diag(p) } # generate n*p dataset X <- t(mvrnorm(n, mu = rep(0, p), Sigma = Sigma)) result <- VBsparsePCA(dat = t(X), r = 2, jointly.row.sparse = TRUE, center.scale = FALSE) loadings <- result$loadings scores <- result$scores
#In this example, the first 20 rows in the loadings matrix are nonzero, the rank is 2 set.seed(2021) library(MASS) library(pracma) n <- 200 p <- 1000 s <- 20 r <- 2 sig2 <- 0.1 # generate eigenvectors U.s <- randortho(s, type = c("orthonormal")) if (r == 1) { U <- rep(0, p) U[1:s] <- as.vector(U.s[, 1:r]) } else { U <- matrix(0, p, r) U[1:s, ] <- U.s[, 1:r] } s.star <- rep(0, p) s.star[1:s] <- 1 eigenvalue <- seq(20, 10, length.out = r) # generate Sigma if (r == 1) { theta.true <- U * sqrt(eigenvalue) Sigma <- tcrossprod(theta.true) + sig2*diag(p) } else { theta.true <- U %*% sqrt(diag(eigenvalue)) Sigma <- tcrossprod(theta.true) + sig2 * diag(p) } # generate n*p dataset X <- t(mvrnorm(n, mu = rep(0, p), Sigma = Sigma)) result <- VBsparsePCA(dat = t(X), r = 2, jointly.row.sparse = TRUE, center.scale = FALSE) loadings <- result$loadings scores <- result$scores