#' @eval get_description('OPLSR')
#' @export OPLSR
#' @examples
#' M = OPLSR('number_components'=2,factor_name='Species')
OPLSR = function(number_components=2,factor_name,...) {
out=struct::new_struct('OPLSR',
number_components = number_components,
factor_name=factor_name,
...)
return(out)
}
.OPLSR<-setClass(
"OPLSR",
contains=c('model'),
slots=c(
number_components='entity',
factor_name='entity',
opls_model='list',
filtered='DatasetExperiment',
orthogonal='DatasetExperiment'
),
prototype = list(name='Orthogonal Partial Least Squares regression',
type="filtering",
predicted='filtered',
description=paste0('OPLS splits a data matrix into two parts. One part
contains information orthogonal to the input vector, and the other is non-orthogonal.'),
.params=c('number_components','factor_name'),
.outputs=c('opls_model','filtered','orthogonal'),
number_components=entity(value = 2,
name = 'Number of OPLS components',
description = 'The number of orthgonal components',
type = c('numeric','integer')
),
factor_name=structToolbox:::ents$factor_name
)
)
#' @export
#' @template model_train
setMethod(f="model_train",
signature=c("OPLSR",'DatasetExperiment'),
definition=function(M,D) {
# prepare
y=D$sample_meta
y=y[,M$factor_name,drop=FALSE] # might be multiple columns (?)
X=as.matrix(D$data) # convert X to matrix
y=as.matrix(y)
# orthogonal PLS
opls_model = nipals_opls(X, y, M$number_components)
# create DE from filtered X
Xfilt = DatasetExperiment(
data=as.data.frame(opls_model$Xfilt),
sample_meta = D$sample_meta,
variable_meta = D$variable_meta,
name = 'OPLS filtered'
)
Xorth = DatasetExperiment(
data=as.data.frame(opls_model$Xorth),
sample_meta = D$sample_meta,
variable_meta = D$variable_meta,
name = 'OPLS orthogonal'
)
# store the results
M$opls_model = opls_model
M$filtered = Xfilt
M$orthogonal = Xorth
return(M)
}
)
#' @export
#' @template model_predict
setMethod(f="model_predict",
signature=c("OPLSR",'DatasetExperiment'),
definition=function(M,D) {
X = as.matrix(D$data)
Wo= M$opls_model$Wo
Po= M$opls_model$Po
Tno = list()
# remove orthogonal components from test set
for (n in 1:M$number_components) {
wo = Wo[,n,drop=FALSE]
po = Po[,n,drop=FALSE]
tno = (X %*% wo) / as.numeric((t(wo) %*% wo))
# deflate
X = X - (tno %*% t(po))
Tno[[n]]=tno
}
Tno = do.call(cbind,Tno)
Xorth = Tno %*% t(Po)
# create DE from filtered X
Xfilt = DatasetExperiment(
data=as.data.frame(X),
sample_meta = D$sample_meta,
variable_meta = D$variable_meta,
name = 'OPLS filtered'
)
Xorth = DatasetExperiment(
data=as.data.frame(Xorth),
sample_meta = D$sample_meta,
variable_meta = D$variable_meta,
name = 'OPLS orthogonal'
)
M$filtered=Xfilt
M$orthogonal=Xorth
return(M)
}
)
nipals_opls = function(X, Y, N) {
# X matrix (samples in rows, variables in columns)
# Y matrix (samples in rows, k columns)
# N number of orthogonal components
# prepare
Wo = list()
To = list()
Po = list()
# compute weights
W = list()
for (k in 1:ncol(Y)) {
y=Y[,k,drop=FALSE]
v = t(X) %*% y
w = v / as.numeric((t(v) %*% v))
W[[k]]=w
}
W = do.call(cbind,W) # J x K
# PCA of weights matrix
model=svd(W,ncol(W),ncol(W)) # assume fewer Y columns than X columns
# get the pca scores
if (ncol(W)==1) {
Tw=model$u * model$d[ncol(W)]
} else {
Tw=model$u %*% diag(model$d[1:ncol(W)])
}
# for each orthogonal component
for (n in 1:N) {
u = Y[,1,drop=FALSE]
unew = u*100
while (sqrt(sum((u - unew)^2)) > 1e-6) {
u = unew
v = t(X) %*% u # u-weights
w = v / sqrt(as.numeric(t(u) %*% u)) # normalised u-weights
t = X %*% w # x-scores
q = (t(Y) %*% t) / as.numeric((t(t) %*% t)) # Y-loadings
unew = Y %*% q / as.numeric(t(q) %*% q)
}
p = (t(X) %*% t) / as.numeric((t(t) %*% t)) # x-loadings
for (k in 1:ncol(Tw)) {
tw=Tw[,k,drop=FALSE]
p = p - as.numeric(((t(tw) %*% p) / (t(tw) %*% tw))) * tw
}
wo = p
wo = wo / as.numeric(sqrt(t(wo) %*% wo))
to = X %*% wo / as.numeric(t(wo) %*% wo)
po = (t(X) %*% to) / as.numeric(t(to) %*% to)
# deflate
X = X - (to %*% t(po))
# need to deflate Y?
# store the results
Wo[[n]] = wo
To[[n]] = to
Po[[n]] = po
}
Wo = do.call(cbind,Wo)
To = do.call(cbind,To)
Po = do.call(cbind,Po)
colnames(Wo)=paste0('OC',1:n)
colnames(To)=paste0('OC',1:n)
colnames(Po)=paste0('OC',1:n)
opls_model=list(
Wo = Wo,
To = To,
Po = Po,
Xfilt = X,
Xorth = To %*% t(Po))
return(opls_model)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.