R/HSDEM_class.R

Defines functions HSDEM

Documented in HSDEM

#' @eval get_description('HSDEM')
#' @include mixed_effect_class.R HSD_class.R
#' @export HSDEM
#' @examples
#' D = iris_DatasetExperiment()
#' D$sample_meta$id=rownames(D) # dummy id column
#' M = HSDEM(formula = y~Species+ Error(id/Species))
#' M = model_apply(M,D)
#'
HSDEM = function(alpha=0.05,mtc='fdr',formula,...) {
    out=struct::new_struct('HSDEM',
        alpha=alpha,
        mtc=mtc,
        formula=formula,
        ...)
    return(out)
}


.HSDEM<-setClass(
    "HSDEM",
    contains=c('model'),
    slots=c(
        # INPUTS
        alpha='entity',
        mtc='enum',
        formula='entity',

        # OUTPUTS
        p_value='entity',
        significant='entity'
    ),
    prototype = list(name="Tukey's Honest Significant Difference using estimated marginal means",
        description=paste0("Tukey's HSD post hoc test is a modified t-test ",
            'applied for all features to all pairs of levels in a factor. ',
            'It is used to determine which groups are different (if any). A multiple ',
            'test corrected p-value is computed to indicate which groups are ',
            'significantly different to the others for each feature. ',
            'For mixed effects models estimated marginal means are used.'),
        type="univariate",
        predicted='p_value',
        ontology="STATO:0000187",
        libraries=c('emmeans','nlme'),
        .params=c('alpha','mtc','formula'),
        .outputs=c('p_value','significant'),

        alpha=ents$alpha,
        mtc=ents$mtc,
        formula=ents$formula,
        p_value=ents$p_value,
        significant=ents$significant
    )
)

#' @export
#' @template model_apply
setMethod(f="model_apply",
    signature=c("HSDEM",'DatasetExperiment'),
    definition=function(M,D) {
        X=D$data
        lmer_formula=aov2lme(M$formula)
        var_names=all.vars(M$formula)
        var_names_1=var_names[1]
        var_names=var_names[-1]
        y=D$sample_meta[var_names]

        # set the contrasts
        O=options('contrasts') # keep the old ones
        options(contrasts = c("contr.sum","contr.poly"))

        # attempt to detect within factors
        within=which(var_names %in% all.names(M$formula)[which('Error'== all.names(M$formula))+2])
        if (length(within)>0) {
            var_names_ex=var_names[-within]
        } else {
            var_names_ex=var_names
        }

        FF=full_fact(var_names_ex)
        FF=apply(FF,1,function(x) var_names_ex[x==1])
        FF=FF[-1]

        output=apply(X,2,function(x) {
            temp=y
            temp[[var_names_1]]=scale(x,center = TRUE,scale=TRUE)

            dona=FALSE

            testlm=tryCatch({ # if any warnings/messages set p-values to NA as unreliable
                LM=nlme::lme(lmer_formula$f,random=lmer_formula$random,method='ML',data=temp,na.action=na.omit)
            }, warning = function(w) {
                NA
            }, message = function(m) {
                NA
            }, error   = function(e) {
                NA
            })

            output2=list()
            for (k in 1:length(FF)) {
                if (!is.na(testlm[[1]])) {
                    testhsd=tryCatch({
                        output2[[k]]=as.data.frame(
                                pairs(
                                emmeans::emmeans(LM,FF[[k]],
                                data=temp)))
                    }, warning  = function(w) {
                        NA
                    } , message = function(m) {
                        NA
                    }, error    = function(e) {
                        NA
                    })

                    if (!is.data.frame(testhsd[1])) {
                        output2[[k]]=NA
                    }
                } else {
                    output2[[k]]=NA
                }
            }

            return(output2)
        })

        p_value=lapply(output,function(x) {
            x=as.data.frame(x)
            return(x$p.value)
        })
        ln=length(p_value[[1]])
        p_value=lapply(p_value,function(x){
            if (length(x)!=ln) {
                return(p_value[[1]]*NA)
            } else {
                return(x)
            }
        })

        p_value=do.call("rbind",p_value)
        p_value=data.frame(p_value)
        colnames(p_value)=as.data.frame(output[[1]])$contrast

        # fdr correct
        M$p_value=as.data.frame(apply(p_value,2,p.adjust,method=M$mtc))

        M$significant=as.data.frame(M$p_value<M$alpha)

        # reset contrasts
        options(O)

        return(M)
    }
)
computational-metabolomics/structtoolbox documentation built on Feb. 9, 2024, 8:19 a.m.