Co-clustering two variable blocks with NMF-RRR (nmf.rrr)

Introduction

Many studies measure two blocks of variables on the same individuals – a block of covariates (inputs) and a block of responses (outputs) – and ask how groups of covariates relate to groups of responses. nmf.rrr() answers this by starting from the multivariate linear regression of the responses on the covariates and giving its non-negative regression coefficient matrix a tri-factorization

where (each column summing to one) softly clusters the response variables, (each row summing to one) softly clusters the covariate variables, and is a tested matrix of block correspondences. Because has rank , this is the non-negative, parts-based member of the reduced-rank regression (RRR) family – hence NMF-RRR – related to RRR as NMF is to PCA.

nmf.rrr() and its nmf.rrr.* helpers are the canonical interface; the names emphasise the reduced-rank-regression reading. The former nmfae() family names are retained as deprecated aliases for backward compatibility.

This vignette reproduces the Doubs example (community ecology), where a single dominant upstream–downstream gradient aligns both blocks, so the correspondence is a clean permutation.

library(nmfkc)

The Doubs data

The Doubs data (Verneaux, 1973) record 27 fish species and 11 environmental variables at 30 sites along a French river – a classic illustration of canonical (correspondence) analysis. We take the fish abundances as the response block and the environmental variables as the covariate block .

Each variable is mapped to by a per-variable min–max transform (nmfkc.normalize()), which makes the sign-free environmental variables non-negative, and both blocks are laid out as variables sites ().

data(doubs, package = "ade4")

# per-variable min-max to [0,1], then transpose to (variables x sites)
nz <- function(M) t(nmfkc.normalize(as.matrix(M)))
Y1 <- nz(doubs$fish)   # responses: 27 fish species x 30 sites
Y2 <- nz(doubs$env)    # covariates: 11 environment x 30 sites
dim(Y1)
#> [1] 27 30
dim(Y2)
#> [1] 11 30

Fitting NMF-RRR

Element-wise cross-validation (below) selects . Signed models and inference benefit from several k-means restarts, so we set nstart = 20 and a tight tolerance.

fit <- nmf.rrr(Y1, Y2, rank1 = 2, rank2 = 2,
               epsilon = 1e-8, nstart = 20, seed = 1)

# in-sample, column-centered R^2
Y1hat <- fit$X1 %*% fit$C %*% fit$X2 %*% Y2
R2 <- 1 - sum((Y1 - Y1hat)^2) / sum((Y1 - rowMeans(Y1))^2)
round(R2, 3)
#> [1] 0.435

The fit is R2 = 0.435, reproducing the classical longitudinal zonation of the river.

Response groups (fish guilds)

Each column of is a probability vector over the fish species; the top species per column name the guild.

for (q in 1:ncol(fit$X1))
  cat(sprintf("Resp%d: %s\n", q,
      paste(rownames(Y1)[order(-fit$X1[, q])[1:6]], collapse = ", ")))
#> Resp1: Neba, Phph, Satr, Cogo, Thth, Teso
#> Resp2: Alal, Ruru, Gogo, Acce, Baba, Titi

Resp1 is a cold-water upstream guild (brown trout Satr, Phph, Neba, Cogo, grayling Thth) and Resp2 a warm-water downstream guild (roach Ruru, Gogo, barbel Baba, Alal).

Covariate groups (environmental gradients)

Each row of is a probability vector over the environmental variables.

for (r in 1:nrow(fit$X2))
  cat(sprintf("Cov%d: %s\n", r,
      paste(rownames(Y2)[order(-fit$X2[r, ])[1:5]], collapse = ", ")))
#> Cov1: dfs, flo, har, nit, pH
#> Cov2: oxy, alt, pH, slo, har

Cov1 is a nutrient / downstream gradient (distance from source dfs, flow flo, nitrate nit, BOD bdo) and Cov2 an oxic / upstream gradient (dissolved oxygen oxy, altitude alt, pH, slope slo).

Choosing the two ranks

Because the attainable fit is bounded by , the in-sample fit cannot choose the ranks; we use element-wise cross-validation (nmf.rrr.ecv()), which holds out entries of and predicts them.

ecv <- nmf.rrr.ecv(Y1, Y2, rank1 = 1:2, rank2 = 1:2,
                   nfolds = 5, seed = 123)
#> Element-wise CV: 4 (Q,R) pairs, 5-fold, 20 tasks...
#>   Q=1, R=1: MSE=0.090948, sigma=0.3016
#>   Q=2, R=1: MSE=0.090948, sigma=0.3016
#>   Q=1, R=2: MSE=0.090954, sigma=0.3016
#>   Q=2, R=2: MSE=0.065768, sigma=0.2565
round(ecv$sigma, 4)
#> Q=1,R=1 Q=2,R=1 Q=1,R=2 Q=2,R=2 
#>  0.3016  0.3016  0.3016  0.2565

The smallest hold-out error is at .

Inference for the correspondence matrix

The entries of say how strongly each covariate group drives each response group. nmf.rrr.inference() attaches standard errors (Fisher + wild bootstrap) and a one-sided boundary test (each ).

inf <- nmf.rrr.inference(fit, Y1, Y2)
co  <- inf$coefficients
print(format(co[order(co$p_value), c("Basis","Covariate","Estimate","SE","z_value","p_value")],
             digits = 3))
#>   Basis Covariate Estimate    SE  z_value  p_value
#> 3 Resp1      Cov2 3.97e+00 0.505 7.86e+00 1.93e-15
#> 2 Resp2      Cov1 1.40e+01 1.837 7.65e+00 1.03e-14
#> 1 Resp1      Cov1 2.06e-48 0.603 3.42e-48 5.00e-01
#> 4 Resp2      Cov2 9.54e-27 1.004 9.51e-27 5.00e-01

is a near-permutation: the upstream guild is driven by the oxic gradient and the downstream guild by the nutrient gradient (both ), while the two off-diagonal paths are essentially zero ().

round(fit$C, 3)
#>         Cov1  Cov2
#> Resp1  0.000 3.971
#> Resp2 14.049 0.000

Visualising and the two co-clusterings

nmf.rrr.heatmap() shows the response basis , the correspondence , and the covariate basis together.

nmf.rrr.heatmap(fit)

Relation to other methods

Dropping non-negativity, at rank is ordinary reduced-rank regression (RRR): it attains a higher in-sample fit ( on Doubs) but returns signed loadings and no clusters. On these data the two share the dominant fitted direction (leading principal-angle cosine ); they differ in the basis of that subspace – non-negative parts versus signed singular directions – exactly as NMF relates to PCA. An unsupervised tri-NMF of the association recovers the same guilds and gradients here (the gradient is so dominant that supervised and unsupervised co-clusterings coincide), but, unlike NMF-RRR, cannot predict the community at a new site through .

When within-block and cross-block structure disagree – e.g. under – the non-negative, normalized parameterization of NMF-RRR stays well-behaved and exposes cross-structure (one response group driven by several covariate groups) that these baselines miss; see the paper for the nutrimouse and microbiome–metabolome examples.

References