Nothing
#' Hessian Locally Linear Embedding
#'
#' An S4 Class implementing Hessian Locally Linear Embedding (HLLE)
#'
#' HLLE uses local hessians to approximate the curvines and is an
#' extension to non-convex subsets in lowdimensional space.
#'
#' @template dimRedMethodSlots
#'
#' @template dimRedMethodGeneralUsage
#'
#' @section Parameters:
#' HLLE can take the following parameters:
#' \describe{
#' \item{knn}{neighborhood size}
#' \item{ndim}{number of output dimensions}
#' }
#'
#' @section Implementation:
#' Own implementation, sticks to the algorithm in Donoho and Grimes
#' (2003). Makes use of sparsity to speed up final embedding.
#'
#' @references
#' Donoho, D.L., Grimes, C., 2003. Hessian eigenmaps: Locally linear
#' embedding techniques for high-dimensional data. PNAS 100,
#' 5591-5596. doi:10.1073/pnas.1031596100
#'
#' @examples
#' if(requireNamespace(c("RSpectra", "Matrix", "RANN"), quietly = TRUE)) {
#'
#' dat <- loadDataSet("3D S Curve", n = 300)
#' emb <- embed(dat, "HLLE", knn = 15)
#' plot(emb, type = "2vars")
#'
#' }
#'
#' @include dimRedResult-class.R
#' @include dimRedMethod-class.R
#' @family dimensionality reduction methods
#' @export HLLE
#' @exportClass HLLE
HLLE <- setClass(
"HLLE",
contains = "dimRedMethod",
prototype = list(
stdpars = list(knn = 50, ndim = 2),
fun = function(data, pars,
keep.org.data = TRUE) {
chckpkg("RSpectra")
chckpkg("Matrix")
chckpkg("RANN")
if (pars$ndim < 2) stop("ndim must be 2 or larger.")
if (is.null(pars$knn)) pars$knn <- 50
if (is.null(pars$ndim)) pars$ndim <- 2
indata <- data@data
n <- nrow(indata)
hs <- pars$ndim * (pars$ndim + 1) / 2
W <- Matrix::sparseMatrix(i = numeric(0),
j = numeric(0),
x = numeric(0),
dims = c(n, hs * n))
ii <- jj <- ww <- list()
## Identify neighbors:
message(Sys.time(), ": Finding nearest neighbors", sep = "")
nnidx <- RANN::nn2(data = indata, query = indata, k = pars$knn + 1,
treetype = "kd", "standard", eps = 0)$nn.idx#[, -1]
message(Sys.time(), ": Calculating Hessian", sep = "")
for (i in seq_len(n)) {
cat(i, "/", n, "\r", sep = "")
## get neighborhood
Nui <- indata[nnidx[i, ], , drop = FALSE]
## Form tangent coordinates:
Nui <- sweep(Nui, 2, colMeans(Nui), "-")
tc <- svd(Nui, nu = pars$ndim, nv = 0)$u
## Develop Hessian Estimator
Xi <- cbind(
1, tc, tc ^ 2,
apply(combn(seq_len(pars$ndim), 2), 2,
function(x) tc[, x[1]] * tc[, x[2]])
)
tHi <- qr.Q(qr(Xi))[, -(1:(pars$ndim + 1)),
drop = FALSE]
## Add quadratic form to hessian
ii[[i]] <- rep(nnidx[i, ], hs)
jj[[i]] <- rep((i - 1) * hs + (1:hs), each = ncol(nnidx))
ww[[i]] <- as.vector(tHi)
}
H <- as(Matrix::tcrossprod(Matrix::spMatrix(
i = unlist(ii, FALSE, FALSE),
j = unlist(jj, FALSE, FALSE),
x = unlist(ww, FALSE, FALSE),
nrow = n, ncol = n * hs)
), "dgCMatrix")
## Find null space:
message(Sys.time(), ": Embedding", sep = "")
## eigs and eigs_sym converges much more reliably and faster
## with sigma = -eps than with which = "L*"
outdata <- RSpectra::eigs_sym(H, k = pars$ndim + 1, sigma = -1e-5)
message(paste(c("Eigenvalues:", format(outdata$values)),
collapse = " "))
outdata <- outdata$vectors[, order(outdata$values)[-1], drop = FALSE]
colnames(outdata) <- paste0("HLLE", seq_len(ncol(outdata)))
message(Sys.time(), ": DONE", sep = "")
return(new(
"dimRedResult",
data = new("dimRedData",
data = outdata,
meta = data@meta),
org.data = if (keep.org.data) data@data else NULL,
has.org.data = keep.org.data,
method = "HLLE",
pars = pars
))
},
requires = c("RSpectra", "Matrix", "RANN"))
)
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.