From 2adde62f18ce6470091a9db117fa0feff2c03fcb Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Tue, 12 Apr 2022 17:50:33 +0100 Subject: [PATCH 01/89] Now possible to specifiy multiple factors to `cls` in aggregation methods --- R/aggregate.R | 91 +++++++++++++++---------------------- man/aggregate.Rd | 8 ++-- vignettes/pre_treatment.Rmd | 6 +-- 3 files changed, 43 insertions(+), 62 deletions(-) diff --git a/R/aggregate.R b/R/aggregate.R index 333c91dc..b54bdaf6 100644 --- a/R/aggregate.R +++ b/R/aggregate.R @@ -2,7 +2,7 @@ #' @rdname aggregate #' @description Aggregation of sample features based on a grouping variable. #' @param d S4 object of class `AnalysisData` -#' @param cls info column to use for class data +#' @param cls info columns across which to aggregate the data #' @return An S4 object of class `AnalysisData` containing the aggregated data. #' @details #' Sample aggregation allows the electronic pooling of sample features based on a grouping variable. @@ -26,17 +26,17 @@ #' #' ## Mean aggregation #' d %>% -#' aggregateMean(cls = 'day') %>% +#' aggregateMean(cls = c('day','class')) %>% #' plotPCA(cls = 'day',ellipses = FALSE) #' #' ## Median aggregation #' d %>% -#' aggregateMedian(cls = 'day') %>% +#' aggregateMedian(cls = c('day','class')) %>% #' plotPCA(cls = 'day',ellipses = FALSE) #' #' ## Sum aggregation #' d %>% -#' aggregateSum(cls = 'day') %>% +#' aggregateSum(cls = c('day','class')) %>% #' plotPCA(cls = 'day',ellipses = FALSE) #' @export @@ -48,23 +48,7 @@ setGeneric("aggregateMean", function(d,cls = 'class') setMethod('aggregateMean',signature = 'AnalysisData', function(d,cls = 'class'){ - dat(d) <- d %>% - dat() %>% - bind_cols(select(d %>% sinfo(),Class = cls)) %>% - gather('Feature','Intensity',-Class) %>% - group_by(Class,Feature) %>% - summarise(Intensity = mean(Intensity)) %>% - ungroup() %>% - spread(Feature,Intensity) %>% - select(-Class) - - sinfo(d) <- d %>% - sinfo() %>% - select(cls) %>% - group_by_all() %>% - summarise() %>% - arrange_all() - + d <- aggregate(d,'mean',cls) return(d) } ) @@ -80,23 +64,7 @@ setGeneric("aggregateMedian", function(d,cls = 'class') setMethod('aggregateMedian',signature = 'AnalysisData', function(d, cls = 'class'){ - dat(d) <- d %>% - dat() %>% - bind_cols(select(d %>% sinfo(),Class = cls)) %>% - gather('Feature','Intensity',-Class) %>% - group_by(Class,Feature) %>% - summarise(Intensity = median(Intensity)) %>% - ungroup() %>% - spread(Feature,Intensity) %>% - select(-Class) - - sinfo(d) <- d %>% - sinfo() %>% - select(cls) %>% - group_by_all() %>% - summarise() %>% - arrange_all() - + d <- aggregate(d,'median',cls) return(d) } ) @@ -113,23 +81,36 @@ setGeneric("aggregateSum", function(d,cls = 'class') setMethod('aggregateSum',signature = 'AnalysisData', function(d,cls = 'class'){ - dat(d) <- d %>% - dat() %>% - bind_cols(select(d %>% sinfo(),Class = cls)) %>% - gather('Feature','Intensity',-Class) %>% - group_by(Class,Feature) %>% - summarise(Intensity = sum(Intensity)) %>% - ungroup() %>% - spread(Feature,Intensity) %>% - select(-Class) - - sinfo(d) <- d %>% - sinfo() %>% - select(cls) %>% - group_by_all() %>% - summarise() %>% - arrange_all() - + d <- aggregate(d,'sum',cls) return(d) } ) + +aggregate <- function(d,method,cls){ + aggregateMethod <- switch(method, + mean = mean, + median = median, + sum = sum) + + sample_info <- d %>% + sinfo() %>% + select(all_of(cls)) + + dat(d) <- d %>% + dat() %>% + bind_cols(sample_info) %>% + gather('Feature','Intensity',-all_of(cls)) %>% + group_by(across(cls),Feature) %>% + summarise(Intensity = aggregateMethod(Intensity)) %>% + ungroup() %>% + spread(Feature,Intensity) %>% + select(-all_of(cls)) + + sinfo(d) <- sample_info %>% + group_by_all() %>% + summarise() %>% + arrange_all() + + return(d) + +} diff --git a/man/aggregate.Rd b/man/aggregate.Rd index 50df4dc4..1ce71093 100644 --- a/man/aggregate.Rd +++ b/man/aggregate.Rd @@ -24,7 +24,7 @@ aggregateSum(d, cls = "class") \arguments{ \item{d}{S4 object of class \code{AnalysisData}} -\item{cls}{info column to use for class data} +\item{cls}{info columns across which to aggregate the data} } \value{ An S4 object of class \code{AnalysisData} containing the aggregated data. @@ -60,16 +60,16 @@ d \%>\% ## Mean aggregation d \%>\% - aggregateMean(cls = 'day') \%>\% + aggregateMean(cls = c('day','class')) \%>\% plotPCA(cls = 'day',ellipses = FALSE) ## Median aggregation d \%>\% - aggregateMedian(cls = 'day') \%>\% + aggregateMedian(cls = c('day','class')) \%>\% plotPCA(cls = 'day',ellipses = FALSE) ## Sum aggregation d \%>\% - aggregateSum(cls = 'day') \%>\% + aggregateSum(cls = c('day','class')) \%>\% plotPCA(cls = 'day',ellipses = FALSE) } diff --git a/vignettes/pre_treatment.Rmd b/vignettes/pre_treatment.Rmd index 704c3de7..d3353001 100644 --- a/vignettes/pre_treatment.Rmd +++ b/vignettes/pre_treatment.Rmd @@ -262,7 +262,7 @@ Using a different approach such as the parametric analysis Of variance (ANOVA) w ### Sample aggregation -Sample aggregation allows the electronic pooling of samples based on a grouping variable. +Sample aggregation allows the electronic pooling of samples based on a grouping variables. This is useful in situations such as the presence of technical replicates that can be aggregated to reduce the effects of pseudo replication. `metabolyseR` provides methods for mean, median and sum aggregation and each starts with the `aggregate` prefix. @@ -275,12 +275,12 @@ d %>% plotPCA(cls = 'day') ``` -The example below shows the mean aggregation of the data using the experimental classes within the `day` sample information column. +The example below shows the mean aggregation of the data using the experimental factors within the `day` and `class` sample information columns. ```{r day_mean} day_mean <- d %>% occupancyMaximum(cls = 'day') %>% - aggregateMean(cls = 'day') + aggregateMean(cls = c('day','class')) ``` The PCA plot below shows these class averages of the data. From 0ec10b42f276023868467abd90f9e0db62dfbd61 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Tue, 12 Apr 2022 17:50:45 +0100 Subject: [PATCH 02/89] Update documentation --- man/modelling-accessors.Rd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/modelling-accessors.Rd b/man/modelling-accessors.Rd index 90565c65..39db705f 100644 --- a/man/modelling-accessors.Rd +++ b/man/modelling-accessors.Rd @@ -107,7 +107,7 @@ Methods for accessing modelling results. \itemize{ \item \code{binaryComparisons}: Return a vector of all possible binary comparisons for a given sample information column. -\item \code{mtry}: Calculate the default \code{mtry} random forest parameter value for a given sample information column. +\item \code{mtry}: Return the default \code{mtry} random forest parameter value for a given sample information column. \item \code{type}: Return the type of random forest analysis. \item \code{response}: Return the response variable name used for a random forest analysis. \item \code{metrics}: Retrieve the model performance metrics for a random forest analysis From d5e29b2c4f756d4024109cedbe756048462a775c Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Thu, 14 Apr 2022 14:42:40 +0100 Subject: [PATCH 03/89] correlations can now be thresholded by both coefficient and number using the `minCoef` and `maxCor` arguments --- NAMESPACE | 1 + R/correlations.R | 34 ++++++++++++++++++++++-------- R/parameters.R | 4 +++- man/correlations.Rd | 8 ++++++- tests/testthat/test-correlations.R | 8 +++++++ tests/testthat/test-parameters.R | 2 +- 6 files changed, 45 insertions(+), 12 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 9e3324d2..8ec844dc 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -144,6 +144,7 @@ importFrom(dplyr,rename_with) importFrom(dplyr,rowwise) importFrom(dplyr,select) importFrom(dplyr,select_if) +importFrom(dplyr,slice) importFrom(dplyr,summarise) importFrom(dplyr,summarise_all) importFrom(dplyr,ungroup) diff --git a/R/correlations.R b/R/correlations.R index df279c48..e6f55791 100644 --- a/R/correlations.R +++ b/R/correlations.R @@ -5,12 +5,14 @@ #' @param method correlation method. One of `pearson` or `spearman`. #' @param pAdjustMethod p-value adjustment method. See `?p.adjust` for available methods. #' @param corPvalue p-value cut-off threshold for significance +#' @param minCoef minimum absolute correlation coefficient threshold +#' @param maxCor maximum number of returned correlations #' @param ... arguments to pass to specific method #' @return A tibble containing results of significantly correlated features. #' @details #' Correlation analyses can be used to identify associated features within data sets. #' This can be useful to identifying clusters of related features that can be used to annotate metabolites within data sets. -#' All features are compared and the returned table of correlations are p-value thresholded using the specified cut-off. +#' All features are compared and the returned table of correlations are thresholded to the specified p-value cut-off. #' @examples #' library(metaboData) #' @@ -28,11 +30,15 @@ setMethod('correlations',signature = 'AnalysisData', function(d, method = 'pearson', pAdjustMethod = 'bonferroni', - corPvalue = 0.05){ + corPvalue = 0.05, + minCoef = 0, + maxCor = Inf){ doCorrelations(d, method = method, pAdjustMethod = pAdjustMethod, - corPvalue = corPvalue) + corPvalue = corPvalue, + minCoef = minCoef, + maxCor = maxCor) }) #' @rdname correlations @@ -87,7 +93,7 @@ setMethod("correlations", signature = "Analysis", #' @importFrom Hmisc rcorr #' @importFrom stats p.adjust na.omit -#' @importFrom dplyr filter bind_cols left_join rename select mutate distinct +#' @importFrom dplyr filter bind_cols left_join rename select mutate distinct slice #' @importFrom tidyr gather #' @importFrom tibble tibble as_tibble #' @importFrom purrr map_df @@ -95,7 +101,9 @@ setMethod("correlations", signature = "Analysis", doCorrelations <- function(d, method = 'pearson', pAdjustMethod = 'bonferroni', - corPvalue = 0.05) + corPvalue = 0.05, + minCoef = 0, + maxCor = Inf) { methods <- eval(formals(rcorr)$type) @@ -147,7 +155,7 @@ doCorrelations <- function(d, rs <- cors$r %>% as_tibble() %>% mutate(Feature1 = colnames(.)) %>% - gather('Feature2','r',-Feature1) %>% + gather('Feature2','coefficient',-Feature1) %>% distinct() %>% bind_cols(ps %>% select(p), ns %>% select(n)) %>% @@ -156,11 +164,19 @@ doCorrelations <- function(d, rename(Intensity1 = Intensity) %>% left_join(intensity, by = c('Feature2' = 'Feature')) %>% rename(Intensity2 = Intensity) %>% - mutate(`|r|` = abs(r), + mutate(`|coefficient|` = abs(coefficient), log2IntensityRatio = log2(Intensity1/Intensity2)) %>% - select(Feature1,Feature2,log2IntensityRatio,r,`|r|`,p,n) %>% + select(Feature1,Feature2,log2IntensityRatio,coefficient,`|coefficient|`,p,n) %>% na.omit() %>% - arrange(desc(`|r|`)) + arrange(desc(`|coefficient|`)) %>% + filter(`|coefficient|` >= minCoef) + + n_correlations <- nrow(rs) + + if (n_correlations > maxCor){ + rs <- rs %>% + slice(seq_len(maxCor)) + } return(rs) } diff --git a/R/parameters.R b/R/parameters.R index c71ac5b9..8b44c690 100644 --- a/R/parameters.R +++ b/R/parameters.R @@ -55,7 +55,9 @@ analysisParameters <- function(elements = analysisElements()){ correlations <- list( method = 'pearson', pAdjustMethod = 'bonferroni', - corPvalue = 0.05 + corPvalue = 0.05, + minCoef = 0, + maxCor = Inf ) } diff --git a/man/correlations.Rd b/man/correlations.Rd index 4a2761df..b2768a43 100644 --- a/man/correlations.Rd +++ b/man/correlations.Rd @@ -12,7 +12,9 @@ correlations(d, ...) d, method = "pearson", pAdjustMethod = "bonferroni", - corPvalue = 0.05 + corPvalue = 0.05, + minCoef = 0, + maxCor = Inf ) \S4method{correlations}{Analysis}(d) @@ -27,6 +29,10 @@ correlations(d, ...) \item{pAdjustMethod}{p-value adjustment method. See \code{?p.adjust} for available methods.} \item{corPvalue}{p-value cut-off threshold for significance} + +\item{minCoef}{minimum absolute correlation coefficient threshold} + +\item{maxCor}{maximum number of returned correlations} } \value{ A tibble containing results of significantly correlated features. diff --git a/tests/testthat/test-correlations.R b/tests/testthat/test-correlations.R index 3787c5b4..a0a8afd7 100644 --- a/tests/testthat/test-correlations.R +++ b/tests/testthat/test-correlations.R @@ -29,3 +29,11 @@ test_that('correlations errors when incorrect correlation p value threshold spec expect_error(correlations(d,corPvalue = 'wrong')) }) +test_that('the number of returned correlations can be thresholded',{ + d <- analysisData(abr1$neg[,200:250],abr1$fact) + + n_correlations <- correlations(d,maxCor = 2) %>% + nrow() + + expect_equal(n_correlations,2) +}) \ No newline at end of file diff --git a/tests/testthat/test-parameters.R b/tests/testthat/test-parameters.R index 2a4fa26c..70fa2f80 100644 --- a/tests/testthat/test-parameters.R +++ b/tests/testthat/test-parameters.R @@ -48,7 +48,7 @@ test_that('correlations parameters assigned for AnalysisParameters',{ parameters(p,'correlations') <- correlationsParameters() expect_identical(parameters(p,'correlations') %>% names(), - c("method","pAdjustMethod","corPvalue")) + c("method","pAdjustMethod","corPvalue",'minCoef','maxCor')) }) test_that('parameters correctly exported and parsed',{ From e79cfe26858118ba27f43e9b0cf2e56080753963 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Thu, 14 Apr 2022 14:48:43 +0100 Subject: [PATCH 04/89] bumped version to 0.15.0 --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index df42262b..afcecb33 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: metabolyseR Title: Methods for Pre-Treatment, Data Mining and Correlation Analyses of Metabolomics Data -Version: 0.14.10 +Version: 0.15.0 Authors@R: person("Jasen", "Finch", email = "jsf9@aber.ac.uk", role = c("aut", "cre")) Description: A tool kit for pre-treatment, modelling, feature selection and correlation analyses of metabolomics data. URL: https://jasenfinch.github.io/metabolyseR From 43c9ceac2725e923506dacf1cf103a0fef93892e Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Thu, 14 Apr 2022 14:51:16 +0100 Subject: [PATCH 05/89] fix install message about use of floor() --- R/modelling-accessors.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/modelling-accessors.R b/R/modelling-accessors.R index 3d0b9f60..4361fcc6 100644 --- a/R/modelling-accessors.R +++ b/R/modelling-accessors.R @@ -98,7 +98,7 @@ setMethod('mtry',signature = 'AnalysisData', mtry <- switch(rf_type, regression = n_features/3, classification = sqrt(n_features)) %>% - floor() %>% + {floor(.)} %>% c(.,1) %>% max() From e2dd51abd9fb1f61db8cf065aced2c4f6dcbf6b6 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Thu, 14 Apr 2022 18:21:54 +0100 Subject: [PATCH 06/89] ensure `minCoef` and `maxCor` arguments are correctly set in correlations method of the Analysis class --- R/correlations.R | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/R/correlations.R b/R/correlations.R index e6f55791..7eaa3964 100644 --- a/R/correlations.R +++ b/R/correlations.R @@ -69,7 +69,9 @@ setMethod("correlations", signature = "Analysis", rs <- correlations(da, params$method, params$pAdjustMethod, - params$corPvalue) + params$corPvalue, + params$minCoef, + params$maxCor) d@correlations <- rs d@log$correlations <- date() From aee32e259eb3a41a0b0fcf7163a03da04ded8434 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Wed, 20 Jul 2022 16:11:39 +0100 Subject: [PATCH 07/89] update documentation --- DESCRIPTION | 2 +- man/correlations.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index afcecb33..e43f0d9c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -38,7 +38,7 @@ Imports: Hmisc, License: GPL (>= 3) Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.1.2 +RoxygenNote: 7.2.0 Suggests: knitr, rmarkdown, readr, diff --git a/man/correlations.Rd b/man/correlations.Rd index b2768a43..efaa63bc 100644 --- a/man/correlations.Rd +++ b/man/correlations.Rd @@ -43,7 +43,7 @@ Feature correlation analysis. \details{ Correlation analyses can be used to identify associated features within data sets. This can be useful to identifying clusters of related features that can be used to annotate metabolites within data sets. -All features are compared and the returned table of correlations are p-value thresholded using the specified cut-off. +All features are compared and the returned table of correlations are thresholded to the specified p-value cut-off. } \examples{ library(metaboData) From 963bd0b06d9329368ff2f794c43f661df68853f9 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Wed, 20 Jul 2022 16:37:52 +0100 Subject: [PATCH 08/89] added predictions accessor method --- NAMESPACE | 1 + R/modelling-accessors.R | 51 ++++++++++++++++++++++++++++++ R/randomForest.R | 18 +++++------ man/modelling-accessors.Rd | 13 ++++++++ tests/testthat/test-metabolyse.R | 1 + tests/testthat/test-randomForest.R | 5 +++ 6 files changed, 80 insertions(+), 9 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 8ec844dc..68357371 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -75,6 +75,7 @@ export(preTreatmentElements) export(preTreatmentMethods) export(preTreatmentParameters) export(predict) +export(predictions) export(proximity) export(randomForest) export(raw) diff --git a/R/modelling-accessors.R b/R/modelling-accessors.R index 4361fcc6..dba1d4fd 100644 --- a/R/modelling-accessors.R +++ b/R/modelling-accessors.R @@ -13,6 +13,7 @@ #' * `type`: Return the type of random forest analysis. #' * `response`: Return the response variable name used for a random forest analysis. #' * `metrics`: Retrieve the model performance metrics for a random forest analysis +#' * `predictions`: Retrieve the out of bag model response predictions for a random forest analysis. #' * `importanceMetrics`: Retrieve the available feature importance metrics for a random forest analysis. #' * `importance`: Retrieve feature importance results. #' * `proximity`: Retrieve the random forest sample proximities. @@ -40,6 +41,9 @@ #' ## Retrieve the model performance metrics #' metrics(rf_analysis) #' +#' ## Retrieve the out of bag model response predictions +#' predictions(rf_analysis) +#' #' ## Show the available feature importance metrics #' importanceMetrics(rf_analysis) #' @@ -182,6 +186,53 @@ setMethod('metrics',signature = 'Analysis', #' @rdname modelling-accessors #' @export +setGeneric("predictions", function(x) + standardGeneric("predictions") +) + +#' @rdname modelling-accessors + +setMethod('predictions',signature = 'RandomForest', + function(x){ + x@predictions + } +) + +setMethod('predictions',signature = 'list', + function(x){ + object_classes <- x %>% + map_chr(class) + + if (FALSE %in% (object_classes == 'RandomForest')) { + message( + str_c('All objects contained within supplied list ', + 'that are not of class RandomForest will be ignored.')) + } + + x <- x[object_classes == 'RandomForest'] + + if (length(x) > 0) { + x %>% + map(predictions) %>% + bind_rows() + } else { + tibble() + } + + }) + +#' @rdname modelling-accessors + +setMethod('predictions',signature = 'Analysis', + function(x){ + x %>% + analysisResults('modelling') %>% + predictions() + }) + +#' @rdname modelling-accessors +#' @export + setGeneric("importanceMetrics", function(x) standardGeneric("importanceMetrics") ) diff --git a/R/randomForest.R b/R/randomForest.R index 209da111..bda51d0e 100644 --- a/R/randomForest.R +++ b/R/randomForest.R @@ -561,7 +561,7 @@ classification <- function(x, predictions <- models %>% map(~{ map(.x,~{ - map(.x$models,~{ + furrr::future_map_dfr(.x$models,~{ m <- .x tibble(sample = seq_along(m$y), obs = m$y, @@ -570,8 +570,8 @@ classification <- function(x, bind_cols(m$votes %>% as_tibble(.name_repair = 'minimal') %>% mutate_all(as.numeric)) - }) %>% - bind_rows(.id = 'Rep') %>% + }, + .id = 'Rep') %>% mutate(Rep = as.numeric(Rep)) }) %>% bind_rows(.id = 'Comparison') @@ -582,13 +582,13 @@ classification <- function(x, importances <- models %>% map(~{ map(.,~{ - map(.$models,~{ + furrr::future_map_dfr(.$models,~{ m <- . importance(m) %>% left_join(fpr_fs(m),by = c('Feature' = 'variable')) %>% rename(SelectionFrequency = freq,FalsePositiveRate = fpr) - }) %>% - bind_rows(.id = 'Rep') %>% + }, + .id = 'Rep') %>% mutate(Rep = as.numeric(Rep)) }) %>% bind_rows(.id = 'Comparison') @@ -599,13 +599,13 @@ classification <- function(x, proximities <- models %>% map(~{ map(.,~{ - map(.$models,~{.$proximity %>% + furrr::future_map_dfr(.$models,~{.$proximity %>% as_tibble() %>% mutate(Sample = seq_len(nrow(.))) %>% gather('Sample2','Proximity',-Sample) %>% rename(Sample1 = Sample) - }) %>% - bind_rows(.id = 'Rep') %>% + }, + .id = 'Rep') %>% mutate(Rep = as.numeric(Rep)) }) %>% bind_rows(.id = 'Comparison') diff --git a/man/modelling-accessors.Rd b/man/modelling-accessors.Rd index 39db705f..4d317395 100644 --- a/man/modelling-accessors.Rd +++ b/man/modelling-accessors.Rd @@ -13,6 +13,9 @@ \alias{metrics,RandomForest-method} \alias{metrics,list-method} \alias{metrics,Analysis-method} +\alias{predictions} +\alias{predictions,RandomForest-method} +\alias{predictions,Analysis-method} \alias{importanceMetrics} \alias{importanceMetrics,RandomForest-method} \alias{importance} @@ -55,6 +58,12 @@ metrics(x) \S4method{metrics}{Analysis}(x) +predictions(x) + +\S4method{predictions}{RandomForest}(x) + +\S4method{predictions}{Analysis}(x) + importanceMetrics(x) \S4method{importanceMetrics}{RandomForest}(x) @@ -111,6 +120,7 @@ Methods for accessing modelling results. \item \code{type}: Return the type of random forest analysis. \item \code{response}: Return the response variable name used for a random forest analysis. \item \code{metrics}: Retrieve the model performance metrics for a random forest analysis +\item \code{predictions}: Retrieve the out of bag model response predictions for a random forest analysis. \item \code{importanceMetrics}: Retrieve the available feature importance metrics for a random forest analysis. \item \code{importance}: Retrieve feature importance results. \item \code{proximity}: Retrieve the random forest sample proximities. @@ -141,6 +151,9 @@ response(rf_analysis) ## Retrieve the model performance metrics metrics(rf_analysis) +## Retrieve the out of bag model response predictions +predictions(rf_analysis) + ## Show the available feature importance metrics importanceMetrics(rf_analysis) diff --git a/tests/testthat/test-metabolyse.R b/tests/testthat/test-metabolyse.R index d71dbc05..93be51ac 100644 --- a/tests/testthat/test-metabolyse.R +++ b/tests/testthat/test-metabolyse.R @@ -27,6 +27,7 @@ test_that('metabolyse-works', { expect_equal(nSamples(analysis),20) expect_s3_class(metrics(analysis),'tbl_df') + expect_s3_class(predictions(analysis),'tbl_df') expect_s3_class(proximity(analysis),'tbl_df') expect_s3_class(mds(analysis),'tbl_df') expect_s3_class(roc(analysis),'tbl_df') diff --git a/tests/testthat/test-randomForest.R b/tests/testthat/test-randomForest.R index 7df93496..86b79910 100644 --- a/tests/testthat/test-randomForest.R +++ b/tests/testthat/test-randomForest.R @@ -11,12 +11,14 @@ test_that('unsupervised random forest works',{ expect_s4_class(rf,'RandomForest') expect_identical(type(rf),'unsupervised') + expect_equal(mtry(rf,cls = NULL),7) }) test_that('random forest classification works',{ expect_warning(rf <- randomForest(d,cls = c('day','name'),perm = 3,returnModels = TRUE)) rf_metrics <- metrics(rf) + rf_predictions <- predictions(rf) rf_importance <- importance(rf) rf_proximity <- proximity(rf,idx = 'sample_names') @@ -25,15 +27,18 @@ test_that('random forest classification works',{ expect_identical(class(rf),'list') expect_identical(type(rf$day),'classification') expect_s3_class(rf_metrics,'tbl_df') + expect_s3_class(rf_predictions,'tbl_df') expect_s3_class(rf_importance,'tbl_df') expect_s3_class(rf_proximity,'tbl_df') expect_s3_class(metrics(rf_wrong),'tbl_df') + expect_s3_class(predictions(rf_wrong),'tbl_df') expect_error(importance(rf_wrong)) expect_s3_class(proximity(rf_wrong),'tbl_df') expect_error(explanatoryFeatures(rf_wrong)) expect_equal(nrow(metrics(list(0,0))),0) + expect_equal(nrow(predictions(list(0,0))),0) expect_equal(nrow(proximity(list(0,0))),0) expect_error(proximity(rf,idx = 'name')) From 6a0d102070eaf17c19d20c87be07a6c07f22c352 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Wed, 20 Jul 2022 17:00:18 +0100 Subject: [PATCH 09/89] parallise the collation of predictions, importance and proximities in random forest --- NAMESPACE | 1 + R/randomForest.R | 51 ++++++++++++++++++++++++++++-------------------- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 68357371..e981d482 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -154,6 +154,7 @@ importFrom(forestControl,fpr_fs) importFrom(furrr,furrr_options) importFrom(furrr,future_map) importFrom(furrr,future_map2) +importFrom(furrr,future_map_dfr) importFrom(future,plan) importFrom(ggdendro,dendro_data) importFrom(ggplot2,aes) diff --git a/R/randomForest.R b/R/randomForest.R index bda51d0e..1195cb0d 100644 --- a/R/randomForest.R +++ b/R/randomForest.R @@ -342,24 +342,26 @@ unsupervised <- function(x,rf,reps,returnModels,seed,...){ set_names(1:reps) importances <- models %>% - map(~{ + future_map_dfr(~{ m <- . importance(m) %>% left_join(fpr_fs(m),by = c('Feature' = 'variable')) %>% rename(SelectionFrequency = freq,FalsePositiveRate = fpr) - }) %>% - bind_rows(.id = 'Rep') %>% + }, + .id = 'Rep', + .options = furrr_options(seed = seed)) %>% mutate(Rep = as.numeric(Rep)) %>% gather('Metric','Value',-Rep,-Feature) proximities <- models %>% - map(.,~{.$proximity %>% + future_map_dfr(.,~{.$proximity %>% as_tibble(.name_repair = 'minimal') %>% mutate(Sample = seq_len(nrow(.))) %>% gather('Sample2','Proximity',-Sample) %>% rename(Sample1 = Sample) - }) %>% - bind_rows(.id = 'Rep') %>% + }, + .id = 'Rep', + .options = furrr_options(seed = seed)) %>% mutate(Rep = as.numeric(Rep)) %>% mutate(Sample2 = as.numeric(Sample2)) @@ -434,6 +436,7 @@ supervised <- function(x, #' @importFrom dplyr summarise_all group_by_all n #' @importFrom stringr str_split #' @importFrom magrittr set_names +#' @importFrom furrr future_map_dfr classification <- function(x, cls, @@ -561,7 +564,7 @@ classification <- function(x, predictions <- models %>% map(~{ map(.x,~{ - furrr::future_map_dfr(.x$models,~{ + future_map_dfr(.x$models,~{ m <- .x tibble(sample = seq_along(m$y), obs = m$y, @@ -571,7 +574,8 @@ classification <- function(x, as_tibble(.name_repair = 'minimal') %>% mutate_all(as.numeric)) }, - .id = 'Rep') %>% + .id = 'Rep', + .options = furrr_options(seed = seed)) %>% mutate(Rep = as.numeric(Rep)) }) %>% bind_rows(.id = 'Comparison') @@ -582,13 +586,14 @@ classification <- function(x, importances <- models %>% map(~{ map(.,~{ - furrr::future_map_dfr(.$models,~{ + future_map_dfr(.$models,~{ m <- . importance(m) %>% left_join(fpr_fs(m),by = c('Feature' = 'variable')) %>% rename(SelectionFrequency = freq,FalsePositiveRate = fpr) }, - .id = 'Rep') %>% + .id = 'Rep', + .options = furrr_options(seed = seed)) %>% mutate(Rep = as.numeric(Rep)) }) %>% bind_rows(.id = 'Comparison') @@ -599,13 +604,14 @@ classification <- function(x, proximities <- models %>% map(~{ map(.,~{ - furrr::future_map_dfr(.$models,~{.$proximity %>% + future_map_dfr(.$models,~{.$proximity %>% as_tibble() %>% mutate(Sample = seq_len(nrow(.))) %>% gather('Sample2','Proximity',-Sample) %>% rename(Sample1 = Sample) }, - .id = 'Rep') %>% + .id = 'Rep', + .options = furrr_options(seed = seed)) %>% mutate(Rep = as.numeric(Rep)) }) %>% bind_rows(.id = 'Comparison') @@ -691,22 +697,24 @@ regression <- function(x, predictions <- models %>% map(~{ - map(.$models,~{ + future_map_dfr(.$models,~{ m <- . tibble(sample = seq_along(m$y),obs = m$y,pred = m$predicted) - }) %>% - bind_rows(.id = 'Rep') %>% + }, + .id = 'Rep', + .options = furrr_options(seed = seed)) %>% mutate(Rep = as.numeric(Rep)) }) %>% bind_rows(.id = 'Response') importances <- models %>% map(~{ - map(.$models,~{ + future_map_dfr(.$models,~{ m <- . importance(m) - }) %>% - bind_rows(.id = 'Rep') %>% + }, + .id = 'Rep', + .options = furrr_options(seed = seed)) %>% mutate(Rep = as.numeric(Rep)) }) %>% bind_rows(.id = 'Response') %>% @@ -714,13 +722,14 @@ regression <- function(x, proximities <- models %>% map(~{ - map(.$models,~{.$proximity %>% + future_map_dfr(.$models,~{.$proximity %>% as_tibble() %>% mutate(Sample = seq_len(nrow(.))) %>% gather('Sample2','Proximity',-Sample) %>% rename(Sample1 = Sample) - }) %>% - bind_rows(.id = 'Rep') %>% + }, + .id = 'Rep', + .options = furrr_options(seed = seed)) %>% mutate(Rep = as.numeric(Rep)) }) %>% bind_rows(.id = 'Response') %>% From 9c44f8c278c0767bd81dbf0c59111d8ead751e66 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Tue, 27 Sep 2022 22:12:36 +0100 Subject: [PATCH 10/89] correlations performance improvement --- R/correlations.R | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/R/correlations.R b/R/correlations.R index 7eaa3964..6f60e52b 100644 --- a/R/correlations.R +++ b/R/correlations.R @@ -146,30 +146,36 @@ doCorrelations <- function(d, map_df(p.adjust,method = pAdjustMethod,n = nrow(.) - 1) %>% mutate(Feature1 = colnames(.)) %>% gather('Feature2','p',-Feature1) %>% + drop_na() %>% distinct() ns <- cors$n %>% as_tibble() %>% mutate(Feature1 = colnames(.)) %>% gather('Feature2','n',-Feature1) %>% + drop_na() %>% distinct() rs <- cors$r %>% as_tibble() %>% mutate(Feature1 = colnames(.)) %>% gather('Feature2','coefficient',-Feature1) %>% + drop_na() %>% distinct() %>% - bind_cols(ps %>% select(p), - ns %>% select(n)) %>% + left_join(ps, + by = c("Feature1", "Feature2")) %>% + left_join(ns, + by = c("Feature1", "Feature2")) %>% filter(Feature1 != Feature2,p < corPvalue,n > 2) %>% - left_join(intensity, by = c('Feature1' = 'Feature')) %>% + left_join(intensity, + by = c('Feature1' = 'Feature')) %>% rename(Intensity1 = Intensity) %>% - left_join(intensity, by = c('Feature2' = 'Feature')) %>% + left_join(intensity, + by = c('Feature2' = 'Feature')) %>% rename(Intensity2 = Intensity) %>% mutate(`|coefficient|` = abs(coefficient), log2IntensityRatio = log2(Intensity1/Intensity2)) %>% select(Feature1,Feature2,log2IntensityRatio,coefficient,`|coefficient|`,p,n) %>% - na.omit() %>% arrange(desc(`|coefficient|`)) %>% filter(`|coefficient|` >= minCoef) From 61e624ab23f84f22eb577910d1ee0c76fc170ff4 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Tue, 11 Oct 2022 18:32:53 +0100 Subject: [PATCH 11/89] Occupancy methods now error if the occupancy argument is non-numeric. --- R/occupancy.R | 12 ++++++++++++ tests/testthat/test-occupancyMethods.R | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/R/occupancy.R b/R/occupancy.R index c8b8e429..1e6142b2 100644 --- a/R/occupancy.R +++ b/R/occupancy.R @@ -41,6 +41,12 @@ setGeneric("occupancyMaximum", function(d, cls = 'class', occupancy = 2/3) setMethod('occupancyMaximum',signature = 'AnalysisData', function(d,cls = 'class', occupancy = 2/3){ + + if (!is.numeric(occupancy)){ + stop('Argument `occupancy` is non-numeric.', + call. = FALSE) + } + occ <- occupancy(d,cls) fd <- occ %>% group_by(Feature) %>% @@ -67,6 +73,12 @@ setGeneric("occupancyMinimum", function(d, cls = 'class', occupancy = 2/3) setMethod('occupancyMinimum',signature = 'AnalysisData', function(d,cls = 'class', occupancy = 2/3){ + + if (!is.numeric(occupancy)){ + stop('Argument `occupancy` is non-numeric.', + call. = FALSE) + } + occ <- occupancy(d,cls) fd <- occ %>% group_by(Feature) %>% diff --git a/tests/testthat/test-occupancyMethods.R b/tests/testthat/test-occupancyMethods.R index 95454b0f..7fa6fe5e 100644 --- a/tests/testthat/test-occupancyMethods.R +++ b/tests/testthat/test-occupancyMethods.R @@ -32,3 +32,10 @@ test_that('methods work',{ m, ~{nrow(.x %>% sinfo()) == nrow(dat %>% sinfo())})) }) + +test_that('occupancy methods error argument `occupancy` is non-numeric',{ + dat <- analysisData(data = metaboData::abr1$neg, info = metaboData::abr1$fact) + + expect_error(occupancyMaximum(dat,occupancy = 'wrong')) + expect_error(occupancyMinimum(dat,occupancy = 'wrong')) +}) From c47d87cfa1667e0cd205218dfa57df70e560889a Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Thu, 27 Oct 2022 16:13:21 +0100 Subject: [PATCH 12/89] organise random forest code into seperate files --- DESCRIPTION | 4 + R/randomForest-classification.R | 315 +++++++++++++ R/randomForest-internals.R | 111 +++++ R/randomForest-permute.R | 172 +++++++ R/randomForest-regression.R | 166 +++++++ R/randomForest.R | 766 -------------------------------- 6 files changed, 768 insertions(+), 766 deletions(-) create mode 100644 R/randomForest-classification.R create mode 100644 R/randomForest-internals.R create mode 100644 R/randomForest-permute.R create mode 100644 R/randomForest-regression.R diff --git a/DESCRIPTION b/DESCRIPTION index e43f0d9c..1f2da817 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -81,6 +81,10 @@ Collate: allClasses.R reexports.R remove.R randomForest.R + randomForest-classification.R + randomForest-internals.R + randomForest-permute.R + randomForest-regression.R rsd.R roc.R show-method.R diff --git a/R/randomForest-classification.R b/R/randomForest-classification.R new file mode 100644 index 00000000..866fe2bb --- /dev/null +++ b/R/randomForest-classification.R @@ -0,0 +1,315 @@ + +#' @importFrom randomForest margin +#' @importFrom stats pnorm + +classificationMeasures <- function(predictions,permutations){ + + class_metrics <- metric_set(accuracy,kap) + + meas <- predictions %>% + base::split(.$Response) %>% + map(~{ + d <- . + d %>% + base::split(.$Comparison) %>% + map(~{ + p <- . + p %>% + mutate(obs = factor(obs),pred = factor(pred)) %>% + group_by(Response,Comparison) %>% + class_metrics(obs,estimate = pred) + }) %>% + bind_rows() + }) %>% + bind_rows() %>% + bind_rows( + suppressMessages( + predictions %>% + base::split(.$Response) %>% + map(~{ + d <- . + d %>% + base::split(.$Comparison) %>% + map(~{ + p <- . + + p <- p %>% + mutate(obs = factor(obs),pred = factor(pred)) + if (length(levels(p$obs)) > 2) { + estimate <- levels(p$obs) + } else { + estimate <- levels(p$obs)[1] + } + p %>% + group_by(Response,Comparison) %>% + roc_auc(obs,estimate) + }) %>% + bind_rows() + }) %>% + bind_rows())) %>% + bind_rows(predictions %>% + group_by(Response,Comparison) %>% + summarise(.estimate = mean(margin)) %>% + mutate(.metric = 'margin')) + + if (length(permutations) > 0) { + meas <- meas %>% + left_join( + permutations$measures, + by = c("Response","Comparison", ".metric")) %>% + mutate(Pvalue = pnorm(.estimate,Mean,SD,lower.tail = FALSE)) %>% + select(-Mean,-SD) + } + + return(meas) +} + +#' @importFrom dplyr rowwise + +classificationImportance <- function(importances,permutations){ + imps <- importances %>% + group_by(Response,Comparison,Feature,Metric) %>% + summarise(Value = mean(Value)) + + if (length(permutations) > 0) { + lowertail <- list(MeanDecreaseGini = FALSE, + SelectionFrequency = FALSE, + FalsePositiveRate = TRUE) + + imps <- imps %>% + left_join( + permutations$importance, + by = c("Response","Comparison", "Feature", "Metric")) %>% + base::split(.$Metric) %>% + map(~{ + i <- . + tail <- lowertail[[i$Metric[1]]] + i %>% + rowwise() %>% + mutate(Pvalue = pnorm(Value,Mean,SD,lower.tail = tail)) %>% + ungroup() + }) %>% + bind_rows() %>% + group_by(Metric) %>% + mutate(adjustedPvalue = p.adjust(Pvalue,method = 'bonferroni')) %>% + select(-Mean,-SD) + } + + return(imps) +} + +#' @importFrom yardstick metric_set accuracy kap roc_auc +#' @importFrom dplyr summarise_all group_by_all n +#' @importFrom stringr str_split +#' @importFrom magrittr set_names +#' @importFrom furrr future_map_dfr + +classification <- function(x, + cls, + rf, + reps, + binary, + comparisons, + perm, + returnModels, + seed){ + + i <- x %>% + sinfo() %>% + select(all_of(cls)) + + clsFreq <- i %>% + group_by_all() %>% + summarise(n = n(),.groups = 'drop') + + if (any(clsFreq$n < 5)) { + clsRem <- clsFreq %>% + filter(n < 5) + + x <- x %>% + removeClasses(cls = cls,classes = clsRem %>% + select(all_of(cls)) %>% + deframe()) + + cls_list <- clsRem %>% + select(all_of(cls)) %>% + deframe() %>% + str_c('"',.,'"') %>% + str_c(.,collapse = ', ') + + warning(str_c('Classes with < 5 replicates removed: ', + cls_list), + call. = FALSE) + + i <- x %>% + sinfo() %>% + select(cls) + } + + if (length(unique(deframe(i))) < 2) { + stop('Need at least two classes to do classification.',call. = FALSE) + } + + if (length(comparisons) > 0) { + comp <- comparisons + } else { + if (binary == TRUE) { + comp <- map(names(i),~{ + binaryComparisons(x,cls = .x) + }) %>% + set_names(names(i)) + } else { + comp <- map(i,~{unique(.) %>% + sort() %>% + str_c(collapse = '~')}) + } + } + + models <- i %>% + colnames() %>% + map(~{ + inf <- . + + comps <- comp[[inf]] + + comps %>% + map(~{ + comparison <- str_split(.,'~')[[1]] + + cda <- keepClasses(x,inf,classes = comparison) + + pred <- cda %>% + sinfo() %>% + select(all_of(inf)) %>% + deframe() %>% + factor() + + predFreq <- pred %>% + tibble(cls = .) %>% + group_by_all() %>% + summarise(n = n(),.groups = 'drop') + + if (length(unique(predFreq$n)) > 1) { + message( + str_c('Unbalanced classes detected. Stratifying ', + 'sample size to the smallest class size.')) + + ss <- pred %>% + table() %>% + min() %>% + rep(length(unique(pred))) + + rf <- c(rf,list(strata = pred,sampsize = ss)) + } + + set.seed(seed) + + mod <- future_map(1:reps,~{ + params <- formals(randomForest::randomForest) + params$x <- cda %>% dat() + params$y <- pred + params <- c(params,rf) + do.call(randomForest::randomForest,params) + },.options = furrr_options(seed = seed)) %>% + set_names(1:reps) + + mod <- list(models = mod) + + if (perm > 0) { + perms <- permute(x,cls,rf,n = perm) + mod <- c(mod,list(permutations = perms)) + } + + return(mod) + }) %>% + set_names(comps) + }) %>% + set_names(colnames(i)) + + suppressMessages({ + predictions <- models %>% + map(~{ + map(.x,~{ + future_map_dfr(.x$models,~{ + m <- .x + tibble(sample = seq_along(m$y), + obs = m$y, + pred = m$predicted, + margin = margin(m)) %>% + bind_cols(m$votes %>% + as_tibble(.name_repair = 'minimal') %>% + mutate_all(as.numeric)) + }, + .id = 'Rep', + .options = furrr_options(seed = seed)) %>% + mutate(Rep = as.numeric(Rep)) + }) %>% + bind_rows(.id = 'Comparison') + }) %>% + bind_rows(.id = 'Response') + }) + + importances <- models %>% + map(~{ + map(.,~{ + future_map_dfr(.$models,~{ + m <- . + importance(m) %>% + left_join(fpr_fs(m),by = c('Feature' = 'variable')) %>% + rename(SelectionFrequency = freq,FalsePositiveRate = fpr) + }, + .id = 'Rep', + .options = furrr_options(seed = seed)) %>% + mutate(Rep = as.numeric(Rep)) + }) %>% + bind_rows(.id = 'Comparison') + }) %>% + bind_rows(.id = 'Response') %>% + gather('Metric','Value',-(Response:Feature)) + + proximities <- models %>% + map(~{ + map(.,~{ + future_map_dfr(.$models,~{.$proximity %>% + as_tibble() %>% + mutate(Sample = seq_len(nrow(.))) %>% + gather('Sample2','Proximity',-Sample) %>% + rename(Sample1 = Sample) + }, + .id = 'Rep', + .options = furrr_options(seed = seed)) %>% + mutate(Rep = as.numeric(Rep)) + }) %>% + bind_rows(.id = 'Comparison') + }) %>% + bind_rows(.id = 'Response') %>% + mutate(Sample2 = as.numeric(Sample2)) + + if (perm > 0) { + permutations <- classificationPermutationMeasures(models) + } else { + permutations <- list() + } + + results <- list( + measures = classificationMeasures(predictions,permutations), + importances = classificationImportance(importances,permutations) + ) + + res <- new('RandomForest') + res@type <- 'classification' + res@response <- cls + dat(res) <- dat(x) + sinfo(res) <- sinfo(x) + res@results <- results + res@predictions <- predictions + res@permutations <- permutations + res@importances <- importances + res@proximities <- proximities + + if (isTRUE(returnModels)) { + res@models <- models + } + + return(res) +} diff --git a/R/randomForest-internals.R b/R/randomForest-internals.R new file mode 100644 index 00000000..5e29289a --- /dev/null +++ b/R/randomForest-internals.R @@ -0,0 +1,111 @@ + +importance <- function(x){ + x %>% + randomForest::importance() %>% + {bind_cols(tibble(Feature = rownames(.)),as_tibble(.,.name_repair = 'minimal'))} +} + +#' @importFrom forestControl fpr_fs + +unsupervised <- function(x,rf,reps,returnModels,seed,...){ + + set.seed(seed) + + models <- future_map(1:reps,~{ + params <- formals(randomForest::randomForest) + params$x <- x %>% dat() + params <- c(params,rf) + do.call(randomForest::randomForest,params) + },.options = furrr_options(seed = seed)) %>% + set_names(1:reps) + + importances <- models %>% + future_map_dfr(~{ + m <- . + importance(m) %>% + left_join(fpr_fs(m),by = c('Feature' = 'variable')) %>% + rename(SelectionFrequency = freq,FalsePositiveRate = fpr) + }, + .id = 'Rep', + .options = furrr_options(seed = seed)) %>% + mutate(Rep = as.numeric(Rep)) %>% + gather('Metric','Value',-Rep,-Feature) + + proximities <- models %>% + future_map_dfr(.,~{.$proximity %>% + as_tibble(.name_repair = 'minimal') %>% + mutate(Sample = seq_len(nrow(.))) %>% + gather('Sample2','Proximity',-Sample) %>% + rename(Sample1 = Sample) + }, + .id = 'Rep', + .options = furrr_options(seed = seed)) %>% + mutate(Rep = as.numeric(Rep)) %>% + mutate(Sample2 = as.numeric(Sample2)) + + results <- list( + importances = importances %>% + select(-Rep) %>% + group_by(Feature,Metric) %>% + summarise(Value = mean(Value)) + ) + + res <- new('RandomForest') + res@type <- 'unsupervised' + dat(res) <- dat(x) + sinfo(res) <- sinfo(x) + res@results <- results + res@importances <- importances + res@proximities <- proximities + + if (isTRUE(returnModels)) { + res@models <- models + } + + return(list(res)) +} + +supervised <- function(x, + cls, + rf, + reps, + binary, + comparisons, + perm, + returnModels, + seed){ + i <- x %>% + sinfo() %>% + select(all_of(cls)) + + i %>% + colnames() %>% + map(~{ + cls <- . + + pred <- i %>% + select(all_of(cls)) %>% + deframe() + + if (is.numeric(pred)) { + regression(x, + cls, + rf, + reps, + perm, + returnModels, + seed) + } else { + classification(x, + cls, + rf, + reps, + binary, + comparisons, + perm, + returnModels, + seed) + } + }) %>% + set_names(colnames(i)) +} \ No newline at end of file diff --git a/R/randomForest-permute.R b/R/randomForest-permute.R new file mode 100644 index 00000000..464fa91b --- /dev/null +++ b/R/randomForest-permute.R @@ -0,0 +1,172 @@ +nPerm <- function(n,k){choose(n,k) * factorial(k)} + +#' @importFrom stats runif + +permute <- function(x,cls,rf,n = 1000){ + i <- x %>% + sinfo() %>% + select(cls) %>% + unlist(use.names = FALSE) + + if (is.character(i) | is.factor(i)) { + i <- factor(i) + } + + if (nPerm(length(i),length(unique(i))) < n) { + n <- nPerm(length(i),length(unique(i))) + } + + models <- future_map(1:n,~{ + params <- formals(randomForest::randomForest) + params <- c(params,rf) + params$x <- x %>% dat() + ind <- sample(i) + params$y <- ind + params$strata <- ind + do.call(randomForest::randomForest,params) + },.options = furrr_options(seed = runif(1) %>% + {. * 100000} %>% + round())) %>% + set_names(1:n) + + return(models) +} + +classificationPermutationMeasures <- function(models){ + suppressWarnings({ + preds <- models %>% + map(~{ + map(.,~{ + map(.$permutations,~{ + m <- . + tibble(sample = seq_along(m$y), + obs = m$y, + pred = m$predicted, + margin = margin(m)) %>% + bind_cols(m$votes %>% + as_tibble(.name_repair = 'minimal')) + }) %>% + { + suppressMessages(bind_rows(.,.id = 'Permutation')) + } %>% + mutate(Permutation = as.numeric(Permutation)) + }) %>% + bind_rows(.id = 'Comparison') + }) %>% + bind_rows(.id = 'Response') + }) + + class_metrics <- metric_set(accuracy,kap) + + meas <- preds %>% + base::split(.$Response) %>% + map(~{ + d <- . + d %>% + base::split(.$Comparison) %>% + map(~{ + p <- . + p %>% + mutate(obs = factor(obs),pred = factor(pred)) %>% + group_by(Response,Comparison,Permutation) %>% + class_metrics(obs,estimate = pred) + }) %>% + bind_rows() + }) %>% + bind_rows() %>% + bind_rows( + suppressMessages( + preds %>% + base::split(.$Response) %>% + map(~{ + d <- . + d %>% + base::split(.$Comparison) %>% + map(~{ + p <- . + + p <- p %>% + mutate(obs = factor(obs),pred = factor(pred)) + if (length(levels(p$obs)) > 2) { + estimate <- levels(p$obs) + } else { + estimate <- levels(p$obs)[1] + } + p %>% + group_by(Response,Comparison,Permutation) %>% + roc_auc(obs,estimate) + }) %>% + bind_rows() + }) %>% + bind_rows())) %>% + bind_rows(preds %>% + group_by(Response,Comparison,Permutation) %>% + summarise(.estimate = mean(margin)) %>% + mutate(.metric = 'margin')) %>% + group_by(Response,Comparison,.metric) %>% + summarise(Mean = mean(.estimate),SD = sd(.estimate)) + + imps <- models %>% + map(~{ + map(.,~{ + map(.$permutations,~{ + m <- . + importance(m) %>% + left_join(fpr_fs(m),by = c('Feature' = 'variable')) %>% + rename(SelectionFrequency = freq,FalsePositiveRate = fpr) + }) %>% + bind_rows(.id = 'Permutation') %>% + mutate(Permutation = as.numeric(Permutation)) + }) %>% + bind_rows(.id = 'Comparison') + }) %>% + bind_rows(.id = 'Response') %>% + gather('Metric','Value',-(Response:Feature)) %>% + group_by(Response,Comparison,Feature,Metric) %>% + summarise(Mean = mean(Value),SD = sd(Value)) + + return(list(measures = meas,importance = imps)) +} + +regressionPermutationMeasures <- function(models){ + preds <- models %>% + map(~{ + map(.$permutations,~{ + m <- . + tibble(sample = seq_along(m$y),obs = m$y,pred = m$predicted) + }) %>% + bind_rows(.id = 'Permutation') %>% + mutate(Permutation = as.numeric(Permutation)) + }) %>% + bind_rows(.id = 'Response') + + reg_metrics <- metric_set(rsq,mae,mape,rmse,ccc) + + meas <- preds %>% + base::split(.$Response) %>% + map(~{ + d <- . + d %>% + group_by(Response,Permutation) %>% + reg_metrics(obs,estimate = pred) + }) %>% + bind_rows() %>% + group_by(Response,.metric) %>% + summarise(Mean = mean(.estimate),SD = sd(.estimate)) + + imps <- models %>% + map(~{ + map(.$permutations,~{ + m <- . + importance(m) + }) %>% + bind_rows(.id = 'Permutation') %>% + mutate(Permutation = as.numeric(Permutation)) + }) %>% + bind_rows(.id = 'Response') %>% + gather('Metric','Value',-Response,-Permutation,-Feature) %>% + group_by(Response,Feature,Metric) %>% + summarise(Mean = mean(Value),SD = sd(Value)) + + return(list(measures = meas,importance = imps)) +} diff --git a/R/randomForest-regression.R b/R/randomForest-regression.R new file mode 100644 index 00000000..77e7fce3 --- /dev/null +++ b/R/randomForest-regression.R @@ -0,0 +1,166 @@ +regressionMeasures <- function(predictions,permutations){ + reg_metrics <- metric_set(rsq,mae,mape,rmse,ccc) + meas <- predictions %>% + base::split(.$Response) %>% + map(~{ + d <- . + d %>% + group_by(Response) %>% + reg_metrics(obs,estimate = pred) + }) %>% + bind_rows() + + if (length(permutations) > 0) { + lowertail <- list(rsq = FALSE, + mae = TRUE, + mape = TRUE, + mape = TRUE, + rmse = TRUE, + ccc = FALSE) + + meas <- meas %>% + left_join(permutations$measures, by = c("Response", ".metric")) %>% + rowwise() %>% + mutate(Pvalue = pnorm(.estimate, + Mean, + SD, + lower.tail = lowertail[[.metric]])) %>% + select(-Mean,-SD) + } + + return(meas) +} + +regressionImportance <- function(importances,permutations){ + imps <- importances %>% + group_by(Response,Feature,Metric) %>% + summarise(Value = mean(Value)) + + if (length(permutations) > 0) { + imps <- imps %>% + left_join(permutations$importance, + by = c("Response", "Feature", "Metric")) %>% + mutate(Pvalue = pnorm(Value,Mean,SD,lower.tail = FALSE)) %>% + group_by(Metric) %>% + mutate(adjustedPvalue = p.adjust(Pvalue,method = 'bonferroni')) %>% + select(-Mean,-SD) + } + + return(imps) +} + +#' @importFrom yardstick rsq mae mape rmse ccc + +regression <- function(x, + cls, + rf, + reps, + perm, + returnModels, + seed){ + i <- x %>% + sinfo() %>% + select(cls) + + models <- i %>% + colnames() %>% + map(~{ + inf <- . + + pred <- i %>% + select(inf) %>% + unlist(use.names = FALSE) + + set.seed(seed) + + mod <- future_map(1:reps,~{ + params <- formals(randomForest::randomForest) + params$x <- x %>% dat() + params$y <- pred + params <- c(params,rf) + do.call(randomForest::randomForest,params) + },.options = furrr_options(seed = seed)) %>% + set_names(1:reps) + + mod <- list(models = mod) + + if (perm > 0) { + perms <- permute(x,cls,rf,n = perm) + } else { + perms <- list() + } + + mod <- c(mod,list(permutations = perms)) + + return(mod) + }) %>% + set_names(colnames(i)) + + predictions <- models %>% + map(~{ + future_map_dfr(.$models,~{ + m <- . + tibble(sample = seq_along(m$y),obs = m$y,pred = m$predicted) + }, + .id = 'Rep', + .options = furrr_options(seed = seed)) %>% + mutate(Rep = as.numeric(Rep)) + }) %>% + bind_rows(.id = 'Response') + + importances <- models %>% + map(~{ + future_map_dfr(.$models,~{ + m <- . + importance(m) + }, + .id = 'Rep', + .options = furrr_options(seed = seed)) %>% + mutate(Rep = as.numeric(Rep)) + }) %>% + bind_rows(.id = 'Response') %>% + gather('Metric','Value',-Response,-Rep,-Feature) + + proximities <- models %>% + map(~{ + future_map_dfr(.$models,~{.$proximity %>% + as_tibble() %>% + mutate(Sample = seq_len(nrow(.))) %>% + gather('Sample2','Proximity',-Sample) %>% + rename(Sample1 = Sample) + }, + .id = 'Rep', + .options = furrr_options(seed = seed)) %>% + mutate(Rep = as.numeric(Rep)) + }) %>% + bind_rows(.id = 'Response') %>% + mutate(Sample2 = as.numeric(Sample2)) + + if (perm > 0) { + permutations <- regressionPermutationMeasures(models) + } else { + permutations <- list() + } + + results <- list( + measures = regressionMeasures(predictions,permutations), + importances = regressionImportance(importances,permutations) + ) + + res <- new('RandomForest') + res@type <- 'regression' + res@response <- cls + dat(res) <- dat(x) + sinfo(res) <- sinfo(x) + res@results <- results + res@predictions <- predictions + res@permutations <- permutations + res@importances <- importances + res@proximities <- proximities + + if (isTRUE(returnModels)) { + res@models <- models + } + + return(res) +} diff --git a/R/randomForest.R b/R/randomForest.R index 1195cb0d..b03f7f6b 100644 --- a/R/randomForest.R +++ b/R/randomForest.R @@ -1,769 +1,3 @@ -nPerm <- function(n,k){choose(n,k) * factorial(k)} - -#' @importFrom stats runif - -permute <- function(x,cls,rf,n = 1000){ - i <- x %>% - sinfo() %>% - select(cls) %>% - unlist(use.names = FALSE) - - if (is.character(i) | is.factor(i)) { - i <- factor(i) - } - - if (nPerm(length(i),length(unique(i))) < n) { - n <- nPerm(length(i),length(unique(i))) - } - - models <- future_map(1:n,~{ - params <- formals(randomForest::randomForest) - params <- c(params,rf) - params$x <- x %>% dat() - ind <- sample(i) - params$y <- ind - params$strata <- ind - do.call(randomForest::randomForest,params) - },.options = furrr_options(seed = runif(1) %>% - {. * 100000} %>% - round())) %>% - set_names(1:n) - - return(models) -} - -importance <- function(x){ - x %>% - randomForest::importance() %>% - {bind_cols(tibble(Feature = rownames(.)),as_tibble(.,.name_repair = 'minimal'))} -} - -#' @importFrom randomForest margin -#' @importFrom stats pnorm - -classificationMeasures <- function(predictions,permutations){ - - class_metrics <- metric_set(accuracy,kap) - - meas <- predictions %>% - base::split(.$Response) %>% - map(~{ - d <- . - d %>% - base::split(.$Comparison) %>% - map(~{ - p <- . - p %>% - mutate(obs = factor(obs),pred = factor(pred)) %>% - group_by(Response,Comparison) %>% - class_metrics(obs,estimate = pred) - }) %>% - bind_rows() - }) %>% - bind_rows() %>% - bind_rows( - suppressMessages( - predictions %>% - base::split(.$Response) %>% - map(~{ - d <- . - d %>% - base::split(.$Comparison) %>% - map(~{ - p <- . - - p <- p %>% - mutate(obs = factor(obs),pred = factor(pred)) - if (length(levels(p$obs)) > 2) { - estimate <- levels(p$obs) - } else { - estimate <- levels(p$obs)[1] - } - p %>% - group_by(Response,Comparison) %>% - roc_auc(obs,estimate) - }) %>% - bind_rows() - }) %>% - bind_rows())) %>% - bind_rows(predictions %>% - group_by(Response,Comparison) %>% - summarise(.estimate = mean(margin)) %>% - mutate(.metric = 'margin')) - - if (length(permutations) > 0) { - meas <- meas %>% - left_join( - permutations$measures, - by = c("Response","Comparison", ".metric")) %>% - mutate(Pvalue = pnorm(.estimate,Mean,SD,lower.tail = FALSE)) %>% - select(-Mean,-SD) - } - - return(meas) -} - -#' @importFrom dplyr rowwise - -classificationImportance <- function(importances,permutations){ - imps <- importances %>% - group_by(Response,Comparison,Feature,Metric) %>% - summarise(Value = mean(Value)) - - if (length(permutations) > 0) { - lowertail <- list(MeanDecreaseGini = FALSE, - SelectionFrequency = FALSE, - FalsePositiveRate = TRUE) - - imps <- imps %>% - left_join( - permutations$importance, - by = c("Response","Comparison", "Feature", "Metric")) %>% - base::split(.$Metric) %>% - map(~{ - i <- . - tail <- lowertail[[i$Metric[1]]] - i %>% - rowwise() %>% - mutate(Pvalue = pnorm(Value,Mean,SD,lower.tail = tail)) %>% - ungroup() - }) %>% - bind_rows() %>% - group_by(Metric) %>% - mutate(adjustedPvalue = p.adjust(Pvalue,method = 'bonferroni')) %>% - select(-Mean,-SD) - } - - return(imps) -} - -classificationPermutationMeasures <- function(models){ - suppressWarnings({ - preds <- models %>% - map(~{ - map(.,~{ - map(.$permutations,~{ - m <- . - tibble(sample = seq_along(m$y), - obs = m$y, - pred = m$predicted, - margin = margin(m)) %>% - bind_cols(m$votes %>% - as_tibble(.name_repair = 'minimal')) - }) %>% - { - suppressMessages(bind_rows(.,.id = 'Permutation')) - } %>% - mutate(Permutation = as.numeric(Permutation)) - }) %>% - bind_rows(.id = 'Comparison') - }) %>% - bind_rows(.id = 'Response') - }) - - class_metrics <- metric_set(accuracy,kap) - - meas <- preds %>% - base::split(.$Response) %>% - map(~{ - d <- . - d %>% - base::split(.$Comparison) %>% - map(~{ - p <- . - p %>% - mutate(obs = factor(obs),pred = factor(pred)) %>% - group_by(Response,Comparison,Permutation) %>% - class_metrics(obs,estimate = pred) - }) %>% - bind_rows() - }) %>% - bind_rows() %>% - bind_rows( - suppressMessages( - preds %>% - base::split(.$Response) %>% - map(~{ - d <- . - d %>% - base::split(.$Comparison) %>% - map(~{ - p <- . - - p <- p %>% - mutate(obs = factor(obs),pred = factor(pred)) - if (length(levels(p$obs)) > 2) { - estimate <- levels(p$obs) - } else { - estimate <- levels(p$obs)[1] - } - p %>% - group_by(Response,Comparison,Permutation) %>% - roc_auc(obs,estimate) - }) %>% - bind_rows() - }) %>% - bind_rows())) %>% - bind_rows(preds %>% - group_by(Response,Comparison,Permutation) %>% - summarise(.estimate = mean(margin)) %>% - mutate(.metric = 'margin')) %>% - group_by(Response,Comparison,.metric) %>% - summarise(Mean = mean(.estimate),SD = sd(.estimate)) - - imps <- models %>% - map(~{ - map(.,~{ - map(.$permutations,~{ - m <- . - importance(m) %>% - left_join(fpr_fs(m),by = c('Feature' = 'variable')) %>% - rename(SelectionFrequency = freq,FalsePositiveRate = fpr) - }) %>% - bind_rows(.id = 'Permutation') %>% - mutate(Permutation = as.numeric(Permutation)) - }) %>% - bind_rows(.id = 'Comparison') - }) %>% - bind_rows(.id = 'Response') %>% - gather('Metric','Value',-(Response:Feature)) %>% - group_by(Response,Comparison,Feature,Metric) %>% - summarise(Mean = mean(Value),SD = sd(Value)) - - return(list(measures = meas,importance = imps)) -} - -regressionMeasures <- function(predictions,permutations){ - reg_metrics <- metric_set(rsq,mae,mape,rmse,ccc) - meas <- predictions %>% - base::split(.$Response) %>% - map(~{ - d <- . - d %>% - group_by(Response) %>% - reg_metrics(obs,estimate = pred) - }) %>% - bind_rows() - - if (length(permutations) > 0) { - lowertail <- list(rsq = FALSE, - mae = TRUE, - mape = TRUE, - mape = TRUE, - rmse = TRUE, - ccc = FALSE) - - meas <- meas %>% - left_join(permutations$measures, by = c("Response", ".metric")) %>% - rowwise() %>% - mutate(Pvalue = pnorm(.estimate, - Mean, - SD, - lower.tail = lowertail[[.metric]])) %>% - select(-Mean,-SD) - } - - return(meas) -} - -regressionImportance <- function(importances,permutations){ - imps <- importances %>% - group_by(Response,Feature,Metric) %>% - summarise(Value = mean(Value)) - - if (length(permutations) > 0) { - imps <- imps %>% - left_join(permutations$importance, - by = c("Response", "Feature", "Metric")) %>% - mutate(Pvalue = pnorm(Value,Mean,SD,lower.tail = FALSE)) %>% - group_by(Metric) %>% - mutate(adjustedPvalue = p.adjust(Pvalue,method = 'bonferroni')) %>% - select(-Mean,-SD) - } - - return(imps) -} - -regressionPermutationMeasures <- function(models){ - preds <- models %>% - map(~{ - map(.$permutations,~{ - m <- . - tibble(sample = seq_along(m$y),obs = m$y,pred = m$predicted) - }) %>% - bind_rows(.id = 'Permutation') %>% - mutate(Permutation = as.numeric(Permutation)) - }) %>% - bind_rows(.id = 'Response') - - reg_metrics <- metric_set(rsq,mae,mape,rmse,ccc) - - meas <- preds %>% - base::split(.$Response) %>% - map(~{ - d <- . - d %>% - group_by(Response,Permutation) %>% - reg_metrics(obs,estimate = pred) - }) %>% - bind_rows() %>% - group_by(Response,.metric) %>% - summarise(Mean = mean(.estimate),SD = sd(.estimate)) - - imps <- models %>% - map(~{ - map(.$permutations,~{ - m <- . - importance(m) - }) %>% - bind_rows(.id = 'Permutation') %>% - mutate(Permutation = as.numeric(Permutation)) - }) %>% - bind_rows(.id = 'Response') %>% - gather('Metric','Value',-Response,-Permutation,-Feature) %>% - group_by(Response,Feature,Metric) %>% - summarise(Mean = mean(Value),SD = sd(Value)) - - return(list(measures = meas,importance = imps)) -} - -#' @importFrom forestControl fpr_fs - -unsupervised <- function(x,rf,reps,returnModels,seed,...){ - - set.seed(seed) - - models <- future_map(1:reps,~{ - params <- formals(randomForest::randomForest) - params$x <- x %>% dat() - params <- c(params,rf) - do.call(randomForest::randomForest,params) - },.options = furrr_options(seed = seed)) %>% - set_names(1:reps) - - importances <- models %>% - future_map_dfr(~{ - m <- . - importance(m) %>% - left_join(fpr_fs(m),by = c('Feature' = 'variable')) %>% - rename(SelectionFrequency = freq,FalsePositiveRate = fpr) - }, - .id = 'Rep', - .options = furrr_options(seed = seed)) %>% - mutate(Rep = as.numeric(Rep)) %>% - gather('Metric','Value',-Rep,-Feature) - - proximities <- models %>% - future_map_dfr(.,~{.$proximity %>% - as_tibble(.name_repair = 'minimal') %>% - mutate(Sample = seq_len(nrow(.))) %>% - gather('Sample2','Proximity',-Sample) %>% - rename(Sample1 = Sample) - }, - .id = 'Rep', - .options = furrr_options(seed = seed)) %>% - mutate(Rep = as.numeric(Rep)) %>% - mutate(Sample2 = as.numeric(Sample2)) - - results <- list( - importances = importances %>% - select(-Rep) %>% - group_by(Feature,Metric) %>% - summarise(Value = mean(Value)) - ) - - res <- new('RandomForest') - res@type <- 'unsupervised' - dat(res) <- dat(x) - sinfo(res) <- sinfo(x) - res@results <- results - res@importances <- importances - res@proximities <- proximities - - if (isTRUE(returnModels)) { - res@models <- models - } - - return(list(res)) -} - -supervised <- function(x, - cls, - rf, - reps, - binary, - comparisons, - perm, - returnModels, - seed){ - i <- x %>% - sinfo() %>% - select(all_of(cls)) - - i %>% - colnames() %>% - map(~{ - cls <- . - - pred <- i %>% - select(all_of(cls)) %>% - deframe() - - if (is.numeric(pred)) { - regression(x, - cls, - rf, - reps, - perm, - returnModels, - seed) - } else { - classification(x, - cls, - rf, - reps, - binary, - comparisons, - perm, - returnModels, - seed) - } - }) %>% - set_names(colnames(i)) -} - -#' @importFrom yardstick metric_set accuracy kap roc_auc -#' @importFrom dplyr summarise_all group_by_all n -#' @importFrom stringr str_split -#' @importFrom magrittr set_names -#' @importFrom furrr future_map_dfr - -classification <- function(x, - cls, - rf, - reps, - binary, - comparisons, - perm, - returnModels, - seed){ - - i <- x %>% - sinfo() %>% - select(all_of(cls)) - - clsFreq <- i %>% - group_by_all() %>% - summarise(n = n(),.groups = 'drop') - - if (any(clsFreq$n < 5)) { - clsRem <- clsFreq %>% - filter(n < 5) - - x <- x %>% - removeClasses(cls = cls,classes = clsRem %>% - select(all_of(cls)) %>% - deframe()) - - cls_list <- clsRem %>% - select(all_of(cls)) %>% - deframe() %>% - str_c('"',.,'"') %>% - str_c(.,collapse = ', ') - - warning(str_c('Classes with < 5 replicates removed: ', - cls_list), - call. = FALSE) - - i <- x %>% - sinfo() %>% - select(cls) - } - - if (length(unique(deframe(i))) < 2) { - stop('Need at least two classes to do classification.',call. = FALSE) - } - - if (length(comparisons) > 0) { - comp <- comparisons - } else { - if (binary == TRUE) { - comp <- map(names(i),~{ - binaryComparisons(x,cls = .x) - }) %>% - set_names(names(i)) - } else { - comp <- map(i,~{unique(.) %>% - sort() %>% - str_c(collapse = '~')}) - } - } - - models <- i %>% - colnames() %>% - map(~{ - inf <- . - - comps <- comp[[inf]] - - comps %>% - map(~{ - comparison <- str_split(.,'~')[[1]] - - cda <- keepClasses(x,inf,classes = comparison) - - pred <- cda %>% - sinfo() %>% - select(all_of(inf)) %>% - deframe() %>% - factor() - - predFreq <- pred %>% - tibble(cls = .) %>% - group_by_all() %>% - summarise(n = n(),.groups = 'drop') - - if (length(unique(predFreq$n)) > 1) { - message( - str_c('Unbalanced classes detected. Stratifying ', - 'sample size to the smallest class size.')) - - ss <- pred %>% - table() %>% - min() %>% - rep(length(unique(pred))) - - rf <- c(rf,list(strata = pred,sampsize = ss)) - } - - set.seed(seed) - - mod <- future_map(1:reps,~{ - params <- formals(randomForest::randomForest) - params$x <- cda %>% dat() - params$y <- pred - params <- c(params,rf) - do.call(randomForest::randomForest,params) - },.options = furrr_options(seed = seed)) %>% - set_names(1:reps) - - mod <- list(models = mod) - - if (perm > 0) { - perms <- permute(x,cls,rf,n = perm) - mod <- c(mod,list(permutations = perms)) - } - - return(mod) - }) %>% - set_names(comps) - }) %>% - set_names(colnames(i)) - - suppressMessages({ - predictions <- models %>% - map(~{ - map(.x,~{ - future_map_dfr(.x$models,~{ - m <- .x - tibble(sample = seq_along(m$y), - obs = m$y, - pred = m$predicted, - margin = margin(m)) %>% - bind_cols(m$votes %>% - as_tibble(.name_repair = 'minimal') %>% - mutate_all(as.numeric)) - }, - .id = 'Rep', - .options = furrr_options(seed = seed)) %>% - mutate(Rep = as.numeric(Rep)) - }) %>% - bind_rows(.id = 'Comparison') - }) %>% - bind_rows(.id = 'Response') - }) - - importances <- models %>% - map(~{ - map(.,~{ - future_map_dfr(.$models,~{ - m <- . - importance(m) %>% - left_join(fpr_fs(m),by = c('Feature' = 'variable')) %>% - rename(SelectionFrequency = freq,FalsePositiveRate = fpr) - }, - .id = 'Rep', - .options = furrr_options(seed = seed)) %>% - mutate(Rep = as.numeric(Rep)) - }) %>% - bind_rows(.id = 'Comparison') - }) %>% - bind_rows(.id = 'Response') %>% - gather('Metric','Value',-(Response:Feature)) - - proximities <- models %>% - map(~{ - map(.,~{ - future_map_dfr(.$models,~{.$proximity %>% - as_tibble() %>% - mutate(Sample = seq_len(nrow(.))) %>% - gather('Sample2','Proximity',-Sample) %>% - rename(Sample1 = Sample) - }, - .id = 'Rep', - .options = furrr_options(seed = seed)) %>% - mutate(Rep = as.numeric(Rep)) - }) %>% - bind_rows(.id = 'Comparison') - }) %>% - bind_rows(.id = 'Response') %>% - mutate(Sample2 = as.numeric(Sample2)) - - if (perm > 0) { - permutations <- classificationPermutationMeasures(models) - } else { - permutations <- list() - } - - results <- list( - measures = classificationMeasures(predictions,permutations), - importances = classificationImportance(importances,permutations) - ) - - res <- new('RandomForest') - res@type <- 'classification' - res@response <- cls - dat(res) <- dat(x) - sinfo(res) <- sinfo(x) - res@results <- results - res@predictions <- predictions - res@permutations <- permutations - res@importances <- importances - res@proximities <- proximities - - if (isTRUE(returnModels)) { - res@models <- models - } - - return(res) -} - -#' @importFrom yardstick rsq mae mape rmse ccc - -regression <- function(x, - cls, - rf, - reps, - perm, - returnModels, - seed){ - i <- x %>% - sinfo() %>% - select(cls) - - models <- i %>% - colnames() %>% - map(~{ - inf <- . - - pred <- i %>% - select(inf) %>% - unlist(use.names = FALSE) - - set.seed(seed) - - mod <- future_map(1:reps,~{ - params <- formals(randomForest::randomForest) - params$x <- x %>% dat() - params$y <- pred - params <- c(params,rf) - do.call(randomForest::randomForest,params) - },.options = furrr_options(seed = seed)) %>% - set_names(1:reps) - - mod <- list(models = mod) - - if (perm > 0) { - perms <- permute(x,cls,rf,n = perm) - } else { - perms <- list() - } - - mod <- c(mod,list(permutations = perms)) - - return(mod) - }) %>% - set_names(colnames(i)) - - predictions <- models %>% - map(~{ - future_map_dfr(.$models,~{ - m <- . - tibble(sample = seq_along(m$y),obs = m$y,pred = m$predicted) - }, - .id = 'Rep', - .options = furrr_options(seed = seed)) %>% - mutate(Rep = as.numeric(Rep)) - }) %>% - bind_rows(.id = 'Response') - - importances <- models %>% - map(~{ - future_map_dfr(.$models,~{ - m <- . - importance(m) - }, - .id = 'Rep', - .options = furrr_options(seed = seed)) %>% - mutate(Rep = as.numeric(Rep)) - }) %>% - bind_rows(.id = 'Response') %>% - gather('Metric','Value',-Response,-Rep,-Feature) - - proximities <- models %>% - map(~{ - future_map_dfr(.$models,~{.$proximity %>% - as_tibble() %>% - mutate(Sample = seq_len(nrow(.))) %>% - gather('Sample2','Proximity',-Sample) %>% - rename(Sample1 = Sample) - }, - .id = 'Rep', - .options = furrr_options(seed = seed)) %>% - mutate(Rep = as.numeric(Rep)) - }) %>% - bind_rows(.id = 'Response') %>% - mutate(Sample2 = as.numeric(Sample2)) - - if (perm > 0) { - permutations <- regressionPermutationMeasures(models) - } else { - permutations <- list() - } - - results <- list( - measures = regressionMeasures(predictions,permutations), - importances = regressionImportance(importances,permutations) - ) - - res <- new('RandomForest') - res@type <- 'regression' - res@response <- cls - dat(res) <- dat(x) - sinfo(res) <- sinfo(x) - res@results <- results - res@predictions <- predictions - res@permutations <- permutations - res@importances <- importances - res@proximities <- proximities - - if (isTRUE(returnModels)) { - res@models <- models - } - - return(res) -} - #' Random forest analysis #' @rdname randomForest #' @description Perform random forest on an `AnalysisData` object From 8ef9941157a2e8aa562c8db39259a755e4fb61d1 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Thu, 27 Oct 2022 17:21:14 +0100 Subject: [PATCH 13/89] tidy rf permutation calculation --- R/randomForest-classification.R | 50 ++++++++++++++++++++++++++------- R/randomForest-internals.R | 14 +++++++-- R/randomForest-permute.R | 48 +++++++++++++++++++++---------- 3 files changed, 85 insertions(+), 27 deletions(-) diff --git a/R/randomForest-classification.R b/R/randomForest-classification.R index 866fe2bb..3927f10b 100644 --- a/R/randomForest-classification.R +++ b/R/randomForest-classification.R @@ -1,4 +1,42 @@ +classificationPredictions <- function(model){ + tibble(sample = seq_along(model$y), + obs = model$y, + pred = model$predicted, + margin = margin(model)) %>% + bind_cols(model$votes %>% + as_tibble(.name_repair = 'minimal') %>% + mutate_all(as.numeric)) +} + +classificationMetrics <- function(model){ + predictions <- model %>% + classificationPredictions() + + class_metrics <- metric_set(accuracy,kap) + + acc_kap <- predictions %>% + class_metrics(obs,estimate = pred) + + if (length(levels(predictions$obs)) > 2) { + estimate <- levels(predictions$obs) + } else { + estimate <- levels(predictions$obs)[1] + } + + roc <- predictions %>% + roc_auc(obs,estimate) + + bind_rows( + acc_kap, + roc, + tibble(.metric = 'margin', + .estimate = margin(model) %>% + mean()) + ) + +} + #' @importFrom randomForest margin #' @importFrom stats pnorm @@ -230,16 +268,8 @@ classification <- function(x, predictions <- models %>% map(~{ map(.x,~{ - future_map_dfr(.x$models,~{ - m <- .x - tibble(sample = seq_along(m$y), - obs = m$y, - pred = m$predicted, - margin = margin(m)) %>% - bind_cols(m$votes %>% - as_tibble(.name_repair = 'minimal') %>% - mutate_all(as.numeric)) - }, + future_map_dfr(.x$models, + classificationPredictions, .id = 'Rep', .options = furrr_options(seed = seed)) %>% mutate(Rep = as.numeric(Rep)) diff --git a/R/randomForest-internals.R b/R/randomForest-internals.R index 5e29289a..39c44a48 100644 --- a/R/randomForest-internals.R +++ b/R/randomForest-internals.R @@ -1,6 +1,16 @@ -importance <- function(x){ - x %>% +performRF <- function(x,cls,rf){ + +} + +performanceMetrics <- function(model,type){ + switch(type, + classification = classificationMetrics(model), + regression = regressionMetrics(model)) +} + +importance <- function(model){ + model %>% randomForest::importance() %>% {bind_cols(tibble(Feature = rownames(.)),as_tibble(.,.name_repair = 'minimal'))} } diff --git a/R/randomForest-permute.R b/R/randomForest-permute.R index 464fa91b..ffe01806 100644 --- a/R/randomForest-permute.R +++ b/R/randomForest-permute.R @@ -2,7 +2,25 @@ nPerm <- function(n,k){choose(n,k) * factorial(k)} #' @importFrom stats runif -permute <- function(x,cls,rf,n = 1000){ +permute <- function(x,cls,rf,type){ + params <- formals(randomForest::randomForest) + params <- c(params,rf) + params$x <- x %>% dat() + ind <- x %>% + sinfo() %>% + select(all_of(cls)) %>% + unlist(use.names = FALSE) %>% + sample() + params$y <- ind + params$strata <- ind + + model <- do.call(randomForest::randomForest,params) + + performanceMetrics(model, + type = type) +} + +permutations <- function(x,cls,rf,n,type){ i <- x %>% sinfo() %>% select(cls) %>% @@ -16,20 +34,20 @@ permute <- function(x,cls,rf,n = 1000){ n <- nPerm(length(i),length(unique(i))) } - models <- future_map(1:n,~{ - params <- formals(randomForest::randomForest) - params <- c(params,rf) - params$x <- x %>% dat() - ind <- sample(i) - params$y <- ind - params$strata <- ind - do.call(randomForest::randomForest,params) - },.options = furrr_options(seed = runif(1) %>% - {. * 100000} %>% - round())) %>% - set_names(1:n) - - return(models) + future_map_dfr(1:n, + ~permute(x = x, + cls = cls, + rf = rf, + type = type), + .id = 'permutation', + .options = furrr_options( + seed = runif(1) %>% + {. * 100000} %>% + round() + )) %>% + group_by(.metric) %>% + summarise(mean = mean(.estimate), + sd = sd(.estimate)) } classificationPermutationMeasures <- function(models){ From e40900d58b999169245a18447c73a3a112645bf0 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Thu, 27 Oct 2022 18:50:01 +0100 Subject: [PATCH 14/89] streamline randomforest classification --- R/allClasses.R | 12 +- R/modelling-accessors.R | 4 +- R/randomForest-classification.R | 208 +++++++++++++------------------- R/randomForest-internals.R | 54 ++++++++- R/randomForest-permute.R | 44 ++++--- R/randomForest-regression.R | 6 + R/show-method.R | 4 +- 7 files changed, 182 insertions(+), 150 deletions(-) diff --git a/R/allClasses.R b/R/allClasses.R index 6edd9228..c461096c 100644 --- a/R/allClasses.R +++ b/R/allClasses.R @@ -91,12 +91,22 @@ setClass('RandomForest', slots = list( type = 'character', response = 'character', - results = 'list', + metrics = 'tbl_df', predictions = 'tbl_df', permutations = 'list', importances = 'tbl_df', proximities = 'tbl_df', models = 'list' + ), + prototype = list( + type = 'classification', + response = 'class', + metrics = tibble(), + predictions = tibble(), + permutations = list(), + importances = tibble(), + proximities = tibble(), + models = list() ) ) diff --git a/R/modelling-accessors.R b/R/modelling-accessors.R index dba1d4fd..6b65b0db 100644 --- a/R/modelling-accessors.R +++ b/R/modelling-accessors.R @@ -145,7 +145,7 @@ setGeneric("metrics", function(x) setMethod('metrics',signature = 'RandomForest', function(x){ - x@results$measures + x@metrics } ) @@ -258,7 +258,7 @@ setGeneric("importance", function(x) setMethod('importance',signature = 'RandomForest', function(x){ - x@results$importances %>% + x@importances %>% ungroup() } ) diff --git a/R/randomForest-classification.R b/R/randomForest-classification.R index 3927f10b..07525aec 100644 --- a/R/randomForest-classification.R +++ b/R/randomForest-classification.R @@ -37,6 +37,14 @@ classificationMetrics <- function(model){ } +classificationImportance <- function(model){ + model %>% + randomForest::importance() %>% + {bind_cols(tibble(Feature = rownames(.)),as_tibble(.,.name_repair = 'minimal'))} %>% + left_join(fpr_fs(model),by = c('Feature' = 'variable')) %>% + rename(SelectionFrequency = freq,FalsePositiveRate = fpr) +} + #' @importFrom randomForest margin #' @importFrom stats pnorm @@ -104,37 +112,37 @@ classificationMeasures <- function(predictions,permutations){ #' @importFrom dplyr rowwise -classificationImportance <- function(importances,permutations){ - imps <- importances %>% - group_by(Response,Comparison,Feature,Metric) %>% - summarise(Value = mean(Value)) - - if (length(permutations) > 0) { - lowertail <- list(MeanDecreaseGini = FALSE, - SelectionFrequency = FALSE, - FalsePositiveRate = TRUE) - - imps <- imps %>% - left_join( - permutations$importance, - by = c("Response","Comparison", "Feature", "Metric")) %>% - base::split(.$Metric) %>% - map(~{ - i <- . - tail <- lowertail[[i$Metric[1]]] - i %>% - rowwise() %>% - mutate(Pvalue = pnorm(Value,Mean,SD,lower.tail = tail)) %>% - ungroup() - }) %>% - bind_rows() %>% - group_by(Metric) %>% - mutate(adjustedPvalue = p.adjust(Pvalue,method = 'bonferroni')) %>% - select(-Mean,-SD) - } - - return(imps) -} +# classificationImportance <- function(importances,permutations){ +# imps <- importances %>% +# group_by(Response,Comparison,Feature,Metric) %>% +# summarise(Value = mean(Value)) +# +# if (length(permutations) > 0) { +# lowertail <- list(MeanDecreaseGini = FALSE, +# SelectionFrequency = FALSE, +# FalsePositiveRate = TRUE) +# +# imps <- imps %>% +# left_join( +# permutations$importance, +# by = c("Response","Comparison", "Feature", "Metric")) %>% +# base::split(.$Metric) %>% +# map(~{ +# i <- . +# tail <- lowertail[[i$Metric[1]]] +# i %>% +# rowwise() %>% +# mutate(Pvalue = pnorm(Value,Mean,SD,lower.tail = tail)) %>% +# ungroup() +# }) %>% +# bind_rows() %>% +# group_by(Metric) %>% +# mutate(adjustedPvalue = p.adjust(Pvalue,method = 'bonferroni')) %>% +# select(-Mean,-SD) +# } +# +# return(imps) +# } #' @importFrom yardstick metric_set accuracy kap roc_auc #' @importFrom dplyr summarise_all group_by_all n @@ -144,13 +152,17 @@ classificationImportance <- function(importances,permutations){ classification <- function(x, cls, - rf, - reps, - binary, - comparisons, - perm, - returnModels, - seed){ + rf = list( + keep.forest = TRUE, + proximity = TRUE, + importance = TRUE + ), + reps = 1, + binary = FALSE, + comparisons = list(), + perm = 0, + returnModels = FALSE, + seed = 1234){ i <- x %>% sinfo() %>% @@ -206,13 +218,13 @@ classification <- function(x, models <- i %>% colnames() %>% map(~{ - inf <- . + inf <- .x comps <- comp[[inf]] comps %>% map(~{ - comparison <- str_split(.,'~')[[1]] + comparison <- str_split(.x,'~')[[1]] cda <- keepClasses(x,inf,classes = comparison) @@ -242,104 +254,48 @@ classification <- function(x, set.seed(seed) - mod <- future_map(1:reps,~{ - params <- formals(randomForest::randomForest) - params$x <- cda %>% dat() - params$y <- pred - params <- c(params,rf) - do.call(randomForest::randomForest,params) - },.options = furrr_options(seed = seed)) %>% + models <- future_map( + 1:reps,~{ + performRF( + dat(cda), + pred, + rf, + type = 'classification', + returnModel = returnModels) + }, + .options = furrr_options(seed = seed)) %>% set_names(1:reps) - mod <- list(models = mod) - - if (perm > 0) { - perms <- permute(x,cls,rf,n = perm) - mod <- c(mod,list(permutations = perms)) - } - - return(mod) + return(models) }) %>% set_names(comps) }) %>% set_names(colnames(i)) - suppressMessages({ - predictions <- models %>% - map(~{ - map(.x,~{ - future_map_dfr(.x$models, - classificationPredictions, - .id = 'Rep', - .options = furrr_options(seed = seed)) %>% - mutate(Rep = as.numeric(Rep)) - }) %>% - bind_rows(.id = 'Comparison') - }) %>% - bind_rows(.id = 'Response') - }) - - importances <- models %>% - map(~{ - map(.,~{ - future_map_dfr(.$models,~{ - m <- . - importance(m) %>% - left_join(fpr_fs(m),by = c('Feature' = 'variable')) %>% - rename(SelectionFrequency = freq,FalsePositiveRate = fpr) - }, - .id = 'Rep', - .options = furrr_options(seed = seed)) %>% - mutate(Rep = as.numeric(Rep)) - }) %>% - bind_rows(.id = 'Comparison') - }) %>% - bind_rows(.id = 'Response') %>% - gather('Metric','Value',-(Response:Feature)) - - proximities <- models %>% - map(~{ - map(.,~{ - future_map_dfr(.$models,~{.$proximity %>% - as_tibble() %>% - mutate(Sample = seq_len(nrow(.))) %>% - gather('Sample2','Proximity',-Sample) %>% - rename(Sample1 = Sample) - }, - .id = 'Rep', - .options = furrr_options(seed = seed)) %>% - mutate(Rep = as.numeric(Rep)) - }) %>% - bind_rows(.id = 'Comparison') - }) %>% - bind_rows(.id = 'Response') %>% - mutate(Sample2 = as.numeric(Sample2)) - if (perm > 0) { - permutations <- classificationPermutationMeasures(models) + permutation_results <- permutations(x, + cls, + rf, + perm, + type = 'classification') } else { - permutations <- list() + permutations_results <- list() } - results <- list( - measures = classificationMeasures(predictions,permutations), - importances = classificationImportance(importances,permutations) - ) - - res <- new('RandomForest') - res@type <- 'classification' - res@response <- cls - dat(res) <- dat(x) - sinfo(res) <- sinfo(x) - res@results <- results - res@predictions <- predictions - res@permutations <- permutations - res@importances <- importances - res@proximities <- proximities - + res <- new('RandomForest', + x, + type = 'classification', + response = cls, + metrics = collate(models,'metrics'), + predictions = collate(models,'predictions'), + importances = collate(models,'importance'), + proximities = collate(models,'proximities'), + permutations = permutation_results) + + if (isTRUE(returnModels)) { - res@models <- models + res@models <- collateModels(models) } - + return(res) } diff --git a/R/randomForest-internals.R b/R/randomForest-internals.R index 39c44a48..e0f3b91b 100644 --- a/R/randomForest-internals.R +++ b/R/randomForest-internals.R @@ -1,6 +1,21 @@ -performRF <- function(x,cls,rf){ +performRF <- function(x,cls,rf,type,returnModel){ + params <- formals(randomForest::randomForest) + params$x <- x + params$y <- cls + params <- c(params,rf) + model <- do.call(randomForest::randomForest,params) + model_results <- list(metrics = performanceMetrics(model, + type = type), + importance = modelImportance(model,type), + predictions = modelPredictions(model,type), + proximities = modelProximities(model)) + + if (isTRUE(returnModel)) model_results <- c(model_results, + list(model = model)) + + return(model_results) } performanceMetrics <- function(model,type){ @@ -9,10 +24,39 @@ performanceMetrics <- function(model,type){ regression = regressionMetrics(model)) } -importance <- function(model){ - model %>% - randomForest::importance() %>% - {bind_cols(tibble(Feature = rownames(.)),as_tibble(.,.name_repair = 'minimal'))} +modelPredictions <- function(model,type){ + switch(type, + classification = classificationPredictions(model), + regression = regressionPredictions(model)) +} + +modelImportance <- function(model,type){ + switch(type, + classification = classificationImportance(model), + regression = model %>% + randomForest::importance() %>% + {bind_cols(tibble(Feature = rownames(.)),as_tibble(.,.name_repair = 'minimal'))}) +} + +modelProximities <- function(model){ + model$proximity %>% + as_tibble(.name_repair = 'minimal') %>% + mutate(Sample = seq_len(nrow(.))) %>% + gather('Sample2','Proximity',-Sample) %>% + rename(Sample1 = Sample) +} + +collate <- function(models,type){ + models %>% + map_dfr( + ~.x %>% + map_dfr(~.x %>% + map_dfr(~.x[[type]], + .id = 'rep'), + .id = 'comparison' + ), + .id = 'response' + ) } #' @importFrom forestControl fpr_fs diff --git a/R/randomForest-permute.R b/R/randomForest-permute.R index ffe01806..f7b7cd7d 100644 --- a/R/randomForest-permute.R +++ b/R/randomForest-permute.R @@ -3,21 +3,23 @@ nPerm <- function(n,k){choose(n,k) * factorial(k)} #' @importFrom stats runif permute <- function(x,cls,rf,type){ - params <- formals(randomForest::randomForest) - params <- c(params,rf) - params$x <- x %>% dat() - ind <- x %>% + + randomised_cls <- x %>% sinfo() %>% select(all_of(cls)) %>% unlist(use.names = FALSE) %>% sample() - params$y <- ind - params$strata <- ind - model <- do.call(randomForest::randomForest,params) + rf$strata <- randomised_cls + + model <- performRF(dat(x), + randomised_cls, + rf, + type, + returnModel = FALSE) - performanceMetrics(model, - type = type) + list(metrics = model$metrics, + importance = model$importance) } permutations <- function(x,cls,rf,n,type){ @@ -34,7 +36,7 @@ permutations <- function(x,cls,rf,n,type){ n <- nPerm(length(i),length(unique(i))) } - future_map_dfr(1:n, + permutation_results <- future_map(1:n, ~permute(x = x, cls = cls, rf = rf, @@ -44,10 +46,24 @@ permutations <- function(x,cls,rf,n,type){ seed = runif(1) %>% {. * 100000} %>% round() - )) %>% - group_by(.metric) %>% - summarise(mean = mean(.estimate), - sd = sd(.estimate)) + )) + + permutation_metrics <- permutation_results %>% + map_dfr(~.x$metrics,id = 'permutation') %>% + group_by(.metric) %>% + summarise(mean = mean(.estimate), + sd = sd(.estimate)) + + permutation_importance <- permutation_results %>% + map_dfr(~.x$importance,id = 'permutation') %>% + gather(metric,value,-Feature) %>% + group_by(Feature,metric) %>% + summarise(mean = mean(value), + sd = sd(value), + .groups = 'drop') + + list(metrics = permutation_metrics, + importance = permutation_importance) } classificationPermutationMeasures <- function(models){ diff --git a/R/randomForest-regression.R b/R/randomForest-regression.R index 77e7fce3..6638c528 100644 --- a/R/randomForest-regression.R +++ b/R/randomForest-regression.R @@ -1,3 +1,9 @@ +regressionPredictions <- function(model){ + tibble(sample = seq_along(model$y), + obs = model$y, + pred = model$predicted) +} + regressionMeasures <- function(predictions,permutations){ reg_metrics <- metric_set(rsq,mae,mape,rmse,ccc) meas <- predictions %>% diff --git a/R/show-method.R b/R/show-method.R index f7ccf3b5..d38dff0c 100644 --- a/R/show-method.R +++ b/R/show-method.R @@ -159,14 +159,14 @@ setMethod('show',signature = 'RandomForest', if (object@type != 'unsupervised') { cat('Response:\t',metrics(object) %>% - .$Response %>% + .$response %>% unique() %>% str_c(collapse = ', '),'\n') } if (object@type == 'classification') { cat('# comparisons:\t',metrics(object) %>% - .$Comparison %>% + .$comparison %>% unique() %>% length(),'\n') } From 473afd41c33b382c7d8a059c97e41c1013f68ae5 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Thu, 27 Oct 2022 23:19:29 +0100 Subject: [PATCH 15/89] streamline random forest regression --- R/randomForest-regression.R | 237 ++++++++++++++++-------------------- 1 file changed, 108 insertions(+), 129 deletions(-) diff --git a/R/randomForest-regression.R b/R/randomForest-regression.R index 6638c528..d13de278 100644 --- a/R/randomForest-regression.R +++ b/R/randomForest-regression.R @@ -4,66 +4,90 @@ regressionPredictions <- function(model){ pred = model$predicted) } -regressionMeasures <- function(predictions,permutations){ - reg_metrics <- metric_set(rsq,mae,mape,rmse,ccc) - meas <- predictions %>% - base::split(.$Response) %>% - map(~{ - d <- . - d %>% - group_by(Response) %>% - reg_metrics(obs,estimate = pred) - }) %>% - bind_rows() +regressionMetrics <- function(model){ + predictions <- model %>% + regressionPredictions() - if (length(permutations) > 0) { - lowertail <- list(rsq = FALSE, - mae = TRUE, - mape = TRUE, - mape = TRUE, - rmse = TRUE, - ccc = FALSE) - - meas <- meas %>% - left_join(permutations$measures, by = c("Response", ".metric")) %>% - rowwise() %>% - mutate(Pvalue = pnorm(.estimate, - Mean, - SD, - lower.tail = lowertail[[.metric]])) %>% - select(-Mean,-SD) - } + reg_metrics <- metric_set(rsq,mae,mape,rmse,ccc) - return(meas) + predictions %>% + reg_metrics(obs,estimate = pred) } -regressionImportance <- function(importances,permutations){ - imps <- importances %>% - group_by(Response,Feature,Metric) %>% - summarise(Value = mean(Value)) - - if (length(permutations) > 0) { - imps <- imps %>% - left_join(permutations$importance, - by = c("Response", "Feature", "Metric")) %>% - mutate(Pvalue = pnorm(Value,Mean,SD,lower.tail = FALSE)) %>% - group_by(Metric) %>% - mutate(adjustedPvalue = p.adjust(Pvalue,method = 'bonferroni')) %>% - select(-Mean,-SD) - } - - return(imps) -} +# regressionMeasures <- function(predictions,permutations){ + # reg_metrics <- metric_set(rsq,mae,mape,rmse,ccc) +# meas <- predictions %>% +# base::split(.$Response) %>% +# map(~{ +# d <- . +# d %>% +# group_by(Response) %>% +# reg_metrics(obs,estimate = pred) +# }) %>% +# bind_rows() +# +# if (length(permutations) > 0) { +# lowertail <- list(rsq = FALSE, +# mae = TRUE, +# mape = TRUE, +# mape = TRUE, +# rmse = TRUE, +# ccc = FALSE) +# +# meas <- meas %>% +# left_join(permutations$measures, by = c("Response", ".metric")) %>% +# rowwise() %>% +# mutate(Pvalue = pnorm(.estimate, +# Mean, +# SD, +# lower.tail = lowertail[[.metric]])) %>% +# select(-Mean,-SD) +# } +# +# return(meas) +# } +# regressionImportance <- function(importances,permutations){ +# imps <- importances %>% +# group_by(Response,Feature,Metric) %>% +# summarise(Value = mean(Value)) +# +# if (length(permutations) > 0) { +# imps <- imps %>% +# left_join(permutations$importance, +# by = c("Response", "Feature", "Metric")) %>% +# mutate(Pvalue = pnorm(Value,Mean,SD,lower.tail = FALSE)) %>% +# group_by(Metric) %>% +# mutate(adjustedPvalue = p.adjust(Pvalue,method = 'bonferroni')) %>% +# select(-Mean,-SD) +# } +# +# return(imps) +# } + +collateRegression <- function(models,results){ + models %>% + map_dfr( + ~.x$reps %>% + map_dfr(~.x[[results]], + .id = 'rep'), + .id = 'response' + ) +} +c #' @importFrom yardstick rsq mae mape rmse ccc regression <- function(x, - cls, - rf, - reps, - perm, - returnModels, - seed){ + cls = 'class', + rf = list( + keep.forest = TRUE, + proximity = TRUE, + importance = TRUE + ), + reps = 1, + perm = 0, + returnModels = FALSE, + seed = 1234){ i <- x %>% sinfo() %>% select(cls) @@ -77,95 +101,50 @@ regression <- function(x, select(inf) %>% unlist(use.names = FALSE) - set.seed(seed) - - mod <- future_map(1:reps,~{ - params <- formals(randomForest::randomForest) - params$x <- x %>% dat() - params$y <- pred - params <- c(params,rf) - do.call(randomForest::randomForest,params) - },.options = furrr_options(seed = seed)) %>% + models <- future_map(1:reps,~{ + performRF(dat(x), + pred, + rf, + type = 'regression', + returnModel = returnModels) + }, + .options = furrr_options(seed = seed)) %>% set_names(1:reps) - mod <- list(models = mod) - if (perm > 0) { - perms <- permute(x,cls,rf,n = perm) + permutation_results <- permutations(cda, + inf, + rf, + perm, + type = 'regression') } else { - perms <- list() + permutations_results <- list() } - mod <- c(mod,list(permutations = perms)) - - return(mod) + return( + list(reps = models, + permutations = permutation_results) + ) }) %>% set_names(colnames(i)) - predictions <- models %>% - map(~{ - future_map_dfr(.$models,~{ - m <- . - tibble(sample = seq_along(m$y),obs = m$y,pred = m$predicted) - }, - .id = 'Rep', - .options = furrr_options(seed = seed)) %>% - mutate(Rep = as.numeric(Rep)) - }) %>% - bind_rows(.id = 'Response') - - importances <- models %>% - map(~{ - future_map_dfr(.$models,~{ - m <- . - importance(m) - }, - .id = 'Rep', - .options = furrr_options(seed = seed)) %>% - mutate(Rep = as.numeric(Rep)) - }) %>% - bind_rows(.id = 'Response') %>% - gather('Metric','Value',-Response,-Rep,-Feature) - - proximities <- models %>% - map(~{ - future_map_dfr(.$models,~{.$proximity %>% - as_tibble() %>% - mutate(Sample = seq_len(nrow(.))) %>% - gather('Sample2','Proximity',-Sample) %>% - rename(Sample1 = Sample) - }, - .id = 'Rep', - .options = furrr_options(seed = seed)) %>% - mutate(Rep = as.numeric(Rep)) - }) %>% - bind_rows(.id = 'Response') %>% - mutate(Sample2 = as.numeric(Sample2)) - - if (perm > 0) { - permutations <- regressionPermutationMeasures(models) - } else { - permutations <- list() - } - - results <- list( - measures = regressionMeasures(predictions,permutations), - importances = regressionImportance(importances,permutations) - ) + res <- new('RandomForest', + x, + type = 'regression', + response = cls, + metrics = collate(models,'metrics',type = 'regression') %>% + group_by(response,.metric,.estimator) %>% + summarise(.estimate = mean(.estimate)), + predictions = collate(models,'predictions',type = 'regression'), + importances = collate(models,'importance',type = 'regression') %>% + group_by(response,feature,metric) %>% + summarise(value = mean(value)), + proximities = collate(models,'proximities',type = 'regression'), + permutations = collatePermutations(models,type = 'regression')) - res <- new('RandomForest') - res@type <- 'regression' - res@response <- cls - dat(res) <- dat(x) - sinfo(res) <- sinfo(x) - res@results <- results - res@predictions <- predictions - res@permutations <- permutations - res@importances <- importances - res@proximities <- proximities if (isTRUE(returnModels)) { - res@models <- models + res@models <- collateModels(models) } return(res) From ce2dbee85add08cdb578d1ecb158518e5b1ffaab Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Thu, 27 Oct 2022 23:20:25 +0100 Subject: [PATCH 16/89] streamline random forest permutation pvalue calculation --- R/randomForest-permute.R | 288 +++++++++++++++++++-------------------- 1 file changed, 137 insertions(+), 151 deletions(-) diff --git a/R/randomForest-permute.R b/R/randomForest-permute.R index f7b7cd7d..216630da 100644 --- a/R/randomForest-permute.R +++ b/R/randomForest-permute.R @@ -3,7 +3,7 @@ nPerm <- function(n,k){choose(n,k) * factorial(k)} #' @importFrom stats runif permute <- function(x,cls,rf,type){ - + randomised_cls <- x %>% sinfo() %>% select(all_of(cls)) %>% @@ -37,27 +37,26 @@ permutations <- function(x,cls,rf,n,type){ } permutation_results <- future_map(1:n, - ~permute(x = x, - cls = cls, - rf = rf, - type = type), - .id = 'permutation', - .options = furrr_options( - seed = runif(1) %>% - {. * 100000} %>% - round() - )) + ~permute(x = x, + cls = cls, + rf = rf, + type = type), + .id = 'permutation', + .options = furrr_options( + seed = runif(1) %>% + {. * 100000} %>% + round() + )) permutation_metrics <- permutation_results %>% map_dfr(~.x$metrics,id = 'permutation') %>% - group_by(.metric) %>% - summarise(mean = mean(.estimate), - sd = sd(.estimate)) + group_by(.metric) %>% + summarise(mean = mean(.estimate), + sd = sd(.estimate)) permutation_importance <- permutation_results %>% map_dfr(~.x$importance,id = 'permutation') %>% - gather(metric,value,-Feature) %>% - group_by(Feature,metric) %>% + group_by(feature,metric) %>% summarise(mean = mean(value), sd = sd(value), .groups = 'drop') @@ -66,141 +65,128 @@ permutations <- function(x,cls,rf,n,type){ importance = permutation_importance) } -classificationPermutationMeasures <- function(models){ - suppressWarnings({ - preds <- models %>% - map(~{ - map(.,~{ - map(.$permutations,~{ - m <- . - tibble(sample = seq_along(m$y), - obs = m$y, - pred = m$predicted, - margin = margin(m)) %>% - bind_cols(m$votes %>% - as_tibble(.name_repair = 'minimal')) - }) %>% - { - suppressMessages(bind_rows(.,.id = 'Permutation')) - } %>% - mutate(Permutation = as.numeric(Permutation)) - }) %>% - bind_rows(.id = 'Comparison') - }) %>% - bind_rows(.id = 'Response') - }) - - class_metrics <- metric_set(accuracy,kap) - - meas <- preds %>% - base::split(.$Response) %>% - map(~{ - d <- . - d %>% - base::split(.$Comparison) %>% - map(~{ - p <- . - p %>% - mutate(obs = factor(obs),pred = factor(pred)) %>% - group_by(Response,Comparison,Permutation) %>% - class_metrics(obs,estimate = pred) - }) %>% - bind_rows() - }) %>% - bind_rows() %>% - bind_rows( - suppressMessages( - preds %>% - base::split(.$Response) %>% - map(~{ - d <- . - d %>% - base::split(.$Comparison) %>% - map(~{ - p <- . - - p <- p %>% - mutate(obs = factor(obs),pred = factor(pred)) - if (length(levels(p$obs)) > 2) { - estimate <- levels(p$obs) - } else { - estimate <- levels(p$obs)[1] - } - p %>% - group_by(Response,Comparison,Permutation) %>% - roc_auc(obs,estimate) - }) %>% - bind_rows() - }) %>% - bind_rows())) %>% - bind_rows(preds %>% - group_by(Response,Comparison,Permutation) %>% - summarise(.estimate = mean(margin)) %>% - mutate(.metric = 'margin')) %>% - group_by(Response,Comparison,.metric) %>% - summarise(Mean = mean(.estimate),SD = sd(.estimate)) - - imps <- models %>% - map(~{ - map(.,~{ - map(.$permutations,~{ - m <- . - importance(m) %>% - left_join(fpr_fs(m),by = c('Feature' = 'variable')) %>% - rename(SelectionFrequency = freq,FalsePositiveRate = fpr) - }) %>% - bind_rows(.id = 'Permutation') %>% - mutate(Permutation = as.numeric(Permutation)) - }) %>% - bind_rows(.id = 'Comparison') - }) %>% - bind_rows(.id = 'Response') %>% - gather('Metric','Value',-(Response:Feature)) %>% - group_by(Response,Comparison,Feature,Metric) %>% - summarise(Mean = mean(Value),SD = sd(Value)) - - return(list(measures = meas,importance = imps)) +collatePermutations <- function(models,type){ + switch(type, + classification = collatePermutationsClassification(models), + regression = collatePermutationsRegression(models)) +} + +collatePermutationsClassification <- function(models){ + permutation_metrics <- models %>% + map_dfr( + ~.x %>% + map_dfr(~.x$permutations$metrics, + .id = 'comparison' + ), + .id = 'response' + ) + + permutation_importance <- models %>% + map_dfr( + ~.x %>% + map_dfr(~.x$permutations$importance, + .id = 'comparison' + ), + .id = 'response' + ) + + list(metrics = permutation_metrics, + importance = permutation_importance) +} + +collatePermutationsRegression <- function(models){ + permutation_metrics <- models %>% + map_dfr( + ~.x$permutations$metrics, + .id = 'response' + ) + + permutation_importance <- models %>% + map_dfr( + ~.x$permutations$importance, + .id = 'response' + ) + + list(metrics = permutation_metrics, + importance = permutation_importance) } -regressionPermutationMeasures <- function(models){ - preds <- models %>% - map(~{ - map(.$permutations,~{ - m <- . - tibble(sample = seq_along(m$y),obs = m$y,pred = m$predicted) - }) %>% - bind_rows(.id = 'Permutation') %>% - mutate(Permutation = as.numeric(Permutation)) - }) %>% - bind_rows(.id = 'Response') - - reg_metrics <- metric_set(rsq,mae,mape,rmse,ccc) - - meas <- preds %>% - base::split(.$Response) %>% - map(~{ - d <- . - d %>% - group_by(Response,Permutation) %>% - reg_metrics(obs,estimate = pred) - }) %>% - bind_rows() %>% - group_by(Response,.metric) %>% - summarise(Mean = mean(.estimate),SD = sd(.estimate)) - - imps <- models %>% - map(~{ - map(.$permutations,~{ - m <- . - importance(m) - }) %>% - bind_rows(.id = 'Permutation') %>% - mutate(Permutation = as.numeric(Permutation)) - }) %>% - bind_rows(.id = 'Response') %>% - gather('Metric','Value',-Response,-Permutation,-Feature) %>% - group_by(Response,Feature,Metric) %>% - summarise(Mean = mean(Value),SD = sd(Value)) - - return(list(measures = meas,importance = imps)) +metricPvals <- function(x){ + model_type <- type(x) + + switch(model_type, + classification = classificationMetricPvals(x), + regression = regressionMetricPvals(x)) } + +classificationMetricPvals <- function(x){ + left_join(x@metrics, + x@permutations$metrics, + by = c("response", "comparison", ".metric")) %>% + mutate(`p-value` = pnorm(.estimate,mean,sd,lower.tail = FALSE)) %>% + select(-mean,-sd) +} + +regressionMetricPvals <- function(x){ + lowertail <- list(rsq = FALSE, + mae = TRUE, + mape = TRUE, + mape = TRUE, + rmse = TRUE, + ccc = FALSE) + + left_join(x@metrics, + x@permutations$metrics, + by = c("response", ".metric")) %>% + rowwise() %>% + mutate(`p-value` = pnorm(.estimate, + mean, + sd, + lower.tail = lowertail[[.metric]])) %>% + select(-mean,-sd) + +} + +importancePvals <- function(x){ + model_type <- type(x) + + switch(model_type, + classification = classificationImportancePvals(x), + regression = regressionImportancePvals(x)) +} + +classificationImportancePvals <- function(x){ + lowertail <- list(MeanDecreaseGini = FALSE, + SelectionFrequency = FALSE, + FalsePositiveRate = TRUE) + + left_join(x@importances, + x@permutations$importance, + by = c("response", "comparison", "feature",'metric')) %>% + rowwise() %>% + mutate(`p-value` = pnorm(value, + mean, + sd, + lower.tail = lowertail[[metric]]), + `adjusted_p-value` = p.adjust(`p-value`, + method = 'bonferroni', + n = nFeatures(x))) %>% + select(-mean,-sd) %>% + ungroup() +} + +regressionImportancePvals <- function(x){ + left_join(x@importances, + x@permutations$importance, + by = c("response","feature",'metric')) %>% + rowwise() %>% + mutate(`p-value` = pnorm(value, + mean, + sd, + lower.tail = FALSE), + `adjusted_p-value` = p.adjust(`p-value`, + method = 'bonferroni', + n = nFeatures(x))) %>% + select(-mean,-sd) %>% + ungroup() +} \ No newline at end of file From b8a2008992f96697ec433da03856d5f38dde0aaa Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Thu, 27 Oct 2022 23:24:30 +0100 Subject: [PATCH 17/89] remove redundant code, fix permutation placement --- R/randomForest-classification.R | 168 +++++++++----------------------- 1 file changed, 46 insertions(+), 122 deletions(-) diff --git a/R/randomForest-classification.R b/R/randomForest-classification.R index 07525aec..0bd716ff 100644 --- a/R/randomForest-classification.R +++ b/R/randomForest-classification.R @@ -1,3 +1,4 @@ +#' @importFrom randomForest margin classificationPredictions <- function(model){ tibble(sample = seq_along(model$y), @@ -34,116 +35,32 @@ classificationMetrics <- function(model){ .estimate = margin(model) %>% mean()) ) - } classificationImportance <- function(model){ model %>% randomForest::importance() %>% - {bind_cols(tibble(Feature = rownames(.)),as_tibble(.,.name_repair = 'minimal'))} %>% - left_join(fpr_fs(model),by = c('Feature' = 'variable')) %>% - rename(SelectionFrequency = freq,FalsePositiveRate = fpr) + {bind_cols(tibble(feature = rownames(.)),as_tibble(.,.name_repair = 'minimal'))} %>% + left_join(fpr_fs(model),by = c('feature' = 'variable')) %>% + rename(selection_frequency = freq,false_positive_rate = fpr) %>% + gather(metric,value,-feature) } -#' @importFrom randomForest margin -#' @importFrom stats pnorm - -classificationMeasures <- function(predictions,permutations){ - - class_metrics <- metric_set(accuracy,kap) - - meas <- predictions %>% - base::split(.$Response) %>% - map(~{ - d <- . - d %>% - base::split(.$Comparison) %>% - map(~{ - p <- . - p %>% - mutate(obs = factor(obs),pred = factor(pred)) %>% - group_by(Response,Comparison) %>% - class_metrics(obs,estimate = pred) - }) %>% - bind_rows() - }) %>% - bind_rows() %>% - bind_rows( - suppressMessages( - predictions %>% - base::split(.$Response) %>% - map(~{ - d <- . - d %>% - base::split(.$Comparison) %>% - map(~{ - p <- . - - p <- p %>% - mutate(obs = factor(obs),pred = factor(pred)) - if (length(levels(p$obs)) > 2) { - estimate <- levels(p$obs) - } else { - estimate <- levels(p$obs)[1] - } - p %>% - group_by(Response,Comparison) %>% - roc_auc(obs,estimate) - }) %>% - bind_rows() - }) %>% - bind_rows())) %>% - bind_rows(predictions %>% - group_by(Response,Comparison) %>% - summarise(.estimate = mean(margin)) %>% - mutate(.metric = 'margin')) - - if (length(permutations) > 0) { - meas <- meas %>% - left_join( - permutations$measures, - by = c("Response","Comparison", ".metric")) %>% - mutate(Pvalue = pnorm(.estimate,Mean,SD,lower.tail = FALSE)) %>% - select(-Mean,-SD) - } - - return(meas) +collateClassification <- function(models,results){ + suppressMessages( + models %>% + map_dfr( + ~.x %>% + map_dfr(~.x$reps %>% + map_dfr(~.x[[results]], + .id = 'rep'), + .id = 'comparison' + ), + .id = 'response' + ) + ) } -#' @importFrom dplyr rowwise - -# classificationImportance <- function(importances,permutations){ -# imps <- importances %>% -# group_by(Response,Comparison,Feature,Metric) %>% -# summarise(Value = mean(Value)) -# -# if (length(permutations) > 0) { -# lowertail <- list(MeanDecreaseGini = FALSE, -# SelectionFrequency = FALSE, -# FalsePositiveRate = TRUE) -# -# imps <- imps %>% -# left_join( -# permutations$importance, -# by = c("Response","Comparison", "Feature", "Metric")) %>% -# base::split(.$Metric) %>% -# map(~{ -# i <- . -# tail <- lowertail[[i$Metric[1]]] -# i %>% -# rowwise() %>% -# mutate(Pvalue = pnorm(Value,Mean,SD,lower.tail = tail)) %>% -# ungroup() -# }) %>% -# bind_rows() %>% -# group_by(Metric) %>% -# mutate(adjustedPvalue = p.adjust(Pvalue,method = 'bonferroni')) %>% -# select(-Mean,-SD) -# } -# -# return(imps) -# } - #' @importFrom yardstick metric_set accuracy kap roc_auc #' @importFrom dplyr summarise_all group_by_all n #' @importFrom stringr str_split @@ -252,8 +169,6 @@ classification <- function(x, rf <- c(rf,list(strata = pred,sampsize = ss)) } - set.seed(seed) - models <- future_map( 1:reps,~{ performRF( @@ -266,36 +181,45 @@ classification <- function(x, .options = furrr_options(seed = seed)) %>% set_names(1:reps) - return(models) + if (perm > 0) { + permutation_results <- permutations(cda, + inf, + rf, + perm, + type = 'classification') + } else { + permutations_results <- list() + } + + return( + list(reps = models, + permutations = permutation_results) + ) }) %>% set_names(comps) }) %>% set_names(colnames(i)) - if (perm > 0) { - permutation_results <- permutations(x, - cls, - rf, - perm, - type = 'classification') - } else { - permutations_results <- list() - } - res <- new('RandomForest', x, type = 'classification', response = cls, - metrics = collate(models,'metrics'), - predictions = collate(models,'predictions'), - importances = collate(models,'importance'), - proximities = collate(models,'proximities'), - permutations = permutation_results) - - + metrics = collate(models,'metrics',type = 'classification') %>% + group_by(response,comparison,.metric,.estimator) %>% + summarise(.estimate = mean(.estimate), + .groups = 'drop'), + predictions = collate(models,'predictions',type = 'classification'), + importances = collate(models,'importance',type = 'classification') %>% + group_by(response,comparison,feature,metric) %>% + summarise(value = mean(value), + .groups = 'drop'), + proximities = collate(models,'proximities',type = 'classification'), + permutations = collatePermutations(models,type = 'classification')) + + if (isTRUE(returnModels)) { res@models <- collateModels(models) } - + return(res) } From 47d0a867642d53494dd1a29e0106e5e282ee3b75 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Thu, 27 Oct 2022 23:24:42 +0100 Subject: [PATCH 18/89] fix metrics and importance methods --- R/modelling-accessors.R | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/R/modelling-accessors.R b/R/modelling-accessors.R index 6b65b0db..1be1465f 100644 --- a/R/modelling-accessors.R +++ b/R/modelling-accessors.R @@ -145,7 +145,14 @@ setGeneric("metrics", function(x) setMethod('metrics',signature = 'RandomForest', function(x){ - x@metrics + + if (length(x@permutations) > 0){ + metrics <- metricPvals(x) + } else { + metrics <- x@metrics + } + + return(metrics) } ) @@ -258,8 +265,14 @@ setGeneric("importance", function(x) setMethod('importance',signature = 'RandomForest', function(x){ - x@importances %>% - ungroup() + + if (length(x@permutations) > 0){ + importance <- importancePvals(x) + } else { + importance <- x@importances + } + + return(importance) } ) From b82f04eecec5968f5eb6b47d7e25b2d683b96367 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Thu, 27 Oct 2022 23:25:13 +0100 Subject: [PATCH 19/89] fix collate function --- R/randomForest-internals.R | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/R/randomForest-internals.R b/R/randomForest-internals.R index e0f3b91b..5fc94313 100644 --- a/R/randomForest-internals.R +++ b/R/randomForest-internals.R @@ -35,7 +35,8 @@ modelImportance <- function(model,type){ classification = classificationImportance(model), regression = model %>% randomForest::importance() %>% - {bind_cols(tibble(Feature = rownames(.)),as_tibble(.,.name_repair = 'minimal'))}) + {bind_cols(tibble(feature = rownames(.)),as_tibble(.,.name_repair = 'minimal'))} %>% + gather(metric,value,-feature)) } modelProximities <- function(model){ @@ -46,17 +47,11 @@ modelProximities <- function(model){ rename(Sample1 = Sample) } -collate <- function(models,type){ - models %>% - map_dfr( - ~.x %>% - map_dfr(~.x %>% - map_dfr(~.x[[type]], - .id = 'rep'), - .id = 'comparison' - ), - .id = 'response' - ) +collate <- function(models,results,type){ + switch(type, + classification = collateClassification(models,results), + regression = collateRegression(models,results) + ) } #' @importFrom forestControl fpr_fs From 826244a7bbcb199e8cf296113630606a9747e3e7 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Thu, 27 Oct 2022 23:25:27 +0100 Subject: [PATCH 20/89] rehome function imports --- R/randomForest-permute.R | 3 +++ 1 file changed, 3 insertions(+) diff --git a/R/randomForest-permute.R b/R/randomForest-permute.R index 216630da..91336452 100644 --- a/R/randomForest-permute.R +++ b/R/randomForest-permute.R @@ -119,6 +119,9 @@ metricPvals <- function(x){ regression = regressionMetricPvals(x)) } +#' @importFrom stats pnorm +#' @importFrom dplyr rowwise + classificationMetricPvals <- function(x){ left_join(x@metrics, x@permutations$metrics, From f6417999824659783051a1bae31ddc94c3708eae Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Thu, 27 Oct 2022 23:25:37 +0100 Subject: [PATCH 21/89] remove redundant code --- R/randomForest-regression.R | 51 ------------------------------------- 1 file changed, 51 deletions(-) diff --git a/R/randomForest-regression.R b/R/randomForest-regression.R index d13de278..b2251aac 100644 --- a/R/randomForest-regression.R +++ b/R/randomForest-regression.R @@ -14,57 +14,6 @@ regressionMetrics <- function(model){ reg_metrics(obs,estimate = pred) } -# regressionMeasures <- function(predictions,permutations){ - # reg_metrics <- metric_set(rsq,mae,mape,rmse,ccc) -# meas <- predictions %>% -# base::split(.$Response) %>% -# map(~{ -# d <- . -# d %>% -# group_by(Response) %>% -# reg_metrics(obs,estimate = pred) -# }) %>% -# bind_rows() -# -# if (length(permutations) > 0) { -# lowertail <- list(rsq = FALSE, -# mae = TRUE, -# mape = TRUE, -# mape = TRUE, -# rmse = TRUE, -# ccc = FALSE) -# -# meas <- meas %>% -# left_join(permutations$measures, by = c("Response", ".metric")) %>% -# rowwise() %>% -# mutate(Pvalue = pnorm(.estimate, -# Mean, -# SD, -# lower.tail = lowertail[[.metric]])) %>% -# select(-Mean,-SD) -# } -# -# return(meas) -# } - -# regressionImportance <- function(importances,permutations){ -# imps <- importances %>% -# group_by(Response,Feature,Metric) %>% -# summarise(Value = mean(Value)) -# -# if (length(permutations) > 0) { -# imps <- imps %>% -# left_join(permutations$importance, -# by = c("Response", "Feature", "Metric")) %>% -# mutate(Pvalue = pnorm(Value,Mean,SD,lower.tail = FALSE)) %>% -# group_by(Metric) %>% -# mutate(adjustedPvalue = p.adjust(Pvalue,method = 'bonferroni')) %>% -# select(-Mean,-SD) -# } -# -# return(imps) -# } - collateRegression <- function(models,results){ models %>% map_dfr( From f29d6518304b5ef9b7549cf252e37b987965abed Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Thu, 27 Oct 2022 23:41:43 +0100 Subject: [PATCH 22/89] move unsupervised RF code to own file --- DESCRIPTION | 1 + R/randomForest-internals.R | 64 ++--------------------------------- R/randomForest-unsupervised.R | 58 +++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 61 deletions(-) create mode 100644 R/randomForest-unsupervised.R diff --git a/DESCRIPTION b/DESCRIPTION index 1f2da817..c12a574e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -85,6 +85,7 @@ Collate: allClasses.R randomForest-internals.R randomForest-permute.R randomForest-regression.R + randomForest-unsupervised.R rsd.R roc.R show-method.R diff --git a/R/randomForest-internals.R b/R/randomForest-internals.R index 5fc94313..41a03966 100644 --- a/R/randomForest-internals.R +++ b/R/randomForest-internals.R @@ -2,8 +2,10 @@ performRF <- function(x,cls,rf,type,returnModel){ params <- formals(randomForest::randomForest) params$x <- x - params$y <- cls params <- c(params,rf) + + if (!is.null(cls)) params$y <- cls + model <- do.call(randomForest::randomForest,params) model_results <- list(metrics = performanceMetrics(model, @@ -54,66 +56,6 @@ collate <- function(models,results,type){ ) } -#' @importFrom forestControl fpr_fs - -unsupervised <- function(x,rf,reps,returnModels,seed,...){ - - set.seed(seed) - - models <- future_map(1:reps,~{ - params <- formals(randomForest::randomForest) - params$x <- x %>% dat() - params <- c(params,rf) - do.call(randomForest::randomForest,params) - },.options = furrr_options(seed = seed)) %>% - set_names(1:reps) - - importances <- models %>% - future_map_dfr(~{ - m <- . - importance(m) %>% - left_join(fpr_fs(m),by = c('Feature' = 'variable')) %>% - rename(SelectionFrequency = freq,FalsePositiveRate = fpr) - }, - .id = 'Rep', - .options = furrr_options(seed = seed)) %>% - mutate(Rep = as.numeric(Rep)) %>% - gather('Metric','Value',-Rep,-Feature) - - proximities <- models %>% - future_map_dfr(.,~{.$proximity %>% - as_tibble(.name_repair = 'minimal') %>% - mutate(Sample = seq_len(nrow(.))) %>% - gather('Sample2','Proximity',-Sample) %>% - rename(Sample1 = Sample) - }, - .id = 'Rep', - .options = furrr_options(seed = seed)) %>% - mutate(Rep = as.numeric(Rep)) %>% - mutate(Sample2 = as.numeric(Sample2)) - - results <- list( - importances = importances %>% - select(-Rep) %>% - group_by(Feature,Metric) %>% - summarise(Value = mean(Value)) - ) - - res <- new('RandomForest') - res@type <- 'unsupervised' - dat(res) <- dat(x) - sinfo(res) <- sinfo(x) - res@results <- results - res@importances <- importances - res@proximities <- proximities - - if (isTRUE(returnModels)) { - res@models <- models - } - - return(list(res)) -} - supervised <- function(x, cls, rf, diff --git a/R/randomForest-unsupervised.R b/R/randomForest-unsupervised.R new file mode 100644 index 00000000..9141976c --- /dev/null +++ b/R/randomForest-unsupervised.R @@ -0,0 +1,58 @@ + +unsupervised <- function(x,rf,reps,returnModels,seed,...){ + + set.seed(seed) + + models <- future_map(1:reps,~{ + params <- formals(randomForest::randomForest) + params$x <- x %>% dat() + params <- c(params,rf) + do.call(randomForest::randomForest,params) + },.options = furrr_options(seed = seed)) %>% + set_names(1:reps) + + importances <- models %>% + future_map_dfr(~{ + m <- . + importance(m) %>% + left_join(fpr_fs(m),by = c('Feature' = 'variable')) %>% + rename(SelectionFrequency = freq,FalsePositiveRate = fpr) + }, + .id = 'Rep', + .options = furrr_options(seed = seed)) %>% + mutate(Rep = as.numeric(Rep)) %>% + gather('Metric','Value',-Rep,-Feature) + + proximities <- models %>% + future_map_dfr(.,~{.$proximity %>% + as_tibble(.name_repair = 'minimal') %>% + mutate(Sample = seq_len(nrow(.))) %>% + gather('Sample2','Proximity',-Sample) %>% + rename(Sample1 = Sample) + }, + .id = 'Rep', + .options = furrr_options(seed = seed)) %>% + mutate(Rep = as.numeric(Rep)) %>% + mutate(Sample2 = as.numeric(Sample2)) + + results <- list( + importances = importances %>% + select(-Rep) %>% + group_by(Feature,Metric) %>% + summarise(Value = mean(Value)) + ) + + res <- new('RandomForest') + res@type <- 'unsupervised' + dat(res) <- dat(x) + sinfo(res) <- sinfo(x) + res@results <- results + res@importances <- importances + res@proximities <- proximities + + if (isTRUE(returnModels)) { + res@models <- models + } + + return(list(res)) +} \ No newline at end of file From ef44d3b6fadb35a2b8c4803403850799dcdd09f9 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Thu, 27 Oct 2022 23:42:16 +0100 Subject: [PATCH 23/89] remove metaboData library load from random forest test --- tests/testthat/test-randomForest.R | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/testthat/test-randomForest.R b/tests/testthat/test-randomForest.R index 86b79910..df1904aa 100644 --- a/tests/testthat/test-randomForest.R +++ b/tests/testthat/test-randomForest.R @@ -1,11 +1,9 @@ -library(metaboData) -d <- analysisData(abr1$neg,abr1$fact) %>% +d <- analysisData(metaboData::abr1$neg, + metaboData::abr1$fact) %>% keepFeatures(features = features(.)[200:250]) %>% clsAdd('sample_names',paste0(seq_len(nSamples(.)),'_a')) -context('randomForest') - test_that('unsupervised random forest works',{ rf <- randomForest(d,cls = NULL,returnModels = TRUE) From 4506a296a9d9eaf6f5c6a4bf5a484bb1d9ee2e6a Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Thu, 27 Oct 2022 23:42:30 +0100 Subject: [PATCH 24/89] function import --- R/randomForest-classification.R | 2 ++ 1 file changed, 2 insertions(+) diff --git a/R/randomForest-classification.R b/R/randomForest-classification.R index 0bd716ff..9740ac78 100644 --- a/R/randomForest-classification.R +++ b/R/randomForest-classification.R @@ -37,6 +37,8 @@ classificationMetrics <- function(model){ ) } +#' @importFrom forestControl fpr_fs + classificationImportance <- function(model){ model %>% randomForest::importance() %>% From b6a49cef858e6dd3a35b990b234446aca3861223 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Thu, 27 Oct 2022 23:58:28 +0100 Subject: [PATCH 25/89] fix randomForest class prototype --- R/allClasses.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/allClasses.R b/R/allClasses.R index c461096c..95c57f57 100644 --- a/R/allClasses.R +++ b/R/allClasses.R @@ -99,8 +99,8 @@ setClass('RandomForest', models = 'list' ), prototype = list( - type = 'classification', - response = 'class', + type = 'unsupervised', + response = '', metrics = tibble(), predictions = tibble(), permutations = list(), From b08be59fc7b100a39ad847dbf9fa4fe7696487b6 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Thu, 27 Oct 2022 23:58:55 +0100 Subject: [PATCH 26/89] add unsupervised to randomForest internals --- R/randomForest-internals.R | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/R/randomForest-internals.R b/R/randomForest-internals.R index 41a03966..7808defc 100644 --- a/R/randomForest-internals.R +++ b/R/randomForest-internals.R @@ -22,23 +22,23 @@ performRF <- function(x,cls,rf,type,returnModel){ performanceMetrics <- function(model,type){ switch(type, + unsupervised = tibble(), classification = classificationMetrics(model), regression = regressionMetrics(model)) } modelPredictions <- function(model,type){ switch(type, + unsupervised = tibble(), classification = classificationPredictions(model), regression = regressionPredictions(model)) } modelImportance <- function(model,type){ switch(type, + unsupervised = regressionImportance(model), classification = classificationImportance(model), - regression = model %>% - randomForest::importance() %>% - {bind_cols(tibble(feature = rownames(.)),as_tibble(.,.name_repair = 'minimal'))} %>% - gather(metric,value,-feature)) + regression = regressionImportance(model)) } modelProximities <- function(model){ @@ -51,6 +51,7 @@ modelProximities <- function(model){ collate <- function(models,results,type){ switch(type, + unsupervised = collateUnsupervised(models,results), classification = collateClassification(models,results), regression = collateRegression(models,results) ) From 4fb34af1780f55c54871f25a006cff878e83faf5 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Thu, 27 Oct 2022 23:59:32 +0100 Subject: [PATCH 27/89] add regression importance function --- R/randomForest-regression.R | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/R/randomForest-regression.R b/R/randomForest-regression.R index b2251aac..25f6765a 100644 --- a/R/randomForest-regression.R +++ b/R/randomForest-regression.R @@ -14,6 +14,13 @@ regressionMetrics <- function(model){ reg_metrics(obs,estimate = pred) } +regressionImportance <- function(model){ + model %>% + randomForest::importance() %>% + {bind_cols(tibble(feature = rownames(.)),as_tibble(.,.name_repair = 'minimal'))} %>% + gather(metric,value,-feature) +} + collateRegression <- function(models,results){ models %>% map_dfr( From 72281fca5d40d3e9e8bd88ef4140769dee73660f Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Thu, 27 Oct 2022 23:59:52 +0100 Subject: [PATCH 28/89] streamline unsupervised random forest --- R/randomForest-unsupervised.R | 74 +++++++++++++---------------------- 1 file changed, 28 insertions(+), 46 deletions(-) diff --git a/R/randomForest-unsupervised.R b/R/randomForest-unsupervised.R index 9141976c..de627324 100644 --- a/R/randomForest-unsupervised.R +++ b/R/randomForest-unsupervised.R @@ -1,58 +1,40 @@ -unsupervised <- function(x,rf,reps,returnModels,seed,...){ - - set.seed(seed) +collateUnsupervised <- function(models,result){ + models %>% + map_dfr(~.x[[result]], + .id = 'rep') +} + +unsupervised <- function(x, + rf = list(), + reps = 1, + returnModels = FALSE, + seed = 1234, + ...){ models <- future_map(1:reps,~{ - params <- formals(randomForest::randomForest) - params$x <- x %>% dat() - params <- c(params,rf) - do.call(randomForest::randomForest,params) + performRF( + dat(x), + cls = NULL, + rf = rf, + type = 'unsupervised', + returnModel = returnModels + ) },.options = furrr_options(seed = seed)) %>% set_names(1:reps) - importances <- models %>% - future_map_dfr(~{ - m <- . - importance(m) %>% - left_join(fpr_fs(m),by = c('Feature' = 'variable')) %>% - rename(SelectionFrequency = freq,FalsePositiveRate = fpr) - }, - .id = 'Rep', - .options = furrr_options(seed = seed)) %>% - mutate(Rep = as.numeric(Rep)) %>% - gather('Metric','Value',-Rep,-Feature) - - proximities <- models %>% - future_map_dfr(.,~{.$proximity %>% - as_tibble(.name_repair = 'minimal') %>% - mutate(Sample = seq_len(nrow(.))) %>% - gather('Sample2','Proximity',-Sample) %>% - rename(Sample1 = Sample) - }, - .id = 'Rep', - .options = furrr_options(seed = seed)) %>% - mutate(Rep = as.numeric(Rep)) %>% - mutate(Sample2 = as.numeric(Sample2)) - - results <- list( - importances = importances %>% - select(-Rep) %>% - group_by(Feature,Metric) %>% - summarise(Value = mean(Value)) - ) + res <- new('RandomForest', + x, + type = 'unsupervised', + importances = collate(models,'importance',type = 'unsupervised') %>% + group_by(feature,metric) %>% + summarise(value = mean(value)), + proximities = collate(models,'proximities',type = 'unsupervised')) - res <- new('RandomForest') - res@type <- 'unsupervised' - dat(res) <- dat(x) - sinfo(res) <- sinfo(x) - res@results <- results - res@importances <- importances - res@proximities <- proximities if (isTRUE(returnModels)) { - res@models <- models + res@models <- collateModels(models) } - return(list(res)) + return(res) } \ No newline at end of file From 88a167115b4dba62fa1cecb59131f2de9ebf852f Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 00:24:56 +0100 Subject: [PATCH 29/89] fix typo --- R/randomForest-classification.R | 2 +- R/randomForest-regression.R | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/randomForest-classification.R b/R/randomForest-classification.R index 9740ac78..60d5157c 100644 --- a/R/randomForest-classification.R +++ b/R/randomForest-classification.R @@ -190,7 +190,7 @@ classification <- function(x, perm, type = 'classification') } else { - permutations_results <- list() + permutation_results <- list() } return( diff --git a/R/randomForest-regression.R b/R/randomForest-regression.R index 25f6765a..6f8888b0 100644 --- a/R/randomForest-regression.R +++ b/R/randomForest-regression.R @@ -74,7 +74,7 @@ regression <- function(x, perm, type = 'regression') } else { - permutations_results <- list() + permutation_results <- list() } return( From c4a1ee51985e4a34844c7ceb11fd9df5d15c47f4 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 00:25:09 +0100 Subject: [PATCH 30/89] fix file collate --- DESCRIPTION | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index c12a574e..3417683f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -80,12 +80,12 @@ Collate: allClasses.R QC.R reexports.R remove.R - randomForest.R - randomForest-classification.R - randomForest-internals.R randomForest-permute.R + randomForest-classification.R randomForest-regression.R + randomForest-internals.R randomForest-unsupervised.R + randomForest.R rsd.R roc.R show-method.R From a323a5afa3be0b35307bfe8917985c2ab8f2367b Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 00:25:27 +0100 Subject: [PATCH 31/89] fix metrics and importance methods --- R/modelling-accessors.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/modelling-accessors.R b/R/modelling-accessors.R index 1be1465f..5e55c741 100644 --- a/R/modelling-accessors.R +++ b/R/modelling-accessors.R @@ -146,7 +146,7 @@ setGeneric("metrics", function(x) setMethod('metrics',signature = 'RandomForest', function(x){ - if (length(x@permutations) > 0){ + if (nrow(x@permutations$metrics) > 0){ metrics <- metricPvals(x) } else { metrics <- x@metrics @@ -266,7 +266,7 @@ setGeneric("importance", function(x) setMethod('importance',signature = 'RandomForest', function(x){ - if (length(x@permutations) > 0){ + if (nrow(x@permutations$importance) > 0){ importance <- importancePvals(x) } else { importance <- x@importances From 71d6501b77b3a9b9e6982df6a1eb9db45dd70bcf Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 00:32:29 +0100 Subject: [PATCH 32/89] fix select warnings --- R/QC.R | 2 +- R/info.R | 2 +- R/modellingPlots.R | 6 +++--- R/occupancy.R | 4 ++-- R/plotPCA.R | 2 +- R/randomForest-classification.R | 2 +- R/randomForest-permute.R | 2 +- R/randomForest-regression.R | 4 ++-- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/R/QC.R b/R/QC.R index e0889efa..33e1c446 100644 --- a/R/QC.R +++ b/R/QC.R @@ -80,7 +80,7 @@ setMethod('QCimpute',signature = 'AnalysisData', dat(d)[d %>% sinfo() %>% - select(cls) %>% + select(all_of(cls)) %>% deframe() %>% {. == QCidx},] <- QC %>% dat() diff --git a/R/info.R b/R/info.R index 969c792d..bd9577dc 100644 --- a/R/info.R +++ b/R/info.R @@ -206,7 +206,7 @@ setMethod('clsExtract', function(d, cls = 'class'){ d %>% sinfo() %>% - select(cls) %>% + select(all_of(cls)) %>% deframe() }) diff --git a/R/modellingPlots.R b/R/modellingPlots.R index ff743a04..924195c0 100644 --- a/R/modellingPlots.R +++ b/R/modellingPlots.R @@ -398,7 +398,7 @@ setMethod('plotMDS', .x %>% bind_cols(cda %>% sinfo() %>% - select(cls) %>% + select(all_of(cls)) %>% mutate_all(as.character) ) }) %>% @@ -414,7 +414,7 @@ setMethod('plotMDS', comparison <- str_split(d$Comparison[1],'~')[[1]] cda <- removeClasses(x,cls,classes = sinfo(x) %>% - select(cls) %>% + select(all_of(cls)) %>% unlist() %>% unique() %>% .[!(. %in% comparison)]) @@ -434,7 +434,7 @@ setMethod('plotMDS', mds_dimensions <- mds_dimensions %>% bind_cols(x %>% sinfo() %>% - select(cls) %>% + select(all_of(cls)) %>% mutate_all(factor) ) } diff --git a/R/occupancy.R b/R/occupancy.R index 1e6142b2..64914e7e 100644 --- a/R/occupancy.R +++ b/R/occupancy.R @@ -58,7 +58,7 @@ setMethod('occupancyMaximum',signature = 'AnalysisData', unique(fd$Feature)] dat(d) <- d %>% dat() %>% - select(feat) + select(all_of(feat)) return(d) } ) @@ -90,7 +90,7 @@ setMethod('occupancyMinimum',signature = 'AnalysisData', unique(fd$Feature)] dat(d) <- d %>% dat() %>% - select(feat) + select(all_of(feat)) return(d) } ) diff --git a/R/plotPCA.R b/R/plotPCA.R index 3030cf7f..ba191221 100644 --- a/R/plotPCA.R +++ b/R/plotPCA.R @@ -68,7 +68,7 @@ setMethod('plotPCA', pca <- prcomp(dat(analysis),scale. = scale,center = center) info <- sinfo(analysis) %>% - select(cls) %>% + select(all_of(cls)) %>% mutate(!!cls := factor(!!sym(cls))) var <- pca$sdev diff --git a/R/randomForest-classification.R b/R/randomForest-classification.R index 60d5157c..8213a17f 100644 --- a/R/randomForest-classification.R +++ b/R/randomForest-classification.R @@ -112,7 +112,7 @@ classification <- function(x, i <- x %>% sinfo() %>% - select(cls) + select(all_of(cls)) } if (length(unique(deframe(i))) < 2) { diff --git a/R/randomForest-permute.R b/R/randomForest-permute.R index 91336452..6f960210 100644 --- a/R/randomForest-permute.R +++ b/R/randomForest-permute.R @@ -25,7 +25,7 @@ permute <- function(x,cls,rf,type){ permutations <- function(x,cls,rf,n,type){ i <- x %>% sinfo() %>% - select(cls) %>% + select(all_of(cls)) %>% unlist(use.names = FALSE) if (is.character(i) | is.factor(i)) { diff --git a/R/randomForest-regression.R b/R/randomForest-regression.R index 6f8888b0..a0c4cd85 100644 --- a/R/randomForest-regression.R +++ b/R/randomForest-regression.R @@ -46,7 +46,7 @@ regression <- function(x, seed = 1234){ i <- x %>% sinfo() %>% - select(cls) + select(all_of(cls)) models <- i %>% colnames() %>% @@ -54,7 +54,7 @@ regression <- function(x, inf <- . pred <- i %>% - select(inf) %>% + select(all_of(inf)) %>% unlist(use.names = FALSE) models <- future_map(1:reps,~{ From fca181328321b78258181e1c3462b0a15fa01a4e Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 10:47:53 +0100 Subject: [PATCH 33/89] select warning fixes --- R/aggregate.R | 2 +- R/info.R | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/aggregate.R b/R/aggregate.R index b54bdaf6..6bd7e2f1 100644 --- a/R/aggregate.R +++ b/R/aggregate.R @@ -100,7 +100,7 @@ aggregate <- function(d,method,cls){ dat() %>% bind_cols(sample_info) %>% gather('Feature','Intensity',-all_of(cls)) %>% - group_by(across(cls),Feature) %>% + group_by(across(all_of(cls)),Feature) %>% summarise(Intensity = aggregateMethod(Intensity)) %>% ungroup() %>% spread(Feature,Intensity) %>% diff --git a/R/info.R b/R/info.R index bd9577dc..5a60993a 100644 --- a/R/info.R +++ b/R/info.R @@ -246,7 +246,7 @@ setMethod('clsRemove',signature = 'AnalysisData',function(d,cls){ sinfo(d) <- d %>% sinfo() %>% - select(-{{cls}}) + select(-all_of(cls)) return(d) }) From 118c349f4aa85937590184cbd43df21efd3355eb Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 10:48:12 +0100 Subject: [PATCH 34/89] rf model proximity table headers now lowercase --- R/modelling-accessors.R | 22 +++++++++++----------- R/randomForest-internals.R | 6 +++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/R/modelling-accessors.R b/R/modelling-accessors.R index 5e55c741..61bbd1f2 100644 --- a/R/modelling-accessors.R +++ b/R/modelling-accessors.R @@ -328,14 +328,14 @@ setMethod('proximity',signature = 'RandomForest', function(x,idx = NULL){ group_vars <- switch(type(x), - classification = c('Response','Comparison'), - regression = 'Response', + classification = c('response','comparison'), + regression = 'response', unsupervised = NULL) %>% - c(.,'Sample1','Sample2') + c(.,'sample1','sample2') proximities <- x@proximities %>% group_by_at(group_vars) %>% - summarise(Proximity = mean(Proximity), + summarise(proximity = mean(proximity), .groups = 'drop') if (!is.null(idx)){ @@ -355,16 +355,16 @@ setMethod('proximity',signature = 'RandomForest', proximities <- proximities %>% left_join(sample_idx, - by = c('Sample1' = 'row')) %>% + by = c('sample1' = 'row')) %>% rename(idx_1 = idx) %>% left_join(sample_idx, - by = c('Sample2' = 'row')) %>% + by = c('sample2' = 'row')) %>% rename(idx_2 = idx) %>% - select(-Sample1, - -Sample2, - Sample1 = idx_1, - Sample2 = idx_2) %>% - relocate(Proximity,.after = Sample2) + select(-sample1, + -sample2, + sample1 = idx_1, + sample2 = idx_2) %>% + relocate(proximity,.after = sample2) } return(proximities) diff --git a/R/randomForest-internals.R b/R/randomForest-internals.R index 7808defc..0e2f9e3b 100644 --- a/R/randomForest-internals.R +++ b/R/randomForest-internals.R @@ -44,9 +44,9 @@ modelImportance <- function(model,type){ modelProximities <- function(model){ model$proximity %>% as_tibble(.name_repair = 'minimal') %>% - mutate(Sample = seq_len(nrow(.))) %>% - gather('Sample2','Proximity',-Sample) %>% - rename(Sample1 = Sample) + mutate(sample = seq_len(nrow(.))) %>% + gather('sample2','proximity',-sample) %>% + rename(sample1 = sample) } collate <- function(models,results,type){ From 73a809a3aa929b1549aff3a80db12f882aef6830 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 10:48:40 +0100 Subject: [PATCH 35/89] fix mds --- R/mds.R | 18 +++++++++--------- tests/testthat/test-mds.R | 4 +++- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/R/mds.R b/R/mds.R index e9c514cc..aa385426 100644 --- a/R/mds.R +++ b/R/mds.R @@ -29,14 +29,14 @@ setMethod('mds',signature = 'RandomForest', function(x,dimensions = 2,idx = NULL){ group_vars <- switch(type(x), - classification = c('Response','Comparison'), - regression = 'Response', + classification = c('response','comparison'), + regression = 'response', unsupervised = NULL) dissimilarities <- x %>% proximity(idx = idx) %>% - mutate(across(Sample1:Sample2,as.character)) %>% - spread(Sample2,Proximity) %>% + mutate(across(sample1:sample2,as.character)) %>% + spread(sample2,proximity) %>% mutate_if(is.numeric,~ 1 - .x) mds_dimensions <- dissimilarities %>% @@ -44,23 +44,23 @@ setMethod('mds',signature = 'RandomForest', group_map(~ .x %>% select_if(is.numeric) %>% cmdscale(k = dimensions) %>% - set_colnames(str_c('Dimension ', + set_colnames(str_c('dimension ', seq_len(dimensions))) %>% as_tibble() %>% bind_cols(select_if(.x %>% ungroup(), is.character)) %>% - relocate(contains('Dimension'), + relocate(contains('dimension'), .after = last_col()), .keep = TRUE ) %>% bind_rows() %>% - rename(Sample = Sample1) + rename(sample = sample1) if (is.null(idx)){ mds_dimensions <- mds_dimensions %>% - mutate(Sample = as.numeric(Sample)) %>% - arrange(across(c(group_vars,'Sample'))) + mutate(sample = as.numeric(sample)) %>% + arrange(across(c(group_vars,'sample'))) } return(mds_dimensions) diff --git a/tests/testthat/test-mds.R b/tests/testthat/test-mds.R index ce75af31..cdfaf3e3 100644 --- a/tests/testthat/test-mds.R +++ b/tests/testthat/test-mds.R @@ -1,4 +1,6 @@ -d <- analysisData(abr1$neg,abr1$fact) %>% +d <- analysisData( + metaboData::abr1$neg, + metaboData::abr1$fact) %>% keepFeatures(features = features(.)[200:250]) %>% clsAdd('sample_names',paste0(seq_len(nSamples(.)),'_a')) From 1f0068133f1d14f4fc7fd50cc7de81c02cb3976f Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 10:59:04 +0100 Subject: [PATCH 36/89] remove metaboData load from unit tests --- tests/testthat.R | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/testthat.R b/tests/testthat.R index 8a7284d5..307f2dd4 100644 --- a/tests/testthat.R +++ b/tests/testthat.R @@ -1,5 +1,4 @@ library(testthat) library(metabolyseR) -library(metaboData) test_check("metabolyseR") From 9bba708772b49110417a51e723f51dc8eb3ddecf Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 11:06:44 +0100 Subject: [PATCH 37/89] tidy impute methods test --- tests/testthat/test-imputeMethods.R | 51 ++++++++--------------------- tests/testthat/test-mds.R | 1 + 2 files changed, 15 insertions(+), 37 deletions(-) diff --git a/tests/testthat/test-imputeMethods.R b/tests/testthat/test-imputeMethods.R index fabd8eee..ddebbe04 100644 --- a/tests/testthat/test-imputeMethods.R +++ b/tests/testthat/test-imputeMethods.R @@ -1,49 +1,26 @@ -library(metaboData) - -context('imputeMethods') - -plan(future::multisession,workers = 2) test_that('imputeMethods returns methods correctly',{ m <- map_lgl(imputeMethods(),is.function) - expect_false(F %in% m) + expect_true(all(m)) }) test_that('methods work',{ - m <- names(imputeMethods()) - d <- abr1 %>% - { - analysisData(.$neg,.$fact) - } %>% - keepClasses(classes = c(1,6)) %>% - { - keepFeatures(.,features = features(.)[500:600]) - } + d <- analysisData(metaboData::abr1$neg[,500:550], + metaboData::abr1$fact) %>% + keepClasses(classes = c(1,6)) - m <- m %>% + m <- names(imputeMethods()) %>% map(~{ method <- imputeMethods(.x) - res <- method(d) - return(res) + method(d) }) - expect_false(FALSE %in% ('AnalysisData' == map_chr(m,class))) - expect_false(FALSE %in% map_lgl( - m, - ~{identical(class(dat(.x)), c('tbl_df','tbl','data.frame'))})) - expect_false(FALSE %in% map_lgl( - m, - ~{identical(class(sinfo(.x)),c('tbl_df','tbl','data.frame'))})) - expect_false(FALSE %in% map_lgl( - m, - ~{ncol(dat(.x)) == ncol(dat(d))})) - expect_false(FALSE %in% map_lgl( - m, - ~{nrow(dat(.x)) == nrow(dat(d))})) - expect_false(FALSE %in% map_lgl( - m, - ~{ncol(sinfo(.x)) == ncol(sinfo(d))})) - expect_false(FALSE %in% map_lgl( - m, - ~{nrow(sinfo(.x)) == nrow(sinfo(d))})) + expect_true(all(map_chr(m,class) == 'AnalysisData')) + + expect_true(all(map_lgl(m,~{'tbl_df' %in% class(dat(.x))}))) + expect_true(all(map_lgl(m,~{'tbl_df' %in% class(sinfo(.x))}))) + + expect_true(all(map_lgl(m,~{ncol(dat(.x)) == ncol(dat(d))}))) + expect_true(all(map_lgl(m,~{ncol(sinfo(.x)) == ncol(sinfo(d))}))) + expect_true(all(map_lgl(m,~{nrow(sinfo(.x)) == nrow(sinfo(d))}))) }) diff --git a/tests/testthat/test-mds.R b/tests/testthat/test-mds.R index cdfaf3e3..a85486fe 100644 --- a/tests/testthat/test-mds.R +++ b/tests/testthat/test-mds.R @@ -1,3 +1,4 @@ + d <- analysisData( metaboData::abr1$neg, metaboData::abr1$fact) %>% From f2b358f21c1a3a0cc24cafafc55b049e6ee25f57 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 11:07:22 +0100 Subject: [PATCH 38/89] rename impute tests file --- tests/testthat/{test-imputeMethods.R => test-impute.R} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/testthat/{test-imputeMethods.R => test-impute.R} (100%) diff --git a/tests/testthat/test-imputeMethods.R b/tests/testthat/test-impute.R similarity index 100% rename from tests/testthat/test-imputeMethods.R rename to tests/testthat/test-impute.R From a35f35acf730a712ddab641048c979f3c92bbc34 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 11:14:45 +0100 Subject: [PATCH 39/89] run impute tests serially --- tests/testthat/test-impute.R | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/testthat/test-impute.R b/tests/testthat/test-impute.R index ddebbe04..5b290913 100644 --- a/tests/testthat/test-impute.R +++ b/tests/testthat/test-impute.R @@ -9,11 +9,10 @@ test_that('methods work',{ metaboData::abr1$fact) %>% keepClasses(classes = c(1,6)) - m <- names(imputeMethods()) %>% - map(~{ - method <- imputeMethods(.x) - method(d) - }) + m <- list( + imputeAll(d,parallel = 'no'), + imputeClass(d) + ) expect_true(all(map_chr(m,class) == 'AnalysisData')) From 8a76009df5548bb6125c76386e7df658336c0899 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 11:18:41 +0100 Subject: [PATCH 40/89] fix roc --- R/roc.R | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/R/roc.R b/R/roc.R index 016ff219..5a19897f 100644 --- a/R/roc.R +++ b/R/roc.R @@ -30,18 +30,18 @@ setMethod('roc',signature = 'RandomForest', } roc_curves <- x@predictions %>% - group_by(Response,Comparison) %>% + group_by(response,comparison) %>% group_map(~{ .x <- .x %>% mutate(obs = factor(obs)) if (length(levels(.x$obs)) > 2) { .x %>% - group_by(Response,Comparison) %>% + group_by(response,comparison) %>% roc_curve(obs,levels(.x$obs)) } else { .x %>% - group_by(Response,Comparison) %>% + group_by(response,comparison) %>% roc_curve(obs,levels(.x$obs)[1]) } }, .keep = TRUE) %>% From 7420218a7200cc74e67c06adaeb7ae80d1fea5cc Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 11:18:57 +0100 Subject: [PATCH 41/89] remove metaboData library load from metabolyse tests --- tests/testthat/test-metabolyse.R | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/testthat/test-metabolyse.R b/tests/testthat/test-metabolyse.R index 93be51ac..a28803ab 100644 --- a/tests/testthat/test-metabolyse.R +++ b/tests/testthat/test-metabolyse.R @@ -1,6 +1,3 @@ -library(metaboData) - -context('metabolyse') test_that('metabolyse-works', { p <- analysisParameters() @@ -13,12 +10,14 @@ test_that('metabolyse-works', { changeParameter(p,'cls') <- 'day' - cls1 <- abr1$neg[abr1$fact$class %in% c('1'),190:200][1:10,] - cls2 <- abr1$neg[abr1$fact$class %in% c('6'),190:200][1:10,] + cls1 <- metaboData::abr1$neg[metaboData::abr1$fact$class %in% c('1'),190:200][1:10,] + cls2 <- metaboData::abr1$neg[metaboData::abr1$fact$class %in% c('6'),190:200][1:10,] dat <- rbind(cls1,cls2) - inf1 <- abr1$fact[abr1$fact$class %in% c('1'),][1:10,] - inf2 <- abr1$fact[abr1$fact$class %in% c('6'),][1:10,] + + inf1 <- metaboData::abr1$fact[abr1$fact$class %in% c('1'),][1:10,] + inf2 <- metaboData::abr1$fact[abr1$fact$class %in% c('6'),][1:10,] info <- rbind(inf1,inf2) + analysis <- metabolyse(dat,info,p,verbose = FALSE) expect_true(isS4(analysis)) From 34ee442f3ec0b500d5f66a85e092bccea89e36f2 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 11:31:09 +0100 Subject: [PATCH 42/89] fix select warning --- R/mds.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/mds.R b/R/mds.R index aa385426..30c2044e 100644 --- a/R/mds.R +++ b/R/mds.R @@ -60,7 +60,7 @@ setMethod('mds',signature = 'RandomForest', if (is.null(idx)){ mds_dimensions <- mds_dimensions %>% mutate(sample = as.numeric(sample)) %>% - arrange(across(c(group_vars,'sample'))) + arrange(across(all_of(c(group_vars,'sample')))) } return(mds_dimensions) From 0f30002a67d43ad02b16d4df1d6f2aff1a21f9f6 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 11:31:20 +0100 Subject: [PATCH 43/89] remove redundant code --- R/randomForest.R | 4 ---- 1 file changed, 4 deletions(-) diff --git a/R/randomForest.R b/R/randomForest.R index b03f7f6b..ce46e612 100644 --- a/R/randomForest.R +++ b/R/randomForest.R @@ -75,10 +75,6 @@ setMethod('randomForest',signature = 'AnalysisData', seed) } - if (is.null(cls) | length(cls) == 1) { - res <- res[[1]] - } - return(res) } From dc974a49f9cc5b0f66159c371de57d21aa349147 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 11:40:45 +0100 Subject: [PATCH 44/89] fix for randomForest class prototype --- R/allClasses.R | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/R/allClasses.R b/R/allClasses.R index 95c57f57..8cf9e342 100644 --- a/R/allClasses.R +++ b/R/allClasses.R @@ -103,7 +103,10 @@ setClass('RandomForest', response = '', metrics = tibble(), predictions = tibble(), - permutations = list(), + permutations = list( + metrics = tibble(), + importance = tibble() + ), importances = tibble(), proximities = tibble(), models = list() From 8ef766710419ee238eccd7fae4f22b5237372316 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 12:04:23 +0100 Subject: [PATCH 45/89] importanceMetrics fix --- R/modelling-accessors.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/modelling-accessors.R b/R/modelling-accessors.R index 61bbd1f2..88bf13ab 100644 --- a/R/modelling-accessors.R +++ b/R/modelling-accessors.R @@ -249,7 +249,7 @@ setGeneric("importanceMetrics", function(x) setMethod('importanceMetrics',signature = 'RandomForest',function(x){ x %>% importance() %>% - .$Metric %>% + .$metric %>% unique() %>% sort() }) From 533c38e25468afb7da000f2e835405f9dd92c0db Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 12:04:53 +0100 Subject: [PATCH 46/89] modelling plots fixes --- DESCRIPTION | 2 +- NAMESPACE | 1 + R/modellingPlots.R | 69 ++++++++++++++++------------ R/randomForest-internals.R | 2 +- man/plotImportance.Rd | 2 +- tests/testthat/test-modellingPlots.R | 13 +++--- 6 files changed, 50 insertions(+), 39 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 3417683f..98e25a5c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -38,7 +38,7 @@ Imports: Hmisc, License: GPL (>= 3) Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.2.0 +RoxygenNote: 7.2.1 Suggests: knitr, rmarkdown, readr, diff --git a/NAMESPACE b/NAMESPACE index e981d482..f3d24139 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -246,6 +246,7 @@ importFrom(stringr,str_replace_all) importFrom(stringr,str_split) importFrom(stringr,str_split_fixed) importFrom(stringr,str_sub) +importFrom(stringr,str_to_title) importFrom(tibble,as_tibble) importFrom(tibble,deframe) importFrom(tibble,rowid_to_column) diff --git a/R/modellingPlots.R b/R/modellingPlots.R index 924195c0..9f173750 100644 --- a/R/modellingPlots.R +++ b/R/modellingPlots.R @@ -103,12 +103,14 @@ setMethod('plotImportance',signature = 'Univariate', ) #' @rdname plotImportance +#' @importFrom stringr str_to_title setMethod('plotImportance',signature = 'RandomForest', - function(x,metric = 'FalsePositiveRate',rank = TRUE){ + function(x,metric = 'false_positive_rate',rank = TRUE){ typ <- type(x) metrics <- importanceMetrics(x) + current_metric <- metric if (!(metric %in% metrics)) { @@ -121,28 +123,28 @@ setMethod('plotImportance',signature = 'RandomForest', } res <- importance(x) %>% - filter(Metric == metric) + filter(metric == current_metric) if (typ == 'classification') { pl <- res %>% - base::split(.$Comparison) %>% + base::split(.$comparison) %>% map(~{ if (isTRUE(rank)) { .x <- .x %>% - arrange(Value) + arrange(value) - rank <- .x$Feature + rank <- .x$feature .x <- .x %>% - mutate(Feature = factor(Feature,levels = rank)) + mutate(feature = factor(feature,levels = rank)) } .x <- .x %>% - spread(Metric,Value) + spread(metric,value) - comparison <- .x$Comparison[1] + comparison <- .x$comparison[1] - pl <- ggplot(.x,aes(x = Feature,y = !!sym(metric))) + + pl <- ggplot(.x,aes(x = feature,y = !!sym(metric))) + geom_point(shape = 21,alpha = 0.5,fill = ptol_pal()(1)) + theme_bw() + theme(axis.ticks.x = element_blank(), @@ -154,11 +156,17 @@ setMethod('plotImportance',signature = 'RandomForest', plot.title = element_text(face = 'bold', hjust = 0.5), plot.caption = element_text(hjust = -1)) + - labs(title = comparison) + labs(title = comparison, + x = 'Feature', + y = str_replace_all(metric,'_',' ') %>% + str_to_title()) if (typ != 'unsupervised') { pl <- pl + - labs(title = res$Response[1]) + labs(title = res$response[1], + x = 'Feature', + y = str_replace_all(metric,'_',' ') %>% + str_to_title()) } }) %>% @@ -169,18 +177,18 @@ setMethod('plotImportance',signature = 'RandomForest', d <- . if (isTRUE(rank)) { d <- d %>% - arrange(Value) + arrange(value) - rank <- d$Feature + rank <- d$feature d <- d %>% - mutate(Feature = factor(Feature,levels = rank)) + mutate(feature = factor(feature,levels = rank)) } d } %>% - spread(Metric,Value) %>% + spread(metric,value) %>% { - p <- ggplot(.,aes(x = Feature,y = !!sym(metric))) + + p <- ggplot(.,aes(x = feature,y = !!sym(metric))) + geom_point(shape = 21,alpha = 0.5,fill = ptol_pal()(1)) + theme_bw() + theme(axis.ticks.x = element_blank(), @@ -195,7 +203,10 @@ setMethod('plotImportance',signature = 'RandomForest', if (typ != 'unsupervised') { p <- p + - labs(title = res$Response[1]) + labs(title = res$response[1], + x = 'Feature', + y = str_replace_all(metric,'_',' ') %>% + str_to_title()) } p } @@ -211,7 +222,7 @@ setMethod('plotImportance',signature = 'RandomForest', setMethod('plotImportance', signature = 'list', - function(x,metric = 'FalsePositiveRate'){ + function(x,metric = 'false_positive_rate'){ object_classes <- x %>% map_chr(class) @@ -389,9 +400,9 @@ setMethod('plotMDS', if (type(x) == 'classification') { if (!is.null(cls)) { mds_dimensions <- mds_dimensions %>% - base::split(.$Comparison) %>% + base::split(.$comparison) %>% map(~{ - comparison <- str_split(.x$Comparison[1],'~')[[1]] + comparison <- str_split(.x$comparison[1],'~')[[1]] cda <- keepClasses(x,response(x),comparison) @@ -408,10 +419,10 @@ setMethod('plotMDS', if (!is.null(label)) { mds_dimensions <- mds_dimensions %>% - base::split(.$Comparison) %>% + base::split(.$comparison) %>% map(~{ d <- . - comparison <- str_split(d$Comparison[1],'~')[[1]] + comparison <- str_split(d$comparison[1],'~')[[1]] cda <- removeClasses(x,cls,classes = sinfo(x) %>% select(all_of(cls)) %>% @@ -456,8 +467,8 @@ setMethod('plotMDS', pl <- scatterPlot( mds_dimensions, cls, - 'Dimension 1', - 'Dimension 2', + 'dimension 1', + 'dimension 2', ellipses, shape, label, @@ -470,7 +481,7 @@ setMethod('plotMDS', if (x@type == 'classification') { pl <- pl + - facet_wrap(~Comparison) + facet_wrap(~comparison) } return(pl) @@ -547,7 +558,7 @@ setMethod('plotROC',signature = 'RandomForest', preds <- roc(x) - meas <- x@results$measures %>% + meas <- x@metrics %>% filter(.metric == 'roc_auc') %>% mutate(x = 0.8, y = 0, @@ -567,11 +578,11 @@ setMethod('plotROC',signature = 'RandomForest', colour = Class)) + geom_text(data = meas,aes(x = x,y = y,label = label),size = 3) + theme_bw() + - facet_wrap(~Comparison) + + facet_wrap(~comparison) + coord_fixed() + guides( colour = guide_legend( - title = x@results$measures$Response[1])) + + title = x@metrics$response[1])) + labs(title = title) if ((preds$Class %>% unique() %>% length()) <= 12) { @@ -594,7 +605,7 @@ setMethod('plotROC',signature = 'RandomForest', data = meas, aes(x = x,y = y,label = label),size = 3) + theme_bw() + - facet_wrap(~Comparison) + + facet_wrap(~comparison) + coord_fixed() + guides(colour = guide_legend(title = 'Class')) + labs(title = title) diff --git a/R/randomForest-internals.R b/R/randomForest-internals.R index 0e2f9e3b..2a7fe62f 100644 --- a/R/randomForest-internals.R +++ b/R/randomForest-internals.R @@ -36,7 +36,7 @@ modelPredictions <- function(model,type){ modelImportance <- function(model,type){ switch(type, - unsupervised = regressionImportance(model), + unsupervised = classificationImportance(model), classification = classificationImportance(model), regression = regressionImportance(model)) } diff --git a/man/plotImportance.Rd b/man/plotImportance.Rd index cb5b5219..517cf0cd 100644 --- a/man/plotImportance.Rd +++ b/man/plotImportance.Rd @@ -11,7 +11,7 @@ plotImportance(x, ...) \S4method{plotImportance}{Univariate}(x, response = "class", rank = TRUE, threshold = 0.05) -\S4method{plotImportance}{RandomForest}(x, metric = "FalsePositiveRate", rank = TRUE) +\S4method{plotImportance}{RandomForest}(x, metric = "false_positive_rate", rank = TRUE) \S4method{plotImportance}{list}(x, metric = "FalsePositiveRate") } diff --git a/tests/testthat/test-modellingPlots.R b/tests/testthat/test-modellingPlots.R index 139e9474..7b1e68ee 100644 --- a/tests/testthat/test-modellingPlots.R +++ b/tests/testthat/test-modellingPlots.R @@ -1,7 +1,6 @@ -context('modellingPlots') - -d <- analysisData(abr1$neg,abr1$fact) %>% +d <- analysisData(metaboData::abr1$neg, + metaboData::abr1$fact) %>% keepFeatures(features = features(.)[seq_len(200)]) %>% keepClasses(cls = 'day',classes = c('H','1','2')) %>% occupancyMaximum(cls = 'day') %>% @@ -10,8 +9,8 @@ d <- analysisData(abr1$neg,abr1$fact) %>% ttest_res <- d %>% ttest(cls = 'day') -unsupervised_rf_res <- d %>% - randomForest(cls = NULL) +unsupervised_rf_res <- randomForest(d, + cls = NULL) suppressWarnings( classification_rf_res <- d %>% @@ -46,7 +45,7 @@ test_that('plotImportance works for random forest classification',{ test_that('plotImportance works for random forest regression',{ pl <- plotImportance(regression_rf_res,metric = '%IncMSE') - expect_identical(class(pl),c('gg','ggplot')) + expect_identical(class(pl),'list') }) test_that('plotImportance for Univariate class throws an error when the incorrect response is specified',{ @@ -78,7 +77,7 @@ test_that('plotMetrics works for random forest regression',{ pl <- regression_rf_res %>% plotMetrics() - expect_identical(class(pl),c('gg','ggplot')) + expect_type(pl,'list') }) test_that('an error is thrown from plotMetrics for unsupervised random forest',{ From 187108494799f569df46bd679b42901f12c56560 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 12:05:02 +0100 Subject: [PATCH 47/89] update documentation --- man/tune.Rd | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/man/tune.Rd b/man/tune.Rd index ca20d62e..62ec983b 100644 --- a/man/tune.Rd +++ b/man/tune.Rd @@ -8,8 +8,8 @@ tune( x, cls = "class", - mtry_range = floor(seq(mtry(x, cls = cls) - mtry(x, cls = cls)/2, mtry(x, cls = cls) - + mtry(x, cls = cls)/2, length.out = 4)), + mtry_range = floor(seq(mtry(x, cls = cls) - mtry(x, cls = cls)/2, mtry(x, cls = cls) + + mtry(x, cls = cls)/2, length.out = 4)), ntree_range = 1000, seed = 1234 ) @@ -17,8 +17,8 @@ tune( \S4method{tune}{AnalysisData}( x, cls = "class", - mtry_range = floor(seq(mtry(x, cls = cls) - mtry(x, cls = cls)/2, mtry(x, cls = cls) - + mtry(x, cls = cls)/2, length.out = 4)), + mtry_range = floor(seq(mtry(x, cls = cls) - mtry(x, cls = cls)/2, mtry(x, cls = cls) + + mtry(x, cls = cls)/2, length.out = 4)), ntree_range = 1000, seed = 1234 ) From 13e80d62a50988a862ffb249dfe0aa24e8d4e489 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 12:40:40 +0100 Subject: [PATCH 48/89] fix univariate results column headers --- R/univariate.R | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/R/univariate.R b/R/univariate.R index 85a2ecd9..feefc1c9 100644 --- a/R/univariate.R +++ b/R/univariate.R @@ -116,9 +116,9 @@ setMethod('anova',signature = 'AnalysisData', mutate(adjusted.p.value = p.adjust(p.value, method = pAdjust)) }) %>% - bind_rows(.id = 'Comparison') + bind_rows(.id = 'comparison') }) %>% - bind_rows(.id = 'Response') %>% + bind_rows(.id = 'response') %>% filter(term == 'response') res <- new('Univariate') @@ -227,9 +227,9 @@ setMethod('ttest',signature = 'AnalysisData', mutate(adjusted.p.value = p.adjust(p.value, method = pAdjust)) }) %>% - bind_rows(.id = 'Comparison') + bind_rows(.id = 'comparison') }) %>% - bind_rows(.id = 'Response') + bind_rows(.id = 'response') res <- new('Univariate') res@type <- 't-test' @@ -318,7 +318,7 @@ setMethod('linearRegression',signature = 'AnalysisData', mutate(adjusted.p.value = p.adjust(p.value, method = pAdjust)) }) %>% - bind_rows(.id = 'Response') + bind_rows(.id = 'response') res <- new('Univariate') res@type <- 'linear regression' From d5795561adb7346fc72a805dc7303a263a69a70d Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 12:41:47 +0100 Subject: [PATCH 49/89] rename modelling plots file --- DESCRIPTION | 2 +- R/{modellingPlots.R => modelling-plots.R} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename R/{modellingPlots.R => modelling-plots.R} (100%) diff --git a/DESCRIPTION b/DESCRIPTION index 98e25a5c..d167a355 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -61,7 +61,7 @@ Collate: allClasses.R metabolyse.R metabolyseR.R modelling.R - modellingPlots.R + modelling-plots.R nlda.R occupancy.R parameters.R diff --git a/R/modellingPlots.R b/R/modelling-plots.R similarity index 100% rename from R/modellingPlots.R rename to R/modelling-plots.R From 1bfe0894aee66cd7122c0e8a99cf01fd6b4197cd Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 12:44:56 +0100 Subject: [PATCH 50/89] rename modelling plots test file --- tests/testthat/{test-modellingPlots.R => test-modelling-plots.R} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/testthat/{test-modellingPlots.R => test-modelling-plots.R} (100%) diff --git a/tests/testthat/test-modellingPlots.R b/tests/testthat/test-modelling-plots.R similarity index 100% rename from tests/testthat/test-modellingPlots.R rename to tests/testthat/test-modelling-plots.R From 58d7172d048626f2c7f458d38e1858ddee3d8622 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 12:49:18 +0100 Subject: [PATCH 51/89] fix modelling plots for univariate class --- R/modelling-plots.R | 21 ++++++++++++--------- R/show-method.R | 4 ++-- R/univariate.R | 8 ++++---- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/R/modelling-plots.R b/R/modelling-plots.R index 9f173750..de306455 100644 --- a/R/modelling-plots.R +++ b/R/modelling-plots.R @@ -29,12 +29,14 @@ setGeneric("plotImportance", function(x,...) setMethod('plotImportance',signature = 'Univariate', function(x, response = 'class',rank = TRUE,threshold = 0.05){ + current_response <- response + res <- importance(x) - available_responses <- res$Response %>% + available_responses <- res$response %>% unique() - if (!(response %in% unique(res$Response))) { + if (!(response %in% unique(res$response))) { ar <- available_responses %>% str_c('"',.,'"') %>% str_c(collapse = ', ') @@ -53,25 +55,25 @@ setMethod('plotImportance',signature = 'Univariate', } res <- res %>% - filter(Response == response) %>% + filter(response == current_response) %>% mutate(`-log10(p)` = -log10(adjusted.p.value)) pl <- res %>% - base::split(.$Comparison) %>% + base::split(.$comparison) %>% map(~{ if (isTRUE(rank)) { .x <- .x %>% arrange(`-log10(p)`) - rank <- .x$Feature + rank <- .x$feature .x <- .x %>% - mutate(Feature = factor(Feature,levels = rank)) + mutate(feature = factor(feature,levels = rank)) } - comparison <- .x$Comparison[1] + comparison <- .x$comparison[1] - ggplot(.x,aes(x = Feature,y = `-log10(p)`)) + + ggplot(.x,aes(x = feature,y = `-log10(p)`)) + geom_hline( yintercept = -log10(threshold), linetype = 2, @@ -86,7 +88,8 @@ setMethod('plotImportance',signature = 'Univariate', axis.title = element_text(face = 'bold'), plot.title = element_text(face = 'bold', hjust = 0.5)) + - labs(title = comparison) + labs(title = comparison, + x = 'Feature') }) %>% wrap_plots() + diff --git a/R/show-method.R b/R/show-method.R index d38dff0c..1086e071 100644 --- a/R/show-method.R +++ b/R/show-method.R @@ -182,12 +182,12 @@ setMethod('show',signature = 'Univariate', cat('Samples:\t',nSamples(object),'\n') cat('Features:\t',nFeatures(object),'\n') cat('Responses:\t',importance(object) %>% - .$Response %>% + .$response %>% unique() %>% str_c(collapse = ', '),'\n') if (object@type != 'linear regression') { cat('# comparisons:\t',importance(object) %>% - .$Comparison %>% + .$comparison %>% unique() %>% length(),'\n') diff --git a/R/univariate.R b/R/univariate.R index feefc1c9..4c6534eb 100644 --- a/R/univariate.R +++ b/R/univariate.R @@ -12,7 +12,7 @@ #' d <- analysisData(abr1$neg[,200:300],abr1$fact) #' #' ## Perform ANOVA -#' anova_analysis <- anova(d,cls = 'day') +#' anova_analysis <- anova(d,cls = 'ay') #' #' ## Extract significant features #' explanatoryFeatures(anova_analysis) @@ -112,7 +112,7 @@ setMethod('anova',signature = 'AnalysisData', map(~{ map(.,~{ map(.,tidy) %>% - bind_rows(.id = 'Feature') %>% + bind_rows(.id = 'feature') %>% mutate(adjusted.p.value = p.adjust(p.value, method = pAdjust)) }) %>% @@ -223,7 +223,7 @@ setMethod('ttest',signature = 'AnalysisData', map(~{ map(.,~{ map(.,glance) %>% - bind_rows(.id = 'Feature') %>% + bind_rows(.id = 'feature') %>% mutate(adjusted.p.value = p.adjust(p.value, method = pAdjust)) }) %>% @@ -314,7 +314,7 @@ setMethod('linearRegression',signature = 'AnalysisData', map(.,~{ glance(.) }) %>% - bind_rows(.id = 'Feature') %>% + bind_rows(.id = 'feature') %>% mutate(adjusted.p.value = p.adjust(p.value, method = pAdjust)) }) %>% From 072a7b52d5932ebf48ac78f90d0d17ffe955fe67 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 12:52:51 +0100 Subject: [PATCH 52/89] fix random forest regression permutation testing --- R/randomForest-regression.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/randomForest-regression.R b/R/randomForest-regression.R index a0c4cd85..26cd1d1c 100644 --- a/R/randomForest-regression.R +++ b/R/randomForest-regression.R @@ -68,7 +68,7 @@ regression <- function(x, set_names(1:reps) if (perm > 0) { - permutation_results <- permutations(cda, + permutation_results <- permutations(x, inf, rf, perm, From 2409b3542e5344c963077b172dd557860cd9822d Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 12:59:01 +0100 Subject: [PATCH 53/89] added type and response methods for Univariate class --- R/modelling-accessors.R | 14 +++++++++++++- man/modelling-accessors.Rd | 8 +++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/R/modelling-accessors.R b/R/modelling-accessors.R index 88bf13ab..81963fa9 100644 --- a/R/modelling-accessors.R +++ b/R/modelling-accessors.R @@ -121,6 +121,12 @@ setMethod('type',signature = 'RandomForest',function(x){ x@type }) +#' @rdname modelling-accessors + +setMethod('type',signature = 'Univariate',function(x){ + x@type +}) + #' @rdname modelling-accessors #' @export @@ -134,6 +140,12 @@ setMethod('response',signature = 'RandomForest',function(x){ x@response }) +#' @rdname modelling-accessors + +setMethod('response',signature = 'Univariate',function(x){ + unique(x@results$response) +}) + #' @rdname modelling-accessors #' @export @@ -427,7 +439,7 @@ setMethod('explanatoryFeatures',signature = 'Univariate', #' @rdname modelling-accessors setMethod('explanatoryFeatures',signature = 'RandomForest', - function(x,metric = 'FalsePositiveRate', threshold = 0.05){ + function(x,metric = 'false_positive_rate', threshold = 0.05){ typ <- type(x) diff --git a/man/modelling-accessors.Rd b/man/modelling-accessors.Rd index 4d317395..f620c339 100644 --- a/man/modelling-accessors.Rd +++ b/man/modelling-accessors.Rd @@ -7,8 +7,10 @@ \alias{mtry,AnalysisData-method} \alias{type} \alias{type,RandomForest-method} +\alias{type,Univariate-method} \alias{response} \alias{response,RandomForest-method} +\alias{response,Univariate-method} \alias{metrics} \alias{metrics,RandomForest-method} \alias{metrics,list-method} @@ -46,10 +48,14 @@ type(x) \S4method{type}{RandomForest}(x) +\S4method{type}{Univariate}(x) + response(x) \S4method{response}{RandomForest}(x) +\S4method{response}{Univariate}(x) + metrics(x) \S4method{metrics}{RandomForest}(x) @@ -90,7 +96,7 @@ explanatoryFeatures(x, ...) \S4method{explanatoryFeatures}{Univariate}(x, threshold = 0.05) -\S4method{explanatoryFeatures}{RandomForest}(x, metric = "FalsePositiveRate", threshold = 0.05) +\S4method{explanatoryFeatures}{RandomForest}(x, metric = "false_positive_rate", threshold = 0.05) \S4method{explanatoryFeatures}{list}(x, ...) From c374f2f7df8cb8cf7e9b97cf9e7e595d39e52220 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 13:10:59 +0100 Subject: [PATCH 54/89] ensure random forest returns a randomForest object instead of a list if only a single response used --- R/randomForest.R | 4 ++++ tests/testthat/test-modelling-plots.R | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/R/randomForest.R b/R/randomForest.R index ce46e612..60e0bc22 100644 --- a/R/randomForest.R +++ b/R/randomForest.R @@ -75,6 +75,10 @@ setMethod('randomForest',signature = 'AnalysisData', seed) } + if (is.list(res) & {length(res) == 1}){ + res <- res[[1]] + } + return(res) } diff --git a/tests/testthat/test-modelling-plots.R b/tests/testthat/test-modelling-plots.R index 7b1e68ee..37d18fec 100644 --- a/tests/testthat/test-modelling-plots.R +++ b/tests/testthat/test-modelling-plots.R @@ -45,7 +45,7 @@ test_that('plotImportance works for random forest classification',{ test_that('plotImportance works for random forest regression',{ pl <- plotImportance(regression_rf_res,metric = '%IncMSE') - expect_identical(class(pl),'list') + expect_s3_class(pl,'ggplot') }) test_that('plotImportance for Univariate class throws an error when the incorrect response is specified',{ @@ -118,3 +118,4 @@ test_that('plotROC throws an error when non RandomForest object included in list d <- c(classification_rf_res,list('wrong')) expect_error(plotROC(d)) }) + From eda331f242b8724d19dfb10ddaf254eb27f3ae16 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 13:12:34 +0100 Subject: [PATCH 55/89] fix explanatory heat map plots --- NAMESPACE | 1 + R/modelling.R | 20 ++++++----- R/plotExplanatoryHeatmap.R | 35 +++++++++++--------- man/plotExplanatoryHeatmap.Rd | 2 +- tests/testthat/test-plotExplanatoryHeatmap.R | 11 +++--- 5 files changed, 37 insertions(+), 32 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index f3d24139..6b3a4e42 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -224,6 +224,7 @@ importFrom(purrr,map_lgl) importFrom(purrr,walk) importFrom(randomForest,margin) importFrom(rlang,":=") +importFrom(rlang,squash) importFrom(rlang,sym) importFrom(stats,cmdscale) importFrom(stats,cov) diff --git a/R/modelling.R b/R/modelling.R index 3098716e..f775c58a 100644 --- a/R/modelling.R +++ b/R/modelling.R @@ -96,16 +96,16 @@ explanatoryFeaturesClassification <- function(x,metric,threshold){ } explan <- imp %>% - filter(Metric == metric) + filter(metric == current_metric) - if (metric == 'FalsePositiveRate') { + if (metric == 'false_positive_rate') { explan <- explan %>% - filter(Value < threshold) %>% - arrange(Value) + filter(value < threshold) %>% + arrange(value) } else { explan <- explan %>% - filter(Value > threshold) %>% - arrange(desc(Value)) + filter(value > threshold) %>% + arrange(desc(value)) } return(explan) @@ -113,6 +113,8 @@ explanatoryFeaturesClassification <- function(x,metric,threshold){ explanatoryFeaturesRegression <- function(x,metric,threshold){ + current_metric <- metric + imp <- x %>% importance() @@ -129,9 +131,9 @@ explanatoryFeaturesRegression <- function(x,metric,threshold){ } explan <- imp %>% - filter(Metric == metric) %>% - filter(Value > threshold) %>% - arrange(desc(Value)) + filter(metric == current_metric) %>% + filter(value > threshold) %>% + arrange(desc(value)) return(explan) } diff --git a/R/plotExplanatoryHeatmap.R b/R/plotExplanatoryHeatmap.R index 0f7da093..72f686f1 100644 --- a/R/plotExplanatoryHeatmap.R +++ b/R/plotExplanatoryHeatmap.R @@ -12,16 +12,16 @@ heatmapClasses <- function(pl, featureLimit){ pl %>% map(~{ - r <- . - pred <- r$Response[1] + r <- .x + pred <- r$response[1] - classes <- r$Comparison %>% + classes <- r$comparison %>% unique() %>% str_split('~') %>% unlist() %>% unique() - feat <- r$Feature %>% + feat <- r$feature %>% unique() if (length(feat) > featureLimit){ @@ -145,9 +145,9 @@ heatmapRegression <- function(pl, pl %>% map(~{ - response <- .x$Response[1] + response <- .x$response[1] - feat <- .x$Feature %>% + feat <- .x$feature %>% unique() if (length(feat) > featureLimit){ @@ -313,7 +313,7 @@ setMethod('plotExplanatoryHeatmap', } pl <- res %>% - base::split(.$Response) + base::split(.$response) if (x@type == 't-test' | x@type == 'ANOVA') { pl <- heatmapClasses( @@ -341,7 +341,7 @@ setMethod('plotExplanatoryHeatmap', featureLimit = featureLimit) } - feat <- res$Feature %>% + feat <- res$feature %>% unique() caption <- str_c( @@ -368,7 +368,7 @@ setMethod('plotExplanatoryHeatmap', setMethod('plotExplanatoryHeatmap', signature = 'RandomForest', function(x, - metric = 'FalsePositiveRate', + metric = 'false_positive_rate', threshold = 0.05, title = '', distanceMeasure = "euclidean", @@ -391,7 +391,7 @@ setMethod('plotExplanatoryHeatmap', } pl <- explan %>% - base::split(.$Response) + base::split(.$response) if (x@type == 'classification') { pl <- heatmapClasses( @@ -419,7 +419,7 @@ setMethod('plotExplanatoryHeatmap', featureLimit = featureLimit) } - feat <- explan$Feature %>% + feat <- explan$feature %>% unique() if (metric == 'FalsePositiveRate') { @@ -448,6 +448,7 @@ setMethod('plotExplanatoryHeatmap', ) #' @rdname plotExplanatoryHeatmap +#' @importFrom rlang squash setMethod('plotExplanatoryHeatmap', signature = 'list', @@ -457,6 +458,9 @@ setMethod('plotExplanatoryHeatmap', clusterMethod = 'ward.D2', featureNames = TRUE, featureLimit = Inf){ + + suppressWarnings(x <- squash(x)) + object_classes <- x %>% map_chr(class) @@ -467,13 +471,12 @@ setMethod('plotExplanatoryHeatmap', 'should be of class RandomForest or Univariate'), call. = FALSE) } - - x %>% - names() %>% + + x %>% map(~{plotExplanatoryHeatmap( - x[[.x]], + .x, threshold = threshold, - title = .x, + title = response(.x), distanceMeasure = distanceMeasure, clusterMethod = clusterMethod, featureNames = featureNames, diff --git a/man/plotExplanatoryHeatmap.Rd b/man/plotExplanatoryHeatmap.Rd index 1d687024..0ed155f3 100644 --- a/man/plotExplanatoryHeatmap.Rd +++ b/man/plotExplanatoryHeatmap.Rd @@ -23,7 +23,7 @@ plotExplanatoryHeatmap(x, ...) \S4method{plotExplanatoryHeatmap}{RandomForest}( x, - metric = "FalsePositiveRate", + metric = "false_positive_rate", threshold = 0.05, title = "", distanceMeasure = "euclidean", diff --git a/tests/testthat/test-plotExplanatoryHeatmap.R b/tests/testthat/test-plotExplanatoryHeatmap.R index 58592b27..07b23def 100644 --- a/tests/testthat/test-plotExplanatoryHeatmap.R +++ b/tests/testthat/test-plotExplanatoryHeatmap.R @@ -1,7 +1,3 @@ -library(metaboData) - -context('plotExplanatoryHeatmap') - test_that('plotExplanatoryHeatmap returns a plot for random forest classification Analysis',{ p <- analysisParameters(elements = c('pre-treatment','modelling')) @@ -18,7 +14,10 @@ test_that('plotExplanatoryHeatmap returns a plot for random forest classificatio changeParameter(p,'cls') <- 'day' - d <- metabolyse(abr1$neg[,200:300],abr1$fact,p,verbose = TRUE) + d <- metabolyse(metaboData::abr1$neg[,200:300], + metaboData::abr1$fact, + p, + verbose = TRUE) pl_feat <- plotExplanatoryHeatmap(d,threshold = 0.5) pl_no_feat <- plotExplanatoryHeatmap(d,threshold = 0.5,featureNames = FALSE) @@ -59,7 +58,7 @@ test_that('plotExplanatoryHeatmap works for linear regression',{ }) test_that('plotExplanatoryHeatmap method for lists throws an error when non modelling classes supplied',{ - expect_error(list(wrong = list()) %>% + expect_error(list(wrong = list(wrong = 1)) %>% plotExplanatoryHeatmap()) }) From 060fb7e31acf9ca831541aae2879703031b0b800 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 13:14:31 +0100 Subject: [PATCH 56/89] fixed supervised RF plots --- R/plotSupervisedRF.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/plotSupervisedRF.R b/R/plotSupervisedRF.R index 9d31b357..a18a1fc2 100644 --- a/R/plotSupervisedRF.R +++ b/R/plotSupervisedRF.R @@ -75,7 +75,7 @@ setMethod('plotSupervisedRF', labelSize = labelSize) + labs( caption = str_c('Margin: ', - rf@results$measures$.estimate[4] %>% + rf@metrics$.estimate[4] %>% round(3))) if (isTRUE(ROC) & rf@type == 'classification') { From f23b63813cad96bc47b7e895d1e60050c2fcdda6 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 13:38:32 +0100 Subject: [PATCH 57/89] fixed predict methods --- R/predict.R | 20 +++++++++----------- R/randomForest-classification.R | 14 +++++++++++++- R/randomForest-internals.R | 7 +++++++ R/randomForest-regression.R | 12 ++++++++++-- R/randomForest-unsupervised.R | 15 ++++++++++++--- 5 files changed, 51 insertions(+), 17 deletions(-) diff --git a/R/predict.R b/R/predict.R index 0e55c097..6b6f36ed 100644 --- a/R/predict.R +++ b/R/predict.R @@ -83,27 +83,25 @@ setMethod('predict',signature = c('RandomForest','AnalysisData'), test_data <- dat(new_data) model_object_depth <- switch(type(model), - classification = 4, - regression = 3) + classification = 3, + regression = 2) model_predictions <- model@models %>% map_depth(.depth = model_object_depth, .f = ~ .x %>% { tibble( - Sample = sample_idx, - Prediction = stats::predict( + sample = sample_idx, + prediction = stats::predict( object = .x, newdata = test_data, type = type, ...)) - }) %>% - map_depth(.depth = model_object_depth - 2, - .f = ~ .x$models) + }) - column_headers <- c('Response', - 'Comparison', - 'Rep') + column_headers <- c('response', + 'comparison', + 'rep') type_column_headers <- switch( type(model), classification = column_headers, @@ -117,7 +115,7 @@ setMethod('predict',signature = c('RandomForest','AnalysisData'), } model_predictions <- model_predictions %>% - mutate(Rep = as.numeric(Rep)) + mutate(rep = as.numeric(rep)) return(model_predictions) }) diff --git a/R/randomForest-classification.R b/R/randomForest-classification.R index 8213a17f..11817f8e 100644 --- a/R/randomForest-classification.R +++ b/R/randomForest-classification.R @@ -63,6 +63,18 @@ collateClassification <- function(models,results){ ) } +collateClassificationModels <- function(models){ + suppressMessages( + models %>% + map( + ~.x %>% + map(~.x$reps %>% + map(~.x$model) + ) + ) + ) +} + #' @importFrom yardstick metric_set accuracy kap roc_auc #' @importFrom dplyr summarise_all group_by_all n #' @importFrom stringr str_split @@ -220,7 +232,7 @@ classification <- function(x, if (isTRUE(returnModels)) { - res@models <- collateModels(models) + res@models <- collateModels(models,type = 'classification') } return(res) diff --git a/R/randomForest-internals.R b/R/randomForest-internals.R index 2a7fe62f..1724a10f 100644 --- a/R/randomForest-internals.R +++ b/R/randomForest-internals.R @@ -57,6 +57,13 @@ collate <- function(models,results,type){ ) } +collateModels <- function(models,type){ + switch(type, + unsupervised = collateUnsupervisedModels(models), + classification = collateClassificationModels(models), + regression = collateRegressionModels(models)) +} + supervised <- function(x, cls, rf, diff --git a/R/randomForest-regression.R b/R/randomForest-regression.R index 26cd1d1c..883bc854 100644 --- a/R/randomForest-regression.R +++ b/R/randomForest-regression.R @@ -30,7 +30,15 @@ collateRegression <- function(models,results){ .id = 'response' ) } -c + +collateRegressionModels <- function(models){ + models %>% + map( + ~.x$reps %>% + map(~.x$model) + ) +} + #' @importFrom yardstick rsq mae mape rmse ccc regression <- function(x, @@ -100,7 +108,7 @@ regression <- function(x, if (isTRUE(returnModels)) { - res@models <- collateModels(models) + res@models <- collateModels(models,type = 'regression') } return(res) diff --git a/R/randomForest-unsupervised.R b/R/randomForest-unsupervised.R index de627324..b7376939 100644 --- a/R/randomForest-unsupervised.R +++ b/R/randomForest-unsupervised.R @@ -5,8 +5,17 @@ collateUnsupervised <- function(models,result){ .id = 'rep') } +collateUnsupervisedModels <- function(models){ + models %>% + map(~.x$model) +} + unsupervised <- function(x, - rf = list(), + rf = list( + keep.forest = TRUE, + proximity = TRUE, + importance = TRUE + ), reps = 1, returnModels = FALSE, seed = 1234, @@ -28,12 +37,12 @@ unsupervised <- function(x, type = 'unsupervised', importances = collate(models,'importance',type = 'unsupervised') %>% group_by(feature,metric) %>% - summarise(value = mean(value)), + summarise(value = mean(value),.groups = 'drop'), proximities = collate(models,'proximities',type = 'unsupervised')) if (isTRUE(returnModels)) { - res@models <- collateModels(models) + res@models <- collateModels(models,type = 'unsupervised') } return(res) From 0e818cded4ad42990a6d2bdd1ebedb2a424a7f2e Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 13:40:07 +0100 Subject: [PATCH 58/89] fixed QC test --- tests/testthat/test-QCMethods.R | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/testthat/test-QCMethods.R b/tests/testthat/test-QCMethods.R index a520607f..54730dd9 100644 --- a/tests/testthat/test-QCMethods.R +++ b/tests/testthat/test-QCMethods.R @@ -1,8 +1,3 @@ -library(metaboData) - -context('QCMethods') - -plan(future::multisession,workers = 2) test_that('QCMethods returns methods correctly',{ m <- map_lgl(QCMethods(),is.function) @@ -11,13 +6,19 @@ test_that('QCMethods returns methods correctly',{ test_that('methods work',{ m <- names(QCMethods()) - d <- analysisData(abr1$neg,abr1$fact) %>% + d <- analysisData( + metaboData::abr1$neg, + metaboData::abr1$fact) %>% keepFeatures(features = features(.)[290:300]) %>% keepClasses(classes = c(1,6)) m <- map(m,~{ method <- QCMethods(.) - method(d, cls = 'class', QCidx = '1') + if (.x == 'impute'){ + method(d, cls = 'class', QCidx = '1',parallel = 'no') + } else { + method(d, cls = 'class', QCidx = '1') + } }) expect_false(FALSE %in% map_lgl( From 4c9702613e5e7a0b9413e3cda3d9036bbf668c4d Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 13:40:20 +0100 Subject: [PATCH 59/89] update documentation --- man/anova.Rd | 2 +- man/plotImportance.Rd | 4 ++-- man/plotMDS.Rd | 2 +- man/plotMetrics.Rd | 2 +- man/plotROC.Rd | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/man/anova.Rd b/man/anova.Rd index f946b77f..cb7f6dd0 100644 --- a/man/anova.Rd +++ b/man/anova.Rd @@ -41,7 +41,7 @@ library(metaboData) d <- analysisData(abr1$neg[,200:300],abr1$fact) ## Perform ANOVA -anova_analysis <- anova(d,cls = 'day') +anova_analysis <- anova(d,cls = 'ay') ## Extract significant features explanatoryFeatures(anova_analysis) diff --git a/man/plotImportance.Rd b/man/plotImportance.Rd index 517cf0cd..72035daa 100644 --- a/man/plotImportance.Rd +++ b/man/plotImportance.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/modellingPlots.R +% Please edit documentation in R/modelling-plots.R \name{plotImportance} \alias{plotImportance} \alias{plotImportance,Univariate-method} @@ -13,7 +13,7 @@ plotImportance(x, ...) \S4method{plotImportance}{RandomForest}(x, metric = "false_positive_rate", rank = TRUE) -\S4method{plotImportance}{list}(x, metric = "FalsePositiveRate") +\S4method{plotImportance}{list}(x, metric = "false_positive_rate") } \arguments{ \item{x}{S4 object of class \code{Univariate} or \code{RandomForest}} diff --git a/man/plotMDS.Rd b/man/plotMDS.Rd index 7331663b..8d5577bf 100644 --- a/man/plotMDS.Rd +++ b/man/plotMDS.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/modellingPlots.R +% Please edit documentation in R/modelling-plots.R \name{plotMDS} \alias{plotMDS} \alias{plotMDS,RandomForest-method} diff --git a/man/plotMetrics.Rd b/man/plotMetrics.Rd index c198362c..686aa3b7 100644 --- a/man/plotMetrics.Rd +++ b/man/plotMetrics.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/modellingPlots.R +% Please edit documentation in R/modelling-plots.R \name{plotMetrics} \alias{plotMetrics} \alias{plotMetrics,RandomForest-method} diff --git a/man/plotROC.Rd b/man/plotROC.Rd index 9b090c01..7a91f597 100644 --- a/man/plotROC.Rd +++ b/man/plotROC.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/modellingPlots.R +% Please edit documentation in R/modelling-plots.R \name{plotROC} \alias{plotROC} \alias{plotROC,RandomForest-method} From 54b13507d073327d89b8eaa9de69e95502d981ec Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 14:06:51 +0100 Subject: [PATCH 60/89] ensure randomised classes are refactored during permutation testing --- R/randomForest-permute.R | 4 +++- tests/testthat/test-randomForest.R | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/R/randomForest-permute.R b/R/randomForest-permute.R index 6f960210..b54aa8bf 100644 --- a/R/randomForest-permute.R +++ b/R/randomForest-permute.R @@ -8,7 +8,9 @@ permute <- function(x,cls,rf,type){ sinfo() %>% select(all_of(cls)) %>% unlist(use.names = FALSE) %>% - sample() + sample() + + if (is.factor(randomised_cls)) randomised_cls <- factor(randomised_cls) rf$strata <- randomised_cls diff --git a/tests/testthat/test-randomForest.R b/tests/testthat/test-randomForest.R index df1904aa..b488b31b 100644 --- a/tests/testthat/test-randomForest.R +++ b/tests/testthat/test-randomForest.R @@ -13,7 +13,7 @@ test_that('unsupervised random forest works',{ }) test_that('random forest classification works',{ - expect_warning(rf <- randomForest(d,cls = c('day','name'),perm = 3,returnModels = TRUE)) + expect_warning(rf <- randomForest(d,cls = c('day','name'),perm = 2,returnModels = TRUE)) rf_metrics <- metrics(rf) rf_predictions <- predictions(rf) From 40fc33dc63d285c2c9af8191fc39a8cfe84460ee Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 14:34:23 +0100 Subject: [PATCH 61/89] suppress messages from classification predictions --- R/randomForest-classification.R | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/R/randomForest-classification.R b/R/randomForest-classification.R index 11817f8e..c4d1cdc4 100644 --- a/R/randomForest-classification.R +++ b/R/randomForest-classification.R @@ -1,13 +1,15 @@ #' @importFrom randomForest margin classificationPredictions <- function(model){ - tibble(sample = seq_along(model$y), - obs = model$y, - pred = model$predicted, - margin = margin(model)) %>% - bind_cols(model$votes %>% - as_tibble(.name_repair = 'minimal') %>% - mutate_all(as.numeric)) + suppressMessages( + tibble(sample = seq_along(model$y), + obs = model$y, + pred = model$predicted, + margin = margin(model)) %>% + bind_cols(model$votes %>% + as_tibble(.name_repair = 'minimal') %>% + mutate_all(as.numeric)) + ) } classificationMetrics <- function(model){ From 7edb777af2bf30b28b22ac69d304da732106a1a3 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 14:34:34 +0100 Subject: [PATCH 62/89] fix rf proximity column type --- R/randomForest-internals.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/R/randomForest-internals.R b/R/randomForest-internals.R index 1724a10f..74a6ed64 100644 --- a/R/randomForest-internals.R +++ b/R/randomForest-internals.R @@ -46,7 +46,8 @@ modelProximities <- function(model){ as_tibble(.name_repair = 'minimal') %>% mutate(sample = seq_len(nrow(.))) %>% gather('sample2','proximity',-sample) %>% - rename(sample1 = sample) + rename(sample1 = sample) %>% + mutate(sample2 = as.numeric(sample2)) } collate <- function(models,results,type){ From e271fac71c03005d997fff536e46bcc619fb8784 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 14:37:31 +0100 Subject: [PATCH 63/89] rename class definition file --- R/{allClasses.R => all-classes.R} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename R/{allClasses.R => all-classes.R} (100%) diff --git a/R/allClasses.R b/R/all-classes.R similarity index 100% rename from R/allClasses.R rename to R/all-classes.R From 96c194ff2b795bc8d347d7ee3e0da99609ac058f Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 14:45:51 +0100 Subject: [PATCH 64/89] Fix RandomForest class show method --- DESCRIPTION | 2 +- R/show-method.R | 20 +++++++++++++------- tests/testthat/test-show.R | 14 +++++--------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index d167a355..70559888 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -47,7 +47,7 @@ Suggests: knitr, prettydoc, covr, kableExtra -Collate: allClasses.R +Collate: all-classes.R analysis-accessors.R aggregate.R analysisData.R diff --git a/R/show-method.R b/R/show-method.R index 1086e071..08d92a50 100644 --- a/R/show-method.R +++ b/R/show-method.R @@ -158,17 +158,23 @@ setMethod('show',signature = 'RandomForest', cat('Features:\t',nFeatures(object),'\n') if (object@type != 'unsupervised') { - cat('Response:\t',metrics(object) %>% - .$response %>% - unique() %>% + cat('Response:\t',response(object) %>% str_c(collapse = ', '),'\n') } if (object@type == 'classification') { - cat('# comparisons:\t',metrics(object) %>% - .$comparison %>% - unique() %>% - length(),'\n') + + comparisons <- metrics(object) + + if (nrow(comparisons) > 0){ + comparisons <- comparisons$comparison %>% + unique() %>% + length() + } else { + comparisons <- 0 + } + + cat('# comparisons:\t',comparisons,'\n') } cat('\n') diff --git a/tests/testthat/test-show.R b/tests/testthat/test-show.R index 2cc90ccb..fecf4474 100644 --- a/tests/testthat/test-show.R +++ b/tests/testthat/test-show.R @@ -1,6 +1,3 @@ -library(metaboData) - -context('show') test_that('AnalysisParameters show method works',{ expect_output(new('AnalysisParameters') %>% @@ -18,12 +15,11 @@ test_that('Analysis show method works',{ }) test_that('RandomForest class show method works',{ - expect_output(new('RandomForest') %>% - { - .@type <- 'classification' - . - } %>% - print(),'Random forest classification') + object <- new('RandomForest', + type = 'classification', + response = 'class') + expect_output(print(object), + 'Random forest classification') }) test_that('Univariate class show method works',{ From 96e05d4d4c2d8f007987622ac80ee91afd8cf590 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 14:48:42 +0100 Subject: [PATCH 65/89] fix random forest tuning --- R/tune.R | 2 +- tests/testthat/test-tune.R | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/R/tune.R b/R/tune.R index 2a1cc86f..d2270a93 100644 --- a/R/tune.R +++ b/R/tune.R @@ -82,7 +82,7 @@ setMethod('tune',signature = 'AnalysisData', if (class(rf_res) == 'RandomForest'){ rf_res %>% metrics() %>% - select(-Response,-.estimator,-contains('Comparison')) %>% + select(-response,-.estimator,-contains('comparison')) %>% spread(.metric,.estimate) %>% mutate(ntree = .x, mtry = .y) diff --git a/tests/testthat/test-tune.R b/tests/testthat/test-tune.R index d8f4db96..1a829d74 100644 --- a/tests/testthat/test-tune.R +++ b/tests/testthat/test-tune.R @@ -1,5 +1,6 @@ -x <- analysisData(abr1$neg[,200:300],abr1$fact) %>% +x <- analysisData(metaboData::abr1$neg[,200:300], + metaboData::abr1$fact) %>% occupancyMaximum(cls = 'day') %>% transformTICnorm() From 700f4299b2645c74392cbca6ff0f716029418232 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 18:13:07 +0100 Subject: [PATCH 66/89] fixed explanatory feature error --- R/modelling.R | 2 ++ 1 file changed, 2 insertions(+) diff --git a/R/modelling.R b/R/modelling.R index f775c58a..8314a1cd 100644 --- a/R/modelling.R +++ b/R/modelling.R @@ -80,6 +80,8 @@ setMethod('modelling',signature = 'Analysis', explanatoryFeaturesClassification <- function(x,metric,threshold){ + current_metric <- metric + imp <- x %>% importance() From 5e1860e8b7feb97a4445467e4c6f6d9d6844e57f Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 18:13:25 +0100 Subject: [PATCH 67/89] added test for random forest regression pvalue calculation --- tests/testthat/test-randomForest.R | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/testthat/test-randomForest.R b/tests/testthat/test-randomForest.R index b488b31b..35fcdfb4 100644 --- a/tests/testthat/test-randomForest.R +++ b/tests/testthat/test-randomForest.R @@ -62,6 +62,8 @@ test_that('random forest regression works',{ expect_s4_class(rf,'RandomForest') expect_identical(type(rf),'regression') + expect_s3_class(metrics(rf),'tbl_df') + expect_s3_class(importance(rf),'tbl_df') }) test_that('low sample permutation testing works',{ From 96197a4fc7e2538d061db7a3ede223531532f9a5 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 18:30:54 +0100 Subject: [PATCH 68/89] increase test coverage --- R/pre-treatment.R | 6 +++--- tests/testthat/test-QCMethods.R | 4 ++++ tests/testthat/test-aggregateMethods.R | 4 ++++ tests/testthat/test-correctionMethods.R | 4 ++++ tests/testthat/test-impute.R | 4 ++++ tests/testthat/test-keep.R | 4 ++++ tests/testthat/test-metabolyse.R | 4 ++++ tests/testthat/test-occupancyMethods.R | 4 ++++ tests/testthat/test-removeMethods.R | 4 ++++ tests/testthat/test-transformMethods.R | 4 ++++ 10 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 tests/testthat/test-keep.R diff --git a/R/pre-treatment.R b/R/pre-treatment.R index 3f9db95a..6b589319 100644 --- a/R/pre-treatment.R +++ b/R/pre-treatment.R @@ -189,11 +189,11 @@ QCMethods <- function(method = NULL){ return(method) } -removeMethods <- function(method = NULL, description = FALSE){ +removeMethods <- function(method = NULL){ methods <- list( samples = removeSamples, classes = removeClasses, - features = removeFeatures + features = removeFeatures ) if (is.null(method)) { @@ -203,7 +203,7 @@ removeMethods <- function(method = NULL, description = FALSE){ stop(str_c("Remove method '", method, "' not recognised. Available methods include: ", - str_c(str_c("'",names(methods),"'"),collapse = ', '),'.')) + str_c(str_c("'",names(methods),"'"),collapse = ' '),'.')) } method <- methods[[method]] } diff --git a/tests/testthat/test-QCMethods.R b/tests/testthat/test-QCMethods.R index 54730dd9..96b6fed6 100644 --- a/tests/testthat/test-QCMethods.R +++ b/tests/testthat/test-QCMethods.R @@ -4,6 +4,10 @@ test_that('QCMethods returns methods correctly',{ expect_false(FALSE %in% m) }) +test_that('QCMethods errors if incorrect method specified',{ + expect_error(QCMethods('incorrect')) +}) + test_that('methods work',{ m <- names(QCMethods()) d <- analysisData( diff --git a/tests/testthat/test-aggregateMethods.R b/tests/testthat/test-aggregateMethods.R index c5497353..f0a1d058 100644 --- a/tests/testthat/test-aggregateMethods.R +++ b/tests/testthat/test-aggregateMethods.R @@ -7,6 +7,10 @@ test_that('aggregateMethods returns methods correctly',{ expect_false(FALSE %in% m) }) +test_that('aggregateMethods errors if incorrect method specified',{ + expect_error(aggregateMethods('incorrect')) +}) + test_that('methods work',{ m <- names(aggregateMethods()) d <- analysisData(abr1$neg,abr1$fact) %>% diff --git a/tests/testthat/test-correctionMethods.R b/tests/testthat/test-correctionMethods.R index 5676e332..e556d662 100644 --- a/tests/testthat/test-correctionMethods.R +++ b/tests/testthat/test-correctionMethods.R @@ -7,6 +7,10 @@ test_that('correctionMethods returns methods correctly',{ expect_false(FALSE %in% m) }) +test_that('correctionMethods errors if incorrect method specified',{ + expect_error(correctionMethods('incorrect')) +}) + test_that('methods work',{ m <- names(correctionMethods()) d <- analysisData(abr1$neg[,200:250],abr1$fact) %>% diff --git a/tests/testthat/test-impute.R b/tests/testthat/test-impute.R index 5b290913..290cc76d 100644 --- a/tests/testthat/test-impute.R +++ b/tests/testthat/test-impute.R @@ -4,6 +4,10 @@ test_that('imputeMethods returns methods correctly',{ expect_true(all(m)) }) +test_that('imputeMethods errors if incorrect method specified',{ + expect_error(imputeMethods('incorrect')) +}) + test_that('methods work',{ d <- analysisData(metaboData::abr1$neg[,500:550], metaboData::abr1$fact) %>% diff --git a/tests/testthat/test-keep.R b/tests/testthat/test-keep.R new file mode 100644 index 00000000..3e429958 --- /dev/null +++ b/tests/testthat/test-keep.R @@ -0,0 +1,4 @@ + +test_that('keepMethods errors if incorrect method specified',{ + expect_error(keepMethods('incorrect')) +}) \ No newline at end of file diff --git a/tests/testthat/test-metabolyse.R b/tests/testthat/test-metabolyse.R index a28803ab..db8ec15d 100644 --- a/tests/testthat/test-metabolyse.R +++ b/tests/testthat/test-metabolyse.R @@ -31,3 +31,7 @@ test_that('metabolyse-works', { expect_s3_class(mds(analysis),'tbl_df') expect_s3_class(roc(analysis),'tbl_df') }) + +test_that('getPreTreatMethods errors if incorrect method specified',{ + expect_error(getPreTreatMethods('incorrect')) +}) \ No newline at end of file diff --git a/tests/testthat/test-occupancyMethods.R b/tests/testthat/test-occupancyMethods.R index 7fa6fe5e..cce41caf 100644 --- a/tests/testthat/test-occupancyMethods.R +++ b/tests/testthat/test-occupancyMethods.R @@ -7,6 +7,10 @@ test_that('occupancyMethods returns methods correctly',{ expect_false(F %in% m) }) +test_that('occupancyMethods errors if incorrect method specified',{ + expect_error(occupancyMethods('incorrect')) +}) + test_that('methods work',{ m <- names(occupancyMethods()) dat <- analysisData(data = abr1$neg, info = abr1$fact) diff --git a/tests/testthat/test-removeMethods.R b/tests/testthat/test-removeMethods.R index 210b4fd5..bab006bc 100644 --- a/tests/testthat/test-removeMethods.R +++ b/tests/testthat/test-removeMethods.R @@ -7,6 +7,10 @@ test_that('removeMethods returns methods correctly',{ expect_false(F %in% m) }) +test_that('removeMethods errors if incorrect method specified',{ + expect_error(removeMethods('incorrect')) +}) + test_that('methods work',{ d <- analysisData(abr1$neg,abr1$fact) diff --git a/tests/testthat/test-transformMethods.R b/tests/testthat/test-transformMethods.R index 5af126a6..c806bfa7 100644 --- a/tests/testthat/test-transformMethods.R +++ b/tests/testthat/test-transformMethods.R @@ -7,6 +7,10 @@ test_that('transformMethods returns methods correctly',{ expect_false(FALSE %in% m) }) +test_that('transformMethods errors if incorrect method specified',{ + expect_error(transformMethods('incorrect')) +}) + test_that('methods work',{ m <- names(transformMethods()) From cc79828154d9633bd87fc42353baa167c948acbc Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 18:35:18 +0100 Subject: [PATCH 69/89] update documentation --- NAMESPACE | 1 + R/randomForest-classification.R | 2 ++ man/Analysis-class.Rd | 2 +- man/AnalysisData-class.Rd | 2 +- man/AnalysisParameters-class.Rd | 2 +- man/RandomForest-class.Rd | 2 +- man/Univariate-class.Rd | 2 +- 7 files changed, 8 insertions(+), 5 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 6b3a4e42..12b6cd92 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -220,6 +220,7 @@ importFrom(purrr,map_chr) importFrom(purrr,map_dbl) importFrom(purrr,map_depth) importFrom(purrr,map_df) +importFrom(purrr,map_dfr) importFrom(purrr,map_lgl) importFrom(purrr,walk) importFrom(randomForest,margin) diff --git a/R/randomForest-classification.R b/R/randomForest-classification.R index c4d1cdc4..9d168dbd 100644 --- a/R/randomForest-classification.R +++ b/R/randomForest-classification.R @@ -50,6 +50,8 @@ classificationImportance <- function(model){ gather(metric,value,-feature) } +#' @importFrom purrr map_dfr + collateClassification <- function(models,results){ suppressMessages( models %>% diff --git a/man/Analysis-class.Rd b/man/Analysis-class.Rd index f2b2283b..a1074cbd 100644 --- a/man/Analysis-class.Rd +++ b/man/Analysis-class.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/allClasses.R +% Please edit documentation in R/all-classes.R \docType{class} \name{Analysis-class} \alias{Analysis-class} diff --git a/man/AnalysisData-class.Rd b/man/AnalysisData-class.Rd index f2fc0319..b1542b62 100644 --- a/man/AnalysisData-class.Rd +++ b/man/AnalysisData-class.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/allClasses.R +% Please edit documentation in R/all-classes.R \docType{class} \name{AnalysisData-class} \alias{AnalysisData-class} diff --git a/man/AnalysisParameters-class.Rd b/man/AnalysisParameters-class.Rd index 3df60e70..2687c425 100644 --- a/man/AnalysisParameters-class.Rd +++ b/man/AnalysisParameters-class.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/allClasses.R +% Please edit documentation in R/all-classes.R \docType{class} \name{AnalysisParameters-class} \alias{AnalysisParameters-class} diff --git a/man/RandomForest-class.Rd b/man/RandomForest-class.Rd index 09e1ddd0..e3cfbe23 100644 --- a/man/RandomForest-class.Rd +++ b/man/RandomForest-class.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/allClasses.R +% Please edit documentation in R/all-classes.R \docType{class} \name{RandomForest-class} \alias{RandomForest-class} diff --git a/man/Univariate-class.Rd b/man/Univariate-class.Rd index d43535d7..7766187c 100644 --- a/man/Univariate-class.Rd +++ b/man/Univariate-class.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/allClasses.R +% Please edit documentation in R/all-classes.R \docType{class} \name{Univariate-class} \alias{Univariate-class} From c16a1c2cdee2c336cab55c2f5f2720b8abb65f35 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 18:40:25 +0100 Subject: [PATCH 70/89] remove vignette building from installation instructions in readme --- README.Rmd | 2 +- README.md | 31 +++++++++++++------------ man/figures/README-supervised_RF-1.png | Bin 54751 -> 54551 bytes 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/README.Rmd b/README.Rmd index 5e6f1d9e..4d96c1ad 100644 --- a/README.Rmd +++ b/README.Rmd @@ -38,7 +38,7 @@ This package provides a tool kit of methods for metabolomics analyses that inclu The `metabolyseR` package can be installed from GitHub using the following: ```r -devtools::install_github('jasenfinch/metabolyseR',build_vignettes = TRUE) +remotes::install_github('jasenfinch/metabolyseR') ``` ## Learn more diff --git a/README.md b/README.md index 8e455b69..19f9106f 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ The `metabolyseR` package can be installed from GitHub using the following: ``` r -devtools::install_github('jasenfinch/metabolyseR',build_vignettes = TRUE) +remotes::install_github('jasenfinch/metabolyseR') ``` ## Learn more @@ -170,7 +170,7 @@ anova_results <- d %>% ``` A table of the significantly explanatory features can be extracted with -a bonferroni correction adjusted p value < 0.05 using: +a bonferroni correction adjusted p value \< 0.05 using: ``` r explan_feat <- explanatoryFeatures(anova_results,threshold = 0.05) @@ -179,19 +179,20 @@ explan_feat <- explanatoryFeatures(anova_results,threshold = 0.05) ``` r explan_feat #> # A tibble: 379 × 10 -#> Response Comparison Feature term df sumsq meansq statistic p.value -#> -#> 1 day 1~2~3~4~5~H N341 respo… 5 3.88e-4 7.76e-5 137. 1.55e-46 -#> 2 day 1~2~3~4~5~H N133 respo… 5 7.00e-5 1.40e-5 126. 8.63e-45 -#> 3 day 1~2~3~4~5~H N163 respo… 5 6.01e-5 1.20e-5 117. 2.95e-43 -#> 4 day 1~2~3~4~5~H N1087 respo… 5 2.42e-6 4.84e-7 99.8 5.61e-40 -#> 5 day 1~2~3~4~5~H N171 respo… 5 2.25e-7 4.50e-8 95.7 3.84e-39 -#> 6 day 1~2~3~4~5~H N513 respo… 5 3.38e-6 6.76e-7 95.3 4.78e-39 -#> 7 day 1~2~3~4~5~H N1025 respo… 5 2.78e-6 5.56e-7 91.0 3.91e-38 -#> 8 day 1~2~3~4~5~H N342 respo… 5 3.71e-6 7.41e-7 90.3 5.32e-38 -#> 9 day 1~2~3~4~5~H N1083 respo… 5 5.11e-5 1.02e-5 89.0 1.06e-37 -#> 10 day 1~2~3~4~5~H N1085 respo… 5 1.10e-5 2.19e-6 83.4 1.92e-36 -#> # … with 369 more rows, and 1 more variable: adjusted.p.value +#> respo…¹ compa…² feature term df sumsq meansq stati…³ p.value adjust…⁴ +#> +#> 1 day 1~2~3~… N341 resp… 5 3.88e-4 7.76e-5 137. 1.55e-46 2.73e-43 +#> 2 day 1~2~3~… N133 resp… 5 7.00e-5 1.40e-5 126. 8.63e-45 1.52e-41 +#> 3 day 1~2~3~… N163 resp… 5 6.01e-5 1.20e-5 117. 2.95e-43 5.19e-40 +#> 4 day 1~2~3~… N1087 resp… 5 2.42e-6 4.84e-7 99.8 5.61e-40 9.88e-37 +#> 5 day 1~2~3~… N171 resp… 5 2.25e-7 4.50e-8 95.7 3.84e-39 6.75e-36 +#> 6 day 1~2~3~… N513 resp… 5 3.38e-6 6.76e-7 95.3 4.78e-39 8.41e-36 +#> 7 day 1~2~3~… N1025 resp… 5 2.78e-6 5.56e-7 91.0 3.91e-38 6.87e-35 +#> 8 day 1~2~3~… N342 resp… 5 3.71e-6 7.41e-7 90.3 5.32e-38 9.36e-35 +#> 9 day 1~2~3~… N1083 resp… 5 5.11e-5 1.02e-5 89.0 1.06e-37 1.87e-34 +#> 10 day 1~2~3~… N1085 resp… 5 1.10e-5 2.19e-6 83.4 1.92e-36 3.37e-33 +#> # … with 369 more rows, and abbreviated variable names ¹​response, ²​comparison, +#> # ³​statistic, ⁴​adjusted.p.value ``` The ANOVA has identified 379 features significantly explanatory over the diff --git a/man/figures/README-supervised_RF-1.png b/man/figures/README-supervised_RF-1.png index 86497dbcc975c91993bcdacbf23c21a58ef42803..a0215515717a6e46ada680cb92487c251b1d9a04 100644 GIT binary patch literal 54551 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 F{{y7cb6o%c literal 54751 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

${itA=LokUfd@6Z*O^aukQjf6JK1NCQmnMX$)ju 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 Date: Fri, 28 Oct 2022 19:17:24 +0100 Subject: [PATCH 71/89] update documentation --- R/all-classes.R | 2 +- R/modelling-accessors.R | 4 +++- man/RandomForest-class.Rd | 2 +- man/modelling-accessors.Rd | 5 ++++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/R/all-classes.R b/R/all-classes.R index 8cf9e342..4364f11a 100644 --- a/R/all-classes.R +++ b/R/all-classes.R @@ -78,7 +78,7 @@ setClass('Analysis', #' @description An S4 class for random forest results and models. #' @slot type random forest type #' @slot response response variable name -#' @slot results list of measure and importance results tables +#' @slot metric tibble of model performance metrics #' @slot predictions tibble of model observation predictions #' @slot permutations list of permutations measure and importance results tables #' @slot importances tibble of model feature importances diff --git a/R/modelling-accessors.R b/R/modelling-accessors.R index 81963fa9..5c3decc0 100644 --- a/R/modelling-accessors.R +++ b/R/modelling-accessors.R @@ -54,7 +54,7 @@ #' proximity(rf_analysis) #' #' ## Retrieve the explanatory features -#' explanatoryFeatures(rf_analysis,metric = 'FalsePositiveRate',threshold = 0.05) +#' explanatoryFeatures(rf_analysis,metric = 'false_positive_rate',threshold = 0.05) #' @export setGeneric('binaryComparisons',function(x,cls = 'class') @@ -217,6 +217,8 @@ setMethod('predictions',signature = 'RandomForest', } ) +#' @rdname modelling-accessors + setMethod('predictions',signature = 'list', function(x){ object_classes <- x %>% diff --git a/man/RandomForest-class.Rd b/man/RandomForest-class.Rd index e3cfbe23..c45a9e02 100644 --- a/man/RandomForest-class.Rd +++ b/man/RandomForest-class.Rd @@ -14,7 +14,7 @@ An S4 class for random forest results and models. \item{\code{response}}{response variable name} -\item{\code{results}}{list of measure and importance results tables} +\item{\code{metric}}{tibble of model performance metrics} \item{\code{predictions}}{tibble of model observation predictions} diff --git a/man/modelling-accessors.Rd b/man/modelling-accessors.Rd index f620c339..98deb87a 100644 --- a/man/modelling-accessors.Rd +++ b/man/modelling-accessors.Rd @@ -17,6 +17,7 @@ \alias{metrics,Analysis-method} \alias{predictions} \alias{predictions,RandomForest-method} +\alias{predictions,list-method} \alias{predictions,Analysis-method} \alias{importanceMetrics} \alias{importanceMetrics,RandomForest-method} @@ -68,6 +69,8 @@ predictions(x) \S4method{predictions}{RandomForest}(x) +\S4method{predictions}{list}(x) + \S4method{predictions}{Analysis}(x) importanceMetrics(x) @@ -170,5 +173,5 @@ importance(rf_analysis) proximity(rf_analysis) ## Retrieve the explanatory features -explanatoryFeatures(rf_analysis,metric = 'FalsePositiveRate',threshold = 0.05) +explanatoryFeatures(rf_analysis,metric = 'false_positive_rate',threshold = 0.05) } From 98d84e1b044c8f8ad99d24de7b1bdab0e2567a59 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 19:49:34 +0100 Subject: [PATCH 72/89] check fixes --- NAMESPACE | 1 + R/all-classes.R | 2 +- R/metabolyseR.R | 10 ++++++---- R/modelling-plots.R | 2 +- R/plotFeature.R | 3 ++- R/plotSupervisedRF.R | 2 +- R/tune.R | 2 +- R/univariate.R | 2 +- man/RandomForest-class.Rd | 2 +- man/anova.Rd | 2 +- vignettes/modelling.Rmd | 10 +++++----- 11 files changed, 21 insertions(+), 17 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 12b6cd92..2cc7206c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -207,6 +207,7 @@ importFrom(magrittr,set_names) importFrom(magrittr,set_rownames) importFrom(methods,"slot<-") importFrom(methods,as) +importFrom(methods,is) importFrom(methods,new) importFrom(methods,show) importFrom(methods,slot) diff --git a/R/all-classes.R b/R/all-classes.R index 4364f11a..8a69af1b 100644 --- a/R/all-classes.R +++ b/R/all-classes.R @@ -78,7 +78,7 @@ setClass('Analysis', #' @description An S4 class for random forest results and models. #' @slot type random forest type #' @slot response response variable name -#' @slot metric tibble of model performance metrics +#' @slot metrics tibble of model performance metrics #' @slot predictions tibble of model observation predictions #' @slot permutations list of permutations measure and importance results tables #' @slot importances tibble of model feature importances diff --git a/R/metabolyseR.R b/R/metabolyseR.R index 75389ffd..75c70896 100644 --- a/R/metabolyseR.R +++ b/R/metabolyseR.R @@ -1,11 +1,13 @@ globalVariables( - c('Response','Feature','Sample2','Comparison','Measure','Value', + c('response','feature','Sample2','comparison','Measure','value', 'Pvalue','Mean','SD','.','.estimate','Permutation','.metric', 'Class','Intensity','Feature1','p','n','Feature2','Intensity1', - 'Intensity2','log2IntensityRatio','r','ID','Sample','Rep','Count', + 'Intensity2','log2IntensityRatio','coefficient','ID','Sample','rep','Count', 'Occupancy','adjustedPvalue','adjusted.p.value','Label','response', - '-log10(p)','DF1','Sample1','Proximity','Dimension 1','Dimension 2', + '-log10(p)','DF1','sample1','Proximity','Dimension 1','Dimension 2', 'x','.level','sensitivity','specificity','Mode','RSD','Median','Colour', - 'Index','TIC','y','label','batch','correction','N','term','Metric','Frequency','|r|','idx_1','idx_2' + 'Index','TIC','y','label','batch','correction','N','term','Metric','Frequency', + '|coefficient|','idx_1','idx_2','.estimator','metric','fpr','p-value','obs','pred', + 'sample2','Feature','freq' )) diff --git a/R/modelling-plots.R b/R/modelling-plots.R index de306455..69ee153c 100644 --- a/R/modelling-plots.R +++ b/R/modelling-plots.R @@ -278,7 +278,7 @@ setMethod('plotMetrics',signature = 'RandomForest', response <- response(x) if (x@type == 'classification') { - pl <- ggplot(res,aes(x = .estimate,y = Comparison)) + + pl <- ggplot(res,aes(x = .estimate,y = comparison)) + geom_point(shape = 21,fill = ptol_pal()(1)) + theme_bw() + facet_wrap(~.metric) + diff --git a/R/plotFeature.R b/R/plotFeature.R index e9708d80..2fa7294b 100644 --- a/R/plotFeature.R +++ b/R/plotFeature.R @@ -33,6 +33,7 @@ setGeneric('plotFeature', #' @rdname plotFeature #' @importFrom ggplot2 aes geom_point theme_bw element_text guides #' @importFrom ggplot2 scale_fill_manual xlab +#' @importFrom methods is setMethod('plotFeature', signature = 'AnalysisData', @@ -72,7 +73,7 @@ setMethod('plotFeature', mutate(Intensity = as.numeric(Intensity)) } - if (class(i$Class) == 'character' | class(i$Class) == 'factor') { + if (is(i$Class,'character') | is(i$Class,'factor')) { classes <- d %>% select(Class) %>% unique() %>% diff --git a/R/plotSupervisedRF.R b/R/plotSupervisedRF.R index a18a1fc2..738d1be8 100644 --- a/R/plotSupervisedRF.R +++ b/R/plotSupervisedRF.R @@ -65,7 +65,7 @@ setMethod('plotSupervisedRF', reps = 1, seed = seed)) - if (class(rf) != 'try-error') { + if (!is(rf,'try-error')) { pl <- plotMDS(rf, cls = cls, label = label, diff --git a/R/tune.R b/R/tune.R index d2270a93..d3609fff 100644 --- a/R/tune.R +++ b/R/tune.R @@ -79,7 +79,7 @@ setMethod('tune',signature = 'AnalysisData', rf = list(ntree = .x, mtry = .y)), silent = TRUE) - if (class(rf_res) == 'RandomForest'){ + if (is(rf_res,'RandomForest')){ rf_res %>% metrics() %>% select(-response,-.estimator,-contains('comparison')) %>% diff --git a/R/univariate.R b/R/univariate.R index 4c6534eb..0f1da28d 100644 --- a/R/univariate.R +++ b/R/univariate.R @@ -12,7 +12,7 @@ #' d <- analysisData(abr1$neg[,200:300],abr1$fact) #' #' ## Perform ANOVA -#' anova_analysis <- anova(d,cls = 'ay') +#' anova_analysis <- anova(d,cls = 'day') #' #' ## Extract significant features #' explanatoryFeatures(anova_analysis) diff --git a/man/RandomForest-class.Rd b/man/RandomForest-class.Rd index c45a9e02..d29107b5 100644 --- a/man/RandomForest-class.Rd +++ b/man/RandomForest-class.Rd @@ -14,7 +14,7 @@ An S4 class for random forest results and models. \item{\code{response}}{response variable name} -\item{\code{metric}}{tibble of model performance metrics} +\item{\code{metrics}}{tibble of model performance metrics} \item{\code{predictions}}{tibble of model observation predictions} diff --git a/man/anova.Rd b/man/anova.Rd index cb7f6dd0..f946b77f 100644 --- a/man/anova.Rd +++ b/man/anova.Rd @@ -41,7 +41,7 @@ library(metaboData) d <- analysisData(abr1$neg[,200:300],abr1$fact) ## Perform ANOVA -anova_analysis <- anova(d,cls = 'ay') +anova_analysis <- anova(d,cls = 'day') ## Extract significant features explanatoryFeatures(anova_analysis) diff --git a/vignettes/modelling.Rmd b/vignettes/modelling.Rmd index 8fe7195a..d0f85349 100644 --- a/vignettes/modelling.Rmd +++ b/vignettes/modelling.Rmd @@ -169,7 +169,7 @@ The following will extract the explanatory features below a threshold of 0.05 ba ```{r unsupervised-explanatory} unsupervised_rf %>% - explanatoryFeatures(metric = "FalsePositiveRate", + explanatoryFeatures(metric = "false_positive_rate", threshold = 0.05) ``` @@ -270,11 +270,11 @@ Here, we will use the false positive rate metric with a threshold of below 0.05 ```{r multinomial-explanatory} multinomial_rf %>% - explanatoryFeatures(metric = 'FalsePositiveRate', + explanatoryFeatures(metric = 'false_positive_rate', threshold = 0.05) ``` -As shown above there were a total of `r multinomial_rf %>% explanatoryFeatures(metric = 'FalsePositiveRate',threshold = 0.05) %>% nrow()` explanatory features identified. +As shown above there were a total of `r multinomial_rf %>% explanatoryFeatures(metric = 'false_positive_rate',threshold = 0.05) %>% nrow()` explanatory features identified. Within a multinomial experiment, it is also possible to specify the exact class comparisons to include, where it might not be suitable to compare all the classes at once using the `comparisons` argument. This should be specified as a named list, the corresponding to the `cls` argument. @@ -369,7 +369,7 @@ This gives a total of `r nrow(explanatoryFeatures(binary_rf))` explanatory featu ```{r binary-explanatory} binary_rf %>% - explanatoryFeatures(metric = 'FalsePositiveRate', + explanatoryFeatures(metric = 'false_positive_rate', threshold = 0.05) ``` @@ -385,7 +385,7 @@ binary_rf <- clsReplace(binary_rf, value = refactor_cls, cls = 'day') binary_rf %>% - plotExplanatoryHeatmap(metric = 'FalsePositiveRate', + plotExplanatoryHeatmap(metric = 'false_positive_rate', threshold = 0.05, featureNames = TRUE) ``` From 5c6191b7ef0fd34fda3e73a69e08e32aff6945c2 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 28 Oct 2022 21:42:09 +0100 Subject: [PATCH 73/89] fix response factoring in rf permutation testing --- R/randomForest-permute.R | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/R/randomForest-permute.R b/R/randomForest-permute.R index b54aa8bf..16d29f8d 100644 --- a/R/randomForest-permute.R +++ b/R/randomForest-permute.R @@ -10,9 +10,10 @@ permute <- function(x,cls,rf,type){ unlist(use.names = FALSE) %>% sample() - if (is.factor(randomised_cls)) randomised_cls <- factor(randomised_cls) - - rf$strata <- randomised_cls + if (type == 'classification'){ + randomised_cls <- factor(randomised_cls) + rf$strata <- randomised_cls + } model <- performRF(dat(x), randomised_cls, From 4a3d719f2f42d477eec221ad34175b09091cd985 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Tue, 8 Nov 2022 13:33:23 +0000 Subject: [PATCH 74/89] ensure that groupings are dropped for random forest regression metrics and importance --- R/randomForest-regression.R | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/R/randomForest-regression.R b/R/randomForest-regression.R index 883bc854..6143451d 100644 --- a/R/randomForest-regression.R +++ b/R/randomForest-regression.R @@ -98,11 +98,13 @@ regression <- function(x, response = cls, metrics = collate(models,'metrics',type = 'regression') %>% group_by(response,.metric,.estimator) %>% - summarise(.estimate = mean(.estimate)), + summarise(.estimate = mean(.estimate), + .groups = 'drop'), predictions = collate(models,'predictions',type = 'regression'), importances = collate(models,'importance',type = 'regression') %>% group_by(response,feature,metric) %>% - summarise(value = mean(value)), + summarise(value = mean(value), + .groups = 'drop'), proximities = collate(models,'proximities',type = 'regression'), permutations = collatePermutations(models,type = 'regression')) From a979bfb5a494989413bd55c2d9e94ee0cbd6f575 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Wed, 9 Nov 2022 11:29:42 +0000 Subject: [PATCH 75/89] correct lower tail specifications for classification importance metric p values --- R/randomForest-permute.R | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/R/randomForest-permute.R b/R/randomForest-permute.R index 16d29f8d..c86b3e89 100644 --- a/R/randomForest-permute.R +++ b/R/randomForest-permute.R @@ -161,10 +161,16 @@ importancePvals <- function(x){ regression = regressionImportancePvals(x)) } +classificationPtail <- function(metric){ + if (metric == 'false_positive_rate'){ + lowertail <- TRUE + } else { + lowertail <- FALSE + } + return(lowertail) +} + classificationImportancePvals <- function(x){ - lowertail <- list(MeanDecreaseGini = FALSE, - SelectionFrequency = FALSE, - FalsePositiveRate = TRUE) left_join(x@importances, x@permutations$importance, @@ -173,7 +179,7 @@ classificationImportancePvals <- function(x){ mutate(`p-value` = pnorm(value, mean, sd, - lower.tail = lowertail[[metric]]), + lower.tail = classificationPtail(metric)), `adjusted_p-value` = p.adjust(`p-value`, method = 'bonferroni', n = nFeatures(x))) %>% From 029a4391b32524c1cdcda253ea3e0b3084df248e Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Tue, 22 Nov 2022 16:36:32 +0000 Subject: [PATCH 76/89] plotLDA now returns a warning and skips plotting if an error is encountered during PC-LDA --- DESCRIPTION | 2 +- R/plotLDA.R | 7 ++++++- tests/testthat/test-plotLDA.R | 30 +++++++++++++++--------------- tests/testthat/test-predict.R | 9 ++++++--- 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 70559888..80132561 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -38,7 +38,7 @@ Imports: Hmisc, License: GPL (>= 3) Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.2.1 +RoxygenNote: 7.2.2 Suggests: knitr, rmarkdown, readr, diff --git a/R/plotLDA.R b/R/plotLDA.R index 7f427619..d573b798 100644 --- a/R/plotLDA.R +++ b/R/plotLDA.R @@ -63,8 +63,10 @@ setMethod('plotLDA', legendPosition = 'bottom', labelSize = 2){ - lda <- nlda(analysis,cls = cls,scale = scale,center = center) + lda <- try(nlda(analysis,cls = cls,scale = scale,center = center)) + + if (!is(lda,'try-error')) { tw <- lda@Tw %>% round(2) @@ -111,6 +113,9 @@ setMethod('plotLDA', } return(pl) + } else { + warning('Errors encounted in PC-LDA, skipping plotting of PC-LDA.',call. = FALSE) + } } ) diff --git a/tests/testthat/test-plotLDA.R b/tests/testthat/test-plotLDA.R index a835f602..45cefd73 100644 --- a/tests/testthat/test-plotLDA.R +++ b/tests/testthat/test-plotLDA.R @@ -26,30 +26,30 @@ test_that('plotLDA throws error when wrong type specified for Analysis',{ expect_error(plotLDA(d,type = 'wrong')) }) -test_that('A warning is thrown when a single replicate class is included',{ - d <- analysisData(abr1$neg[,200:300],abr1$fact) %>% - occupancyMaximum(cls = 'day') - - d <- d %>% - removeSamples(idx = 'injorder', - samples = c(6,13,30,31,32,38, - 41,58,62,63,70, - 87,88,93,99,102, - 103,107, 120)) +test_that('plotLDA throws a warning if an error is encountered during LDA',{ + a <- analysisData( + tibble::tibble( + x = 1:10, + y = 20:29 + ), + tibble( + class = rep(1,10) + ) + ) - expect_warning(plotLDA(d,cls = 'day')) + expect_warning(plotLDA(a)) }) -test_that('plotLDA throws error when number of classes is less than 2',{ +test_that('plotLDA throws warning and skips plotting when number of classes is less than 2',{ d <- analysisData(abr1$neg,abr1$fact) %>% keepClasses(cls = 'day', classes = '1') - expect_error(plotLDA(d,cls = 'day')) + expect_warning(plotLDA(d,cls = 'day')) }) -test_that('plotLDA throws error when numeric classes specified',{ +test_that('plotLDA throws a warning and skips plotting when numeric classes specified',{ d <- analysisData(abr1$neg,abr1$fact) - expect_error(plotLDA(d)) + expect_warning(plotLDA(d)) }) test_that('plotLDA plots for 2 classes',{ diff --git a/tests/testthat/test-predict.R b/tests/testthat/test-predict.R index 9c55677c..41108e98 100644 --- a/tests/testthat/test-predict.R +++ b/tests/testthat/test-predict.R @@ -1,5 +1,6 @@ test_that("predict works", { - x <- analysisData(abr1$neg[,200:300],abr1$fact) %>% + x <- analysisData(metaboData::abr1$neg[,200:300], + metaboData::abr1$fact) %>% occupancyMaximum(cls = 'day') %>% transformTICnorm() @@ -25,7 +26,8 @@ test_that("predict works", { }) test_that("predit throws an error if unsupervised random forest used",{ - x <- analysisData(abr1$neg[,200:300],abr1$fact) %>% + x <- analysisData(metaboData::abr1$neg[,200:300], + metaboData::abr1$fact) %>% occupancyMaximum(cls = 'day') %>% transformTICnorm() @@ -46,7 +48,8 @@ test_that("predit throws an error if unsupervised random forest used",{ }) test_that("predict throws an error if RandomForest object does not contain models",{ - x <- analysisData(abr1$neg[,200:300],abr1$fact) %>% + x <- analysisData(metaboData::abr1$neg[,200:300], + metaboData::abr1$fact) %>% occupancyMaximum(cls = 'day') %>% transformTICnorm() From e5d057303c97efc0ff08fe1073420b83a144d4ea Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Tue, 22 Nov 2022 16:55:40 +0000 Subject: [PATCH 77/89] add installation instructions for compiling the vignettes locally --- README.Rmd | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.Rmd b/README.Rmd index 4d96c1ad..aab6536d 100644 --- a/README.Rmd +++ b/README.Rmd @@ -41,6 +41,12 @@ The `metabolyseR` package can be installed from GitHub using the following: remotes::install_github('jasenfinch/metabolyseR') ``` +The package documentation can be browsed online at ; however, if users want to compile the vignettes locally, the following can be used. + +```r +remotes::install_github('jasenfinch/metabolyseR',build_vignettes = TRUE,dependencies = TRUE) +``` + ## Learn more The package documentation can be browsed online at . From 6cf71d792570ac4022cb9e8a1891fd222c0fa582 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Tue, 22 Nov 2022 17:04:12 +0000 Subject: [PATCH 78/89] update README.md --- README.md | 14 +++++++++++--- man/figures/README-feature_plot-1.png | Bin 18560 -> 18479 bytes man/figures/README-pca-1.png | Bin 71883 -> 70315 bytes man/figures/README-supervised_RF-1.png | Bin 54551 -> 53965 bytes 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 19f9106f..bf986055 100644 --- a/README.md +++ b/README.md @@ -23,9 +23,9 @@ release](https://img.shields.io/github/release/jasenfinch/metabolyseR.svg)](http This package provides a tool kit of methods for metabolomics analyses that includes: -- data pre-treatment -- multivariate and univariate modelling/data mining techniques -- correlation analysis +- data pre-treatment +- multivariate and univariate modelling/data mining techniques +- correlation analysis ## Installation @@ -36,6 +36,14 @@ following: remotes::install_github('jasenfinch/metabolyseR') ``` +The package documentation can be browsed online at +; however, if users want to +compile the vignettes locally, the following can be used. + +``` r +remotes::install_github('jasenfinch/metabolyseR',build_vignettes = TRUE,dependencies = TRUE) +``` + ## Learn more The package documentation can be browsed online at diff --git a/man/figures/README-feature_plot-1.png b/man/figures/README-feature_plot-1.png index d972455920d2162b34e49a9e910deedadca94ea4..99176c10f7adee859c7201b4e048641d1d283d9f 100644 GIT binary patch literal 18479 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 literal 18560 zcmeIaWmJ}HyDoeqA{`2XlA@G=gdklappuG6w@7z`lv2_vA|)+SBHb+_N_VG7cQ@?w zVb1x!Ywxwz-g}Jw{rsLW=48$%?zpZqkK;J+fJgH8@o~s;5Cp-0_&`DtLCz&22-*bJ zIe2G#<-s%fgKhml%??2b>QVooHCm+`Ajmc3p~PJ!=Z{OHMq)}T-!4pW;a|COP}_0$ zQRb`HM3NU-JJVm^YPfXgQi#Q^!4UE%+=Hc`a~VvN#d`+ygVjQ+=t*;524Xz^^b<>Z z74JDY*XFUVXx|;CK?63UnGKN|!H`TKAUURtGv=%~LZNfT%YqKbt< zh#_paPVy)P8s)blsWY{9fNJ&rD>IshzciGw4JQkh>k={C3Z=~@& zT5n9bA9mt+!>sR%%kHSt?(%S2`y8@H0hhcN_Wu2QbWDQ63T9DJ&)K#(pEnUKD#}lv zE)Nw25h*@>x;^SNF1(-TjY$|U;y%>UvXqgNmYTXekoT-7{c(c(&Q-2Kw27L;3HTSQ zR=HA!(uw1K)r(y$T1~cHZ$gpWl9B`-iSb?ZqqpIYczNEdL$9rgj*h0M zqazaU`=a(lUHza(T}DPmR8&+)XZ+o}cO_%4Sx&2Ca&mG(WbE;`pGz-dZftJW?EMbH zCT0jGzq3$6;kiE@ISadH)J7>NDEQfv2)PEU=iKFkO{}l4PfkIh@h?%^Wo2b~d3oQo%m>!V&Hcr`?8Q%CkTp%zlC#7AP1%-JI4+kvE~{72VBz4n9__97 zWoz8JbxYwR-$fc41uTBYC0OG|Xx&chG=49g zs+jR-bKla^(yDsj(5#3?*i|W8IYGodhA7{BFuzY`mYA3rn-&8DgOVU^dr1hHGeBMV z&_Zukc6N3`Or6zed2dTg%eQaIU%q^C2vB8Z@LAh;Bk;dROOFVVfg#7wOiZjz`qPLM zaa_OtiYU3$n3PS^d3&K3Ofp-iCZ6aLDd~^d&Hk@i!+Sow<8I+Zzb7X<2L`SX5q0c~ zofg2*OepiLy5AOekhaw28&nrv>(WM2?`qxi>zQ(Qo{CQ^Bss{EXmFhfr_{0^P zIx;e{_Gm6fUfxJYBKWfRv+pS9N7`Tg=Og@Y!@_@k(trQN>uYLtwKm+1JX$c=FJgZg zTr(&nglgPsLWaF+YqMRnI~2X;cQ*l?JuWFRQFr?lJx!>~V8-d|p_$JLBI?W2)4gd5 zG(%-xH=|Goz&0^4@peQ1_{9R7ws?m0#*6JT=k@E$k7}>MZHqupX)nqIFz(i{~FLF1jIkQC$PYyYfX;(VifUUH)wk9Pd zdG0ssfbnfnUxu>rj!IQG0wGM5)L~r^#==1pUPo zxnI9p9v^Ijv&zfLe#y!bbY4sJuses?s~PXIiMM;UUcGu%KaY=(Z=j{cyd{eB*RNkx zUoD*UOiVJevn|@=g<(&1oF{$nhf&Y-GQtX0%)5}eOG^4yRJ>R;b8^~kYHC8Ar=z?3 zNz$WFpFbb$?P-?V-xLrix3~dO;&6AB(dT_cgqphg0l_p7f>Fw##%ZG7xw?)un*eXynup#`^nALhVM81k7>F`hRHP{P!6jqc z%jEMue!;JFQ-UhU}B;?{2QAq{8WOK^u>!8GIW=Q?t0n4x&Dhn z` zIg%Zm+%*ge+*)PV_&PK07)WYu@xp>PZ{B2QU;XBbi;7Z7@@a>2DPg~V|8`s%nO|6N z-CNT;o`D3U%PUOgCMD&k%1S^$z{ABw!DT3GYisLomQd93;|GI~(8u=K8VCw0QXySd z@?ay5-J5I&fq^&>(E9pUR#qY+BK`@35fQy)I&QQP(#J(jq}melwlX#*!tu?{@fA;!WmvSfsKBM5py=-E^258jF&(LMNgV2@A)e$% zOl=?ep^l4Q?9VB2zX)fK|1^8G@&O$)JG+(pt;psC0j{s3Mayj5yu7=cn~TFG?6h<| zJUjJ-qUOV|y}j=(((XgJnwZf2C!n=Y&|i9JV`Hil(pkd*FuW1~H9^{_fdM#lU1?{~MILv$(0$;sv8g|1Rj9rw^G>C%j3lK$Na zAX+ldo~0;frN*7R;(zAw9>?4L0mO_e2TKVM=}-D=P9y~hIAl%NCb**l`Q37-flW?(7iY;-Id~|GV(;XZrfa zv*$kRk_n@(YU)P_+UT*&q8a<_>>rg64STz?3JPhcICpl{x+W$r8*QyL>}gRO`=%j3 zzJ2>0^3wfZLHPVju{S!}0>XcMk-YBu^2}`B9Ht2AzoRVD1nY}~gA?Vk)nDy?D7AN9 z77MS}qzElk9-ny{(yid+mCD%I*tj^V?vz?9R8(hTVP%DcMT&JkI8;$ZrN3VM`|LVa z*nO;vu|Y90nW>65Q@k^KO?|~7$JWg;b+Do8KzB&lV0^&@de5G14vzRb1RB~AKY1Q> z;Q0L4(X>?<1#f8Q-S&_C^>aIu{D0*JS=p8x;;Bm>A~P0@Y?(O@3p6`JW;vbztlZ_( zy++ZM${lqNk7}qhR8_C|*C)kc{T2JgUwNZmCTU)6&;cPk&fxUg+VNRgW{(~bEwdu; z;YPgZt4|IVpEOqEZaBHCs?M(nU!$dc**FDf5W|OZZD0aSeO7*TB#PtSwTX-3B05e> zYm@cF46=!FxL)KVL8z~cRlT^VC*mfelB#G@H1zV=eRZr#Mvw%N1KZF=&r{V@hN^Qu zCMJfPT+T!-&f6P(`4Pgc2m6{^=Y@v;?%kJN>IaLRtzRn_CUYW9YmOaRmmgh7OHS5r z45cEZ7P5A7O5l9v=kJfXEKz%{1+E$&+`9UBN8_uD>hE1boF@8M9t&F=nA5^l+z1K7UZP_rk9xAu(>G*g(DRhD z(|(E_$m6M6hg`qDzFugD_5_vQchWO5Ak;=h6=!8;O0(vhzF^7A&&bS7j>3%cgH`>o zcXGIDBuix@IyD#QWazf>i&0k8y?1VFp?7hpzLGS=k0`l!UXkX{#0SSEKdmjK_Ci@% zndpjkg~>97X@sV+<;i|IF{Av}Rbf}|Wz7qp6cR-48C9S3f3on9|Jv2GQ9UIUc7^km zBa75w)1tZ`{}nl9i7yd-AyVjq7n;`~7ZC zcYihl@OSfTmjZY!NA}XYT&Bq~ZuS=~@~%L$MDec;^a%=Tez96bMoAgGIDv*`h^lA; zrBZIPusq4?E%ZjF&g{4W+{$%(;f~3~#EFOp1+V2ND$FQf)M`*OM`S`KhLZ5wRCL_$SdCRe z?dI(4ytOnK?ntRiiZX!2)KuU4$?pp8b!z(B}k+WZUqNmIPZ$;l8&6R|7iz*-rD^Zb$`N+u5a1VS3$OO2$N#^9l?9*sjOoBdFrMR*H(`DE)ED z&eC8vSSY^2mo7ooPyiO!7)FDtcoz~U(&S=`p_Ya&3|hRe zs(Igrh6Fe{Z8{R~0#HWdzV+DM-F^1cdBjUJBQMVe3XgKLXd7|NtV4{=nN}8dc2ug_ zs*ulbZf~!F14Bl~#l_W#Bq1Y1VPOz4WDNnOt9tnG;kvm}*gVzB@--Ju4mxpNm!mx! zRHC8M#H<1E1W+?WBcqb)?Tw8X0f&V`lkV^O>kv}ewJU$Ri6cmdH$WG8KQouJzc+o( z%nXFSSsjyW&&S7SY02EoY*DSiF!j@?2dQ1XSt^J7`-8*7(8&qX(S5R0JcraK^kk{z zEMgF#n>Blx$k?o&ich@0xH}NDsK3SV#edlt$U7^kz z+%+`1j6Od8{yFMJ%sf2Bc2CfdBP(WRX3|^g-@Bh;I}51Eoiy!|@(G*-&GYBk{Az7o zo}N)t)=^Q?xRsYrV6)rQ+?)a?*W*#g5+P0C55H{A0l;1sqDqZWop z8bvM1Zfghj!zMuEC_Wj(8Q!y2EJo1vdOx3eU~?5?ypsjsDx#^-r+d|Whe9s-%n)zNAXs3WJz zLBSUJb&JNwESsSuYB}v zNxDnI4&xLEvH*~fqT;3g%GI|8`1D28!;aKWf7L$LWh2x(1Xf!Cn*4k_*=y-yd0Z<7 zjh0j`6Oc;yjXM%+PPTIZyZG?o!*Gd}=XS3ORGZ!WlL+D=s-ZDlGVT%Uh*N(DJnd8X ztn{Lp-2S^@u5#7!RqP z100QD10Qc?=EmCxM?ymP{e9>e8P6_N_W}(yHCu#qK|TsGk(HD4C!~SU#|!OP8#aJC z2g$vr2|`(+^^+6vpO*US@ZyQ|pFJbKdUeos#Qo3Dx5iEg@~o%E^E9YTjo#so&zqRf ze#B0e#nc`c#jp;W8ykKERHk}*b^BIv#DJJ?HFS5|J^jtQXlL0n7*TrA*RX%OmkzNI z1@s6ENQ#0<0N~gb0DxC;U?}QkX=<9Eo0}Miai#xmU0Pb&=Kc{X`>lP$)wFCp+(bia zYm-JRUK8L{1L`TAYCDjt7Z-j3Ni;JxF@fMsuuO8$KQdze{JEr{Bw6p>x*V+v9%z4| z=zuOGju;C`%*xBl+M$AK zZOyj(VQOq_EWE%BD4~%=Vybuj0*Yv9ZCX zS=uo}fy(taxJ3f-YHARh7G(T9{{(buC6X}$45Q8 z8gdY=1Y2ZmRMZi>C@YeyEF;qlm@7TcQ+M%7YSOU;k>i0-DnV;kGW+LLOUXLL<`B*X zzXuR&j029MtfEqLdU6O0`GC$;P@FxoS@Qa0f3smN=ilG4p#gPV%{Q>Js)6f*d<01+ zGdcP9?$H~h))nFm=d_UeUf&uT`(E|Qf)|?J3?>0(A{CC;X9AoP;GeuN;1AV!dM*y% zeDeAGj~^nlV~&>sK9!c1ZaX}D`0I(0Nihn&b#ZZldLdTGWuq%qrn#w!K_OmKN9Xju zhX^u99vBolK&YP9*Q@36C2AC*?fjc z)60BVLX~r4Rgl`{<>lcXii(R*o`^Dez3ra2hm#INl?3ftyj`4WWG}=IK_{Bo>BwW( zla;uNFw4=KbDb%esE)+J8c&3oc>(gb$5aR}7VT_%f`W{UpzGEgRP^!NF4SSWD;29> zb!xOTl%ymi3WZ%Q_cx}2!NkVG+FKqna>qc1=IqO%wp*=o{N6Nt_i^tY3QQWWrsBnV zp*UXc&a!w*nem8)uR~2;HSU&$%V~HX_;*K7-KJMiVBo>-s*aLUPx1G`LH;{;db_*B z_syw(wzS|85Wszb$A6B)@KP(W93>Y%yxtyWH9XI;b zc;Fp&@s|y^Py0u=a988w;^cTQAzD-SF@eSLkOe3sSYyMi3~ zr==M^F%j;3+ZSrZoV^>IR72L9$R{A6Eub>IQ=I-u>iYacPC~>1stxg^Qn&rvv|=EsmfB$4h#ud9#MkWWu%_%`0E{g zQ9qa45@nmkm?Nj###I7M90<5fb0(*O_hl>?OtW2;n!ve50FS+WlIpXpCjs4 zxpYpFYUCFiz@WhYkdl&qJncheaWNgBn9;RPHd#Bw$api9q&W#Wvb|p=2*22Yd=Ud8 z07iTS;rKo}DqNHNW!b{xIe%M}VF>|_h_G;6`|Rn#V$SX8FYDN-gf`)sti%jBmdE`f z76t~X;Zb+Hjd_-?5h|57nOn~7WvhI-VwjB+;J06un1|V-(Gd<+Xx9!wJYe3k*v!1B z6L%E3zd742Z=ky8<^k3OthzniB^rCEy6`ixYFu+J5Vrunz7!(@qjxl_f*P#x$B#^W8k-Hj?|6DH7xf!6p1S}h4vlI1X^ebYwcW zX(|8kAz(64M}-6iehdAPrdj3c@W$$mcWQ(zL&0t0(7CIw`y0-X7B zh(kN`OE|vzkb(7Hj$}N0Avg1pt*MehOVdW31ziH=O!1B-dq*4Fm6olS;^ zKVqh8j~+g1c@`xVLVo$`)iUUo0QRaVE9?9RQQTS`_go#*HmeruVnjvex5sa4ocARl zW?u|z1QTnxW2=Q0iozbDA;G8M38p@EtYW@Kr@sKj3DD#K#wKE;usLkDNI_GO{G>>A z5}eZ|I)e%&!T0^}DWE2UI={ks{daAx*igV38>$-sR4ec;fByV|;zTw;Ox-P&L|`#gxax*D?$KufzJS!w6`$a{X?ewp|nvu74KfX&s{xsZ z%GL%)c<~Hve;FIA;qtT~O~uJfBOptoL?HUYtba-Kj~_n(A|D%zcO=rKL}7>EnrM{W z)Z^y-u^xx(goioW?MezCUu*P=N1`xqo(bDBh^~|z27ObegbFpKS{06J8XC}ci4mi= zT?QgFh@3j)(R7(mi*iXlduMCDdv|r*$<7WK#^AL8vud<*lt?7^rE*prx5*_PmhH_v z(HChZAi+peNFWW60091xH=OLpyuCn#bi*7Gqx{E5yyK^bm??5{7`JZ4;@QCMNulC{t3F#;OE=HYSy+scH1nO>DXz$W#y7aMRKG zbl%0LExkgBhr(2&rk9s3pp)A&*o8hqtt2c{$u#MzPIli|6DxF5^W!z5Dc+aFt?%+* zVTEhvkhw-wT2{s>EG;4N{bfQi{j%)hX!Ew7UTgIG%F^}j(b3UpYO-40NdXl6{PE*Q z&Ku`a4qR0FxgAy+PMTxiLW2VK<;8HuWE84r7v{Rw#Xk17Cx`lU`$LdG+!;S|76QPn zt>_DDu?Abiz@@KKP#dn3S{>;J7 zpncG+0hjs>Q=ToW$Y%3uJ_rW$Q~?h}5{#mL?cvIWaOfidNs2;2)|U3@y4)bH`=pp5 zaeaMj>r-3<(Y$?mPfyS0Y69uMu@Xk${7Xdn#fz8Tgo(_1s|w-=6|Pk)5?Q zEWlv?q9(m;2B5R?lwFM+kG(45(E+SOTCb@I<84-fILn5>%Yr3eYzx?B+tO>1;7`bDc9C8pBoxpz{LC)om|UWrU?q3 ztrs)&66Q@7eIK-3-#BuVL4GK-yGoR;Ea{KGUp9{$cpttLotqQ_dazR zJ42o$spSL14fcA(Gy-iIUBX3z`4}|yn)fscDWeJBrfqpGN3MuiANbmb#5GSqWJnrK zz*ruWoB+Mb)WpO@uG_w?r{^g&$1cv!9ih)&pFdXzqC{ZLq25O&heotSJV*}zciIv! z;X-u_fQy02SiXjAoiUn#-E-Oe{(da_H9=s$0rCYHskLsJ6N~65*zn5z0 zf!3qkVG-nzr53|H0TTHxn}#S|!iV|(obfoy<>eM}s07#2H`2US{P8KI&W^^m7aWY2 zr%FjlX>Mr91M){mktnSQ2MY@eDAxM>`$4n@JIT+_f6$7Ju-+gI5@Bpd`B$31A9HOG*jg2VHmzO&L!o`-O(t;RXNgZ}|yxiPa zzTf)##giT}ggcZ1WMF7$m@UJmU0LdWxZ^bLUSe_M&Ye3nZfl^o&C7etO1k*B(9MOc z>H(c16G?W?v~Ae~x&`ayg6gi0j$GgbKt}8aF#gHO30%0Yy(Qq7fZ(CfFB*}f!_}HJ zDog|~E*@9=`dgr4N~+mz-hBIj?o9Kdo~>PGn+hc(#F**%`Tajq&=~Vr41v{thQS_8$QV$C?djxuK={(a=!jG1}CGb4ZuO0-8s*M)BG^WOMcc z1PN>Avba_xK(`?m{t=7Z=HddREId3sB_+kg2u)X6T>RT%K$hf`+iS08+E4olmtdl{RM~G{`q-P zLjhAzu%fSoLF9X&)g9L@V=2rk$K@F1tmpPvh%NyRwHP6=2UkX`6B2an)Py7J=_$pr zOxUt^seU(aC4#^d@;{OS<%ZNXZf^SpuXRysA;ab6YdNNPlP+>G+yRbE2!}CbsvEVF z)+q7&q>=x4jpz8UUpIMp`bI`R{`2`1$X0bwGI|}iw;;&nASfmHM|h9Qi$Gfc0Fmh= z*j{^E+lL2qIW;HcXVL^jw*z&0u~bEnpRdN;ZX9ZS%vNwtBO@bgn*+yN1D}1Hj^2>1%mz9P6=AM$ zpM4DJ-dP|>w#5M_`^~f8Bdx8d#DH2>xacD_fjBmLdf!f35Yv$3WLEg@zFp%3efX9p z!FWXbR$@_6k$zrOCoST|&*bbS8dN_C>RT=WpMZd0K`+t6Rt_S}*n94zpSx9g?%cU3 z>i6}N9OdqaE(s2GE!NNJjiV#Chf!pWJ_?29mBW%yLVeQ%$vFXukQa3@wQx-5a@wa) zO8l8ZH(nH17ZIs}y5}>>fXGvZF%cM*D6g{L$$AX)hVnFsL$9fdBX$lioE71_!2F1sO8ffK%M#a?c2q1gJ!}%?@iWnVizl@%pUJeh5dDGJUBUo^mLzc zW*4gV_v1au@5B9oE(MtmaseOG)(v3Yz|@IUqipwus-wNQO@M3s%P6i2d0m8w3ErpH zi|r&>Ba$%!^t?5Lb{`o5G5yP86IF7wO}~Cn-5`;?9r~s{@3)_iPsiDjQN~&eV;V}g zebt$7Xoi0NqV}}Y`Q*su%ostFv1W8u%qdCvtJZi3*HlEPSz*eByrR%edwUbc8^}Im zW@lv;6cjxB+leO>@=8h~LBSUh*!dV>gJSuIK0@(97?VU6Nx_X%oWki~CItmtDfbY> z4!p@T5b%9_d+zQOz%q$%_%pG6SQBC`Dw3Wq+ISm2Hs@o5R_ly%3NOWs!X4}M3YDbh zFAP4a<--71|Ft@(VrpS=F``IL`JPbOC0Y|>lX7K1a?Na z%M>V6%=i?Cb++MnlFG_`fJ{R&2L;5Q8{kEeFHY25 z1LAD5^?6q4a}oKylQn30Vq;>Ap+E)vO^M`J<%qBr)kk!{0^`=(p+$+GGM@LzJOQd1`usD8d|3^O z#GG29>RO2mB~$Jg>Lm6*Gc#QT&#mEh%QOk@*H5myfFuMeQOE0Nu`jXx*RPD^bg{JV zI{*_G7QPp4`kOg~AD*~thWu@?lA$+ztB)0RB3$TJ z)$*9yO4{AAOapq<;Q4bkmjM1sV9G{5SJ1Jr1XbEq7qw#brI&#&mkR zpW!a3rKN?!F93QCEI<9|oc_fEKw1z}A$T-6)Og^1_h5SI`Sa(%NUNz`1$hsujsH<( zWg{J0siYkDSjppf5;zg4$Ijy20q6~1Vc_DF{=SRbKR|GW?6hQeb+qC>6#o~o&I3DX zMHsSr^3(KVbD~CCS8g~u5>MDT@v<7|&q(8z7TizsH;r1dEh-NssD+$4n3!HWveoPB z>0KlvQ+fLIGBNSg%8I-o0dhs4W#XkshEmLn8?8Myn8H!EY{^nwTnXK1^2^WavRMr~ ztD_)z3XqbKHBR4l=AH%iC?xFp;~e&MHfF3~YAqe*9;K)|mXrk;j?+z-&su#~=%PME zML_{v4D^H`KZg8xO(zQL`74DdTK)bWK%qmqGVJ+U*wa+cvE%}n--=s&b{=4%!M$C*WGKh94W1v+kt^MM*BsR z>4}kpzNWhUz2)Kg`T1Z1X)MkUPv+2&6NE&lqray|DblHgjF#Ow4j4t0E*LntU; zJf!ab`uUUNvbxC~a^j>i`LsKnTtM-P9&Zt&Pz}0E*xe9pJ6^r=pS7{GyWzv(o;6fh zSh)4x%%?fe!QRZ|aq9A^e1;Mf|B)!v1Xy@kLNr7S7tV118j<~CU&vY2m)<)s|3%}b zZCqSjm2mvVej&*3 z7|ciVt)?}16LZV+lYdwAN49wefuYO=ik$3C5o-_#YCLF)VexCdQs%mCIuvjM-K*d| zY3U}=c{aAGQj!u^nD#P{G)&(V5fSl>-DS`jPX6L7L4uF&iV4gafLe%F8^E~j=KP$E ztJ?wbDKmT39wz-|AlmF8*lx6m61f}052~8Fx;mH%x^VJfb!cd)BmM1hWBXK0ptGiB zpYO4ZHqAaT0^M!TtpQ$M8LL{Hm>{}*xncI%_$9=?*kyC(a(qi`c6f}f9EtjKFAFD| z!eQWojb{(M*UaAAKzQLQvAg-z^iOQD@ts?Sp`+|N)xob$vjH3ZOv8bWtWoy%_J$cW zgjY7kSYw!GA6QSCScU+>;z@}UZ)00lSzY{N@cXB{jkf`h=v2}_O-p&MTtJXR@M7GT z`@b4zDSdzAxJ2;lq$@F-_#c31GkD6HZ(DNrcBnUIa%_<- zccks&A2G8Oauq!`e$V9WObv2SKg8?5Ozo8-cbf%@f zJ;#_SVTr3x=8yJ((owy)cb}q~qa#oElmJNSH8d983z(dLq^71~TYR)v&z8@+@u{J! zZfa~_2bE$u7!)%==&y2(h(kacnq;h!xjHs5_)JH*|2;gUx zRhbN#n}fqPbb5vAw^C9l`K-lyTP{Zh?0pu`{w%4yBgPO8GoWu!CQVIEt*56a8+H!q zz*cA9(?7s|1GcEHo6&2+?~~GNVj=gXOw*DPuc>3&T&sKndU?Ugy(Wm`_>tL&+1VSRq!`qVmt9v1Zf76%ixmJu&9&B5;l!! z|6$WwgY*gW8n$I0J0AlPlW7|0enHL=n_Aqy{C*@QY{Pu24bo3w~^-OiyVPuKY(~^Nl&jl{o)5#p9bHpeM|%8J z$U8`FHw;p(jRo$8iV9?Pnv_yf``5cH-n!wj77?%UB&G8Uz)2t&1&t*{K{7VYIqT(B z9pg_z!os)cwMlorinCyHncbHOC`n1V0o5(ChHCZq`5noyZ=H90`M`K`abgqr$u4l) z`LYQZ^8BuEV{M%acLq{Ym^cvBJUk>L&j9TD&4IYt?21Rdp{rlmyZ-mGaRLz#QxNAE zfD@{9b`?GzG}T6>2RzX}nd}iEBqSV4I^lzXyPWiN5UX3cFR!d2;9`n1zkb!uH^4?IM<|-B zSAaMKwj|=i2Z%8-u@vhC0U)JSo%@df%Kj5F@1lyGU3PPNA}na7-~|HfsOq{m)HY?B zDk>_4f(T+yAdDLBGkHNR_V6K)*z>5B901CEp=x&wkkwtlkRGe3q>Uc|5Vw>#`-%`7 z`{u1%5z?uE<@aPf0m+D|R{Y-@4!BMbHPxa7Z)E=OX5-oF)FBbmbOHHiMBzcgia82ZVi*xYqeFg zX6_7n!{P5IOQ5vR%F2q4zPfzPFQ|RCqP!gFgh^ry_)c#axJt zjZI!i2tGl*Xpnpw%gvj4!0PGk8FiW#L3oA(6NE@TQC2pzvI?tTYX`JKQCpjhG|1-4 ziJB7g)924q0gt*!_&@b_U z769m*H`1v%*w|{N*0hdyMT1~u6clu@7$%sU604P)@_>9VE&?+Nv(x^T)c0Tr3K$~j zm_>`JFovt$1!)aH1FmFu3}C<0JD7X}B61>LXc^!>RZ!pnMq6Sr%<%RBkJXs0;M+Qv zy*1Q$DN2q1{rh*AvWI%IQ{JGo*nAL$P7U3}Q-Z<^)HDQ;NPsK>88(U!{f1Y~<#w_^ z3$-7L3n4-W{_ip+<UJ*-WZ49d*P0%jcIsjitB4CA0kg{>kg`D$QPp^_VS z-__n;92 ziT%Z8KEG*b-as7=J+8;r+(kHLQ+vA=us7K`KvaTM?ICYi9l)r&PZ$TU-u!5Qxs}no z01uBSFD-QgV#|2f5pwn#s0g!jUPUO)ZYk<~o%7j@P{l41T@qBgq_)>FGgfl%$xk)SJ~`>9Prm zjwvpnRROBo9rx79R)*9_5&0{R8UR@co#K2joAlp4@8f?8bw~Gs%Fch@3}C#OiOE$` z(qf>#QBQ?<3I=%gAP^z4i?vJ>KtAr3!0G1Z=0MCS{u*S1=H_%h_N!yZ5Wk_;l}^py z&J)A&{npd--c}izL(T52S;1B7fm97x3;;1f)(GV)$Y-HBUfUVA>JGhtoN@v0NF@GR zmf;YzbXc@7eMEqdPw#Ucq{;)ivkq($}~^D;j$Bn1I-Vb zN0`KskqHV51FoeNrQGm=srh9HhZcG^^)yhU+5I(a`}mu%~D1Pv<(c5-`HPHP<e)vO@?y?f*)ZpLxj#?MnPMIRkdg`Ny29=Z8tX zRliq9;rWH=uVZ4B>v9htp)q(TV&O=I>)!s7d$;(f{-wt@A1K=JBb)iRoufBJ)@2S; zBjchwjSXUE+(b@IPqHb_iQ>J)gzH;(t{gPSp;gcBYqU9@ww>R0y-P$A)Zp2+Y*Y}f z*p$yYT#R22_%6+6gZ?C+{O#zE@@aR8xXD8}@cI|GRW?_3i1+xN4KODN$9J2j^JiWB z^ne2fiL;vsalm)Wl4ipKPtkmeu*PLa4QVyzh~nYpsdcP+>w-b1)Xd(@_xXw$4{oYt z^=`Xru|;+oZ*{w5E5F$7@+$V&K0J2vME5!sXC*DLICQKSU3D7Y<%*WA(oT?Nn73EQ zN_tO@cR~EMWrI diff --git a/man/figures/README-pca-1.png b/man/figures/README-pca-1.png index 2445ed52bea2fe2b883f70ffadfade2ca1b264de..57eb61ff88daedc91e797d208015ebfa7cb799f2 100644 GIT binary patch literal 70315 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 literal 71883 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�v)5SSl{efI8XwV$=(Xs40XsHdo& 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 z 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 F{{y7cb6o%c From b08eac01bcf74643526734775a91c6958d0d6429 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Tue, 22 Nov 2022 17:07:19 +0000 Subject: [PATCH 79/89] Use the CRAN version of missForest with the merging of pull request #25 https://github.com/stekhoven/missForest/pull/25 and release of version 1.5 --- DESCRIPTION | 1 - 1 file changed, 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 80132561..b35f8d97 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -95,4 +95,3 @@ Collate: all-classes.R univariate.R modelling-accessors.R VignetteBuilder: knitr -Remotes: jasenfinch/missForest From fd885caed39949d4dbc2b2f32e1989912535ec04 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Thu, 22 Dec 2022 13:09:30 +0000 Subject: [PATCH 80/89] Make 'pre-treated' the default for argument `type` in Analysis class methods. Fix the return values of `clsArrange` and `clsRename` Analysis class methods --- DESCRIPTION | 2 +- R/analysis-accessors.R | 127 +++++++++++++++++++---------- R/info.R | 102 +++++++++++++++-------- R/plotFeature.R | 19 +++-- R/plotLDA.R | 19 +++-- R/plotPCA.R | 47 ++++++----- R/plotSupervisedRF.R | 18 ++-- R/plotTIC.R | 15 ++-- R/plotUnsupervisedRF.R | 18 ++-- man/analysis-accessors.Rd | 14 ++-- man/cls.Rd | 14 ++-- man/plotFeature.Rd | 2 +- man/plotLDA.Rd | 2 +- man/plotPCA.Rd | 2 +- man/plotSupervisedRF.Rd | 2 +- man/plotTIC.Rd | 2 +- man/plotUnsupervisedRF.Rd | 2 +- tests/testthat/test-analysisData.R | 2 +- tests/testthat/test-info.R | 49 +++++++---- tests/testthat/test-metabolyse.R | 6 +- tests/testthat/test-plotTIC.R | 4 +- 21 files changed, 289 insertions(+), 179 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index b35f8d97..f9851c70 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -38,7 +38,7 @@ Imports: Hmisc, License: GPL (>= 3) Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.2.2 +RoxygenNote: 7.2.3 Suggests: knitr, rmarkdown, readr, diff --git a/R/analysis-accessors.R b/R/analysis-accessors.R index 54005498..4c8bad45 100644 --- a/R/analysis-accessors.R +++ b/R/analysis-accessors.R @@ -60,21 +60,27 @@ setMethod('dat',signature = 'AnalysisData', #' @rdname analysis-accessors setMethod('dat',signature = 'Analysis', - function(x, type = c('raw','pre-treated')){ + function(x, type = c('pre-treated','raw')){ - type <- match.arg(type, - choices = c('raw', - 'pre-treated')) + type <- match.arg( + type, + choices = c( + 'pre-treated', + 'raw')) if (type == 'pre-treated') { - x %>% + d <- x %>% preTreated() %>% dat() - } else { - x %>% + } + + if (type == 'raw'){ + d <- x %>% raw() %>% dat() } + + return(d) } ) @@ -96,17 +102,21 @@ setMethod("dat<-",signature = 'AnalysisData', #' @rdname analysis-accessors setMethod('dat<-',signature = 'Analysis', - function(x, type = c('raw','pre-treated'), value){ + function(x, type = c('pre-treated','raw'), value){ - type <- match.arg(type, - choices = c('raw', - 'pre-treated')) + type <- match.arg( + type, + choices = c( + 'pre-treated', + 'raw')) if (type == 'pre-treated'){ d <- preTreated(x) dat(d) <- value preTreated(x) <- d - } else { + } + + if (type == 'raw'){ d <- raw(x) dat(d) <- value raw(x) <- d @@ -134,21 +144,27 @@ setMethod('sinfo',signature = 'AnalysisData', #' @rdname analysis-accessors setMethod('sinfo',signature = 'Analysis', - function(x, type = c('raw','pre-treated'), value){ + function(x, type = c('pre-treated','raw'), value){ - type <- match.arg(type, - choices = c('raw', - 'pre-treated')) + type <- match.arg( + type, + choices = c( + 'pre-treated', + 'raw')) if (type == 'pre-treated') { - x %>% + i <- x %>% preTreated() %>% sinfo() - } else { - x %>% + } + + if (type == 'raw'){ + i <- x %>% raw() %>% sinfo() } + + return(i) } ) @@ -171,17 +187,21 @@ setMethod('sinfo<-',signature = 'AnalysisData', #' @rdname analysis-accessors setMethod('sinfo<-',signature = 'Analysis', - function(x,type = c('raw','pre-treated'), value){ + function(x,type = c('pre-treated','raw'), value){ - type <- match.arg(type, - choices = c('raw', - 'pre-treated')) + type <- match.arg( + type, + choices = c( + 'pre-treated', + 'raw')) if (type == 'pre-treated'){ d <- preTreated(x) sinfo(d) <- value preTreated(x) <- d - } else { + } + + if (type == 'raw'){ d <- raw(x) sinfo(d) <- value raw(x) <- d @@ -268,20 +288,26 @@ setMethod('features',signature = 'AnalysisData', #' @rdname analysis-accessors setMethod('features',signature = 'Analysis', - function(x,type = c('raw','pre-treated')){ - type <- match.arg(type, - choices = c('raw', - 'pre-treated')) + function(x,type = c('pre-treated','raw')){ + type <- match.arg( + type, + choices = c( + 'pre-treated', + 'raw')) if (type == 'pre-treated') { - x %>% + f <- x %>% preTreated() %>% features() - } else { - x %>% + } + + if (type == 'raw'){ + f <- x %>% raw() %>% features() } + + return(f) }) #' @rdname analysis-accessors @@ -302,20 +328,26 @@ setMethod('nSamples',signature = 'AnalysisData', #' @rdname analysis-accessors setMethod('nSamples',signature = 'Analysis', - function(x,type = c('raw','pre-treated')){ - type <- match.arg(type, - choices = c('raw', - 'pre-treated')) + function(x,type = c('pre-treated','raw')){ + type <- match.arg( + type, + choices = c( + 'pre-treated', + 'raw')) if (type == 'pre-treated') { - x %>% + n_samples <- x %>% preTreated() %>% nSamples() - } else { - x %>% + } + + if (type == 'raw'){ + n_samples <- x %>% raw() %>% nSamples() } + + return(n_samples) }) #' @rdname analysis-accessors @@ -337,22 +369,27 @@ setMethod('nFeatures',signature = 'AnalysisData', #' @rdname analysis-accessors setMethod('nFeatures',signature = 'Analysis', - function(x,type = c('raw','pre-treated')){ + function(x,type = c('pre-treated','raw')){ - type <- match.arg(type, - choices = c('raw', - 'pre-treated')) + type <- match.arg( + type, + choices = c( + 'pre-treated', + 'raw')) if (type == 'pre-treated') { - x %>% + n_features <- x %>% preTreated() %>% nFeatures() - } else { - x %>% + } + + if (type == 'raw'){ + n_features <- x %>% raw() %>% nFeatures() } + return(n_features) }) #' @rdname analysis-accessors diff --git a/R/info.R b/R/info.R index 5a60993a..0b15236b 100644 --- a/R/info.R +++ b/R/info.R @@ -79,15 +79,19 @@ setMethod('clsAdd', setMethod('clsAdd', signature = 'Analysis', - function(d,cls,value,type = c('raw','pre-treated')){ - type <- match.arg(type, - choices = c('raw', - 'pre-treated')) + function(d,cls,value,type = c('pre-treated','raw')){ + type <- match.arg( + type, + choices = c( + 'pre-treated', + 'raw')) if (type == 'raw'){ sl <- get('raw') `sl<-` <- get(str_c('raw','<-')) - } else { + } + + if (type == 'pre-treated'){ sl <- get('preTreated') `sl<-` <- get(str_c('preTreated','<-')) } @@ -143,15 +147,19 @@ setMethod('clsArrange', setMethod('clsArrange', signature = 'Analysis', - function(d,cls = 'class', descending = FALSE, type = c('raw','pre-treated')){ - type <- match.arg(type, - choices = c('raw', - 'pre-treated')) + function(d,cls = 'class', descending = FALSE, type = c('pre-treated','raw')){ + type <- match.arg( + type, + choices = c( + 'pre-treated', + 'raw')) if (type == 'raw'){ sl <- get('raw') `sl<-` <- get(str_c('raw','<-')) - } else { + } + + if (type == 'pre-treated'){ sl <- get('preTreated') `sl<-` <- get(str_c('preTreated','<-')) } @@ -159,6 +167,8 @@ setMethod('clsArrange', sl(d) <- d %>% sl() %>% clsArrange(cls = cls,descending = descending) + + return(d) }) #' @rdname cls @@ -177,14 +187,18 @@ setMethod('clsAvailable',signature = 'AnalysisData',function(d){ #' @rdname cls -setMethod('clsAvailable',signature = 'Analysis',function(d,type = c('raw','pre-treated')){ - type <- match.arg(type, - choices = c('raw', - 'pre-treated')) +setMethod('clsAvailable',signature = 'Analysis',function(d,type = c('pre-treated','raw')){ + type <- match.arg( + type, + choices = c( + 'pre-treated', + 'raw')) if (type == 'raw'){ sl <- get('raw') - } else { + } + + if (type == 'pre-treated'){ sl <- get('preTreated') } @@ -214,14 +228,18 @@ setMethod('clsExtract', setMethod('clsExtract', signature = 'Analysis', - function(d,cls = 'class',type = c('raw','pre-treated')){ - type <- match.arg(type, - choices = c('raw', - 'pre-treated')) + function(d,cls = 'class',type = c('pre-treated','raw')){ + type <- match.arg( + type, + choices = c( + 'pre-treated', + 'raw')) if (type == 'raw'){ sl <- get('raw') - } else { + } + + if (type =='pre-treated'){ sl <- get('preTreated') } @@ -255,15 +273,19 @@ setMethod('clsRemove',signature = 'AnalysisData',function(d,cls){ setMethod('clsRemove', signature = 'Analysis', - function(d,cls,type = c('raw','pre-treated')){ - type <- match.arg(type, - choices = c('raw', - 'pre-treated')) + function(d,cls,type = c('pre-treated','raw')){ + type <- match.arg( + type, + choices = c( + 'pre-treated', + 'raw')) if (type == 'raw'){ sl <- get('raw') `sl<-` <- get(str_c('raw','<-')) - } else { + } + + if (type == 'pre-treated'){ sl <- get('preTreated') `sl<-` <- get(str_c('preTreated','<-')) } @@ -297,15 +319,19 @@ setMethod('clsRename', setMethod('clsRename', signature = 'Analysis', - function(d,cls,newName, type = c('raw','pre-treated')){ - type <- match.arg(type, - choices = c('raw', - 'pre-treated')) + function(d,cls,newName, type = c('pre-treated','raw')){ + type <- match.arg( + type, + choices = c( + 'pre-treated', + 'raw')) if (type == 'raw'){ sl <- get('raw') `sl<-` <- get(str_c('raw','<-')) - } else { + } + + if(type == 'pre-treated'){ sl <- get('preTreated') `sl<-` <- get(str_c('preTreated','<-')) } @@ -313,6 +339,8 @@ setMethod('clsRename', sl(d) <- d %>% sl() %>% clsRename(cls = cls,newName = newName) + + return(d) }) #' @rdname cls @@ -342,15 +370,19 @@ setMethod('clsReplace', setMethod('clsReplace', signature = 'Analysis', - function(d, value, cls = 'class', type = c('raw','pre-treated')){ - type <- match.arg(type, - choices = c('raw', - 'pre-treated')) + function(d, value, cls = 'class', type = c('pre-treated','raw')){ + type <- match.arg( + type, + choices = c( + 'pre-treated', + 'raw')) if (type == 'raw'){ sl <- get('raw') `sl<-` <- get(str_c('raw','<-')) - } else { + } + + if (type == 'pre-treated'){ sl <- get('preTreated') `sl<-` <- get(str_c('preTreated','<-')) } diff --git a/R/plotFeature.R b/R/plotFeature.R index 2fa7294b..28c7933d 100644 --- a/R/plotFeature.R +++ b/R/plotFeature.R @@ -140,17 +140,22 @@ setMethod('plotFeature', cls = 'class', label = NULL, labelSize = 2, - type = 'pre-treated'){ - if (!(type %in% c('raw','pre-treated'))) { - stop( - 'Argument "type" should be one of "raw" or "pre-treated".', - call. = FALSE) - } + type = c('pre-treated', + 'raw')){ + type <- match.arg( + type, + choices = c( + 'pre-treated', + 'raw' + ) + ) if (type == 'pre-treated') { d <- analysis %>% preTreated() - } else { + } + + if (type == 'raw'){ d <- analysis %>% raw() } diff --git a/R/plotLDA.R b/R/plotLDA.R index d573b798..f866a682 100644 --- a/R/plotLDA.R +++ b/R/plotLDA.R @@ -135,18 +135,23 @@ setMethod('plotLDA', title = 'PC-LDA', legendPosition = 'bottom', labelSize = 2, - type = 'raw'){ + type = c('pre-treated', + 'raw')){ - if (!(type %in% c('raw','pre-treated'))) { - stop( - 'Argument "type" should be one of "raw" or "pre-treated".', - call. = FALSE) - } + type <- match.arg( + type, + choices = c( + 'pre-treated', + 'raw' + ) + ) if (type == 'pre-treated') { d <- analysis %>% preTreated() - } else { + } + + if (type == 'raw'){ d <- analysis %>% raw() } diff --git a/R/plotPCA.R b/R/plotPCA.R index ba191221..ca6d32e7 100644 --- a/R/plotPCA.R +++ b/R/plotPCA.R @@ -30,20 +30,20 @@ setGeneric('plotPCA', function( - analysis, - cls = 'class', - label = NULL, - scale = TRUE, - center = TRUE, - xAxis = 'PC1', - yAxis = 'PC2', - shape = FALSE, - ellipses = TRUE, - title = 'PCA', - legendPosition = 'bottom', - labelSize = 2, - ...) - standardGeneric('plotPCA')) + analysis, + cls = 'class', + label = NULL, + scale = TRUE, + center = TRUE, + xAxis = 'PC1', + yAxis = 'PC2', + shape = FALSE, + ellipses = TRUE, + title = 'PCA', + legendPosition = 'bottom', + labelSize = 2, + ...) + standardGeneric('plotPCA')) #' @rdname plotPCA #' @importFrom ggplot2 scale_shape_manual geom_hline geom_vline @@ -127,18 +127,23 @@ setMethod('plotPCA', title = 'PCA', legendPosition = 'bottom', labelSize = 2, - type = 'raw'){ + type = c('pre-treated', + 'raw')){ - if (!(type %in% c('raw','pre-treated'))) { - stop( - 'Argument "type" should be one of "raw" or "pre-treated".', - call. = FALSE) - } + type <- match.arg( + type, + choices = c( + 'pre-treated', + 'raw' + ) + ) if (type == 'pre-treated') { d <- analysis %>% preTreated() - } else { + } + + if (type == 'raw'){ d <- analysis %>% raw() } diff --git a/R/plotSupervisedRF.R b/R/plotSupervisedRF.R index 738d1be8..caf321ee 100644 --- a/R/plotSupervisedRF.R +++ b/R/plotSupervisedRF.R @@ -110,18 +110,22 @@ setMethod('plotSupervisedRF', title = '', legendPosition = 'bottom', labelSize = 2, - type = 'raw'){ + type = c('pre-treated','raw')){ - if (!(type %in% c('raw','pre-treated'))) { - stop( - 'Argument "type" should be one of "raw" or "pre-treated".', - call. = FALSE) - } + type <- match.arg( + type, + choices = c( + 'pre-treated', + 'raw' + ) + ) if (type == 'pre-treated') { d <- x %>% preTreated() - } else { + } + + if (type == 'raw'){ d <- x %>% raw() } diff --git a/R/plotTIC.R b/R/plotTIC.R index 03fd5a7d..cfd4b266 100644 --- a/R/plotTIC.R +++ b/R/plotTIC.R @@ -50,7 +50,7 @@ setMethod('plotTIC',signature = 'AnalysisData', } else { d <- d %>% group_by(ID,!!sym(by)) - + } d <- d %>% @@ -113,14 +113,19 @@ setMethod('plotTIC',signature = 'Analysis', function(analysis, by = 'injOrder', colour = 'block', - type = c('raw','pre-treated')) { + type = c('pre-treated','raw')) { - type <- match.arg(type, - choices = c('raw','pre-treated')) + type <- match.arg( + type, + choices = c( + 'pre-treated', + 'raw')) if (type == 'raw'){ ty <- get('raw') - } else { + } + + if (type == 'pre-treated'){ ty <- get('preTreated') } diff --git a/R/plotUnsupervisedRF.R b/R/plotUnsupervisedRF.R index f8a63cd4..4b3a25c2 100644 --- a/R/plotUnsupervisedRF.R +++ b/R/plotUnsupervisedRF.R @@ -87,18 +87,22 @@ setMethod('plotUnsupervisedRF', title = '', legendPosition = 'bottom', labelSize = 2, - type = 'raw'){ + type = c('pre-treated','raw')){ - if (!(type %in% c('raw','pre-treated'))) { - stop( - 'Argument "type" should be one of "raw" or "pre-treated".', - call. = FALSE) - } + type <- match.arg( + type, + choices = c( + 'pre-treated', + 'raw' + ) + ) if (type == 'pre-treated') { d <- x %>% preTreated() - } else { + } + + if (type == 'raw'){ d <- x %>% raw() } diff --git a/man/analysis-accessors.Rd b/man/analysis-accessors.Rd index e96e0b23..799bc1e8 100644 --- a/man/analysis-accessors.Rd +++ b/man/analysis-accessors.Rd @@ -38,25 +38,25 @@ dat(x, ...) \S4method{dat}{AnalysisData}(x) -\S4method{dat}{Analysis}(x, type = c("raw", "pre-treated")) +\S4method{dat}{Analysis}(x, type = c("pre-treated", "raw")) dat(x, ...) <- value \S4method{dat}{AnalysisData}(x) <- value -\S4method{dat}{Analysis}(x, type = c("raw", "pre-treated")) <- value +\S4method{dat}{Analysis}(x, type = c("pre-treated", "raw")) <- value sinfo(x, ...) \S4method{sinfo}{AnalysisData}(x) -\S4method{sinfo}{Analysis}(x, type = c("raw", "pre-treated"), value) +\S4method{sinfo}{Analysis}(x, type = c("pre-treated", "raw"), value) sinfo(x, ...) <- value \S4method{sinfo}{AnalysisData}(x) <- value -\S4method{sinfo}{Analysis}(x, type = c("raw", "pre-treated")) <- value +\S4method{sinfo}{Analysis}(x, type = c("pre-treated", "raw")) <- value raw(x) @@ -78,19 +78,19 @@ features(x, ...) \S4method{features}{AnalysisData}(x) -\S4method{features}{Analysis}(x, type = c("raw", "pre-treated")) +\S4method{features}{Analysis}(x, type = c("pre-treated", "raw")) nSamples(x, ...) \S4method{nSamples}{AnalysisData}(x) -\S4method{nSamples}{Analysis}(x, type = c("raw", "pre-treated")) +\S4method{nSamples}{Analysis}(x, type = c("pre-treated", "raw")) nFeatures(x, ...) \S4method{nFeatures}{AnalysisData}(x) -\S4method{nFeatures}{Analysis}(x, type = c("raw", "pre-treated")) +\S4method{nFeatures}{Analysis}(x, type = c("pre-treated", "raw")) analysisResults(x, element) diff --git a/man/cls.Rd b/man/cls.Rd index 7bf0afed..23ff43bb 100644 --- a/man/cls.Rd +++ b/man/cls.Rd @@ -28,7 +28,7 @@ clsAdd(d, cls, value, ...) \S4method{clsAdd}{AnalysisData}(d, cls, value) -\S4method{clsAdd}{Analysis}(d, cls, value, type = c("raw", "pre-treated")) +\S4method{clsAdd}{Analysis}(d, cls, value, type = c("pre-treated", "raw")) clsArrange(d, cls = "class", descending = FALSE, ...) @@ -38,38 +38,38 @@ clsArrange(d, cls = "class", descending = FALSE, ...) d, cls = "class", descending = FALSE, - type = c("raw", "pre-treated") + type = c("pre-treated", "raw") ) clsAvailable(d, ...) \S4method{clsAvailable}{AnalysisData}(d) -\S4method{clsAvailable}{Analysis}(d, type = c("raw", "pre-treated")) +\S4method{clsAvailable}{Analysis}(d, type = c("pre-treated", "raw")) clsExtract(d, cls = "class", ...) \S4method{clsExtract}{AnalysisData}(d, cls = "class") -\S4method{clsExtract}{Analysis}(d, cls = "class", type = c("raw", "pre-treated")) +\S4method{clsExtract}{Analysis}(d, cls = "class", type = c("pre-treated", "raw")) clsRemove(d, cls, ...) \S4method{clsRemove}{AnalysisData}(d, cls) -\S4method{clsRemove}{Analysis}(d, cls, type = c("raw", "pre-treated")) +\S4method{clsRemove}{Analysis}(d, cls, type = c("pre-treated", "raw")) clsRename(d, cls, newName, ...) \S4method{clsRename}{AnalysisData}(d, cls, newName) -\S4method{clsRename}{Analysis}(d, cls, newName, type = c("raw", "pre-treated")) +\S4method{clsRename}{Analysis}(d, cls, newName, type = c("pre-treated", "raw")) clsReplace(d, value, cls = "class", ...) \S4method{clsReplace}{AnalysisData}(d, value, cls = "class") -\S4method{clsReplace}{Analysis}(d, value, cls = "class", type = c("raw", "pre-treated")) +\S4method{clsReplace}{Analysis}(d, value, cls = "class", type = c("pre-treated", "raw")) } \arguments{ \item{d}{S4 object of class Analysis or AnalysisData} diff --git a/man/plotFeature.Rd b/man/plotFeature.Rd index 094c0d43..26810142 100644 --- a/man/plotFeature.Rd +++ b/man/plotFeature.Rd @@ -16,7 +16,7 @@ plotFeature(analysis, feature, cls = "class", label = NULL, labelSize = 2, ...) cls = "class", label = NULL, labelSize = 2, - type = "pre-treated" + type = c("pre-treated", "raw") ) } \arguments{ diff --git a/man/plotLDA.Rd b/man/plotLDA.Rd index 5ee7afba..c8fa621e 100644 --- a/man/plotLDA.Rd +++ b/man/plotLDA.Rd @@ -50,7 +50,7 @@ plotLDA( title = "PC-LDA", legendPosition = "bottom", labelSize = 2, - type = "raw" + type = c("pre-treated", "raw") ) } \arguments{ diff --git a/man/plotPCA.Rd b/man/plotPCA.Rd index 201dee78..7d72a2d7 100644 --- a/man/plotPCA.Rd +++ b/man/plotPCA.Rd @@ -50,7 +50,7 @@ plotPCA( title = "PCA", legendPosition = "bottom", labelSize = 2, - type = "raw" + type = c("pre-treated", "raw") ) } \arguments{ diff --git a/man/plotSupervisedRF.Rd b/man/plotSupervisedRF.Rd index 6a564fb9..401977ac 100644 --- a/man/plotSupervisedRF.Rd +++ b/man/plotSupervisedRF.Rd @@ -47,7 +47,7 @@ plotSupervisedRF( title = "", legendPosition = "bottom", labelSize = 2, - type = "raw" + type = c("pre-treated", "raw") ) } \arguments{ diff --git a/man/plotTIC.Rd b/man/plotTIC.Rd index 1a69454f..614eb81b 100644 --- a/man/plotTIC.Rd +++ b/man/plotTIC.Rd @@ -14,7 +14,7 @@ plotTIC(analysis, by = "injOrder", colour = "block", ...) analysis, by = "injOrder", colour = "block", - type = c("raw", "pre-treated") + type = c("pre-treated", "raw") ) } \arguments{ diff --git a/man/plotUnsupervisedRF.Rd b/man/plotUnsupervisedRF.Rd index 21d2fe3e..eecc0cb1 100644 --- a/man/plotUnsupervisedRF.Rd +++ b/man/plotUnsupervisedRF.Rd @@ -44,7 +44,7 @@ plotUnsupervisedRF( title = "", legendPosition = "bottom", labelSize = 2, - type = "raw" + type = c("pre-treated", "raw") ) } \arguments{ diff --git a/tests/testthat/test-analysisData.R b/tests/testthat/test-analysisData.R index 37a10828..118d0a53 100644 --- a/tests/testthat/test-analysisData.R +++ b/tests/testthat/test-analysisData.R @@ -153,5 +153,5 @@ test_that('number of features and samples correctly returned from Analysis',{ d <- metabolyse(abr1$neg[,columns],abr1$fact,p,verbose = FALSE) expect_equal(nFeatures(d),length(columns)) - expect_equal(nSamples(d),nrow(abr1$neg)) + expect_equal(nSamples(d,type = 'raw'),nrow(abr1$neg)) }) diff --git a/tests/testthat/test-info.R b/tests/testthat/test-info.R index f05f1414..6ae1d8fe 100644 --- a/tests/testthat/test-info.R +++ b/tests/testthat/test-info.R @@ -1,15 +1,15 @@ -library(metaboData) a <- new('Analysis') -raw(a) <- analysisData(abr1$neg,abr1$fact) +raw(a) <- analysisData(metaboData::abr1$neg, + metaboData::abr1$fact) context('sample information methods') test_that('clsAvailable works',{ - cl <- clsAvailable(a) - expect_true(is.character(cl)) - expect_length(cl,9) + cl <- clsAvailable(a,type = 'raw') + expect_true(is.character(cl)) + expect_length(cl,9) }) test_that('clsAvailable throws error when incorrect type specified',{ @@ -17,7 +17,10 @@ test_that('clsAvailable throws error when incorrect type specified',{ }) test_that('clsExtract works',{ - cl <- clsExtract(a,cls = 'class') + cl <- clsExtract( + a, + cls = 'class', + type = 'raw') expect_true(is.numeric(cl)) expect_length(cl,120) }) @@ -29,7 +32,10 @@ test_that('clsExtract errors when incorrect type specified',{ }) test_that('clsReplace works',{ - b <- clsReplace(a,rep(1,120),cls = 'class') + b <- clsReplace( + a,rep(1,120), + cls = 'class', + type = 'raw') i <- b %>% sinfo(type = 'raw') @@ -50,10 +56,16 @@ test_that('clsReplace errors when incorrect type specified',{ }) test_that('clsAdd works',{ - b <- clsAdd(a,'test',rep(1,120)) + b <- clsAdd( + a, + 'test', + rep(1,120), + type = 'raw') + i <- b %>% sinfo(type = 'raw') - expect_true('test' %in% clsAvailable(b)) + + expect_true('test' %in% clsAvailable(b,type = 'raw')) expect_equal(1,unique(i$test)) }) @@ -69,7 +81,7 @@ test_that('clsAdd errors when incorrect type specified',{ }) test_that('clsRemove works',{ - b <- clsRemove(a,'class') + b <- clsRemove(a,'class',type = 'raw') expect_false('class' %in% clsAvailable(b)) }) @@ -82,18 +94,19 @@ test_that('clsRemove errors when incorrect type specified',{ }) test_that('clsArrange works',{ - b <- clsArrange(a,'class') - expect_identical(clsExtract(a) %>% + b <- clsArrange(a,'class',type = 'raw') + expect_identical(clsExtract(a,type = 'raw') %>% sort(), - clsExtract(b)) + clsExtract(b,type = 'raw')) }) test_that('clsArrange works for decending arrangment',{ b <- clsArrange(a,'class', - descending = TRUE) - expect_identical(clsExtract(a) %>% + descending = TRUE, + type = 'raw') + expect_identical(clsExtract(a,type = 'raw') %>% sort(decreasing = TRUE), - clsExtract(b)) + clsExtract(b,type = 'raw')) }) test_that('clsArrange errors when incorrect type specified',{ @@ -101,8 +114,8 @@ test_that('clsArrange errors when incorrect type specified',{ }) test_that('clsRename works',{ - b <- clsRename(a,'rep','replicate') - expect_true('replicate' %in% clsAvailable(b)) + b <- clsRename(a,'rep','replicate',type = 'raw') + expect_true('replicate' %in% clsAvailable(b,type = 'raw')) }) test_that('clsRename errors when incorrect type specified',{ diff --git a/tests/testthat/test-metabolyse.R b/tests/testthat/test-metabolyse.R index db8ec15d..998dee20 100644 --- a/tests/testthat/test-metabolyse.R +++ b/tests/testthat/test-metabolyse.R @@ -22,8 +22,8 @@ test_that('metabolyse-works', { expect_true(isS4(analysis)) expect_true(class(analysis) == 'Analysis') - expect_equal(nFeatures(analysis),11) - expect_equal(nSamples(analysis),20) + expect_equal(nFeatures(analysis,type = 'raw'),11) + expect_equal(nSamples(analysis,type = 'raw'),20) expect_s3_class(metrics(analysis),'tbl_df') expect_s3_class(predictions(analysis),'tbl_df') @@ -34,4 +34,4 @@ test_that('metabolyse-works', { test_that('getPreTreatMethods errors if incorrect method specified',{ expect_error(getPreTreatMethods('incorrect')) -}) \ No newline at end of file +}) diff --git a/tests/testthat/test-plotTIC.R b/tests/testthat/test-plotTIC.R index b8810250..a42e1edf 100644 --- a/tests/testthat/test-plotTIC.R +++ b/tests/testthat/test-plotTIC.R @@ -7,8 +7,8 @@ test_that('plotTIC works',{ raw(d) <- analysisData(abr1$neg[,300:400],abr1$fact) - pl_scatter <- plotTIC(d,by = 'injorder',colour = 'day') - pl_boxplot <- plotTIC(d,by = 'day',colour = 'day') + pl_scatter <- plotTIC(d,by = 'injorder',colour = 'day',type = 'raw') + pl_boxplot <- plotTIC(d,by = 'day',colour = 'day',type = 'raw') expect_s3_class(pl_scatter,'ggplot') expect_s3_class(pl_boxplot,'ggplot') From 0b1808c80807a2e5fbf246bf1f131c40423080fa Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Wed, 25 Jan 2023 17:35:27 +0000 Subject: [PATCH 81/89] add the `value` argument to the explanatoryFeatures method of the Univariate and RandomForest classes to enable the selection of importance value on which to theshold --- R/modelling-accessors.R | 26 +++++++++++++----- R/modelling.R | 43 +++++++++++++++++++++--------- man/modelling-accessors.Rd | 17 +++++++++--- tests/testthat/test-randomForest.R | 8 ++++++ tests/testthat/test-univariate.R | 1 + 5 files changed, 73 insertions(+), 22 deletions(-) diff --git a/R/modelling-accessors.R b/R/modelling-accessors.R index 5c3decc0..8e5dfb25 100644 --- a/R/modelling-accessors.R +++ b/R/modelling-accessors.R @@ -5,6 +5,7 @@ #' @param cls sample information column to use #' @param metric importance metric for which to retrieve explanatory features #' @param threshold threshold below which explanatory features are extracted +#' @param value the importance value to threshold. See the usage section for possible values for each class. #' @param idx sample information column to use for sample names. If `NULL`, the sample row number will be used. Sample names should be unique for each row of data. #' @param ... arguments to parse to method for specific class #' @section Methods: @@ -431,26 +432,39 @@ setGeneric('explanatoryFeatures', function(x,...) #' @importFrom dplyr arrange setMethod('explanatoryFeatures',signature = 'Univariate', - function(x,threshold = 0.05){ + function(x,threshold = 0.05,value = c('adjusted.p.value','p.value')){ + + value <- match.arg( + value, + choices = c('adjusted.p.value', + 'p.value')) + importance(x) %>% - filter(adjusted.p.value < threshold) %>% - arrange(adjusted.p.value) + filter(.data[[value]] < threshold) %>% + arrange(.data[[value]]) } ) #' @rdname modelling-accessors setMethod('explanatoryFeatures',signature = 'RandomForest', - function(x,metric = 'false_positive_rate', threshold = 0.05){ + function(x,metric = 'false_positive_rate',value = c('value','p-value','adjusted_p-value'),threshold = 0.05){ + + value <- match.arg( + value, + choices = c('value', + 'p-value', + 'adjusted_p-value') + ) typ <- type(x) if (typ %in% c('unsupervised','classification')) { - explan <- explanatoryFeaturesClassification(x,metric,threshold) + explan <- explanatoryFeaturesClassification(x,metric,value,threshold) } if (typ == 'regression') { - explan <- explanatoryFeaturesRegression(x,metric,threshold) + explan <- explanatoryFeaturesRegression(x,metric,value,threshold) } return(explan) diff --git a/R/modelling.R b/R/modelling.R index 8314a1cd..f9ae8080 100644 --- a/R/modelling.R +++ b/R/modelling.R @@ -78,13 +78,18 @@ setMethod('modelling',signature = 'Analysis', } ) -explanatoryFeaturesClassification <- function(x,metric,threshold){ +explanatoryFeaturesClassification <- function(x,metric,value,threshold){ current_metric <- metric imp <- x %>% importance() + if (value != 'value' & !'p-value' %in% colnames(imp)){ + stop('p-values unavailable for this RandomForest class object. Use argument `perm` in randomForest() to for permutation testing to generate p-values.', + call. = FALSE) + } + metrics <- importanceMetrics(x) if (!(metric %in% metrics)) { @@ -92,7 +97,7 @@ explanatoryFeaturesClassification <- function(x,metric,threshold){ metrics <- str_c('"',metrics,'"') stop( - 'Argument "metric" should be one of ', + 'Argument `metric` should be one of ', str_c(metrics,collapse = ', '), call. = FALSE) } @@ -100,26 +105,31 @@ explanatoryFeaturesClassification <- function(x,metric,threshold){ explan <- imp %>% filter(metric == current_metric) - if (metric == 'false_positive_rate') { + if (metric == 'false_positive_rate' | value != 'value') { explan <- explan %>% - filter(value < threshold) %>% - arrange(value) + filter(.data[[value]] < threshold) %>% + arrange(!!sym(value)) } else { explan <- explan %>% - filter(value > threshold) %>% - arrange(desc(value)) + filter(.data[[value]] > threshold) %>% + arrange(desc(!!sym(value))) } return(explan) } -explanatoryFeaturesRegression <- function(x,metric,threshold){ +explanatoryFeaturesRegression <- function(x,metric,value,threshold){ current_metric <- metric imp <- x %>% importance() + if (value != 'value' & !'p-value' %in% colnames(imp)){ + stop('p-values unavailable for this RandomForest class object. Use argument `perm` in randomForest() to for permutation testing to generate p-values.', + call. = FALSE) + } + metrics <- importanceMetrics(x) if (!(metric %in% metrics)) { @@ -127,15 +137,22 @@ explanatoryFeaturesRegression <- function(x,metric,threshold){ metrics <- str_c('"',metrics,'"') stop( - 'Argument "metric" should be one of ', + 'Argument `metric` should be one of ', str_c(metrics,collapse = ', '), call. = FALSE) } - explan <- imp %>% - filter(metric == current_metric) %>% - filter(value > threshold) %>% - arrange(desc(value)) + if (value == 'value'){ + explan <- imp %>% + filter(metric == current_metric) %>% + filter(.data[[value]] > threshold) %>% + arrange(desc(!!sym(value))) + } else { + explan <- imp %>% + filter(metric == current_metric) %>% + filter(.data[[value]] < threshold) %>% + arrange(!!sym(value)) + } return(explan) } diff --git a/man/modelling-accessors.Rd b/man/modelling-accessors.Rd index 98deb87a..871da690 100644 --- a/man/modelling-accessors.Rd +++ b/man/modelling-accessors.Rd @@ -97,9 +97,18 @@ proximity(x, idx = NULL) explanatoryFeatures(x, ...) -\S4method{explanatoryFeatures}{Univariate}(x, threshold = 0.05) - -\S4method{explanatoryFeatures}{RandomForest}(x, metric = "false_positive_rate", threshold = 0.05) +\S4method{explanatoryFeatures}{Univariate}( + x, + threshold = 0.05, + value = c("adjusted.p.value", "p.value") +) + +\S4method{explanatoryFeatures}{RandomForest}( + x, + metric = "false_positive_rate", + value = c("value", "p-value", "adjusted_p-value"), + threshold = 0.05 +) \S4method{explanatoryFeatures}{list}(x, ...) @@ -116,6 +125,8 @@ explanatoryFeatures(x, ...) \item{threshold}{threshold below which explanatory features are extracted} +\item{value}{the importance value to threshold. See the usage section for possible values for each class.} + \item{metric}{importance metric for which to retrieve explanatory features} } \description{ diff --git a/tests/testthat/test-randomForest.R b/tests/testthat/test-randomForest.R index 35fcdfb4..8212fe18 100644 --- a/tests/testthat/test-randomForest.R +++ b/tests/testthat/test-randomForest.R @@ -14,6 +14,7 @@ test_that('unsupervised random forest works',{ test_that('random forest classification works',{ expect_warning(rf <- randomForest(d,cls = c('day','name'),perm = 2,returnModels = TRUE)) + rf_no_perm <- randomForest(d,cls = 'day') rf_metrics <- metrics(rf) rf_predictions <- predictions(rf) @@ -28,6 +29,7 @@ test_that('random forest classification works',{ expect_s3_class(rf_predictions,'tbl_df') expect_s3_class(rf_importance,'tbl_df') expect_s3_class(rf_proximity,'tbl_df') + expect_s3_class(explanatoryFeatures(rf,metric = 'MeanDecreaseAccuracy'),'tbl_df') expect_s3_class(metrics(rf_wrong),'tbl_df') expect_s3_class(predictions(rf_wrong),'tbl_df') @@ -40,6 +42,8 @@ test_that('random forest classification works',{ expect_equal(nrow(proximity(list(0,0))),0) expect_error(proximity(rf,idx = 'name')) + expect_error(explanatoryFeatures(rf,metric = 'wrong')) + expect_error(explanatoryFeatures(rf_no_perm,value = 'p-value')) }) test_that('binary classification works',{ @@ -59,11 +63,15 @@ test_that('classification throws an error when less than 2 classes available',{ test_that('random forest regression works',{ rf <- randomForest(d,cls = 'injorder',perm = 3,returnModels = TRUE) + rf_no_perm <- randomForest(d,cls = 'injorder') expect_s4_class(rf,'RandomForest') expect_identical(type(rf),'regression') expect_s3_class(metrics(rf),'tbl_df') expect_s3_class(importance(rf),'tbl_df') + expect_s3_class(explanatoryFeatures(rf,metric = "IncNodePurity",value = 'p-value'),'tbl_df') + expect_error(explanatoryFeatures(rf,metric = 'wrong')) + expect_error(explanatoryFeatures(rf_no_perm,value = 'p-value')) }) test_that('low sample permutation testing works',{ diff --git a/tests/testthat/test-univariate.R b/tests/testthat/test-univariate.R index cc1da131..b8fe0f57 100644 --- a/tests/testthat/test-univariate.R +++ b/tests/testthat/test-univariate.R @@ -14,6 +14,7 @@ test_that('anova works',{ expect_identical(class(i),c("tbl_df","tbl","data.frame")) expect_equal(ncol(i),10) expect_equal(nrow(i),51) + expect_identical(type(res),'ANOVA') }) test_that('ttest works',{ From d52082adb1476f2b142e7b3737ab986934663319 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Fri, 10 Feb 2023 10:51:27 +0000 Subject: [PATCH 82/89] Use the jasenfinch/missForest version of missForest --- DESCRIPTION | 1 + 1 file changed, 1 insertion(+) diff --git a/DESCRIPTION b/DESCRIPTION index f9851c70..99a3503e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -95,3 +95,4 @@ Collate: all-classes.R univariate.R modelling-accessors.R VignetteBuilder: knitr +Remotes: jasenfinch/missForest From 875aba00294aa9d7d4b1cdcf71f3632652697784 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Mon, 20 Feb 2023 12:22:17 +0000 Subject: [PATCH 83/89] plotFeature now correctly displays the cls name as the x-axis label --- NAMESPACE | 1 + R/plotFeature.R | 24 ++++++++++++------------ man/plotFeature.Rd | 5 ++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 2cc7206c..9f1a7e33 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -139,6 +139,7 @@ importFrom(dplyr,mutate_all) importFrom(dplyr,mutate_at) importFrom(dplyr,mutate_if) importFrom(dplyr,n) +importFrom(dplyr,pull) importFrom(dplyr,relocate) importFrom(dplyr,rename) importFrom(dplyr,rename_with) diff --git a/R/plotFeature.R b/R/plotFeature.R index 28c7933d..04df2bb4 100644 --- a/R/plotFeature.R +++ b/R/plotFeature.R @@ -9,9 +9,8 @@ #' @param type `raw` or `pre-treated` data to plot #' @param ... arguments to pass to the appropriate method #' @examples -#' library(metaboData) -#' -#' d <- analysisData(abr1$neg,abr1$fact) +#' d <- analysisData(metaboData::abr1$neg, +#' metaboData::abr1$fact) #' #' ## Plot a categorical response variable #' plotFeature(d,'N133',cls = 'day') @@ -34,6 +33,7 @@ setGeneric('plotFeature', #' @importFrom ggplot2 aes geom_point theme_bw element_text guides #' @importFrom ggplot2 scale_fill_manual xlab #' @importFrom methods is +#' @importFrom dplyr pull setMethod('plotFeature', signature = 'AnalysisData', @@ -43,6 +43,7 @@ setMethod('plotFeature', label = NULL, labelSize = 2){ + cls <- sym(cls) feat <- features(analysis) if (!feature %in% feat) { @@ -57,33 +58,33 @@ setMethod('plotFeature', i <- sinfo(analysis) i <- i %>% - select(Class = cls,Label = label) + select(!!cls,Label = label) if (!is.null(label)) { d <- d %>% bind_cols(i) %>% - gather('Feature','Intensity',-Class,-Label) %>% + gather('Feature','Intensity',-!!cls,-Label) %>% filter(Feature == feature) %>% mutate(Intensity = as.numeric(Intensity)) } else { d <- d %>% bind_cols(i) %>% - gather('Feature','Intensity',-Class) %>% + gather('Feature','Intensity',-!!cls) %>% filter(Feature == feature) %>% mutate(Intensity = as.numeric(Intensity)) } - if (is(i$Class,'character') | is(i$Class,'factor')) { + if (is(pull(i,!!cls),'character') | is(pull(i,!!cls),'factor')) { classes <- d %>% - select(Class) %>% + select(!!cls) %>% unique() %>% unlist() %>% length() pl <- d %>% - ggplot(aes(x = Class,y = Intensity,group = Class)) + + ggplot(aes(x = !!cls,y = Intensity,group = !!cls)) + geom_boxplot(outlier.shape = NA,colour = 'darkgrey') + - geom_point(aes(fill = Class),shape = 21,alpha = 0.8) + + geom_point(aes(fill = !!cls),shape = 21,alpha = 0.8) + theme_bw() + ggtitle(feature) + theme(axis.title = element_text(face = 'bold'), @@ -108,11 +109,10 @@ setMethod('plotFeature', } } else { pl <- d %>% - ggplot(aes(x = Class, y = Intensity)) + + ggplot(aes(x = !!cls, y = Intensity)) + geom_point(fill = ptol_pal()(1),shape = 21) + theme_bw() + ggtitle(feature) + - xlab(cls) + theme(axis.title = element_text(face = 'bold'), plot.title = element_text(face = 'bold', hjust = 0.5), diff --git a/man/plotFeature.Rd b/man/plotFeature.Rd index 26810142..e896f7a2 100644 --- a/man/plotFeature.Rd +++ b/man/plotFeature.Rd @@ -38,9 +38,8 @@ plotFeature(analysis, feature, cls = "class", label = NULL, labelSize = 2, ...) Plot the trend of a feature. } \examples{ -library(metaboData) - -d <- analysisData(abr1$neg,abr1$fact) +d <- analysisData(metaboData::abr1$neg, + metaboData::abr1$fact) ## Plot a categorical response variable plotFeature(d,'N133',cls = 'day') From 356f53e55e2207787810a5982fca5928a4cde2f5 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Mon, 20 Feb 2023 12:36:27 +0000 Subject: [PATCH 84/89] documentation fix --- R/randomForest.R | 2 +- man/randomForest.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/randomForest.R b/R/randomForest.R index 60e0bc22..1f8bcbc9 100644 --- a/R/randomForest.R +++ b/R/randomForest.R @@ -1,4 +1,4 @@ -#' Random forest analysis +#' Random forest #' @rdname randomForest #' @description Perform random forest on an `AnalysisData` object #' @param x S4 object of class `AnalysisData` diff --git a/man/randomForest.Rd b/man/randomForest.Rd index ea253fee..5de8aeef 100644 --- a/man/randomForest.Rd +++ b/man/randomForest.Rd @@ -3,7 +3,7 @@ \name{randomForest} \alias{randomForest} \alias{randomForest,AnalysisData-method} -\title{Random forest analysis} +\title{Random forest} \usage{ randomForest( x, From 79e686797618ad8c8e884a3b29bd0cdbbced8700 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Mon, 20 Feb 2023 13:51:25 +0000 Subject: [PATCH 85/89] Update the package NEWS --- NEWS.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/NEWS.md b/NEWS.md index 7336d921..94b44de7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,25 @@ +# metabolyseR 0.15.0 + +* It is now possible to specify multiple `cls` arguments to the [aggregation methods](https://jasenfinch.github.io/metabolyseR/reference/aggregate.html). + +* Correlation thresholds are now available for both coefficient and total number using the `minCoef` and `maxCor` arguments in the [`correlations()`](https://jasenfinch.github.io/metabolyseR/reference/correlations.html) method. + +* Added the [`predictions()`]() accessor method for the [`RandomForest`](https://jasenfinch.github.io/metabolyseR/reference/RandomForest-class.html) S4 class to enable the retrieval of the out of bag model response predictions. + +* The [occupancy filtering methods](https://jasenfinch.github.io/metabolyseR/reference/occupancyFilter.html) now error if the value supplied to argument `occupancy` is non-numeric. + +* Memory usage and performance improvements for the [`randomForest()`](https://jasenfinch.github.io/metabolyseR/reference/randomForest.html) method. + +* Added [`type()`](https://jasenfinch.github.io/metabolyseR/reference/modelling-accessors.html) and [`response()`](https://jasenfinch.github.io/metabolyseR/reference/modelling-accessors.html) methods for the [`Univariate`](https://jasenfinch.github.io/metabolyseR/reference/Univariate-class.html) S4 class. + +* [`plotLDA()`](https://jasenfinch.github.io/metabolyseR/reference/plotLDA.html) now returns a warning and skips plotting if an error is encountered during PC-LDA. + +* The value `pre-treated` is now the default for argument `type` in the [`Analysis`](https://jasenfinch.github.io/metabolyseR/reference/Analysis-class.html) S4 class [accessor methods](https://jasenfinch.github.io/metabolyseR/reference/analysis-accessors.html). + +* Added the `value` argument to the [`explanatoryFeatures()`](https://jasenfinch.github.io/metabolyseR/reference/modelling-accessors.html) method to allow the specification of on which importance value to apply the specified `threshold`. + +* The specified `cls` argument is now correctly displayed on the x-axis title of the resulting plots from the [`plotFeature()`](https://jasenfinch.github.io/metabolyseR/reference/plotFeature.html) method. + # metabolyseR 0.14.10 * Added the method [`predict()`](https://jasenfinch.github.io/metabolyseR/reference/predict.html) for the [`RandomForest`](https://jasenfinch.github.io/metabolyseR/reference/RandomForest-class.html) S4 class to predict model response values. From 093e784b0bce6940853d7e40380dbb8f9de80208 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Mon, 20 Feb 2023 14:07:12 +0000 Subject: [PATCH 86/89] Update README.md --- README.Rmd | 3 ++- man/figures/README-feature_plot-1.png | Bin 18479 -> 18253 bytes 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.Rmd b/README.Rmd index aab6536d..b6865845 100644 --- a/README.Rmd +++ b/README.Rmd @@ -9,7 +9,8 @@ knitr::opts_chunk$set(collapse = TRUE, comment = "#>", fig.align = 'center', fig.path = "man/figures/README-", - message = FALSE) + message = FALSE, + warning = FALSE) ``` # metabolyseR diff --git a/man/figures/README-feature_plot-1.png b/man/figures/README-feature_plot-1.png index 99176c10f7adee859c7201b4e048641d1d283d9f..3d94c6531b83d4a2ff84d9f4604d9aef4185e775 100644 GIT binary patch literal 18253 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 From 5871c989f9f7a0dc921d5136a2f7cd14834388b7 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Mon, 20 Feb 2023 14:31:14 +0000 Subject: [PATCH 87/89] vignette fixes --- inst/defaultParameters.yaml | 47 +++++++++++++++++-------------------- vignettes/modelling.Rmd | 3 ++- 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/inst/defaultParameters.yaml b/inst/defaultParameters.yaml index 77ac55e8..5f8a35d2 100644 --- a/inst/defaultParameters.yaml +++ b/inst/defaultParameters.yaml @@ -3,49 +3,44 @@ pre-treatment: occupancyFilter: cls: class QCidx: QC - occupancy: 0.667 + occupancy: 0.6666667 impute: cls: class QCidx: QC - occupancy: 0.667 + occupancy: 0.6666667 + parallel: variables + seed: 1234.0 RSDfilter: cls: class QCidx: QC - RSDthresh: 0.5 + RSDthresh: 50.0 removeQC: cls: class QCidx: QC - occupancyFilter: maximum: cls: class - occupancy: 0.667 - + occupancy: 0.6666667 impute: class: cls: class - occupancy: 0.667 - + occupancy: 0.6666667 + seed: 1234.0 transform: - TICnorm: - -classification: - cls: class - method: randomForest - pars: - sampling: boot - niter: 10 - nreps: 10 - strat: TRUE - -featureSelection: - method: fs.rf - cls: class - pars: - fs.rf: - nreps: 100 - + TICnorm: {} +modelling: + randomForest: + cls: class + rf: [] + reps: 1.0 + binary: no + comparisons: [] + perm: 0.0 + returnModels: no + seed: 1234.0 correlations: method: pearson pAdjustMethod: bonferroni corPvalue: 0.05 + minCoef: 0.0 + maxCor: .inf diff --git a/vignettes/modelling.Rmd b/vignettes/modelling.Rmd index d0f85349..d4110ea6 100644 --- a/vignettes/modelling.Rmd +++ b/vignettes/modelling.Rmd @@ -23,7 +23,8 @@ library(stringr) opts_chunk$set( collapse = TRUE, comment = "#>", - fig.align = 'center' + fig.align = 'center', + warning = FALSE ) ``` From 228b2dcf05fa58d9bafd455ee121e064344113d1 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Mon, 20 Feb 2023 15:35:58 +0000 Subject: [PATCH 88/89] check fix --- R/metabolyseR.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/metabolyseR.R b/R/metabolyseR.R index 75c70896..a6110325 100644 --- a/R/metabolyseR.R +++ b/R/metabolyseR.R @@ -9,5 +9,5 @@ globalVariables( 'x','.level','sensitivity','specificity','Mode','RSD','Median','Colour', 'Index','TIC','y','label','batch','correction','N','term','Metric','Frequency', '|coefficient|','idx_1','idx_2','.estimator','metric','fpr','p-value','obs','pred', - 'sample2','Feature','freq' + 'sample2','Feature','freq','.data' )) From b81658b778ef5a9233197c057bf921812fbe3ad4 Mon Sep 17 00:00:00 2001 From: jasenfinch Date: Mon, 20 Feb 2023 16:09:21 +0000 Subject: [PATCH 89/89] update github actions workflows --- .github/workflows/R-CMD-check.yaml | 19 +++++++++------- .github/workflows/pkgdown.yaml | 33 ++++++++++++++++++---------- .github/workflows/test-coverage.yaml | 32 ++++++++++++++++++++++----- DESCRIPTION | 2 +- README.Rmd | 2 +- README.md | 2 +- 6 files changed, 62 insertions(+), 28 deletions(-) diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index db4dceed..c21abc88 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -1,4 +1,4 @@ -# Workflow derived from https://github.com/r-lib/actions/tree/master/examples +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help on: push: @@ -18,7 +18,7 @@ jobs: fail-fast: false matrix: config: - - {os: macOS-latest, r: 'release'} + - {os: macos-latest, r: 'release'} - {os: windows-latest, r: 'release'} - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} - {os: ubuntu-latest, r: 'release'} @@ -29,18 +29,21 @@ jobs: R_KEEP_PKG_SOURCE: yes steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: r-lib/actions/setup-pandoc@v1 + - uses: r-lib/actions/setup-pandoc@v2 - - uses: r-lib/actions/setup-r@v1 + - uses: r-lib/actions/setup-r@v2 with: r-version: ${{ matrix.config.r }} http-user-agent: ${{ matrix.config.http-user-agent }} use-public-rspm: true - - uses: r-lib/actions/setup-r-dependencies@v1 + - uses: r-lib/actions/setup-r-dependencies@v2 with: - extra-packages: rcmdcheck + extra-packages: any::rcmdcheck + needs: check - - uses: r-lib/actions/check-r-package@v1 + - uses: r-lib/actions/check-r-package@v2 + with: + upload-snapshots: true diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index 63cbb18a..087f0b05 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -1,8 +1,10 @@ -# Workflow derived from https://github.com/r-lib/actions/tree/master/examples +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help on: push: branches: [main, master] + pull_request: + branches: [main, master] release: types: [published] workflow_dispatch: @@ -12,24 +14,33 @@ name: pkgdown jobs: pkgdown: runs-on: ubuntu-latest + # Only restrict concurrency for non-PR jobs + concurrency: + group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: r-lib/actions/setup-pandoc@v1 + - uses: r-lib/actions/setup-pandoc@v2 - - uses: r-lib/actions/setup-r@v1 + - uses: r-lib/actions/setup-r@v2 with: use-public-rspm: true - - uses: r-lib/actions/setup-r-dependencies@v1 + - uses: r-lib/actions/setup-r-dependencies@v2 with: - extra-packages: pkgdown + extra-packages: any::pkgdown, local::. needs: website - - name: Deploy package - run: | - git config --local user.name "$GITHUB_ACTOR" - git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" - Rscript -e 'pkgdown::deploy_to_branch(new_process = FALSE)' + - name: Build site + run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) + shell: Rscript {0} + + - name: Deploy to GitHub pages 🚀 + if: github.event_name != 'pull_request' + uses: JamesIves/github-pages-deploy-action@v4.4.1 + with: + clean: false + branch: gh-pages + folder: docs diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml index 3c0da1c9..2c5bb502 100644 --- a/.github/workflows/test-coverage.yaml +++ b/.github/workflows/test-coverage.yaml @@ -1,4 +1,4 @@ -# Workflow derived from https://github.com/r-lib/actions/tree/master/examples +# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help on: push: @@ -15,16 +15,36 @@ jobs: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: r-lib/actions/setup-r@v1 + - uses: r-lib/actions/setup-r@v2 with: use-public-rspm: true - - uses: r-lib/actions/setup-r-dependencies@v1 + - uses: r-lib/actions/setup-r-dependencies@v2 with: - extra-packages: covr + extra-packages: any::covr + needs: coverage - name: Test coverage - run: covr::codecov() + run: | + covr::codecov( + quiet = FALSE, + clean = FALSE, + install_path = file.path(Sys.getenv("RUNNER_TEMP"), "package") + ) shell: Rscript {0} + + - name: Show testthat output + if: always() + run: | + ## -------------------------------------------------------------------- + find ${{ runner.temp }}/package -name 'testthat.Rout*' -exec cat '{}' \; || true + shell: bash + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v3 + with: + name: coverage-test-failures + path: ${{ runner.temp }}/package diff --git a/DESCRIPTION b/DESCRIPTION index 99a3503e..9b1caa94 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -3,7 +3,7 @@ Title: Methods for Pre-Treatment, Data Mining and Correlation Analyses of Metabo Version: 0.15.0 Authors@R: person("Jasen", "Finch", email = "jsf9@aber.ac.uk", role = c("aut", "cre")) Description: A tool kit for pre-treatment, modelling, feature selection and correlation analyses of metabolomics data. -URL: https://jasenfinch.github.io/metabolyseR +URL: https://jasenfinch.github.io/metabolyseR/ BugReports: https://github.com/jasenfinch/metabolyseR/issues biocViews: Metabolomics Depends: R (>= 3.4.0) diff --git a/README.Rmd b/README.Rmd index b6865845..ea42b6b8 100644 --- a/README.Rmd +++ b/README.Rmd @@ -17,7 +17,7 @@ knitr::opts_chunk$set(collapse = TRUE, [![Lifecycle: stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable) -[![R-CMD-check](https://github.com/jasenfinch/metabolyseR/workflows/R-CMD-check/badge.svg)](https://github.com/jasenfinch/metabolyseR/actions) +[![R-CMD-check](https://github.com/jasenfinch/metabolyseR/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/jasenfinch/metabolyseR/actions/workflows/R-CMD-check.yaml) [![codecov](https://codecov.io/gh/jasenfinch/metabolyseR/branch/master/graph/badge.svg)](https://codecov.io/gh/jasenfinch/metabolyseR/branch/master) [![license](https://img.shields.io/badge/license-GNU%20GPL%20v3.0-blue.svg)](https://github.com/jasenfinch/metabolyseR/blob/master/DESCRIPTION) [![DOI](https://zenodo.org/badge/88983134.svg)](https://zenodo.org/badge/latestdoi/88983134) diff --git a/README.md b/README.md index bf986055..60582d11 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![Lifecycle: stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable) -[![R-CMD-check](https://github.com/jasenfinch/metabolyseR/workflows/R-CMD-check/badge.svg)](https://github.com/jasenfinch/metabolyseR/actions) +[![R-CMD-check](https://github.com/jasenfinch/metabolyseR/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/jasenfinch/metabolyseR/actions/workflows/R-CMD-check.yaml) [![codecov](https://codecov.io/gh/jasenfinch/metabolyseR/branch/master/graph/badge.svg)](https://codecov.io/gh/jasenfinch/metabolyseR/branch/master) [![license](https://img.shields.io/badge/license-GNU%20GPL%20v3.0-blue.svg)](https://github.com/jasenfinch/metabolyseR/blob/master/DESCRIPTION) [![DOI](https://zenodo.org/badge/88983134.svg)](https://zenodo.org/badge/latestdoi/88983134)