Mercurial > repos > eschen42 > w4mkmeans
view w4m_general_purpose_routines.R @ 2:c415b7dc6f37 draft default tip
planemo upload for repository https://github.com/HegemanLab/w4mkmeans_galaxy_wrapper/tree/master commit 3e916537da6bb37e6f3927d7a11e98e0ab6ef5ec
author | eschen42 |
---|---|
date | Mon, 05 Mar 2018 12:40:17 -0500 |
parents | 6ccbe18131a6 |
children |
line wrap: on
line source
##----------------------------------------------- ## helper functions for error detection/reporting ##----------------------------------------------- # ISO 8601 date ref: https://en.wikipedia.org/wiki/ISO_8601 iso_date <- function() { format(Sys.time(), "%Y-%m-%dT%H:%M:%S%z") } # log-printing to stderr log_print <- function(x, ...) { cat( sep="" , file=stderr() , iso_date() , " " , c(x, ...) , "\n" ) } # format error for logging format_error <- function(e) { paste(c("Error { message:", e$message, ", call:", e$call, "}"), collapse = " ") } # tryCatchFunc produces a list # func - a function that takes no arguments # On success of func(), tryCatchFunc produces # list(success = TRUE, value = func(), msg = "") # On failure of func(), tryCatchFunc produces # list(success = FALSE, value = NA, msg = "the error message") tryCatchFunc <- function(func) { retval <- NULL tryCatch( expr = { retval <- ( list( success = TRUE, value = func(), msg = "" ) ) } , error = function(e) { retval <<- list( success = FALSE, value = NA, msg = format_error(e) ) } ) return (retval) } # prepare.data.matrix - Prepare x.datamatrix for multivariate statistical analaysis (MVA) # - Motivation: # - Selection: # - You may want to exclude several samples from your analysis: # - If so, set the argument 'exclude.samples' to a vector of sample names # - You may want to exclude several features or features from your analysis: # - If so, set the argument 'exclude.features' to a vector of feature names # - Renaming samples: # - You may want to rename several samples from your analysis: # - If so, set the argument 'sample.rename.function' to a function accepting a vector # of sample names and producing a vector of strings of equivalent length # - MVA is confounded by missing values. # - By default, this function imputes missing values as zero. # - For a different imputation, set the 'data.imputation' argument to a function # accepting a single matrix argument and returning a matrix of the same # dimensions as the argument. # - Transformation # - It may be desirable to transform the intensity data to reduce the range. # - By default, this function performs an eigth-root transformation: # - Any root-tranformation has the advantage of never being negative. # - Calculation of the eight-root is four times faster in my hands than log10. # - However, it has the disadvantage that calculation of fold-differences # is not additive as with log-transformation. # - Rather, you must divide the values and raise to the eighth power. # - For a different transformation, set the 'data.transformation' argument # to a function accepting a single matrix argument. # - The function should be written to return a matrix of the same dimensions # as the argument. # arguments: # - x.matrix - matrix of intensities (or data.frame of sample metadata) # - one row per sample # - one column per feature or metadata attribute # - exclude.samples - vector of labels of matrix rows (samples) to omit from analysis # - exclude.features - vector of labels of matrix columnss (features) to omit from analysis # - sample.rename.function - function to be used to rename rows if necessary, or NULL # - e.g., sample.rename.function = function(x) { # sub("(.*)_.*","\\1", row.names(x)) # } # - data.imputation - function applied to matrix to impute missing values # - e.g., data.imputation = function(m) { # m[is.na(m)] <- min(m, na.rm = TRUE) / 100 # return (m) # } # - data.transformation - function applied to matrix cells # - e.g., data.transformation = function(x) { return( log10(x) ) } # or, data.transformation = log10 # result value: # transformed, imputed x.datamatrix with renamed rows and with neither excluded values nor features # ################################ ## ## Notes regarding the effectiveness and performance of the data transformation method. ## ## The two transformations that I tried (log10 and 8th root) required different imputation methods. ## ## For the LCMS resin data set that I was working with, separation in MVA was nearly equivalent for: ## data.imputation <- function(x.matrix) { ## x.matrix[is.na(x.matrix)] <- 0 ## return (x.matrix) ## } ## data.transformation <- function(x) { ## sqrt( sqrt( sqrt(x) ) ) ## } ## and ## data.imputation <- function(x.matrix) { ## x.matrix[is.na(x.matrix)] <- min(x.matrix, na.rm = TRUE) / 100 ## return (x.matrix) ## } ## data.transformation <- function(x) { ## log10(x) ## } ## ## Note further that triple application of the square root: ## - may be four times faster than log10: ## - may be three times faster than log2: ## ## system.time( junk <- sqrt( sqrt( sqrt(1:100000000) ) ) ) ## user system elapsed ## 0.832 0.236 1.069 ## system.time( junk <- log10(1:100000000) ) ## user system elapsed ## 3.936 0.400 4.337 ## system.time( junk <- log2(1:100000000) ) ## user system elapsed ## 2.784 0.320 3.101 ## ################################ # prepare.data.matrix <- function( x.matrix , exclude.samples = NULL , exclude.features = NULL , sample.rename.function = NULL , data.imputation = function(m) { # replace NA values with zero m[is.na(m)] <- 0 # replace negative values with zero, if applicable (It should never be applicable!) if (min(m < 0)) { m <- matrix(lapply(X = m, FUN = function(z) {max(z,0)}), nrow = nrow(m) ) } # return matrix as the result return (m) } , data.transformation = function(x) { sqrt( sqrt( sqrt(x) ) ) } , en = new.env() ) { # log to environment if ( !exists("log", envir = en) ) { en$log <- c() } enlog <- function(s) { en$log <- c(en$log, s); s } #enlog("foo") # MatVar - Compute variance of rows or columns of a matrix # ref: http://stackoverflow.com/a/25100036 # For row variance, dim == 1, for col variance, dim == 2 MatVar <- function(x, dim = 1) { if (dim == 1) { dim.x.2 <- dim(x)[2] if ( dim.x.2 == 0 ) stop("MatVar: there are zero columns") if ( dim.x.2 == 1 ) { stop("MatVar: a single column is insufficient to calculate a variance") # return ( rep.int(x = 0, times = nrow(x)) ) } else { return ( rowSums( (x - rowMeans(x))^2 ) / ( dim(x)[2] - 1 ) ) } } else if (dim == 2) { dim.x.1 <- dim(x)[1] if ( dim.x.1 == 0 ) { stop("MatVar: there are zero rows") } if ( dim.x.1 == 1 ) { stop("MatVar: a single row is insufficient to calculate a variance") # return ( rep.int(x = 0, times = ncol(x)) ) } else { return ( rowSums( (t(x) - colMeans(x))^2 ) / ( dim(x)[1] - 1 ) ) } } else stop("Please enter valid dimension, for rows, dim = 1; for colums, dim = 2") } nonzero.var <- function(x) { if (nrow(x) == 0) { stop("matrix has no rows") } if (ncol(x) == 0) { stop("matrix has no columns") } if ( is.numeric(x) ) { # exclude any rows with zero variance row.vars <- MatVar(x, dim = 1) nonzero.row.vars <- row.vars > 0 nonzero.rows <- row.vars[nonzero.row.vars] if ( length(rownames(x)) != length(rownames(nonzero.rows)) ) { row.names <- attr(nonzero.rows,"names") x <- x[ row.names, , drop = FALSE ] } # exclude any columns with zero variance column.vars <- MatVar(x, dim = 2) nonzero.column.vars <- column.vars > 0 nonzero.columns <- column.vars[nonzero.column.vars] if ( length(colnames(x)) != length(colnames(nonzero.columns)) ) { column.names <- attr(nonzero.columns,"names") x <- x[ , column.names, drop = FALSE ] } } return (x) } if (is.null(x.matrix)) { stop("FATAL ERROR - prepare.data.matrix was called with null x.matrix") } enlog("prepare.data.matrix - get matrix") en$xpre <- x <- x.matrix # exclude any samples as indicated if ( !is.null(exclude.features) ) { enlog("prepare.data.matrix - exclude any samples as indicated") my.colnames <- colnames(x) my.col.diff <- setdiff(my.colnames, exclude.features) x <- x[ , my.col.diff , drop = FALSE ] } # exclude any features as indicated if ( !is.null(exclude.samples) ) { enlog("prepare.data.matrix - exclude any features as indicated") my.rownames <- rownames(x) my.row.diff <- setdiff(my.rownames, exclude.samples) x <- x[ my.row.diff, , drop = FALSE ] } # rename rows if desired if ( !is.null(sample.rename.function) ) { enlog("prepare.data.matrix - rename rows if desired") renamed <- sample.rename.function(x) rownames(x) <- renamed } enlog("prepare.data.matrix - save redacted x.datamatrix to environment") # save redacted x.datamatrix to environment en$redacted.data.matrix <- x # impute values missing from the x.datamatrix if ( !is.null(data.imputation) ) { enlog("prepare.data.matrix - impute values missing from the x.datamatrix") x <- data.imputation(x) } # perform transformation if desired if ( !is.null(data.transformation) ) { enlog("prepare.data.matrix - perform transformation") x <- data.transformation(x) } else { x <- x } # purge rows and columns that have zero variance if ( is.numeric(x) ) { enlog("prepare.data.matrix - purge rows and columns that have zero variance") x <- nonzero.var(x) } # save imputed, transformed x.datamatrix to environment en$imputed.transformed.data.matrix <- x return(x) } # vim: sw=2 ts=2 et :