From 3e9908f00fa511e59226675a5df76ceb77c973c0 Mon Sep 17 00:00:00 2001 From: Ethan Heinzen Date: Tue, 31 Jan 2017 23:41:55 +0000 Subject: [PATCH] version 0.2.0 --- DESCRIPTION | 17 +- MD5 | 80 +- NAMESPACE | 8 + NEWS.md | 9 + R/arsenal.R | 5 +- R/freqlist.R | 2 +- R/internal.functions.R | 2 +- R/modelsum.R | 11 +- R/summary.modelsum.R | 2 +- R/tableby.R | 2 +- R/write2.R | 202 +- README.md | 37 +- build/vignette.rds | Bin 255 -> 280 bytes inst/doc/freqlist.R | 23 +- inst/doc/freqlist.Rmd | 40 +- inst/doc/freqlist.html | 3018 +++++++++++++++++++++++++++ inst/doc/freqlist.pdf | Bin 258253 -> 0 bytes inst/doc/modelsum.R | 13 +- inst/doc/modelsum.Rmd | 140 +- inst/doc/modelsum.html | 1623 +++++++------- inst/doc/tableby.R | 126 +- inst/doc/tableby.Rmd | 126 +- inst/doc/tableby.html | 730 +++---- inst/doc/write2.R | 78 + inst/doc/write2.Rmd | 177 ++ inst/doc/write2.html | 224 ++ man/arsenal.Rd | 4 + man/as.data.frame.modelsum.Rd | 2 +- man/modelsum.Rd | 11 +- man/summary.modelsum.Rd | 2 +- man/tableby.Rd | 2 +- man/write2.Rd | 85 +- man/write2specific.Rd | 62 + tests/testthat/test_formulize.R | 4 + tests/testthat/test_freqlist.R | 5 + tests/testthat/test_modelsum.R | 37 +- tests/testthat/test_tableby.R | 3 + tests/testthat/test_write2.R | 92 + tests/testthat/write2.freqlist.html | 326 +++ tests/testthat/write2.kable.html | 274 +++ tests/testthat/write2.modelsum.html | 240 +++ tests/testthat/write2.pander.html | 322 +++ tests/testthat/write2.tableby.html | 219 ++ tests/testthat/write2.xtable.html | 458 ++++ vignettes/freqlist.Rmd | 40 +- vignettes/modelsum.Rmd | 140 +- vignettes/tableby.Rmd | 126 +- vignettes/write2.Rmd | 177 ++ 48 files changed, 7570 insertions(+), 1756 deletions(-) create mode 100644 inst/doc/freqlist.html delete mode 100644 inst/doc/freqlist.pdf create mode 100644 inst/doc/write2.R create mode 100644 inst/doc/write2.Rmd create mode 100644 inst/doc/write2.html create mode 100644 man/write2specific.Rd create mode 100644 tests/testthat/test_write2.R create mode 100644 tests/testthat/write2.freqlist.html create mode 100644 tests/testthat/write2.kable.html create mode 100644 tests/testthat/write2.modelsum.html create mode 100644 tests/testthat/write2.pander.html create mode 100644 tests/testthat/write2.tableby.html create mode 100644 tests/testthat/write2.xtable.html create mode 100644 vignettes/write2.Rmd diff --git a/DESCRIPTION b/DESCRIPTION index 2f783a6..2e80fe2 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,8 +1,9 @@ Package: arsenal Title: An Arsenal of 'R' Functions for Large-Scale Statistical Summaries -Version: 0.1.2 -Date: 2016-12-29 +Version: 0.2.0 +Date: 2017-01-31 +URL: https://cran.r-project.org/package=arsenal Authors@R: c( person("Ethan", "Heinzen", email = "heinzen.ethan@mayo.edu", role = c("aut", "cre")), person("Jason", "Sinnwell", role="aut"), @@ -10,6 +11,8 @@ Authors@R: c( person("Tina", "Gunderson", role="aut"), person("Gregory", "Dougherty", role="aut"), person("Patrick", "Votruba", role="ctb"), + person("Ryan", "Lennon", role="ctb"), + person("Krista", "Goergen", role="ctb"), person("Emily", "Lundt", role="ctb") ) Description: An Arsenal of 'R' functions for large-scale statistical summaries, @@ -20,22 +23,24 @@ Description: An Arsenal of 'R' functions for large-scale statistical summaries, variable; modelsum(), which performs simple model fits on the same endpoint for many variables (univariate or adjusted for standard covariates); and freqlist(), a powerful frequency table across many categorical variables. -Suggests: knitr, rmarkdown, xtable, survival, testthat, coin, pROC, - MASS, gam, rpart +Suggests: knitr, rmarkdown, xtable, pander, survival, testthat, coin, + pROC, MASS, gam, rpart Depends: R (>= 3.2.0), stats (>= 3.2.0) Imports: broom, stringr VignetteBuilder: knitr License: GPL (>= 2) RoxygenNote: 5.0.1 NeedsCompilation: no -Packaged: 2016-12-29 15:03:54 UTC; m144326 +Packaged: 2017-01-31 23:21:39 UTC; m144326 Author: Ethan Heinzen [aut, cre], Jason Sinnwell [aut], Elizabeth Atkinson [aut], Tina Gunderson [aut], Gregory Dougherty [aut], Patrick Votruba [ctb], + Ryan Lennon [ctb], + Krista Goergen [ctb], Emily Lundt [ctb] Maintainer: Ethan Heinzen Repository: CRAN -Date/Publication: 2016-12-30 01:18:42 +Date/Publication: 2017-02-01 00:41:55 diff --git a/MD5 b/MD5 index cbe9746..a030b39 100644 --- a/MD5 +++ b/MD5 @@ -1,43 +1,46 @@ -966d309a0df5d55be152e36454793ba7 *DESCRIPTION -3f62d030021234740076da4d1ba8f002 *NAMESPACE -a5124b7fb1a608cf22414d0d439c5893 *NEWS.md -babe9da5c34ab0be1462ebb582b67f01 *R/arsenal.R +64ca95954a157e40c441927a12517109 *DESCRIPTION +163a641c4257c9de5b13411233a96e6d *NAMESPACE +ed12d43b046ac8b13ad042d42dd7dcf4 *NEWS.md +9e5c80edccdf89f7401dc898be315b6a *R/arsenal.R 79e2033244f329fa85d87cbc4013f678 *R/formulize.R -cfa9ea4571efbb3e9de3bc79dcc56041 *R/freqlist.R +9b361e8234e2f7dbdb5bf8abad07e12a *R/freqlist.R e42ce669505128b0f0b20ac6c621e91d *R/freqlist.internal.R -02a7e6a76fe38503ed55d6d0da6e12dd *R/internal.functions.R +75cce2779e3a321a78e8cd56f6e42b6a *R/internal.functions.R 2f474534e9fc946996d331ad8103b5ea *R/magic8.R e54a23c0326058d798de6b3c912a8003 *R/mdy.Date.R 1de6a042544ab82b1d3e5d5264e3ffe9 *R/mockstudy.R -8a60fb9fd3e6b75451fd52a671343fdf *R/modelsum.R +db9d7550daea1f2251908395723b6606 *R/modelsum.R 8972abaedd55f0c7f1418ad70f233302 *R/modelsum.control.R 8c879e7ce937bdbedb5fd3fb31a11d3f *R/modelsum.internal.R 0e56f25775a178e261295319e70889bd *R/not.in.R 50cd5149107450c83f3e3f855aeb57ad *R/release_questions.R 915d58ab60615cd9c66bfc92131cfba1 *R/summary.freqlist.R -1dff52d601070cac366b7123de8f8680 *R/summary.modelsum.R +e3eaad9fb39c372f2ed4aeaddf303289 *R/summary.modelsum.R 318e7c0c95e3737f5c209a9ba9ebea7b *R/summary.tableby.R -918558ed28af0fd4f0338c9d9787b926 *R/tableby.R +5df40ef875f0a8d2d7ffdca177c051d5 *R/tableby.R 6cd26e41a5b57be0697d1e98594fb16d *R/tableby.control.R 4b5df64d48a8f090b29f7eb55008b5db *R/tableby.internal.R 9bb29fd9186f2e7c11351693f70aa2e8 *R/tableby.stat.tests.R d795cb92f9d3e5ec846b31c0579badd3 *R/tableby.stats.R -872993fdbe93e6707fae16f6e0a0c99f *R/write2.R -018618b1d1fb15a1945e7892e2868204 *README.md -4aafc7bc18223c036874a46def9050bc *build/vignette.rds +56b73ad8b0d8ae2da6a8cd8e0934749e *R/write2.R +9978346e6d56e7fcdf127d79f01a7649 *README.md +e91dac73925af6b800aafec7b3780ab6 *build/vignette.rds 30cd2d9369ee4d94dd76dcbf5a215559 *data/mockstudy.RData -79433ae6628afba73b4751b5e6bbb32e *inst/doc/freqlist.R -b90b634df89f2a4dc597b834d4a0457d *inst/doc/freqlist.Rmd -197db4ba70c32f0a3579ba56e71b8c7b *inst/doc/freqlist.pdf -2be512c16c57f0c19d46a03559fa66ed *inst/doc/modelsum.R -cfe0b0bd54ea0d5dd64b179d025a5621 *inst/doc/modelsum.Rmd -85570c3c621adb383c345f2e09bd5a1e *inst/doc/modelsum.html -48ac3590253a78deafa97b9c8a30ba4f *inst/doc/tableby.R -0f686caa3862dd071b6538bd17b5d0c8 *inst/doc/tableby.Rmd -78a397ba49bf53164ac6bf6eb5278c0b *inst/doc/tableby.html -fb7f3dd8cf45309fc533d5cb863271b8 *man/arsenal.Rd +6426e345a14c9dec20d62c6456c4e9f0 *inst/doc/freqlist.R +d81e95828e521941e139482c962e9710 *inst/doc/freqlist.Rmd +37d87dba1400ad18ec9abbba8dda1cbf *inst/doc/freqlist.html +92e0994599563842bd6a019ec6ea4102 *inst/doc/modelsum.R +7b5d1fa9bc0c43d57a226738d4b54c7f *inst/doc/modelsum.Rmd +b540f480e5ac4f64684563ef0e97666d *inst/doc/modelsum.html +a68ec9f4260ce8c2c93e5a85f6c673e2 *inst/doc/tableby.R +d19754caf6254260ec847743d8b228db *inst/doc/tableby.Rmd +eb330c6faaa31ef5f91bcf135056faad *inst/doc/tableby.html +2be7ca8e41f22208b476876029e80657 *inst/doc/write2.R +403d798936814c679eeaa22ea6180ff7 *inst/doc/write2.Rmd +2301d10e20887d78abda3bdd2d52d5b3 *inst/doc/write2.html +33f826e2f2c76b4f19e4f032d67fac58 *man/arsenal.Rd a08790dee110e6f91216f1c9f7b9888e *man/as.data.frame.freqlist.Rd -fb7c429f3c12092d0fad2dc88754fd8f *man/as.data.frame.modelsum.Rd +cedee07e345ad606f41d35fb7c5c208c *man/as.data.frame.modelsum.Rd 1326c71d7954bf79cd26895f0aedd30f *man/as.data.frame.tableby.Rd 2133b459a58b59f77b1e835fafc009e6 *man/formulize.Rd c15c3a5f78637e5ac782800687fd2289 *man/freqlist.Rd @@ -45,22 +48,31 @@ b149f67287b2605109b516fbd9ef8f20 *man/freqlist.internal.Rd 5148640645d5b9f0de27a83ba4ed6788 *man/grapes-nin-grapes.Rd 2e1f8c2d941134f65a82f84346247458 *man/mdy.Date.Rd 4cd57758131c3d1dffce65879eb34e76 *man/mockstudy.Rd -fb624ea9b801473dae9d30eefe8a1047 *man/modelsum.Rd +1d876b7eb1a077a5220759b72535f65c *man/modelsum.Rd ee7241120bee38b7c92d9160f86699e0 *man/modelsum.control.Rd 56b926cfc2d81c0539e70ca8a4d68794 *man/modelsum.internal.Rd 562faf3ed641a245644af5887f5704aa *man/summary.freqlist.Rd -1a749d94bb67684290e8d11927700f0d *man/summary.modelsum.Rd +0ab1c3227e5d79e9a4419e0546fbaa77 *man/summary.modelsum.Rd b03d9fe7d9940a052a7b539b58a4f2c5 *man/summary.tableby.Rd -d8894b3a8db813af90570d664d3009dd *man/tableby.Rd +43e9f7d6d6a5c5316f98dc1bdc78e3c1 *man/tableby.Rd e60ebe8ed16f9112a141ec2b24574b10 *man/tableby.control.Rd c00a698159af17705b7306ce44e2070b *man/tableby.internal.Rd a7d8a4fca049fadfeb6be460b35a209f *man/tableby.stats.Rd -6d0a923e8398c923744d26bcbb44ddc3 *man/write2.Rd +fa58b2bb17f00974410a7d06f6b20b83 *man/write2.Rd +013f6556b9cd188c26365af8f42c1ec7 *man/write2specific.Rd b86d96d2b720f7aeeb3b9412b87d67ef *tests/testthat.R -ba8ab9b99798b694a5f5b06b9a28f2d8 *tests/testthat/test_formulize.R -6811553415304e4626ae831d29c1d680 *tests/testthat/test_freqlist.R -d4732617af6ee210bbdc165014b5a4b2 *tests/testthat/test_modelsum.R -357806abad78c1b6ca0c358d6d4d9b4a *tests/testthat/test_tableby.R -b90b634df89f2a4dc597b834d4a0457d *vignettes/freqlist.Rmd -cfe0b0bd54ea0d5dd64b179d025a5621 *vignettes/modelsum.Rmd -0f686caa3862dd071b6538bd17b5d0c8 *vignettes/tableby.Rmd +1c0b875954db84c2384bf6d753d50146 *tests/testthat/test_formulize.R +2943f65b203a330bfde7f22fbd0967d9 *tests/testthat/test_freqlist.R +8016a1934078062f9128e70b1943a8fb *tests/testthat/test_modelsum.R +d37c1af2099852398edf4aa01295a6bf *tests/testthat/test_tableby.R +1c732994556af5cd482c218cf6c039d8 *tests/testthat/test_write2.R +f177f2b74b4f9f751e8edbb6a9fad712 *tests/testthat/write2.freqlist.html +0a7b3e0ee537b49cf7ed5c11b1a4fecd *tests/testthat/write2.kable.html +83bfb15f5b9103e625c16cbccbfad808 *tests/testthat/write2.modelsum.html +61cdf411f2af5411f89903cba990ea9e *tests/testthat/write2.pander.html +f43dc701ee19bf489fa31c12c1f9ffb1 *tests/testthat/write2.tableby.html +f00648a7b68d7c41a326ef44d2129152 *tests/testthat/write2.xtable.html +d81e95828e521941e139482c962e9710 *vignettes/freqlist.Rmd +7b5d1fa9bc0c43d57a226738d4b54c7f *vignettes/modelsum.Rmd +d19754caf6254260ec847743d8b228db *vignettes/tableby.Rmd +403d798936814c679eeaa22ea6180ff7 *vignettes/write2.Rmd diff --git a/NAMESPACE b/NAMESPACE index c522040..ebd0277 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -21,6 +21,13 @@ S3method(summary,freqlist) S3method(summary,modelsum) S3method(summary,tableby) S3method(tests,tableby) +S3method(write2,character) +S3method(write2,default) +S3method(write2,freqlist) +S3method(write2,knitr_kable) +S3method(write2,modelsum) +S3method(write2,tableby) +S3method(write2,xtable) export("%nin%") export("labels<-") export(Date.mdy) @@ -44,6 +51,7 @@ export(q1q3) export(tableby) export(tableby.control) export(tests) +export(write2) export(write2html) export(write2pdf) export(write2word) diff --git a/NEWS.md b/NEWS.md index 74248d6..7f0fa55 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,12 @@ +# arsenal 0.2.0 + +* Vignettes have been updated. + +* `write2()` is now exported and supports all output formats supported by `rmarkdown::render()`. There is now a vignette for it + and the S3 methods have been expanded to handle more inputs, including `knitr::kable()`, `xtable::xtable()`, and `pander::pander_return()`. + +* Fixed a bug in `summary.modelsum()`. + # arsenal 0.1.2 * `broom` and `stringr` have been moved to `imports` instead of `depends`. diff --git a/R/arsenal.R b/R/arsenal.R index 361dbac..7a1527c 100644 --- a/R/arsenal.R +++ b/R/arsenal.R @@ -6,6 +6,8 @@ #' An Arsenal of 'R' functions for large-scale statistical summaries, #' which are streamlined to work within the latest reporting tools in 'R' and 'RStudio' and #' which use formulas and versatile summary statistics for summary tables and models. +#' +#' The package download, NEWS, and README are available on CRAN: \url{https://cran.r-project.org/package=arsenal} #' #' @section Functions: #' @@ -19,6 +21,8 @@ #' #' \code{\link{write2word}}, \code{\link{write2html}}, \code{\link{write2pdf}}: Functions to generate a word, html, or pdf document containing a single table. #' +#' \code{\link{write2}}: Functions to generate a single document containing a single table. (Also the S3 backbone behind the \code{write2*} functions.) +#' #' \code{\link{formulize}}: A shortcut to generate one-, two-, or many-sided formulas. #' #' \code{\link{mdy.Date}} and \code{\link{Date.mdy}}: Convert numeric dates for month, day, and year to Date object, and vice versa. @@ -36,7 +40,6 @@ NULL #### commands to build the package using devtools -# devtools::document() # devtools::check_man() # devtools::test() # devtools::check() diff --git a/R/freqlist.R b/R/freqlist.R index f1a3748..245bacb 100644 --- a/R/freqlist.R +++ b/R/freqlist.R @@ -131,7 +131,7 @@ freqlist <- function(tab, sparse = FALSE, na.options = c('include', 'showexclude #' @export print.freqlist <- function(x, ...) { - cat("Freqlist object\n\n") + cat("Freqlist Object\n\n") cat(ncol(x$freqlist) - 4, " variables:\n", sep = "") print(colnames(x$freqlist)[1:(ncol(x$freqlist) - 4)]) invisible(x) diff --git a/R/internal.functions.R b/R/internal.functions.R index bebc788..97d9fda 100644 --- a/R/internal.functions.R +++ b/R/internal.functions.R @@ -498,7 +498,7 @@ makePaddedStr <- function(startStr, size, padChar = ' ') { } # See if can split the string on a reasonable boundary character - for (split in c(" ", "\t", "_", "-", "*", ".", ";", ":")) { + for (split in c(" ", "\t", "_", "-",".", ";", ":")) { results <- strsplit(startStr, split, fixed = TRUE)[[1]] if ((length(results) > 1) && (minStrLen(results) <= size)) return(pastePaddedStr(results, size, sep = split, padChar = padChar, appendSep = TRUE)) diff --git a/R/modelsum.R b/R/modelsum.R index 187d448..077b60a 100644 --- a/R/modelsum.R +++ b/R/modelsum.R @@ -47,13 +47,14 @@ #' #' data(mockstudy) #' -#' tab1 <- modelsum(bmi ~ sex + age, data=mockstudy) -#' summary(tab1, text=TRUE) +#' tab1 <- modelsum(bmi ~ sex + age, data = mockstudy) +#' summary(tab1, text = TRUE) #' -#' tab2 <- modelsum(alk.phos ~ arm + ps + hgb, adjust= ~age + sex, family="gaussian",data=mockstudy) -#' summary(tab2, text=TRUE) +#' tab2 <- modelsum(alk.phos ~ arm + ps + hgb, adjust = ~ age + sex, +#' family = "gaussian", data = mockstudy) +#' summary(tab2, text = TRUE) #' -#' summary(tab2, show.intercept=FALSE, text=TRUE) +#' summary(tab2, show.intercept = FALSE, text = TRUE) #' #' tab2.df <- as.data.frame(tab2) #' diff --git a/R/summary.modelsum.R b/R/summary.modelsum.R index c4c9744..87215ef 100644 --- a/R/summary.modelsum.R +++ b/R/summary.modelsum.R @@ -14,7 +14,7 @@ modelsum.translations <- list() ## adj.r.squared = "adj.rsq", sex = "Sex", sexM #' @param object The data defining the table to display #' @param title Title for the table, defaults to \code{NULL} (no title) #' @param labelTranslations List where name is the label in the output, and value is the label you -#' want displayed e.g. \code{list (q1q3: "Q1, Q3", medsurv = "Median Survival")}. +#' want displayed e.g. \code{list(q1q3 = "Q1, Q3", medsurv = "Median Survival")}. #' @param digits Maximum number of digits to display for floating point numbers. #' If \code{NA} (default), it uses the value from \code{object$control$digits} #' (whose default is 3, which would result in, e.g., 12.3, 1.23, 0.123, and 0.012). diff --git a/R/tableby.R b/R/tableby.R index 502f0b6..573ca24 100644 --- a/R/tableby.R +++ b/R/tableby.R @@ -111,7 +111,7 @@ #' tab1 <- tableby(arm ~ sex + age, data=mockstudy) #' summary(tab1, text=TRUE) #' -#' mylabels <- list( sex = "SEX", age ="Age, yrs") +#' mylabels <- list(sex = "SEX", age ="Age, yrs") #' summary(tab1, labelTranslations = mylabels, text=TRUE) #' #' tab3 <- tableby(arm ~ sex + age, data=mockstudy, test=FALSE, total=FALSE, diff --git a/R/write2.R b/R/write2.R index cf8b979..0068337 100644 --- a/R/write2.R +++ b/R/write2.R @@ -1,86 +1,220 @@ -#' write2word, write2html, write2pdf +#' write2 #' -#' Functions to generate a word, html, or pdf document containing a single table. +#' Functions to generate a single document containing a single table. (Also the S3 backbone behind the \code{write2*} functions.) #' -#' @param object An object whose \code{summary} output looks "good" when using \code{results='asis'} in markdown. +#' @param object An object. #' @param file A single character string denoting the filename for the output document. -#' @param ... Additional arguments to be passed to \code{summary}, \code{rmarkdown::render}, etc. +#' @param ... Additional arguments to be passed to \code{FUN}, \code{rmarkdown::render}, etc. #' One popular option is to use \code{quiet = TRUE} to suppress the command line output. +#' @param FUN The summary-like or print-like function to use to generate the markdown content. Can be passed as a function or a +#' character string. It's expected that \code{FUN(object, ...)} looks "good" when using \code{results='asis'} in markdown. #' @param keep.md Logical, denoting whether to keep the intermediate \code{.md} file. +#' @param output_format One of the following: +#' \enumerate{ +#' \item{An output format object, e.g. \code{rmarkdown::\link[rmarkdown]{html_document}(...)}.} +#' \item{A character string denoting such a format function, e.g. \code{"html_document"}. In this case, the \code{"..."} are NOT passed.} +#' \item{The format function itself, e.g. \code{rmarkdown::html_document}. In this case, the \code{"..."} arguments are passed.} +#' \item{One of \code{"html"}, \code{"pdf"}, and \code{"word"}, shortcuts implemented here. In this case, the \code{"..."} arguments are passed.} +#' \item{\code{NULL}, in which the output is HTML by default.} +#' } +#' See \code{rmarkdown::\link[rmarkdown]{render}} for details. #' @return \code{object} is returned invisibly, and \code{file} is written. -#' @details This is (kind of) an S3 method (the real S3 method is \code{write2}),and the default -#' (used for \code{\link{tableby}}, \code{\link{modelsum}}, \code{\link{freqlist}}, etc.) assumes -#' that there is a \code{summary} method implemented. -#' -#' To generate the appropriate file type, the default uses one of \code{rmarkdown::word_document}, \code{rmarkdown::html_document}, -#' and \code{rmarkdown::pdf_document} to get the job done. \code{"..."} arguments are passed to these functions, too. -#' @seealso \code{\link[rmarkdown]{render}}, \code{\link[rmarkdown]{word_document}}, \code{\link[rmarkdown]{html_document}}, \code{\link[rmarkdown]{pdf_document}} +#' @details \code{write2} is an S3 method, and the default +#' assumes that there is a \code{FUN} method implemented which looks 'good' in Rmarkdown. +#' +#' There are methods implemented for \code{\link{tableby}}, \code{\link{modelsum}}, and \code{\link{freqlist}}, all of which use the +#' \code{summary} function. There are also methods compatible with \code{\link[knitr]{kable}}, \code{\link[xtable]{xtable}}, +#' and \code{\link[pander]{pander_return}}. +#' @seealso \code{\link{write2word}}, \code{\link{write2pdf}}, \code{\link{write2html}}, +#' \code{\link[rmarkdown]{render}}, \code{\link[rmarkdown]{word_document}}, \code{\link[rmarkdown]{html_document}}, \code{\link[rmarkdown]{pdf_document}}, +#' \code{\link[rmarkdown]{rtf_document}}, \code{\link[rmarkdown]{md_document}}, \code{\link[rmarkdown]{odt_document}} #' @examples #' \dontrun{ #' data(mockstudy) #' # tableby example #' tab1 <- tableby(arm ~ sex + age, data=mockstudy) -#' write2html(tab1, "~/ibm/trash.html") -#' -#' # freqlist example -#' tab.ex <- table(mockstudy[, c("arm", "sex", "mdquality.s")], useNA = "ifany") -#' noby <- freqlist(tab.ex, na.options = "include") -#' write2pdf(noby, "~/ibm/trash2.pdf") -#' -#' # A more complicated example -#' write2word(tab1, "~/ibm/trash.doc", keep.md = TRUE, -#' reference_docx = mystyles.docx, # passed to rmarkdown::word_document +#' write2(tab1, "~/trash.rtf", +#' toc = TRUE, # passed to rmarkdown::rtf_document, though in this case it's not practical #' quiet = TRUE, # passed to rmarkdown::render -#' title = "My cool new title" # passed to summary.tableby +#' title = "My cool new title", # passed to summary.tableby +#' output_format = rmarkdown::rtf_document) #' } #' @author Ethan Heinzen, adapted from code from Krista Goergen #' @name write2 NULL #> NULL + +#' @rdname write2 +#' @export write2 <- function(object, file, ..., keep.md, output_format) { UseMethod("write2") } -write2.default <- function(object, file, ..., keep.md = FALSE, output_format = c("html", "pdf", "word")) +############################ write2 for arsenal objects ############################ + +#' @rdname write2 +#' @export +write2.tableby <- function(object, file, ..., keep.md = FALSE, output_format = NULL) +{ + write2.default(object = object, file = file, FUN = summary, ..., keep.md = keep.md, output_format = output_format) +} + +#' @rdname write2 +#' @export +write2.modelsum <- function(object, file, ..., keep.md = FALSE, output_format = NULL) +{ + write2.default(object = object, file = file, FUN = summary, ..., keep.md = keep.md, output_format = output_format) +} + +#' @rdname write2 +#' @export +write2.freqlist <- function(object, file, ..., keep.md = FALSE, output_format = NULL) +{ + write2.default(object = object, file = file, FUN = summary, ..., keep.md = keep.md, output_format = output_format) +} + +############################ write2 for external objects ############################ + +#' @rdname write2 +#' @export +write2.knitr_kable <- function(object, file, ..., keep.md = FALSE, output_format = NULL) +{ + write2.default(object = object, file = file, FUN = print, ..., keep.md = keep.md, output_format = output_format) +} + +#' @rdname write2 +#' @export +write2.xtable <- function(object, file, ..., keep.md = FALSE, output_format = NULL) +{ + write2.default(object = object, file = file, FUN = print, ..., keep.md = keep.md, output_format = output_format) +} + +## this intended for use with pander_return() +#' @rdname write2 +#' @export +write2.character <- function(object, file, ..., keep.md = FALSE, output_format = NULL) +{ + write2.default(object = object, file = file, FUN = cat, ..., sep = "\n", keep.md = keep.md, output_format = output_format) +} + + +#' @rdname write2 +#' @export +write2.default <- function(object, file, FUN, ..., keep.md = FALSE, output_format = NULL) { if(!is.character(file) || length(file) > 1) stop("'file' argument must be a single character string.") if(!is.logical(keep.md) || length(keep.md) > 1) stop("'keep.md' argument must be a single character string.") - output_format <- match.arg(output_format) + FUN <- match.fun(FUN) - output_format <- if(output_format == "html") rmarkdown::html_document else if(output_format == "pdf") rmarkdown::pdf_document else rmarkdown::word_document - dots <- list(...) - utils::capture.output(summary(object, ...), file = paste0(file, ".md")) + if(is.character(output_format) && length(output_format) > 1) + { + warning("At this point, write2() only supports one output type.") + output_format <- output_format[1] + } - output.args <- dots[names(dots) %in% names(formals(output_format))] + + output_format <- if(is.null(output_format) || identical(output_format, "html")) + { + rmarkdown::html_document + } else if(identical(output_format, "pdf")) + { + rmarkdown::pdf_document + } else if(identical(output_format, "word")) + { + rmarkdown::word_document + } else output_format + + filename <- paste0(file, ".md") + file.create(filename) + dots <- list(...) + if(names(formals(FUN))[1] == "...") # this is when the FUN is, e.g., cat(). Any named arguments would still get cat'd, which we don't want + { + ARGS <- c(list(object), dots[names(dots) %in% names(formals(FUN))]) + utils::capture.output(do.call(FUN, ARGS), file = filename) + } else + { + utils::capture.output(FUN(object, ...), file = filename) + } render.args <- dots[names(dots) %in% names(formals(rmarkdown::render))] - render.args$input <- paste0(file, ".md") - render.args$output_format <- do.call(output_format, output.args) + render.args$input <- filename render.args$output_file <- file + + # if output_format is a function, evaluate it with the ... arguments + # otherwise, just return the character string or list which rmarkdown::render() will handle + render.args$output_format <- if(is.function(output_format)) + { + if("..." %in% names(formals(output_format))) + { + do.call(output_format, dots) + } else do.call(output_format, dots[names(dots) %in% names(formals(output_format))]) + } else output_format + do.call(rmarkdown::render, render.args) - if(!keep.md) system(paste0("rm -f ", file, ".md")) + # This short-circuits if they want to keep the .md file. Otherwise, file.remove() returns a logical about successful file removal + if(!keep.md && !file.remove(filename)) warning("Something went wrong removing the temporary .md file.") + invisible(object) } -#' @rdname write2 +######################################################################################################################################################### +######################################################################################################################################################### +######################################################################################################################################################### + + +#' write2word, write2html, write2pdf +#' +#' Functions to generate a word, html, or pdf document containing a single table. +#' +#' @inheritParams write2 +#' @return \code{object} is returned invisibly, and \code{file} is written. +#' @details +#' To generate the appropriate file type, the \code{write2*} functions use one of \code{rmarkdown::word_document}, \code{rmarkdown::html_document}, +#' and \code{rmarkdown::pdf_document} to get the job done. \code{"..."} arguments are passed to these functions, too. +#' @seealso \code{\link{write2}} +#' @examples +#' \dontrun{ +#' data(mockstudy) +#' # tableby example +#' tab1 <- tableby(arm ~ sex + age, data=mockstudy) +#' write2html(tab1, "~/trash.html") +#' +#' # freqlist example +#' tab.ex <- table(mockstudy[, c("arm", "sex", "mdquality.s")], useNA = "ifany") +#' noby <- freqlist(tab.ex, na.options = "include") +#' write2pdf(noby, "~/trash2.pdf") +#' +#' # A more complicated example +#' write2word(tab1, "~/trash.doc", +#' keep.md = TRUE, +#' reference_docx = mystyles.docx, # passed to rmarkdown::word_document +#' quiet = TRUE, # passed to rmarkdown::render +#' title = "My cool new title") # passed to summary.tableby +#' } +#' @author Ethan Heinzen, adapted from code from Krista Goergen +#' @name write2specific +NULL +#> NULL + +#' @rdname write2specific #' @export write2word <- function(object, file, ..., keep.md = FALSE) { write2(object, file, ..., keep.md = keep.md, output_format = "word") } -#' @rdname write2 +#' @rdname write2specific #' @export write2pdf <- function(object, file, ..., keep.md = FALSE) { write2(object, file, ..., keep.md = keep.md, output_format = "pdf") } -#' @rdname write2 +#' @rdname write2specific #' @export write2html <- function(object, file, ..., keep.md = FALSE) { diff --git a/README.md b/README.md index ab4c939..9e35f7c 100644 --- a/README.md +++ b/README.md @@ -4,35 +4,36 @@ The goal of `library(arsenal)` is to make statistical reporting easy. It include in his/her "arsenal" of functions. There are, at this time, 3 main functions, documented below. Each of these functions is motivated by a local SAS macro of similar functionality. -## The `tableby` Function +## The `tableby()` Function -`tableby` is a function to easily summarize a set of independent variables by a categorical variable. +`tableby()` is a function to easily summarize a set of independent variables by a categorical variable. Optionally, an appropriate test is performed to test the distribution of the independent variables across -the levels of the categorical variable. Options for this function are easily controled using `tableby.control`. +the levels of the categorical variable. Options for this function are easily controled using `tableby.control()`. -The `tableby` output is easily knitted in an Rmarkdown document or displayed in the command line using the `summary` function. -Other S3 methods are implemented for objects of class `"tableby"`, including `print`, `[`, `as.data.frame`, and `merge`. +The `tableby()` output is easily knitted in an Rmarkdown document or displayed in the command line using the `summary()` function. +Other S3 methods are implemented for objects of class `"tableby"`, including `print()`, `[`, `as.data.frame()`, and `merge()`. -## The `modelsum` Function +## The `modelsum()` Function -`modelsum` is a function to fit and summarize models for each independent variable with a response variable, -with options to adjust by variables for each model. Options for this function are easily controled using `modelsum.control`. +`modelsum()` is a function to fit and summarize models for each independent variable with a response variable, +with options to adjust by variables for each model. Options for this function are easily controled using `modelsum.control()`. -The `modelsum` output is easily knitted in an Rmarkdown document or displayed in the command line using the `summary` function. -Other S3 methods are implemented for objects of class `"modelsum"`, including `print` and `as.data.frame`. +The `modelsum` output is easily knitted in an Rmarkdown document or displayed in the command line using the `summary()` function. +Other S3 methods are implemented for objects of class `"modelsum"`, including `print()` and `as.data.frame()`. -## The `freqlist` Function +## The `freqlist()` Function -`freqlist` is a function to approximate the output from SAS's `PROC FREQ` procedure when using the `/list` option of the `TABLE` statement. +`freqlist()` is a function to approximate the output from SAS's `PROC FREQ` procedure when using the `/list` option of the `TABLE` statement. -The `freqlist` output is easily knitted in an Rmarkdown document or displayed in the command line using the `summary` function. -Other S3 methods are implemented for objects of class `"freqlist"`, including `print` and `as.data.frame`. +The `freqlist()` output is easily knitted in an Rmarkdown document or displayed in the command line using the `summary()` function. +Other S3 methods are implemented for objects of class `"freqlist"`, including `print()` and `as.data.frame()`. ## Other Notable Functions -* `write2word`, `write2pdf`, and `write2html` are functions to output any of the above objects into a document. They're a shortcut for - "I just want to output this one table but I don't want to open an Rmarkdown script, ugh..." +* `write2word()`, `write2pdf()`, and `write2html()` are functions to output an object into a document, much like SAS's `ODS` procedure. + They're a shortcut for "I just want to output this one table but I don't want to open an Rmarkdown script, ugh..." + The S3 method behind them is `write2()`. -* `formulize` is a shortcut to collapse variable names into a formula. +* `formulize()` is a shortcut to collapse variable names into a formula. -* `mdy.Date` and `Date.mdy` convert numeric dates for month, day, and year to Date object, and vice versa. +* `mdy.Date()` and `Date.mdy()` convert numeric dates for month, day, and year to Date object, and vice versa. diff --git a/build/vignette.rds b/build/vignette.rds index 7d4268a08a41613df72ec6d1a0e41b7f5b29da7c..ff5ce583583eb6b647e60a33096e7211a2000fa7 100644 GIT binary patch literal 280 zcmV+z0q6c7iwFP!000001C5fuZi6ro#to)vAc<5d?VcxK=rcrFx>Qw$u1+`;>^KlCl%0zy|n#-zi)SL8&IZ?TR20J8A|*Ou60@Ad2AF{Wu21Qs(oGGI5kc4 eGtKCzgrSTGCYi7z%`5yLPrrYmiz^JD0ssK135A*f literal 255 zcmVthe*U#sjBMooM@|rp+rPRQdp6sCEiDLy#a`=O&mS~ F0041feqsOs diff --git a/inst/doc/freqlist.R b/inst/doc/freqlist.R index 3989afb..699a1c1 100644 --- a/inst/doc/freqlist.R +++ b/inst/doc/freqlist.R @@ -2,12 +2,10 @@ knitr::opts_chunk$set(echo = TRUE, tidy.opts=list(width.cutoff=80), tidy=TRUE, comment=NA) options(width=80, max.print=1000) +## ----message = FALSE---------------------------------------------------------- require(arsenal) -# source("/data5/bsi/adhoc/s200555.R-infrastructure/devel/eph/arsenal-eph/R/freqlist.R") -# source("/data5/bsi/adhoc/s200555.R-infrastructure/devel/eph/arsenal-eph/R/summary.freqlist.R") -# source("/data5/bsi/adhoc/s200555.R-infrastructure/devel/eph/arsenal-eph/R/freqlist.internal.R") -## ----loading and setting up data---------------------------------------------- +## ----loading.data------------------------------------------------------------- # load the data data(mockstudy) @@ -23,7 +21,7 @@ noby <- freqlist(tab.ex) str(noby) # view the data frame portion of freqlist output -noby[["freqlist"]] +noby[["freqlist"]] ## or use as.data.frame(noby) ## ---- results = 'asis'-------------------------------------------------------- summary(noby) @@ -31,6 +29,9 @@ summary(noby) ## ---- results = 'asis'-------------------------------------------------------- summary(noby, caption="Basic freqlist output") +## ----------------------------------------------------------------------------- +head(as.data.frame(noby)) + ## ----labelTranslations, results = 'asis'-------------------------------------- withnames <- freqlist(tab.ex, labelTranslations = c("Treatment Arm","Gender","LASA QOL"), digits = 0) @@ -50,7 +51,7 @@ summary(freqlist(tab.ex, na.options="include")) summary(freqlist(tab.ex, na.options="showexclude")) summary(freqlist(tab.ex, na.options="remove")) -## ----frequency counts, results='asis'----------------------------------------- +## ----freq.counts, results='asis'---------------------------------------------- withby <- freqlist(tab.ex, groupBy = c("arm","sex")) summary(withby) @@ -65,14 +66,12 @@ summary(noby) ## ---- results = 'asis'-------------------------------------------------------- summary(noby, labelTranslations = c("Hi there", "What up", "Bye")) -## ----xtable setup------------------------------------------------------------- +## ----xtable.setup------------------------------------------------------------- require(xtable) -#turn off xtable header -options(xtable.comment = FALSE) -#set up custom function for xtable text +# set up custom function for xtable text italic <- function(x){ -paste0('{\\emph{ ', x, '}}') +paste0('', x, '') } @@ -83,7 +82,7 @@ xftbl <- xtable(noby[["freqlist"]], # change the column names names(xftbl)[1:3] <- c("Arm", "Gender", "LASA QOL") -print(xftbl, sanitize.colnames.function = italic, include.rownames = FALSE) +print(xftbl, sanitize.colnames.function = italic, include.rownames = FALSE, type = "html", comment = FALSE) ## ----------------------------------------------------------------------------- # base table default removes NAs diff --git a/inst/doc/freqlist.Rmd b/inst/doc/freqlist.Rmd index 74111f0..61b9e75 100644 --- a/inst/doc/freqlist.Rmd +++ b/inst/doc/freqlist.Rmd @@ -3,12 +3,9 @@ title: "The freqlist function" author: "Tina Gunderson" date: '`r format(Sys.time(),"%d %B, %Y")`' output: - pdf_document: + rmarkdown::html_vignette: toc: yes toc_depth: 3 - html_document: - toc: yes - toc_depth: '3' header-includes: \usepackage{tabularx} vignette: | %\VignetteIndexEntry{The freqlist function} @@ -19,11 +16,6 @@ vignette: | ```{r setup, include=FALSE} knitr::opts_chunk$set(echo = TRUE, tidy.opts=list(width.cutoff=80), tidy=TRUE, comment=NA) options(width=80, max.print=1000) - -require(arsenal) -# source("/data5/bsi/adhoc/s200555.R-infrastructure/devel/eph/arsenal-eph/R/freqlist.R") -# source("/data5/bsi/adhoc/s200555.R-infrastructure/devel/eph/arsenal-eph/R/summary.freqlist.R") -# source("/data5/bsi/adhoc/s200555.R-infrastructure/devel/eph/arsenal-eph/R/freqlist.internal.R") ``` \newpage @@ -34,6 +26,10 @@ require(arsenal) `freqlist` provides options for handling missing or sparse data and can provide cumulative counts and percentages based on subgroups. It depends on the `knitr` package for printing. +```{r message = FALSE} +require(arsenal) +``` + ## Sample dataset For our examples, we'll load the `mockstudy` data included with this package and use it to create a basic table. @@ -41,7 +37,7 @@ Because they have fewer levels, for brevity, we'll use the variables arm, sex, a We'll retain NAs in the table creation. See the appendix for notes regarding default NA handling and other useful information regarding tables in R. -```{r loading and setting up data} +```{r loading.data} # load the data data(mockstudy) @@ -68,7 +64,7 @@ noby <- freqlist(tab.ex) str(noby) # view the data frame portion of freqlist output -noby[["freqlist"]] +noby[["freqlist"]] ## or use as.data.frame(noby) ``` \newpage @@ -91,7 +87,11 @@ summary(noby, caption="Basic freqlist output") ``` You can also easily pull out the `freqlist` data frame for more complicated formatting or manipulation -(e.g. with another function such as `xtable` or `pander`). See below. +(e.g. with another function such as `xtable` or `pander`) using `as.data.frame`: + +```{r} +head(as.data.frame(noby)) +``` \newpage @@ -138,9 +138,11 @@ summary(freqlist(tab.ex, na.options="remove")) ## Frequency counts and percentages subset by factor levels -The groupBy argument internally subsets the data by the specified factor prior to calculating cumulative counts and percentages. By default, when used each subset will print in a separate table. Using the `single = TRUE` option when printing will collapse the subsetted result into a single table. +The groupBy argument internally subsets the data by the specified factor prior to calculating cumulative counts and percentages. +By default, when used each subset will print in a separate table. Using the `single = TRUE` option when printing will collapse +the subsetted result into a single table. -```{r frequency counts, results='asis'} +```{r freq.counts, results='asis'} withby <- freqlist(tab.ex, groupBy = c("arm","sex")) summary(withby) @@ -168,14 +170,12 @@ summary(noby, labelTranslations = c("Hi there", "What up", "Bye")) Fair warning: `xtable` has kind of a steep learning curve. These examples are given without explanation for more advanced users. -```{r xtable setup} +```{r xtable.setup} require(xtable) -#turn off xtable header -options(xtable.comment = FALSE) -#set up custom function for xtable text +# set up custom function for xtable text italic <- function(x){ -paste0('{\\emph{ ', x, '}}') +paste0('', x, '') } ``` @@ -187,7 +187,7 @@ xftbl <- xtable(noby[["freqlist"]], # change the column names names(xftbl)[1:3] <- c("Arm", "Gender", "LASA QOL") -print(xftbl, sanitize.colnames.function = italic, include.rownames = FALSE) +print(xftbl, sanitize.colnames.function = italic, include.rownames = FALSE, type = "html", comment = FALSE) ``` \newpage diff --git a/inst/doc/freqlist.html b/inst/doc/freqlist.html new file mode 100644 index 0000000..8de9a3a --- /dev/null +++ b/inst/doc/freqlist.html @@ -0,0 +1,3018 @@ + + + + + + + + + + + + + + + +The freqlist function + + + + + + + + + + + + + + + + + +

The freqlist function

+

Tina Gunderson

+

31 January, 2017

+ + + + + +
+

Overview

+

freqlist is a function meant to produce output similar to SAS’s PROC FREQ procedure when using the /list option of the TABLE statement. freqlist provides options for handling missing or sparse data and can provide cumulative counts and percentages based on subgroups. It depends on the knitr package for printing.

+
require(arsenal)
+
+

Sample dataset

+

For our examples, we’ll load the mockstudy data included with this package and use it to create a basic table. Because they have fewer levels, for brevity, we’ll use the variables arm, sex, and mdquality.s to create the example table. We’ll retain NAs in the table creation. See the appendix for notes regarding default NA handling and other useful information regarding tables in R.

+
# load the data
+data(mockstudy)
+
+# examine the data
+str(mockstudy)
+
'data.frame':   1499 obs. of  14 variables:
+ $ case       : int  110754 99706 105271 105001 112263 86205 99508 90158 88989 90515 ...
+ $ age        : atomic  67 74 50 71 69 56 50 57 51 63 ...
+  ..- attr(*, "label")= chr "Age in Years"
+ $ arm        : atomic  F: FOLFOX A: IFL A: IFL G: IROX ...
+  ..- attr(*, "label")= chr "Treatment Arm"
+ $ sex        : Factor w/ 2 levels "Male","Female": 1 2 2 2 2 1 1 1 2 1 ...
+ $ race       : atomic  Caucasian Caucasian Caucasian Caucasian ...
+  ..- attr(*, "label")= chr "Race"
+ $ fu.time    : int  922 270 175 128 233 120 369 421 387 363 ...
+ $ fu.stat    : int  2 2 2 2 2 2 2 2 2 2 ...
+ $ ps         : int  0 1 1 1 0 0 0 0 1 1 ...
+ $ hgb        : num  11.5 10.7 11.1 12.6 13 10.2 13.3 12.1 13.8 12.1 ...
+ $ bmi        : atomic  25.1 19.5 NA 29.4 26.4 ...
+  ..- attr(*, "label")= chr "Body Mass Index (kg/m^2)"
+ $ alk.phos   : int  160 290 700 771 350 569 162 152 231 492 ...
+ $ ast        : int  35 52 100 68 35 27 16 12 25 18 ...
+ $ mdquality.s: int  NA 1 1 1 NA 1 1 1 1 1 ...
+ $ age.ord    : Ord.factor w/ 8 levels "10-19"<"20-29"<..: 6 7 4 7 6 5 4 5 5 6 ...
+
# retain NAs when creating the table using the useNA argument
+tab.ex <- table(mockstudy[, c("arm", "sex", "mdquality.s")], useNA = "ifany")
+ +
+
+
+

The freqlist object

+

The freqlist function returns an object of class freqlist, which has three parts: freqlist, byVar, and labels.

+
    +
  • freqlist is a single data frame containing all contingency tables with calculated frequencies, cumulative frequencies, percentages, and cumulative percentages.

  • +
  • byVar and labels are used in the summary method for subgroups and variable names, which will be covered in later examples.

  • +
+
noby <- freqlist(tab.ex)
+
+str(noby)
+
List of 3
+ $ freqlist:'data.frame':   18 obs. of  7 variables:
+  ..$ arm        : Factor w/ 3 levels "A: IFL","F: FOLFOX",..: 1 1 1 1 1 1 2 2 2 2 ...
+  ..$ sex        : Factor w/ 2 levels "Male","Female": 1 1 1 2 2 2 1 1 1 2 ...
+  ..$ mdquality.s: Factor w/ 2 levels "0","1": 1 2 NA 1 2 NA 1 2 NA 1 ...
+  ..$ Freq       : int [1:18] 29 214 34 12 118 21 31 285 95 21 ...
+  ..$ cumFreq    : int [1:18] 29 243 277 289 407 428 459 744 839 860 ...
+  ..$ freqPercent: num [1:18] 1.93 14.28 2.27 0.8 7.87 ...
+  ..$ cumPercent : num [1:18] 1.93 16.21 18.48 19.28 27.15 ...
+ $ byVar   : NULL
+ $ labels  : NULL
+ - attr(*, "class")= chr "freqlist"
+
# view the data frame portion of freqlist output
+noby[["freqlist"]]  ## or use as.data.frame(noby)
+
         arm    sex mdquality.s Freq cumFreq freqPercent cumPercent
+1     A: IFL   Male           0   29      29        1.93       1.93
+2     A: IFL   Male           1  214     243       14.28      16.21
+3     A: IFL   Male        <NA>   34     277        2.27      18.48
+4     A: IFL Female           0   12     289        0.80      19.28
+5     A: IFL Female           1  118     407        7.87      27.15
+6     A: IFL Female        <NA>   21     428        1.40      28.55
+7  F: FOLFOX   Male           0   31     459        2.07      30.62
+8  F: FOLFOX   Male           1  285     744       19.01      49.63
+9  F: FOLFOX   Male        <NA>   95     839        6.34      55.97
+10 F: FOLFOX Female           0   21     860        1.40      57.37
+11 F: FOLFOX Female           1  198    1058       13.21      70.58
+12 F: FOLFOX Female        <NA>   61    1119        4.07      74.65
+13   G: IROX   Male           0   17    1136        1.13      75.78
+14   G: IROX   Male           1  187    1323       12.47      88.26
+15   G: IROX   Male        <NA>   24    1347        1.60      89.86
+16   G: IROX Female           0   14    1361        0.93      90.79
+17   G: IROX Female           1  121    1482        8.07      98.87
+18   G: IROX Female        <NA>   17    1499        1.13     100.00
+ +
+
+

Basic output using summary

+

The summary method for freqlist relies on the kable function (in the knitr package) for printing. knitr::kable converts the output to markdown which can be printed in the console or easily rendered in Word, pdf, or html documents.

+

Note that you must supply results="asis" to properly format the markdown output.

+
summary(noby)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
armsexmdquality.sFreqcumFreqfreqPercentcumPercent
A: IFLMale029291.931.93
121424314.2816.21
NA342772.2718.48
Female0122890.8019.28
11184077.8727.15
NA214281.4028.55
F: FOLFOXMale0314592.0730.62
128574419.0149.63
NA958396.3455.97
Female0218601.4057.37
1198105813.2170.58
NA6111194.0774.65
G: IROXMale01711361.1375.78
1187132312.4788.26
NA2413471.6089.86
Female01413610.9390.79
112114828.0798.87
NA1714991.13100.00
+

Additional arguments (except digits) in the kable function can be passed through. Perhaps the most useful is caption.

+
summary(noby, caption = "Basic freqlist output")
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Basic freqlist output
armsexmdquality.sFreqcumFreqfreqPercentcumPercent
A: IFLMale029291.931.93
121424314.2816.21
NA342772.2718.48
Female0122890.8019.28
11184077.8727.15
NA214281.4028.55
F: FOLFOXMale0314592.0730.62
128574419.0149.63
NA958396.3455.97
Female0218601.4057.37
1198105813.2170.58
NA6111194.0774.65
G: IROXMale01711361.1375.78
1187132312.4788.26
NA2413471.6089.86
Female01413610.9390.79
112114828.0798.87
NA1714991.13100.00
+

You can also easily pull out the freqlist data frame for more complicated formatting or manipulation (e.g. with another function such as xtable or pander) using as.data.frame:

+
head(as.data.frame(noby))
+
     arm    sex mdquality.s Freq cumFreq freqPercent cumPercent
+1 A: IFL   Male           0   29      29        1.93       1.93
+2 A: IFL   Male           1  214     243       14.28      16.21
+3 A: IFL   Male        <NA>   34     277        2.27      18.48
+4 A: IFL Female           0   12     289        0.80      19.28
+5 A: IFL Female           1  118     407        7.87      27.15
+6 A: IFL Female        <NA>   21     428        1.40      28.55
+ +
+
+

Rounding percentage digits or changing variable names for printing

+

The digits argument takes a single numeric value and controls the rounding of percentages in the output. The labelTranslations argument is a character vector whose length must be equal to the number of factors used in the table. Note: this does not change the names of the data frame in the freqlist object, only those used in printing. Both options are applied in the following example.

+
withnames <- freqlist(tab.ex, labelTranslations = c("Treatment Arm", "Gender", "LASA QOL"), 
+    digits = 0)
+
+summary(withnames)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Treatment ArmGenderLASA QOLFreqcumFreqfreqPercentcumPercent
A: IFLMale0292922
12142431416
NA34277218
Female012289119
1118407827
NA21428129
F: FOLFOXMale031459231
12857441950
NA95839656
Female021860157
119810581371
NA611119475
G: IROXMale0171136176
118713231288
NA241347290
Female0141361191
11211482899
NA1714991100
+ +
+
+

Additional examples

+
+

Including combinations with frequencies of zero

+

The sparse argument takes a single logical value as input. The default option is FALSE. If set to TRUE, the sparse option will include combinations with frequencies of zero in the list of results. As our initial table did not have any such levels, we create a second table to use in our example.

+
# we create a second table example to showcase the sparse argument
+tab.sparse <- table(mockstudy[, c("race", "sex", "arm")])
+
+nobysparse <- freqlist(tab.sparse, sparse = TRUE, digits = 1)
+summary(nobysparse)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
racesexarmFreqcumFreqfreqPercentcumPercent
African-AmMaleA: IFL25251.71.7
F: FOLFOX24491.63.3
G: IROX16651.14.4
FemaleA: IFL14790.95.3
F: FOLFOX251041.77.0
G: IROX111150.77.7
AsianMaleA: IFL01150.07.7
F: FOLFOX101250.78.4
G: IROX11260.18.4
FemaleA: IFL11270.18.5
F: FOLFOX41310.38.8
G: IROX21330.18.9
CaucasianMaleA: IFL24037316.125.0
F: FOLFOX35272523.648.6
G: IROX19592013.161.7
FemaleA: IFL13110518.870.4
F: FOLFOX234128515.786.1
G: IROX13614219.195.2
Hawaii/PacificMaleA: IFL114220.195.3
F: FOLFOX114230.195.4
G: IROX014230.095.4
FemaleA: IFL014230.095.4
F: FOLFOX214250.195.5
G: IROX114260.195.6
HispanicMaleA: IFL814340.596.1
F: FOLFOX1714511.197.3
G: IROX1214630.898.1
FemaleA: IFL414670.398.3
F: FOLFOX1114780.799.1
G: IROX214800.199.2
Native-Am/AlaskaMaleA: IFL114810.199.3
F: FOLFOX014810.099.3
G: IROX214830.199.4
FemaleA: IFL114840.199.5
F: FOLFOX114850.199.5
G: IROX014850.099.5
OtherMaleA: IFL214870.199.7
F: FOLFOX214890.199.8
G: IROX114900.199.9
FemaleA: IFL014900.099.9
F: FOLFOX214920.1100.0
G: IROX014920.0100.0
+
+
+

Options for NA handling

+

The various na.options allow you to include or exclude data with missing values for one or more factor levels in the counts and percentages as well as show the missing data but exclude it from the cumulative counts and percentages. The default option is to include all combinations with missing values.

+
summary(freqlist(tab.ex, na.options = "include"))
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
armsexmdquality.sFreqcumFreqfreqPercentcumPercent
A: IFLMale029291.931.93
121424314.2816.21
NA342772.2718.48
Female0122890.8019.28
11184077.8727.15
NA214281.4028.55
F: FOLFOXMale0314592.0730.62
128574419.0149.63
NA958396.3455.97
Female0218601.4057.37
1198105813.2170.58
NA6111194.0774.65
G: IROXMale01711361.1375.78
1187132312.4788.26
NA2413471.6089.86
Female01413610.9390.79
112114828.0798.87
NA1714991.13100.00
+
summary(freqlist(tab.ex, na.options = "showexclude"))
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
armsexmdquality.sFreqcumFreqfreqPercentcumPercent
A: IFLMale029292.332.33
121424317.1619.49
NA34NANANA
Female0122550.9620.45
11183739.4629.91
NA21NANANA
F: FOLFOXMale0314042.4932.40
128568922.8555.25
NA95NANANA
Female0217101.6856.94
119890815.8872.81
NA61NANANA
G: IROXMale0179251.3674.18
1187111215.0089.17
NA24NANANA
Female01411261.1290.30
112112479.70100.00
NA17NANANA
+
summary(freqlist(tab.ex, na.options = "remove"))
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
armsexmdquality.sFreqcumFreqfreqPercentcumPercent
A: IFLMale029292.332.33
121424317.1619.49
Female0122550.9620.45
11183739.4629.91
F: FOLFOXMale0314042.4932.40
128568922.8555.25
Female0217101.6856.94
119890815.8872.81
G: IROXMale0179251.3674.18
1187111215.0089.17
Female01411261.1290.30
112112479.70100.00
+
+
+

Frequency counts and percentages subset by factor levels

+

The groupBy argument internally subsets the data by the specified factor prior to calculating cumulative counts and percentages. By default, when used each subset will print in a separate table. Using the single = TRUE option when printing will collapse the subsetted result into a single table.

+
withby <- freqlist(tab.ex, groupBy = c("arm", "sex"))
+summary(withby)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
armsexmdquality.sFreqcumFreqfreqPercentcumPercent
A: IFLMale0292910.4710.47
121424377.2687.73
NA3427712.27100.00
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
armsexmdquality.sFreqcumFreqfreqPercentcumPercent
A: IFLFemale012127.957.95
111813078.1586.09
NA2115113.91100.00
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
armsexmdquality.sFreqcumFreqfreqPercentcumPercent
F: FOLFOXMale031317.547.54
128531669.3476.89
NA9541123.11100.00
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
armsexmdquality.sFreqcumFreqfreqPercentcumPercent
F: FOLFOXFemale021217.507.50
119821970.7178.21
NA6128021.79100.00
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
armsexmdquality.sFreqcumFreqfreqPercentcumPercent
G: IROXMale017177.467.46
118720482.0289.47
NA2422810.53100.00
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
armsexmdquality.sFreqcumFreqfreqPercentcumPercent
G: IROXFemale014149.219.21
112113579.6188.82
NA1715211.18100.00
+
# using the single = TRUE argument will collapse results into a single table for
+# printing
+summary(withby, single = TRUE)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
armsexmdquality.sFreqcumFreqfreqPercentcumPercent
A: IFLMale0292910.4710.47
121424377.2687.73
NA3427712.27100.00
Female012127.957.95
111813078.1586.09
NA2115113.91100.00
F: FOLFOXMale031317.547.54
128531669.3476.89
NA9541123.11100.00
Female021217.507.50
119821970.7178.21
NA6128021.79100.00
G: IROXMale017177.467.46
118720482.0289.47
NA2422810.53100.00
Female014149.219.21
112113579.6188.82
NA1715211.18100.00
+
+
+

Change labels on the fly

+

At this time, the labels can be changed just for the variables (e.g. not the frequency columns).

+
labels(noby) <- c("Arm", "Sex", "OtherThing")
+summary(noby)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ArmSexOtherThingFreqcumFreqfreqPercentcumPercent
A: IFLMale029291.931.93
121424314.2816.21
NA342772.2718.48
Female0122890.8019.28
11184077.8727.15
NA214281.4028.55
F: FOLFOXMale0314592.0730.62
128574419.0149.63
NA958396.3455.97
Female0218601.4057.37
1198105813.2170.58
NA6111194.0774.65
G: IROXMale01711361.1375.78
1187132312.4788.26
NA2413471.6089.86
Female01413610.9390.79
112114828.0798.87
NA1714991.13100.00
+

You can also supply labelTranslations to summary.

+
summary(noby, labelTranslations = c("Hi there", "What up", "Bye"))
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Hi thereWhat upByeFreqcumFreqfreqPercentcumPercent
A: IFLMale029291.931.93
121424314.2816.21
NA342772.2718.48
Female0122890.8019.28
11184077.8727.15
NA214281.4028.55
F: FOLFOXMale0314592.0730.62
128574419.0149.63
NA958396.3455.97
Female0218601.4057.37
1198105813.2170.58
NA6111194.0774.65
G: IROXMale01711361.1375.78
1187132312.4788.26
NA2413471.6089.86
Female01413610.9390.79
112114828.0798.87
NA1714991.13100.00
+
+
+

Using xtable to format and print freqlist results

+

Fair warning: xtable has kind of a steep learning curve. These examples are given without explanation for more advanced users.

+
require(xtable)
+
Loading required package: xtable
+
# set up custom function for xtable text
+italic <- function(x) {
+    paste0("<i>", x, "</i>")
+}
+
xftbl <- xtable(noby[["freqlist"]], caption = "xtable formatted output of freqlist data frame", 
+    align = "|r|r|r|r|c|c|c|r|")
+
+# change the column names
+names(xftbl)[1:3] <- c("Arm", "Gender", "LASA QOL")
+
+print(xftbl, sanitize.colnames.function = italic, include.rownames = FALSE, type = "html", 
+    comment = FALSE)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+xtable formatted output of freqlist data frame +
+Arm + +Gender + +LASA QOL + +Freq + +cumFreq + +freqPercent + +cumPercent +
+A: IFL + +Male + +0 + +29 + +29 + +1.93 + +1.93 +
+A: IFL + +Male + +1 + +214 + +243 + +14.28 + +16.21 +
+A: IFL + +Male + + +34 + +277 + +2.27 + +18.48 +
+A: IFL + +Female + +0 + +12 + +289 + +0.80 + +19.28 +
+A: IFL + +Female + +1 + +118 + +407 + +7.87 + +27.15 +
+A: IFL + +Female + + +21 + +428 + +1.40 + +28.55 +
+F: FOLFOX + +Male + +0 + +31 + +459 + +2.07 + +30.62 +
+F: FOLFOX + +Male + +1 + +285 + +744 + +19.01 + +49.63 +
+F: FOLFOX + +Male + + +95 + +839 + +6.34 + +55.97 +
+F: FOLFOX + +Female + +0 + +21 + +860 + +1.40 + +57.37 +
+F: FOLFOX + +Female + +1 + +198 + +1058 + +13.21 + +70.58 +
+F: FOLFOX + +Female + + +61 + +1119 + +4.07 + +74.65 +
+G: IROX + +Male + +0 + +17 + +1136 + +1.13 + +75.78 +
+G: IROX + +Male + +1 + +187 + +1323 + +12.47 + +88.26 +
+G: IROX + +Male + + +24 + +1347 + +1.60 + +89.86 +
+G: IROX + +Female + +0 + +14 + +1361 + +0.93 + +90.79 +
+G: IROX + +Female + +1 + +121 + +1482 + +8.07 + +98.87 +
+G: IROX + +Female + + +17 + +1499 + +1.13 + +100.00 +
+ +
+
+
+

Appendix: Notes regarding table options in R

+
+

NAs

+

There are several widely used options for basic tables in R. The table function in base R is probably the most common; by default it excludes NA values. You can change NA handling in base::table using the useNA or exclude arguments.

+
# base table default removes NAs
+tab.d1 <- base::table(mockstudy[, c("arm", "sex", "mdquality.s")], useNA = "ifany")
+tab.d1
+
, , mdquality.s = 0
+
+           sex
+arm         Male Female
+  A: IFL      29     12
+  F: FOLFOX   31     21
+  G: IROX     17     14
+
+, , mdquality.s = 1
+
+           sex
+arm         Male Female
+  A: IFL     214    118
+  F: FOLFOX  285    198
+  G: IROX    187    121
+
+, , mdquality.s = NA
+
+           sex
+arm         Male Female
+  A: IFL      34     21
+  F: FOLFOX   95     61
+  G: IROX     24     17
+

xtabs is similar to table, but uses a formula-based syntax. However, there is not an option for retaining NAs in the xtabs function; instead, NAs must be added to each level of the factor where present using the addNA function.

+
# without specifying addNA
+tab.d2 <- xtabs(formula = ~arm + sex + mdquality.s, data = mockstudy)
+tab.d2
+
, , mdquality.s = 0
+
+           sex
+arm         Male Female
+  A: IFL      29     12
+  F: FOLFOX   31     21
+  G: IROX     17     14
+
+, , mdquality.s = 1
+
+           sex
+arm         Male Female
+  A: IFL     214    118
+  F: FOLFOX  285    198
+  G: IROX    187    121
+
# now with addNA
+tab.d3 <- xtabs(~arm + sex + addNA(mdquality.s), data = mockstudy)
+tab.d3
+
, , addNA(mdquality.s) = 0
+
+           sex
+arm         Male Female
+  A: IFL      29     12
+  F: FOLFOX   31     21
+  G: IROX     17     14
+
+, , addNA(mdquality.s) = 1
+
+           sex
+arm         Male Female
+  A: IFL     214    118
+  F: FOLFOX  285    198
+  G: IROX    187    121
+
+, , addNA(mdquality.s) = NA
+
+           sex
+arm         Male Female
+  A: IFL      34     21
+  F: FOLFOX   95     61
+  G: IROX     24     17
+
+
+

Table dimname names (dnn)

+

Supplying a data.frame to the table function without giving columns individually will create a contingency table using all variables in the data.frame.

+

However, if the columns of a data.frame or matrix are supplied separately (i.e., as vectors), column names will not be preserved.

+
# providing variables separately (as vectors) drops column names
+tab.d4 <- base::table(mockstudy[, "arm"], mockstudy[, "sex"], mockstudy[, "mdquality.s"])
+tab.d4
+
, ,  = 0
+
+           
+            Male Female
+  A: IFL      29     12
+  F: FOLFOX   31     21
+  G: IROX     17     14
+
+, ,  = 1
+
+           
+            Male Female
+  A: IFL     214    118
+  F: FOLFOX  285    198
+  G: IROX    187    121
+

If desired, you can use the dnn argument to pass variable names.

+
# add the column name labels back using dnn option in base::table
+tab.dnn <- base::table(mockstudy[, "arm"], mockstudy[, "sex"], mockstudy[, "mdquality.s"], 
+    dnn = c("Amy", "Susan", "George"))
+tab.dnn
+
, , George = 0
+
+           Susan
+Amy         Male Female
+  A: IFL      29     12
+  F: FOLFOX   31     21
+  G: IROX     17     14
+
+, , George = 1
+
+           Susan
+Amy         Male Female
+  A: IFL     214    118
+  F: FOLFOX  285    198
+  G: IROX    187    121
+

If using freqlist, you can provide the labels directly to freqlist or to summary using labelTranslations.

+
+
+ + + + + + + + diff --git a/inst/doc/freqlist.pdf b/inst/doc/freqlist.pdf deleted file mode 100644 index 306cb93438481caf946862d3dc2001ebd85e7130..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 258253 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%0ACRIkCU!n^cM%G1B`z27D@Oo{(! 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 diff --git a/inst/doc/modelsum.R b/inst/doc/modelsum.R index 1ff4c13..a400bbb 100644 --- a/inst/doc/modelsum.R +++ b/inst/doc/modelsum.R @@ -6,12 +6,8 @@ require(MASS) require(pROC) require(rpart) -opts_chunk$set(comment = NA, echo=TRUE, prompt=TRUE ,collapse=TRUE) +opts_chunk$set(comment = NA, echo=TRUE, prompt=TRUE, collapse=TRUE) -#vignette: > -# %\VignetteIndexEntry{modelsum} -# %\VignetteEngine{knitr::rmarkdown} -# \usepackage[utf8]{inputenc} ## ---- load-data---------------------------------------------------------- require(arsenal) @@ -29,6 +25,9 @@ summary(tab1, text=TRUE) ## ----simple-markdown, results='asis'------------------------------------- summary(tab1) +## ------------------------------------------------------------------------ +as.data.frame(tab1) + ## ----adjust, results="asis"---------------------------------------------- tab2 <- modelsum(alk.phos ~ arm + ps + hgb, adjust= ~age + sex, data=mockstudy) summary(tab2) @@ -374,15 +373,17 @@ mockstudy$wts <- gpwts[index] ## show weights by treatment arm group tapply(mockstudy$wts,mockstudy$arm, summary) -## ----results='asis', warning=FALSE--------------------------------------- +## ----results='asis'------------------------------------------------------ mockstudy$newvarA <- as.numeric(mockstudy$arm=='A: IFL') tab1 <- modelsum(newvarA ~ ast + bmi + hgb, data=mockstudy, subset=(arm !='G: IROX'), family=binomial) summary(tab1, title='No Case Weights used') +suppressWarnings({ tab2 <- modelsum(newvarA ~ ast + bmi + hgb, data=mockstudy, subset=(arm !='G: IROX'), weights=wts, family=binomial) summary(tab2, title='Case Weights used') +}) ## ------------------------------------------------------------------------ summary(tab2, text=T) diff --git a/inst/doc/modelsum.Rmd b/inst/doc/modelsum.Rmd index 03dc754..97a23b6 100644 --- a/inst/doc/modelsum.Rmd +++ b/inst/doc/modelsum.Rmd @@ -3,15 +3,9 @@ title: "The modelsum function" author: "Beth Atkinson, Pat Votruba, Jason Sinnwell, Shannon McDonnell and Greg Dougherty" date: '`r format(Sys.time(),"%d %B, %Y")`' output: - html_document: - toc: yes - toc_depth: '3' - pdf_document: + rmarkdown::html_vignette: toc: yes toc_depth: 3 - word_document: - toc: yes - toc_depth: '3' vignette: | %\VignetteIndexEntry{The modelsum function} %\VignetteEncoding{UTF-8} @@ -26,17 +20,12 @@ require(MASS) require(pROC) require(rpart) -opts_chunk$set(comment = NA, echo=TRUE, prompt=TRUE ,collapse=TRUE) +opts_chunk$set(comment = NA, echo=TRUE, prompt=TRUE, collapse=TRUE) -#vignette: > -# %\VignetteIndexEntry{modelsum} -# %\VignetteEngine{knitr::rmarkdown} -# \usepackage[utf8]{inputenc} ``` -Introduction -============= +# Introduction Very often we are asked to summarize model results from multiple fits into a nice table. The endpoint might be of different types (e.g., survival, case/control, continuous) and there @@ -54,10 +43,9 @@ so the tables could be displayed within an R markdown report. This report provides step-by-step directions for using the functions associated with `modelsum`. All functions presented here are available within the `arsenal` package. An assumption is made that users are somewhat familiar with R markdown documents. For those who are new to the topic, a good initial -resource is available at [rmarkdown.rstudio.com](rmarkdown.rstudio.com). +resource is available at [rmarkdown.rstudio.com](http://rmarkdown.rstudio.com). -Simple Example -================ +# Simple Example The first step when using the `modelsum` function is to load the `arsenal` package. All the examples in this report use a dataset called `mockstudy` made available by Paul Novotny which includes a variety of types of variables @@ -82,7 +70,7 @@ If you want to take a quick look at the table, you can use `summary` on your mod print out as text in your R console window. If you use `summary` without any options you will see a number of $\ $ statements which translates to "space" in HTML. -### Pretty text version of table +## Pretty text version of table If you want a nicer version in your console window then adding the `text=TRUE` option. @@ -90,23 +78,25 @@ If you want a nicer version in your console window then adding the `text=TRUE` o summary(tab1, text=TRUE) ``` -### Pretty Rmarkdown version of table +## Pretty Rmarkdown version of table In order for the report to look nice within an R markdown (knitr) report, you just need to specify `results="asis"` when creating the r chunk. This changes the layout slightly (compresses it) and bolds -the variable names. The three single quotes are often located above the tab key. - -`r ''` ```{r results="asis"} - - summary(tab1) - -``` +the variable names. ```{r simple-markdown, results='asis'} summary(tab1) ``` -### Add an adjustor to the model +## Data frame version of table + +If you want a data.frame version, simply use `as.data.frame`. + +```{r} +as.data.frame(tab1) +``` + +## Add an adjustor to the model The argument `adjust` allows the user to indicate that all the variables should be adjusted for these terms. @@ -116,16 +106,14 @@ summary(tab2) ``` -Models for each endpoint type -================================== +# Models for each endpoint type To make sure the correct model is run you need to specify "family". The options available right now are : gaussian, binomial, survival, and poisson. If there is enough interest, additional models can be added. -Gaussian ------------ +## Gaussian -### fit and summarize linear regression model +### Fit and summarize linear regression model Look at whether there is any evidence that AlkPhos values vary by study arm after adjusting for sex and age (assuming a linear age relationship). @@ -163,7 +151,7 @@ termplot(fit3, term=2, se=T, rug=T) In this instance it looks like there isn't enough evidence to say that the relationship is non-linear. -### extract data using the `broom` package +### Extract data using the `broom` package The `broom` package makes it easy to extract information from the fit. @@ -175,7 +163,7 @@ tmp glance(fit3) ``` -### create a summary table using modelsum +### Create a summary table using modelsum ```{r, results="asis"} ms.logy <- modelsum(log(alk.phos) ~ arm + ps + hgb, data=mockstudy, adjust= ~age + sex, @@ -184,10 +172,9 @@ ms.logy <- modelsum(log(alk.phos) ~ arm + ps + hgb, data=mockstudy, adjust= ~age summary(ms.logy) ``` -Binomial ----------- +## Binomial -### fit and summarize logistic regression model +### Fit and summarize logistic regression model ```{r} boxplot(age ~ mdquality.s, data=mockstudy, ylab=attr(mockstudy$age,'label'), xlab='mdquality.s') @@ -216,7 +203,7 @@ tmp$auc ``` -### extract data using `broom` package +### Extract data using `broom` package The `broom` package makes it easy to extract information from the fit. @@ -226,7 +213,7 @@ tidy(fit, exp=T, conf.int=T) # coefficients, p-values, conf.intervals glance(fit) # model summary statistics ``` -### create a summary table using modelsum +### Create a summary table using modelsum ```{r, results="asis"} summary(modelsum(mdquality.s ~ age + bmi, data=mockstudy, adjust=~sex, family=binomial)) @@ -237,10 +224,9 @@ summary(fitall) ``` -Survival ---------- +## Survival -### fit and summarize a Cox regression model +### Fit and summarize a Cox regression model ```{r survival} require(survival) @@ -271,7 +257,7 @@ summary(fit2)$concordance survConcordance(Surv(fu.time, fu.stat) ~ predict(fit2), data=mockstudy) ``` -### extract data using `broom` package +### Extract data using `broom` package The `broom` package makes it easy to extract information from the fit. @@ -281,7 +267,7 @@ tidy(fit) # coefficients, p-values glance(fit) # model summary statistics ``` -### create a summary table using modelsum +### Create a summary table using modelsum ```{r results="asis"} ##Note: You must use quotes when specifying family="survival" @@ -295,8 +281,7 @@ summary(modelsum(Surv(fu.time, fu.stat) ~ arm, ``` -Poisson --------- +## Poisson Poisson regression is useful when predicting an outcome variable representing counts. It can also be useful when looking at survival data. Cox models and Poisson models are very closely @@ -331,7 +316,7 @@ fit2 <- glm(skips ~ Opening + Solder + Mask, data=solder, family=quasipoisson) summary(fit2) ``` -### extract data using `broom` package +### Extract data using `broom` package The `broom` package makes it easy to extract information from the fit. @@ -342,7 +327,7 @@ glance(fit) # model summary statistics ``` -### create a summary table using modelsum +### Create a summary table using modelsum ```{r results='asis'} summary(modelsum(skips~Opening + Solder + Mask, data=solder, family="quasipoisson")) @@ -373,7 +358,7 @@ fit2 <- glm(fu.stat ~ offset(log(fu.time+.01)) + age + sex + arm, summary(fit2) ``` -### extract data using `broom` package +### Extract data using `broom` package The `broom` package makes it easy to extract information from the fit. @@ -384,7 +369,7 @@ glance(fit) ##model summary statistics ``` -### create a summary table using modelsum +### Create a summary table using `modelsum` Remember that the result from `modelsum` is different from the `fit` above. The `modelsum` summary shows the results for `age + offset(log(fu.time+.01))` then `sex + offset(log(fu.time+.01))` @@ -397,12 +382,12 @@ summary(modelsum(fu.stat ~ age, adjust=~offset(log(fu.time+.01))+ sex + arm, ``` -Additional Examples -==================== +# Additional Examples + Here are multiple examples showing how to use some of the different options. -###1. Change summary statistics globally +## 1. Change summary statistics globally There are standard settings for each type of model regarding what information is summarized in the table. This behavior can be modified using the modelsum.control function. In fact, you can save your standard @@ -425,7 +410,7 @@ tab3 <- modelsum(bmi ~ age, adjust=~sex, data=mockstudy, summary(tab3) ``` -###2. Add labels to independent variables +## 2. Add labels to independent variables In the above example, age is shown with a label (Age in Years), but sex is listed "as is". This is because the data was created in SAS and in the SAS dataset, age had a label but sex did not. @@ -470,20 +455,20 @@ labels(tab1) summary(tab1) ``` -###2. Don't show intercept values +## 3. Don't show intercept values ```{r, results='asis'} summary(modelsum(age~mdquality.s+sex, data=mockstudy), show.intercept=FALSE) ``` -###3. Don't show results for adjustment variables +## 4. Don't show results for adjustment variables ```{r, results='asis'} summary(modelsum(mdquality.s ~ age + bmi, data=mockstudy, adjust=~sex, family=binomial), show.adjust=FALSE) ``` -###4. Summarize multiple variables without typing them out +## 5. Summarize multiple variables without typing them out Often one wants to summarize a number of variables. Instead of typing by hand each individual variable, an alternative approach is to create a formula using the `paste` command with the `collapse="+"` option. @@ -519,7 +504,7 @@ summary(modelsum(tmp, data=mockstudy, family=binomial)) ``` -###5. Subset the dataset used in the analysis +## 6. Subset the dataset used in the analysis Here are two ways to get the same result (limit the analysis to subjects age>50 and in the F: FOLFOX treatment group). @@ -548,7 +533,7 @@ summary(modelsum(alk.phos ~ ps + bmi, adjust=~sex, subset = age>50 & bmi<24, dat summary(modelsum(alk.phos ~ ps + bmi, adjust=~sex, subset=1:30, data=mockstudy)) ``` -###6. Create combinations of variables on the fly +## 7. Create combinations of variables on the fly ```{r} ## create a variable combining the levels of mdquality.s and sex @@ -559,7 +544,7 @@ with(mockstudy, table(interaction(mdquality.s,sex))) summary(modelsum(age ~ interaction(mdquality.s,sex), data=mockstudy)) ``` -###9. Transform variables on the fly +## 8. Transform variables on the fly Certain transformations need to be surrounded by `I()` so that R knows to treat it as a variable transformation and not some special model feature. If the transformation includes any of the @@ -572,7 +557,7 @@ summary(modelsum(arm=="F: FOLFOX" ~ I(age/10) + log(bmi) + mdquality.s, ``` -###10. Change the ordering of the variables or delete a variable +## 9. Change the ordering of the variables or delete a variable ```{r, results='asis'} mytab <- modelsum(bmi ~ sex + alk.phos + age, data=mockstudy) @@ -582,7 +567,7 @@ summary(mytab[c('age','sex')]) summary(mytab[c(3,1)]) ``` -###11. Merge two modelsum objects together +## 10. Merge two `modelsum` objects together It is possible to combine two modelsum objects so that they print out together, however you need to pay attention to the columns that are being displayed. It is easier to combine two models of the same @@ -602,7 +587,7 @@ class(tab12) #summary(tab12) ``` -###12. Add a title to the table +## 11. Add a title to the table When creating a pdf the tables are automatically numbered and the title appears below the table. In Word and HTML, the titles appear un-numbered and above the table. @@ -612,11 +597,12 @@ t1 <- modelsum(bmi ~ sex + age, data=mockstudy) summary(t1, title='Demographics') ``` -###13. Modify how missing values are treated +## 12. Modify how missing values are treated Depending on the report you are writing you have the following options: * Use all values available for each variable + * Use only those subjects who have measurements available for all the variables ```{r} @@ -642,13 +628,16 @@ summary(modelsum(bmi ~ ast + age, data=mockstudy, control=modelsum.control(gaussian.stats=c("estimate")))) ``` -###14. Modify the number of digits used +## 13. Modify the number of digits used Within modelsum.control function there are 4 options for controlling the number of significant digits shown. * digits: controls the number of significant digits (counting both before and after the decimal point) for continuous variables + * nsmall: controls the number of digits after the decimal point for the beta and standard error + * nsmall.ratio: controls the number of digits for the ratio statistics (OR, HR, RR), default=2 + * digits.test: controls the number of digits after the decimal point for p-values (default=3) ```{r, results='asis'} @@ -670,7 +659,7 @@ format(pi*100, nsmall=4) format(pi*100, nsmall=2, digits=4) ``` -###15. Use case-weights in the models +## 14. Use case-weights in the models Occasionally it is of interest to fit models using case weights. The `modelsum` function allows you to pass on the weights to the models and it will do the appropriate fit. @@ -692,18 +681,20 @@ mockstudy$wts <- gpwts[index] tapply(mockstudy$wts,mockstudy$arm, summary) ``` -```{r results='asis', warning=FALSE} +```{r results='asis'} mockstudy$newvarA <- as.numeric(mockstudy$arm=='A: IFL') tab1 <- modelsum(newvarA ~ ast + bmi + hgb, data=mockstudy, subset=(arm !='G: IROX'), family=binomial) summary(tab1, title='No Case Weights used') +suppressWarnings({ tab2 <- modelsum(newvarA ~ ast + bmi + hgb, data=mockstudy, subset=(arm !='G: IROX'), weights=wts, family=binomial) summary(tab2, title='Case Weights used') +}) ``` -###16. Use `modelsum` within an Sweave document +## 15. Use `modelsum` within an Sweave document For those users who wish to create tables within an Sweave document, the following code seems to work. @@ -737,7 +728,7 @@ render("Test.md", pdf_document(keep_tex=TRUE)) \end{document} ``` -###17. Export `modelsum` results to a .CSV file +## 16. Export `modelsum` results to a .CSV file When looking at multiple variables it is sometimes useful to export the results to a csv file. The `as.data.frame` function creates a data frame object that can be exported or further manipulated within R. @@ -750,7 +741,7 @@ tmp # write.csv(tmp, '/my/path/here/mymodel.csv') ``` -###18. Write `modelsum` object to a separate Word or HTML file +## 17. Write `modelsum` object to a separate Word or HTML file ```{r} ## write to an HTML document @@ -760,10 +751,9 @@ tmp # write2word(tab2, "~/ibm/trash.doc", title="My table in Word") ``` -Available Function Options -================================== +# Available Function Options -### Summary statistics +## Summary statistics The available summary statistics, by varible type, are: @@ -827,7 +817,7 @@ The full description of these parameters that can be shown for models include: * `CI.lower.estimate, CI.upper.estimate`: print the confidence interval for the beta coefficient -### modelsum.control settings +## `modelsum.control` settings A quick way to see what arguments are possible to utilize in a function is to use the `args()` command. Settings involving the number of digits can be set in `modelsum.control` or in `summary.modelsum`. @@ -851,7 +841,7 @@ Settings: * poisson.stats, quasipoisson.stats -### summary.modelsum settings +## `summary.modelsum` settings The summary.modelsum function has options that modify how the table appears (such as adding a title or modifying labels). diff --git a/inst/doc/modelsum.html b/inst/doc/modelsum.html index a53f2c5..753030d 100644 --- a/inst/doc/modelsum.html +++ b/inst/doc/modelsum.html @@ -8,119 +8,69 @@ + The modelsum function - - - - - - + - - - - - + - - - - -

- - - - - - - - - - - - -
@@ -186,59 +137,56 @@

29 December, 2016

Introduction

Very often we are asked to summarize model results from multiple fits into a nice table. The endpoint might be of different types (e.g., survival, case/control, continuous) and there may be several independent variables that we want to examine univariately or adjusted for certain variables such as age and sex. Locally, the SAS macros %modelsum, %glmuniv, and %logisuni were written to create such summary tables. With the increasing interest in R, we have developed the function modelsum to create similar tables within the R environment.

In developing the modelsum function, the goal was to bring the best features of these macros into an R function. However, the task was not simply to duplicate all the functionality, but rather to make use of R’s strengths (modeling, method dispersion, flexibility in function definition and output format) and make a tool that fits the needs of R users. Additionally, the results needed to fit within the general reproducible research framework so the tables could be displayed within an R markdown report.

-

This report provides step-by-step directions for using the functions associated with modelsum. All functions presented here are available within the arsenal package. An assumption is made that users are somewhat familiar with R markdown documents. For those who are new to the topic, a good initial resource is available at rmarkdown.rstudio.com.

+

This report provides step-by-step directions for using the functions associated with modelsum. All functions presented here are available within the arsenal package. An assumption is made that users are somewhat familiar with R markdown documents. For those who are new to the topic, a good initial resource is available at rmarkdown.rstudio.com.

Simple Example

The first step when using the modelsum function is to load the arsenal package. All the examples in this report use a dataset called mockstudy made available by Paul Novotny which includes a variety of types of variables (character, numeric, factor, ordered factor, survival) to use as examples.

-
> require(arsenal)
-> data(mockstudy) # load data
-> dim(mockstudy)  # look at how many subjects and variables are in the dataset 
-[1] 1499   14
-> # help(mockstudy) # learn more about the dataset and variables
-> str(mockstudy) # quick look at the data
-'data.frame':   1499 obs. of  14 variables:
- $ case       : int  110754 99706 105271 105001 112263 86205 99508 90158 88989 90515 ...
- $ age        : atomic  67 74 50 71 69 56 50 57 51 63 ...
-  ..- attr(*, "label")= chr "Age in Years"
- $ arm        : atomic  F: FOLFOX A: IFL A: IFL G: IROX ...
-  ..- attr(*, "label")= chr "Treatment Arm"
- $ sex        : Factor w/ 2 levels "Male","Female": 1 2 2 2 2 1 1 1 2 1 ...
- $ race       : atomic  Caucasian Caucasian Caucasian Caucasian ...
-  ..- attr(*, "label")= chr "Race"
- $ fu.time    : int  922 270 175 128 233 120 369 421 387 363 ...
- $ fu.stat    : int  2 2 2 2 2 2 2 2 2 2 ...
- $ ps         : int  0 1 1 1 0 0 0 0 1 1 ...
- $ hgb        : num  11.5 10.7 11.1 12.6 13 10.2 13.3 12.1 13.8 12.1 ...
- $ bmi        : atomic  25.1 19.5 NA 29.4 26.4 ...
-  ..- attr(*, "label")= chr "Body Mass Index (kg/m^2)"
- $ alk.phos   : int  160 290 700 771 350 569 162 152 231 492 ...
- $ ast        : int  35 52 100 68 35 27 16 12 25 18 ...
- $ mdquality.s: int  NA 1 1 1 NA 1 1 1 1 1 ...
- $ age.ord    : Ord.factor w/ 8 levels "10-19"<"20-29"<..: 6 7 4 7 6 5 4 5 5 6 ...
+
> require(arsenal)
+> data(mockstudy) # load data
+> dim(mockstudy)  # look at how many subjects and variables are in the dataset 
+[1] 1499   14
+> # help(mockstudy) # learn more about the dataset and variables
+> str(mockstudy) # quick look at the data
+'data.frame':   1499 obs. of  14 variables:
+ $ case       : int  110754 99706 105271 105001 112263 86205 99508 90158 88989 90515 ...
+ $ age        : atomic  67 74 50 71 69 56 50 57 51 63 ...
+  ..- attr(*, "label")= chr "Age in Years"
+ $ arm        : atomic  F: FOLFOX A: IFL A: IFL G: IROX ...
+  ..- attr(*, "label")= chr "Treatment Arm"
+ $ sex        : Factor w/ 2 levels "Male","Female": 1 2 2 2 2 1 1 1 2 1 ...
+ $ race       : atomic  Caucasian Caucasian Caucasian Caucasian ...
+  ..- attr(*, "label")= chr "Race"
+ $ fu.time    : int  922 270 175 128 233 120 369 421 387 363 ...
+ $ fu.stat    : int  2 2 2 2 2 2 2 2 2 2 ...
+ $ ps         : int  0 1 1 1 0 0 0 0 1 1 ...
+ $ hgb        : num  11.5 10.7 11.1 12.6 13 10.2 13.3 12.1 13.8 12.1 ...
+ $ bmi        : atomic  25.1 19.5 NA 29.4 26.4 ...
+  ..- attr(*, "label")= chr "Body Mass Index (kg/m^2)"
+ $ alk.phos   : int  160 290 700 771 350 569 162 152 231 492 ...
+ $ ast        : int  35 52 100 68 35 27 16 12 25 18 ...
+ $ mdquality.s: int  NA 1 1 1 NA 1 1 1 1 1 ...
+ $ age.ord    : Ord.factor w/ 8 levels "10-19"<"20-29"<..: 6 7 4 7 6 5 4 5 5 6 ...

To create a simple linear regression table (the default), use a formula statement to specify the variables that you want summarized. The example below predicts BMI with the variables sex and age.

-
> tab1 <- modelsum(bmi ~ sex + age, data=mockstudy)
+
> tab1 <- modelsum(bmi ~ sex + age, data=mockstudy)

If you want to take a quick look at the table, you can use summary on your modelsum object and the table will print out as text in your R console window. If you use summary without any options you will see a number of \(\&nbsp;\) statements which translates to “space” in HTML.

-
-

Pretty text version of table

+
+

Pretty text version of table

If you want a nicer version in your console window then adding the text=TRUE option.

-
> summary(tab1, text=TRUE)
+
> summary(tab1, text=TRUE)
 ----------------------------------------------------------------------------------
-                    estimate        std.error       p.value         adj.r.squared 
------------------- --------------- --------------- --------------- ---------------
-(Intercept)        27.5            0.181           <0.001          0.004          
-sex Female         -0.731          0.29            0.012           .              
-(Intercept)        26.4            0.752           <0.001          0              
-Age in Years       0.013           0.012           0.290           .              
-----------------------------------------------------------------------------------
+ estimate std.error p.value adj.r.squared +------------------ --------------- --------------- --------------- --------------- +(Intercept) 27.5 0.181 <0.001 0.004 +sex Female -0.731 0.29 0.012 . +(Intercept) 26.4 0.752 <0.001 0 +Age in Years 0.013 0.012 0.290 . +----------------------------------------------------------------------------------
-
-

Pretty Rmarkdown version of table

-

In order for the report to look nice within an R markdown (knitr) report, you just need to specify results="asis" when creating the r chunk. This changes the layout slightly (compresses it) and bolds the variable names. The three single quotes are often located above the tab key.

-

```{r results=“asis”}

-

summary(tab1)

-

```

-
> summary(tab1)
+
+

Pretty Rmarkdown version of table

+

In order for the report to look nice within an R markdown (knitr) report, you just need to specify results="asis" when creating the r chunk. This changes the layout slightly (compresses it) and bolds the variable names.

+
> summary(tab1)
@@ -288,11 +236,21 @@

Pretty Rmarkdown version of table

-
-

Add an adjustor to the model

+
+

Data frame version of table

+

If you want a data.frame version, simply use as.data.frame.

+
> as.data.frame(tab1)
+          term model endpoint estimate std.error p.value adj.r.squared
+1  (Intercept)     1      bmi   27.500     0.181      NA         0.004
+2   sex Female     1      bmi   -0.731     0.290   0.012         0.004
+3  (Intercept)     2      bmi   26.400     0.752      NA         0.000
+4 Age in Years     2      bmi    0.013     0.012   0.290         0.000
+
+
+

Add an adjustor to the model

The argument adjust allows the user to indicate that all the variables should be adjusted for these terms.

-
> tab2 <- modelsum(alk.phos ~ arm + ps + hgb, adjust= ~age + sex, data=mockstudy)
-> summary(tab2)
+
> tab2 <- modelsum(alk.phos ~ arm + ps + hgb, adjust= ~age + sex, data=mockstudy)
+> summary(tab2)
@@ -412,112 +370,112 @@

Models for each endpoint type

Gaussian

-

fit and summarize linear regression model

+

Fit and summarize linear regression model

Look at whether there is any evidence that AlkPhos values vary by study arm after adjusting for sex and age (assuming a linear age relationship).

-
> fit <- lm(alk.phos ~ arm + age + sex, data=mockstudy)
-> summary(fit)
+
> fit <- lm(alk.phos ~ arm + age + sex, data=mockstudy)
+> summary(fit)
 
 Call:
-lm(formula = alk.phos ~ arm + age + sex, data = mockstudy)
+lm(formula = alk.phos ~ arm + age + sex, data = mockstudy)
 
 Residuals:
-    Min      1Q  Median      3Q     Max 
--168.80  -81.45  -47.17   37.39  853.56 
+    Min      1Q  Median      3Q     Max 
+-168.80  -81.45  -47.17   37.39  853.56 
 
 Coefficients:
-              Estimate Std. Error t value Pr(>|t|)    
-(Intercept)  175.54808   20.58665   8.527   <2e-16 ***
-armF: FOLFOX -13.70062    8.72963  -1.569    0.117    
-armG: IROX    -2.24498    9.86004  -0.228    0.820    
-age           -0.01741    0.31878  -0.055    0.956    
-sexFemale      3.01598    7.52097   0.401    0.688    
+              Estimate Std. Error t value Pr(>|t|)    
+(Intercept)  175.54808   20.58665   8.527   <2e-16 ***
+armF: FOLFOX -13.70062    8.72963  -1.569    0.117    
+armG: IROX    -2.24498    9.86004  -0.228    0.820    
+age           -0.01741    0.31878  -0.055    0.956    
+sexFemale      3.01598    7.52097   0.401    0.688    
 ---
-Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
-
-Residual standard error: 128.5 on 1228 degrees of freedom
-  (266 observations deleted due to missingness)
-Multiple R-squared:  0.002552,  Adjusted R-squared:  -0.0006969 
-F-statistic: 0.7855 on 4 and 1228 DF,  p-value: 0.5346
-> plot(fit)
-

+Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 + +Residual standard error: 128.5 on 1228 degrees of freedom + (266 observations deleted due to missingness) +Multiple R-squared: 0.002552, Adjusted R-squared: -0.0006969 +F-statistic: 0.7855 on 4 and 1228 DF, p-value: 0.5346 +> plot(fit)
+

The results suggest that the endpoint may need to be transformed. Calculating the Box-Cox transformation suggests a log transformation.

-
> require(MASS)
-> boxcox(fit)
-

-
> fit2 <- lm(log(alk.phos) ~ arm + age + sex, data=mockstudy)
-> summary(fit2)
+
> require(MASS)
+> boxcox(fit)
+

+
> fit2 <- lm(log(alk.phos) ~ arm + age + sex, data=mockstudy)
+> summary(fit2)
 
 Call:
-lm(formula = log(alk.phos) ~ arm + age + sex, data = mockstudy)
+lm(formula = log(alk.phos) ~ arm + age + sex, data = mockstudy)
 
 Residuals:
-    Min      1Q  Median      3Q     Max 
--3.0098 -0.4470 -0.1065  0.4205  2.0620 
+    Min      1Q  Median      3Q     Max 
+-3.0098 -0.4470 -0.1065  0.4205  2.0620 
 
 Coefficients:
-               Estimate Std. Error t value Pr(>|t|)    
-(Intercept)   4.9692474  0.1025239  48.469   <2e-16 ***
-armF: FOLFOX -0.0766798  0.0434746  -1.764    0.078 .  
-armG: IROX   -0.0192828  0.0491041  -0.393    0.695    
-age          -0.0004058  0.0015876  -0.256    0.798    
-sexFemale     0.0179253  0.0374553   0.479    0.632    
+               Estimate Std. Error t value Pr(>|t|)    
+(Intercept)   4.9692474  0.1025239  48.469   <2e-16 ***
+armF: FOLFOX -0.0766798  0.0434746  -1.764    0.078 .  
+armG: IROX   -0.0192828  0.0491041  -0.393    0.695    
+age          -0.0004058  0.0015876  -0.256    0.798    
+sexFemale     0.0179253  0.0374553   0.479    0.632    
 ---
-Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
-
-Residual standard error: 0.6401 on 1228 degrees of freedom
-  (266 observations deleted due to missingness)
-Multiple R-squared:  0.003121,  Adjusted R-squared:  -0.0001258 
-F-statistic: 0.9613 on 4 and 1228 DF,  p-value: 0.4278
-> plot(fit2)
-

+Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 + +Residual standard error: 0.6401 on 1228 degrees of freedom + (266 observations deleted due to missingness) +Multiple R-squared: 0.003121, Adjusted R-squared: -0.0001258 +F-statistic: 0.9613 on 4 and 1228 DF, p-value: 0.4278 +> plot(fit2)
+

Finally, look to see whether there there is a non-linear relationship with age.

-
> require(gam)
-> fit3 <- lm(log(alk.phos) ~ arm + ns(age, df=2) + sex, data=mockstudy)
-> 
-> # test whether there is a difference between models 
-> anova(fit2,fit3)
+
> require(gam)
+> fit3 <- lm(log(alk.phos) ~ arm + ns(age, df=2) + sex, data=mockstudy)
+> 
+> # test whether there is a difference between models 
+> anova(fit2,fit3)
 Analysis of Variance Table
 
-Model 1: log(alk.phos) ~ arm + age + sex
-Model 2: log(alk.phos) ~ arm + ns(age, df = 2) + sex
-  Res.Df    RSS Df Sum of Sq      F  Pr(>F)  
-1   1228 503.19                              
-2   1227 502.07  1    1.1137 2.7218 0.09924 .
+Model 1: log(alk.phos) ~ arm + age + sex
+Model 2: log(alk.phos) ~ arm + ns(age, df = 2) + sex
+  Res.Df    RSS Df Sum of Sq      F  Pr(>F)  
+1   1228 503.19                              
+2   1227 502.07  1    1.1137 2.7218 0.09924 .
 ---
-Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
-> 
-> # look at functional form of age
-> termplot(fit3, term=2, se=T, rug=T)
-

+Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 +> +> # look at functional form of age +> termplot(fit3, term=2, se=T, rug=T)
+

In this instance it looks like there isn’t enough evidence to say that the relationship is non-linear.

-

extract data using the broom package

+

Extract data using the broom package

The broom package makes it easy to extract information from the fit.

-
> tmp <- tidy(fit3) # coefficients, p-values
-> class(tmp)
-[1] "data.frame"
-> tmp
+
> tmp <- tidy(fit3) # coefficients, p-values
+> class(tmp)
+[1] "data.frame"
+> tmp
               term    estimate  std.error statistic       p.value
-1      (Intercept)  4.76454026 0.14102237 33.785704 1.928465e-177
-2     armF: FOLFOX -0.07668790 0.04344412 -1.765208  7.777754e-02
-3       armG: IROX -0.01945575 0.04906984 -0.396491  6.918118e-01
-4 ns(age, df = 2)1  0.33031939 0.26002425  1.270341  2.042041e-01
-5 ns(age, df = 2)2 -0.10069469 0.09349337 -1.077025  2.816809e-01
-6        sexFemale  0.01829092 0.03742970  0.488674  6.251598e-01
-> 
-> glance(fit3)
+1      (Intercept)  4.76454026 0.14102237 33.785704 1.928465e-177
+2     armF: FOLFOX -0.07668790 0.04344412 -1.765208  7.777754e-02
+3       armG: IROX -0.01945575 0.04906984 -0.396491  6.918118e-01
+4 ns(age, df = 2)1  0.33031939 0.26002425  1.270341  2.042041e-01
+5 ns(age, df = 2)2 -0.10069469 0.09349337 -1.077025  2.816809e-01
+6        sexFemale  0.01829092 0.03742970  0.488674  6.251598e-01
+> 
+> glance(fit3)
   r.squared adj.r.squared     sigma statistic   p.value df    logLik
-1 0.0053278   0.001274531 0.6396787  1.314445 0.2552466  6 -1195.653
+1 0.0053278   0.001274531 0.6396787  1.314445 0.2552466  6 -1195.653
        AIC      BIC deviance df.residual
-1 2405.305 2441.126 502.0747        1227
+1 2405.305 2441.126 502.0747 1227
-

create a summary table using modelsum

-
> ms.logy <- modelsum(log(alk.phos) ~ arm + ps + hgb, data=mockstudy, adjust= ~age + sex, 
-+                     family=gaussian,  
-+                     gaussian.stats=c("estimate","CI.lower.estimate","CI.upper.estimate","p.value"))
-> summary(ms.logy)
+

Create a summary table using modelsum

+
> ms.logy <- modelsum(log(alk.phos) ~ arm + ps + hgb, data=mockstudy, adjust= ~age + sex, 
++                     family=gaussian,  
++                     gaussian.stats=c("estimate","CI.lower.estimate","CI.upper.estimate","p.value"))
+> summary(ms.logy)
@@ -634,51 +592,51 @@

create a summary table using modelsum

Binomial

-

fit and summarize logistic regression model

-
> boxplot(age ~ mdquality.s, data=mockstudy, ylab=attr(mockstudy$age,'label'), xlab='mdquality.s')
-

-
> 
-> fit <- glm(mdquality.s ~ age + sex, data=mockstudy, family=binomial)
-> summary(fit)
+

Fit and summarize logistic regression model

+
> boxplot(age ~ mdquality.s, data=mockstudy, ylab=attr(mockstudy$age,'label'), xlab='mdquality.s')
+

+
> 
+> fit <- glm(mdquality.s ~ age + sex, data=mockstudy, family=binomial)
+> summary(fit)
 
 Call:
-glm(formula = mdquality.s ~ age + sex, family = binomial, data = mockstudy)
+glm(formula = mdquality.s ~ age + sex, family = binomial, data = mockstudy)
 
-Deviance Residuals: 
-    Min       1Q   Median       3Q      Max  
--2.1832   0.4500   0.4569   0.4626   0.4756  
+Deviance Residuals: 
+    Min       1Q   Median       3Q      Max  
+-2.1832   0.4500   0.4569   0.4626   0.4756  
 
 Coefficients:
-             Estimate Std. Error z value Pr(>|z|)    
-(Intercept)  2.329442   0.514684   4.526 6.01e-06 ***
-age         -0.002353   0.008256  -0.285    0.776    
-sexFemale    0.039227   0.195330   0.201    0.841    
+             Estimate Std. Error z value Pr(>|z|)    
+(Intercept)  2.329442   0.514684   4.526 6.01e-06 ***
+age         -0.002353   0.008256  -0.285    0.776    
+sexFemale    0.039227   0.195330   0.201    0.841    
 ---
-Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
+Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
 
-(Dispersion parameter for binomial family taken to be 1)
+(Dispersion parameter for binomial family taken to be 1)
 
-    Null deviance: 807.68  on 1246  degrees of freedom
-Residual deviance: 807.55  on 1244  degrees of freedom
-  (252 observations deleted due to missingness)
-AIC: 813.55
+    Null deviance: 807.68  on 1246  degrees of freedom
+Residual deviance: 807.55  on 1244  degrees of freedom
+  (252 observations deleted due to missingness)
+AIC: 813.55
 
-Number of Fisher Scoring iterations: 4
-> 
-> # create Odd's ratio w/ confidence intervals
-> tmp <- data.frame(summary(fit)$coef)
-> tmp
+Number of Fisher Scoring iterations: 4
+> 
+> # create Odd's ratio w/ confidence intervals
+> tmp <- data.frame(summary(fit)$coef)
+> tmp
                 Estimate  Std..Error    z.value     Pr...z..
-(Intercept)  2.329441734 0.514683688  4.5259677 6.011977e-06
-age         -0.002353404 0.008255814 -0.2850602 7.755980e-01
-sexFemale    0.039227292 0.195330166  0.2008256 8.408350e-01
-> 
-> tmp$OR <- round(exp(tmp[,1]),2)
-> tmp$lower.CI <- round(exp(tmp[,1] - 1.96* tmp[,2]),2)
-> tmp$upper.CI <- round(exp(tmp[,1] + 1.96* tmp[,2]),2)
-> names(tmp)[4] <- 'P-value'
-> 
-> kable(tmp[,c('OR','lower.CI','upper.CI','P-value')])
+(Intercept) 2.329441734 0.514683688 4.5259677 6.011977e-06 +age -0.002353404 0.008255814 -0.2850602 7.755980e-01 +sexFemale 0.039227292 0.195330166 0.2008256 8.408350e-01 +> +> tmp$OR <- round(exp(tmp[,1]),2) +> tmp$lower.CI <- round(exp(tmp[,1] - 1.96* tmp[,2]),2) +> tmp$upper.CI <- round(exp(tmp[,1] + 1.96* tmp[,2]),2) +> names(tmp)[4] <- 'P-value' +> +> kable(tmp[,c('OR','lower.CI','upper.CI','P-value')])
@@ -713,37 +671,37 @@

fit and summarize logistic regression model

-
> 
-> # Assess the predictive ability of the model
-> 
-> # code using the pROC package
-> require(pROC)
-> pred <- predict(fit, type='response')
-> tmp <- pROC::roc(mockstudy$mdquality.s[!is.na(mockstudy$mdquality.s)]~ pred, plot=TRUE, percent=TRUE)
-

-
> tmp$auc
-Area under the curve: 50.69%
+
> 
+> # Assess the predictive ability of the model
+> 
+> # code using the pROC package
+> require(pROC)
+> pred <- predict(fit, type='response')
+> tmp <- pROC::roc(mockstudy$mdquality.s[!is.na(mockstudy$mdquality.s)]~ pred, plot=TRUE, percent=TRUE)
+

+
> tmp$auc
+Area under the curve: 50.69%
-

extract data using broom package

+

Extract data using broom package

The broom package makes it easy to extract information from the fit.

-
> tidy(fit, exp=T, conf.int=T) # coefficients, p-values, conf.intervals
+
> tidy(fit, exp=T, conf.int=T) # coefficients, p-values, conf.intervals
          term   estimate   std.error  statistic      p.value  conf.low
-1 (Intercept) 10.2722053 0.514683688  4.5259677 6.011977e-06 3.8305925
-2         age  0.9976494 0.008255814 -0.2850602 7.755980e-01 0.9814436
-3   sexFemale  1.0400068 0.195330166  0.2008256 8.408350e-01 0.7119068
+1 (Intercept) 10.2722053 0.514683688  4.5259677 6.011977e-06 3.8305925
+2         age  0.9976494 0.008255814 -0.2850602 7.755980e-01 0.9814436
+3   sexFemale  1.0400068 0.195330166  0.2008256 8.408350e-01 0.7119068
   conf.high
-1 28.876261
-2  1.013764
-3  1.533763
-> 
-> glance(fit) # model summary statistics
+1 28.876261
+2  1.013764
+3  1.533763
+> 
+> glance(fit) # model summary statistics
   null.deviance df.null    logLik      AIC      BIC deviance df.residual
-1      807.6764    1246 -403.7734 813.5468 828.9323 807.5468        1244
+1 807.6764 1246 -403.7734 813.5468 828.9323 807.5468 1244
-

create a summary table using modelsum

-
> summary(modelsum(mdquality.s ~ age + bmi, data=mockstudy, adjust=~sex, family=binomial))
+

Create a summary table using modelsum

+
> summary(modelsum(mdquality.s ~ age + bmi, data=mockstudy, adjust=~sex, family=binomial))
@@ -822,10 +780,10 @@

create a summary table using modelsum

-
> 
-> fitall <- modelsum(mdquality.s ~ age, data=mockstudy, family=binomial,
-+                    binomial.stats=c("Nmiss2","OR","p.value"))
-> summary(fitall)
+
> 
+> fitall <- modelsum(mdquality.s ~ age, data=mockstudy, family=binomial,
++                    binomial.stats=c("Nmiss2","OR","p.value"))
+> summary(fitall)
@@ -861,121 +819,121 @@

create a summary table using modelsum

Survival

-

fit and summarize a Cox regression model

-
> require(survival)
-Loading required package: survival
-> 
-> # multivariable model with all 3 terms
-> fit  <- coxph(Surv(fu.time, fu.stat) ~ age + sex + arm, data=mockstudy)
-> summary(fit)
+

Fit and summarize a Cox regression model

+
> require(survival)
+Loading required package: survival
+> 
+> # multivariable model with all 3 terms
+> fit  <- coxph(Surv(fu.time, fu.stat) ~ age + sex + arm, data=mockstudy)
+> summary(fit)
 Call:
-coxph(formula = Surv(fu.time, fu.stat) ~ age + sex + arm, data = mockstudy)
+coxph(formula = Surv(fu.time, fu.stat) ~ age + sex + arm, data = mockstudy)
 
-  n= 1499, number of events= 1356 
+  n= 1499, number of events= 1356 
 
-                  coef exp(coef)  se(coef)      z Pr(>|z|)    
-age           0.004600  1.004611  0.002501  1.839   0.0659 .  
-sexFemale     0.039893  1.040699  0.056039  0.712   0.4765    
-armF: FOLFOX -0.454650  0.634670  0.064878 -7.008 2.42e-12 ***
-armG: IROX   -0.140785  0.868676  0.072760 -1.935   0.0530 .  
+                  coef exp(coef)  se(coef)      z Pr(>|z|)    
+age           0.004600  1.004611  0.002501  1.839   0.0659 .  
+sexFemale     0.039893  1.040699  0.056039  0.712   0.4765    
+armF: FOLFOX -0.454650  0.634670  0.064878 -7.008 2.42e-12 ***
+armG: IROX   -0.140785  0.868676  0.072760 -1.935   0.0530 .  
 ---
-Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
-
-             exp(coef) exp(-coef) lower .95 upper .95
-age             1.0046     0.9954    0.9997    1.0095
-sexFemale       1.0407     0.9609    0.9324    1.1615
-armF: FOLFOX    0.6347     1.5756    0.5589    0.7207
-armG: IROX      0.8687     1.1512    0.7532    1.0018
-
-Concordance= 0.563  (se = 0.009 )
-Rsquare= 0.037   (max possible= 1 )
-Likelihood ratio test= 56.21  on 4 df,   p=1.811e-11
-Wald test            = 56.26  on 4 df,   p=1.77e-11
-Score (logrank) test = 56.96  on 4 df,   p=1.259e-11
-> 
-> # check proportional hazards assumption
-> fit.z <- cox.zph(fit)
-> fit.z
+Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
+
+             exp(coef) exp(-coef) lower .95 upper .95
+age             1.0046     0.9954    0.9997    1.0095
+sexFemale       1.0407     0.9609    0.9324    1.1615
+armF: FOLFOX    0.6347     1.5756    0.5589    0.7207
+armG: IROX      0.8687     1.1512    0.7532    1.0018
+
+Concordance= 0.563  (se = 0.009 )
+Rsquare= 0.037   (max possible= 1 )
+Likelihood ratio test= 56.21  on 4 df,   p=1.811e-11
+Wald test            = 56.26  on 4 df,   p=1.77e-11
+Score (logrank) test = 56.96  on 4 df,   p=1.259e-11
+> 
+> # check proportional hazards assumption
+> fit.z <- cox.zph(fit)
+> fit.z
                  rho chisq     p
-age          -0.0311  1.46 0.226
-sexFemale    -0.0325  1.44 0.230
-armF: FOLFOX  0.0343  1.61 0.205
-armG: IROX    0.0337  1.54 0.214
-GLOBAL            NA  4.59 0.332
-> plot(fit.z[1], resid=FALSE) # makes for a cleaner picture in this case
-> abline(h=coef(fit)[1], col='red')
-

-
> 
-> # check functional form for age using pspline (penalized spline)
-> # results are returned for the linear and non-linear components
-> fit2 <- coxph(Surv(fu.time, fu.stat) ~ pspline(age) + sex + arm, data=mockstudy)
-> fit2
+age          -0.0311  1.46 0.226
+sexFemale    -0.0325  1.44 0.230
+armF: FOLFOX  0.0343  1.61 0.205
+armG: IROX    0.0337  1.54 0.214
+GLOBAL            NA  4.59 0.332
+> plot(fit.z[1], resid=FALSE) # makes for a cleaner picture in this case
+> abline(h=coef(fit)[1], col='red')
+

+
> 
+> # check functional form for age using pspline (penalized spline)
+> # results are returned for the linear and non-linear components
+> fit2 <- coxph(Surv(fu.time, fu.stat) ~ pspline(age) + sex + arm, data=mockstudy)
+> fit2
 Call:
-coxph(formula = Surv(fu.time, fu.stat) ~ pspline(age) + sex + 
-    arm, data = mockstudy)
-
-                         coef se(coef)      se2    Chisq   DF       p
-pspline(age), linear  0.00443  0.00237  0.00237  3.48989 1.00  0.0617
-pspline(age), nonlin                            13.11270 3.08  0.0047
-sexFemale             0.03993  0.05610  0.05607  0.50663 1.00  0.4766
-armF: FOLFOX         -0.46240  0.06494  0.06493 50.69608 1.00 1.1e-12
-armG: IROX           -0.15243  0.07301  0.07299  4.35876 1.00  0.0368
-
-Iterations: 6 outer, 16 Newton-Raphson
-     Theta= 0.954 
-Degrees of freedom for terms= 4.1 1.0 2.0 
-Likelihood ratio test=70.1  on 7.08 df, p=1.59e-12  n= 1499 
-> 
-> # plot smoothed age to visualize why significant
-> termplot(fit2, se=T, terms=1)
-> abline(h=0)
-

-
> 
-> # The c-statistic comes out in the summary of the fit
-> summary(fit2)$concordance
-          C       se(C) 
-0.568432549 0.008779125 
-> 
-> # It can also be calculated using the survConcordance function
-> survConcordance(Surv(fu.time, fu.stat) ~ predict(fit2), data=mockstudy)
+coxph(formula = Surv(fu.time, fu.stat) ~ pspline(age) + sex + 
+    arm, data = mockstudy)
+
+                         coef se(coef)      se2    Chisq   DF       p
+pspline(age), linear  0.00443  0.00237  0.00237  3.48989 1.00  0.0617
+pspline(age), nonlin                            13.11270 3.08  0.0047
+sexFemale             0.03993  0.05610  0.05607  0.50663 1.00  0.4766
+armF: FOLFOX         -0.46240  0.06494  0.06493 50.69608 1.00 1.1e-12
+armG: IROX           -0.15243  0.07301  0.07299  4.35876 1.00  0.0368
+
+Iterations: 6 outer, 16 Newton-Raphson
+     Theta= 0.954 
+Degrees of freedom for terms= 4.1 1.0 2.0 
+Likelihood ratio test=70.1  on 7.08 df, p=1.59e-12  n= 1499 
+> 
+> # plot smoothed age to visualize why significant
+> termplot(fit2, se=T, terms=1)
+> abline(h=0)
+

+
> 
+> # The c-statistic comes out in the summary of the fit
+> summary(fit2)$concordance
+          C       se(C) 
+0.568432549 0.008779125 
+> 
+> # It can also be calculated using the survConcordance function
+> survConcordance(Surv(fu.time, fu.stat) ~ predict(fit2), data=mockstudy)
 Call:
-survConcordance(formula = Surv(fu.time, fu.stat) ~ predict(fit2), 
-    data = mockstudy)
+survConcordance(formula = Surv(fu.time, fu.stat) ~ predict(fit2), 
+    data = mockstudy)
 
-  n= 1499 
-Concordance= 0.5684325 se= 0.008779125
-concordant discordant  tied.risk  tied.time   std(c-d) 
- 620221.00  470282.00    5021.00     766.00   19235.49 
+ n= 1499 +Concordance= 0.5684325 se= 0.008779125 +concordant discordant tied.risk tied.time std(c-d) + 620221.00 470282.00 5021.00 766.00 19235.49
-

extract data using broom package

+

Extract data using broom package

The broom package makes it easy to extract information from the fit.

-
> tidy(fit) # coefficients, p-values
+
> tidy(fit) # coefficients, p-values
           term     estimate   std.error  statistic      p.value
-1          age  0.004600011 0.002501114  1.8391844 6.588807e-02
-2    sexFemale  0.039892735 0.056038632  0.7118792 4.765396e-01
-3 armF: FOLFOX -0.454650445 0.064878289 -7.0077441 2.421952e-12
-4   armG: IROX -0.140784996 0.072759529 -1.9349355 5.299821e-02
+1          age  0.004600011 0.002501114  1.8391844 6.588807e-02
+2    sexFemale  0.039892735 0.056038632  0.7118792 4.765396e-01
+3 armF: FOLFOX -0.454650445 0.064878289 -7.0077441 2.421952e-12
+4   armG: IROX -0.140784996 0.072759529 -1.9349355 5.299821e-02
        conf.low    conf.high
-1 -0.0003020836  0.009502105
-2 -0.0699409642  0.149726435
-3 -0.5818095536 -0.327491336
-4 -0.2833910528  0.001821061
-> 
-> glance(fit) # model summary statistics
+1 -0.0003020836  0.009502105
+2 -0.0699409642  0.149726435
+3 -0.5818095536 -0.327491336
+4 -0.2833910528  0.001821061
+> 
+> glance(fit) # model summary statistics
      n nevent statistic.log  p.value.log statistic.sc   p.value.sc
-1 1499   1356      56.21071 1.811218e-11      56.9642 1.258749e-11
+1 1499   1356      56.21071 1.811218e-11      56.9642 1.258749e-11
   statistic.wald p.value.wald  r.squared r.squared.max concordance
-1          56.26 1.770173e-11 0.03680443     0.9999923    0.562838
+1          56.26 1.770173e-11 0.03680443     0.9999923    0.562838
   std.error.concordance    logLik      AIC      BIC
-1           0.008779125 -8797.588 17603.18 17624.03
+1 0.008779125 -8797.588 17603.18 17624.03
-

create a summary table using modelsum

-
> ##Note: You must use quotes when specifying family="survival" 
-> ##      family=survival will not work
-> summary(modelsum(Surv(fu.time, fu.stat) ~ arm, 
-+                  adjust=~age + sex, data=mockstudy, family="survival"))
+

Create a summary table using modelsum

+
> ##Note: You must use quotes when specifying family="survival" 
+> ##      family=survival will not work
+> summary(modelsum(Surv(fu.time, fu.stat) ~ arm, 
++                  adjust=~age + sex, data=mockstudy, family="survival"))
@@ -1030,10 +988,10 @@

create a summary table using modelsum

-
> 
-> ##Note: the pspline term is not working yet
-> #summary(modelsum(Surv(fu.time, fu.stat) ~ arm, 
-> #                adjust=~pspline(age) + sex, data=mockstudy, family='survival'))
+
> 
+> ##Note: the pspline term is not working yet
+> #summary(modelsum(Surv(fu.time, fu.stat) ~ arm, 
+> #                adjust=~pspline(age) + sex, data=mockstudy, family='survival'))
@@ -1042,112 +1000,112 @@

Poisson

Example 1: fit and summarize a Poisson regression model

For the first example, use the solder dataset available in the rpart package. The endpoint skips has a definite Poisson look.

-
> require(rpart) ##just to get access to solder dataset
-> data(solder)
-> hist(solder$skips)
-

-
> 
-> fit <- glm(skips ~ Opening + Solder + Mask , data=solder, family=poisson)
-> anova(fit, test='Chi')
+
> require(rpart) ##just to get access to solder dataset
+> data(solder)
+> hist(solder$skips)
+

+
> 
+> fit <- glm(skips ~ Opening + Solder + Mask , data=solder, family=poisson)
+> anova(fit, test='Chi')
 Analysis of Deviance Table
 
-Model: poisson, link: log
+Model: poisson, link: log
 
-Response: skips
+Response: skips
 
-Terms added sequentially (first to last)
+Terms added sequentially (first to last)
 
-        Df Deviance Resid. Df Resid. Dev  Pr(>Chi)    
-NULL                      719     6855.7              
-Opening  2  2524.56       717     4331.1 < 2.2e-16 ***
-Solder   1   936.95       716     3394.2 < 2.2e-16 ***
-Mask     3  1653.09       713     1741.1 < 2.2e-16 ***
+        Df Deviance Resid. Df Resid. Dev  Pr(>Chi)    
+NULL                      719     6855.7              
+Opening  2  2524.56       717     4331.1 < 2.2e-16 ***
+Solder   1   936.95       716     3394.2 < 2.2e-16 ***
+Mask     3  1653.09       713     1741.1 < 2.2e-16 ***
 ---
-Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
-> summary(fit)
+Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
+> summary(fit)
 
 Call:
-glm(formula = skips ~ Opening + Solder + Mask, family = poisson, 
-    data = solder)
+glm(formula = skips ~ Opening + Solder + Mask, family = poisson, 
+    data = solder)
 
-Deviance Residuals: 
-    Min       1Q   Median       3Q      Max  
--4.7252  -1.3409  -0.6276   0.6930   5.2342  
+Deviance Residuals: 
+    Min       1Q   Median       3Q      Max  
+-4.7252  -1.3409  -0.6276   0.6930   5.2342  
 
 Coefficients:
-            Estimate Std. Error z value Pr(>|z|)    
-(Intercept) -1.30871    0.08068 -16.222  < 2e-16 ***
-OpeningM     0.25851    0.06656   3.884 0.000103 ***
-OpeningS     1.89349    0.05363  35.306  < 2e-16 ***
-SolderThin   1.09973    0.03864  28.465  < 2e-16 ***
-MaskA3       0.42819    0.07547   5.674  1.4e-08 ***
-MaskB3       1.20225    0.06697  17.953  < 2e-16 ***
-MaskB6       1.86648    0.06310  29.580  < 2e-16 ***
+            Estimate Std. Error z value Pr(>|z|)    
+(Intercept) -1.30871    0.08068 -16.222  < 2e-16 ***
+OpeningM     0.25851    0.06656   3.884 0.000103 ***
+OpeningS     1.89349    0.05363  35.306  < 2e-16 ***
+SolderThin   1.09973    0.03864  28.465  < 2e-16 ***
+MaskA3       0.42819    0.07547   5.674  1.4e-08 ***
+MaskB3       1.20225    0.06697  17.953  < 2e-16 ***
+MaskB6       1.86648    0.06310  29.580  < 2e-16 ***
 ---
-Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
+Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
 
-(Dispersion parameter for poisson family taken to be 1)
+(Dispersion parameter for poisson family taken to be 1)
 
-    Null deviance: 6855.7  on 719  degrees of freedom
-Residual deviance: 1741.1  on 713  degrees of freedom
-AIC: 3337.2
+    Null deviance: 6855.7  on 719  degrees of freedom
+Residual deviance: 1741.1  on 713  degrees of freedom
+AIC: 3337.2
 
-Number of Fisher Scoring iterations: 5
+Number of Fisher Scoring iterations: 5

Overdispersion is when the Residual deviance is larger than the degrees of freedom. This can be tested, approximately using the following code. The goal is to have a p-value that is \(>0.05\).

-
> 1-pchisq(fit$deviance, fit$df.residual)
-[1] 0
+
> 1-pchisq(fit$deviance, fit$df.residual)
+[1] 0

One possible solution is to use the quasipoisson family instead of the poisson family. This adjusts for the overdispersion.

-
> fit2 <- glm(skips ~ Opening + Solder + Mask, data=solder, family=quasipoisson)
-> summary(fit2)
+
> fit2 <- glm(skips ~ Opening + Solder + Mask, data=solder, family=quasipoisson)
+> summary(fit2)
 
 Call:
-glm(formula = skips ~ Opening + Solder + Mask, family = quasipoisson, 
-    data = solder)
+glm(formula = skips ~ Opening + Solder + Mask, family = quasipoisson, 
+    data = solder)
 
-Deviance Residuals: 
-    Min       1Q   Median       3Q      Max  
--4.7252  -1.3409  -0.6276   0.6930   5.2342  
+Deviance Residuals: 
+    Min       1Q   Median       3Q      Max  
+-4.7252  -1.3409  -0.6276   0.6930   5.2342  
 
 Coefficients:
-            Estimate Std. Error t value Pr(>|t|)    
-(Intercept) -1.30871    0.12496 -10.473  < 2e-16 ***
-OpeningM     0.25851    0.10310   2.507 0.012382 *  
-OpeningS     1.89349    0.08307  22.794  < 2e-16 ***
-SolderThin   1.09973    0.05984  18.377  < 2e-16 ***
-MaskA3       0.42819    0.11689   3.663 0.000268 ***
-MaskB3       1.20225    0.10372  11.591  < 2e-16 ***
-MaskB6       1.86648    0.09774  19.097  < 2e-16 ***
+            Estimate Std. Error t value Pr(>|t|)    
+(Intercept) -1.30871    0.12496 -10.473  < 2e-16 ***
+OpeningM     0.25851    0.10310   2.507 0.012382 *  
+OpeningS     1.89349    0.08307  22.794  < 2e-16 ***
+SolderThin   1.09973    0.05984  18.377  < 2e-16 ***
+MaskA3       0.42819    0.11689   3.663 0.000268 ***
+MaskB3       1.20225    0.10372  11.591  < 2e-16 ***
+MaskB6       1.86648    0.09774  19.097  < 2e-16 ***
 ---
-Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
+Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
 
-(Dispersion parameter for quasipoisson family taken to be 2.399074)
+(Dispersion parameter for quasipoisson family taken to be 2.399074)
 
-    Null deviance: 6855.7  on 719  degrees of freedom
-Residual deviance: 1741.1  on 713  degrees of freedom
-AIC: NA
+    Null deviance: 6855.7  on 719  degrees of freedom
+Residual deviance: 1741.1  on 713  degrees of freedom
+AIC: NA
 
-Number of Fisher Scoring iterations: 5
+Number of Fisher Scoring iterations: 5
-

extract data using broom package

+

Extract data using broom package

The broom package makes it easy to extract information from the fit.

-
> tidy(fit) # coefficients, p-values
+
> tidy(fit) # coefficients, p-values
          term   estimate  std.error  statistic       p.value
-1 (Intercept) -1.3087062 0.08067587 -16.221780  3.537930e-59
-2    OpeningM  0.2585107 0.06656163   3.883780  1.028452e-04
-3    OpeningS  1.8934884 0.05363137  35.305612 4.816124e-273
-4  SolderThin  1.0997315 0.03863508  28.464582 3.216362e-178
-5      MaskA3  0.4281934 0.07546810   5.673833  1.396375e-08
-6      MaskB3  1.2022472 0.06696662  17.952933  4.552147e-72
-7      MaskB6  1.8664830 0.06309987  29.579826 2.716304e-192
-> 
-> glance(fit) # model summary statistics
+1 (Intercept) -1.3087062 0.08067587 -16.221780  3.537930e-59
+2    OpeningM  0.2585107 0.06656163   3.883780  1.028452e-04
+3    OpeningS  1.8934884 0.05363137  35.305612 4.816124e-273
+4  SolderThin  1.0997315 0.03863508  28.464582 3.216362e-178
+5      MaskA3  0.4281934 0.07546810   5.673833  1.396375e-08
+6      MaskB3  1.2022472 0.06696662  17.952933  4.552147e-72
+7      MaskB6  1.8664830 0.06309987  29.579826 2.716304e-192
+> 
+> glance(fit) # model summary statistics
   null.deviance df.null    logLik      AIC      BIC deviance df.residual
-1       6855.69     719 -1661.623 3337.247 3369.302  1741.08         713
+1 6855.69 719 -1661.623 3337.247 3369.302 1741.08 713
-

create a summary table using modelsum

-
> summary(modelsum(skips~Opening + Solder + Mask, data=solder, family="quasipoisson"))
+

Create a summary table using modelsum

+
> summary(modelsum(skips~Opening + Solder + Mask, data=solder, family="quasipoisson"))
@@ -1231,7 +1189,7 @@

create a summary table using modelsum

-
> summary(modelsum(skips~Opening + Solder + Mask, data=solder, family="poisson"))
+
> summary(modelsum(skips~Opening + Solder + Mask, data=solder, family="poisson"))
@@ -1319,101 +1277,101 @@

create a summary table using modelsum

Example 2: fit and summarize a Poisson regression model

This second example uses the survival endpoint available in the mockstudy dataset. There is a close relationship between survival and Poisson models, and often it is easier to fit the model using Poisson regression, especially if you want to present absolute risk.

-
> # add .01 to the follow-up time (.01*1 day) in order to keep everyone in the analysis
-> fit <- glm(fu.stat ~ offset(log(fu.time+.01)) + age + sex + arm, data=mockstudy, family=poisson)
-> summary(fit)
+
> # add .01 to the follow-up time (.01*1 day) in order to keep everyone in the analysis
+> fit <- glm(fu.stat ~ offset(log(fu.time+.01)) + age + sex + arm, data=mockstudy, family=poisson)
+> summary(fit)
 
 Call:
-glm(formula = fu.stat ~ offset(log(fu.time + 0.01)) + age + sex + 
-    arm, family = poisson, data = mockstudy)
+glm(formula = fu.stat ~ offset(log(fu.time + 0.01)) + age + sex + 
+    arm, family = poisson, data = mockstudy)
 
-Deviance Residuals: 
-    Min       1Q   Median       3Q      Max  
--3.1188  -0.4041   0.3242   0.9727   4.3588  
+Deviance Residuals: 
+    Min       1Q   Median       3Q      Max  
+-3.1188  -0.4041   0.3242   0.9727   4.3588  
 
 Coefficients:
-              Estimate Std. Error z value Pr(>|z|)    
-(Intercept)  -5.875627   0.108984 -53.913  < 2e-16 ***
-age           0.003724   0.001705   2.184   0.0290 *  
-sexFemale     0.027321   0.038575   0.708   0.4788    
-armF: FOLFOX -0.335141   0.044600  -7.514 5.72e-14 ***
-armG: IROX   -0.107776   0.050643  -2.128   0.0333 *  
+              Estimate Std. Error z value Pr(>|z|)    
+(Intercept)  -5.875627   0.108984 -53.913  < 2e-16 ***
+age           0.003724   0.001705   2.184   0.0290 *  
+sexFemale     0.027321   0.038575   0.708   0.4788    
+armF: FOLFOX -0.335141   0.044600  -7.514 5.72e-14 ***
+armG: IROX   -0.107776   0.050643  -2.128   0.0333 *  
 ---
-Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
-
-(Dispersion parameter for poisson family taken to be 1)
-
-    Null deviance: 2113.5  on 1498  degrees of freedom
-Residual deviance: 2048.0  on 1494  degrees of freedom
-AIC: 5888.2
-
-Number of Fisher Scoring iterations: 5
-> 1-pchisq(fit$deviance, fit$df.residual)
-[1] 0
-> 
-> coef(coxph(Surv(fu.time,fu.stat) ~ age + sex + arm, data=mockstudy))
-         age    sexFemale armF: FOLFOX   armG: IROX 
- 0.004600011  0.039892735 -0.454650445 -0.140784996 
-> coef(fit)[-1]
-         age    sexFemale armF: FOLFOX   armG: IROX 
- 0.003723763  0.027320917 -0.335141090 -0.107775577 
-> 
-> # results from the Poisson model can then be described as risk ratios (similar to the hazard ratio)
-> exp(coef(fit)[-1])
-         age    sexFemale armF: FOLFOX   armG: IROX 
-   1.0037307    1.0276976    0.7152372    0.8978291 
-> 
-> # As before, we can model the dispersion which alters the standard error
-> fit2 <- glm(fu.stat ~ offset(log(fu.time+.01)) + age + sex + arm, 
-+             data=mockstudy, family=quasipoisson)
-> summary(fit2)
+Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
+
+(Dispersion parameter for poisson family taken to be 1)
+
+    Null deviance: 2113.5  on 1498  degrees of freedom
+Residual deviance: 2048.0  on 1494  degrees of freedom
+AIC: 5888.2
+
+Number of Fisher Scoring iterations: 5
+> 1-pchisq(fit$deviance, fit$df.residual)
+[1] 0
+> 
+> coef(coxph(Surv(fu.time,fu.stat) ~ age + sex + arm, data=mockstudy))
+         age    sexFemale armF: FOLFOX   armG: IROX 
+ 0.004600011  0.039892735 -0.454650445 -0.140784996 
+> coef(fit)[-1]
+         age    sexFemale armF: FOLFOX   armG: IROX 
+ 0.003723763  0.027320917 -0.335141090 -0.107775577 
+> 
+> # results from the Poisson model can then be described as risk ratios (similar to the hazard ratio)
+> exp(coef(fit)[-1])
+         age    sexFemale armF: FOLFOX   armG: IROX 
+   1.0037307    1.0276976    0.7152372    0.8978291 
+> 
+> # As before, we can model the dispersion which alters the standard error
+> fit2 <- glm(fu.stat ~ offset(log(fu.time+.01)) + age + sex + arm, 
++             data=mockstudy, family=quasipoisson)
+> summary(fit2)
 
 Call:
-glm(formula = fu.stat ~ offset(log(fu.time + 0.01)) + age + sex + 
-    arm, family = quasipoisson, data = mockstudy)
+glm(formula = fu.stat ~ offset(log(fu.time + 0.01)) + age + sex + 
+    arm, family = quasipoisson, data = mockstudy)
 
-Deviance Residuals: 
-    Min       1Q   Median       3Q      Max  
--3.1188  -0.4041   0.3242   0.9727   4.3588  
+Deviance Residuals: 
+    Min       1Q   Median       3Q      Max  
+-3.1188  -0.4041   0.3242   0.9727   4.3588  
 
 Coefficients:
-              Estimate Std. Error t value Pr(>|t|)    
-(Intercept)  -5.875627   0.566666 -10.369   <2e-16 ***
-age           0.003724   0.008867   0.420    0.675    
-sexFemale     0.027321   0.200572   0.136    0.892    
-armF: FOLFOX -0.335141   0.231899  -1.445    0.149    
-armG: IROX   -0.107776   0.263318  -0.409    0.682    
+              Estimate Std. Error t value Pr(>|t|)    
+(Intercept)  -5.875627   0.566666 -10.369   <2e-16 ***
+age           0.003724   0.008867   0.420    0.675    
+sexFemale     0.027321   0.200572   0.136    0.892    
+armF: FOLFOX -0.335141   0.231899  -1.445    0.149    
+armG: IROX   -0.107776   0.263318  -0.409    0.682    
 ---
-Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
+Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
 
-(Dispersion parameter for quasipoisson family taken to be 27.03493)
+(Dispersion parameter for quasipoisson family taken to be 27.03493)
 
-    Null deviance: 2113.5  on 1498  degrees of freedom
-Residual deviance: 2048.0  on 1494  degrees of freedom
-AIC: NA
+    Null deviance: 2113.5  on 1498  degrees of freedom
+Residual deviance: 2048.0  on 1494  degrees of freedom
+AIC: NA
 
-Number of Fisher Scoring iterations: 5
+Number of Fisher Scoring iterations: 5
-

extract data using broom package

+

Extract data using broom package

The broom package makes it easy to extract information from the fit.

-
> tidy(fit) ##coefficients, p-values
+
> tidy(fit) ##coefficients, p-values
           term     estimate   std.error   statistic      p.value
-1  (Intercept) -5.875626610 0.108984423 -53.9125359 0.000000e+00
-2          age  0.003723763 0.001705363   2.1835606 2.899455e-02
-3    sexFemale  0.027320917 0.038575062   0.7082533 4.787879e-01
-4 armF: FOLFOX -0.335141090 0.044600079  -7.5143610 5.718959e-14
-5   armG: IROX -0.107775577 0.050642805  -2.1281518 3.332450e-02
-> 
-> glance(fit) ##model summary statistics
+1  (Intercept) -5.875626610 0.108984423 -53.9125359 0.000000e+00
+2          age  0.003723763 0.001705363   2.1835606 2.899455e-02
+3    sexFemale  0.027320917 0.038575062   0.7082533 4.787879e-01
+4 armF: FOLFOX -0.335141090 0.044600079  -7.5143610 5.718959e-14
+5   armG: IROX -0.107775577 0.050642805  -2.1281518 3.332450e-02
+> 
+> glance(fit) ##model summary statistics
   null.deviance df.null    logLik      AIC      BIC deviance df.residual
-1      2113.504    1498 -2939.082 5888.164 5914.727 2047.979        1494
+1 2113.504 1498 -2939.082 5888.164 5914.727 2047.979 1494
-

create a summary table using modelsum

+

Create a summary table using modelsum

Remember that the result from modelsum is different from the fit above. The modelsum summary shows the results for age + offset(log(fu.time+.01)) then sex + offset(log(fu.time+.01)) instead of age + sex + arm + offset(log(fu.time+.01)).

-
> summary(modelsum(fu.stat ~ age, adjust=~offset(log(fu.time+.01))+ sex + arm, 
-+                  data=mockstudy, family=poisson))
+
> summary(modelsum(fu.stat ~ age, adjust=~offset(log(fu.time+.01))+ sex + arm, 
++                  data=mockstudy, family=poisson))
@@ -1475,13 +1433,13 @@

create a summary table using modelsum

Additional Examples

Here are multiple examples showing how to use some of the different options.

-
-

1. Change summary statistics globally

+
+

1. Change summary statistics globally

There are standard settings for each type of model regarding what information is summarized in the table. This behavior can be modified using the modelsum.control function. In fact, you can save your standard settings and use that for future tables.

-
> mycontrols  <- modelsum.control(gaussian.stats=c("estimate","std.error","adj.r.squared","Nmiss"),
-+                                 show.adjust=FALSE, show.intercept=FALSE)                            
-> tab2 <- modelsum(bmi ~ age, adjust=~sex, data=mockstudy, control=mycontrols)
-> summary(tab2)
+
> mycontrols  <- modelsum.control(gaussian.stats=c("estimate","std.error","adj.r.squared","Nmiss"),
++                                 show.adjust=FALSE, show.intercept=FALSE)                            
+> tab2 <- modelsum(bmi ~ age, adjust=~sex, data=mockstudy, control=mycontrols)
+> summary(tab2)
@@ -1507,10 +1465,10 @@

1. Change summary statistics globally

You can also change these settings directly in the modelsum call.

-
> tab3 <- modelsum(bmi ~  age, adjust=~sex, data=mockstudy,
-+                  gaussian.stats=c("estimate","std.error","adj.r.squared","Nmiss"), 
-+                  show.intercept=FALSE, show.adjust=FALSE)
-> summary(tab3)
+
> tab3 <- modelsum(bmi ~  age, adjust=~sex, data=mockstudy,
++                  gaussian.stats=c("estimate","std.error","adj.r.squared","Nmiss"), 
++                  show.intercept=FALSE, show.adjust=FALSE)
+> summary(tab3)
@@ -1536,42 +1494,42 @@

1. Change summary statistics globally

-
-

2. Add labels to independent variables

+
+

2. Add labels to independent variables

In the above example, age is shown with a label (Age in Years), but sex is listed “as is”. This is because the data was created in SAS and in the SAS dataset, age had a label but sex did not. The label is stored as an attribute within R.

-
> ## Look at one variable's label
-> attr(mockstudy$age,'label')
-[1] "Age in Years"
-> 
-> ## See all the variables with a label
-> unlist(lapply(mockstudy,'attr','label'))
+
> ## Look at one variable's label
+> attr(mockstudy$age,'label')
+[1] "Age in Years"
+> 
+> ## See all the variables with a label
+> unlist(lapply(mockstudy,'attr','label'))
                        age                        arm 
-            "Age in Years"            "Treatment Arm" 
+            "Age in Years"            "Treatment Arm" 
                       race                        bmi 
-                    "Race" "Body Mass Index (kg/m^2)" 
-> 
-> ## or
-> cbind(sapply(mockstudy,attr,'label'))
-            [,1]                      
-case        NULL                      
-age         "Age in Years"            
-arm         "Treatment Arm"           
-sex         NULL                      
-race        "Race"                    
-fu.time     NULL                      
-fu.stat     NULL                      
-ps          NULL                      
-hgb         NULL                      
-bmi         "Body Mass Index (kg/m^2)"
-alk.phos    NULL                      
-ast         NULL                      
-mdquality.s NULL                      
-age.ord     NULL                      
+ "Race" "Body Mass Index (kg/m^2)" +> +> ## or +> cbind(sapply(mockstudy,attr,'label')) + [,1] +case NULL +age "Age in Years" +arm "Treatment Arm" +sex NULL +race "Race" +fu.time NULL +fu.stat NULL +ps NULL +hgb NULL +bmi "Body Mass Index (kg/m^2)" +alk.phos NULL +ast NULL +mdquality.s NULL +age.ord NULL

If you want to add labels to other variables, there are a couple of options. First, you could add labels to the variables in your dataset.

-
> attr(mockstudy$age,'label')  <- 'Age, yrs'
-> 
-> tab1 <- modelsum(bmi ~  age, adjust=~sex, data=mockstudy)
-> summary(tab1)
+
> attr(mockstudy$age,'label')  <- 'Age, yrs'
+> 
+> tab1 <- modelsum(bmi ~  age, adjust=~sex, data=mockstudy)
+> summary(tab1)
@@ -1614,8 +1572,8 @@

2. Add labels to independent variables

Another option is to add labels after you have created the table

-
> mylabels <- list(sexFemale = "Female", age ="Age, yrs")
-> summary(tab1, labelTranslations = mylabels)
+
> mylabels <- list(sexFemale = "Female", age ="Age, yrs")
+> summary(tab1, labelTranslations = mylabels)
@@ -1658,18 +1616,18 @@

2. Add labels to independent variables

Alternatively, you can check the variable labels and manipulate them with a function called labels, which works on the tableby object.

-
> labels(tab1)
+
> labels(tab1)
                        bmi                        age 
-"Body Mass Index (kg/m^2)"                 "Age, yrs" 
+"Body Mass Index (kg/m^2)"                 "Age, yrs" 
                  sexFemale 
-              "sex Female" 
-> labels(tab1) <- c(sexFemale="Female", age="Baseline Age (yrs)")
-> labels(tab1)
+              "sex Female" 
+> labels(tab1) <- c(sexFemale="Female", age="Baseline Age (yrs)")
+> labels(tab1)
                        bmi                        age 
-"Body Mass Index (kg/m^2)"       "Baseline Age (yrs)" 
+"Body Mass Index (kg/m^2)"       "Baseline Age (yrs)" 
                  sexFemale 
-                  "Female" 
-
> summary(tab1)
+ "Female"
+
> summary(tab1)
@@ -1712,9 +1670,9 @@

2. Add labels to independent variables

-
-

2. Don’t show intercept values

-
> summary(modelsum(age~mdquality.s+sex, data=mockstudy), show.intercept=FALSE)
+
+

3. Don’t show intercept values

+
> summary(modelsum(age~mdquality.s+sex, data=mockstudy), show.intercept=FALSE)
@@ -1754,10 +1712,10 @@

2. Don’t show intercept values

-
-

3. Don’t show results for adjustment variables

-
> summary(modelsum(mdquality.s ~ age + bmi, data=mockstudy, adjust=~sex, family=binomial),
-+         show.adjust=FALSE)  
+
+

4. Don’t show results for adjustment variables

+
> summary(modelsum(mdquality.s ~ age + bmi, data=mockstudy, adjust=~sex, family=binomial),
++         show.adjust=FALSE)  
@@ -1819,24 +1777,24 @@

3. Don’t show results for adjustment variables

-
-

4. Summarize multiple variables without typing them out

+
+

5. Summarize multiple variables without typing them out

Often one wants to summarize a number of variables. Instead of typing by hand each individual variable, an alternative approach is to create a formula using the paste command with the collapse="+" option.

-
> # create a vector specifying the variable names
-> myvars <- names(mockstudy)
-> 
-> # select the 8th through the 12th
-> # paste them together, separated by the + sign
-> RHS <- paste(myvars[8:12], collapse="+")
-> RHS
+
> # create a vector specifying the variable names
+> myvars <- names(mockstudy)
+> 
+> # select the 8th through the 12th
+> # paste them together, separated by the + sign
+> RHS <- paste(myvars[8:12], collapse="+")
+> RHS

[1] “ps+hgb+bmi+alk.phos+ast”

-
> 
-> # create a formula using the as.formula function
-> as.formula(paste('mdquality.s ~ ', RHS))
+
> 
+> # create a formula using the as.formula function
+> as.formula(paste('mdquality.s ~ ', RHS))

mdquality.s ~ ps + hgb + bmi + alk.phos + ast

-
> 
-> # use the formula in the modelsum function
-> summary(modelsum(as.formula(paste('mdquality.s ~', RHS)), family=binomial, data=mockstudy))
+
> 
+> # use the formula in the modelsum function
+> summary(modelsum(as.formula(paste('mdquality.s ~', RHS)), family=binomial, data=mockstudy))
@@ -1952,16 +1910,16 @@

4. Summarize multiple variables without typing them out

These steps can also be done using the formulize function.

-
> ## The formulize function does the paste and as.formula steps
-> tmp <- formulize('mdquality.s',myvars[8:10])
-> tmp
-

mdquality.s ~ ps + hgb + bmi <environment: 0x676f4c0>

-
> 
-> ## More complex formulas could also be written using formulize
-> tmp2 <- formulize('mdquality.s',c('ps','hgb','sqrt(bmi)'))
-> 
-> ## use the formula in the modelsum function
-> summary(modelsum(tmp, data=mockstudy, family=binomial))
+
> ## The formulize function does the paste and as.formula steps
+> tmp <- formulize('mdquality.s',myvars[8:10])
+> tmp
+

mdquality.s ~ ps + hgb + bmi <environment: 0x7453118>

+
> 
+> ## More complex formulas could also be written using formulize
+> tmp2 <- formulize('mdquality.s',c('ps','hgb','sqrt(bmi)'))
+> 
+> ## use the formula in the modelsum function
+> summary(modelsum(tmp, data=mockstudy, family=binomial))
@@ -2041,24 +1999,24 @@

4. Summarize multiple variables without typing them out

-
-

5. Subset the dataset used in the analysis

+
+

6. Subset the dataset used in the analysis

Here are two ways to get the same result (limit the analysis to subjects age>50 and in the F: FOLFOX treatment group).

  • The first approach uses the subset function applied to the dataset mockstudy. This example also selects a subset of variables. The modelsum function is then applied to this subsetted data.
-
> newdata <- subset(mockstudy, subset=age>50 & arm=='F: FOLFOX', select = c(age,sex, bmi:alk.phos))
-> dim(mockstudy)
-[1] 1499   14
-> table(mockstudy$arm)
-
-   A: IFL F: FOLFOX   G: IROX 
-      428       691       380 
-> dim(newdata)
-[1] 557   4
-> names(newdata)
-[1] "age"      "sex"      "bmi"      "alk.phos"
-
> summary(modelsum(alk.phos ~ ., data=newdata))
+
> newdata <- subset(mockstudy, subset=age>50 & arm=='F: FOLFOX', select = c(age,sex, bmi:alk.phos))
+> dim(mockstudy)
+[1] 1499   14
+> table(mockstudy$arm)
+
+   A: IFL F: FOLFOX   G: IROX 
+      428       691       380 
+> dim(newdata)
+[1] 557   4
+> names(newdata)
+[1] "age"      "sex"      "bmi"      "alk.phos"
+
> summary(modelsum(alk.phos ~ ., data=newdata))
@@ -2132,7 +2090,7 @@

5. Subset the dataset used in the analysis

  • The second approach does the same analysis but uses the subset argument within modelsum to subset the data.
-
> summary(modelsum(log(alk.phos) ~ sex + ps + bmi, subset=age>50 & arm=="F: FOLFOX", data=mockstudy))
+
> summary(modelsum(log(alk.phos) ~ sex + ps + bmi, subset=age>50 & arm=="F: FOLFOX", data=mockstudy))
@@ -2203,7 +2161,7 @@

5. Subset the dataset used in the analysis

-
> summary(modelsum(alk.phos ~ ps + bmi, adjust=~sex, subset = age>50 & bmi<24, data=mockstudy))
+
> summary(modelsum(alk.phos ~ ps + bmi, adjust=~sex, subset = age>50 & bmi<24, data=mockstudy))
@@ -2266,7 +2224,7 @@

5. Subset the dataset used in the analysis

-
> summary(modelsum(alk.phos ~ ps + bmi, adjust=~sex, subset=1:30, data=mockstudy))
+
> summary(modelsum(alk.phos ~ ps + bmi, adjust=~sex, subset=1:30, data=mockstudy))
@@ -2338,14 +2296,14 @@

5. Subset the dataset used in the analysis

-
-

6. Create combinations of variables on the fly

-
> ## create a variable combining the levels of mdquality.s and sex
-> with(mockstudy, table(interaction(mdquality.s,sex)))
-
-  0.Male   1.Male 0.Female 1.Female 
-      77      686       47      437 
-
> summary(modelsum(age ~ interaction(mdquality.s,sex), data=mockstudy))
+
+

7. Create combinations of variables on the fly

+
> ## create a variable combining the levels of mdquality.s and sex
+> with(mockstudy, table(interaction(mdquality.s,sex)))
+
+  0.Male   1.Male 0.Female 1.Female 
+      77      686       47      437 
+
> summary(modelsum(age ~ interaction(mdquality.s,sex), data=mockstudy))
@@ -2401,11 +2359,11 @@

6. Create combinations of variables on the fly

-
-

9. Transform variables on the fly

+
+

8. Transform variables on the fly

Certain transformations need to be surrounded by I() so that R knows to treat it as a variable transformation and not some special model feature. If the transformation includes any of the symbols / - + ^ * then surround the new variable by I().

-
> summary(modelsum(arm=="F: FOLFOX" ~ I(age/10) + log(bmi) + mdquality.s,
-+                  data=mockstudy, family=binomial))
+
> summary(modelsum(arm=="F: FOLFOX" ~ I(age/10) + log(bmi) + mdquality.s,
++                  data=mockstudy, family=binomial))
@@ -2485,11 +2443,11 @@

9. Transform variables on the fly

-
-

10. Change the ordering of the variables or delete a variable

-
> mytab <- modelsum(bmi ~ sex + alk.phos + age, data=mockstudy)
-> mytab2 <- mytab[c('age','sex','alk.phos')]
-> summary(mytab2)
+
+

9. Change the ordering of the variables or delete a variable

+
> mytab <- modelsum(bmi ~ sex + alk.phos + age, data=mockstudy)
+> mytab2 <- mytab[c('age','sex','alk.phos')]
+> summary(mytab2)
@@ -2560,7 +2518,7 @@

10. Change the ordering of the variables or delete a variable

-
> summary(mytab[c('age','sex')])
+
> summary(mytab[c('age','sex')])
@@ -2609,7 +2567,7 @@

10. Change the ordering of the variables or delete a variable

-
> summary(mytab[c(3,1)])
+
> summary(mytab[c(3,1)])
@@ -2659,26 +2617,26 @@

10. Change the ordering of the variables or delete a variable

-
-

11. Merge two modelsum objects together

+
+

10. Merge two modelsum objects together

It is possible to combine two modelsum objects so that they print out together, however you need to pay attention to the columns that are being displayed. It is easier to combine two models of the same family (such as two sets of linear models). If you want to combine linear and logistic model results then you would want to display the beta coefficients for the logistic model.

-
> ## demographics
-> tab1 <- modelsum(bmi ~ sex + age, data=mockstudy)
-> ## lab data
-> tab2 <- modelsum(mdquality.s ~ hgb + alk.phos, data=mockstudy, family=binomial)
->                 
-> tab12 <- merge(tab1,tab2)
-> class(tab12)
+
> ## demographics
+> tab1 <- modelsum(bmi ~ sex + age, data=mockstudy)
+> ## lab data
+> tab2 <- modelsum(mdquality.s ~ hgb + alk.phos, data=mockstudy, family=binomial)
+>                 
+> tab12 <- merge(tab1,tab2)
+> class(tab12)

[1] “modelsumList”

-
> 
-> ##ERROR: The merge works, but not the summary
-> #summary(tab12)
+
> 
+> ##ERROR: The merge works, but not the summary
+> #summary(tab12)
-
-

12. Add a title to the table

+
+

11. Add a title to the table

When creating a pdf the tables are automatically numbered and the title appears below the table. In Word and HTML, the titles appear un-numbered and above the table.

-
> t1 <- modelsum(bmi ~ sex + age, data=mockstudy)
-> summary(t1, title='Demographics')
+
> t1 <- modelsum(bmi ~ sex + age, data=mockstudy)
+> summary(t1, title='Demographics')
@@ -2729,24 +2687,24 @@

12. Add a title to the table

Demographics
-
-

13. Modify how missing values are treated

+
+

12. Modify how missing values are treated

Depending on the report you are writing you have the following options:

    -
  • Use all values available for each variable
  • -
  • Use only those subjects who have measurements available for all the variables
  • +
  • Use all values available for each variable

  • +
  • Use only those subjects who have measurements available for all the variables

-
> ## look at how many missing values there are for each variable
-> apply(is.na(mockstudy),2,sum)
+
> ## look at how many missing values there are for each variable
+> apply(is.na(mockstudy),2,sum)
        case         age         arm         sex        race     fu.time 
-          0           0           0           0           7           0 
+          0           0           0           0           7           0 
     fu.stat          ps         hgb         bmi    alk.phos         ast 
-          0         266         266          33         266         266 
+          0         266         266          33         266         266 
 mdquality.s     age.ord 
-        252           0 
-
> ## Show how many subjects have each variable (non-missing)
-> summary(modelsum(bmi ~ ast + age, data=mockstudy,
-+                 control=modelsum.control(gaussian.stats=c("N","estimate"))))
+ 252 0
+
> ## Show how many subjects have each variable (non-missing)
+> summary(modelsum(bmi ~ ast + age, data=mockstudy,
++                 control=modelsum.control(gaussian.stats=c("N","estimate"))))
@@ -2783,10 +2741,10 @@

13. Modify how missing values are treated

-
> 
-> ## Always list the number of missing values
-> summary(modelsum(bmi ~ ast + age, data=mockstudy,
-+                 control=modelsum.control(gaussian.stats=c("Nmiss2","estimate"))))
+
> 
+> ## Always list the number of missing values
+> summary(modelsum(bmi ~ ast + age, data=mockstudy,
++                 control=modelsum.control(gaussian.stats=c("Nmiss2","estimate"))))
@@ -2823,10 +2781,10 @@

13. Modify how missing values are treated

-
> 
-> ## Only show the missing values if there are some (default)
-> summary(modelsum(bmi ~ ast + age, data=mockstudy, 
-+                 control=modelsum.control(gaussian.stats=c("Nmiss","estimate"))))
+
> 
+> ## Only show the missing values if there are some (default)
+> summary(modelsum(bmi ~ ast + age, data=mockstudy, 
++                 control=modelsum.control(gaussian.stats=c("Nmiss","estimate"))))
@@ -2863,10 +2821,10 @@

13. Modify how missing values are treated

-
> 
-> ## Don't show N at all
-> summary(modelsum(bmi ~ ast + age, data=mockstudy, 
-+                 control=modelsum.control(gaussian.stats=c("estimate"))))
+
> 
+> ## Don't show N at all
+> summary(modelsum(bmi ~ ast + age, data=mockstudy, 
++                 control=modelsum.control(gaussian.stats=c("estimate"))))
@@ -2898,16 +2856,16 @@

13. Modify how missing values are treated

-
-

14. Modify the number of digits used

+
+

13. Modify the number of digits used

Within modelsum.control function there are 4 options for controlling the number of significant digits shown.

    -
  • digits: controls the number of significant digits (counting both before and after the decimal point) for continuous variables
  • -
  • nsmall: controls the number of digits after the decimal point for the beta and standard error
  • -
  • nsmall.ratio: controls the number of digits for the ratio statistics (OR, HR, RR), default=2
  • -
  • digits.test: controls the number of digits after the decimal point for p-values (default=3)
  • +
  • digits: controls the number of significant digits (counting both before and after the decimal point) for continuous variables

  • +
  • nsmall: controls the number of digits after the decimal point for the beta and standard error

  • +
  • nsmall.ratio: controls the number of digits for the ratio statistics (OR, HR, RR), default=2

  • +
  • digits.test: controls the number of digits after the decimal point for p-values (default=3)

-
> summary(modelsum(bmi ~ sex + age + fu.time, data=mockstudy), digits=4, digits.test=2)
+
> summary(modelsum(bmi ~ sex + age + fu.time, data=mockstudy), digits=4, digits.test=2)
@@ -2971,59 +2929,59 @@

14. Modify the number of digits used

It is important to understand how R treats the digits argument. Here are some summaries for the variable pi. Note that with 4 digits, the number after the decimal point changes after multiplying pi by 10 or 100. However, the nsmall option specifies the number of values after the decimal point. The two can be used together (see the help file for format for more details on how that works).

-
> format(pi, digits=1)
-[1] "3"
-> format(pi, digits=3)
-[1] "3.14"
-> format(pi, digits=4)
-[1] "3.142"
-> format(pi*10, digits=4)
-[1] "31.42"
-> format(pi*100, digits=4)
-[1] "314.2"
-> format(pi*100, nsmall=4)
-[1] "314.1593"
-> format(pi*100, nsmall=2, digits=4)
-[1] "314.16"
+
> format(pi, digits=1)
+[1] "3"
+> format(pi, digits=3)
+[1] "3.14"
+> format(pi, digits=4)
+[1] "3.142"
+> format(pi*10, digits=4)
+[1] "31.42"
+> format(pi*100, digits=4)
+[1] "314.2"
+> format(pi*100, nsmall=4)
+[1] "314.1593"
+> format(pi*100, nsmall=2, digits=4)
+[1] "314.16"
-
-

15. Use case-weights in the models

+
+

14. Use case-weights in the models

Occasionally it is of interest to fit models using case weights. The modelsum function allows you to pass on the weights to the models and it will do the appropriate fit.

-
> mockstudy$agegp <- cut(mockstudy$age, breaks=c(18,50,60,70,90), right=FALSE)
-> 
-> ## create weights based on agegp and sex distribution
-> tab1 <- with(mockstudy,table(agegp, sex))
-> tab1
+
> mockstudy$agegp <- cut(mockstudy$age, breaks=c(18,50,60,70,90), right=FALSE)
+> 
+> ## create weights based on agegp and sex distribution
+> tab1 <- with(mockstudy,table(agegp, sex))
+> tab1
          sex
 agegp     Male Female
-  [18,50)  152    110
-  [50,60)  258    178
-  [60,70)  295    173
-  [70,90)  211    122
-> tab2 <- with(mockstudy, table(agegp, sex, arm))
-> gpwts <- rep(tab1, length(unique(mockstudy$arm)))/tab2
-> 
-> ## apply weights to subjects
-> index <- with(mockstudy, cbind(as.numeric(agegp), as.numeric(sex), as.numeric(as.factor(arm)))) 
-> mockstudy$wts <- gpwts[index]
-> 
-> ## show weights by treatment arm group
-> tapply(mockstudy$wts,mockstudy$arm, summary)
-$`A: IFL`
+  [18,50)  152    110
+  [50,60)  258    178
+  [60,70)  295    173
+  [70,90)  211    122
+> tab2 <- with(mockstudy, table(agegp, sex, arm))
+> gpwts <- rep(tab1, length(unique(mockstudy$arm)))/tab2
+> 
+> ## apply weights to subjects
+> index <- with(mockstudy, cbind(as.numeric(agegp), as.numeric(sex), as.numeric(as.factor(arm)))) 
+> mockstudy$wts <- gpwts[index]
+> 
+> ## show weights by treatment arm group
+> tapply(mockstudy$wts,mockstudy$arm, summary)
+$`A: IFL`
    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
-  2.923   3.225   3.548   3.502   3.844   4.045 
+  2.923   3.225   3.548   3.502   3.844   4.045 
 
-$`F: FOLFOX`
+$`F: FOLFOX`
    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
-  2.033   2.070   2.201   2.169   2.263   2.303 
+  2.033   2.070   2.201   2.169   2.263   2.303 
 
-$`G: IROX`
+$`G: IROX`
    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
-  3.667   3.734   4.023   3.945   4.031   4.471 
-
> mockstudy$newvarA <- as.numeric(mockstudy$arm=='A: IFL')
-> tab1 <- modelsum(newvarA ~ ast + bmi + hgb, data=mockstudy, subset=(arm !='G: IROX'), 
-+                  family=binomial)
-> summary(tab1, title='No Case Weights used')
+ 3.667 3.734 4.023 3.945 4.031 4.471
+
> mockstudy$newvarA <- as.numeric(mockstudy$arm=='A: IFL')
+> tab1 <- modelsum(newvarA ~ ast + bmi + hgb, data=mockstudy, subset=(arm !='G: IROX'), 
++                  family=binomial)
+> summary(tab1, title='No Case Weights used')
@@ -3103,10 +3061,12 @@

15. Use case-weights in the models

No Case Weights used
-
> 
-> tab2 <- modelsum(newvarA ~ ast + bmi + hgb, data=mockstudy, subset=(arm !='G: IROX'), 
-+                  weights=wts, family=binomial)
-> summary(tab2, title='Case Weights used')
+
> 
+> suppressWarnings({
++ tab2 <- modelsum(newvarA ~ ast + bmi + hgb, data=mockstudy, subset=(arm !='G: IROX'), 
++                  weights=wts, family=binomial)
++ summary(tab2, title='Case Weights used')
++ })
@@ -3187,8 +3147,8 @@

15. Use case-weights in the models

Case Weights used
-
-

16. Use modelsum within an Sweave document

+
+

15. Use modelsum within an Sweave document

For those users who wish to create tables within an Sweave document, the following code seems to work.

\documentclass{article}
 
@@ -3219,51 +3179,51 @@ 

16. Use modelsum within an Sweave document

\end{document}
-
-

17. Export modelsum results to a .CSV file

+
+

16. Export modelsum results to a .CSV file

When looking at multiple variables it is sometimes useful to export the results to a csv file. The as.data.frame function creates a data frame object that can be exported or further manipulated within R.

-
> summary(tab2, text=T)
+
> summary(tab2, text=T)
 -----------------------------------------------------------------------------------------------------------
-                   OR             CI.lower.OR    CI.upper.OR    p.value        concordance    Nmiss        
------------------ -------------- -------------- -------------- -------------- -------------- --------------
-(Intercept)       NA             NA             NA             0.504          0.55           210           
-ast               1              1              1.01           0.068          .              .             
-(Intercept)       NA             NA             NA             0.820          0.5            29            
-bmi               1              0.988          1.02           0.780          .              .             
-(Intercept)       NA             NA             NA             0.039          0.514          210           
-hgb               0.956          0.913          1              0.058          .              .             
+                   OR             CI.lower.OR    CI.upper.OR    p.value        concordance    Nmiss        
+----------------- -------------- -------------- -------------- -------------- -------------- --------------
+(Intercept)       NA             NA             NA             0.504          0.55           210           
+ast               1              1              1.01           0.068          .              .             
+(Intercept)       NA             NA             NA             0.820          0.5            29            
+bmi               1              0.988          1.02           0.780          .              .             
+(Intercept)       NA             NA             NA             0.039          0.514          210           
+hgb               0.956          0.913          1              0.058          .              .             
 -----------------------------------------------------------------------------------------------------------
-> tmp <- as.data.frame(tab2)
-> tmp
+> tmp <- as.data.frame(tab2)
+> tmp
          term model endpoint    OR CI.lower.OR CI.upper.OR p.value
-1 (Intercept)     1  newvarA    NA          NA          NA   0.504
-2         ast     1  newvarA 1.000       1.000        1.01   0.068
-3 (Intercept)     2  newvarA    NA          NA          NA   0.820
-4         bmi     2  newvarA 1.000       0.988        1.02   0.780
-5 (Intercept)     3  newvarA    NA          NA          NA   0.039
-6         hgb     3  newvarA 0.956       0.913        1.00   0.058
+1 (Intercept)     1  newvarA    NA          NA          NA   0.504
+2         ast     1  newvarA 1.000       1.000        1.01   0.068
+3 (Intercept)     2  newvarA    NA          NA          NA   0.820
+4         bmi     2  newvarA 1.000       0.988        1.02   0.780
+5 (Intercept)     3  newvarA    NA          NA          NA   0.039
+6         hgb     3  newvarA 0.956       0.913        1.00   0.058
   concordance Nmiss
-1       0.550   210
-2       0.550   210
-3       0.500    29
-4       0.500    29
-5       0.514   210
-6       0.514   210
-> # write.csv(tmp, '/my/path/here/mymodel.csv')
+1 0.550 210 +2 0.550 210 +3 0.500 29 +4 0.500 29 +5 0.514 210 +6 0.514 210 +> # write.csv(tmp, '/my/path/here/mymodel.csv')
-
-

18. Write modelsum object to a separate Word or HTML file

-
> ## write to an HTML document
-> # write2html(tab2, "~/ibm/trash.html")
-> 
-> ## write to a Word document
-> # write2word(tab2, "~/ibm/trash.doc", title="My table in Word")
+
+

17. Write modelsum object to a separate Word or HTML file

+
> ## write to an HTML document
+> # write2html(tab2, "~/ibm/trash.html")
+> 
+> ## write to a Word document
+> # write2word(tab2, "~/ibm/trash.doc", title="My table in Word")

Available Function Options

-
-

Summary statistics

+
+

Summary statistics

The available summary statistics, by varible type, are:

  • binomial,quasibinomial: Logistic regression models
  • @@ -3317,19 +3277,19 @@

    Summary statistics

  • CI.lower.estimate, CI.upper.estimate: print the confidence interval for the beta coefficient
-
-

modelsum.control settings

+
+

modelsum.control settings

A quick way to see what arguments are possible to utilize in a function is to use the args() command. Settings involving the number of digits can be set in modelsum.control or in summary.modelsum.

-
> args(modelsum.control)
-function (digits = 3, nsmall = NULL, nsmall.ratio = 2, digits.test = 3, 
-    show.adjust = TRUE, show.intercept = TRUE, conf.level = 0.95, 
-    binomial.stats = c("OR", "CI.lower.OR", "CI.upper.OR", "p.value", 
-        "concordance", "Nmiss"), gaussian.stats = c("estimate", 
-        "std.error", "p.value", "adj.r.squared", "Nmiss"), poisson.stats = c("RR", 
-        "CI.lower.RR", "CI.upper.RR", "p.value", "concordance", 
-        "Nmiss"), survival.stats = c("HR", "CI.lower.HR", "CI.upper.HR", 
-        "p.value", "concordance", "Nmiss"), ...) 
-NULL
+
> args(modelsum.control)
+function (digits = 3, nsmall = NULL, nsmall.ratio = 2, digits.test = 3, 
+    show.adjust = TRUE, show.intercept = TRUE, conf.level = 0.95, 
+    binomial.stats = c("OR", "CI.lower.OR", "CI.upper.OR", "p.value", 
+        "concordance", "Nmiss"), gaussian.stats = c("estimate", 
+        "std.error", "p.value", "adj.r.squared", "Nmiss"), poisson.stats = c("RR", 
+        "CI.lower.RR", "CI.upper.RR", "p.value", "concordance", 
+        "Nmiss"), survival.stats = c("HR", "CI.lower.HR", "CI.upper.HR", 
+        "p.value", "concordance", "Nmiss"), ...) 
+NULL

Settings:

  • digits=3 (number of significant digits for beta coefficient and standard error)
  • @@ -3345,15 +3305,15 @@

    modelsum.control settings

  • poisson.stats, quasipoisson.stats
-
-

summary.modelsum settings

+
+

summary.modelsum settings

The summary.modelsum function has options that modify how the table appears (such as adding a title or modifying labels).

-
> args(arsenal:::summary.modelsum)
-function (object, title = NULL, labelTranslations = NULL, digits = NA, 
-    nsmall = NA, nsmall.ratio = NA, digits.test = NA, show.intercept = NA, 
-    show.adjust = NA, text = FALSE, removeBlanks = text, labelSize = 1.2, 
-    pfootnote = TRUE, ...) 
-NULL
+
> args(arsenal:::summary.modelsum)
+function (object, title = NULL, labelTranslations = NULL, digits = NA, 
+    nsmall = NA, nsmall.ratio = NA, digits.test = NA, show.intercept = NA, 
+    show.adjust = NA, text = FALSE, removeBlanks = text, labelSize = 1.2, 
+    pfootnote = TRUE, ...) 
+NULL

Settings:

  • title
  • @@ -3374,19 +3334,6 @@

    summary.modelsum settings

    - -
- - - - - - - - + - - - - - + - - - - -
- - - - - - - - - - - - - @@ -172,19 +123,19 @@

29 December, 2016

Introduction

One of the most common tables in medical literature includes summary statistics for a set of variables, often stratified by some group (e.g. treatment arm). Locally, the SAS macros %table and %summary were written to create summary tables with a single call. With the increasing interest in R, we have developed the function tableby to create similar tables within the R environment.

In developing the tableby function, the goal was to bring the best features of these macros into an R function. However, the task was not simply to duplicate all the functionality, but rather to make use of R’s strengths (modeling, method dispersion, flexibility in function definition and output format) and make a tool that fits the needs of R users. Additionally, the results needed to fit within the general reproducible research framework so the tables could be displayed within an R markdown report.

-

This report provides step-by-step directions for using the functions associated with tableby. All functions presented here are available within the arsenal package. An assumption is made that users are somewhat familiar with R markdown documents. For those who are new to the topic, a good initial resource is available at rmarkdown.rstudio.com.

+

This report provides step-by-step directions for using the functions associated with tableby. All functions presented here are available within the arsenal package. An assumption is made that users are somewhat familiar with R markdown documents. For those who are new to the topic, a good initial resource is available at rmarkdown.rstudio.com.

Simple Example

The first step when using the tableby function is to load the arsenal package. All the examples in this report use a dataset called mockstudy made available by Paul Novotny which includes a variety of types of variables (character, numeric, factor, ordered factor, survival) to use as examples.

-
require(arsenal)
-require(knitr)
-require(survival)
-data(mockstudy) ##load data
-dim(mockstudy)  ##look at how many subjects and variables are in the dataset 
+
require(arsenal)
+require(knitr)
+require(survival)
+data(mockstudy) ##load data
+dim(mockstudy)  ##look at how many subjects and variables are in the dataset 
## [1] 1499   14
-
# help(mockstudy) ##learn more about the dataset and variables
-str(mockstudy) ##quick look at the data
+
# help(mockstudy) ##learn more about the dataset and variables
+str(mockstudy) ##quick look at the data
## 'data.frame':    1499 obs. of  14 variables:
 ##  $ case       : int  110754 99706 105271 105001 112263 86205 99508 90158 88989 90515 ...
 ##  $ age        : atomic  67 74 50 71 69 56 50 57 51 63 ...
@@ -205,12 +156,12 @@ 

Simple Example

## $ mdquality.s: int NA 1 1 1 NA 1 1 1 1 1 ... ## $ age.ord : Ord.factor w/ 8 levels "10-19"<"20-29"<..: 6 7 4 7 6 5 4 5 5 6 ...

To create a simple table stratified by treament arm, use a formula statement to specify the variables that you want summarized. The example below uses age (a continuous variable) and sex (a factor).

-
tab1 <- tableby(arm ~ sex + age, data=mockstudy)
+
tab1 <- tableby(arm ~ sex + age, data=mockstudy)

If you want to take a quick look at the table, you can use summary on your tableby object and the table will print out as text in your R console window. If you use summary without any options you will see a number of \(\&nbsp;\) statements which translates to “space” in HTML.

-
-

Pretty text version of table

+
+

Pretty text version of table

If you want a nicer version in your console window then adding the text=TRUE option.

-
summary(tab1, text=TRUE)
+
summary(tab1, text=TRUE)
## ---------------------------------------------------------------------------------------------------------------------------
 ##                          A: IFL (N=428)      F: FOLFOX (N=691)   G: IROX (N=380)     Total (N=1499)      p value           
 ## ----------------------- ------------------- ------------------- ------------------- ------------------- -------------------
@@ -223,13 +174,10 @@ 

Pretty text version of table

## Range 27 - 88 19 - 88 26 - 85 19 - 88 ## ---------------------------------------------------------------------------------------------------------------------------
-
-

Pretty Rmarkdown version of table

+
+

Pretty Rmarkdown version of table

In order for the report to look nice within an R markdown (knitr) report, you just need to specify results="asis" when creating the r chunk. This changes the layout slightly (compresses it) and bolds the variable names.

-

```{r, results=“asis”}

-

summary(tab1)

-

```

-
summary(tab1)
+
summary(tab1)
@@ -309,29 +257,42 @@

Pretty Rmarkdown version of table

-
-

Summaries using standard R code

-
## base R frequency example
-tmp <- table(Gender=mockstudy$sex, "Study Arm"=mockstudy$arm)
-tmp
+
+

Data frame version of table

+

If you want a data.frame version, simply use as.data.frame.

+
as.data.frame(tab1)
+
##           term variable A: IFL (N=428) F: FOLFOX (N=691) G: IROX (N=380) Total (N=1499) p value
+## 1          Sex      sex                                                                   0.190
+## 2         Male      sex    277 (64.7%)       411 (59.5%)       228 (60%)    916 (61.1%)        
+## 3       Female      sex    151 (35.3%)       280 (40.5%)       152 (40%)    583 (38.9%)        
+## 4 Age in Years      age                                                                   0.614
+## 5    Mean (SD)      age    59.7 (11.4)       60.3 (11.6)     59.8 (11.5)      60 (11.5)        
+## 6       Q1, Q3      age         53, 68            52, 69          52, 68         52, 68        
+## 7        Range      age        27 - 88           19 - 88         26 - 85        19 - 88
+
+
+

Summaries using standard R code

+
## base R frequency example
+tmp <- table(Gender=mockstudy$sex, "Study Arm"=mockstudy$arm)
+tmp
##         Study Arm
 ## Gender   A: IFL F: FOLFOX G: IROX
 ##   Male      277       411     228
 ##   Female    151       280     152
-
# Note: The continuity correction is applied by default in R (not used in %table)
-chisq.test(tmp) 
+
# Note: The continuity correction is applied by default in R (not used in %table)
+chisq.test(tmp) 
## 
 ##  Pearson's Chi-squared test
 ## 
 ## data:  tmp
 ## X-squared = 3.3168, df = 2, p-value = 0.1904
-
## gmodels frequency example
-#require(gmodels)
-#CrossTable(mockstudy$sex, mockstudy$arm, prop.r=F, prop.t=F, 
-#           prop.chisq=F, chisq=T, dnn=c('Gender','Study Arm'))
+
## gmodels frequency example
+#require(gmodels)
+#CrossTable(mockstudy$sex, mockstudy$arm, prop.r=F, prop.t=F, 
+#           prop.chisq=F, chisq=T, dnn=c('Gender','Study Arm'))
 
 ## base R numeric summary example
-tapply(mockstudy$age, mockstudy$arm, summary)
+tapply(mockstudy$age, mockstudy$arm, summary)
## $`A: IFL`
 ##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 ##   27.00   53.00   61.00   59.67   68.00   88.00 
@@ -343,7 +304,7 @@ 

Summaries using standard R code

## $`G: IROX` ## Min. 1st Qu. Median Mean 3rd Qu. Max. ## 26.00 52.00 61.00 59.76 68.00 85.00
-
summary(aov(age ~ arm, data=mockstudy))
+
summary(aov(age ~ arm, data=mockstudy))
##               Df Sum Sq Mean Sq F value Pr(>F)
 ## arm            2    129    64.7   0.487  0.614
 ## Residuals   1496 198628   132.8
@@ -351,23 +312,23 @@

Summaries using standard R code

Modifying Output

-
-

Add labels

+
+

Add labels

In the above example, age is shown with a label (Age in Years), but sex is listed “as is” with lower case letters. This is because the data was created in SAS and in the SAS dataset, age had a label but sex did not. The label is stored as an attribute within R.

-
## Look at one variable's label
-attr(mockstudy$age,'label')
+
## Look at one variable's label
+attr(mockstudy$age,'label')
## [1] "Age in Years"
-
## See all the variables with a label
-unlist(lapply(mockstudy,'attr','label'))
-
##                        age                        arm 
-##             "Age in Years"            "Treatment Arm" 
-##                       race                        bmi 
-##                     "Race" "Body Mass Index (kg/m^2)"
+
## See all the variables with a label
+unlist(lapply(mockstudy,'attr','label'))
+
##                        age                        arm                       race 
+##             "Age in Years"            "Treatment Arm"                     "Race" 
+##                        bmi 
+## "Body Mass Index (kg/m^2)"

If you want to add labels to other variables, there are a couple of options. First, you could add labels to the variables in your dataset.

-
attr(mockstudy$sex,'label')  <- 'Gender'
+
attr(mockstudy$sex,'label')  <- 'Gender'
 
-tab1 <- tableby(arm ~ sex + age, data=mockstudy)
-summary(tab1)
+tab1 <- tableby(arm ~ sex + age, data=mockstudy) +summary(tab1)
@@ -447,8 +408,8 @@

Add labels

Another option is to add labels after you have created the table

-
mylabels <- list( sex = "SEX", age ="Age, yrs")
-summary(tab1, labelTranslations = mylabels)
+
mylabels <- list( sex = "SEX", age ="Age, yrs")
+summary(tab1, labelTranslations = mylabels)
@@ -528,14 +489,14 @@

Add labels

Alternatively, you can check the variable labels and manipulate them with a function called labels, which works on the tableby object.

-
labels(tab1)
+
labels(tab1)
##             arm             sex             age 
 ## "Treatment Arm"        "Gender"  "Age in Years"
-
labels(tab1) <- c(arm="Treatment Assignment", age="Baseline Age (yrs)")
-labels(tab1)
+
labels(tab1) <- c(arm="Treatment Assignment", age="Baseline Age (yrs)")
+labels(tab1)
##                    arm                    sex                    age 
 ## "Treatment Assignment"               "Gender"   "Baseline Age (yrs)"
-
summary(tab1)
+
summary(tab1)
@@ -615,16 +576,16 @@

Add labels

-
-

Change summary statistics globally

+
+

Change summary statistics globally

Currently the default behavior is to summarize continuous variables with: Number of missing values, Mean (SD), 25th - 75th quantiles, and Minimum-Maximum values with an ANOVA (t-test with equal variances) p-value. For categorical variables the default is to show: Number of missing values and count (column percent) with a chi-square p-value. This behavior can be modified using the tableby.control function. In fact, you can save your standard settings and use that for future tables. Note that test=FALSE and total=FALSE results in the total column and p-value column not being printed.

-
mycontrols  <- tableby.control(test=FALSE, total=FALSE,
-                               numeric.test="kwt", cat.test="chisq",
-                               numeric.stats=c("N", "median", "q1q3"),
-                               cat.stats=c("countpct"),
-                               stats.labels=list(N='Count', median='Median', q1q3='Q1,Q3'))                            
-tab2 <- tableby(arm ~ sex + age, data=mockstudy, control=mycontrols)
-summary(tab2)
+
mycontrols  <- tableby.control(test=FALSE, total=FALSE,
+                               numeric.test="kwt", cat.test="chisq",
+                               numeric.stats=c("N", "median", "q1q3"),
+                               cat.stats=c("countpct"),
+                               stats.labels=list(N='Count', median='Median', q1q3='Q1,Q3'))
+tab2 <- tableby(arm ~ sex + age, data=mockstudy, control=mycontrols)
+summary(tab2)
@@ -686,9 +647,9 @@

Change summary statistics globally

You can also change these settings directly in the tableby call.

-
tab3 <- tableby(arm ~ sex + age, data=mockstudy, test=FALSE, total=FALSE, 
-                numeric.stats=c("median","q1q3"), numeric.test="kwt")
-summary(tab3)
+
tab3 <- tableby(arm ~ sex + age, data=mockstudy, test=FALSE, total=FALSE, 
+                numeric.stats=c("median","q1q3"), numeric.test="kwt")
+summary(tab3)
@@ -744,17 +705,17 @@

Change summary statistics globally

-
-

Change summary statistics within the formula

+
+

Change summary statistics within the formula

In addition to modifying summary options globally, it is possible to modify the test and summary statistics for specific variables within the formula statement. For example, both the kwt (Kruskal-Wallis rank-based) and anova (asymptotic analysis of variance) tests apply to numeric variables and we can use one for the variable “age” and another for the variable “ast”. A list of all the options is shown at the end of the vignette.

The tests function can do a quick check on what tests were performed on each variable in tableby.

-
tab.test <- tableby(arm ~ kwt(age) + anova(bmi) + kwt(ast), data=mockstudy)
-tests(tab.test)
+
tab.test <- tableby(arm ~ kwt(age) + anova(bmi) + kwt(ast), data=mockstudy)
+tests(tab.test)
##                     Variable    p.value                       Method
 ## age             Age in Years 0.63906143 Kruskal-Wallis rank sum test
 ## bmi Body Mass Index (kg/m^2) 0.89165522           Linear Model ANOVA
 ## ast                      ast 0.03902803 Kruskal-Wallis rank sum test
-
summary(tab.test)
+
summary(tab.test)
@@ -890,9 +851,9 @@

Change summary statistics within the formula

Summary statistics for any individual variable can also be modified, but it must be done as secondary arguments to the test function. The function names must be strings that are functions already written for tableby, built-in R functions like mean and range, or user-defined functions.

-
tab.test <- tableby(arm ~ kwt(ast, "Nmiss2","median") + anova(age, "N","mean") +
-                    kwt(bmi, "Nmiss","median"), data=mockstudy)
-summary(tab.test)
+
tab.test <- tableby(arm ~ kwt(ast, "Nmiss2","median") + anova(age, "N","mean") +
+                    kwt(bmi, "Nmiss","median"), data=mockstudy)
+summary(tab.test)
@@ -988,8 +949,8 @@

Change summary statistics within the formula

-
-

Modifying the look & feel in Word documents

+
+

Modifying the look & feel in Word documents

You can easily create Word versions of tableby output via an Rmarkdown report and the default options will give you a reasonable table in Word - just select the “Knit Word” option in RStudio.

The functionality listed in this next paragraph is coming soon but needs an upgraded version of RStudio If you want to modify fonts used for the table, then you’ll need to add an extra line to your header at the beginning of your file. You can take the WordStylesReference01.docx file and modify the fonts (storing the format preferences in your project directory). To see how this works, run your report once using WordStylesReference01.docx and then WordStylesReference02.docx.

output: word_document
@@ -1000,10 +961,10 @@ 

Modifying the look & feel in Word documents

Additional Examples

Here are multiple examples showing how to use some of the different options.

-
-

1. Summarize without a group/by variable

-
tab.noby <- tableby(~ bmi + sex + age, data=mockstudy)
-summary(tab.noby)
+
+

1. Summarize without a group/by variable

+
tab.noby <- tableby(~ bmi + sex + age, data=mockstudy)
+summary(tab.noby)
@@ -1067,9 +1028,9 @@

1. Summarize without a group/by variable

-
-

2. Display footnotes indicating which “test” was used

-
summary(tab.test) #, pfootnote=TRUE)
+
+

2. Display footnotes indicating which “test” was used

+
summary(tab.test) #, pfootnote=TRUE)
@@ -1165,11 +1126,11 @@

2. Display footnotes indicating which “test” was used

-
-

3. Summarize an ordered factor

+
+

3. Summarize an ordered factor

When comparing groups of ordered data there are a couple of options. The default uses a general independence test available from the coin package. For two-group comparisons, this is essentially the Armitage trend test. The other option is to specify the Kruskal Wallis test. The example below shows both options.

-
mockstudy$age.ordnew <- ordered(c("a",NA,as.character(mockstudy$age.ord[-(1:2)])))
-table(mockstudy$age.ord, mockstudy$sex)
+
mockstudy$age.ordnew <- ordered(c("a",NA,as.character(mockstudy$age.ord[-(1:2)])))
+table(mockstudy$age.ord, mockstudy$sex)
##        
 ##         Male Female
 ##   10-19    1      0
@@ -1180,7 +1141,7 @@ 

3. Summarize an ordered factor

## 60-69 298 170 ## 70-79 168 101 ## 80-89 20 9
-
table(mockstudy$age.ordnew, mockstudy$sex)
+
table(mockstudy$age.ordnew, mockstudy$sex)
##        
 ##         Male Female
 ##   10-19    1      0
@@ -1192,9 +1153,9 @@ 

3. Summarize an ordered factor

## 70-79 168 100 ## 80-89 20 9 ## a 1 0
-
class(mockstudy$age.ord)
+
class(mockstudy$age.ord)
## [1] "ordered" "factor"
-
summary(tableby(sex ~ age.ordnew, data = mockstudy)) #, pfootnote = TRUE)
+
summary(tableby(sex ~ age.ordnew, data = mockstudy)) #, pfootnote = TRUE)
@@ -1292,7 +1253,7 @@

3. Summarize an ordered factor

-
summary(tableby(sex ~ kwt(age.ord), data = mockstudy)) #) #, pfootnote = TRUE)
+
summary(tableby(sex ~ kwt(age.ord), data = mockstudy)) #) #, pfootnote = TRUE)
@@ -1384,16 +1345,16 @@

3. Summarize an ordered factor

-
-

4. Summarize a survival variable

+
+

4. Summarize a survival variable

First look at the information that is presented by the survfit function, then see how the same results can be seen with tableby. The default is to show the median survival (time at which the probability of survival = 50%).

-
survfit(Surv(fu.time, fu.stat)~sex, data=mockstudy)
+
survfit(Surv(fu.time, fu.stat)~sex, data=mockstudy)
## Call: survfit(formula = Surv(fu.time, fu.stat) ~ sex, data = mockstudy)
 ## 
 ##              n events median 0.95LCL 0.95UCL
 ## sex=Male   916    829    550     515     590
 ## sex=Female 583    527    543     511     575
-
survdiff(Surv(fu.time, fu.stat)~sex, data=mockstudy)
+
survdiff(Surv(fu.time, fu.stat)~sex, data=mockstudy)
## Call:
 ## survdiff(formula = Surv(fu.time, fu.stat) ~ sex, data = mockstudy)
 ## 
@@ -1402,7 +1363,7 @@ 

4. Summarize a survival variable

## sex=Female 583 527 526 0.000583 0.000956 ## ## Chisq= 0 on 1 degrees of freedom, p= 0.975
-
summary(tableby(sex ~ Surv(fu.time, fu.stat), data=mockstudy))
+
summary(tableby(sex ~ Surv(fu.time, fu.stat), data=mockstudy))
@@ -1445,7 +1406,7 @@

4. Summarize a survival variable

It is also possible to obtain summaries of the %survival at certain time points (say the probability of surviving 1-year).

-
summary(survfit(Surv(fu.time/365.25, fu.stat)~sex, data=mockstudy), times=1:5)
+
summary(survfit(Surv(fu.time/365.25, fu.stat)~sex, data=mockstudy), times=1:5)
## Call: survfit(formula = Surv(fu.time/365.25, fu.stat) ~ sex, data = mockstudy)
 ## 
 ##                 sex=Male 
@@ -1463,7 +1424,7 @@ 

4. Summarize a survival variable

## 3 95 90 0.1701 0.0157 0.1420 0.204 ## 4 51 32 0.1093 0.0133 0.0861 0.139 ## 5 18 12 0.0745 0.0126 0.0534 0.104
-
summary(tableby(sex ~ Surv(fu.time/365.25, fu.stat), data=mockstudy, times=1:5, surv.stats=c("NeventsSurv","NriskSurv")))
+
summary(tableby(sex ~ Surv(fu.time/365.25, fu.stat), data=mockstudy, times=1:5, surv.stats=c("NeventsSurv","NriskSurv")))
## Warning in tableby(sex ~ Surv(fu.time/365.25, fu.stat), data = mockstudy, : unused arguments: times
@@ -1577,14 +1538,14 @@

4. Summarize a survival variable

-
-

5. Summarize date variables

+
+

5. Summarize date variables

Date variables by default are summarized with the number of missing values, the median, and the range. For example purposes we’ve created a random date. Missing values are introduced for impossible February dates.

-
set.seed(100)
-N <- nrow(mockstudy)
-mockstudy$dtentry <- mdy.Date(month=sample(1:12,N,replace=T), day=sample(1:29,N,replace=T), 
-                              year=sample(2005:2009,N,replace=T))
-summary(tableby(sex ~ dtentry, data=mockstudy))
+
set.seed(100)
+N <- nrow(mockstudy)
+mockstudy$dtentry <- mdy.Date(month=sample(1:12,N,replace=T), day=sample(1:29,N,replace=T), 
+                              year=sample(2005:2009,N,replace=T))
+summary(tableby(sex ~ dtentry, data=mockstudy))
@@ -1634,22 +1595,22 @@

5. Summarize date variables

-
-

6. Summarize multiple variables without typing them out

+
+

6. Summarize multiple variables without typing them out

Often one wants to summarize a number of variables. Instead of typing by hand each individual variable, an alternative approach is to create a formula using the paste command with the collapse="+" option.

-
## create a vector specifying the variable names
-myvars <- names(mockstudy)
+
## create a vector specifying the variable names
+myvars <- names(mockstudy)
 
 ## select the 8th through the last variables
 ## paste them together, separated by the + sign
-RHS <- paste(myvars[8:10], collapse="+")
-RHS
+RHS <- paste(myvars[8:10], collapse="+") +RHS

[1] “ps+hgb+bmi”

-
## create a formula using the as.formula function
-as.formula(paste('arm ~ ', RHS))
+
## create a formula using the as.formula function
+as.formula(paste('arm ~ ', RHS))

arm ~ ps + hgb + bmi

-
## use the formula in the tableby function
-summary(tableby(as.formula(paste('arm ~', RHS)), data=mockstudy))
+
## use the formula in the tableby function
+summary(tableby(as.formula(paste('arm ~', RHS)), data=mockstudy))
@@ -1793,15 +1754,15 @@

6. Summarize multiple variables without typing them out

These steps can also be done using the formulize function.

-
## The formulize function does the paste and as.formula steps
-tmp <- formulize('arm',myvars[8:10])
-tmp
-

arm ~ ps + hgb + bmi <environment: 0x6593680>

-
## More complex formulas could also be written using formulize
-tmp2 <- formulize('arm',c('ps','hgb^2','bmi'))
+
## The formulize function does the paste and as.formula steps
+tmp <- formulize('arm',myvars[8:10])
+tmp
+

arm ~ ps + hgb + bmi <environment: 0x5ca23f8>

+
## More complex formulas could also be written using formulize
+tmp2 <- formulize('arm',c('ps','hgb^2','bmi'))
 
 ## use the formula in the tableby function
-summary(tableby(tmp, data=mockstudy))
+summary(tableby(tmp, data=mockstudy))
@@ -1945,24 +1906,24 @@

6. Summarize multiple variables without typing them out

-
-

7. Subset the dataset used in the analysis

+
+

7. Subset the dataset used in the analysis

Here are two ways to get the same result (limit the analysis to subjects age>5 and in the F: FOLFOX treatment group).

  • The first approach uses the subset function applied to the dataset mockstudy. This example also selects a subset of variables. The tableby function is then applied to this subsetted data.
-
newdata <- subset(mockstudy, subset=age>50 & arm=='F: FOLFOX', select = c(sex,ps:bmi))
-dim(mockstudy)
+
newdata <- subset(mockstudy, subset=age>50 & arm=='F: FOLFOX', select = c(sex,ps:bmi))
+dim(mockstudy)
## [1] 1499   16
-
table(mockstudy$arm)
+
table(mockstudy$arm)
## 
 ##    A: IFL F: FOLFOX   G: IROX 
 ##       428       691       380
-
dim(newdata)
+
dim(newdata)
## [1] 557   4
-
names(newdata)
+
names(newdata)
## [1] "sex" "ps"  "hgb" "bmi"
-
summary(tableby(sex ~ ., data=newdata))
+
summary(tableby(sex ~ ., data=newdata))
@@ -2091,7 +2052,7 @@

7. Subset the dataset used in the analysis

  • The second approach does the same analysis but uses the subset argument within tableby to subset the data.
-
summary(tableby(sex ~ ps + hgb + bmi, subset=age>50 & arm=="F: FOLFOX", data=mockstudy))
+
summary(tableby(sex ~ ps + hgb + bmi, subset=age>50 & arm=="F: FOLFOX", data=mockstudy))
@@ -2218,14 +2179,14 @@

7. Subset the dataset used in the analysis

-
-

8. Create combinations of variables on the fly

-
## create a variable combining the levels of mdquality.s and sex
-with(mockstudy, table(interaction(mdquality.s,sex)))
+
+

8. Create combinations of variables on the fly

+
## create a variable combining the levels of mdquality.s and sex
+with(mockstudy, table(interaction(mdquality.s,sex)))
## 
 ##   0.Male   1.Male 0.Female 1.Female 
 ##       77      686       47      437
-
summary(tableby(arm ~ interaction(mdquality.s,sex), data=mockstudy))
+
summary(tableby(arm ~ interaction(mdquality.s,sex), data=mockstudy))
@@ -2296,8 +2257,8 @@

8. Create combinations of variables on the fly

-
## create a new grouping variable with combined levels of arm and sex
-summary(tableby(interaction(mdquality.s, sex) ~  age + bmi, data=mockstudy, subset=arm=="F: FOLFOX"))
+
## create a new grouping variable with combined levels of arm and sex
+summary(tableby(interaction(mdquality.s, sex) ~  age + bmi, data=mockstudy, subset=arm=="F: FOLFOX"))
@@ -2404,12 +2365,12 @@

8. Create combinations of variables on the fly

-
-

9. Transform variables on the fly

+
+

9. Transform variables on the fly

Certain transformations need to be surrounded by I() so that R knows to treat it as a variable transformation and not some special model feature. If the transformation includes any of the symbols / - + ^ * then surround the new variable by I().

-
trans <- tableby(arm ~ I(age/10) + log(bmi) + factor(mdquality.s, levels=0:1, labels=c('N','Y')),
-                 data=mockstudy)
-summary(trans)
+
trans <- tableby(arm ~ I(age/10) + log(bmi) + factor(mdquality.s, levels=0:1, labels=c('N','Y')),
+                 data=mockstudy)
+summary(trans)
@@ -2537,7 +2498,7 @@

9. Transform variables on the fly

The labels for these variables isn’t exactly what we’d like so we can change modify those after the fact. Instead of typing out the very long variable names you can modify specific labels by position.

-
labels(trans)
+
labels(trans)
##                                                           arm 
 ##                                               "Treatment Arm" 
 ##                                                     I(age/10) 
@@ -2546,8 +2507,8 @@ 

9. Transform variables on the fly

## "log(bmi)" ## factor(mdquality.s, levels = 0:1, labels = c("N", "Y")) ## "factor(mdquality.s, levels = 0:1, labels = c(\"N\", \"Y\"))"
-
labels(trans)[2:4] <- c('Age per 10 yrs', 'log(BMI)', 'MD Quality')
-labels(trans)
+
labels(trans)[2:4] <- c('Age per 10 yrs', 'log(BMI)', 'MD Quality')
+labels(trans)
##                                                     arm 
 ##                                         "Treatment Arm" 
 ##                                               I(age/10) 
@@ -2556,7 +2517,7 @@ 

9. Transform variables on the fly

## "log(BMI)" ## factor(mdquality.s, levels = 0:1, labels = c("N", "Y")) ## "MD Quality"
-
summary(trans)
+
summary(trans)
@@ -2684,9 +2645,9 @@

9. Transform variables on the fly

Note that if we had not changed mdquality.s to a factor, it would have been summarized as though it were a continuous variable.

-
class(mockstudy$mdquality.s)
+
class(mockstudy$mdquality.s)

[1] “integer”

-
summary(tableby(arm~mdquality.s, data=mockstudy))
+
summary(tableby(arm~mdquality.s, data=mockstudy))
@@ -2750,7 +2711,7 @@

9. Transform variables on the fly

Another option would be to specify the test and summary statistics. In fact, if I had a set of variables coded 0/1 and that was all I was summarizing, then I could change the global option for continuous variables to use the chi-square test and show countpct.

-
summary(tableby(arm ~ chisq(mdquality.s, "Nmiss","countpct"), data=mockstudy))
+
summary(tableby(arm ~ chisq(mdquality.s, "Nmiss","countpct"), data=mockstudy))
@@ -2806,11 +2767,11 @@

9. Transform variables on the fly

-
-

10. Change the ordering of the variables or delete a variable

-
mytab <- tableby(arm ~ sex + alk.phos + age, data=mockstudy)
-mytab2 <- mytab[c('age','sex','alk.phos')]
-summary(mytab2)
+
+

10. Change the ordering of the variables or delete a variable

+
mytab <- tableby(arm ~ sex + alk.phos + age, data=mockstudy)
+mytab2 <- mytab[c('age','sex','alk.phos')]
+summary(mytab2)
@@ -2929,7 +2890,7 @@

10. Change the ordering of the variables or delete a variable

-
summary(mytab[c('age','sex')], nsmall = 2)
+
summary(mytab[c('age','sex')], nsmall = 2)
@@ -3008,7 +2969,7 @@

10. Change the ordering of the variables or delete a variable

-
summary(mytab[c(3,1)], nsmall = 3)
+
summary(mytab[c(3,1)], nsmall = 3)
@@ -3088,26 +3049,26 @@

10. Change the ordering of the variables or delete a variable

-
-

11. Merge two tableby objects together

+
+

11. Merge two tableby objects together

It is possible to combine two tableby objects so that they print out together.

-
## demographics
-tab1 <- tableby(arm ~ sex + age, data=mockstudy,
-                control=tableby.control(numeric.stats=c("Nmiss","meansd"), total=FALSE))
+
## demographics
+tab1 <- tableby(arm ~ sex + age, data=mockstudy,
+                control=tableby.control(numeric.stats=c("Nmiss","meansd"), total=FALSE))
 ## lab data
-tab2 <- tableby(arm ~ hgb + alk.phos, data=mockstudy,
-                control=tableby.control(numeric.stats=c("Nmiss","median","q1q3"),
-                                        numeric.test="kwt", total=FALSE))
-names(tab1$x)
+tab2 <- tableby(arm ~ hgb + alk.phos, data=mockstudy, + control=tableby.control(numeric.stats=c("Nmiss","median","q1q3"), + numeric.test="kwt", total=FALSE)) +names(tab1$x)

[1] “sex” “age”

-
names(tab2$x)
+
names(tab2$x)

[1] “hgb” “alk.phos”

-
tab12 <- merge(tab1,tab2)
-class(tab12)
+
tab12 <- merge(tab1,tab2)
+class(tab12)

[1] “tableby”

-
names(tab12$x)
+
names(tab12$x)

[1] “sex” “age” “hgb” “alk.phos”

-
summary(tab12) #, pfootnote=TRUE)
+
summary(tab12) #, pfootnote=TRUE)
@@ -3220,11 +3181,11 @@

11. Merge two tableby objects together

-
-

12. Add a title to the table

+
+

12. Add a title to the table

When creating a pdf the tables are automatically numbered and the title appears below the table. In Word and HTML, the titles appear un-numbered and above the table.

-
t1 <- tableby(arm ~ sex + age, data=mockstudy)
-summary(t1, title='Demographics')
+
t1 <- tableby(arm ~ sex + age, data=mockstudy)
+summary(t1, title='Demographics')
@@ -3305,20 +3266,24 @@

12. Add a title to the table

Demographics
-
-

13. Modify how missing values are displayed

-

Depending on the report you are writing you have the following options: * Show how many subjects have each variable * Show how many subjects are missing each variable * Show how many subjects are missing each variable only if there are any missing values * Don’t indicate missing values at all

-
## look at how many missing values there are for each variable
-apply(is.na(mockstudy),2,sum)
-
##        case         age         arm         sex        race     fu.time 
-##           0           0           0           0           7           0 
-##     fu.stat          ps         hgb         bmi    alk.phos         ast 
-##           0         266         266          33         266         266 
-## mdquality.s     age.ord  age.ordnew     dtentry 
-##         252           0           1           5
-
## Show how many subjects have each variable (non-missing)
-summary(tableby(sex ~ ast + age, data=mockstudy,
-                control=tableby.control(numeric.stats=c("N","median"), total=FALSE)))
+
+

13. Modify how missing values are displayed

+

Depending on the report you are writing you have the following options:

+
    +
  • Show how many subjects have each variable

  • +
  • Show how many subjects are missing each variable

  • +
  • Show how many subjects are missing each variable only if there are any missing values

  • +
  • Don’t indicate missing values at all

  • +
+
## look at how many missing values there are for each variable
+apply(is.na(mockstudy),2,sum)
+
##        case         age         arm         sex        race     fu.time     fu.stat          ps 
+##           0           0           0           0           7           0           0         266 
+##         hgb         bmi    alk.phos         ast mdquality.s     age.ord  age.ordnew     dtentry 
+##         266          33         266         266         252           0           1           5
+
## Show how many subjects have each variable (non-missing)
+summary(tableby(sex ~ ast + age, data=mockstudy,
+                control=tableby.control(numeric.stats=c("N","median"), total=FALSE)))
@@ -3373,9 +3338,9 @@

13. Modify how missing values are displayed

-
## Always list the number of missing values
-summary(tableby(sex ~ ast + age, data=mockstudy,
-                control=tableby.control(numeric.stats=c("Nmiss2","median"), total=FALSE)))
+
## Always list the number of missing values
+summary(tableby(sex ~ ast + age, data=mockstudy,
+                control=tableby.control(numeric.stats=c("Nmiss2","median"), total=FALSE)))
@@ -3430,9 +3395,9 @@

13. Modify how missing values are displayed

-
## Only show the missing values if there are some (default)
-summary(tableby(sex ~ ast + age, data=mockstudy, 
-                control=tableby.control(numeric.stats=c("Nmiss","mean"),total=FALSE)))
+
## Only show the missing values if there are some (default)
+summary(tableby(sex ~ ast + age, data=mockstudy, 
+                control=tableby.control(numeric.stats=c("Nmiss","mean"),total=FALSE)))
@@ -3481,9 +3446,9 @@

13. Modify how missing values are displayed

-
## Don't show N at all
-summary(tableby(sex ~ ast + age, data=mockstudy, 
-                control=tableby.control(numeric.stats=c("mean"),total=FALSE)))
+
## Don't show N at all
+summary(tableby(sex ~ ast + age, data=mockstudy, 
+                control=tableby.control(numeric.stats=c("mean"),total=FALSE)))
@@ -3527,16 +3492,16 @@

13. Modify how missing values are displayed

-
-

14. Modify the number of digits used

+
+

14. Modify the number of digits used

Within tableby.control function there are 4 options for controlling the number of significant digits shown.

    -
  • digits: controls the number of significant digits (counting both before and after the decimal point) for continuous variables
  • -
  • nsmall: controls the number of digits after the decimal point for continous variables
  • -
  • nsmall.pct: controls the number of digits after the decimal point for percentages
  • -
  • digits.test: controls the number of digits after the decimal point for p-values (default=3)
  • +
  • digits: controls the number of significant digits (counting both before and after the decimal point) for continuous variables

  • +
  • nsmall: controls the number of digits after the decimal point for continous variables

  • +
  • nsmall.pct: controls the number of digits after the decimal point for percentages

  • +
  • digits.test: controls the number of digits after the decimal point for p-values (default=3)

-
summary(tableby(arm ~ sex + age + fu.time, data=mockstudy), digits=4, digits.test=2, nsmall.pct=1)
+
summary(tableby(arm ~ sex + age + fu.time, data=mockstudy), digits=4, digits.test=2, nsmall.pct=1)
@@ -3648,31 +3613,31 @@

14. Modify the number of digits used

It is important to understand how R treats the digits argument. Here are some summaries for the variable pi. Note that with 4 digits, the number after the decimal point changes after multiplying pi by 10 or 100. However, the nsmall option specifies the number of values after the decimal point. The two can be used together (see the help file for format for more details on how that works).

-
format(pi, digits=1)
+
format(pi, digits=1)
## [1] "3"
-
format(pi, digits=3)
+
format(pi, digits=3)
## [1] "3.14"
-
format(pi, digits=4)
+
format(pi, digits=4)
## [1] "3.142"
-
format(pi*10, digits=4)
+
format(pi*10, digits=4)
## [1] "31.42"
-
format(pi*100, digits=4)
+
format(pi*100, digits=4)
## [1] "314.2"
-
format(pi*100, nsmall=4)
+
format(pi*100, nsmall=4)
## [1] "314.1593"
-
format(pi*100, nsmall=2, digits=4)
+
format(pi*100, nsmall=2, digits=4)
## [1] "314.16"
-
-

15. Create a user-defined summary statistic

+
+

15. Create a user-defined summary statistic

For purposes of this example, the code below creates a trimmed mean function (trims 10%) and use that to summarize the data. Note the use of the ... which tells R to pass extra arguments on - this is required for user-defined functions. In this case, na.rm=T is passed to myfunc. The weights argument is also required, even though it isn’t passed on to the internal function in this particular example.

-
myfunc <- function(x, weights=rep(1,length(x)), ...){
-  mean(x, trim=.1, ...)
+
myfunc <- function(x, weights=rep(1,length(x)), ...){
+  mean(x, trim=.1, ...)
 }
 
-summary(tableby(sex ~ hgb, data=mockstudy, 
-                control=tableby.control(numeric.stats=c("Nmiss","myfunc"), numeric.test="kwt",
-                    stats.labels=list(Nmiss='Missing values', myfunc="Trimmed Mean, 10%"))))
+summary(tableby(sex ~ hgb, data=mockstudy, + control=tableby.control(numeric.stats=c("Nmiss","myfunc"), numeric.test="kwt", + stats.labels=list(Nmiss='Missing values', myfunc="Trimmed Mean, 10%"))))
@@ -3715,20 +3680,20 @@

15. Create a user-defined summary statistic

-
-

16. Use case-weights for creating summary statistics

+
+

16. Use case-weights for creating summary statistics

When comparing groups, they are often unbalanced when it comes to nuisances such as age and sex. The tableby function allows you to create weighted summary statistics. If this option us used then p-values are not calculated (test=FALSE).

-
##create fake group that is not balanced by age/sex 
-set.seed(200)
-mockstudy$fake_arm <- ifelse(mockstudy$age>60 & mockstudy$sex=='Female',sample(c('A','B'),replace=T, prob=c(.2,.8)),
-                            sample(c('A','B'),replace=T, prob=c(.8,.4)))
+
##create fake group that is not balanced by age/sex 
+set.seed(200)
+mockstudy$fake_arm <- ifelse(mockstudy$age>60 & mockstudy$sex=='Female',sample(c('A','B'),replace=T, prob=c(.2,.8)),
+                            sample(c('A','B'),replace=T, prob=c(.8,.4)))
 
-mockstudy$agegp <- cut(mockstudy$age, breaks=c(18,50,60,70,90), right=FALSE)
+mockstudy$agegp <- cut(mockstudy$age, breaks=c(18,50,60,70,90), right=FALSE)
 
 ## create weights based on agegp and sex distribution
-tab1 <- with(mockstudy,table(agegp, sex))
-tab2 <- with(mockstudy, table(agegp, sex, fake_arm))
-tab2
+tab1 <- with(mockstudy,table(agegp, sex)) +tab2 <- with(mockstudy, table(agegp, sex, fake_arm)) +tab2
## , , fake_arm = A
 ## 
 ##          sex
@@ -3746,15 +3711,15 @@ 

16. Use case-weights for creating summary statistics

## [50,60) 130 84 ## [60,70) 156 166 ## [70,90) 109 122
-
gpwts <- rep(tab1, length(unique(mockstudy$fake_arm)))/tab2
-gpwts[gpwts>50] <- 30
+
gpwts <- rep(tab1, length(unique(mockstudy$fake_arm)))/tab2
+gpwts[gpwts>50] <- 30
 
 ## apply weights to subjects
-index <- with(mockstudy, cbind(as.numeric(agegp), as.numeric(sex), as.numeric(as.factor(fake_arm)))) 
-mockstudy$wts <- gpwts[index]
+index <- with(mockstudy, cbind(as.numeric(agegp), as.numeric(sex), as.numeric(as.factor(fake_arm)))) 
+mockstudy$wts <- gpwts[index]
 
 ## show weights by treatment arm group
-tapply(mockstudy$wts,mockstudy$fake_arm, summary)
+tapply(mockstudy$wts,mockstudy$fake_arm, summary)
## $A
 ##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 ##   1.774   1.894   2.069   2.276   2.082  24.710 
@@ -3762,8 +3727,8 @@ 

16. Use case-weights for creating summary statistics

## $B ## Min. 1st Qu. Median Mean 3rd Qu. Max. ## 1.000 1.042 1.924 1.677 1.985 2.292
-
orig <- tableby(fake_arm ~ age + sex + Surv(fu.time/365, fu.stat), data=mockstudy, test=FALSE)
-summary(orig, title='No Case Weights used')
+
orig <- tableby(fake_arm ~ age + sex + Surv(fu.time/365, fu.stat), data=mockstudy, test=FALSE)
+summary(orig, title='No Case Weights used')
@@ -3843,8 +3808,8 @@

16. Use case-weights for creating summary statistics

No Case Weights used
-
tab1 <- tableby(fake_arm ~ age + sex + Surv(fu.time/365, fu.stat), data=mockstudy, weights=wts)
-summary(tab1, title='Case Weights used')
+
tab1 <- tableby(fake_arm ~ age + sex + Surv(fu.time/365, fu.stat), data=mockstudy, weights=wts)
+summary(tab1, title='Case Weights used')
@@ -3925,15 +3890,15 @@

16. Use case-weights for creating summary statistics

Case Weights used
-
-

17. Create your own p-value and add it to the table

+
+

17. Create your own p-value and add it to the table

When using weighted summary statistics, it is often desirable to then show a p-value from a model that corresponds to the weighted analysis. It is possible to add your own p-value and modify the column title for that new p-value. Another use for this would be to add standardized differences or confidence intervals instead of a p-value.

To add the p-value you simply need to create a data frame and use the function modpval.tableby. The first 2 columns in the dataframe are required and are the variable name and the new p-value. The third column can be used to indicate what method was used to calculate the p-value. If you specify use.pname=TRUE then the column name indicating the p-value will be also be used in the tableby summary.

-
mypval <- data.frame(variable=c('age','sex','Surv(fu.time/365, fu.stat)'), 
-                     adj.pvalue=c(.953,.811,.01), 
-                     method=c('Age/Sex adjusted model results'))
-tab2 <- modpval.tableby(tab1, mypval, use.pname=TRUE)
-summary(tab2, title='Case Weights used, p-values added') #, pfootnote=TRUE)
+
mypval <- data.frame(variable=c('age','sex','Surv(fu.time/365, fu.stat)'), 
+                     adj.pvalue=c(.953,.811,.01), 
+                     method=c('Age/Sex adjusted model results'))
+tab2 <- modpval.tableby(tab1, mypval, use.pname=TRUE)
+summary(tab2, title='Case Weights used, p-values added') #, pfootnote=TRUE)
@@ -4026,13 +3991,13 @@

17. Create your own p-value and add it to the table

Case Weights used, p-values added
-
-

18. For two-level categorical variables, only display one level.

+
+

18. For two-level categorical variables, only display one level.

If the cat.simplify option is set to TRUE then only the second level of the group. In the example below sex has the levels and “Female” is the second level, hence only the %female is shown in the table. Similarly, “mdquality.s” was turned to a factor and “1” is the second level, hence

-
levels(mockstudy$sex)
+
levels(mockstudy$sex)

[1] “Male” “Female”

-
table2 <- tableby(arm~sex + factor(mdquality.s), data=mockstudy, cat.simplify=TRUE)
-summary(table2, labelTranslations=c(sex="Female", "factor(mdquality.s)"="MD Quality"))
+
table2 <- tableby(arm~sex + factor(mdquality.s), data=mockstudy, cat.simplify=TRUE)
+summary(table2, labelTranslations=c(sex="Female", "factor(mdquality.s)"="MD Quality"))
@@ -4088,8 +4053,8 @@

18. For two-level categorical variables, only display one level.

-
-

19. Use tableby within an Sweave document

+
+

19. Use tableby within an Sweave document

For those users who wish to create tables within an Sweave document, the following code seems to work.

\documentclass{article}
 
@@ -4120,11 +4085,11 @@ 

19. Use tableby within an Sweave document

\end{document}
-
-

20. Export tableby object to a .CSV file

+
+

20. Export tableby object to a .CSV file

When looking at multiple variables it is sometimes useful to export the results to a csv file. The as.data.frame function creates a data frame object that can be exported or further manipulated within R.

-
tab1 <- tableby(arm~sex+age, data=mockstudy)
-summary(tab1, text=T)
+
tab1 <- tableby(arm~sex+age, data=mockstudy)
+summary(tab1, text=T)
## ---------------------------------------------------------------------------------------------------------------------------
 ##                          A: IFL (N=428)      F: FOLFOX (N=691)   G: IROX (N=380)     Total (N=1499)      p value           
 ## ----------------------- ------------------- ------------------- ------------------- ------------------- -------------------
@@ -4136,40 +4101,32 @@ 

20. Export tableby object to a .CSV file

## Q1, Q3 53, 68 52, 69 52, 68 52, 68 ## Range 27 - 88 19 - 88 26 - 85 19 - 88 ## ---------------------------------------------------------------------------------------------------------------------------
-
tmp <- as.data.frame(tab1)
-tmp
-
##           term variable A: IFL (N=428) F: FOLFOX (N=691) G: IROX (N=380)
-## 1       Gender      sex                                                 
-## 2         Male      sex    277 (64.7%)       411 (59.5%)       228 (60%)
-## 3       Female      sex    151 (35.3%)       280 (40.5%)       152 (40%)
-## 4 Age in Years      age                                                 
-## 5    Mean (SD)      age    59.7 (11.4)       60.3 (11.6)     59.8 (11.5)
-## 6       Q1, Q3      age         53, 68            52, 69          52, 68
-## 7        Range      age        27 - 88           19 - 88         26 - 85
-##   Total (N=1499) p value
-## 1                  0.190
-## 2    916 (61.1%)        
-## 3    583 (38.9%)        
-## 4                  0.614
-## 5      60 (11.5)        
-## 6         52, 68        
-## 7        19 - 88
-
# write.csv(tmp, '/my/path/here/mymodel.csv')
+
tmp <- as.data.frame(tab1)
+tmp
+
##           term variable A: IFL (N=428) F: FOLFOX (N=691) G: IROX (N=380) Total (N=1499) p value
+## 1       Gender      sex                                                                   0.190
+## 2         Male      sex    277 (64.7%)       411 (59.5%)       228 (60%)    916 (61.1%)        
+## 3       Female      sex    151 (35.3%)       280 (40.5%)       152 (40%)    583 (38.9%)        
+## 4 Age in Years      age                                                                   0.614
+## 5    Mean (SD)      age    59.7 (11.4)       60.3 (11.6)     59.8 (11.5)      60 (11.5)        
+## 6       Q1, Q3      age         53, 68            52, 69          52, 68         52, 68        
+## 7        Range      age        27 - 88           19 - 88         26 - 85        19 - 88
+
# write.csv(tmp, '/my/path/here/mymodel.csv')
-
-

21. Write tableby object to a separate Word or HTML file

-
## write to an HTML document
-tab1 <- tableby(arm ~ sex + age, data=mockstudy)
-# write2html(tab1, "~/ibm/trash.html")
+
+

21. Write tableby object to a separate Word or HTML file

+
## write to an HTML document
+tab1 <- tableby(arm ~ sex + age, data=mockstudy)
+write2html(tab1, "~/trash.html")
 
 ## write to a Word document
-# write2word(tab1, "~/ibm/trash.doc", title="My table in Word")
+write2word(tab1, "~/trash.doc", title="My table in Word")

Available Function Options

-
-

Summary statistics

+
+

Summary statistics

The default summary statistics, by varible type, are:

  • cont: Continuous variables will show by default Nmiss, meansd, q1q3, range
  • @@ -4193,8 +4150,8 @@

    Summary statistics

  • medsurv: print the median survival
-
-

Testing options

+
+

Testing options

The tests used to calculate p-values differ by the variable type, but can be specified explicitly in the formula statement or in the control function.

The following tests are accepted:

    @@ -4206,10 +4163,10 @@

    Testing options

  • trend: The independence_test function from the coin is used to test for trends. Whenthe grouping variable has two levels, it is equivalent to the Armitage trend test. This is the default for ordered factors

-
-

tableby.control settings

+
+

tableby.control settings

A quick way to see what arguments are possible to utilize in a function is to use the args() command. Settings involving the number of digits can be set in tableby.control or in summary.tableby.

-
args(tableby.control)
+
args(tableby.control)
## function (test = TRUE, total = TRUE, test.pname = NULL, cat.simplify = FALSE, 
 ##     numeric.test = "anova", cat.test = "chisq", ordered.test = "trend", 
 ##     surv.test = "logrank", date.test = "kwt", numeric.stats = c("Nmiss", 
@@ -4239,10 +4196,10 @@ 

tableby.control settings

  • surv.test, surv.stats
  • -
    -

    summary.tableby settings

    -

    The summary.tableby function has options that modify how the table appears (such as adding a title or modifying labels).

    -
    args(arsenal:::summary.tableby)
    +
    +

    summary.tableby settings

    +

    The summary.tableby function has options that modify how the table appears (such as adding a title or modifying labels).

    +
    args(arsenal:::summary.tableby)
    ## function (object, title = NULL, labelTranslations = NULL, digits = NA, 
     ##     nsmall = NA, nsmall.pct = NA, digits.test = NA, text = FALSE, 
     ##     removeBlanks = text, labelSize = 1.2, test = NA, test.pname = NA, 
    @@ -4267,19 +4224,6 @@ 

    summary.tableby settings

    - -
    - - - + + + diff --git a/man/arsenal.Rd b/man/arsenal.Rd index 7452805..77734dd 100644 --- a/man/arsenal.Rd +++ b/man/arsenal.Rd @@ -9,6 +9,8 @@ An Arsenal of 'R' functions for large-scale statistical summaries, which are streamlined to work within the latest reporting tools in 'R' and 'RStudio' and which use formulas and versatile summary statistics for summary tables and models. + +The package download, NEWS, and README are available on CRAN: \url{https://cran.r-project.org/package=arsenal} } \section{Functions}{ @@ -23,6 +25,8 @@ Below are listed some of the most widely used functions available in \code{arsen \code{\link{write2word}}, \code{\link{write2html}}, \code{\link{write2pdf}}: Functions to generate a word, html, or pdf document containing a single table. +\code{\link{write2}}: Functions to generate a single document containing a single table. (Also the S3 backbone behind the \code{write2*} functions.) + \code{\link{formulize}}: A shortcut to generate one-, two-, or many-sided formulas. \code{\link{mdy.Date}} and \code{\link{Date.mdy}}: Convert numeric dates for month, day, and year to Date object, and vice versa. diff --git a/man/as.data.frame.modelsum.Rd b/man/as.data.frame.modelsum.Rd index 0bf4fe8..ed42a90 100644 --- a/man/as.data.frame.modelsum.Rd +++ b/man/as.data.frame.modelsum.Rd @@ -17,7 +17,7 @@ \item{title}{Title for the table, defaults to \code{NULL} (no title)} \item{labelTranslations}{List where name is the label in the output, and value is the label you -want displayed e.g. \code{list (q1q3: "Q1, Q3", medsurv = "Median Survival")}.} +want displayed e.g. \code{list(q1q3 = "Q1, Q3", medsurv = "Median Survival")}.} \item{digits}{Maximum number of digits to display for floating point numbers. If \code{NA} (default), it uses the value from \code{object$control$digits} diff --git a/man/modelsum.Rd b/man/modelsum.Rd index dcbe264..1fad245 100644 --- a/man/modelsum.Rd +++ b/man/modelsum.Rd @@ -59,13 +59,14 @@ Fit and summarize models for each independent (x) variable with a response varia data(mockstudy) -tab1 <- modelsum(bmi ~ sex + age, data=mockstudy) -summary(tab1, text=TRUE) +tab1 <- modelsum(bmi ~ sex + age, data = mockstudy) +summary(tab1, text = TRUE) -tab2 <- modelsum(alk.phos ~ arm + ps + hgb, adjust= ~age + sex, family="gaussian",data=mockstudy) -summary(tab2, text=TRUE) +tab2 <- modelsum(alk.phos ~ arm + ps + hgb, adjust = ~ age + sex, + family = "gaussian", data = mockstudy) +summary(tab2, text = TRUE) -summary(tab2, show.intercept=FALSE, text=TRUE) +summary(tab2, show.intercept = FALSE, text = TRUE) tab2.df <- as.data.frame(tab2) diff --git a/man/summary.modelsum.Rd b/man/summary.modelsum.Rd index f19222b..7ffe351 100644 --- a/man/summary.modelsum.Rd +++ b/man/summary.modelsum.Rd @@ -15,7 +15,7 @@ \item{title}{Title for the table, defaults to \code{NULL} (no title)} \item{labelTranslations}{List where name is the label in the output, and value is the label you -want displayed e.g. \code{list (q1q3: "Q1, Q3", medsurv = "Median Survival")}.} +want displayed e.g. \code{list(q1q3 = "Q1, Q3", medsurv = "Median Survival")}.} \item{digits}{Maximum number of digits to display for floating point numbers. If \code{NA} (default), it uses the value from \code{object$control$digits} diff --git a/man/tableby.Rd b/man/tableby.Rd index 79879de..eeaeddc 100644 --- a/man/tableby.Rd +++ b/man/tableby.Rd @@ -116,7 +116,7 @@ data(mockstudy) tab1 <- tableby(arm ~ sex + age, data=mockstudy) summary(tab1, text=TRUE) -mylabels <- list( sex = "SEX", age ="Age, yrs") +mylabels <- list(sex = "SEX", age ="Age, yrs") summary(tab1, labelTranslations = mylabels, text=TRUE) tab3 <- tableby(arm ~ sex + age, data=mockstudy, test=FALSE, total=FALSE, diff --git a/man/write2.Rd b/man/write2.Rd index 6d194ac..0d15c5b 100644 --- a/man/write2.Rd +++ b/man/write2.Rd @@ -2,64 +2,93 @@ % Please edit documentation in R/write2.R \name{write2} \alias{write2} -\alias{write2html} -\alias{write2pdf} -\alias{write2word} -\title{write2word, write2html, write2pdf} +\alias{write2.character} +\alias{write2.default} +\alias{write2.freqlist} +\alias{write2.knitr_kable} +\alias{write2.modelsum} +\alias{write2.tableby} +\alias{write2.xtable} +\title{write2} \usage{ -write2word(object, file, ..., keep.md = FALSE) +write2(object, file, ..., keep.md, output_format) -write2pdf(object, file, ..., keep.md = FALSE) +\method{write2}{tableby}(object, file, ..., keep.md = FALSE, + output_format = NULL) -write2html(object, file, ..., keep.md = FALSE) +\method{write2}{modelsum}(object, file, ..., keep.md = FALSE, + output_format = NULL) + +\method{write2}{freqlist}(object, file, ..., keep.md = FALSE, + output_format = NULL) + +\method{write2}{knitr_kable}(object, file, ..., keep.md = FALSE, + output_format = NULL) + +\method{write2}{xtable}(object, file, ..., keep.md = FALSE, + output_format = NULL) + +\method{write2}{character}(object, file, ..., keep.md = FALSE, + output_format = NULL) + +\method{write2}{default}(object, file, FUN, ..., keep.md = FALSE, + output_format = NULL) } \arguments{ -\item{object}{An object whose \code{summary} output looks "good" when using \code{results='asis'} in markdown.} +\item{object}{An object.} \item{file}{A single character string denoting the filename for the output document.} -\item{...}{Additional arguments to be passed to \code{summary}, \code{rmarkdown::render}, etc. +\item{...}{Additional arguments to be passed to \code{FUN}, \code{rmarkdown::render}, etc. One popular option is to use \code{quiet = TRUE} to suppress the command line output.} \item{keep.md}{Logical, denoting whether to keep the intermediate \code{.md} file.} + +\item{output_format}{One of the following: +\enumerate{ + \item{An output format object, e.g. \code{rmarkdown::\link[rmarkdown]{html_document}(...)}.} + \item{A character string denoting such a format function, e.g. \code{"html_document"}. In this case, the \code{"..."} are NOT passed.} + \item{The format function itself, e.g. \code{rmarkdown::html_document}. In this case, the \code{"..."} arguments are passed.} + \item{One of \code{"html"}, \code{"pdf"}, and \code{"word"}, shortcuts implemented here. In this case, the \code{"..."} arguments are passed.} + \item{\code{NULL}, in which the output is HTML by default.} +} +See \code{rmarkdown::\link[rmarkdown]{render}} for details.} + +\item{FUN}{The summary-like or print-like function to use to generate the markdown content. Can be passed as a function or a +character string. It's expected that \code{FUN(object, ...)} looks "good" when using \code{results='asis'} in markdown.} } \value{ \code{object} is returned invisibly, and \code{file} is written. } \description{ -Functions to generate a word, html, or pdf document containing a single table. +Functions to generate a single document containing a single table. (Also the S3 backbone behind the \code{write2*} functions.) } \details{ -This is (kind of) an S3 method (the real S3 method is \code{write2}),and the default - (used for \code{\link{tableby}}, \code{\link{modelsum}}, \code{\link{freqlist}}, etc.) assumes - that there is a \code{summary} method implemented. - - To generate the appropriate file type, the default uses one of \code{rmarkdown::word_document}, \code{rmarkdown::html_document}, - and \code{rmarkdown::pdf_document} to get the job done. \code{"..."} arguments are passed to these functions, too. +\code{write2} is an S3 method, and the default + assumes that there is a \code{FUN} method implemented which looks 'good' in Rmarkdown. + + There are methods implemented for \code{\link{tableby}}, \code{\link{modelsum}}, and \code{\link{freqlist}}, all of which use the + \code{summary} function. There are also methods compatible with \code{\link[knitr]{kable}}, \code{\link[xtable]{xtable}}, + and \code{\link[pander]{pander_return}}. } \examples{ \dontrun{ data(mockstudy) # tableby example tab1 <- tableby(arm ~ sex + age, data=mockstudy) -write2html(tab1, "~/ibm/trash.html") - -# freqlist example -tab.ex <- table(mockstudy[, c("arm", "sex", "mdquality.s")], useNA = "ifany") -noby <- freqlist(tab.ex, na.options = "include") -write2pdf(noby, "~/ibm/trash2.pdf") - -# A more complicated example -write2word(tab1, "~/ibm/trash.doc", keep.md = TRUE, - reference_docx = mystyles.docx, # passed to rmarkdown::word_document +write2(tab1, "~/trash.rtf", + toc = TRUE, # passed to rmarkdown::rtf_document, though in this case it's not practical quiet = TRUE, # passed to rmarkdown::render - title = "My cool new title" # passed to summary.tableby + title = "My cool new title", # passed to summary.tableby + output_format = rmarkdown::rtf_document) } } \author{ Ethan Heinzen, adapted from code from Krista Goergen } \seealso{ -\code{\link[rmarkdown]{render}}, \code{\link[rmarkdown]{word_document}}, \code{\link[rmarkdown]{html_document}}, \code{\link[rmarkdown]{pdf_document}} +\code{\link{write2word}}, \code{\link{write2pdf}}, \code{\link{write2html}}, + \code{\link[rmarkdown]{render}}, \code{\link[rmarkdown]{word_document}}, \code{\link[rmarkdown]{html_document}}, \code{\link[rmarkdown]{pdf_document}}, + \code{\link[rmarkdown]{rtf_document}}, \code{\link[rmarkdown]{md_document}}, \code{\link[rmarkdown]{odt_document}} } diff --git a/man/write2specific.Rd b/man/write2specific.Rd new file mode 100644 index 0000000..a62d2df --- /dev/null +++ b/man/write2specific.Rd @@ -0,0 +1,62 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/write2.R +\name{write2specific} +\alias{write2html} +\alias{write2pdf} +\alias{write2specific} +\alias{write2word} +\title{write2word, write2html, write2pdf} +\usage{ +write2word(object, file, ..., keep.md = FALSE) + +write2pdf(object, file, ..., keep.md = FALSE) + +write2html(object, file, ..., keep.md = FALSE) +} +\arguments{ +\item{object}{An object.} + +\item{file}{A single character string denoting the filename for the output document.} + +\item{...}{Additional arguments to be passed to \code{FUN}, \code{rmarkdown::render}, etc. +One popular option is to use \code{quiet = TRUE} to suppress the command line output.} + +\item{keep.md}{Logical, denoting whether to keep the intermediate \code{.md} file.} +} +\value{ +\code{object} is returned invisibly, and \code{file} is written. +} +\description{ +Functions to generate a word, html, or pdf document containing a single table. +} +\details{ +To generate the appropriate file type, the \code{write2*} functions use one of \code{rmarkdown::word_document}, \code{rmarkdown::html_document}, + and \code{rmarkdown::pdf_document} to get the job done. \code{"..."} arguments are passed to these functions, too. +} +\examples{ +\dontrun{ +data(mockstudy) +# tableby example +tab1 <- tableby(arm ~ sex + age, data=mockstudy) +write2html(tab1, "~/trash.html") + +# freqlist example +tab.ex <- table(mockstudy[, c("arm", "sex", "mdquality.s")], useNA = "ifany") +noby <- freqlist(tab.ex, na.options = "include") +write2pdf(noby, "~/trash2.pdf") + +# A more complicated example +write2word(tab1, "~/trash.doc", + keep.md = TRUE, + reference_docx = mystyles.docx, # passed to rmarkdown::word_document + quiet = TRUE, # passed to rmarkdown::render + title = "My cool new title") # passed to summary.tableby +} +} +\author{ +Ethan Heinzen, adapted from code from Krista Goergen +} +\seealso{ +\code{\link{write2}} +} + diff --git a/tests/testthat/test_formulize.R b/tests/testthat/test_formulize.R index 7db4245..26bea20 100644 --- a/tests/testthat/test_formulize.R +++ b/tests/testthat/test_formulize.R @@ -98,3 +98,7 @@ test_that("Two-sided formula, mixed input", { ) }) + +########################################################################################################### +#### Reported bugs for formulize +########################################################################################################### \ No newline at end of file diff --git a/tests/testthat/test_freqlist.R b/tests/testthat/test_freqlist.R index 243e835..65dbce5 100644 --- a/tests/testthat/test_freqlist.R +++ b/tests/testthat/test_freqlist.R @@ -251,3 +251,8 @@ test_that("Changing the labels", { ) }) + + +########################################################################################################### +#### Reported bugs for freqlist +########################################################################################################### diff --git a/tests/testthat/test_modelsum.R b/tests/testthat/test_modelsum.R index f9352b6..ab73e7e 100644 --- a/tests/testthat/test_modelsum.R +++ b/tests/testthat/test_modelsum.R @@ -24,7 +24,7 @@ attr(mdat$trt, "label") <- "Treatment Arm" attr(mdat$Age, "label") <- "Age in Years" ########################################################################################################### -#### Basic two-sided tableby +#### Basic modelsum call ########################################################################################################### test_that("A basic modelsum call--no labels, no missings", { @@ -110,3 +110,38 @@ test_that("A basic modelsum call--suppressing intercept and/or adjustment vars", ) ) }) + +########################################################################################################### +#### Reported bugs for modelsum +########################################################################################################### + +set.seed(3248) +dat <- data.frame(short.name = rnorm(100), really.long.name = rnorm(100), + why.would.you.name.something = rnorm(100), + as.long.as.this = rnorm(100)) + + +test_that("01/26/2017: Brendan Broderick's Bold Text Wrapping Problem", { + expect_identical( + capture.output(summary(modelsum(short.name ~ really.long.name + as.long.as.this, adjust = ~ why.would.you.name.something, data = dat))), + c("--------------------------------------------------------------------------------------------", + " estimate std.error p.value adj.r.squared ", + "-------------------- ----------------- ----------------- ----------------- -----------------", + "(Intercept) 0.035 0.099 0.721 -0.001 ", + "" , + "**really.long.name** 0.099 0.099 0.319 . ", + "" , + "**why.would.you.name -0.083 0.09 0.361 . ", + ".something** ", + "" , + "(Intercept) 0.048 0.097 0.624 0.023 ", + "" , + "**as.long.as.this** 0.198 0.106 0.066 . ", + "" , + "**why.would.you.name -0.09 0.089 0.314 . ", + ".something** ", + "" , + "--------------------------------------------------------------------------------------------" + ) + ) +}) diff --git a/tests/testthat/test_tableby.R b/tests/testthat/test_tableby.R index 6c6c682..a53d673 100644 --- a/tests/testthat/test_tableby.R +++ b/tests/testthat/test_tableby.R @@ -397,5 +397,8 @@ test_that("Changing tests", { }) +########################################################################################################### +#### Reported bugs for tableby +########################################################################################################### diff --git a/tests/testthat/test_write2.R b/tests/testthat/test_write2.R new file mode 100644 index 0000000..ca65fce --- /dev/null +++ b/tests/testthat/test_write2.R @@ -0,0 +1,92 @@ +## Tests for write2 + + +context("Testing the write2 output") + +data(mockstudy) + +expect_write2_worked <- function(FUN, object, reference, ...) +{ + FUN <- match.fun(FUN) + filename <- tempfile(fileext = ".html") + on.exit(expect_true(file.remove(filename))) + if(!file.exists(reference)) skip("Couldn't find the reference file.") + if(!file.create(filename)) skip("Couldn't create the temporary file.") + if(!grepl("/data5/bsi/adhoc/s200555.R-infrastructure/devel/eph/arsenal-eph/", getwd(), fixed = TRUE)) skip("These tests only run in Ethan's space.") + FUN(object, file = filename, ...) + generated <- readLines(filename) + expect_output_file(cat(generated, sep = "\n"), reference) +} + +########################################################################################################### +#### HTML output +########################################################################################################### + +test_that("write2.tableby -> HTML", { + expect_write2_worked(write2html, tableby(arm ~ sex + age, data=mockstudy), reference = "write2.tableby.html", quiet = TRUE, + title = "My test table", labelTranslations = list(sex = "SEX", age ="Age, yrs"), total = FALSE) +}) + +test_that("write2.modelsum -> HTML", { + expect_write2_worked(write2html, modelsum(alk.phos ~ arm + ps + hgb, adjust= ~ age + sex, family = "gaussian", data = mockstudy), + reference = "write2.modelsum.html", quiet = TRUE, + title = "My test table", show.intercept = FALSE, digits = 5) +}) + +test_that("write2.freqlist -> HTML", { + expect_write2_worked(write2html, freqlist(table(mockstudy[, c("arm", "sex", "mdquality.s")], useNA = "ifany"), groupBy = c("arm", "sex")), + reference = "write2.freqlist.html", quiet = TRUE, single = TRUE) +}) + +test_that("write2.knitr_kable -> HTML", { + if(require(knitr)) + { + expect_write2_worked(write2html, knitr::kable(head(mockstudy)), reference = "write2.kable.html", quiet = TRUE) + } else skip("library(knitr) not available.") +}) + +test_that("write2.xtable -> HTML", { + if(require(xtable)) + { + expect_write2_worked(write2html, xtable::xtable(head(mockstudy), caption = "My xtable"), reference = "write2.xtable.html", quiet = TRUE, + type = "html", comment = FALSE, include.rownames = FALSE, caption.placement = 'top') + } else skip("library(xtable) not available.") +}) + + +test_that("write2.character (pander) -> HTML", { + if(require(pander)) + { + expect_write2_worked(write2html, pander::pander_return(head(mockstudy)), reference = "write2.pander.html", quiet = TRUE) + } else skip("library(pander) not available.") +}) + +########################################################################################################### +#### Code used to generate the files +########################################################################################################### +# +# write2html(tableby(arm ~ sex + age, data=mockstudy), "/data5/bsi/adhoc/s200555.R-infrastructure/devel/eph/arsenal-eph/tests/testthat/write2.tableby.html", +# title = "My test table", labelTranslations = list(sex = "SEX", age ="Age, yrs"), total = FALSE) +# +# write2html(modelsum(alk.phos ~ arm + ps + hgb, adjust= ~ age + sex, family = "gaussian", data = mockstudy), +# "/data5/bsi/adhoc/s200555.R-infrastructure/devel/eph/arsenal-eph/tests/testthat/write2.modelsum.html", +# title = "My test table", show.intercept = FALSE, digits = 5) +# +# write2html(freqlist(table(mockstudy[, c("arm", "sex", "mdquality.s")], useNA = "ifany"), groupBy = c("arm", "sex")), +# "/data5/bsi/adhoc/s200555.R-infrastructure/devel/eph/arsenal-eph/tests/testthat/write2.freqlist.html", single = TRUE) +# +# write2html(knitr::kable(head(mockstudy)), +# "/data5/bsi/adhoc/s200555.R-infrastructure/devel/eph/arsenal-eph/tests/testthat/write2.kable.html") +# +# write2html(xtable::xtable(head(mockstudy), caption = "My xtable"), +# "/data5/bsi/adhoc/s200555.R-infrastructure/devel/eph/arsenal-eph/tests/testthat/write2.xtable.html", +# type = "html", comment = FALSE, include.rownames = FALSE, caption.placement = "top") +# +# write2html(pander::pander_return(head(mockstudy)), +# "/data5/bsi/adhoc/s200555.R-infrastructure/devel/eph/arsenal-eph/tests/testthat/write2.pander.html") + +########################################################################################################### +#### Reported bugs for write2 +########################################################################################################### + + diff --git a/tests/testthat/write2.freqlist.html b/tests/testthat/write2.freqlist.html new file mode 100644 index 0000000..dca7c90 --- /dev/null +++ b/tests/testthat/write2.freqlist.html @@ -0,0 +1,326 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    armsexmdquality.sFreqcumFreqfreqPercentcumPercent
    A: IFLMale0292910.4710.47
    121424377.2687.73
    NA3427712.27100.00
    Female012127.957.95
    111813078.1586.09
    NA2115113.91100.00
    F: FOLFOXMale031317.547.54
    128531669.3476.89
    NA9541123.11100.00
    Female021217.507.50
    119821970.7178.21
    NA6128021.79100.00
    G: IROXMale017177.467.46
    118720482.0289.47
    NA2422810.53100.00
    Female014149.219.21
    112113579.6188.82
    NA1715211.18100.00
    + + + + +
    + + + + + + + + diff --git a/tests/testthat/write2.kable.html b/tests/testthat/write2.kable.html new file mode 100644 index 0000000..9b20e4e --- /dev/null +++ b/tests/testthat/write2.kable.html @@ -0,0 +1,274 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    caseagearmsexracefu.timefu.statpshgbbmialk.phosastmdquality.sage.ord
    111075467F: FOLFOXMaleCaucasian9222011.525.0986116035NA60-69
    29970674A: IFLFemaleCaucasian2702110.719.4978629052170-79
    410527150A: IFLFemaleCaucasian1752111.1NA700100140-49
    510500171G: IROXFemaleCaucasian1282112.629.4292277168170-79
    711226369F: FOLFOXFemaleNA2332013.026.3535235035NA60-69
    88620556G: IROXMaleCaucasian1202010.219.0367356927150-59
    + + + + +
    + + + + + + + + diff --git a/tests/testthat/write2.modelsum.html b/tests/testthat/write2.modelsum.html new file mode 100644 index 0000000..90a931d --- /dev/null +++ b/tests/testthat/write2.modelsum.html @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + +++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    My test table
    estimatestd.errorp.valueadj.r.squared
    Treatment Arm F: FOLFOX-13.78.72960.117-7e-04
    Treatment Arm G: IROX-2.2459.860.820.
    sex Female3.0167.5210.688.
    Age in Years-0.017410.318780.956.
    ps46.7215.987<0.0010.04501
    sex Female1.16937.3430.874.
    Age in Years-0.08420.311080.787.
    hgb-13.842.137<0.0010.03078
    sex Female-5.987.51620.426.
    Age in Years0.094550.314030.763.
    + + + + +
    + + + + + + + + diff --git a/tests/testthat/write2.pander.html b/tests/testthat/write2.pander.html new file mode 100644 index 0000000..ab1acf5 --- /dev/null +++ b/tests/testthat/write2.pander.html @@ -0,0 +1,322 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + ++++++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Table continues below
     caseagearmsexracefu.timefu.statpshgb
    111075467F: FOLFOXMaleCaucasian9222011.5
    29970674A: IFLFemaleCaucasian2702110.7
    410527150A: IFLFemaleCaucasian1752111.1
    510500171G: IROXFemaleCaucasian1282112.6
    711226369F: FOLFOXFemaleNA2332013
    88620556G: IROXMaleCaucasian1202010.2
    + ++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     bmialk.phosastmdquality.sage.ord
    125.116035NA60-69
    219.529052170-79
    4NA700100140-49
    529.4377168170-79
    726.3535035NA60-69
    819.0456927150-59
    + + + + +
    + + + + + + + + diff --git a/tests/testthat/write2.tableby.html b/tests/testthat/write2.tableby.html new file mode 100644 index 0000000..51972b4 --- /dev/null +++ b/tests/testthat/write2.tableby.html @@ -0,0 +1,219 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + +++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    My test table
    A: IFL (N=428)F: FOLFOX (N=691)G: IROX (N=380)p value
    SEX0.190
        Male277 (64.7%)411 (59.5%)228 (60%)
        Female151 (35.3%)280 (40.5%)152 (40%)
    Age, yrs0.614
        Mean (SD)59.7 (11.4)60.3 (11.6)59.8 (11.5)
        Q1, Q353, 6852, 6952, 68
        Range27 - 8819 - 8826 - 85
    + + + + +
    + + + + + + + + diff --git a/tests/testthat/write2.xtable.html b/tests/testthat/write2.xtable.html new file mode 100644 index 0000000..8c7b931 --- /dev/null +++ b/tests/testthat/write2.xtable.html @@ -0,0 +1,458 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +My xtable +
    +case + +age + +arm + +sex + +race + +fu.time + +fu.stat + +ps + +hgb + +bmi + +alk.phos + +ast + +mdquality.s + +age.ord +
    +110754 + +67 + +F: FOLFOX + +Male + +Caucasian + +922 + +2 + +0 + +11.50 + +25.10 + +160 + +35 + + +60-69 +
    +99706 + +74 + +A: IFL + +Female + +Caucasian + +270 + +2 + +1 + +10.70 + +19.50 + +290 + +52 + +1 + +70-79 +
    +105271 + +50 + +A: IFL + +Female + +Caucasian + +175 + +2 + +1 + +11.10 + + +700 + +100 + +1 + +40-49 +
    +105001 + +71 + +G: IROX + +Female + +Caucasian + +128 + +2 + +1 + +12.60 + +29.43 + +771 + +68 + +1 + +70-79 +
    +112263 + +69 + +F: FOLFOX + +Female + + +233 + +2 + +0 + +13.00 + +26.35 + +350 + +35 + + +60-69 +
    +86205 + +56 + +G: IROX + +Male + +Caucasian + +120 + +2 + +0 + +10.20 + +19.04 + +569 + +27 + +1 + +50-59 +
    + + + + +
    + + + + + + + + diff --git a/vignettes/freqlist.Rmd b/vignettes/freqlist.Rmd index 74111f0..61b9e75 100644 --- a/vignettes/freqlist.Rmd +++ b/vignettes/freqlist.Rmd @@ -3,12 +3,9 @@ title: "The freqlist function" author: "Tina Gunderson" date: '`r format(Sys.time(),"%d %B, %Y")`' output: - pdf_document: + rmarkdown::html_vignette: toc: yes toc_depth: 3 - html_document: - toc: yes - toc_depth: '3' header-includes: \usepackage{tabularx} vignette: | %\VignetteIndexEntry{The freqlist function} @@ -19,11 +16,6 @@ vignette: | ```{r setup, include=FALSE} knitr::opts_chunk$set(echo = TRUE, tidy.opts=list(width.cutoff=80), tidy=TRUE, comment=NA) options(width=80, max.print=1000) - -require(arsenal) -# source("/data5/bsi/adhoc/s200555.R-infrastructure/devel/eph/arsenal-eph/R/freqlist.R") -# source("/data5/bsi/adhoc/s200555.R-infrastructure/devel/eph/arsenal-eph/R/summary.freqlist.R") -# source("/data5/bsi/adhoc/s200555.R-infrastructure/devel/eph/arsenal-eph/R/freqlist.internal.R") ``` \newpage @@ -34,6 +26,10 @@ require(arsenal) `freqlist` provides options for handling missing or sparse data and can provide cumulative counts and percentages based on subgroups. It depends on the `knitr` package for printing. +```{r message = FALSE} +require(arsenal) +``` + ## Sample dataset For our examples, we'll load the `mockstudy` data included with this package and use it to create a basic table. @@ -41,7 +37,7 @@ Because they have fewer levels, for brevity, we'll use the variables arm, sex, a We'll retain NAs in the table creation. See the appendix for notes regarding default NA handling and other useful information regarding tables in R. -```{r loading and setting up data} +```{r loading.data} # load the data data(mockstudy) @@ -68,7 +64,7 @@ noby <- freqlist(tab.ex) str(noby) # view the data frame portion of freqlist output -noby[["freqlist"]] +noby[["freqlist"]] ## or use as.data.frame(noby) ``` \newpage @@ -91,7 +87,11 @@ summary(noby, caption="Basic freqlist output") ``` You can also easily pull out the `freqlist` data frame for more complicated formatting or manipulation -(e.g. with another function such as `xtable` or `pander`). See below. +(e.g. with another function such as `xtable` or `pander`) using `as.data.frame`: + +```{r} +head(as.data.frame(noby)) +``` \newpage @@ -138,9 +138,11 @@ summary(freqlist(tab.ex, na.options="remove")) ## Frequency counts and percentages subset by factor levels -The groupBy argument internally subsets the data by the specified factor prior to calculating cumulative counts and percentages. By default, when used each subset will print in a separate table. Using the `single = TRUE` option when printing will collapse the subsetted result into a single table. +The groupBy argument internally subsets the data by the specified factor prior to calculating cumulative counts and percentages. +By default, when used each subset will print in a separate table. Using the `single = TRUE` option when printing will collapse +the subsetted result into a single table. -```{r frequency counts, results='asis'} +```{r freq.counts, results='asis'} withby <- freqlist(tab.ex, groupBy = c("arm","sex")) summary(withby) @@ -168,14 +170,12 @@ summary(noby, labelTranslations = c("Hi there", "What up", "Bye")) Fair warning: `xtable` has kind of a steep learning curve. These examples are given without explanation for more advanced users. -```{r xtable setup} +```{r xtable.setup} require(xtable) -#turn off xtable header -options(xtable.comment = FALSE) -#set up custom function for xtable text +# set up custom function for xtable text italic <- function(x){ -paste0('{\\emph{ ', x, '}}') +paste0('', x, '') } ``` @@ -187,7 +187,7 @@ xftbl <- xtable(noby[["freqlist"]], # change the column names names(xftbl)[1:3] <- c("Arm", "Gender", "LASA QOL") -print(xftbl, sanitize.colnames.function = italic, include.rownames = FALSE) +print(xftbl, sanitize.colnames.function = italic, include.rownames = FALSE, type = "html", comment = FALSE) ``` \newpage diff --git a/vignettes/modelsum.Rmd b/vignettes/modelsum.Rmd index 03dc754..97a23b6 100644 --- a/vignettes/modelsum.Rmd +++ b/vignettes/modelsum.Rmd @@ -3,15 +3,9 @@ title: "The modelsum function" author: "Beth Atkinson, Pat Votruba, Jason Sinnwell, Shannon McDonnell and Greg Dougherty" date: '`r format(Sys.time(),"%d %B, %Y")`' output: - html_document: - toc: yes - toc_depth: '3' - pdf_document: + rmarkdown::html_vignette: toc: yes toc_depth: 3 - word_document: - toc: yes - toc_depth: '3' vignette: | %\VignetteIndexEntry{The modelsum function} %\VignetteEncoding{UTF-8} @@ -26,17 +20,12 @@ require(MASS) require(pROC) require(rpart) -opts_chunk$set(comment = NA, echo=TRUE, prompt=TRUE ,collapse=TRUE) +opts_chunk$set(comment = NA, echo=TRUE, prompt=TRUE, collapse=TRUE) -#vignette: > -# %\VignetteIndexEntry{modelsum} -# %\VignetteEngine{knitr::rmarkdown} -# \usepackage[utf8]{inputenc} ``` -Introduction -============= +# Introduction Very often we are asked to summarize model results from multiple fits into a nice table. The endpoint might be of different types (e.g., survival, case/control, continuous) and there @@ -54,10 +43,9 @@ so the tables could be displayed within an R markdown report. This report provides step-by-step directions for using the functions associated with `modelsum`. All functions presented here are available within the `arsenal` package. An assumption is made that users are somewhat familiar with R markdown documents. For those who are new to the topic, a good initial -resource is available at [rmarkdown.rstudio.com](rmarkdown.rstudio.com). +resource is available at [rmarkdown.rstudio.com](http://rmarkdown.rstudio.com). -Simple Example -================ +# Simple Example The first step when using the `modelsum` function is to load the `arsenal` package. All the examples in this report use a dataset called `mockstudy` made available by Paul Novotny which includes a variety of types of variables @@ -82,7 +70,7 @@ If you want to take a quick look at the table, you can use `summary` on your mod print out as text in your R console window. If you use `summary` without any options you will see a number of $\ $ statements which translates to "space" in HTML. -### Pretty text version of table +## Pretty text version of table If you want a nicer version in your console window then adding the `text=TRUE` option. @@ -90,23 +78,25 @@ If you want a nicer version in your console window then adding the `text=TRUE` o summary(tab1, text=TRUE) ``` -### Pretty Rmarkdown version of table +## Pretty Rmarkdown version of table In order for the report to look nice within an R markdown (knitr) report, you just need to specify `results="asis"` when creating the r chunk. This changes the layout slightly (compresses it) and bolds -the variable names. The three single quotes are often located above the tab key. - -`r ''` ```{r results="asis"} - - summary(tab1) - -``` +the variable names. ```{r simple-markdown, results='asis'} summary(tab1) ``` -### Add an adjustor to the model +## Data frame version of table + +If you want a data.frame version, simply use `as.data.frame`. + +```{r} +as.data.frame(tab1) +``` + +## Add an adjustor to the model The argument `adjust` allows the user to indicate that all the variables should be adjusted for these terms. @@ -116,16 +106,14 @@ summary(tab2) ``` -Models for each endpoint type -================================== +# Models for each endpoint type To make sure the correct model is run you need to specify "family". The options available right now are : gaussian, binomial, survival, and poisson. If there is enough interest, additional models can be added. -Gaussian ------------ +## Gaussian -### fit and summarize linear regression model +### Fit and summarize linear regression model Look at whether there is any evidence that AlkPhos values vary by study arm after adjusting for sex and age (assuming a linear age relationship). @@ -163,7 +151,7 @@ termplot(fit3, term=2, se=T, rug=T) In this instance it looks like there isn't enough evidence to say that the relationship is non-linear. -### extract data using the `broom` package +### Extract data using the `broom` package The `broom` package makes it easy to extract information from the fit. @@ -175,7 +163,7 @@ tmp glance(fit3) ``` -### create a summary table using modelsum +### Create a summary table using modelsum ```{r, results="asis"} ms.logy <- modelsum(log(alk.phos) ~ arm + ps + hgb, data=mockstudy, adjust= ~age + sex, @@ -184,10 +172,9 @@ ms.logy <- modelsum(log(alk.phos) ~ arm + ps + hgb, data=mockstudy, adjust= ~age summary(ms.logy) ``` -Binomial ----------- +## Binomial -### fit and summarize logistic regression model +### Fit and summarize logistic regression model ```{r} boxplot(age ~ mdquality.s, data=mockstudy, ylab=attr(mockstudy$age,'label'), xlab='mdquality.s') @@ -216,7 +203,7 @@ tmp$auc ``` -### extract data using `broom` package +### Extract data using `broom` package The `broom` package makes it easy to extract information from the fit. @@ -226,7 +213,7 @@ tidy(fit, exp=T, conf.int=T) # coefficients, p-values, conf.intervals glance(fit) # model summary statistics ``` -### create a summary table using modelsum +### Create a summary table using modelsum ```{r, results="asis"} summary(modelsum(mdquality.s ~ age + bmi, data=mockstudy, adjust=~sex, family=binomial)) @@ -237,10 +224,9 @@ summary(fitall) ``` -Survival ---------- +## Survival -### fit and summarize a Cox regression model +### Fit and summarize a Cox regression model ```{r survival} require(survival) @@ -271,7 +257,7 @@ summary(fit2)$concordance survConcordance(Surv(fu.time, fu.stat) ~ predict(fit2), data=mockstudy) ``` -### extract data using `broom` package +### Extract data using `broom` package The `broom` package makes it easy to extract information from the fit. @@ -281,7 +267,7 @@ tidy(fit) # coefficients, p-values glance(fit) # model summary statistics ``` -### create a summary table using modelsum +### Create a summary table using modelsum ```{r results="asis"} ##Note: You must use quotes when specifying family="survival" @@ -295,8 +281,7 @@ summary(modelsum(Surv(fu.time, fu.stat) ~ arm, ``` -Poisson --------- +## Poisson Poisson regression is useful when predicting an outcome variable representing counts. It can also be useful when looking at survival data. Cox models and Poisson models are very closely @@ -331,7 +316,7 @@ fit2 <- glm(skips ~ Opening + Solder + Mask, data=solder, family=quasipoisson) summary(fit2) ``` -### extract data using `broom` package +### Extract data using `broom` package The `broom` package makes it easy to extract information from the fit. @@ -342,7 +327,7 @@ glance(fit) # model summary statistics ``` -### create a summary table using modelsum +### Create a summary table using modelsum ```{r results='asis'} summary(modelsum(skips~Opening + Solder + Mask, data=solder, family="quasipoisson")) @@ -373,7 +358,7 @@ fit2 <- glm(fu.stat ~ offset(log(fu.time+.01)) + age + sex + arm, summary(fit2) ``` -### extract data using `broom` package +### Extract data using `broom` package The `broom` package makes it easy to extract information from the fit. @@ -384,7 +369,7 @@ glance(fit) ##model summary statistics ``` -### create a summary table using modelsum +### Create a summary table using `modelsum` Remember that the result from `modelsum` is different from the `fit` above. The `modelsum` summary shows the results for `age + offset(log(fu.time+.01))` then `sex + offset(log(fu.time+.01))` @@ -397,12 +382,12 @@ summary(modelsum(fu.stat ~ age, adjust=~offset(log(fu.time+.01))+ sex + arm, ``` -Additional Examples -==================== +# Additional Examples + Here are multiple examples showing how to use some of the different options. -###1. Change summary statistics globally +## 1. Change summary statistics globally There are standard settings for each type of model regarding what information is summarized in the table. This behavior can be modified using the modelsum.control function. In fact, you can save your standard @@ -425,7 +410,7 @@ tab3 <- modelsum(bmi ~ age, adjust=~sex, data=mockstudy, summary(tab3) ``` -###2. Add labels to independent variables +## 2. Add labels to independent variables In the above example, age is shown with a label (Age in Years), but sex is listed "as is". This is because the data was created in SAS and in the SAS dataset, age had a label but sex did not. @@ -470,20 +455,20 @@ labels(tab1) summary(tab1) ``` -###2. Don't show intercept values +## 3. Don't show intercept values ```{r, results='asis'} summary(modelsum(age~mdquality.s+sex, data=mockstudy), show.intercept=FALSE) ``` -###3. Don't show results for adjustment variables +## 4. Don't show results for adjustment variables ```{r, results='asis'} summary(modelsum(mdquality.s ~ age + bmi, data=mockstudy, adjust=~sex, family=binomial), show.adjust=FALSE) ``` -###4. Summarize multiple variables without typing them out +## 5. Summarize multiple variables without typing them out Often one wants to summarize a number of variables. Instead of typing by hand each individual variable, an alternative approach is to create a formula using the `paste` command with the `collapse="+"` option. @@ -519,7 +504,7 @@ summary(modelsum(tmp, data=mockstudy, family=binomial)) ``` -###5. Subset the dataset used in the analysis +## 6. Subset the dataset used in the analysis Here are two ways to get the same result (limit the analysis to subjects age>50 and in the F: FOLFOX treatment group). @@ -548,7 +533,7 @@ summary(modelsum(alk.phos ~ ps + bmi, adjust=~sex, subset = age>50 & bmi<24, dat summary(modelsum(alk.phos ~ ps + bmi, adjust=~sex, subset=1:30, data=mockstudy)) ``` -###6. Create combinations of variables on the fly +## 7. Create combinations of variables on the fly ```{r} ## create a variable combining the levels of mdquality.s and sex @@ -559,7 +544,7 @@ with(mockstudy, table(interaction(mdquality.s,sex))) summary(modelsum(age ~ interaction(mdquality.s,sex), data=mockstudy)) ``` -###9. Transform variables on the fly +## 8. Transform variables on the fly Certain transformations need to be surrounded by `I()` so that R knows to treat it as a variable transformation and not some special model feature. If the transformation includes any of the @@ -572,7 +557,7 @@ summary(modelsum(arm=="F: FOLFOX" ~ I(age/10) + log(bmi) + mdquality.s, ``` -###10. Change the ordering of the variables or delete a variable +## 9. Change the ordering of the variables or delete a variable ```{r, results='asis'} mytab <- modelsum(bmi ~ sex + alk.phos + age, data=mockstudy) @@ -582,7 +567,7 @@ summary(mytab[c('age','sex')]) summary(mytab[c(3,1)]) ``` -###11. Merge two modelsum objects together +## 10. Merge two `modelsum` objects together It is possible to combine two modelsum objects so that they print out together, however you need to pay attention to the columns that are being displayed. It is easier to combine two models of the same @@ -602,7 +587,7 @@ class(tab12) #summary(tab12) ``` -###12. Add a title to the table +## 11. Add a title to the table When creating a pdf the tables are automatically numbered and the title appears below the table. In Word and HTML, the titles appear un-numbered and above the table. @@ -612,11 +597,12 @@ t1 <- modelsum(bmi ~ sex + age, data=mockstudy) summary(t1, title='Demographics') ``` -###13. Modify how missing values are treated +## 12. Modify how missing values are treated Depending on the report you are writing you have the following options: * Use all values available for each variable + * Use only those subjects who have measurements available for all the variables ```{r} @@ -642,13 +628,16 @@ summary(modelsum(bmi ~ ast + age, data=mockstudy, control=modelsum.control(gaussian.stats=c("estimate")))) ``` -###14. Modify the number of digits used +## 13. Modify the number of digits used Within modelsum.control function there are 4 options for controlling the number of significant digits shown. * digits: controls the number of significant digits (counting both before and after the decimal point) for continuous variables + * nsmall: controls the number of digits after the decimal point for the beta and standard error + * nsmall.ratio: controls the number of digits for the ratio statistics (OR, HR, RR), default=2 + * digits.test: controls the number of digits after the decimal point for p-values (default=3) ```{r, results='asis'} @@ -670,7 +659,7 @@ format(pi*100, nsmall=4) format(pi*100, nsmall=2, digits=4) ``` -###15. Use case-weights in the models +## 14. Use case-weights in the models Occasionally it is of interest to fit models using case weights. The `modelsum` function allows you to pass on the weights to the models and it will do the appropriate fit. @@ -692,18 +681,20 @@ mockstudy$wts <- gpwts[index] tapply(mockstudy$wts,mockstudy$arm, summary) ``` -```{r results='asis', warning=FALSE} +```{r results='asis'} mockstudy$newvarA <- as.numeric(mockstudy$arm=='A: IFL') tab1 <- modelsum(newvarA ~ ast + bmi + hgb, data=mockstudy, subset=(arm !='G: IROX'), family=binomial) summary(tab1, title='No Case Weights used') +suppressWarnings({ tab2 <- modelsum(newvarA ~ ast + bmi + hgb, data=mockstudy, subset=(arm !='G: IROX'), weights=wts, family=binomial) summary(tab2, title='Case Weights used') +}) ``` -###16. Use `modelsum` within an Sweave document +## 15. Use `modelsum` within an Sweave document For those users who wish to create tables within an Sweave document, the following code seems to work. @@ -737,7 +728,7 @@ render("Test.md", pdf_document(keep_tex=TRUE)) \end{document} ``` -###17. Export `modelsum` results to a .CSV file +## 16. Export `modelsum` results to a .CSV file When looking at multiple variables it is sometimes useful to export the results to a csv file. The `as.data.frame` function creates a data frame object that can be exported or further manipulated within R. @@ -750,7 +741,7 @@ tmp # write.csv(tmp, '/my/path/here/mymodel.csv') ``` -###18. Write `modelsum` object to a separate Word or HTML file +## 17. Write `modelsum` object to a separate Word or HTML file ```{r} ## write to an HTML document @@ -760,10 +751,9 @@ tmp # write2word(tab2, "~/ibm/trash.doc", title="My table in Word") ``` -Available Function Options -================================== +# Available Function Options -### Summary statistics +## Summary statistics The available summary statistics, by varible type, are: @@ -827,7 +817,7 @@ The full description of these parameters that can be shown for models include: * `CI.lower.estimate, CI.upper.estimate`: print the confidence interval for the beta coefficient -### modelsum.control settings +## `modelsum.control` settings A quick way to see what arguments are possible to utilize in a function is to use the `args()` command. Settings involving the number of digits can be set in `modelsum.control` or in `summary.modelsum`. @@ -851,7 +841,7 @@ Settings: * poisson.stats, quasipoisson.stats -### summary.modelsum settings +## `summary.modelsum` settings The summary.modelsum function has options that modify how the table appears (such as adding a title or modifying labels). diff --git a/vignettes/tableby.Rmd b/vignettes/tableby.Rmd index 3e7d5a8..8628504 100755 --- a/vignettes/tableby.Rmd +++ b/vignettes/tableby.Rmd @@ -3,11 +3,8 @@ title: "The tableby function" author: "Beth Atkinson, Jason Sinnwell, Shannon McDonnell and Greg Dougherty" date: '`r format(Sys.time(),"%d %B, %Y")`' output: - html_document: + rmarkdown::html_vignette: toc: yes - toc_depth: '3' - pdf_document: - toc: true toc_depth: 3 vignette: | %\VignetteIndexEntry{The tableby function} @@ -15,8 +12,11 @@ vignette: | %\VignetteEngine{knitr::rmarkdown} --- -Introduction -============= +```{r echo = FALSE} +options(width = 100) +``` + +# Introduction One of the most common tables in medical literature includes summary statistics for a set of variables, often stratified by some group (e.g. treatment arm). Locally, the SAS macros `%table` and `%summary` were @@ -32,10 +32,9 @@ so the tables could be displayed within an R markdown report. This report provides step-by-step directions for using the functions associated with `tableby`. All functions presented here are available within the `arsenal` package. An assumption is made that users are somewhat familiar with R markdown documents. For those who are new to the topic, a good initial resource -is available at [rmarkdown.rstudio.com](rmarkdown.rstudio.com). +is available at [rmarkdown.rstudio.com](http://rmarkdown.rstudio.com). -Simple Example -================ +# Simple Example The first step when using the `tableby` function is to load the `arsenal` package. All the examples in this report use a dataset called `mockstudy` made available by Paul Novotny which includes a variety of types of variables (character, @@ -62,7 +61,7 @@ If you want to take a quick look at the table, you can use `summary` on your tab will print out as text in your R console window. If you use `summary` without any options you will see a number of $\ $ statements which translates to "space" in HTML. -### Pretty text version of table +## Pretty text version of table If you want a nicer version in your console window then adding the `text=TRUE` option. @@ -70,22 +69,24 @@ If you want a nicer version in your console window then adding the `text=TRUE` o summary(tab1, text=TRUE) ``` -### Pretty Rmarkdown version of table +## Pretty Rmarkdown version of table In order for the report to look nice within an R markdown (knitr) report, you just need to specify `results="asis"` when creating the r chunk. This changes the layout slightly (compresses it) and bolds the variable names. -`r ''` ```{r, results="asis"} - - summary(tab1) - -``` - ```{r, simple-markdown, results='asis'} summary(tab1) ``` -### Summaries using standard R code +## Data frame version of table + +If you want a data.frame version, simply use `as.data.frame`. + +```{r} +as.data.frame(tab1) +``` + +## Summaries using standard R code ```{r} ## base R frequency example @@ -106,10 +107,9 @@ summary(aov(age ~ arm, data=mockstudy)) ``` -Modifying Output -================ +# Modifying Output -### Add labels +## Add labels In the above example, age is shown with a label (Age in Years), but sex is listed "as is" with lower case letters. This is because the data was created in SAS and in the SAS dataset, age had a label but sex did not. The label is stored as an attribute within R. @@ -150,7 +150,7 @@ labels(tab1) summary(tab1) ``` -### Change summary statistics globally +## Change summary statistics globally Currently the default behavior is to summarize continuous variables with: Number of missing values, Mean (SD), 25th - 75th quantiles, and Minimum-Maximum values with an ANOVA (t-test with equal variances) p-value. @@ -165,7 +165,7 @@ mycontrols <- tableby.control(test=FALSE, total=FALSE, numeric.test="kwt", cat.test="chisq", numeric.stats=c("N", "median", "q1q3"), cat.stats=c("countpct"), - stats.labels=list(N='Count', median='Median', q1q3='Q1,Q3')) + stats.labels=list(N='Count', median='Median', q1q3='Q1,Q3')) tab2 <- tableby(arm ~ sex + age, data=mockstudy, control=mycontrols) summary(tab2) ``` @@ -179,7 +179,7 @@ summary(tab3) ``` -### Change summary statistics within the formula +## Change summary statistics within the formula In addition to modifying summary options globally, it is possible to modify the test and summary statistics for specific variables within the formula statement. For example, both the kwt (Kruskal-Wallis rank-based) and anova @@ -207,7 +207,7 @@ tab.test <- tableby(arm ~ kwt(ast, "Nmiss2","median") + anova(age, "N","mean") + summary(tab.test) ``` -### Modifying the look & feel in Word documents +## Modifying the look & feel in Word documents You can easily create Word versions of `tableby` output via an Rmarkdown report and the default options will give you a reasonable table in Word - just select the "Knit Word" option in RStudio. @@ -224,25 +224,24 @@ output: word_document For more informating on changing the look/feel of your Word document, see the [Rmarkdown documentation](http://rmarkdown.rstudio.com/word_document_format.html) website. -Additional Examples -============================ +# Additional Examples Here are multiple examples showing how to use some of the different options. -###1. Summarize without a group/by variable +## 1. Summarize without a group/by variable ```{r, nobyvar, results='asis'} tab.noby <- tableby(~ bmi + sex + age, data=mockstudy) summary(tab.noby) ``` -###2. Display footnotes indicating which "test" was used +## 2. Display footnotes indicating which "test" was used ```{r, results="asis"} summary(tab.test) #, pfootnote=TRUE) ``` -###3. Summarize an ordered factor +## 3. Summarize an ordered factor When comparing groups of ordered data there are a couple of options. The **default** uses a general independence test available from the `coin` package. For two-group comparisons, this is essentially the Armitage trend test. The other option is to specify the Kruskal Wallis test. @@ -260,7 +259,7 @@ summary(tableby(sex ~ age.ordnew, data = mockstudy)) #, pfootnote = TRUE) summary(tableby(sex ~ kwt(age.ord), data = mockstudy)) #) #, pfootnote = TRUE) ``` -###4. Summarize a survival variable +## 4. Summarize a survival variable First look at the information that is presented by the `survfit` function, then see how the same results can be seen with tableby. The default is to show the median survival (time at which the probability of survival = 50%). @@ -284,7 +283,7 @@ summary(survfit(Surv(fu.time/365.25, fu.stat)~sex, data=mockstudy), times=1:5) summary(tableby(sex ~ Surv(fu.time/365.25, fu.stat), data=mockstudy, times=1:5, surv.stats=c("NeventsSurv","NriskSurv"))) ``` -###5. Summarize date variables +## 5. Summarize date variables Date variables by default are summarized with the number of missing values, the median, and the range. For example purposes we've created a random date. Missing values are introduced for impossible February dates. @@ -297,7 +296,7 @@ mockstudy$dtentry <- mdy.Date(month=sample(1:12,N,replace=T), day=sample(1:29,N, summary(tableby(sex ~ dtentry, data=mockstudy)) ``` -###6. Summarize multiple variables without typing them out +## 6. Summarize multiple variables without typing them out Often one wants to summarize a number of variables. Instead of typing by hand each individual variable, an alternative approach is to create a formula using the `paste` command with the `collapse="+"` option. @@ -332,7 +331,7 @@ tmp2 <- formulize('arm',c('ps','hgb^2','bmi')) summary(tableby(tmp, data=mockstudy)) ``` -###7. Subset the dataset used in the analysis +## 7. Subset the dataset used in the analysis Here are two ways to get the same result (limit the analysis to subjects age>5 and in the F: FOLFOX treatment group). @@ -359,7 +358,7 @@ argument within `tableby` to subset the data. summary(tableby(sex ~ ps + hgb + bmi, subset=age>50 & arm=="F: FOLFOX", data=mockstudy)) ``` -###8. Create combinations of variables on the fly +## 8. Create combinations of variables on the fly ```{r} ## create a variable combining the levels of mdquality.s and sex @@ -375,7 +374,7 @@ summary(tableby(arm ~ interaction(mdquality.s,sex), data=mockstudy)) summary(tableby(interaction(mdquality.s, sex) ~ age + bmi, data=mockstudy, subset=arm=="F: FOLFOX")) ``` -###9. Transform variables on the fly +## 9. Transform variables on the fly Certain transformations need to be surrounded by `I()` so that R knows to treat it as a variable transformation and not some special model feature. If the transformation includes any of the symbols `/ - + ^ *` then surround the new variable by `I()`. @@ -416,7 +415,7 @@ summary(tableby(arm ~ chisq(mdquality.s, "Nmiss","countpct"), data=mockstudy)) ``` -###10. Change the ordering of the variables or delete a variable +## 10. Change the ordering of the variables or delete a variable ```{r, results='asis'} mytab <- tableby(arm ~ sex + alk.phos + age, data=mockstudy) @@ -427,7 +426,7 @@ summary(mytab[c(3,1)], nsmall = 3) ``` -###11. Merge two tableby objects together +## 11. Merge two `tableby` objects together It is possible to combine two tableby objects so that they print out together. @@ -447,7 +446,7 @@ names(tab12$x) summary(tab12) #, pfootnote=TRUE) ``` -###12. Add a title to the table +## 12. Add a title to the table When creating a pdf the tables are automatically numbered and the title appears below the table. In Word and HTML, the titles appear un-numbered and above the table. @@ -456,12 +455,16 @@ t1 <- tableby(arm ~ sex + age, data=mockstudy) summary(t1, title='Demographics') ``` -###13. Modify how missing values are displayed +## 13. Modify how missing values are displayed Depending on the report you are writing you have the following options: + * Show how many subjects have each variable + * Show how many subjects are missing each variable + * Show how many subjects are missing each variable only if there are any missing values + * Don't indicate missing values at all ```{r} @@ -487,13 +490,16 @@ summary(tableby(sex ~ ast + age, data=mockstudy, control=tableby.control(numeric.stats=c("mean"),total=FALSE))) ``` -###14. Modify the number of digits used +## 14. Modify the number of digits used Within tableby.control function there are 4 options for controlling the number of significant digits shown. * digits: controls the number of significant digits (counting both before and after the decimal point) for continuous variables + * nsmall: controls the number of digits after the decimal point for continous variables + * nsmall.pct: controls the number of digits after the decimal point for percentages + * digits.test: controls the number of digits after the decimal point for p-values (default=3) ```{r, results='asis'} @@ -515,9 +521,12 @@ format(pi*100, nsmall=4) format(pi*100, nsmall=2, digits=4) ``` -###15. Create a user-defined summary statistic +## 15. Create a user-defined summary statistic -For purposes of this example, the code below creates a trimmed mean function (trims 10%) and use that to summarize the data. Note the use of the `...` which tells R to pass extra arguments on - this is required for user-defined functions. In this case, `na.rm=T` is passed to `myfunc`. The *weights* argument is also required, even though it isn't passed on to the internal function in this particular example. +For purposes of this example, the code below creates a trimmed mean function (trims 10%) +and use that to summarize the data. Note the use of the `...` which tells R to pass extra arguments on - this is required +for user-defined functions. In this case, `na.rm=T` is passed to `myfunc`. The *weights* argument is also required, even though +it isn't passed on to the internal function in this particular example. ```{r, results='asis'} myfunc <- function(x, weights=rep(1,length(x)), ...){ @@ -530,7 +539,7 @@ summary(tableby(sex ~ hgb, data=mockstudy, ``` -###16. Use case-weights for creating summary statistics +## 16. Use case-weights for creating summary statistics When comparing groups, they are often unbalanced when it comes to nuisances such as age and sex. The `tableby` function allows you to create weighted summary statistics. If this option us used then p-values are not calculated (`test=FALSE`). @@ -566,7 +575,7 @@ summary(tab1, title='Case Weights used') ``` -###17. Create your own p-value and add it to the table +## 17. Create your own p-value and add it to the table When using weighted summary statistics, it is often desirable to then show a p-value from a model that corresponds to the weighted analysis. It is possible to add your own p-value and modify the column title for that new p-value. Another use for this would be to add standardized @@ -586,7 +595,7 @@ tab2 <- modpval.tableby(tab1, mypval, use.pname=TRUE) summary(tab2, title='Case Weights used, p-values added') #, pfootnote=TRUE) ``` -###18. For two-level categorical variables, only display one level. +## 18. For two-level categorical variables, only display one level. If the `cat.simplify` option is set to TRUE then only the second level of the group. In the example below sex has the levels and "Female" is the second level, hence only the %female is shown in the table. Similarly, "mdquality.s" @@ -598,7 +607,7 @@ table2 <- tableby(arm~sex + factor(mdquality.s), data=mockstudy, cat.simplify=TR summary(table2, labelTranslations=c(sex="Female", "factor(mdquality.s)"="MD Quality")) ``` -###19. Use `tableby` within an Sweave document +## 19. Use `tableby` within an Sweave document For those users who wish to create tables within an Sweave document, the following code seems to work. @@ -633,7 +642,7 @@ render("Test.md", pdf_document(keep_tex=TRUE)) \end{document} ``` -###20. Export `tableby` object to a .CSV file +## 20. Export `tableby` object to a .CSV file When looking at multiple variables it is sometimes useful to export the results to a csv file. The `as.data.frame` function creates a data frame object that can be exported or further manipulated within R. @@ -647,22 +656,21 @@ tmp # write.csv(tmp, '/my/path/here/mymodel.csv') ``` -###21. Write `tableby` object to a separate Word or HTML file +## 21. Write `tableby` object to a separate Word or HTML file -```{r} +```{r eval = FALSE} ## write to an HTML document tab1 <- tableby(arm ~ sex + age, data=mockstudy) -# write2html(tab1, "~/ibm/trash.html") +write2html(tab1, "~/trash.html") ## write to a Word document -# write2word(tab1, "~/ibm/trash.doc", title="My table in Word") +write2word(tab1, "~/trash.doc", title="My table in Word") ``` -Available Function Options -================================== +# Available Function Options -### Summary statistics +## Summary statistics The **default** summary statistics, by varible type, are: @@ -687,7 +695,7 @@ however there are a number of extra functions defined specifically for the table * `Nevents`: print number of events for a survival object within each grouping level * `medsurv`: print the median survival -### Testing options +## Testing options The tests used to calculate p-values differ by the variable type, but can be specified explicitly in the formula statement or in the control function. @@ -712,7 +720,7 @@ The following tests are accepted: * `trend`: The `independence_test` function from the `coin` is used to test for trends. Whenthe grouping variable has two levels, it is equivalent to the Armitage trend test. This is the default for ordered factors -### tableby.control settings +## `tableby.control` settings A quick way to see what arguments are possible to utilize in a function is to use the `args()` command. Settings involving the number of digits can be set in `tableby.control` or in `summary.tableby`. @@ -736,9 +744,9 @@ Settings: * ordered.test, ordered.stats * surv.test, surv.stats -### summary.tableby settings +## `summary.tableby` settings -The summary.tableby function has options that modify how the table appears (such as adding a title or modifying labels). +The `summary.tableby` function has options that modify how the table appears (such as adding a title or modifying labels). ```{r} args(arsenal:::summary.tableby) diff --git a/vignettes/write2.Rmd b/vignettes/write2.Rmd new file mode 100644 index 0000000..d652713 --- /dev/null +++ b/vignettes/write2.Rmd @@ -0,0 +1,177 @@ +--- +title: "The write2 function" +author: "Ethan Heinzen" +date: '`r format(Sys.time(),"%d %B, %Y")`' +output: + rmarkdown::html_vignette: + toc: yes + toc_depth: 3 +vignette: | + %\VignetteIndexEntry{The write2 function} + %\VignetteEncoding{UTF-8} + %\VignetteEngine{knitr::rmarkdown} +--- + +```{r include = FALSE} +knitr::opts_chunk$set(eval = FALSE) +``` + +# Introduction + +The `write2*()` functions were designed as an alternative to SAS's `ODS` procedure for useRs who want to save R Markdown tables +to separate Word, HTML, or PDF files without needing separate R Markdown programs. + +There are three shortcut functions for the most common output types: HTML, PDF, and Word. Each of these three functions calls +`write2()`, an S3 function which accepts many file output types (see the help pages for `rmarkdown::render()`). Methods have been implemented for +`tableby()`, `modelsum()`, and `freqlist()`, but also `knitr::kable()`, `xtable::xtable()`, and `pander::pander_return()`. + +The two most important things to recognize with `write2()` are the following: + +1. Which function is being used to output the object. Sometimes the `write2` functions use `summary()`, while other times they will use `print()`. + The details for each object specifically are described below. + +2. How the `...` arguments are passed. To change the options for the summary-like or print-like function, you can pass named arguments which will + in turn get passed to the appropriate function. Details for each object specifically are described below. + +# Examples Using `arsenal` Objects + +```{r} +library(arsenal) +data(mockstudy) +tmpdir <- tempdir() +``` + +## `tableby` + +For `tableby` objects, the output function in `write2()` is `summary()`. For available arguments, see the help pages for `summary.tableby()`. +Don't use the option `text = TRUE` with the `write2` functions. + +```{r} +mylabels <- list(sex = "SEX", age ="Age, yrs") +tab1 <- tableby(arm ~ sex + age, data=mockstudy) + +write2html(tab1, paste0(tmpdir, "/test.tableby.html"), quiet = TRUE, + title = "My test table", # passed to summary.tableby + labelTranslations = mylabels, # passed to summary.tableby + total = FALSE # passed to summary.tableby + ) +``` + +## `modelsum` + +For `modelsum` objects, the output function in `write2()` is `summary()`. For available arguments, see the help pages for `summary.modelsum()`. +Don't use the option `text = TRUE` with the `write2` functions. + +```{r} +tab2 <- modelsum(alk.phos ~ arm + ps + hgb, adjust= ~ age + sex, family = "gaussian", data = mockstudy) + +write2pdf(tab2, paste0(tmpdir, "/test.modelsum.pdf"), quiet = TRUE, + title = "My test table", # passed to summary.modelsum + show.intercept = FALSE, # passed to summary.modelsum + digits = 5 # passed to summary.modelsum + ) +``` + +## `freqlist` + +For `freqlist` objects, the output function in `write2()` is `summary()`. For available arguments, see the help pages for `summary.freqlist()`. + +```{r} +tab3 <- freqlist(table(mockstudy[, c("arm", "sex", "mdquality.s")], useNA = "ifany"), groupBy = c("arm", "sex")) + +write2word(tab3, paste0(tmpdir, "/test.freqlist.doc"), quiet = TRUE, + single = FALSE # passed to summary.freqlist + ) +``` + +# Examples Using Other Objects + +## `knitr::kable()` + +For objects resulting from a call to `kable()`, the output function in `write2()` is `print()`. There aren't any arguments to the `print.knitr_kable()` function. + +```{r} +write2html(knitr::kable(head(mockstudy)), paste0(tmpdir, "/test.kable.html"), quiet = TRUE) +``` + +## `xtable::xtable()` + +For `xtable` objects, the output function in `write2()` is `print()`. For available arguments, see the help pages for `print.xtable()`. + +```{r} +write2pdf(xtable::xtable(head(mockstudy), caption = "My xtable"), paste0(tmpdir, "/test.xtable.pdf"), quiet = TRUE, + comment = FALSE, # passed to print.xtable to turn off the default message about xtable version + include.rownames = FALSE, # passed to print.xtable + caption.placement = "top" # passed to print.xtable + ) +``` + +To make an HTML document, use the `print.xtable()` option `type = "html"`. + +```{r} +write2html(xtable::xtable(head(mockstudy), caption = "My xtable"), paste0(tmpdir, "/test.xtable.html"), quiet = TRUE, + type = "html", # passed to print.xtable + comment = FALSE, # passed to print.xtable to turn off the default message about xtable version + include.rownames = FALSE, # passed to print.xtable + caption.placement = "top" # passed to print.xtable + ) +``` + +User beware! `xtable()` is not compatible with `write2word()`. + +## `pander::pander_return()` + +Pander is a little bit more tricky. Since `pander::pander()` doesn't return an object, the useR should instead use +`pander::pander_return()`. For this (and for all character vectors), the the output function in `write2()` is `cat(sep = '\n')`. + +```{r} +write2word(pander::pander_return(head(mockstudy)), file = paste0(tmpdir, "/test.pander.doc"), quiet = TRUE) +``` + +# FAQs + +## How do I suppress the note about my document getting rendered? + +This is easily accomplished by using the argument `quiet = TRUE` (passed to the `rmarkdown::render()` function). + +```{r} +write2html(knitr::kable(head(mockstudy)), paste0(tmpdir, "/test.kable.quiet.html"), + quiet = TRUE # passed to rmarkdown::render + ) +``` + +## How do I look at the temporary `.md` file? + +This is easily accomplished by using the option `keep.md = TRUE`. + +```{r} +write2html(knitr::kable(head(mockstudy)), paste0(tmpdir, "/test.kable.keep.md.html"), + quiet = TRUE, # passed to rmarkdown::render + keep.md = TRUE + ) +``` + +## How do I tweak the default format from `write2word()`, `write2html()`, or `write2pdf()`? + +You can pass arguments to the format functions used behind the scenes. + +```{r} +write2html(knitr::kable(head(mockstudy)), paste0(tmpdir, "/test.kable.theme.html"), + quiet = TRUE, # passed to rmarkdown::render + theme = "yeti" # passed to rmarkdown::html_document + ) +``` + +See the help pages for `rmarkdown::word_document()`, `rmarkdown::html_document()`, and `rmarkdown::pdf_document()`. + +## How do I output to a file format other than word, HTML, and PDF? + +This can be done using the generic `write2()` function. The last argument in the function can be another format specification. +For details on the acceptable inputs, see the help page for `write2()`. + +```{r} +write2(knitr::kable(head(mockstudy[, 1:4])), paste0(tmpdir, "/test.kable.rtf"), + quiet = TRUE, # passed to rmarkdown::render + output_format = rmarkdown::rtf_document + ) +```