Skip to content

Leave a response fixed per subject untransformed in tpls(), tplsda() and block_tpls() - #17

Open
kimanh-lecao wants to merge 7 commits into
brendanlu:mainfrom
kimanh-lecao:pr/07-subject-fixed-response
Open

kimanh-lecao wants to merge 7 commits into
brendanlu:mainfrom
kimanh-lecao:pr/07-subject-fixed-response

Conversation

@kimanh-lecao

@kimanh-lecao kimanh-lecao commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Builds on #16; only the last commit is new.

A response that is fixed per subject, such as a class label or an endpoint measured once, is copied
to every time point and m-transformed with X. Under the DCT it is then non-zero on face 1 only, the
subject time averages, so every component comes from face 1 and tplsda() equals PLS-DA on the
time averages: features whose groups differ in how they change over time, but not in their mean,
cannot be found.

set.seed(80)
n <- 30; p <- 20; t <- 4
g <- rep(c("A", "B"), each = n / 2)
x <- array(rnorm(n * p * t), dim = c(n, p, t))
# features 1 to 5 rise over time in group A and fall in group B: same mean, different shape
for (j in 1:5) x[, j, ] <- x[, j, ] + outer(ifelse(g == "A", 0.5, -0.5), c(-1.5, -0.5, 0.5, 1.5))
tplsda(x, g, ncomp = 2)$faces   # 1 1 on main; 2 2 with this PR
# share of the component-1 loading on features 1 to 5 (0.25 is chance): 0.37 on main, 0.93 here

Change. A new argument transform_y.

  • tpls() and block_tpls(): NULL by default, decided by the shape of the response. A vector or an
    n x q matrix (the target block, for block_tpls()) is fixed per subject and is not transformed, so
    every face of X is compared with the response itself; an order-3 tensor is transformed as before.
    FALSE with a tensor that changes over time stops with an error.
  • tplsda() and block_tplsda(): transform_y = multi_label, so a single label per subject is not
    transformed and labels repeated over time still are.
  • An untransformed response is one matrix shared by every face, so after each component it is
    deflated on every face. In block_tpls() regression mode that is the existing average over the
    blocks' deflations, applied to every face.

Calls with a tensor response, multi_label = TRUE and transform_y = TRUE are identical() to
before. The default tplsda() and block_tplsda() fits change, as intended. Face scaling, which
the untransformed response needs once between-subject variation is large (face 1 then wins on its
size), follows in #18.

Tests. New tests in test-tens.tpls.R, test-tens.tplsda.R and test-tens.block.tplsda.R:
on data like the example's, tplsda() and block_tplsda() leave face 1, and stay on it with
transform_y = TRUE; a matrix response and the same response as a constant tensor give the same fit;
a rank-1 response in canonical mode leaves nothing for a second component, which checks that it is
deflated on every face; and transform_y = FALSE refuses a response that changes over time. They fail
on the current main and pass with the change. The full test suite passes.

Closes #7.

Copilot AI balanced review requested due to automatic review settings October 16, 2026 00:01

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tplsda() only sees time averages when the response is fixed per subject

2 participants