Skip to contents

Fits a single HALS-NMF V ~ W H to the bulk expression matrix with a fixed number of components k. V is samples x features (matches the layout of raw_data / processed_data on BulkCoExp()). The result is rearranged so that:

  • gene_loadings (features x k) captures per-module gene contributions.

  • sample_activity (samples x k) captures per-module sample activity.

Module membership is derived by keeping the upper tail of each component's gene loadings, see params_module_membership(). A gene can belong to several modules, and a gene in no tail belongs to none.

Usage

nmf_bulk(
  object,
  k,
  preprocessing = c("none", "sd", "sqrt_sd"),
  nmf_hals_params = params_nmf_hals(),
  membership_params = params_module_membership(),
  seed = 42L,
  .verbose = TRUE
)

Arguments

object

The class, see BulkCoExp(). Ideally, you should run preprocess_bulk_coexp() before applying this function. The NMF requires non-negative input, so the pre-processing should either skip scaling or use a strictly non-negative representation.

k

Integer. Number of latent factors (modules).

preprocessing

String. One of c("none", "sd", "sqrt_sd"). Applied inside the Rust kernel to the input matrix before the HALS updates.

nmf_hals_params

List. Output of params_nmf_hals():

  • max_iter - Integer. Maximum number of HALS iterations.

  • tol - Float. Convergence tolerance.

  • eps - Float. Numerical floor.

  • check_every - Integer. Convergence check interval.

  • nmf_init - String. One of c("nndsvd", "svd", "random").

membership_params

List. Controls how the gene loadings are turned into module membership, see params_module_membership(). Membership is not exclusive: a gene loading strongly on several components appears in several modules, and a gene in no tail appears in none.

seed

Integer. Random seed for the NMF initialisation. Defaults to 42L.

.verbose

Boolean or integer 0L/1L/2L. Controls verbosity.

Value

The class with final_results populated (see description) and the fit parameters stored under params$nmf_fit, plus params$detection_method = "nmf-based".

References

Cichocki & Phan, IEICE Trans., 2009.

Examples

# a single four-factor HALS-NMF fit
syn <- generate_gene_module_data(n_samples = 24L, n_genes = 60L)
# NMF needs a non-negative matrix
mat <- syn$data - min(syn$data)
obj <- BulkCoExp(mat, syn$meta_data)
obj <- preprocess_bulk_coexp(
  obj, hvg = NULL, scaling = FALSE, .verbose = FALSE
)
obj <- nmf_bulk(obj, k = 4L, .verbose = FALSE)
head(get_nmf_modules(obj))
#>          gene module_id  loading   sign        z
#>        <char>    <char>    <num> <char>    <num>
#> 1: feature_44   comp_01 3.675330    pos 38.28581
#> 2: feature_40   comp_01 3.643421    pos 37.94433
#> 3: feature_42   comp_01 3.633641    pos 37.83967
#> 4: feature_31   comp_01 3.630990    pos 37.81130
#> 5: feature_34   comp_01 3.602253    pos 37.50377
#> 6: feature_45   comp_01 3.590235    pos 37.37517