#' Unit Testing script for NMF package: NMF models and utilities.
#'
#' @author Renaud Gaujoux
#' @creation 22 April 2009
# make the internal functions/objects visible
if( isNamespaceLoaded('NMF') ){
.predict.nmf <- NMF:::.predict.nmf
is.same <- NMF:::is.same
}
.TestSeed <- 123456
checkOnlyNAs <- function(x, msg){
expect_true( all(is.na(basis(x))) , paste(msg, ': Only NAs in W'))
expect_true( all(is.na(coef(x))), paste(msg, ': Only NAs in H'))
}
basicHM <- aheatmap
checkPlot <- function(...){
if( isCHECK() ) return()
pkgmaker::checkPlot(...)
}
#' checks the validity of a NMF object: dimensions
check.object <- function(obj, n, m, r, title='Check NMF object', class='NMFstd'){
# convert dimensions to integers
n <- as.integer(n)
m <- as.integer(m)
r <- as.integer(r)
# check class
expect_true(is(obj, class), paste(title, ': object is of class "', class, "'"));
# check virtual interface accessors
expect_true(is.same(obj@W, basis(obj)), msg('method `basis` returns slot W'))
expect_true(is.same(obj@H, coef(obj)), msg('method `coef` returns slot H'))
expect_identical(nrow(basis(obj)), n, paste(title, ': number of rows in basis matrix is correct'))
expect_identical(nrow(obj), n, paste(title, ': nrow returns correct value'))
expect_identical(ncol(basis(obj)), r, paste(title, ': number of columns in basis matrix is correct'))
expect_identical(nbasis(obj), r, paste(title, ': nbasis returns correct value'))
expect_identical(nrow(coef(obj)), r, paste(title, ': number of rows in coef matrix correct'))
expect_identical(ncol(coef(obj)), m, paste(title, ': number of columns in coef matrix is correct'))
expect_identical(ncol(obj), m, paste(title, ': ncol returns correct value'))
}
check.NMF.class <- function(class, ...){
set.seed(.TestSeed)
msg <- function(...) paste('New -', class,':', ...)
# base constructor: should build an empty model
a <- new(class, ...)
# check if there is only NAs
checkOnlyNAs(a, msg('with no parameters'))
check.object(a, 0, 0, 0, msg('with no parameters'), class)
# define some dimensions to use as template
n <- 50; m <- 10; r <- 3;
w <- rmatrix(n, r); h <- rmatrix(r, m)
# base constructor with one of the two matrices: exceptions
expect_error(new(class, W=w, ...), "W and H are not compatible", info = msg('error if only basis matrix'))
expect_error(new(class, H=h, ...), "W and H are not compatible", info = msg('error if only coef matrix'))
# base constructor with two matrices
a <- new(class, W=w, H=h, ...)
# check the dimensions of the internal matrices
check.object(a, n, m, r, msg('with two matrices - '), class)
expect_identical(basis(a), w, msg('with two matrices - basis matrix is correctly set'));
expect_identical(coef(a), h, msg('with two matrices - coef matrix is correctly set'));
# check error with wrong dimension
expect_error(a <- new(class, W=matrix(1,n,r+1), H=matrix(1,r,m), ...),
"W and H are not compatible",
info = msg('Error if incompatible dimensions (W)'))
expect_error(a <- new(class, W=matrix(1,n,r), H=matrix(1,r+1,m), ...),
"W and H are not compatible",
info = msg('Error if incompatible dimensions (H)'))
}
check.dimnames <- function(x, dn, msg){
expect_identical(dimnames(x), dn, paste(msg, '-',"dimnames returns correct value"))
expect_identical(dimnames(x)[c(1,3)], dimnames(basis(x)), paste(msg, '-', "dimnames returns value consistent with basis"))
expect_identical(dimnames(x)[c(3,2)], dimnames(coef(x)), paste(msg, '-', "dimnames returns value consistent with coef"))
expect_identical(rownames(x), dn[[1]], paste(msg, '-', "rownames returns correct value"))
expect_identical(rownames(basis(x)), rownames(x), paste(msg, '-', "rownames returns same value as rownames(basis)"))
expect_identical(colnames(x), dn[[2]], paste(msg, '-', "colnames returns correct value"))
expect_identical(colnames(coef(x)), colnames(x), paste(msg, '-', "colnames returns same value as colnames(basis)"))
expect_identical(basisnames(x), dn[[3]], paste(msg, '-', "basisnames returns correct value"))
expect_identical(colnames(basis(x)), basisnames(x), paste(msg, '-', "basisnames returns same value as colnames(basis)"))
expect_identical(rownames(coef(x)), basisnames(x), paste(msg, '-', "basisnames returns same value as rownames(coef)"))
}
test_that("test.basis", {
n <- 50
m <- 10
r <- 3
a <- nmfModel(r)
expect_true(is.same(basis(a), a@W), info = "Method 'basis' correctly returns slot W")
W.ext <- matrix(1, n, r)
basis(a) <- W.ext
expect_identical(W.ext, a@W, info = "Method 'basis<-' correctly sets slot W")
})
test_that("test.class.NMFns", {
check.NMF.class("NMFns")
t <- 0.8
check.NMF.class("NMFns", theta = t)
a <- new("NMFns", theta = t)
expect_identical(t, a@theta, info = "Slot theta is correctly set")
expect_error(a <- new("NMFns", theta = -1), info = "Negative value of theta throws an exception")
expect_error(a <- new("NMFns", theta = 1.2), info = "Value of theta > 1 throws an exception")
set.seed(.TestSeed)
n <- 50
m <- 10
r <- 3
W <- rmatrix(n, r)
H <- rmatrix(r, m)
a.ns <- new("NMFns", W = W, H = H, theta = 0)
a.std <- new("NMFstd", W = W, H = H)
expect_identical(fitted(a.std), fitted(a.ns), info = "Values fitted correspond to standard model if theta=0")
a.ns <- new("NMFns", W = W, H = H, theta = 0.4)
s <- smoothing(a.ns)
expect_equal(c(r, r), dim(s), info = "Smoothing matrix: dimension are correct")
expect_true(all(s >= 0), info = "Smoothing matrix: all entries are nonnegative")
expect_equal(rep(1, r), rowSums(s), info = "Smoothing matrix: sum of rows are ones")
expect_equal(rep(1, r), colSums(s), info = "Smoothing matrix: sum of columns are ones")
expect_equal(basis(a.ns) %*% s %*% coef(a.ns), fitted(a.ns),
info = "Fitted values are correct (product of basis, smoothing and coef).")
})
test_that("test.class.NMFstd", {
check.NMF.class("NMFstd")
})
test_that("test.coef", {
n <- 50
m <- 10
r <- 3
a <- nmfModel(r)
expect_true(is.same(coef(a), a@H), info = "Method 'coef' correctly returns slot H")
ext <- matrix(1, r, m)
coef(a) <- ext
expect_identical(ext, a@H, info = "Method 'coef<-' correctly sets slot H")
})
test_that("test.connectivity", {
n <- 50
m <- 10
r <- 3
set.seed(.TestSeed)
a <- nmfModel(r, c(n, m))
a <- rnmf(a)
con <- connectivity(a)
expect_true(is.matrix(con), info = "The result is a matrix")
expect_true(all(con %in% c(0, 1)), info = "All entries are 0 or 1")
expect_true(all(t(con) == con), info = "The connectivity matrix is symmetric")
})
test_that("test.deviance", {
n <- 10
m <- 5
set.seed(.TestSeed)
y <- rmatrix(n, m)
x <- rnmf(nmfModel(3, y))
expect_warning(dev <- deviance(x, y), "Undefined distance method: .* [returned NA]")
expect_equal(NA_real_, dev, info = "With no method: NA")
expect_error(deviance(x, y, "toto"), info = "Error if undefined method")
norm1 <- function(x, y) {
sum(abs(fitted(x) - y))
}
funname <- paste("test", paste(sample(1:9, 20, replace = TRUE),
collapse = ""), sep = ".")
assign(funname, norm1, envir = .GlobalEnv)
on.exit(rm(list = funname, envir = .GlobalEnv), add = TRUE)
expect_true(deviance(x, y, norm1) > 0, info = "Works with a user-defined function in .GlobalEnv")
expect_true(deviance(x, y, funname) > 0, info = "Works with name of a user-defined function .GlobalEnv")
meth <- "euclidean"
expect_true(deviance(x, y, meth) > 0, info = "Euclidean: positive")
expect_equal(sum((fitted(x) - y)^2)/2, deviance(x, y, meth),
info = "Euclidean: OK")
meth <- "KL"
expect_true(deviance(x, y, meth) > 0, info = "KL: positive")
z <- y
z[1, ] <- 0
expect_true(deviance(x, z, meth) != Inf, info = "Ok if some zeros in the target")
z <- x
basis(z)[1, ] <- 0
expect_identical(Inf, deviance(z, y, meth), info = "Infinite if some zeros in the estimate")
})
test_that("test.dimensions", {
n <- as.integer(50)
m <- as.integer(10)
r <- as.integer(3)
a <- nmfModel(r, n, m)
expect_identical(c(n, m, r), dim(a), info = "Function 'dim' is OK")
expect_identical(n, nrow(a), info = "Function 'nrow' is OK")
expect_identical(m, ncol(a), info = "Function 'ncol' is OK")
expect_identical(r, nbasis(a), info = "Function 'nbasis' is OK")
})
test_that("test.dimnames", {
set.seed(.TestSeed)
n <- 20
m <- 10
r <- 3
w <- rmatrix(n, r)
h <- rmatrix(r, m)
M <- nmfModel(r, n, m)
a <- M
expect_error({
dimnames(a) <- 1:n
}, info = "set to vector")
expect_error({
dimnames(a) <- list(seq(n - 1))
}, info = "Error of wrong dimension (nrow-1)")
expect_error({
dimnames(a) <- list(seq(n + 1))
}, info = "Error of wrong dimension (nrow+1)")
msg <- function(...) paste("Dimnames with 2 elements -",
...)
a <- M
check.dimnames(a, NULL, "No dimnames => NULL")
check.dimnames({
dimnames(a) <- NULL
a
}, NULL, msg("set to NULL"))
check.dimnames({
dimnames(a) <- list()
a
}, NULL, msg("set to list()"))
msg <- function(...) paste("Dimnames with 1 element -", ...)
a <- M
dn <- list(letters[1:nrow(a)])
dn.name <- setNames(dn, "rows")
check.dimnames({
a <- M
dimnames(a) <- dn
a
}, c(dn, list(NULL, NULL)), msg("Set dimnames"))
check.dimnames({
a <- M
dimnames(a) <- dn.name
a
}, c(dn.name, list(NULL, NULL)), msg("Set with names"))
check.dimnames({
a <- M
rownames(a) <- dn[[1]]
a
}, c(dn, list(NULL, NULL)), msg("Set rownames"))
check.dimnames({
a <- M
colnames(a) <- letters[1:ncol(a)]
a
}, list(NULL, letters[1:ncol(a)], NULL), msg("Set colnames"))
check.dimnames({
a <- M
basisnames(a) <- letters[1:nbasis(a)]
a
}, list(NULL, NULL, letters[1:nbasis(a)]), msg("Set basisnames"))
check.dimnames({
dimnames(a) <- NULL
a
}, NULL, msg("Reset to NULL"))
msg <- function(...) paste("Dimnames with 2 elements -",
...)
a <- M
dn <- list(letters[1:nrow(a)], letters[seq(nrow(a) + 1, nrow(a) +
ncol(a))])
dn.name <- setNames(dn, c("rows", "cols"))
check.dimnames({
dimnames(a) <- dn
a
}, c(dn, list(NULL)), msg("Set dimnames"))
check.dimnames({
dimnames(a) <- NULL
a
}, NULL, msg("Reset to NULL"))
check.dimnames({
dimnames(a) <- dn.name
a
}, c(dn.name, list(NULL)), msg("Set with names"))
check.dimnames({
dimnames(a) <- NULL
a
}, NULL, msg("Reset to NULL (2)"))
msg <- function(...) paste("Dimnames with 3 elements -",
...)
a <- M
dn <- list(letters[1:nrow(a)], letters[seq(nrow(a) + 1, nrow(a) +
ncol(a))], letters[seq(nrow(a) + ncol(a) + 1, nrow(a) +
ncol(a) + nbasis(a))])
dn.name <- setNames(dn, c("rows", "cols", "basis"))
check.dimnames({
dimnames(a) <- dn
a
}, dn, msg("Set dimnames"))
check.dimnames({
dimnames(a) <- NULL
a
}, NULL, msg("Reset to NULL"))
check.dimnames({
dimnames(a) <- dn.name
a
}, dn.name, msg("Set with names"))
check.dimnames({
dimnames(a) <- NULL
a
}, NULL, msg("Reset to NULL (2)"))
})
test_that("test.entropy", {
checkBounds <- function(x) {
expect_true(x >= 0, "greater than 0")
expect_true(x <= 1, "lower than 1")
}
x <- as.factor(c(rep(1, 5), rep(2, 10), rep(3, 15)))
e <- entropy(x, x)
checkBounds(e)
expect_equal(0, e)
set.seed(.TestSeed)
e <- entropy(as.factor(sample(x)), x)
checkBounds(e)
})
test_that("test.misc", {
x <- nmfModel()
m <- slot(x, "misc")
expect_true(is.list(m) && length(m) == 0L, info = "On empty model misc is an empty list")
expect_equal(m, misc(x), info = "On empty model misc() returns an empty list")
x$a <- 3
expect_equal(list(a = 3), slot(x, "misc"), info = "Setting misc with $ works")
expect_equal(list(a = 3), misc(x), info = "Getting misc with misc() works")
expect_equal(3, x$a, info = "Getting misc with $ works")
expect_equal(NULL, misc(list()), info = "On empty list misc is NULL")
expect_equal(4, misc(list(misc = 4)), info = "On list with a `misc` element, misc() returns the element")
expect_equal(NULL, misc(1), info = "On non list object misc() is NULL")
a <- 1
attr(a, "misc") <- 2
expect_equal(2, misc(a), info = "On non list object with `misc` attribute, misc() returns the attribute")
})
test_that("test.NMF.rnmf", {
n <- 50
m <- 10
r <- 3
a <- nmfModel(r)
set.seed(.TestSeed)
expect_error(rnmf(a, as.numeric(NA)), info = "Error thrown if single NA value")
expect_error(rnmf(a, as.numeric(c(1, NA))), info = "Error thrown if some NA value")
expect_error(rnmf(a, c(1, 2, 3)), info = "Error thrown if some length greater than 2")
expect_error(rnmf(a, numeric()), info = "Error thrown if some length is 0")
set.seed(.TestSeed)
a <- rnmf(r, n, m)
checkPlot(basicHM(basis(a)), "Random NMF basis (target dimension)")
checkPlot(basicHM(coef(a)), "Random NMF coef (target dimension)")
expect_equal(n, nrow(a), info = "number of rows matches target dimension")
expect_equal(m, ncol(a), info = "number of columns matches target dimension")
expect_equal(r, nbasis(a), info = "number of basis matches target dimension")
set.seed(.TestSeed)
expect_identical(rnmf(r, c(n, m)), a, info = "calling with numeric target of length 2 is equivalent to separate dimensions")
set.seed(.TestSeed)
expect_identical(rnmf(r, n, m), a, info = "calling with numeric target of length 2 is equivalent to separate dimensions")
a <- nmfModel(r, n, m)
set.seed(.TestSeed)
b <- rnmf(a)
checkPlot(basicHM(basis(b)), "Random NMF basis (target NMF)")
checkPlot(basicHM(coef(b)), "Random NMF coef (target NMF)")
expect_equal(nrow(b), nrow(a), info = "number of rows matches NMF target")
expect_equal(ncol(b), ncol(a), info = "number of columns matches NMF target")
expect_equal(nbasis(b), nbasis(a), info = "number of basis matches NMF model")
set.seed(.TestSeed)
max.entry <- 100
V <- ExpressionSet(rmatrix(n, m, min = 0, max = max.entry))
a <- nmfModel(r, n, m)
check.object(a <- rnmf(a, V), n, m, r, "NMFobject + target ExpressionSet")
check.dimnames(a, c(dimnames(exprs(V)), list(NULL)), "NMFobject + target ExpressionSet")
check.object(a <- rnmf(r, V), n, m, r, "rank + target ExpressionSet")
check.dimnames(a, c(dimnames(exprs(V)), list(NULL)), "rank + target ExpressionSet")
set.seed(.TestSeed)
max.entry <- 100
V <- rmatrix(n, m, min = 0, max = max.entry)
a <- nmfModel(r, n, m)
a <- rnmf(a, V)
checkPlot(basicHM(basis(a)), "Random NMF basis (target matrix)")
checkPlot(basicHM(coef(a)), "Random NMF coef (target matrix)")
expect_equal(n, nrow(a), info = "number of rows matches matrix target")
expect_equal(m, ncol(a), info = "number of columns matches matrix target")
expect_equal(r, nbasis(a), info = "matrix target: number of basis matches NMF model")
msg <- function(...) paste("Set max in target matrix -",
...)
.check_max <- function(x, max.entry) {
expect_true(max(basis(a)) <= max.entry, msg("Basis maximum entry is OK (<=)"))
expect_true(max(basis(a)) >= max.entry/2, msg("Basis maximum entry is OK (>=)"))
expect_true(max(coef(a)) <= max.entry, msg("Coef maximum entry is OK (<=)"))
expect_true(max(coef(a)) >= max.entry/2, msg("Coef maximum entry is OK (>=)"))
}
.check_max(a, max.entry)
dn <- list(rows = letters[1:nrow(V)], cols = letters[seq(25 -
ncol(V) + 1, 25)])
dimnames(V) <- dn
check.dimnames(rnmf(a, V), c(dn, list(NULL)), "rnmf on target matrix with dimnames: dimnames are passed")
check.dimnames(rnmf(a, V, use.dimnames = FALSE), NULL, "rnmf on target matrix with dimnames and use.dimnames=FALSE: dimnames are not passed")
msg <- function(...) paste("Set max by argument -", ...)
set.seed(.TestSeed)
a <- rnmf(r, V, model = "NMFOffset")
.check_max(a, max.entry)
msg <- function(...) paste("Set max by argument -", ...)
set.seed(.TestSeed)
max.entry <- 5
a <- rnmf(r, n, m, dist = list(max = max.entry))
.check_max(a, max.entry)
})
test_that("test.nmfModel", {
set.seed(.TestSeed)
n <- as.integer(25)
m <- as.integer(10)
r <- as.integer(3)
check.empty.model <- function(x, n, m, r, msg, class = "NMFstd") {
check.object(x, n, m, r, msg, class)
checkOnlyNAs(x, msg)
}
expect_error(nmfModel(numeric()), info = "Error if negative rank")
expect_error(nmfModel(c(1, 2)), info = "Error if rank of length != 1")
expect_error(nmfModel(r, -1), info = "Error if negative target dimension")
expect_error(nmfModel(r, 1:3), info = "Error if target dimension of length > 2")
expect_error(nmfModel(r, 1, -1), info = "Error if target ncol negative")
expect_error(nmfModel(r, 1, 1:2), info = "Error if target ncol of length > 1")
expect_error(nmfModel(r, 1, matrix(1, 2, 2)), info = "Error if target ncol not vector")
check.empty.model(nmfModel(), 0, 0, 0, "Constructor with no arguments returns empty model")
check.empty.model(nmfModel(ncol = 5), 0, 5, 0, "Constructor with only with ncol specified")
check.empty.model(nmfModel(r), 0, 0, r, "Constructor with missing target")
check.empty.model(nmfModel(r, c(n, m)), n, m, r, "Constructor with dimensions as a vector")
check.empty.model(nmfModel(r, n, m), n, m, r, "Constructor with separate dimensions")
check.empty.model(nmfModel(r, n), n, n, r, "Constructor with single dimension (nrow)")
check.empty.model(nmfModel(r, ncol = m), 0, m, r, "Constructor with single dimension (ncol)")
msg <- function(...) paste("Constructor with target matrix -",
...)
V <- rmatrix(n, m)
check.empty.model(nmfModel(r, V), n, m, r, msg("second argument"))
check.empty.model(nmfModel(V, r), n, m, r, msg("first argument"))
check.empty.model(nmfModel(V), n, m, 0, msg("single argument"))
dimnames(V) <- list(rows = letters[1:n], cols = letters[1:m])
expect_identical(c(dimnames(V), list(NULL)), dimnames(nmfModel(V)),
info = msg("dimnames are correctly set"))
expect_identical(NULL, dimnames(nmfModel(V, use.names = FALSE)),
info = msg("dimnames are not used if use.names=FALSE"))
w <- rmatrix(n, r)
h <- rmatrix(r, m)
msg <- function(...) paste("Constructor with target rank and both basis and coef matrices -",
...)
a <- nmfModel(r, W = w, H = h)
check.object(a, n, m, r, msg())
expect_identical(w, basis(a), info = msg("basis matrix is correctly set"))
expect_identical(h, coef(a), info = msg("coef matrix is correctly set"))
expect_error(nmfModel(r, c(n + 1, m), W = w, H = h), info = msg("error if bad number of rows in basis matrix"))
expect_error(nmfModel(r, c(n, m), W = w[, -r], H = h), info = msg("error if bad number of columns in basis matrix"))
expect_error(nmfModel(r, c(n, m), W = w, H = h[-r, ]), info = msg("error if bad number of rows in coef matrix"))
expect_error(nmfModel(r, c(n, m + 1), W = w, H = h), info = msg("error if bad number of columns in coef matrix"))
rmsg <- function(...) msg("reduce rank -", ...)
expect_warning(a <- nmfModel(r - 1, W = w, H = h),
"(only the first 2 columns of W will be used|only the first 2 rows of H will be used)",
all = TRUE)
check.object(a, n, m, r - 1, rmsg("dimensions are OK"))
expect_identical(w[, -r], basis(a), info = rmsg("entries for basis are OK"))
expect_identical(h[-r, ], coef(a), info = rmsg("entries for coef are OK"))
rmsg <- function(...) msg("reduce nrow -", ...)
expect_warning(a <- nmfModel(r, n - 1, W = w, H = h), "only the first 24 rows of W will be used")
check.object(a, n - 1, m, r, rmsg("dimensions are OK"))
expect_identical(w[-n, ], basis(a), info = rmsg("entries for basis are OK"))
expect_identical(h, coef(a), info = rmsg("entries for coef are OK"))
rmsg <- function(...) msg("reduce ncol -", ...)
expect_warning(a <- nmfModel(r, ncol = m - 1, W = w, H = h), "only the first 9 columns of H will be used")
check.object(a, n, m - 1, r, rmsg("dimensions are OK"))
expect_identical(w, basis(a), info = rmsg("entries for basis are OK"))
expect_identical(h[, -m], coef(a), info = rmsg("entries for coef are OK"))
msg <- function(...) paste("Constructor with only basis and coef matrices (named arguments) -",
...)
a <- nmfModel(W = w, H = h)
check.object(a, n, m, r, msg())
expect_identical(w, basis(a), info = msg("basis matrix is correctly set"))
expect_identical(h, coef(a), info = msg("coef matrix is correctly set"))
expect_error(nmfModel(W = matrix(1, n, r + 1), H = matrix(1,
r, m)), info = msg("error if incompatible dimensions (1)"))
expect_error(nmfModel(W = matrix(1, n, r), H = matrix(1,
r + 1, m)), info = msg("error if incompatible dimensions (2)"))
msg <- function(...) paste("Constructor with only basis and coef matrices (unamed argument) -",
...)
a <- nmfModel(w, h)
check.object(a, n, m, r, msg())
expect_identical(w, basis(a), info = msg("basis matrix is correctly set"))
expect_identical(h, coef(a), info = msg("coef matrix is correctly set"))
expect_error(nmfModel(matrix(1, n, r + 1), matrix(1, r, m)),
info = msg("error if incompatible dimensions (1)"))
expect_error(nmfModel(matrix(1, n, r), matrix(1, r + 1, m)),
info = msg("error if incompatible dimensions (2)"))
msg <- function(...) paste("Constructor with target rank and basis matrix only -",
...)
a <- nmfModel(r, W = w)
check.object(a, n, 0, r, msg())
expect_identical(w, basis(a), info = msg("basis matrix is correctly set"))
expect_true(all(is.na(coef(a))), info = msg("only NA in coef matrix"))
expect_error(nmfModel(r + 1, W = w), info = msg("error if smaller number of columns in basis matrix"))
rmsg <- function(...) msg("reduce rank -", ...)
expect_warning(a <- nmfModel(r - 1, W = w), "only the first 2 columns of W will be used")
check.object(a, n, 0, r - 1, rmsg("dimensions are OK"))
expect_identical(w[, -r], basis(a), info = rmsg("entries for basis are OK"))
expect_true(all(is.na(coef(a))), info = rmsg("only NA in coef matrix"))
expect_error(nmfModel(r - 1, W = w, force.dim = FALSE), info = msg("error if greater number of columns in basis matrix and force.dim=FALSE"))
msg <- function(...) paste("Constructor with basis matrix only -",
...)
a <- nmfModel(W = w)
check.object(a, n, 0, r, msg())
expect_identical(w, basis(a), info = msg("basis matrix is correctly set"))
expect_true(all(is.na(coef(a))), info = msg("only NA in coef matrix"))
msg <- function(...) paste("Constructor with target rank and coef matrix only -",
...)
a <- nmfModel(r, H = h)
check.object(a, 0, m, r, msg())
expect_identical(h, coef(a), info = msg("coef matrix is correctly set"))
expect_true(all(is.na(basis(a))), info = msg("only NA in basis matrix"))
expect_error(nmfModel(r + 1, H = h), info = msg("error if smaller number of rows in coef matrix"))
rmsg <- function(...) msg("reduce rank -", ...)
expect_warning(a <- nmfModel(r - 1, H = h), "only the first 2 rows of H will be used")
check.object(a, 0, m, r - 1, rmsg("dimensions are OK"))
expect_identical(h[-r, ], coef(a), info = rmsg("coef matrix is correctly set"))
expect_true(all(is.na(basis(a))), info = rmsg("only NA in basis matrix"))
expect_error(nmfModel(r - 1, H = h, force.dim = FALSE), info = msg("error if greater number of rows in coef matrix and force.dim=FALSE"))
msg <- function(...) paste("Constructor with coef matrix only -",
...)
a <- nmfModel(H = h)
check.object(a, 0, m, r, msg())
expect_identical(h, coef(a), info = msg("coef matrix is correctly set"))
expect_true(all(is.na(basis(a))), info = msg("only NA in basis matrix"))
msg <- function(...) paste("Constructor with basis matrix and both target dimensions -",
...)
a <- nmfModel(r, n, m, W = w)
check.object(a, n, m, r, msg())
expect_identical(w, basis(a), info = rmsg("entries for basis are OK"))
expect_true(all(is.na(coef(a))), info = rmsg("only NA in coef matrix"))
rmsg <- function(...) msg("reduce nrow -", ...)
expect_warning(a <- nmfModel(r, n - 1, m, W = w), "rows in target is lower than the number of rows in W")
check.object(a, n - 1, m, r, rmsg("dimensions are OK"))
expect_identical(w[-n, ], basis(a), info = rmsg("entries for basis are OK"))
expect_true(all(is.na(coef(a))), info = rmsg("only NA in coef matrix"))
expect_error(nmfModel(r, n + 1, m, W = w), info = msg("error if smaller number of rows in basis matrix"))
expect_error(nmfModel(r, n - 1, W = w, force.dim = FALSE),
info = msg("error if greater number of rows in basis matrix and force.dim=FALSE"))
expect_error(nmfModel(r + 1, n, m, W = w), info = msg("error if smaller number of columns in basis matrix"))
msg <- function(...) paste("Constructor with coef matrix and both target dimensions -",
...)
a <- nmfModel(r, n, m, H = h)
check.object(a, n, m, r, msg())
expect_true(all(is.na(basis(a))), info = msg("only NA in basis matrix"))
expect_identical(h, coef(a), info = msg("coef matrix is correctly set"))
rmsg <- function(...) msg("reduce ncol -", ...)
expect_warning(a <- nmfModel(r, n, m - 1, H = h), "columns in target is lower than the number of columns in H")
check.object(a, n, m - 1, r, rmsg("dimensions are OK"))
expect_identical(h[, -m], coef(a), info = rmsg("coef matrix is correctly set"))
expect_true(all(is.na(basis(a))), info = rmsg("only NA in basis matrix"))
expect_error(nmfModel(r + 1, n, m, H = h), info = msg("error if smaller number of rows in coef matrix"))
expect_error(nmfModel(r, n, m - 1, H = h, force.dim = FALSE),
info = msg("error if greater number of columns in coef matrix and force.dim=FALSE"))
expect_error(nmfModel(r, n, m + 1, H = h), info = msg("error if smaller number of columns in coef matrix"))
check.model.dimnames <- function(x, dn, title) {
msg <- function(...) paste(title, "-", ...)
expect_identical(dimnames(x), dn, msg("dimnames are correct"))
expect_identical(colnames(basis(x)), dn[[3]], msg("colnames of basis matrix are correct"))
expect_identical(rownames(coef(x)), dn[[3]], msg("rownames of coef matrix are correct"))
}
dn <- letters[1:nrow(h)]
h2 <- h
rownames(h2) <- dn
a <- nmfModel(r, H = h2)
check.model.dimnames(a, list(NULL, NULL, dn), "Basis names are passed from input coef matrix")
w2 <- w
colnames(w2) <- dn
a <- nmfModel(r, W = w2)
check.model.dimnames(a, list(NULL, NULL, dn), "Basis names are passed from input basis matrix")
w2 <- w
colnames(w2) <- dn
h2 <- h
rownames(h2) <- dn
a <- nmfModel(W = w2, H = h2)
check.model.dimnames(a, list(NULL, NULL, dn), "Basis names are used unchanged if equal in input basis and coef matrices")
msg <- function(...) paste("Basis names from input basis matrix are used to order the components - ",
...)
w2 <- w
colnames(w2) <- dn
h2 <- h
rownames(h2) <- rev(dn)
a <- nmfModel(W = w2, H = h2)
check.model.dimnames(a, list(NULL, NULL, dn), msg("rownames of input basis are enforced"))
expect_identical(w2, basis(a), info = msg("basis unchanged"))
expect_identical(h2[nrow(h):1, ], coef(a), info = msg("coef entries are reordered"))
msg <- function(...) paste("Basis names from input basis matrix are NOT used to order the components if argument order.basis=FALSE - ",
...)
w2 <- w
colnames(w2) <- dn
h2 <- h
rownames(h2) <- rev(dn)
expect_warning(a <- nmfModel(W = w2, H = h2, order.basis = FALSE), "The rownames of the mixture matrix were set")
check.model.dimnames(a, list(NULL, NULL, dn), msg("rownames of input basis are enforced"))
expect_identical(w2, basis(a), info = msg("basis unchanged"))
expect_equivalent(h2, coef(a), info = msg("coef entries are not ordered"))
msg <- function(...) paste("Basis names from input basis matrix are forced onto to the coef matrix - ",
...)
w2 <- w
colnames(w2) <- dn
h2 <- h
rownames(h2) <- paste(letters[1:nrow(h)], 2)
expect_warning(a <- nmfModel(W = w2, H = h2), "The rownames of the mixture matrix were set")
check.model.dimnames(a, list(NULL, NULL, dn), msg("rownames of input basis are enforced"))
expect_identical(w2, basis(a), info = msg("basis is unchanged"))
expect_equivalent(h2, coef(a), info = msg("coef entries are correct"))
})
test_that("test.predict", {
n <- 100
m <- 20
r <- 3
.msg <- NULL
mess <- function(...) paste(.msg, ":", ...)
.msg <- "Artificial matrix"
V <- matrix(c(c(1, rep(0, n - 1)), c(0, 1, rep(0, n - 2)),
rep(c(0, 0, 1, rep(0, n - 3)), m - 2)), n, m)
res <- .predict.nmf(t(V))
expect_equal(as.factor(c(1, 2, rep(3, m - 2))), res, info = mess("Return known clusters"))
.msg <- "Random matrix"
set.seed(.TestSeed)
V <- matrix(sapply(sample(n), function(i) {
x <- rep(0, n)
x[i] <- 1
x
}), n, m)
res <- .predict.nmf(V)
expect_true(is.factor(res), info = mess("Result is a factor"))
expect_true(length(res) == nrow(V), info = mess("Result is the right size"))
expect_true(nlevels(res) == ncol(V), info = mess("Result has the right number of levels"))
.msg <- "NMF model"
a <- nmfModel(r, V)
set.seed(.TestSeed)
a <- rnmf(a)
res <- predict(a, "samples")
expect_true(is.factor(res), info = mess("Result is a factor"))
expect_true(length(res) == ncol(a), info = mess("Result has right size"))
expect_true(nlevels(res) == nbasis(a), info = mess("Result has right number of levels"))
.msg <- "Factor"
res <- predict(a, "features")
expect_true(is.factor(res), info = mess("Result is a factor"))
expect_true(length(res) == nrow(a), info = mess("Result has right size"))
expect_true(nlevels(res) == nbasis(a), info = mess("Result has right number of levels"))
})
test_that("test.purity", {
checkBounds <- function(x) {
expect_true(x >= 0, "greater than 0")
expect_true(x <= 1, "lower than 1")
}
x <- as.factor(c(rep(1, 5), rep(2, 10), rep(3, 15)))
p <- purity(x, x)
checkBounds(p)
expect_equal(1, p)
set.seed(.TestSeed)
p <- purity(as.factor(sample(x)), x)
checkBounds(p)
})
test_that("test.silhouette", {
x <- rmatrix(20, 15)
cl <- gl(3, 5)
rownames(x) <- letters[seq(nrow(x))]
colnames(x) <- LETTERS[seq(ncol(x))]
si <- NMF:::bigsilhouette(x, cl)
expect_equal(colnames(x), rownames(si))
base_si <- silhouette(as.integer(cl), dmatrix = 1 - cor(x))
expect_identical(rownames(base_si), NULL)
rownames(base_si) <- colnames(x)
attr(base_si, "call") <- NULL
attr(si, "call") <- NULL
expect_equal(base_si, si)
})
test_that("test.sparseness", {
checkBounds <- function(s) {
expect_true(s >= 0, "greater than 0")
expect_true(s <= 1, "lower than 1")
}
x <- rep(1, 100)
s <- sparseness(x)
checkBounds(s)
expect_equal(0, s, info = "should be 0")
x <- c(1, rep(0, 100))
s <- sparseness(x)
checkBounds(s)
expect_equal(1, s)
n <- 100
m <- 20
r <- 3
set.seed(.TestSeed)
V <- matrix(rnorm(n * m), n, m)
s <- sparseness(V)
checkBounds(s)
a <- nmfModel(r, V)
set.seed(.TestSeed)
a <- rnmf(a, V)
s <- sparseness(a)
expect_true(length(s) == 2, info = "Method 'sparseness' returns a 2-length vector")
checkBounds(s[1])
checkBounds(s[2])
})
test_that("test.subset", {
n <- 30
r <- 5
p <- 20
a <- nmfModel(r, n, p)
a <- rnmf(a)
expect_true(identical(a[], a), info = "subset [] is OK (identical)")
expect_true(identical(a[, ], a), info = "subset [,] is OK (identical)")
expect_true(identical(a[TRUE, ], a), info = "subset [TRUE,] is OK (identical)")
expect_true(identical(a[, TRUE], a), info = "subset [,TRUE] is OK (identical)")
expect_true(identical(a[TRUE, TRUE], a), info = "subset [TRUE,TRUE] is OK (identical)")
expect_true(identical(a[, , TRUE], a), info = "subset [,,TRUE] is OK (identical)")
expect_true(identical(a[TRUE, TRUE, TRUE], a), info = "subset [TRUE,TRUE,TRUE] is OK (identical)")
expect_true(identical(a[NULL, ], a[0, ]), info = "subset [NULL,] is OK")
expect_true(identical(a[, NULL], a[, 0]), info = "subset [,NULL] is OK")
expect_true(identical(a[NULL, NULL], a[0, 0]), info = "subset [NULL,NULL] is OK")
expect_true(identical(a[NULL, NULL, NULL], a[0, 0, 0]), info = "subset [NULL,NULL,NULL] is OK")
expect_error(a[, , ], info = "Error when called with [,,]")
expect_equal(c(1, p, r), dim(a[1, ]), info = "subset 1 feature is OK (dim)")
expect_equal(basis(a)[5, , drop = FALSE], basis(a[5, ]),
info = "subset 1 feature is OK (basis)")
expect_equal(coef(a), coef(a[5, ]), info = "subset 1 feature is OK (coef)")
expect_equal(basis(a)[5, , drop = TRUE], a[5, , drop = TRUE],
info = "subset 1 feature dropping is OK (return basis)")
expect_equal(c(10, p, r), dim(a[1:10, ]), info = "subset more than 1 feature is OK (dim)")
expect_equal(basis(a)[1:10, , drop = FALSE], basis(a[1:10,
]), info = "subset more than 1 feature is OK (basis)")
expect_equal(coef(a), coef(a[1:10, ]), info = "subset more than 1 feature is OK (coef)")
expect_equal(basis(a)[1:10, , drop = TRUE], a[1:10, , drop = TRUE],
info = "subset more than 1 feature dropping is OK (return basis)")
expect_equal(c(n, 1, r), dim(a[, 1]), info = "subset 1 sample is OK (dim)")
expect_equal(coef(a)[, 5, drop = FALSE], coef(a[, 5]), info = "subset 1 sample is OK (coef)")
expect_equal(basis(a), basis(a[, 1]), info = "subset 1 sample is OK (basis)")
expect_equal(coef(a)[, 5, drop = TRUE], a[, 5, drop = TRUE],
info = "subset 1 sample dropping is OK (return coef)")
expect_equal(c(n, 10, r), dim(a[, 1:10]), info = "subset more then 1 sample is OK (dim)")
expect_equal(coef(a)[, 1:10, drop = FALSE], coef(a[, 1:10]),
info = "subset more than 1 sample is OK (coef)")
expect_equal(basis(a), basis(a[, 1:10]), info = "subset more than 1 sample is OK (basis)")
expect_equal(coef(a)[, 1:10, drop = TRUE], a[, 1:10, drop = TRUE],
info = "subset more than 1 sample dropping is OK (return coef)")
expect_equal(c(n, p, 1), dim(a[, , 1]), info = "subset 1 basis is OK (dim)")
expect_equal(coef(a)[3, , drop = FALSE], coef(a[, , 3]),
info = "subset 1 basis is OK (coef)")
expect_equal(basis(a)[, 3, drop = FALSE], basis(a[, , 3]),
info = "subset 1 basis is OK (basis)")
expect_true(identical(a[, , 3, drop = TRUE], a[, , 3, drop = TRUE]),
info = "subset 1 basis dropping is OK (do nothing)")
expect_equal(c(n, p, 3), dim(a[, , 2:4]), info = "subset more than 1 basis is OK (dim)")
expect_equal(coef(a)[2:4, , drop = FALSE], coef(a[, , 2:4]),
info = "subset more than 1 basis is OK (coef)")
expect_equal(basis(a)[, 2:4, drop = FALSE], basis(a[, , 2:4]),
info = "subset more than 1 basis is OK (basis)")
expect_true(identical(a[, , 2:4, drop = TRUE], a[, , 2:4,
drop = FALSE]), info = "subset more than 1 basis dropping is OK (do nothing)")
expect_equal(c(n, p, 0), dim(a[NULL]), info = "subset basis NULL is OK (dim)")
expect_identical(basis(a)[, 2], a[2], info = "subset with single index + drop missing returns single basis as vector")
expect_identical(a[, , 2], a[2, drop = FALSE], info = "subset with single index with drop=FALSE returns the complete NMF object")
expect_identical(basis(a)[, 2, drop = TRUE], a[2, drop = TRUE],
info = "subset with single index + drop=TRUE returns single basis as vector")
expect_true(is.nmf(a[2:3]), info = "subset with single vector index returns NMF object")
expect_equal(basis(a)[, 2:3], basis(a[2:3]), info = "subset with single vector index returns subset of NMF object")
expect_equal(basis(a)[, 2:3, drop = TRUE], a[2:3, drop = TRUE],
info = "subset with single vector index + dropping returns correct matrix if length > 1")
expect_identical(a[, , 2:3], a[2:3, drop = FALSE], info = "subset with single vector index + NOT dropping returns correct matrix if length > 1")
expect_equal(c(1, 1, r), dim(a[1, 1]), info = "subset 1 feature x 1 sample is OK (dim)")
expect_equal(coef(a)[, 5, drop = FALSE], coef(a[3, 5]), info = "subset 1 feature x 1 sample is OK (coef)")
expect_equal(basis(a)[3, , drop = FALSE], basis(a[3, 5]),
info = "subset 1 feature x 1 sample is OK (basis)")
expect_equal(c(10, 7, r), dim(a[10:19, 5:11]), info = "subset more than 1 feature x sample is OK (dim)")
expect_equal(coef(a)[, 5:11], coef(a[10:19, 5:11]), info = "subset more than 1 feature x sample is OK (coef)")
expect_equal(basis(a)[10:19, ], basis(a[10:19, 5:11]), info = "subset more than 1 feature x sample is OK (basis)")
})
test_that("test.syntheticNMF", {
n <- 100
m <- 20
r <- 3
set.seed(.TestSeed)
d <- syntheticNMF(n, r, m)
checkPlot(basicHM(d), "Synthetic data plain")
set.seed(.TestSeed)
n.offset <- 15
o <- c(rep(1, n.offset), rep(0, n - n.offset))
d <- syntheticNMF(n, r, m, offset = o)
expect_error(syntheticNMF(n, r, m, offset = o[-1]))
checkPlot(basicHM(d), "Synthetic data offset")
set.seed(.TestSeed)
d <- syntheticNMF(n, r, m, noise = TRUE)
checkPlot(basicHM(d), "Synthetic data with noise")
set.seed(.TestSeed)
d <- syntheticNMF(n, r, m, offset = o, noise = TRUE)
checkPlot(basicHM(d), "Synthetic data with offset and noise")
})
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.