diff --git a/DESCRIPTION b/DESCRIPTION index e124018..bded706 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,8 +1,8 @@ Package: tableone Type: Package Title: Create 'Table 1' to Describe Baseline Characteristics -Version: 0.8.1 -Date: 2017-06-16 +Version: 0.9.0 +Date: 2017-11-03 Author: Kazuki Yoshida, Justin Bohn. Maintainer: Kazuki Yoshida Description: Creates 'Table 1', i.e., description of baseline patient @@ -20,7 +20,9 @@ Imports: e1071, zoo, gmodels, - nlme + nlme, + lmerTest, + labelled Suggests: survival, testthat, diff --git a/NEWS b/NEWS index 0daf499..be6cfdc 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,33 @@ +tableone 0.9.0 (2017-11-03) +---------------------------------------------------------------- + +NEW FEATURES + +* The "varLabels" option for the print.TableOne method was added. + When TRUE, instead of printing the variable names, their + corresponding variable labels are used. Variable labels must be + stored in the data frame to be used via labelled::var_label + function. This option is also available in ExtractSmd function. + +* The "dropEqual" option for the print methods was implemented. If + TRUE, the level description for two-level variables such as " = 1" + and " = TRUE" are not shown. This can obscure what level is being + shown depending on the variable naming scheme, thus, should only + be used after the initial results were checked for correctness. + +BUG FIXES + +* Handling of lme4 models was improved in ShowRegTable. + + +tableone 0.8.2 (2017-08-31) +---------------------------------------------------------------- + +BUG FIXES + +* Handle labelled class as categorical. + + tableone 0.8.1 (2017-06-17) ---------------------------------------------------------------- diff --git a/R/CreateTableOne.R b/R/CreateTableOne.R index 97ed3b9..e593a32 100644 --- a/R/CreateTableOne.R +++ b/R/CreateTableOne.R @@ -129,6 +129,10 @@ function(vars, # character vector of variab ## Abort if no variables exist at this point ModuleStopIfNoVarsLeft(vars) + ## Get variable labels (named list of label string or NULL) + ## Need to occur before applying factor(). + varLabels <- labelled::var_label(data[vars]) + ## Factor conversions if the factorVars argument exist if (!missing(factorVars)) { ## Check if variables exist. Drop them if not. @@ -149,7 +153,7 @@ function(vars, # character vector of variab ## Classify as varFactors if any one of these classes are contained varFactors <-sapply(varClasses, function(VEC) { - any(VEC %in% c("factor", "ordered", "logical", "character")) + any(VEC %in% c("factor", "ordered", "logical", "character", "labelled")) }) varFactors <- names(varFactors)[varFactors] @@ -243,7 +247,9 @@ function(vars, # character vector of variab varFactors = varFactors, varNumerics = varNumerics, ## Missing data percentage for each variable (no strata). - percentMissing = percentMissing)) + percentMissing = percentMissing, + ## Variable labels + varLabels = varLabels)) ## Give a class class(TableOneObject) <- "TableOne" diff --git a/R/ExtractSmd.R b/R/ExtractSmd.R index c5161ed..f0ebb5e 100644 --- a/R/ExtractSmd.R +++ b/R/ExtractSmd.R @@ -4,6 +4,8 @@ ##' ##' ##' @param x A stratified (svy)TableOne object containing standardized mean differences. +##' @param varLabels Whether to replace variable names with variable labels obtained from \code{labelled::var_label()} function. +##' ##' @return A vector or matrix containing the average standardized mean differences (if more than two contrasts exist) as well as the all possible pairwise standardized mean differences. Variables are ordered in the same order as the printed table. ##' @author Kazuki Yoshida ##' @seealso @@ -13,7 +15,7 @@ ##' ## See examples for CreateTableOne and svyCreateTableOne ##' ##' @export -ExtractSmd <- function(x) { +ExtractSmd <- function(x, varLabels = FALSE) { if (class(x)[1] %in% c("TableOne","svyTableOne")) { @@ -22,7 +24,20 @@ ExtractSmd <- function(x) { attr(x$CatTable, "smd")) ## Order by table variable order - matSmd[x$MetaData$vars,] + matSmd <- matSmd[x$MetaData$vars,] + + ## Use variable labels if requested. + if (varLabels) { + for (i in seq_along(x$MetaData$vars)) { + if (!is.null(x$MetaData$varLabels[[i]])) { + ## If the corresponding variable label is non-null replace + rownames(matSmd)[i] <- x$MetaData$varLabels[[i]] + } + } + } + + ## Return manipulated matrix + matSmd } else if (class(x)[1] %in% c("ContTable","svyContTable","CatTable","svyCatTable")) { diff --git a/R/ShowRegTable.R b/R/ShowRegTable.R index 1906188..6faf6b7 100644 --- a/R/ShowRegTable.R +++ b/R/ShowRegTable.R @@ -46,8 +46,9 @@ ShowRegTable <- function(model, exp = TRUE, digits = 2, pDigits = 3, printToggle ## nlme needs special handling ## Use column 2 because it is the point estimate modelCoef <- nlme::intervals(model)[[1]][, 2] - } else if (any(class(model) %in% c("lmerMod","glmerMod"))) { + } else if (any(class(model) %in% c("lmerMod","glmerMod","merModLmerTest"))) { ## (g)lmer gives confint for other extra parameters + ## lmerTest::lmer() gives a merModLmerTest object. modelCoef <- coef(summary(model))[,1] } else { modelCoef <- coef(model) @@ -58,17 +59,26 @@ ShowRegTable <- function(model, exp = TRUE, digits = 2, pDigits = 3, printToggle ## nlme needs special handling ## Drop column 2 because it is the point estimate modelConfInt <- nlme::intervals(model)[[1]][, -2] - } else if (any(class(model) %in% c("lmerMod","glmerMod"))) { - ## (g)lmer gives confint for other extra parameters + } else if (any(class(model) %in% c("lmerMod","glmerMod","merModLmerTest"))) { + ## (g)lmer gives confint for other extra parameters. + ## The bottom ones are for fixed effects. modelConfInt <- tail(suppressMessages(ciFun(model)), length(modelCoef)) } else { modelConfInt <- suppressMessages(ciFun(model)) } - ## P-value extraction + ## Extract p-values if (any(class(model) %in% c("gls", "lme"))) { ## nlme needs special handling modelSummaryMat <- summary(model)$tTable + } else if (any(class(model) %in% c("lmerMod"))) { + ## lmerMod does not have p-values, add NA's + modelSummaryMat <- coef(summary(model)) + modelSummaryMat <- cbind(modelSummaryMat, + rep(NA, nrow(modelSummaryMat))) + } else if (any(class(model) %in% c("merModLmerTest"))) { + ## Need to specify explicitly to invoke the correct summary method. + modelSummaryMat <- coef(lmerTest::summary(model)) } else { modelSummaryMat <- coef(summary(model)) } diff --git a/R/modules-print.R b/R/modules-print.R index f30a8ad..60c287b 100644 --- a/R/modules-print.R +++ b/R/modules-print.R @@ -322,7 +322,7 @@ ModuleContFormatStrata <- function(ContTable, nVars, listOfFunctions, digits) { ################################################################################ ## Module to loop over variables within a stratum formatting categorical variables -ModuleCatFormatVariables <- function(lstVars, varsToFormat, fmt, level, cramVars, showAllLevels) { +ModuleCatFormatVariables <- function(lstVars, varsToFormat, fmt, level, cramVars, dropEqual, showAllLevels) { ## Loop over variables within a stratum ## Each list element is a data frame summarizing levels @@ -378,9 +378,12 @@ ModuleCatFormatVariables <- function(lstVars, varsToFormat, fmt, level, cramVars DF[1,"crammedRowInd"] <- "crammed" } else { - ## Otherwise, keep the second level only - ## change variable name, and delete the first level. - DF$var <- sprintf("%s = %s", DF$var, DF$level) + ## Otherwise, keep the second level only. + ## Change variable name if dropEqual = FALSE. + if (!dropEqual) { + DF$var <- sprintf("%s = %s", DF$var, DF$level) + } + ## Delete the first level. DF <- DF[-1, , drop = FALSE] } @@ -412,7 +415,7 @@ ModuleCatFormatVariables <- function(lstVars, varsToFormat, fmt, level, cramVars ## Module to loop over strata formatting categorical variables -ModuleCatFormatStrata <- function(CatTable, digits, varsToFormat, cramVars, showAllLevels) { +ModuleCatFormatStrata <- function(CatTable, digits, varsToFormat, cramVars, dropEqual, showAllLevels) { ## Create format for percent used in the loop fmt1 <- paste0("%.", digits, "f") @@ -433,6 +436,7 @@ ModuleCatFormatStrata <- function(CatTable, digits, varsToFormat, cramVars, show varsToFormat = varsToFormat, fmt = fmt1, cramVars = cramVars, + dropEqual = dropEqual, showAllLevels = showAllLevels) @@ -632,7 +636,7 @@ ModuleFormatTables <- function(x, catDigits, contDigits, explain, pDigits, ## print.CatTable arguments passed format, exact, - showAllLevels, cramVars, + showAllLevels, cramVars, dropEqual, ## print.ContTable arguments passed nonnormal, minMax, insertLevel ) { @@ -680,6 +684,7 @@ ModuleFormatTables <- function(x, catDigits, contDigits, format = format, exact = exact, showAllLevels = showAllLevels, # Returns one more column if TRUE cramVars = cramVars, + dropEqual = dropEqual, ## print.ContTable arguments passed nonnormal = nonnormal, minMax = minMax, insertLevel = showAllLevels diff --git a/R/print.CatTable.R b/R/print.CatTable.R index 6245fb6..e98e878 100644 --- a/R/print.CatTable.R +++ b/R/print.CatTable.R @@ -13,6 +13,7 @@ ##' @param format The default is "fp" frequency (percentage). You can also choose from "f" frequency only, "p" percentage only, and "pf" percentage (frequency). ##' @param showAllLevels Whether to show all levels. FALSE by default, i.e., for 2-level categorical variables, only the higher level is shown to avoid redundant information. ##' @param cramVars A character vector to specify the two-level categorical variables, for which both levels should be shown in one row. +##' @param dropEqual Whether to drop " = second level name" description indicating which level is shown for two-level categorical variables. ##' @param test Whether to show p-values. TRUE by default. If FALSE, only the numerical summaries are shown. ##' @param exact A character vector to specify the variables for which the p-values should be those of exact tests. By default all p-values are from large sample approximation tests (chisq.test). ##' @param smd Whether to show standardized mean differences. FALSE by default. If there are more than one contrasts, the average of all possible standardized mean differences is shown. For individual contrasts, use \code{summary}. @@ -95,6 +96,7 @@ function(x, # CatTable object format = c("fp","f","p","pf")[1], # Format f_requency and/or p_ercent showAllLevels = FALSE, cramVars = NULL, # variables to be crammed into one row + dropEqual = FALSE, # Do not show " = second level" for two-level variables test = TRUE, # Whether to add p-values exact = NULL, # Which variables should be tested with exact tests @@ -163,6 +165,7 @@ function(x, # CatTable object digits = digits, varsToFormat = varsToFormat, cramVars = cramVars, + dropEqual = dropEqual, showAllLevels = showAllLevels) diff --git a/R/print.TableOne.R b/R/print.TableOne.R index 3901e73..1068bcd 100644 --- a/R/print.TableOne.R +++ b/R/print.TableOne.R @@ -14,9 +14,11 @@ ##' @param smd Whether to show standardized mean differences. FALSE by default. If there are more than one contrasts, the average of all possible standardized mean differences is shown. For individual contrasts, use \code{summary}. ##' @param noSpaces Whether to remove spaces added for alignment. Use this option if you prefer to align numbers yourself in other software. ##' @param padColnames Whether to pad column names with spaces to center justify. The default is FALSE. It is not conducted if noSpaces = TRUE. +##' @param varLabels Whether to replace variable names with variable labels obtained from \code{labelled::var_label()} function. ##' @param format The default is "fp" frequency (percentage). You can also choose from "f" frequency only, "p" percentage only, and "pf" percentage (frequency). ##' @param showAllLevels Whether to show all levels. FALSE by default, i.e., for 2-level categorical variables, only the higher level is shown to avoid redundant information. ##' @param cramVars A character vector to specify the two-level categorical variables, for which both levels should be shown in one row. +##' @param dropEqual Whether to drop " = second level name" description indicating which level is shown for two-level categorical variables. ##' @param exact A character vector to specify the variables for which the p-values should be those of exact tests. By default all p-values are from large sample approximation tests (chisq.test). ##' @param nonnormal A character vector to specify the variables for which the p-values should be those of nonparametric tests. By default all p-values are from normal assumption-based tests (oneway.test). ##' @param minMax Whether to use [min,max] instead of [p25,p75] for nonnormal variables. The default is FALSE. @@ -43,11 +45,13 @@ function(x, # TableOne object smd = FALSE, # Whether to add standardized mean differences noSpaces = FALSE, # Whether to remove spaces for alignments padColnames = FALSE, # Whether to pad column names for alignments + varLabels = FALSE, # Whether to show variable labels instead of names. ## Categorical options format = c("fp","f","p","pf")[1], # Format f_requency and/or p_ercent showAllLevels = FALSE, # Show all levels of a categorical variable cramVars = NULL, # Which 2-level variables to show both levels in one row + dropEqual = FALSE, # Do not show " = second level" for two-level variables exact = NULL, # Which variables should be tested with exact tests ## Continuous options @@ -67,6 +71,7 @@ function(x, # TableOne object ## Returns one more column if TRUE showAllLevels = showAllLevels, cramVars = cramVars, + dropEqual = dropEqual, ## print.ContTable arguments passed nonnormal = nonnormal, minMax = minMax, @@ -91,10 +96,32 @@ function(x, # TableOne object spcFmtEltTables <- ModuleAddSpacesToTable(FmtElementTables, nSpacesToAdd, showAllLevels) - ## Create a list of one variable tables excluding sample size row + ## Create a list of one variable tables excluding sample size row. + ## This is based on the variable order in the MetaData. lstOneVarTables <- ModuleListOfOneVarTables(spcFmtEltTables, MetaData = x$MetaData) + ## Replace variable names with variable labels if requested. + ## Loop over the variable replacing its name with its label. + if (varLabels) { + lstOneVarTables <- + lapply(seq_along(lstOneVarTables), + function(i) { + ## Each element is a string matrix. + mat <- lstOneVarTables[[i]] + ## Manipulate if a non-NULL label is available. + ## Note MetaData$varLabels is a list. + if (!is.null(x$MetaData$varLabels[[i]])) { + ## The first row name contains the variable name + ## without preceding space. Replace by exact matching. + rownames(mat)[1] <- gsub(paste0("^", x$MetaData$vars[i]), + x$MetaData$varLabels[[i]], + rownames(mat)[1]) + } + ## Return the entire matrix. + mat + }) + } ## Check if the first row is CatTable element ## if so, pick sample size row from space-padded CatTable element diff --git a/R/print.svyCatTable.R b/R/print.svyCatTable.R index 2c064d3..9eedcd3 100644 --- a/R/print.svyCatTable.R +++ b/R/print.svyCatTable.R @@ -13,6 +13,7 @@ ##' @param format The default is "fp" frequency (percentage). You can also choose from "f" frequency only, "p" percentage only, and "pf" percentage (frequency). ##' @param showAllLevels Whether to show all levels. FALSE by default, i.e., for 2-level categorical variables, only the higher level is shown to avoid redundant information. ##' @param cramVars A character vector to specify the two-level categorical variables, for which both levels should be shown in one row. +##' @param dropEqual Whether to drop " = second level name" description indicating which level is shown for two-level categorical variables. ##' @param test Whether to show p-values. TRUE by default. If FALSE, only the numerical summaries are shown. ##' @param exact This option is not available for tables from weighted data. ##' @param smd Whether to show standardized mean differences. FALSE by default. If there are more than one contrasts, the average of all possible standardized mean differences is shown. For individual contrasts, use \code{summary}. @@ -40,6 +41,7 @@ function(x, # CatTable object format = c("fp","f","p","pf")[1], # Format f_requency and/or p_ercent showAllLevels = FALSE, cramVars = NULL, # variables to be crammed into one row + dropEqual = FALSE, # Do not show " = second level" for two-level variables test = TRUE, # Whether to add p-values exact = NULL, # Which variables should be tested with exact tests @@ -109,6 +111,7 @@ function(x, # CatTable object digits = digits, varsToFormat = varsToFormat, cramVars = cramVars, + dropEqual = dropEqual, showAllLevels = showAllLevels) diff --git a/R/svyCreateTableOne.R b/R/svyCreateTableOne.R index 28af559..80821da 100644 --- a/R/svyCreateTableOne.R +++ b/R/svyCreateTableOne.R @@ -103,6 +103,10 @@ function(vars, # character vector of variable ## Abort if no variables exist at this point ModuleStopIfNoVarsLeft(vars) + ## Get variable labels (named list of label string or NULL) + ## Need to occur before applying factor(). + varLabels <- labelled::var_label(data$variables[vars]) + ## Factor conversions if the factorVars argument exist if (!missing(factorVars)) { ## Check if variables exist. Drop them if not. @@ -123,7 +127,7 @@ function(vars, # character vector of variable ## Classify as varFactors if any one of these classes are contained varFactors <- sapply(varClasses, function(VEC) { - any(VEC %in% c("factor", "ordered", "logical", "character")) + any(VEC %in% c("factor", "ordered", "logical", "character", "labelled")) }) varFactors <- names(varFactors)[varFactors] @@ -215,7 +219,9 @@ function(vars, # character vector of variable varFactors = varFactors, varNumerics = varNumerics, ## Missing data percentage for each variable (no strata). - percentMissing = percentMissing)) + percentMissing = percentMissing, + ## Variable labels + varLabels = varLabels)) ## Give a class class(TableOneObject) <- c("svyTableOne", "TableOne") diff --git a/README.md b/README.md index 82dbabe..59af7cb 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -tableone (release repo) +tableone (developmental repo) =============================================================================== -[![Travis-CI Build Status](https://travis-ci.org/kaz-yos/tableone.svg?branch=master)](https://travis-ci.org/kaz-yos/tableone) +[![Travis-CI Build Status](https://travis-ci.org/kaz-yos/tableone.svg?branch=develop)](https://travis-ci.org/kaz-yos/tableone) **An R package to create "Table 1", description of baseline characteristics** @@ -80,10 +80,21 @@ stage (%) 0.2 Installation ------------------------------------------------------------------------------- -This is the release version of the tableone package either to be released on CRAN or is already on CRAN. The installation can be done by the usual package installation via CRAN. +This version of tableone package for R is developmetal, and may not be available from the CRAN. You can install it using one of the following way. -- https://cran.r-project.org/package=tableone +**Direct installation from github** -If you prefer to follow the latest development, please see the developmetal repo: +You first need to install the devtools package to do the following. You can choose from the latest stable version and the latest development version. -- https://github.com/kaz-yos/tableone/tree/develop +``` + +## Install devtools (if you do not have it already) +> install.packages("devtools") +## Install directly from github (develop branch) +> devtools::install_github(repo = "kaz-yos/tableone", ref = "develop") + +``` + +Using devtools may requires some preparation, please see the following link for information. + +http://www.rstudio.com/projects/devtools/ diff --git a/cran-check.txt b/cran-check.txt index 58d77f9..2467a8b 100644 --- a/cran-check.txt +++ b/cran-check.txt @@ -1,11 +1,11 @@ * using log directory ‘/Users/kazuki/Documents/programming/r/tableone/tableone.Rcheck’ -* using R version 3.4.0 (2017-04-21) +* using R version 3.4.2 (2017-09-28) * using platform: x86_64-apple-darwin15.6.0 (64-bit) * using session charset: UTF-8 * using option ‘--as-cran’ * checking for file ‘tableone/DESCRIPTION’ ... OK * checking extension type ... Package -* this is package ‘tableone’ version ‘0.8.1’ +* this is package ‘tableone’ version ‘0.9.0’ * checking CRAN incoming feasibility ... Note_to_CRAN_maintainers Maintainer: ‘Kazuki Yoshida ’ * checking package namespace information ... OK diff --git a/cran-comment.md b/cran-comment.md index 9b0d5c5..cdc7246 100644 --- a/cran-comment.md +++ b/cran-comment.md @@ -1,18 +1,31 @@ ## What's new The following changes are included. -tableone 0.8.1 (2017-06-17) +tableone 0.9.0 (2017-11-03) ---------------------------------------------------------------- -BUG FIX -* Fix alignment issue with the Missing column. Note currently the - percentage is shown with 1 decimal and this is hard-coded. -* Change vignetteBuilder to knitr to form the index correctly. -* Single-quote package names in DESCRIPTION. + +NEW FEATURES + +* The "varLabels" option for the print.TableOne method was added. + When TRUE, instead of printing the variable names, their + corresponding variable labels are used. Variable labels must be + stored in the data frame to be used via labelled::var_label + function. This option is also available in ExtractSmd function. + +* The "dropEqual" option for the print methods was implemented. If + TRUE, the level description for two-level variables such as " = 1" + and " = TRUE" are not shown. This can obscure what level is being + shown depending on the variable naming scheme, thus, should only + be used after the initial results were checked for correctness. + +BUG FIXES + +* Handling of lme4 models was improved in ShowRegTable. ## Test environments -* Local OS X 10.12.5, R 3.4.0 -* Ubuntu Linux on Travis-CI (oldrel, release, and devel) +* Local OS X 10.12.6, R 3.4.2 +* Ubuntu Linux on Travis-CI (release and devel) * win-builder (release and devel) diff --git a/man/ExtractSmd.Rd b/man/ExtractSmd.Rd index dc2d4f8..9d8cb50 100644 --- a/man/ExtractSmd.Rd +++ b/man/ExtractSmd.Rd @@ -4,10 +4,12 @@ \alias{ExtractSmd} \title{Extract standardized mean differences from a (svy)TableOne object} \usage{ -ExtractSmd(x) +ExtractSmd(x, varLabels = FALSE) } \arguments{ \item{x}{A stratified (svy)TableOne object containing standardized mean differences.} + +\item{varLabels}{Whether to replace variable names with variable labels obtained from \code{labelled::var_label()} function.} } \value{ A vector or matrix containing the average standardized mean differences (if more than two contrasts exist) as well as the all possible pairwise standardized mean differences. Variables are ordered in the same order as the printed table. diff --git a/man/print.CatTable.Rd b/man/print.CatTable.Rd index dd8021b..2097ac8 100644 --- a/man/print.CatTable.Rd +++ b/man/print.CatTable.Rd @@ -7,8 +7,8 @@ \method{print}{CatTable}(x, digits = 1, pDigits = 3, quote = FALSE, missing = FALSE, explain = TRUE, printToggle = TRUE, noSpaces = FALSE, format = c("fp", "f", "p", "pf")[1], showAllLevels = FALSE, - cramVars = NULL, test = TRUE, exact = NULL, smd = FALSE, - CrossTable = FALSE, ...) + cramVars = NULL, dropEqual = FALSE, test = TRUE, exact = NULL, + smd = FALSE, CrossTable = FALSE, ...) } \arguments{ \item{x}{Object returned by \code{\link{CreateCatTable}} function.} @@ -33,6 +33,8 @@ \item{cramVars}{A character vector to specify the two-level categorical variables, for which both levels should be shown in one row.} +\item{dropEqual}{Whether to drop " = second level name" description indicating which level is shown for two-level categorical variables.} + \item{test}{Whether to show p-values. TRUE by default. If FALSE, only the numerical summaries are shown.} \item{exact}{A character vector to specify the variables for which the p-values should be those of exact tests. By default all p-values are from large sample approximation tests (chisq.test).} diff --git a/man/print.TableOne.Rd b/man/print.TableOne.Rd index 66012f7..2d76ca7 100644 --- a/man/print.TableOne.Rd +++ b/man/print.TableOne.Rd @@ -7,8 +7,9 @@ \method{print}{TableOne}(x, catDigits = 1, contDigits = 2, pDigits = 3, quote = FALSE, missing = FALSE, explain = TRUE, printToggle = TRUE, test = TRUE, smd = FALSE, noSpaces = FALSE, padColnames = FALSE, - format = c("fp", "f", "p", "pf")[1], showAllLevels = FALSE, - cramVars = NULL, exact = NULL, nonnormal = NULL, minMax = FALSE, ...) + varLabels = FALSE, format = c("fp", "f", "p", "pf")[1], + showAllLevels = FALSE, cramVars = NULL, dropEqual = FALSE, + exact = NULL, nonnormal = NULL, minMax = FALSE, ...) } \arguments{ \item{x}{Object returned by \code{\link{CreateTableOne}} function.} @@ -35,12 +36,16 @@ \item{padColnames}{Whether to pad column names with spaces to center justify. The default is FALSE. It is not conducted if noSpaces = TRUE.} +\item{varLabels}{Whether to replace variable names with variable labels obtained from \code{labelled::var_label()} function.} + \item{format}{The default is "fp" frequency (percentage). You can also choose from "f" frequency only, "p" percentage only, and "pf" percentage (frequency).} \item{showAllLevels}{Whether to show all levels. FALSE by default, i.e., for 2-level categorical variables, only the higher level is shown to avoid redundant information.} \item{cramVars}{A character vector to specify the two-level categorical variables, for which both levels should be shown in one row.} +\item{dropEqual}{Whether to drop " = second level name" description indicating which level is shown for two-level categorical variables.} + \item{exact}{A character vector to specify the variables for which the p-values should be those of exact tests. By default all p-values are from large sample approximation tests (chisq.test).} \item{nonnormal}{A character vector to specify the variables for which the p-values should be those of nonparametric tests. By default all p-values are from normal assumption-based tests (oneway.test).} diff --git a/man/print.svyCatTable.Rd b/man/print.svyCatTable.Rd index 7180298..f98f05b 100644 --- a/man/print.svyCatTable.Rd +++ b/man/print.svyCatTable.Rd @@ -7,8 +7,8 @@ \method{print}{svyCatTable}(x, digits = 1, pDigits = 3, quote = FALSE, missing = FALSE, explain = TRUE, printToggle = TRUE, noSpaces = FALSE, format = c("fp", "f", "p", "pf")[1], showAllLevels = FALSE, - cramVars = NULL, test = TRUE, exact = NULL, smd = FALSE, - CrossTable = FALSE, ...) + cramVars = NULL, dropEqual = FALSE, test = TRUE, exact = NULL, + smd = FALSE, CrossTable = FALSE, ...) } \arguments{ \item{x}{The result of a call to the \code{\link{svyCreateCatTable}} function.} @@ -33,6 +33,8 @@ \item{cramVars}{A character vector to specify the two-level categorical variables, for which both levels should be shown in one row.} +\item{dropEqual}{Whether to drop " = second level name" description indicating which level is shown for two-level categorical variables.} + \item{test}{Whether to show p-values. TRUE by default. If FALSE, only the numerical summaries are shown.} \item{exact}{This option is not available for tables from weighted data.} diff --git a/tableone.Rcheck/tableone-Ex.Rout b/tableone.Rcheck/tableone-Ex.Rout index d53cdb1..c8ce6bc 100644 --- a/tableone.Rcheck/tableone-Ex.Rout +++ b/tableone.Rcheck/tableone-Ex.Rout @@ -1,5 +1,5 @@ -R version 3.4.0 (2017-04-21) -- "You Stupid Darkness" +R version 3.4.2 (2017-09-28) -- "Short Summer" Copyright (C) 2017 The R Foundation for Statistical Computing Platform: x86_64-apple-darwin15.6.0 (64-bit) @@ -3166,8 +3166,9 @@ _U_s_a_g_e: print(x, catDigits = 1, contDigits = 2, pDigits = 3, quote = FALSE, missing = FALSE, explain = TRUE, printToggle = TRUE, test = TRUE, smd = FALSE, noSpaces = FALSE, padColnames = FALSE, - format = c("fp", "f", "p", "pf")[1], showAllLevels = FALSE, - cramVars = NULL, exact = NULL, nonnormal = NULL, minMax = FALSE, ...) + varLabels = FALSE, format = c("fp", "f", "p", "pf")[1], + showAllLevels = FALSE, cramVars = NULL, dropEqual = FALSE, + exact = NULL, nonnormal = NULL, minMax = FALSE, ...) _A_r_g_u_m_e_n_t_s: @@ -3207,6 +3208,9 @@ noSpaces: Whether to remove spaces added for alignment. Use this option padColnames: Whether to pad column names with spaces to center justify. The default is FALSE. It is not conducted if noSpaces = TRUE. +varLabels: Whether to replace variable names with variable labels + obtained from ‘labelled::var_label()’ function. + format: The default is "fp" frequency (percentage). You can also choose from "f" frequency only, "p" percentage only, and "pf" percentage (frequency). @@ -3218,6 +3222,10 @@ showAllLevels: Whether to show all levels. FALSE by default, i.e., for cramVars: A character vector to specify the two-level categorical variables, for which both levels should be shown in one row. +dropEqual: Whether to drop " = second level name" description + indicating which level is shown for two-level categorical + variables. + exact: A character vector to specify the variables for which the p-values should be those of exact tests. By default all p-values are from large sample approximation tests @@ -3316,7 +3324,7 @@ detaching ‘package:survey’, ‘package:survival’, ‘package:Matrix’, > ### > options(digits = 7L) > base::cat("Time elapsed: ", proc.time() - base::get("ptime", pos = 'CheckExEnv'),"\n") -Time elapsed: 9.407 0.276 9.755 0.006 0.005 +Time elapsed: 5.798 0.292 6.183 0.004 0.006 > grDevices::dev.off() null device 1 diff --git a/test-all.txt b/test-all.txt index 01fcb09..4235d2b 100644 --- a/test-all.txt +++ b/test-all.txt @@ -164,7 +164,131 @@ Unit tests for the CreateTableOne function: ....................... 2 35 (22.2) 32 ( 20.8) 3 56 (35.4) 64 ( 41.6) 4 55 (34.8) 54 ( 35.1) -. Stratified by trt +. + Overall + n 418 + time (mean (sd)) 1917.78 (1104.67) + status (%) + 0 232 (55.5) + 1 25 ( 6.0) + 2 161 (38.5) + age (mean (sd)) 50.74 (10.45) + sex = f (%) 374 (89.5) + ascites = 1 (%) 24 ( 7.7) + hepato = 1 (%) 160 (51.3) + spiders = 1 (%) 90 (28.8) + edema (%) + 0 354 (84.7) + 0.5 44 (10.5) + 1 20 ( 4.8) + bili (mean (sd)) 3.22 (4.41) + chol (mean (sd)) 369.51 (231.94) + albumin (mean (sd)) 3.50 (0.42) + copper (mean (sd)) 97.65 (85.61) + alk.phos (mean (sd)) 1982.66 (2140.39) + ast (mean (sd)) 122.56 (56.70) + trig (mean (sd)) 124.70 (65.15) + platelet (mean (sd)) 257.02 (98.33) + protime (mean (sd)) 10.73 (1.02) + stage (%) + 1 21 ( 5.1) + 2 92 (22.3) + 3 155 (37.6) + 4 144 (35.0) + + Overall + n 418 + time (mean (sd)) 1917.78 (1104.67) + status (%) + 0 232 (55.5) + 1 25 ( 6.0) + 2 161 (38.5) + age (mean (sd)) 50.74 (10.45) + sex (%) 374 (89.5) + ascites (%) 24 ( 7.7) + hepato (%) 160 (51.3) + spiders (%) 90 (28.8) + edema (%) + 0 354 (84.7) + 0.5 44 (10.5) + 1 20 ( 4.8) + bili (mean (sd)) 3.22 (4.41) + chol (mean (sd)) 369.51 (231.94) + albumin (mean (sd)) 3.50 (0.42) + copper (mean (sd)) 97.65 (85.61) + alk.phos (mean (sd)) 1982.66 (2140.39) + ast (mean (sd)) 122.56 (56.70) + trig (mean (sd)) 124.70 (65.15) + platelet (mean (sd)) 257.02 (98.33) + protime (mean (sd)) 10.73 (1.02) + stage (%) + 1 21 ( 5.1) + 2 92 (22.3) + 3 155 (37.6) + 4 144 (35.0) +..... + Overall + n 418 + time (mean (sd)) 1917.78 (1104.67) + status (%) + 0 232 (55.5) + 1 25 ( 6.0) + 2 161 (38.5) + age (mean (sd)) 50.74 (10.45) + sex = f (%) 374 (89.5) + ascites = 1 (%) 24 ( 7.7) + hepato = 1 (%) 160 (51.3) + spiders = 1 (%) 90 (28.8) + edema (%) + 0 354 (84.7) + 0.5 44 (10.5) + 1 20 ( 4.8) + bili (mean (sd)) 3.22 (4.41) + chol (mean (sd)) 369.51 (231.94) + albumin (mean (sd)) 3.50 (0.42) + copper (mean (sd)) 97.65 (85.61) + alk.phos (mean (sd)) 1982.66 (2140.39) + ast (mean (sd)) 122.56 (56.70) + trig (mean (sd)) 124.70 (65.15) + platelet (mean (sd)) 257.02 (98.33) + protime (mean (sd)) 10.73 (1.02) + stage (%) + 1 21 ( 5.1) + 2 92 (22.3) + 3 155 (37.6) + 4 144 (35.0) + + Overall + n 418 + time (mean (sd)) 1917.78 (1104.67) + status (%) + 0 232 (55.5) + 1 25 ( 6.0) + 2 161 (38.5) + Age in Years (mean (sd)) 50.74 (10.45) + Female Sex = f (%) 374 (89.5) + ascites = 1 (%) 24 ( 7.7) + hepato = 1 (%) 160 (51.3) + spiders = 1 (%) 90 (28.8) + edema (%) + 0 354 (84.7) + 0.5 44 (10.5) + 1 20 ( 4.8) + bili (mean (sd)) 3.22 (4.41) + chol (mean (sd)) 369.51 (231.94) + albumin (mean (sd)) 3.50 (0.42) + copper (mean (sd)) 97.65 (85.61) + alk.phos (mean (sd)) 1982.66 (2140.39) + ast (mean (sd)) 122.56 (56.70) + trig (mean (sd)) 124.70 (65.15) + platelet (mean (sd)) 257.02 (98.33) + protime (mean (sd)) 10.73 (1.02) + Stage of the Disease (%) + 1 21 ( 5.1) + 2 92 (22.3) + 3 155 (37.6) + 4 144 (35.0) +........ Stratified by trt 1 2 p test n 158 154 time (mean (sd)) 2015.62 (1094.12) 1996.86 (1155.93) 0.883 @@ -1994,11 +2118,16 @@ day 0.96758 [0.96225, 0.97295] <0.001 (Intercept) 2.70219 [2.51140, 2.89298] <0.001 trt -0.36806 [-0.57681, -0.15930] 0.001 day -0.06464 [-0.07910, -0.05017] <0.001 -.. coef [confint] p -(Intercept) 2.70219 [2.51320, 2.89118] 27.917 -trt -0.36806 [-0.57306, -0.16305] -3.516 -day -0.06464 [-0.07905, -0.05022] -8.807 -.. exp(coef) [confint] p +..### The lme4 version is 1.1-15 + coef [confint] p +(Intercept) 2.70219 [2.51320, 2.89118] NA +trt -0.36806 [-0.57306, -0.16305] NA +day -0.06464 [-0.07905, -0.05022] NA +.. coef [confint] p +(Intercept) 2.70219 [2.51320, 2.89118] <0.001 +trt -0.36806 [-0.57306, -0.16305] 0.001 +day -0.06464 [-0.07905, -0.05022] <0.001 +... exp(coef) [confint] p (Intercept) 2.82371 [2.31045, 3.43231] <0.001 trt 0.82903 [0.70232, 0.97777] 0.026 day 0.96758 [0.94787, 0.98762] 0.002 diff --git a/tests/testthat/test-CreateTableOne.R b/tests/testthat/test-CreateTableOne.R index 7184c0c..6ef0739 100644 --- a/tests/testthat/test-CreateTableOne.R +++ b/tests/testthat/test-CreateTableOne.R @@ -5,19 +5,21 @@ ## Author: Kazuki Yoshida ################################################################################ -### Structure -## expectations within tests within context - +### ### Prepare environment ################################################################################ library(testthat) + +### ### Context (1 for each file) +################################################################################ context("Unit tests for the CreateTableOne function") +### ### Load data - +################################################################################ library(survival) data(pbc) @@ -33,7 +35,10 @@ vars <- c("time","status","age","sex","ascites","hepato", varsContOnly <- c("time","age","protime") varsCatOnly <- c("status","trt","sex") + +### ### Tests for data checkers +################################################################################ test_that("abnormal data are correctly detected", { @@ -65,7 +70,9 @@ test_that("abnormal data are correctly detected", { }) +### ### Tests for ModuleTestSafe, a wrapper for test functions such as oneway.test and chisq.test +################################################################################ ## Create a dataset for a table dat <- read.table(header = TRUE, text = " @@ -134,8 +141,8 @@ test_that("P-values should be NA for 1xM xtabs", { }) - -### Regression tests +### +### Table construction and printing tests ################################################################################ ## Create a table to test @@ -218,6 +225,72 @@ test_that("Missing percentages are correctly stored and printed", { }) +test_that("dropEqual options correctly retail two-level categorical variable names", { + + ## Default table matrix + mat_default <- print(pbcOverall) + mat_modified <- mat_default + ## Drop " = 1" etc by regex + rownames(mat_modified) <- gsub(" = .* \\(", " (", rownames(mat_modified)) + + ## dropEqual = TRUE to avoid creation of " = 1" + mat_dropEqual <- print(pbcOverall, dropEqual = TRUE) + + ## Expectations + ## These must differ. + expect_false(identical(mat_default, mat_modified)) + expect_false(identical(rownames(mat_default), rownames(mat_modified))) + expect_false(all(rownames(mat_default) == rownames(mat_modified))) + ## These must match. + expect_equal(rownames(mat_modified), rownames(mat_dropEqual)) + expect_equal(mat_modified, mat_dropEqual) +}) + + +test_that("variable labels are correctly shown", { + + ## Construct a dataset with some variable labels. + pbc_labeled <- pbc + ## Continuous + age_label <- "Age in Years" + ## Two-level categorical + sex_label <- "Female Sex" + ## Multi-level categorical + stage_label <- "Stage of the Disease" + ## Apply labels + labelled::var_label(pbc_labeled$age) <- age_label + labelled::var_label(pbc_labeled$sex) <- sex_label + labelled::var_label(pbc_labeled$stage) <-stage_label + ## Show + labelled::var_label(pbc_labeled) + + ## Construct a TableOne object. + ## Using factorVars should not break + pbcOverall <- CreateTableOne(vars = vars, data = pbc_labeled, factorVars = "stage") + + mat_default <- print(pbcOverall) + mat_labelled <- print(pbcOverall, varLabels = TRUE) + + ## Expectations + ## These must differ. + expect_false(identical(mat_default, mat_labelled)) + expect_false(identical(rownames(mat_default), rownames(mat_labelled))) + ## These labels should not exist in the original row names. + expect_true(sum(grepl(age_label, rownames(mat_default))) == 0) + expect_true(sum(grepl(sex_label, rownames(mat_default))) == 0) + expect_true(sum(grepl(stage_label, rownames(mat_default))) == 0) + ## These labels should appear only once in labelled table. + expect_true(sum(grepl(age_label, rownames(mat_labelled))) == 1) + expect_true(sum(grepl(sex_label, rownames(mat_labelled))) == 1) + expect_true(sum(grepl(stage_label, rownames(mat_labelled))) == 1) + +}) + + +### +### Regression tests for the print method +################################################################################ + test_that("printing of a TableOne object does not regress", { ## Expectations @@ -357,6 +430,9 @@ test_that("printing of a TableOne$ContTable object do not regress", { }) +### +### Tests for the summary method +################################################################################ test_that("summary method works without errors", { ## Expectations diff --git a/tests/testthat/test-ShowRegTable.R b/tests/testthat/test-ShowRegTable.R index ad20086..7fe6042 100644 --- a/tests/testthat/test-ShowRegTable.R +++ b/tests/testthat/test-ShowRegTable.R @@ -183,42 +183,81 @@ test_that("nlme works", { ### lme4 test_that("lme4 works", { - library(lme4) - - ## Linear LME - lmer1 <- lmer(formula = y ~ trt + day + (1 | id), - data = koch) - - ciLmer1 <- tail(confint(lmer1), nrow(coef(summary(lmer1)))) - - ## confint - ShowRegTable(lmer1, digits = 5, exp = FALSE) - expect_output(ShowRegTable(lmer1, digits = 5, exp = FALSE), - sprintf("%.5f, %.5f", - ciLmer1[2,1], - ciLmer1[2,2])) - - ## coef - expect_output(ShowRegTable(lmer1, digits = 5, exp = FALSE), - sprintf("%.5f", coef(summary(lmer1))[2,1])) - - - ## GLMM - glmer1 <- glmer(formula = y ~ trt + day + (1 | id), - data = koch, - family = poisson(link = "log")) - ## Last rows correspond to fixed effects - ciGlmer1 <- tail(confint(glmer1), nrow(coef(summary(lmer1)))) - - ## confint - ShowRegTable(glmer1, digits = 5, exp = TRUE) - expect_output(ShowRegTable(glmer1, digits = 5, exp = TRUE), - sprintf("%.5f, %.5f", - exp(ciGlmer1[2,1]), - exp(ciGlmer1[2,2]))) - - ## coef - expect_output(ShowRegTable(glmer1, digits = 5, exp = TRUE), - sprintf("%.5f", exp(coef(summary(glmer1)))[2,1])) - + cat("### The lme4 version is ", installed.packages()["lme4","Version"], "\n") + + if (installed.packages()["lme4","Version"] == "1.1-14") { + cat("### Due to the issues with lme4 1.1-14. The relevant test are skipped.\n") + } + + ## Do not test in version 1.1-14 to avoid warnings. + ## https://github.com/lme4/lme4/issues/440 + if (installed.packages()["lme4","Version"] != "1.1-14") { + library(lme4) + + ## Linear LME + lmer1 <- lmer(formula = y ~ trt + day + (1 | id), + data = koch) + + ciLmer1 <- tail(confint(lmer1), nrow(coef(summary(lmer1)))) + summary(lmer1) + + ## confint + ShowRegTable(lmer1, digits = 5, exp = FALSE) + expect_output(ShowRegTable(lmer1, digits = 5, exp = FALSE), + sprintf("%.5f, %.5f", + ciLmer1[2,1], + ciLmer1[2,2])) + + ## coef + expect_output(ShowRegTable(lmer1, digits = 5, exp = FALSE), + sprintf("%.5f", coef(summary(lmer1))[2,1])) + + + ## For p-values + ## lmerTest::lmer() masks lme4::lmer() + library(lmerTest) + + ## Linear LME + lmer2 <- lmer(formula = y ~ trt + day + (1 | id), + data = koch) + summary(lmer2) + + ciLmer2 <- tail(confint(lmer2), nrow(coef(summary(lmer2)))) + + ## confint + ShowRegTable(lmer2, digits = 5, exp = FALSE) + expect_output(ShowRegTable(lmer2, digits = 5, exp = FALSE), + sprintf("%.5f, %.5f", + ciLmer2[2,1], + ciLmer2[2,2])) + + ## coef + expect_output(ShowRegTable(lmer2, digits = 5, exp = FALSE), + sprintf("%.5f", coef(summary(lmer2))[2,1])) + + ## p-value + ## For some reason, need to specify summary explicitly. + expect_output(ShowRegTable(lmer2, pDigits = 5, exp = FALSE), + sprintf("%.5f", coef(lmerTest::summary(lmer2))[2,5])) + + ## GLMM + glmer1 <- glmer(formula = y ~ trt + day + (1 | id), + data = koch, + family = poisson(link = "log")) + summary(glmer1) + ## Last rows correspond to fixed effects + ciGlmer1 <- tail(confint(glmer1), nrow(coef(summary(glmer1)))) + + ## confint + ShowRegTable(glmer1, digits = 5, exp = TRUE) + expect_output(ShowRegTable(glmer1, digits = 5, exp = TRUE), + sprintf("%.5f, %.5f", + exp(ciGlmer1[2,1]), + exp(ciGlmer1[2,2]))) + + ## coef + expect_output(ShowRegTable(glmer1, digits = 5, exp = TRUE), + sprintf("%.5f", exp(coef(summary(glmer1)))[2,1])) + + } })