| ComDim_y | R Documentation |
Extends any PLS-like method used for regression or discriminant purposes to
the multi-block field. The user provides a function (FUN) that
computes one predictive component from the salience-weighted concatenated
blocks; global scores, local scores, and loadings are then derived following
the traditional ComDim-PLS framework. Optionally, orthogonal components
returned by FUN (e.g. from an O-PLS wrapper) are captured. VIP scores and
k-fold cross-validation are also supported.
ComDim_y(
MB = MB,
y = y,
ndim = NULL,
FUN = FUN,
nort = 0L,
type = c("regression", "discriminant")[1],
decisionRule = c("fixed", "max")[2],
normalise = FALSE,
scale.y = FALSE,
threshold = 1e-10,
loquace = FALSE,
method = "FUN",
cv.k = 7,
...
)
MB |
A MultiBlock object. |
y |
The response: a numeric vector or matrix for regression
( |
ndim |
Number of predictive Common Dimensions. If |
FUN |
The function used as the core of the ComDim analysis. It must
accept
Optional return fields:
|
nort |
Number of orthogonal Common Dimensions to extract before the
predictive loop. Default |
type |
|
decisionRule |
Only used when |
normalise |
To apply block normalisation. |
scale.y |
Logical (default |
threshold |
Convergence threshold: iterations stop when the change
in the global score vector falls below this value (default |
loquace |
Display computation time at each step. |
method |
A string label identifying the method (default: |
cv.k |
Number of folds for k-fold cross-validation (default 7). Set
to 0 to skip CV. When |
... |
Additional arguments passed to |
A ComDim object with the following slots:
MethodThe label supplied via the method argument.
ndimNumber of predictive Common Dimensions extracted.
Q.scoresGlobal consensus scores matrix (n \times
ndim). Each column \mathbf{q}_a (unit-norm) is derived from
the dominant left direction of FUN applied to the salience-weighted
concatenated blocks.
T.scoresNamed list of block-specific local scores
(n \times ndim each). Local loading
\mathbf{p}_{ba} = \tilde{\mathbf{X}}_b'\mathbf{q}_a (computed
on the ort-deflated block when nort > 0); local score
\mathbf{t}_{ba} =
\tilde{\mathbf{X}}_b\,\mathbf{p}_{ba}(\mathbf{p}_{ba}'\mathbf{p}_{ba})^{-1}.
P.loadingsGlobal loadings (p_{tot} \times ndim):
\mathbf{P} = \tilde{\mathbf{X}}'\mathbf{Q}, where
\tilde{\mathbf{X}} is the (optionally ort-deflated) mean-centred
concatenated blocks.
SaliencesBlock salience matrix (ntable \times ndim):
\lambda_{ba} =
\mathbf{q}_a'\tilde{\mathbf{X}}_b\tilde{\mathbf{X}}_b'\mathbf{q}_a.
R2XProportion of X variance captured by each predictive
component (named vector, length ndim). Let \mathbf{t}_a
be the X-score vector returned by FUN for component a:
R2X_a = \|\mathbf{t}_a\|^4 \big/ \sum_k \|\mathbf{t}_k\|^4.
When nort > 0, the denominator also includes the orthogonal
\|\mathbf{t}_{ort,k}\|^4 terms, and the orthogonal R2X fractions
are stored separately in Orthogonal$R2X.
R2YCumulative Y-variance explained (named vector, length
ndim):
R2Y_a = 1 - RSS_a / TSS_Y,
where RSS_a is the residual SS from an OLS regression of
\mathbf{Y} on [1, \mathbf{q}_1, \ldots, \mathbf{q}_a].
Note: R2Y_a is cumulative – the total Y-variance
explained by the first a components together, not the marginal
contribution of component a alone.
Q2Predictive Q2 per response column (regression) or per class (discriminant), named accordingly:
Q2 = 1 - PRESS / TSS_Y,
where PRESS = \sum_i (\hat{y}_i - y_i)^2.
When cv.k >= 2 and nort = 0: cross-validated (out-of-
sample) predictions are used; otherwise training-set predictions.
CV is automatically skipped when nort > 0.
DQ2(Discriminant mode only) Discriminant Q2 per class, using only penalising residuals:
DQ2 = 1 - PRESSD / TSS_Y,
where PRESSD sums \hat{y}_i^2 for class-0 samples with
\hat{y}_i > 0, and (\hat{y}_i - 1)^2 for class-1 samples
with \hat{y}_i < 1. Same cross-validation logic as Q2.
SingularSquared L2 norm of the FUN X-score vector per
component (\|\mathbf{t}_a\|^2), used to derive R2X.
VIPGlobal total VIP (named vector, length p_{tot}):
concatenation of VIP.block[[b]]$tot across blocks. When
nort = 0, uses the Wold formula; when nort = 1, tot
combines predictive and orthogonal VIPs (see VIP.block).
VIP.blockNamed list (one data.frame per block).
When nort = 0: columns p and tot (= p),
using the Wold formula:
VIPp_j = \sqrt{p_b \cdot
\frac{\sum_a s_a \tilde{w}_{j,a}^2}{\sum_a s_a}},
where s_a = \|\mathbf{t}_a\|^2\|\mathbf{q}_a\|^2 and
\tilde{w}_{j,a} = w_{j,a}/\|\mathbf{w}_a\| is the L2-normalised
j-th element of the a-th weight vector.
When nort = 1: columns p (Wold, same as above),
o (orthogonal VIP, loadings-based:
VIPo_j = \sqrt{p_b \cdot \sum_a s_{oa}\tilde{P}_{o,j,a}^2 /
\sum_a s_{oa}},
where s_{oa} = \|\mathbf{q}_{ort}[,a]\|^2 and
\tilde{\mathbf{P}}_o is the column-L2-normalised block-slice of
the ort loadings), and tot
(VIPtot_j = \sqrt{(VIPp_j^2 + VIPo_j^2)/2}).
Row names are variable names.
PLS.modelList with: W (X weight matrix collected
from FUN, p_{tot} \times ndim); B (regression
coefficients,
\mathbf{B} = \mathbf{W}(\mathbf{P}'\mathbf{W})^{-1}\mathbf{Q}',
in original Y units); B0 (intercept,
\mathbf{B}_0 = \bar{\mathbf{y}} -
\overline{\tilde{\mathbf{x}}}\mathbf{B}); Y (original
response matrix as supplied).
Training-set predictions:
\hat{\mathbf{Y}} =
\tilde{\mathbf{X}}\mathbf{B} + \mathbf{B}_0.
cvCross-validation results when cv.k >= 2 and
nort = 0 (empty list otherwise): k, fold
(sample-to-fold vector), Ypred (n \times ncol(Y)
out-of-sample predictions), Q2 (CV Q2 per class/response),
DQ2 (mean CV DQ2, discriminant only),
DQ2.perclass (CV DQ2 per class, discriminant only).
OrthogonalWhen nort > 0: list with nort,
Q.scores (global ort scores, n \times nort, unit-norm),
T.scores (block ort local scores, n \times nort each),
P.loadings.ort (ort loadings, p_{tot} \times nort),
Saliences.ort (ntable \times nort), and R2X
(orthogonal X-variance fractions,
R2X_{ort,a} = \|\mathbf{t}_{ort,a}\|^4 / total).
Empty list when nort = 0.
PredictionTraining-set predictions: Y.pred
(n \times ncol(Y)); for discriminant analysis also
decisionRule, trueClass, predClass (data.frame),
Sensitivity and Specificity (per class),
confusionMatrix (named list of 2x2 matrices).
MeanList with MeanMB (column means per block),
MeanY (column means of Y), and ScaleY (column SDs of Y;
all ones when scale.y = FALSE).
NormList with NormMB: Frobenius norms for block
normalisation.
variable.blockCharacter vector (length p_{tot})
mapping each row of P.loadings and each element of VIP
to its block.
runtimeTotal computation time in seconds.
b1 <- matrix(rnorm(500), 10, 50) # 10 samples, 50 variables
b2 <- matrix(rnorm(800), 10, 80) # 10 samples, 80 variables
mb <- MultiBlock(Data = list(b1 = b1, b2 = b2))
## Example 1: ComDim-PLS (regression) ---------------------------------------
# Single-step NIPALS PLS wrapper (one predictive component per call).
# Note: 'tx' is used instead of 't' to avoid shadowing base::t().
fun.PLS <- function(W, y, ndim, ...) {
output <- list()
w <- t(W) %*% y / as.numeric(t(y) %*% y) # X weight (u = y, 1 step)
w <- w / sqrt(sum(w^2)) # L2 normalise
tx <- W %*% w # X score
p <- t(W) %*% tx / as.numeric(t(tx) %*% tx) # X loading
q <- t(y) %*% tx / as.numeric(t(tx) %*% tx) # Y loading
u <- y %*% q / as.numeric(t(q) %*% q) # Y score
output$scores <- as.vector(tx)
output$P <- as.vector(p)
output$W <- as.vector(w)
output$Q <- as.vector(q)
output$U <- as.vector(u)
return(output)
}
y <- c(1, 1, 1, 1, 1, 5, 5, 5, 10, 10)
resultsPLS <- ComDim_y(mb,
y = y, ndim = 2,
type = "regression",
FUN = fun.PLS,
method = "PLS",
cv.k = 0
)
## Example 2: ComDim-OPLS-DA (discriminant, nort = 1) ----------------------
# Thin wrapper around OPLS_NIPALS_DNR(), the package's NIPALS OPLS engine.
# All inputs (W, y, and any extra args such as 'threshold') are forwarded
# directly via '...'. Use this pattern when nort > 0; for nort = 0 the
# simpler PLS wrapper in Example 1 is sufficient (no orthoscores needed).
fun.OPLS <- function(W, y, ndim, ...) {
res <- OPLS_NIPALS_DNR(W = W, y = y, ...)
list(
scores = as.vector(res$t_pred),
P = as.vector(res$p),
W = as.vector(res$w_pred),
Q = as.vector(res$q),
U = as.vector(res$u),
orthoscores = matrix(res$t_ort, ncol = 1)
)
}
groups <- c(rep("A", 5), rep("B", 5))
resultsOPLS <- ComDim_y(mb,
y = groups, ndim = 1,
nort = 1,
type = "discriminant",
FUN = fun.OPLS,
method = "OPLS-DA",
cv.k = 0
)
## Example 3 (not run): ComDim-OPLS-DA via ropls ---------------------------
# Wrapping ropls::opls is also possible. Key points:
# - Use orthoI = 1 (fixed) instead of NA so the output is predictable.
# - Always return output$orthoscores; ComDim_y ignores it in phases
# where ort has already been removed.
# - Expand the single ropls Q loading to match the ncol(y_dummy) width.
if (requireNamespace("ropls", quietly = TRUE)) {
fun.OPLSDA.ropls <- function(W, y, ndim, ...) {
output <- list()
# Convert dummy matrix to ropls-compatible -1/+1 vector
Y <- c(-1, 1)[apply(y, 1, function(x) match(1, x))]
result <- tryCatch(
ropls::opls(
x = W, y = Y, predI = 1, orthoI = 1,
fig.pdfC = "none", info.txtC = "none"
),
error = function(e) {
ropls::opls(
x = W, y = Y, predI = 1, orthoI = 0,
fig.pdfC = "none", info.txtC = "none"
)
}
)
output$scores <- result@scoreMN[, 1]
output$P <- result@loadingMN[, 1]
output$W <- result@weightMN[, 1]
output$U <- result@uMN[, 1]
# Expand the single ropls Q loading to match the 2-column dummy matrix:
# loadings for class1 and class2 are antisymmetric in binary PLS-DA.
output$Q <- c(-result@cMN[, 1], result@cMN[, 1])
output$y <- result@suppLs$yModelMN # internal y (for scaling detection)
# Orthogonal scores (used during the ort pre-loop when nort > 0)
if (!is.null(result@orthoScoreMN) && ncol(result@orthoScoreMN) > 0) {
output$orthoscores <- result@orthoScoreMN # n x k matrix; col jj used for jj-th ort
} else {
output$orthoscores <- matrix(0, nrow = nrow(W), ncol = 1)
}
return(output)
}
b1_r <- matrix(rnorm(8 * 30), 8, 30)
b2_r <- matrix(rnorm(8 * 20), 8, 20)
mb_r <- MultiBlock(Data = list(b1 = b1_r, b2 = b2_r))
resultsOPLSDA <- ComDim_y(mb_r,
y = c(rep("NI", 4), rep("OFF", 4)),
ndim = 1,
nort = 1,
type = "discriminant",
FUN = fun.OPLSDA.ropls,
method = "OPLS-DA(ropls)",
cv.k = 0
)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.