├── .Rbuildignore ├── .dev └── .dev.R ├── .github ├── .gitignore └── workflows │ ├── R-CMD-check.yaml │ └── lint.yaml ├── .gitignore ├── DESCRIPTION ├── NAMESPACE ├── NEWS.md ├── R ├── Table1.R ├── furniture.R ├── long_wide.R ├── nhanes_data.R ├── rowmeans.R ├── table1_gt.R ├── table1_utils.R ├── tableF.R ├── tableX.R ├── table_cor.R ├── to_latex2.R ├── utils.R ├── washer.R └── zzz.R ├── README.Rmd ├── README.md ├── cran-comments.md ├── data └── nhanes_2010.rda ├── docs ├── 404.html ├── articles │ ├── Furniture.html │ ├── Furniture_files │ │ └── accessible-code-block-0.0.1 │ │ │ └── empty-anchor.js │ ├── Table1.html │ ├── Table1_files │ │ ├── accessible-code-block-0.0.1 │ │ │ └── empty-anchor.js │ │ └── figure-html │ │ │ └── tidyverse-1.png │ └── index.html ├── authors.html ├── bootstrap-toc.css ├── bootstrap-toc.js ├── docsearch.css ├── docsearch.js ├── index.html ├── jquery.sticky-kit.min.js ├── link.svg ├── news │ └── index.html ├── pkgdown.css ├── pkgdown.js ├── pkgdown.yml ├── reference │ ├── Rplot001.png │ ├── figures │ │ ├── furniture_hex.jpg │ │ ├── furniture_hex.pdf │ │ ├── furniture_hex.png │ │ ├── furniture_hex_v2.pdf │ │ ├── furniture_hex_v2_full.png │ │ └── furniture_hex_v2_small.png │ ├── furniture.html │ ├── grapes-xt-grapes.html │ ├── group_by.html │ ├── index.html │ ├── long.html │ ├── mutate_rowmeans.html │ ├── mutate_rowsums.html │ ├── nhanes_2010.html │ ├── pipe.html │ ├── rowmeans.html │ ├── rowmeans.n.html │ ├── rowsums.html │ ├── rowsums.n.html │ ├── selecting.html │ ├── table1.html │ ├── table1_format_condense.html │ ├── table1_format_nocondense.html │ ├── table1_summarizing.html │ ├── tableC.html │ ├── tableF.html │ ├── tableX.html │ ├── to_latex.html │ ├── washer.html │ └── wide.html └── sitemap.xml ├── furniture.Rproj ├── inst └── CITATION ├── man ├── figures │ ├── furniture_hex_v2.pdf │ ├── furniture_hex_v2_full.png │ └── furniture_hex_v2_small.png ├── furniture.Rd ├── long.Rd ├── nhanes_2010.Rd ├── rowmeans.Rd ├── rowmeans.n.Rd ├── rowsums.Rd ├── rowsums.n.Rd ├── table1.Rd ├── table1_gt.Rd ├── tableC.Rd ├── tableF.Rd ├── tableX.Rd ├── to_latex.Rd ├── washer.Rd └── wide.Rd ├── tests ├── testthat.R └── testthat │ ├── test_table1.R │ ├── test_tableF.R │ ├── test_tableX.R │ ├── test_table_cor.R │ ├── test_washer.R │ └── test_widelong.R └── vignettes ├── Furniture.Rmd └── Table1.Rmd /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^Meta$ 2 | ^doc$ 3 | ^CRAN-RELEASE$ 4 | .travis.yml 5 | README.md 6 | cran-comments.md 7 | .gitignore 8 | ^docs$ 9 | README.Rmd 10 | ^.*\.Rproj$ 11 | ^\.Rproj\.user$ 12 | ^\.github$ 13 | ^CRAN-SUBMISSION$ 14 | ^CRAN-RELEASE$ 15 | ^\.dev -------------------------------------------------------------------------------- /.dev/.dev.R: -------------------------------------------------------------------------------- 1 | # document 2 | devtools::document(here::here()) 3 | # check package 4 | devtools::check(here::here()) 5 | # fix github actions 6 | usethis::use_github_action() 7 | usethis::use_github_action("lint") 8 | # check win-builder 9 | devtools::check_win_devel(here::here()) 10 | devtools::check_win_release(here::here()) 11 | devtools::check_win_oldrelease(here::here()) 12 | # update pkg site 13 | pkgdown::build_site(here::here()) 14 | # revdep 15 | revdepcheck::cran_revdeps("furniture") 16 | revdepcheck::revdep_check(here::here()) 17 | # release to CRAN 18 | devtools::release(here::here()) 19 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: R-CMD-check 10 | 11 | jobs: 12 | R-CMD-check: 13 | runs-on: ${{ matrix.config.os }} 14 | 15 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 16 | 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | config: 21 | - {os: macos-latest, r: 'release'} 22 | - {os: windows-latest, r: 'release'} 23 | - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} 24 | - {os: ubuntu-latest, r: 'release'} 25 | - {os: ubuntu-latest, r: 'oldrel-1'} 26 | 27 | env: 28 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 29 | R_KEEP_PKG_SOURCE: yes 30 | 31 | steps: 32 | - uses: actions/checkout@v3 33 | 34 | - uses: r-lib/actions/setup-pandoc@v2 35 | 36 | - uses: r-lib/actions/setup-r@v2 37 | with: 38 | r-version: ${{ matrix.config.r }} 39 | http-user-agent: ${{ matrix.config.http-user-agent }} 40 | use-public-rspm: true 41 | 42 | - uses: r-lib/actions/setup-r-dependencies@v2 43 | with: 44 | extra-packages: any::rcmdcheck 45 | needs: check 46 | 47 | - uses: r-lib/actions/check-r-package@v2 48 | with: 49 | upload-snapshots: true 50 | -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: lint 10 | 11 | jobs: 12 | lint: 13 | runs-on: ubuntu-latest 14 | env: 15 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - uses: r-lib/actions/setup-r@v2 20 | with: 21 | use-public-rspm: true 22 | 23 | - uses: r-lib/actions/setup-r-dependencies@v2 24 | with: 25 | extra-packages: any::lintr, local::. 26 | needs: lint 27 | 28 | - name: Lint 29 | run: lintr::lint_package() 30 | shell: Rscript {0} 31 | env: 32 | LINTR_ERROR_ON_LINT: true 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Meta 2 | doc 3 | .Rproj.user 4 | .Rhistory 5 | .rda 6 | .Rmd 7 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: furniture 2 | Type: Package 3 | Title: Furniture for Quantitative Scientists 4 | Version: 1.10.0 5 | Authors@R: c(person("Tyson S.", "Barrett", 6 | role=c("aut","cre"), 7 | email = "t.barrett88@gmail.com", 8 | comment = c(ORCID = "0000-0002-2137-1391")), 9 | person("Emily", "Brignone", role="aut"), 10 | person("Daniel J.", "Laxman", role="aut")) 11 | Maintainer: Tyson S. Barrett 12 | Description: Contains four main functions (i.e., four pieces of furniture): 13 | table1() which produces a well-formatted table of descriptive statistics common as Table 1 14 | in research articles, tableC() which produces a well-formatted table of correlations, 15 | tableF() which provides frequency counts, and washer() which 16 | is helpful in cleaning up the data. These furniture-themed functions are designed 17 | to simplify common tasks in quantitative analysis. Other data summary and cleaning tools 18 | are also available. 19 | Depends: 20 | R (>= 2.10) 21 | Imports: 22 | knitr, 23 | dplyr (>= 0.8.0), 24 | gt 25 | Suggests: 26 | magrittr, 27 | rmarkdown, 28 | testthat 29 | LazyData: true 30 | VignetteBuilder: knitr 31 | Encoding: UTF-8 32 | License: GPL-3 33 | RoxygenNote: 7.3.0 34 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method(as.data.frame,table1) 4 | S3method(long,data.frame) 5 | S3method(long,matrix) 6 | S3method(long,tbl_df) 7 | S3method(long,tibble) 8 | S3method(print,latex2) 9 | S3method(print,table1) 10 | S3method(print,tableF) 11 | S3method(table1,data.frame) 12 | S3method(wide,data.frame) 13 | S3method(wide,matrix) 14 | S3method(wide,tbl_df) 15 | S3method(wide,tibble) 16 | export(long) 17 | export(rowmeans) 18 | export(rowmeans.n) 19 | export(rowsums) 20 | export(rowsums.n) 21 | export(table1) 22 | export(table1_gt) 23 | export(tableC) 24 | export(tableF) 25 | export(tableX) 26 | export(to_latex) 27 | export(washer) 28 | export(wide) 29 | importFrom(dplyr,group_by) 30 | importFrom(dplyr,mutate) 31 | importFrom(gt,fmt_markdown) 32 | importFrom(gt,gt) 33 | importFrom(gt,tab_spanner) 34 | importFrom(knitr,kable) 35 | importFrom(stats,IQR) 36 | importFrom(stats,addmargins) 37 | importFrom(stats,chisq.test) 38 | importFrom(stats,complete.cases) 39 | importFrom(stats,cor) 40 | importFrom(stats,dchisq) 41 | importFrom(stats,kruskal.test) 42 | importFrom(stats,lm) 43 | importFrom(stats,median) 44 | importFrom(stats,model.frame) 45 | importFrom(stats,oneway.test) 46 | importFrom(stats,pt) 47 | importFrom(stats,reshape) 48 | importFrom(stats,resid) 49 | importFrom(stats,sd) 50 | importFrom(stats,setNames) 51 | importFrom(stats,t.test) 52 | importFrom(utils,capture.output) 53 | importFrom(utils,write.csv) 54 | -------------------------------------------------------------------------------- /R/furniture.R: -------------------------------------------------------------------------------- 1 | #' furniture 2 | #' 3 | #' The furniture package offers simple functions (i.e. pieces of furniture) and 4 | #' an operator that are aimed at helping applied researchers explore and 5 | #' communicate their data as well as clean their data in a tidy way. The package 6 | #' follows similar semantics to the "tidyverse" packages. It contains several 7 | #' table functions (\code{table1()}) being the core one. 8 | #' 9 | #' \itemize{ 10 | #' \item \code{table1} provides a well-formatted descriptive table often seen 11 | #' as table 1 in academic journals (also a version that simplifies the 12 | #' output is available as \code{simple_table1}), 13 | #' \item \code{washer} provides a simple way to clean up data where there are 14 | #' placeholder values, and 15 | #' \item \code{\%xt\%} is an operator that takes two factor variables and 16 | #' creates a cross tabulation and tests for significance via a 17 | #' chi-square test. 18 | #' } 19 | #' 20 | #' Table 1 is the main function in furniture. It is useful in both data 21 | #' exploration and data communication. With minimal cleaning, the outputted 22 | #' table can be put into an academic, peer reviewed journal manuscript. As such, 23 | #' it is very useful in exploring your data when you have a stratifying 24 | #' variable. For example, if you are exploring whether the means of several 25 | #' demographic and behavioral characteristics are related to a health condition, 26 | #' the health condition (i.e. "yes" or "no"; "low", "mid", or "high"; or a list 27 | #' of conditions) as the stratifying variable. With little code, you can test 28 | #' for associations and check means or counts by the stratifying variable. 29 | #' See the vignette for more information. 30 | #' 31 | #' Note: furniture is meant to make life more comfortable and beautiful. 32 | #' In like manner, this package is designed to be "furniture" for quantitative 33 | #' research. 34 | #' 35 | #' @examples 36 | #' \dontrun{ 37 | #' 38 | #' library(furniture) 39 | #' 40 | #' ## Table 1 41 | #' data %>% 42 | #' table1(var1, var2, var3, 43 | #' splitby = ~groupvar, 44 | #' test = TRUE) 45 | #' 46 | #' ## Table F 47 | #' data %>% 48 | #' tableF(var1) 49 | #' 50 | #' ## Washer 51 | #' x = washer(x, 7, 8, 9) 52 | #' x = washer(x, is.na, value=0) 53 | #' 54 | #' } 55 | #' 56 | #' @name furniture 57 | #' @aliases furniture-package 58 | "_PACKAGE" -------------------------------------------------------------------------------- /R/nhanes_data.R: -------------------------------------------------------------------------------- 1 | #' NHANES 2009-2010 2 | #' 3 | #' A dataset containing information on health, healthcare, and demographics of adolescents 4 | #' aged 18 - 30 in the United States from 2009 to 2010. This is a cleaned dataset 5 | #' which is only a subset of the 2009-2010 data release of 6 | #' the National Health and Nutrition Examination Survey (NHANES). 7 | #' 8 | #' @format A data frame with 1417 rows and 24 variables: 9 | #' \describe{ 10 | #' \item{id}{individual ID} 11 | #' \item{gen_health}{general health indicator with five levels} 12 | #' \item{mod_active}{minutes of moderate activity} 13 | #' \item{vig_active}{minutes of vigorous activity} 14 | #' \item{home_meals}{number of home meals a week} 15 | #' \item{gender}{gender of the individual (factor with "male" or "female")} 16 | #' \item{age}{age of the individual in years} 17 | #' \item{marijuana}{whether the individual has used marijuana} 18 | #' \item{illicit}{whether the individual has used illicit drugs} 19 | #' \item{rehab}{whether the individual has been to rehab for their drug usage} 20 | #' \item{asthma}{whether the individual has asthma} 21 | #' \item{overweight}{whether the individual is overweight} 22 | #' \item{cancer}{whether the individual has cancer} 23 | #' \item{low_int}{rating of whether the individual has low interest in things} 24 | #' \item{down}{rating of whether the individual has felt down} 25 | #' \item{sleeping}{rating of whether the individual has had trouble sleeping} 26 | #' \item{low_energy}{rating of whether the individual has low energy} 27 | #' \item{appetite}{rating of whether the individual has lost appetite} 28 | #' \item{feel_bad}{rating of whether the individual has felt bad} 29 | #' \item{no_con}{rating of whether the individual has felt no confidence} 30 | #' \item{speak_move}{rating of whether the individual has trouble speaking/moving} 31 | #' \item{dead}{rating of whether the individual has wished he/she was dead} 32 | #' \item{difficulty}{rating of whether the individual has felt difficulty from the previous conditions} 33 | #' \item{active}{minutes of vigorous or moderate activity} 34 | #' } 35 | #' @source \url{https://wwwn.cdc.gov/nchs/nhanes/continuousnhanes/default.aspx?BeginYear=2009} 36 | "nhanes_2010" -------------------------------------------------------------------------------- /R/rowmeans.R: -------------------------------------------------------------------------------- 1 | #' Get Row Means 2 | #' 3 | #' Does what \code{rowMeans()} does but without having to cbind the variables. Makes it easier to use 4 | #' with the tidyverse 5 | #' 6 | #' @param ... the variables (unquoted) to be included in the row means 7 | #' @param na.rm should the missing values be ignored? default is FALSE 8 | #' 9 | #' @return the row means 10 | #' 11 | #' @examples 12 | #' 13 | #' \dontrun{ 14 | #' 15 | #' library(furniture) 16 | #' library(tidyverse) 17 | #' 18 | #' data <- data.frame( 19 | #' x = sample(c(1,2,3,4), 100, replace=TRUE), 20 | #' y = rnorm(100), 21 | #' z = rnorm(100) 22 | #' ) 23 | #' 24 | #' data2 <- data %>% 25 | #' mutate(y_z_mean = rowmeans(y, z)) 26 | #' data2 <- data %>% 27 | #' mutate(y_z_mean = rowmeans(y, z, na.rm=TRUE)) 28 | #' 29 | #' } 30 | #' 31 | #' @export 32 | rowmeans = function(..., na.rm=FALSE){ 33 | rowMeans(cbind(...), na.rm = na.rm) 34 | } 35 | 36 | #' Get Row Means With N Missing Values Per Row 37 | #' 38 | #' Does what \code{furniture::rowmeans()} does while allowing a certain number (\code{n}) to have missing values. 39 | #' 40 | #' @param ... the variables (unquoted) to be included in the row means 41 | #' @param n the number of values without missingness required to get the row mean 42 | #' 43 | #' @return the row means 44 | #' 45 | #' @examples 46 | #' 47 | #' \dontrun{ 48 | #' 49 | #' library(furniture) 50 | #' library(dplyr) 51 | #' 52 | #' data <- data.frame( 53 | #' x = sample(c(1,2,3,4), 100, replace=TRUE), 54 | #' y = rnorm(100), 55 | #' z = rnorm(100) 56 | #' ) 57 | #' 58 | #' data2 <- mutate(data, x_y_z_mean = rowmeans.n(x, y, z, n = 2)) 59 | #' 60 | #' } 61 | #' 62 | #' @export 63 | rowmeans.n <- function(..., n){ 64 | ifelse(rowmeans(is.na(cbind(...)) <= n), 65 | rowmeans(..., na.rm = TRUE), 66 | NA) 67 | } 68 | 69 | #' Get Row Sums 70 | #' 71 | #' Does what \code{rowSums()} does but without having to cbind the variables. Makes it easier to use 72 | #' with the tidyverse 73 | #' 74 | #' @param ... the variables to be included in the row sums 75 | #' @param na.rm should the missing values be ignored? default is FALSE 76 | #' 77 | #' @return the row sums 78 | #' 79 | #' 80 | #' @examples 81 | #' 82 | #' \dontrun{ 83 | #' 84 | #' library(furniture) 85 | #' library(tidyverse) 86 | #' 87 | #' data <- data.frame( 88 | #' x = sample(c(1,2,3,4), 100, replace=TRUE), 89 | #' y = rnorm(100), 90 | #' z = rnorm(100) 91 | #' ) 92 | #' 93 | #' data2 <- data %>% 94 | #' mutate(y_z_sum = rowsums(y, z)) 95 | #' data2 <- data %>% 96 | #' mutate(y_z_sum = rowsums(y, z, na.rm=TRUE)) 97 | #' 98 | #' } 99 | #' 100 | #' 101 | #' @export 102 | rowsums = function(..., na.rm=FALSE){ 103 | rowSums(cbind(...), na.rm = na.rm) 104 | } 105 | 106 | #' Get Row Sums With N Missing Values Per Row 107 | #' 108 | #' Does what \code{furniture::rowsums()} does while allowing a certain number (\code{n}) to have missing values. 109 | #' 110 | #' @param ... the variables (unquoted) to be included in the row means 111 | #' @param n the number of values without missingness required to get the row mean 112 | #' 113 | #' @return the row sums 114 | #' 115 | #' @examples 116 | #' 117 | #' \dontrun{ 118 | #' 119 | #' library(furniture) 120 | #' library(dplyr) 121 | #' 122 | #' data <- data.frame( 123 | #' x = sample(c(1,2,3,4), 100, replace=TRUE), 124 | #' y = rnorm(100), 125 | #' z = rnorm(100) 126 | #' ) 127 | #' 128 | #' data2 <- mutate(data, x_y_z_mean = rowsums.n(x, y, z, n = 2)) 129 | #' 130 | #' } 131 | #' 132 | #' @export 133 | rowsums.n <- function(..., n){ 134 | ifelse(rowsums(is.na(cbind(...)) <= n), 135 | rowsums(..., na.rm = TRUE), 136 | NA) 137 | } 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /R/table1_gt.R: -------------------------------------------------------------------------------- 1 | #' @title gt output for table1 2 | #' @author Tyson S. Barrett 3 | #' 4 | #' @description This takes a table1 object and outputs a `gt` version. 5 | #' 6 | #' @param tab the table1 object 7 | #' @param spanner the label above the grouping variable (if table1 is grouped) 8 | #' or any label you want to include over the statistics column(s) 9 | #' 10 | #' @importFrom gt gt 11 | #' @importFrom gt fmt_markdown 12 | #' @importFrom gt tab_spanner 13 | #' 14 | #' @examples 15 | #' 16 | #' library(furniture) 17 | #' library(dplyr) 18 | #' 19 | #' data('nhanes_2010') 20 | #' nhanes_2010 %>% 21 | #' group_by(asthma) %>% 22 | #' table1(age, marijuana, illicit, rehab, na.rm = FALSE) %>% 23 | #' table1_gt(spanner = "Asthma") 24 | #' 25 | #' @export 26 | table1_gt <- function(tab, spanner = NULL) { 27 | # save names and adjust table to include n's in header 28 | nams <- names(tab[[1]]) 29 | nams[1] <- "Characteristic" 30 | tab_df <- as.data.frame(tab) 31 | nams <- paste0(nams, tab_df[1, ]) 32 | nams <- gsub("n =", ", n =", nams) 33 | nams <- gsub("[[:space:]]*$","", nams) 34 | tab_df <- tab_df[-1, ] 35 | names(tab_df) <- nams 36 | 37 | # add spacing for the table 38 | tab_df$Characteristic <- ifelse( 39 | grepl(" ", tab_df$Characteristic), 40 | paste("    ", tab_df$Characteristic), 41 | tab_df$Characteristic 42 | ) 43 | 44 | # make it a gt and return 45 | gt_tab <- gt::gt(tab_df) 46 | gt_tab <- gt::fmt_markdown(gt_tab) 47 | 48 | # add spanner 49 | if (!is.null(spanner)) 50 | gt::tab_spanner(gt_tab, label = spanner, columns = -Characteristic) 51 | else 52 | gt_tab 53 | } 54 | -------------------------------------------------------------------------------- /R/tableF.R: -------------------------------------------------------------------------------- 1 | #' Frequency Table 2 | #' 3 | #' Provides in-depth frequency counts and percentages. 4 | #' 5 | #' @param .data the data frame containing the variable 6 | #' @param x the bare variable name (not quoted) 7 | #' @param n the number of values shown int he table 8 | #' @param splitby the stratifying variable 9 | #' 10 | #' @return a list of class \code{tableF} containing the frequency table(s) 11 | #' 12 | #' @examples 13 | #' 14 | #' \dontrun{ 15 | #' 16 | #' library(furniture) 17 | #' 18 | #' data <- data.frame( 19 | #' x = sample(c(1,2,3,4), 100, replace=TRUE), 20 | #' y = rnorm(100) 21 | #' ) 22 | #' 23 | #' ## Basic Use 24 | #' tableF(data, x) 25 | #' tableF(data, y) 26 | #' 27 | #' ## Adjust the number of items shown 28 | #' tableF(data, y, n = 10) 29 | #' 30 | #' ## Add splitby 31 | #' tableF(data, x, splitby = y) 32 | #' 33 | #' } 34 | #' 35 | #' @export 36 | 37 | tableF <- function(.data, x, n = 20, splitby = NULL){ 38 | .call <- match.call() 39 | x <- eval(substitute(x), .data) 40 | 41 | if (is.null(attr(.data, "vars")) && is.null(attr(.data, "groups"))){ 42 | 43 | ### Splitby Variable (adds the variable to d as "split") 44 | splitby = substitute(splitby) 45 | if (inherits(substitute(splitby), "name")){ 46 | splitby_ = eval(substitute(splitby), .data) 47 | } else if (inherits(substitute(splitby), "call")){ 48 | splitby_ = model.frame(splitby, .data, na.action = "na.pass")[[1]] 49 | } else if (inherits(substitute(splitby), "character")){ 50 | splitby_ = .data[[splitby]] 51 | } else if(is.null(splitby)){ 52 | splitby_ = factor(1, labels = paste(.call[3])) 53 | } 54 | } else { 55 | ## Working around different versions of dplyr with group_by() 56 | ## Older (0.7.6) uses "vars": produces the grouping name 57 | ## Developmental one (0.7.9.9000) uses "groups" but it produces a nested table 58 | groups <- attr(.data, "vars") 59 | if (is.null(groups)) 60 | groups <- attr(.data, "groups") %>% names(.) 61 | if (groups[length(groups)] == ".rows") 62 | groups <- groups[-length(groups)] 63 | 64 | message(paste0("Using dplyr::group_by() groups: ", paste(groups, collapse = ", "))) 65 | 66 | if (length(groups) == 1){ 67 | splitby_ <- factor(.data[[groups]]) 68 | } else { 69 | interacts <- interaction(.data[groups], sep = "_") 70 | splitby_ <- factor(interacts) 71 | } 72 | } 73 | 74 | if(any(is.na(splitby_))){ 75 | splitby_ <- factor(ifelse(is.na(splitby_),"Missing", splitby_)) 76 | } 77 | 78 | ## Error catch for all missing 79 | if(all(is.na(x))){ 80 | warn <- paste0("All values for ", .call[3], " are missing.") 81 | warning(warn) 82 | return(NULL) 83 | } 84 | 85 | splitby_ <- factor(splitby_) 86 | 87 | final_list <- list() 88 | for(i in levels(splitby_)){ 89 | 90 | x1 <- x[splitby_ == i & !is.na(splitby_)] 91 | 92 | ## Summary statistics 93 | Freq <- table(x1, useNA="ifany") 94 | CumFreq <- round(cumsum(table(x1, useNA="ifany"))) 95 | Percent <- suppressWarnings(formatC(100*(prop.table(table(x1, useNA="ifany"))), 96 | format = "f", digits = 2, big.mark = ",")) 97 | CumPerc <- suppressWarnings(formatC(100*cumsum(prop.table(table(x1, useNA="ifany"))), 98 | format = "f", digits = 2, big.mark = ",")) 99 | Valid <- suppressWarnings(formatC(100*(prop.table(table(x1, useNA="no"))), 100 | format = "f", digits = 2, big.mark = ",")) 101 | CumValid <- suppressWarnings(formatC(100*cumsum(prop.table(table(x1, useNA="no"))), 102 | format = "f", digits = 2, big.mark = ",")) 103 | 104 | ## If there is missing, add a blank line below the valids 105 | if (any(is.na(x1))){ 106 | names(Freq)[length(names(Freq))] <- "Missing" 107 | names(CumFreq)[length(names(CumFreq))] <- "Missing" 108 | final <- data.frame("Var" = names(Freq), 109 | "Freq" = as.character(Freq), 110 | "CumFreq" = as.character(CumFreq), 111 | "Percent" = paste0(Percent, "%"), 112 | "CumPerc" = paste0(CumPerc, "%"), 113 | "Valid" = c(paste0(Valid, "%"), ""), 114 | "CumValid" = c(paste0(CumValid, "%"), ""), 115 | stringsAsFactors = TRUE) 116 | names(final)[1] <- paste(i) 117 | final[] <- lapply(final,as.character) 118 | 119 | if (dim(final)[1] > n){ 120 | final1 <- final[c(1:(n/2)),] 121 | final2 <- final[c((dim(final)[1] - n/2):(dim(final)[1])),] 122 | final1 <- rbind(final1, "...") 123 | final <- rbind(final1, final2) 124 | row.names(final) = ifelse(final$Freq=="...", "...", row.names(final)) 125 | } 126 | 127 | } else { 128 | final <- data.frame("Var" = names(Freq), 129 | "Freq" = as.character(Freq), 130 | "CumFreq" = as.character(CumFreq), 131 | "Percent" = paste0(Percent, "%"), 132 | "CumPerc" = paste0(CumPerc, "%"), 133 | stringsAsFactors = TRUE) 134 | names(final)[1] <- paste(i) 135 | final[] <- lapply(final,as.character) 136 | 137 | if (dim(final)[1] > n){ 138 | final1 <- final[c(1:(n/2)),] 139 | final2 <- final[c((dim(final)[1] - n/2):(dim(final)[1])),] 140 | final1 <- rbind(final1, "...") 141 | final <- rbind(final1, final2) 142 | row.names(final) <- ifelse(final$Freq=="...", "...", row.names(final)) 143 | }} 144 | 145 | final_list[[i]] <- final 146 | } 147 | 148 | ## Output 149 | class(final_list) <- c("tableF", "list") 150 | attr(final_list, "variable") <- paste(.call[3]) 151 | final_list 152 | } 153 | 154 | #' @export 155 | print.tableF <- function(x, ...){ 156 | max_col_width = max_col_width2 = list() 157 | len = length(x) 158 | 159 | if (len > 1){ 160 | message("Variable:", attr(x, "variable")) 161 | } 162 | 163 | for (i in 1:len){ 164 | x2 = as.data.frame(x[[i]], stringsAsFactors = TRUE) 165 | x2[] = sapply(x2, as.character) 166 | 167 | ## Get width of table for lines 168 | for (j in seq_len(dim(x2)[2])){ 169 | max_col_width[[j]] = max(sapply(x2[[j]], nchar, type="width")) 170 | } 171 | tot_width = sum(ifelse(unlist(max_col_width) > nchar(names(x2)), unlist(max_col_width), nchar(names(x2)))) + 172 | dim(x2)[2] - 1 173 | 174 | ## Print top border 175 | cat("\n\u2500") 176 | for (j in 1:tot_width){ 177 | cat("\u2500") 178 | } 179 | cat("\u2500\n") 180 | ## Print table 181 | print(x2, ..., row.names = FALSE, right = FALSE) 182 | ## Print bottom border 183 | cat("\u2500") 184 | for (j in 1:tot_width){ 185 | cat("\u2500") 186 | } 187 | cat("\u2500\n") 188 | } 189 | } 190 | 191 | -------------------------------------------------------------------------------- /R/tableX.R: -------------------------------------------------------------------------------- 1 | #' Table X (for Cross-Tabs) 2 | #' 3 | #' Provides a pipe-able, clean, flexible version of \code{table()}. 4 | #' 5 | #' @param .data the data frame containing the variables 6 | #' @param x1 the first bare (not quoted) variable found in .data 7 | #' @param x2 the second bare (not quoted) variable found in .data 8 | #' @param type the summarized output type; can be "count", "cell_perc", "row_perc", or "col_perc" 9 | #' @param na.rm logical; whether missing values should be removed 10 | #' @param format_number default is FALSE; if TRUE, then the numbers are formatted with commas (e.g., 20,000 instead of 20000) 11 | #' 12 | #' @examples 13 | #' 14 | #' \dontrun{ 15 | #' 16 | #' library(furniture) 17 | #' library(tidyverse) 18 | #' 19 | #' data <- data.frame( 20 | #' x = sample(c(1,2,3,4), 100, replace=TRUE), 21 | #' y = sample(c(0,1), 100, replace=TRUE) 22 | #' ) 23 | #' 24 | #' tableX(data, x, y) 25 | #' 26 | #' data %>% 27 | #' tableX(x, y) 28 | #' 29 | #' data %>% 30 | #' tableX(x, y, na.rm = TRUE) 31 | #' 32 | #' } 33 | #' 34 | #' @export 35 | tableX = function(.data, x1, x2, type = "count", na.rm = FALSE, format_number = FALSE){ 36 | 37 | .call = match.call() 38 | x1 = eval(substitute(x1), .data) 39 | x2 = eval(substitute(x2), .data) 40 | 41 | ## Missing Data 42 | if(grepl("F|f", na.rm)){ 43 | if(any(is.na(x1))){ 44 | x1 = factor(ifelse(is.na(x1),"Missing", x1)) 45 | } 46 | 47 | if(any(is.na(x2))){ 48 | x2 = factor(ifelse(is.na(x2),"Missing", x2)) 49 | } 50 | } 51 | 52 | 53 | ## Changing "Sum" to "Total" and "Sum" to "All" 54 | Total <- sum 55 | All <- sum 56 | 57 | ## Format Number 58 | big.mark = "" 59 | if (format_number) big.mark = "," 60 | 61 | ## type: Counts 62 | if(type %in% c("count")){ 63 | final = noquote( 64 | suppressWarnings( 65 | formatC( 66 | addmargins( 67 | table(x1, x2, 68 | useNA = "no", 69 | dnn = c(as.character(.call[3]), as.character(.call[4]))), 70 | FUN = Total, 71 | quiet = TRUE), 72 | format = "f", 73 | digits = 0, 74 | big.mark = big.mark) 75 | ) 76 | ) 77 | 78 | } 79 | 80 | ## type: Cell Percentage 81 | else if(type %in% c("cell_perc")){ 82 | final = noquote( 83 | suppressWarnings( 84 | formatC( 85 | addmargins( 86 | 100*(prop.table( 87 | table( 88 | x1, x2, useNA = "no", 89 | dnn = c(as.character(.call[3]), as.character(.call[4]))))), 90 | FUN = Total, quiet = TRUE), 91 | format = "f", digits = 2, 92 | big.mark = big.mark))) 93 | 94 | } 95 | 96 | ## type: Row Percentage 97 | else if(type %in% c("row_perc")){ 98 | final = noquote( 99 | suppressWarnings( 100 | formatC( 101 | addmargins( 102 | 100*prop.table( 103 | addmargins( 104 | table(x1, x2, 105 | useNA = "no", 106 | dnn = c(as.character(.call[3]), as.character(.call[4]))), 107 | margin = 1, 108 | FUN = All, 109 | quiet = TRUE), 110 | margin = 1), 111 | margin = 2, 112 | FUN = Total, 113 | quiet = TRUE), 114 | format = "f", 115 | digits = 2, 116 | big.mark = big.mark) 117 | ) 118 | ) 119 | } 120 | 121 | ## type: Column Percentage 122 | else if(type %in% c("col_perc")){ 123 | final = noquote( 124 | suppressWarnings( 125 | formatC( 126 | addmargins( 127 | 100*prop.table( 128 | addmargins( 129 | table(x1, x2, 130 | useNA = "no", 131 | dnn = c(as.character(.call[3]), as.character(.call[4]))), 132 | margin = 2, 133 | FUN = All, 134 | quiet = TRUE), 135 | margin = 2), 136 | margin = 1, 137 | FUN = Total, 138 | quiet = TRUE), 139 | format = "f", 140 | digits = 2, 141 | big.mark = big.mark) 142 | ) 143 | ) 144 | } 145 | class(final) = 'table' 146 | final 147 | } 148 | 149 | -------------------------------------------------------------------------------- /R/table_cor.R: -------------------------------------------------------------------------------- 1 | #' Correlation Table 2 | #' 3 | #' Correlations printed in a nicely formatted table. 4 | #' 5 | #' @param .data the data frame containing the variables 6 | #' @param ... the unquoted variable names to be included in the correlations 7 | #' @param cor_type the correlation type; default is "pearson", other option is "spearman" 8 | #' @param na.rm logical (default is \code{FALSE}); if set to \code{TRUE}, the correlations use the "complete.obs" methods option from \code{stats::cor()} 9 | #' @param rounding the value passed to \code{round} for the output of both the correlation and p-value; default is 3 10 | #' @param output how the table is output; can be "text" for regular console output, "latex2" for specialized latex output, or any of \code{kable()}'s options from \code{knitr} (e.g., "latex", "markdown", "pandoc"). 11 | #' @param booktabs when \code{output != "text"}; option is passed to \code{knitr::kable} 12 | #' @param caption when \code{output != "text"}; option is passed to \code{knitr::kable} 13 | #' @param align when \code{output != "text"}; option is passed to \code{knitr::kable} 14 | #' @param float when \code{output == "latex2"} it controls the floating parameter (h, t, b, H) 15 | #' 16 | #' @seealso stats::cor 17 | #' 18 | #' @importFrom stats cor 19 | #' @importFrom knitr kable 20 | #' 21 | #' @export 22 | tableC <- function(.data, 23 | ..., 24 | cor_type = "pearson", 25 | na.rm = FALSE, 26 | rounding = 3, 27 | output = "text", 28 | booktabs = TRUE, 29 | caption = NULL, 30 | align = NULL, 31 | float = "htb"){ 32 | 33 | ## Preprocessing ## 34 | .call <- match.call() 35 | data <- selecting(d_=.data, ...) 36 | d <- as.data.frame(data, stringsAsFactors = TRUE) 37 | 38 | ## NA ## 39 | if (na.rm){ 40 | use1 <- "complete.obs" 41 | n <- sum(complete.cases(d)) 42 | } else { 43 | use1 <- "everything" 44 | n <- length(d[[1]]) 45 | } 46 | 47 | ## Correlations ## 48 | cors <- stats::cor(d, 49 | method = cor_type, 50 | use = use1) 51 | ## Significance ## 52 | if (cor_type == "pearson"){ 53 | tvalues <- cors/sqrt((1 - cors^2)/(n-2)) 54 | } else if (cor_type == "spearman"){ 55 | tvalues <- cors * sqrt((n-2)/(1 - cors^2)) 56 | } else { 57 | stop(paste(cor_type, "is not a possible correlation type with this function.")) 58 | } 59 | 60 | pvalues <- 2*pt(abs(tvalues), n-2, lower.tail = FALSE) 61 | 62 | ## Formatting Names and Rownames 63 | cors <- as.data.frame(cors, stringsAsFactors = TRUE) 64 | pvalues <- as.data.frame(pvalues, stringsAsFactors = TRUE) 65 | dims <- dim(cors) 66 | 67 | if (output == "latex2"){ 68 | row.names(cors) <- paste0("{[", 1:dims[1], "]}", row.names(cors)) 69 | } else { 70 | row.names(cors) <- paste0("[", 1:dims[1], "]", row.names(cors)) 71 | } 72 | 73 | names(cors) <- paste0("[", 1:dims[1], "]") 74 | 75 | ## Combine 76 | final <- matrix(nrow = dims[1], ncol = dims[2]) 77 | for (i in 1:dims[1]){ 78 | for (j in 1:dims[2]){ 79 | final[i,j] <- paste0(ifelse(cors[i,j] == 1, "1.00", round(cors[i,j], rounding)), 80 | " ", 81 | ifelse(cors[i,j] == 1, "", 82 | ifelse(pvalues[i,j] < .001, "(<.001)", 83 | paste0("(", 84 | round(pvalues[i,j], rounding), ")")))) 85 | } 86 | } 87 | final[upper.tri(final)] <- " " 88 | final <- as.data.frame(final, stringsAsFactors = TRUE) 89 | row.names(final) <- row.names(cors) 90 | final <- data.frame(" " = row.names(final), final, stringsAsFactors = TRUE) 91 | names(final) <- c(" ", names(cors)) 92 | 93 | ## Output ## 94 | message("N = ", n, "\n", 95 | "Note: ", cor_type, " correlation (p-value).") 96 | 97 | if (output != "text"){ 98 | if (output == "latex2"){ 99 | if (is.null(align)){ 100 | l1 <- dim(final)[2] 101 | align <- c("l", rep("c", (l1-1))) 102 | } 103 | tab <- to_latex(final, caption, align, len = dim(final)[2] - 1, splitby = NA, float, booktabs, cor_type) 104 | return(tab) 105 | 106 | } else { 107 | kab <- knitr::kable(final, 108 | format=output, 109 | booktabs = booktabs, 110 | caption = caption, 111 | align = align, 112 | row.names = FALSE) 113 | return(kab) 114 | } 115 | } else { 116 | 117 | final <- list("Table1" = final) 118 | class(final) <- c("table1", "list") 119 | attr(final, "splitby") <- NULL 120 | attr(final, "output") <- NULL 121 | return(final) 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /R/to_latex2.R: -------------------------------------------------------------------------------- 1 | #' From Table 1 to Latex 2 2 | #' 3 | #' Internal \code{table1()} and \code{tableC()} function for providing output = "latex2" 4 | #' 5 | #' @param tab the table1 object 6 | #' @param caption caption character vector 7 | #' @param align align character vector 8 | #' @param len the number of levels of the grouping factor 9 | #' @param splitby the name of the grouping factor 10 | #' @param float argument for latex formatting 11 | #' @param cor_type optional argument regarding the correlation type (for tableC) 12 | #' @param booktabs add booktabs to latex table 13 | #' @param label latex label option 14 | #' @param total is there a total column (from Table 1) to be printed? 15 | #' 16 | #' @export 17 | #' @importFrom utils capture.output 18 | to_latex = function(tab, caption, align, len, splitby, float, booktabs, label, total=FALSE, cor_type=NULL){ 19 | if (is.null(cor_type) && is.null(splitby)){ 20 | splitby <- "Total" 21 | } else if (!is.null(cor_type)){ 22 | cor_type2 <- paste(toupper(substr(cor_type, 1, 1)), substring(cor_type, 2), 23 | sep = "") 24 | splitby <- paste(cor_type2, "Correlations") 25 | } else if (is.null(cor_type) && !is.null(splitby)) { 26 | splitby <- gsub("`", "", paste(splitby)) 27 | splitby <- gsub("%", "\\%", splitby) 28 | } 29 | if (total) tot_column <- " & " else tot_column <- "" 30 | 31 | ## Fix problematic latex characters 32 | tab[] <- lapply(tab, function(x) gsub("%", "\\%", x, fixed = TRUE)) 33 | tab[] <- lapply(tab, function(x) gsub("NA", "\\emph{missing}", x, fixed = TRUE)) 34 | tab[] <- lapply(tab, function(x) gsub("_", "\\_", x, fixed = TRUE)) 35 | 36 | ## Produce latex table 37 | out <- capture.output({ 38 | cat("\\begin{table}[", float, "] \n") 39 | cat("\\centering \n") 40 | cat("\\caption{", caption, "}", "\\label{", ifelse(is.null(label), "", label), "}\n", sep = "") 41 | cat("\\begin{tabular}{", align, "}\n") 42 | cat(hrule('top', booktabs)) 43 | cat(" & ", tot_column, "\\multicolumn{", paste0(len), "}{c}{", ifelse(is.null(splitby), "Total", splitby), "}\\\\ \n") 44 | 45 | if (is.null(cor_type)){ 46 | cat(paste(gsub("%", "\\%", names(tab), fixed = TRUE), collapse = " & "), "\\\\", "\n") 47 | cat(paste(tab[1, ], collapse = " & "), "\\\\ \n", hrule('mid', booktabs)) 48 | 49 | cat( 50 | for (i in 2:length(tab[[1]])){ 51 | if (grepl("^ ", tab[i, 1])){ 52 | cat("\\hspace{6pt}", paste(tab[i, ], collapse = " & ")) 53 | cat("\\\\", "\n") 54 | } else { 55 | cat(paste(tab[i, ], collapse = " & ")) 56 | cat("\\\\", "\n") 57 | } 58 | 59 | }) 60 | } else { 61 | cat(paste(names(tab), collapse = " & "), "\\\\", paste0("\n",hrule('mid', booktabs))) 62 | cat( 63 | for (i in seq_along(tab[[1]])){ 64 | if (grepl("^ ", tab[i, 1])){ 65 | cat("\\hspace{6pt}", paste(tab[i, ], collapse = " & ")) 66 | cat("\\\\", "\n") 67 | } else { 68 | cat(paste(tab[i, ], collapse = " & ")) 69 | cat("\\\\", "\n") 70 | } 71 | } 72 | ) 73 | } 74 | cat(paste0(c(hrule('bottom', booktabs), 75 | "\\end{tabular}", 76 | "\\end{table}\n"), collapse="\n")) 77 | }) 78 | class(out) <- c("latex2", "character", "table1") 79 | out 80 | } 81 | 82 | #' @export 83 | print.latex2 = function(x, ...){ 84 | cat(paste(x, collapse = "\n")) 85 | } 86 | 87 | 88 | hrule <- function(location, booktabs) { 89 | if (booktabs) { 90 | if (location == 'top') { 91 | "\\toprule\n" 92 | } else if (location == 'mid') { 93 | "\\midrule\n" 94 | } else if (location == 'bottom') { 95 | "\\bottomrule\n" 96 | } else { stop(location) } 97 | } else { 98 | "\\hline\n" 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /R/utils.R: -------------------------------------------------------------------------------- 1 | ## Utilities for the furniture package 2 | 3 | ## Output type constructor 4 | .type_constructor = function(type){ 5 | if (any(grepl("simp", type)) && any(grepl("cond", type))){ 6 | simple <- TRUE 7 | condense <- TRUE 8 | } else if (any(grepl("cond", type))){ 9 | simple <- FALSE 10 | condense <- TRUE 11 | } else if (any(grepl("simp", type))){ 12 | simple <- TRUE 13 | condense <- FALSE 14 | } else { 15 | simple <- FALSE 16 | condense <- FALSE 17 | } 18 | list(condense, simple) 19 | } 20 | 21 | ## Header Labels checker 22 | .header_labels = function(header_labels, format_output){ 23 | if(!is.null(header_labels)){ 24 | if (grepl("f|F", format_output)) { 25 | length_labels <- 3 26 | } else if (grepl("p|P", format_output)) { 27 | length_labels <- 2 28 | } else if (grepl("s|S", format_output)) { 29 | length_labels <- 1 30 | } else { 31 | stop("Type must be one of 'full', 'pvalues', or 'stars'.") 32 | } 33 | 34 | if (length_labels != length(header_labels)){ 35 | stop("header_labels must match the length of adjustable header values.") 36 | } 37 | } 38 | } 39 | 40 | ## More than one value per variable warning 41 | .more_than_one_value <- function(data){ 42 | subset(data, select=-split) %>% 43 | lapply(function(x) length(unique(x)) > 1) %>% 44 | unlist() %>% 45 | all() 46 | } 47 | 48 | ## Observations and Header Labels 49 | .obs_header = function(d, f1, format_output, test, output, header_labels, total){ 50 | 51 | if (isTRUE(total)){ 52 | tot <- NROW(d[[1]]) 53 | nams <- c(" ", "Total", levels(d$split)) 54 | 55 | if (!is.null(header_labels)){ 56 | header_labels <- c(header_labels[1], "Total", header_labels[2:length(header_labels)]) 57 | } 58 | 59 | } else { 60 | tot <- NULL 61 | nams <- c(" ", levels(d$split)) 62 | } 63 | 64 | N <- c("Total" = tot, tapply(d[[1]], d$split, length)) 65 | N[] <- sapply(N, function(x) as.character(paste("n =", x))) 66 | N <- suppressWarnings(formatC(N, big.mark = f1, digits = 0, format = "f")) %>% 67 | sapply(trimws, which = "left") %>% 68 | t(.) 69 | 70 | ## Formatting the N line 71 | if (grepl("f|F", format_output) & test){ 72 | if (is.null(header_labels)){ 73 | header_labels <- c(nams, "Test", "P-Value") 74 | N <- data.frame("", N, "", "", stringsAsFactors = TRUE) 75 | names(N) <- header_labels 76 | } else { 77 | N <- data.frame("", N, "", "", stringsAsFactors = TRUE) 78 | names(N) <- c(header_labels[1], levels(d$split), header_labels[2:length(header_labels)]) 79 | } 80 | } else if ((grepl("p|P", format_output) || grepl("s|S", format_output)) && test){ 81 | N <- data.frame(" ", N, " ", stringsAsFactors = TRUE) 82 | if (grepl("p|P", format_output)){ 83 | if (is.null(header_labels)){ 84 | header_labels <- c(nams, "P-Value") 85 | names(N) <- header_labels 86 | } else { 87 | names(N) <- c(header_labels[1], levels(d$split), header_labels[2:length(header_labels)]) 88 | } 89 | } else { 90 | if (is.null(header_labels)){ 91 | header_labels <- c(nams, " ") 92 | names(N) <- header_labels 93 | } else { 94 | names(N) <- c(header_labels[1], levels(d$split), header_labels[2:length(header_labels)]) 95 | } 96 | 97 | } 98 | } else { 99 | if (is.null(header_labels)){ 100 | header_labels <- nams 101 | N <- data.frame("", N, stringsAsFactors = TRUE) 102 | names(N) <- header_labels 103 | } else { 104 | N <- data.frame("", N, stringsAsFactors = TRUE) 105 | names(N) <- c(header_labels[1], levels(d$split)) 106 | } 107 | 108 | } 109 | N[] <- sapply(N, as.character) 110 | N 111 | } 112 | 113 | 114 | 115 | ## Formatting for default summaries 116 | .summary_functions1 = function(FUN, format_number, digits){ 117 | if (format_number){ 118 | f1 <- "," 119 | } else { 120 | f1 <- "" 121 | } 122 | ## Primary Function 123 | if(is.null(FUN)){ 124 | num_fun <- function(x){ 125 | gettextf("%s (%s)", 126 | formatC(mean(x, na.rm=TRUE), big.mark = f1, digits = digits, format = "f"), 127 | formatC(sd(x, na.rm=TRUE), big.mark = f1, digits = digits, format = "f")) 128 | } 129 | } else { 130 | num_fun <- FUN 131 | } 132 | return(num_fun) 133 | } 134 | .summary_functions2 = function(FUN2, format_number, digits){ 135 | if (format_number){ 136 | f1 <- "," 137 | } else { 138 | f1 <- "" 139 | } 140 | ## Secondary Function 141 | if(is.null(FUN2)){ 142 | num_fun2 <- function(x){ 143 | gettextf("%s [%s]", 144 | formatC(median(x, na.rm=TRUE), big.mark = f1, digits = digits, format = "f"), 145 | formatC(IQR(x, na.rm=TRUE), big.mark = f1, digits = digits, format = "f")) 146 | } 147 | } else { 148 | num_fun2 <- FUN2 149 | } 150 | return(num_fun2) 151 | } 152 | 153 | 154 | ## Pipe 155 | `%>%` <- magrittr::`%>%` 156 | 157 | ## Group by 158 | group_by <- dplyr::group_by 159 | 160 | -------------------------------------------------------------------------------- /R/washer.R: -------------------------------------------------------------------------------- 1 | #' Wash Your Data 2 | #' 3 | #' Washes the data by replacing values with either NA's or other values set by the user. 4 | #' Useful for replacing values such as 777's or 999's that represent missing values in survey research. 5 | #' Can also perform many useful functions on factors (e.g., removing a level, replacing a level, etc.) 6 | #' 7 | #' @param x the variable to have values adjusted 8 | #' @param ... the values in the variable that are to be replaced by either NA's or the value set by the user. Can be a function (or multiple functions) to specify values to change (e.g., is.nan(), is.na()). 9 | #' @param value (optional) if specified, the values in ... will be replaced by this value (must be a single value) 10 | #' 11 | #' @return the original vector (although if the original was a factor, it was changed to a character) with the values changed where indicated. 12 | #' 13 | #' @examples 14 | #' x = c(1:20, NA, NaN) 15 | #' washer(x, 9, 10) 16 | #' washer(x, 9, 10, value=0) 17 | #' washer(x, 1:10) 18 | #' washer(x, is.na, is.nan, value=0) 19 | #' washer(x, is.na, is.nan, 1:3, value=0) 20 | #' 21 | #' @export 22 | washer <- function(x, ..., value=NA){ 23 | 24 | fct <- is.factor(x) 25 | 26 | for (i in seq_along(c(...))){ 27 | if (!is.function(c(...)[[i]])){ 28 | j <- c(...)[i] 29 | if (sum(x == j, na.rm=TRUE) > 0 && fct){ 30 | x <- as.character(x) 31 | } 32 | } 33 | } 34 | 35 | for (i in seq_along(c(...))){ 36 | if (is.function(c(...)[[i]])){ 37 | x[c(...)[[i]](x)] <- value 38 | } else { 39 | j <-c(...)[i] 40 | x[x == j] <- value 41 | } 42 | } 43 | 44 | if (fct){ 45 | x <- as.factor(x) 46 | } 47 | 48 | x 49 | } 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /R/zzz.R: -------------------------------------------------------------------------------- 1 | .onLoad <- function(libname = find.package("furniture"), 2 | pkgname = "furniture") { 3 | if (getRversion() >= "2.15.1") { 4 | utils::globalVariables(c(".", ".rows", ":=", "Characteristic", "comp")) 5 | } 6 | invisible() 7 | } 8 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r, echo = FALSE, message=FALSE, warning=FALSE} 8 | knitr::opts_chunk$set( 9 | collapse = TRUE, 10 | comment = "#>", 11 | fig.path = "README-" 12 | ) 13 | devtools::load_all() 14 | ``` 15 | 16 | 17 | [![CRAN Status Badge](https://www.r-pkg.org/badges/version/furniture)](https://cran.r-project.org/package=furniture) 18 | ![Downloads](https://cranlogs.r-pkg.org/badges/grand-total/furniture) 19 | [![R-CMD-check](https://github.com/TysonStanley/furniture/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/TysonStanley/furniture/actions/workflows/R-CMD-check.yaml) 20 | 21 | 22 | 23 | 24 | # furniture: `v1.10.0` 25 | 26 | The furniture R package contains functions to help with data cleaning/tidying (e.g., `washer()`, `rowmeans()`, `rowsums()`), exploratory data analysis and reporting (e.g., `table1()`, `tableC()`, `tableF()`). It currently contains eight main functions: 27 | 28 | 1. `table1()` : gives a well-formatted table for academic publication of descriptive statistics. Very useful for quick analyses as well. Notably, `table1()` now works with `dplyr::group_by()`. 29 | 2. `tableC()` : gives a well-formatted table of correlations. 30 | 3. `tableF()` : provides a thorough frequency table for quick checks of the levels of a variable. 31 | 4. `washer()` : changes several values in a variable (very useful for changing place holder values to missing). 32 | 5. `long()` : is a wrapper of `stats::reshape()`, takes the data from wide to long format (long is often the tidy version of the data), works well with the tidyverse, and can handle unbalanced multilevel data. 33 | 6. `wide()` : also a wrapper of `stats::reshape()`, takes the data from long to wide, and like `long()`, works well with the tidyverse and can handle unbalanced multilevel data. 34 | 7. `rowmeans()` and `rowmeans.n()` : tidyverse friendly versions of `rowMeans()`, where the `rowmeans.n()` function allows `n` number of missing 35 | 8. `rowsums()` and `rowsums.n()` : tidyverse friendly versions of `rowSums()`, where the `rowsums.n()` function allows `n` number of missing 36 | 37 | In conjunction with many other tidy tools, the package should be useful for health, behavioral, and social scientists working on quantitative research. 38 | 39 | # Installation 40 | 41 | The latest stable build of the package can be downloaded from CRAN via: 42 | 43 | ```{r, eval = FALSE} 44 | install.packages("furniture") 45 | ``` 46 | 47 | You can download the developmental version via: 48 | 49 | ```{r, eval = FALSE} 50 | remotes::install_github("tysonstanley/furniture") 51 | ``` 52 | 53 | # Using furniture 54 | 55 | The main functions are the `table*()` functions (e.g., `table1()`, `tableC()`, `tableF()`). 56 | 57 | ```{r} 58 | library(furniture) 59 | ``` 60 | 61 | ```{r} 62 | data("nhanes_2010") 63 | 64 | table1(nhanes_2010, 65 | age, marijuana, illicit, rehab, 66 | splitby=~asthma, 67 | na.rm = FALSE) 68 | ``` 69 | 70 | ```{r} 71 | table1(nhanes_2010, 72 | age, marijuana, illicit, rehab, 73 | splitby=~asthma, 74 | output = "text2", 75 | na.rm = FALSE) 76 | ``` 77 | 78 | ```{r, warning=FALSE, message=FALSE} 79 | library(tidyverse) 80 | nhanes_2010 %>% 81 | group_by(asthma) %>% 82 | table1(age, marijuana, illicit, rehab, 83 | output = "text2", 84 | na.rm = FALSE) 85 | ``` 86 | 87 | `table1()` can do bivariate significance tests as well. 88 | 89 | ```{r, warning=FALSE, message=FALSE} 90 | library(tidyverse) 91 | nhanes_2010 %>% 92 | group_by(asthma) %>% 93 | table1(age, marijuana, illicit, rehab, 94 | output = "text2", 95 | na.rm = FALSE, 96 | test = TRUE) 97 | ``` 98 | 99 | By default it does the appropriate parametric tests. However, you can change that by setting `param = FALSE` (new with `v 1.9.1`). 100 | 101 | ```{r, warning=FALSE, message=FALSE} 102 | library(tidyverse) 103 | nhanes_2010 %>% 104 | group_by(asthma) %>% 105 | table1(age, marijuana, illicit, rehab, 106 | output = "text2", 107 | na.rm = FALSE, 108 | test = TRUE, 109 | param = FALSE, 110 | type = "condense") 111 | ``` 112 | 113 | It can also do a total column with the stratified columns (new with `v 1.9.0`) with the `total = TRUE` argument. 114 | 115 | ```{r, warning=FALSE, message=FALSE} 116 | nhanes_2010 %>% 117 | group_by(asthma) %>% 118 | table1(age, marijuana, illicit, rehab, 119 | output = "text2", 120 | na.rm = FALSE, 121 | test = TRUE, 122 | type = "condense", 123 | total = TRUE) 124 | ``` 125 | 126 | It can also report the statistics in addition to the p-values. 127 | 128 | ```{r, warning=FALSE, message=FALSE} 129 | nhanes_2010 %>% 130 | group_by(asthma) %>% 131 | table1(age, marijuana, illicit, rehab, 132 | output = "text2", 133 | na.rm = FALSE, 134 | test = TRUE, 135 | total = TRUE, 136 | type = "full") 137 | ``` 138 | 139 | `table1()` can be outputted directly to other formats. All `knitr::kable()` options are available for this and there is an extra option `"latex2"` which provides a publication ready table in Latex documents. 140 | 141 | A new function `table1_gt()` integrates the fantastic `gt` package to make beautiful HTML tables for table1. 142 | 143 | ```{r, results='asis'} 144 | nhanes_2010 %>% 145 | group_by(asthma) %>% 146 | table1(age, marijuana, illicit, rehab, na.rm = FALSE) %>% 147 | table1_gt() %>% 148 | print() 149 | ``` 150 | 151 | 152 | 153 | 154 | The `tableC()` function gives a well-formatted correlation table. 155 | 156 | ```{r} 157 | tableC(nhanes_2010, 158 | age, active, vig_active, 159 | na.rm=TRUE) 160 | ``` 161 | 162 | The `tableF()` function gives a table of frequencies. 163 | 164 | ```{r} 165 | tableF(nhanes_2010, age) 166 | ``` 167 | 168 | In addition, the `rowmeans()` and `rowsums()` functions offer a simplified use of `rowMeans()` and `rowSums()`, particularly when using the tidyverse's `mutate()`. 169 | 170 | ```{r} 171 | nhanes_2010 %>% 172 | select(vig_active, mod_active) %>% 173 | mutate(avg_active = rowmeans(vig_active, mod_active, na.rm=TRUE)) %>% 174 | mutate(sum_active = rowsums(vig_active, mod_active, na.rm=TRUE)) %>% 175 | head() 176 | ``` 177 | 178 | The `rowmeans.n()` and `rowsums.n()` allow `n` missing values while still calculating the mean or sum. 179 | 180 | ```{r} 181 | df <- data.frame( 182 | x = c(NA, 1:5), 183 | y = c(1:5, NA) 184 | ) 185 | 186 | df %>% 187 | mutate(avg = rowmeans.n(x, y, n = 1)) 188 | ``` 189 | 190 | ## Notes 191 | 192 | The package is most useful in conjunction with other tidy tools to get data cleaned/tidied and start exploratory data analysis. I recommend using packages such as `library(dplyr)`, `library(tidyr)`, and `library(ggplot2)` with `library(furniture)` to accomplish this. 193 | 194 | The original function--`table1()`--is simply built for both exploratory descriptive analysis and communication of findings. See vignettes or [tysonbarrett.com](https://tysonstanley.github.io/) for several examples of its use. Also see our paper in the [R Journal](https://journal.r-project.org/archive/2017/RJ-2017-037/RJ-2017-037.pdf). 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## Test environments 2 | * local OS X install, R 4.3.1 3 | * ubuntu (GitHub Actions), R, R dev 4 | * windows (GitHub Actions) 5 | * win-builder R release, R dev 6 | 7 | ## R CMD check results 8 | There were no ERRORs, WARNINGs, or NOTEs. 9 | 10 | ## Downstream Dependencies 11 | Currently, there is one downstream dependency for this package 12 | (`MarginalMediation`). This package has been checked with no errors, 13 | warnings, or notes resulting from the changes to the `furniture` package. 14 | 15 | -------------------------------------------------------------------------------- /data/nhanes_2010.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TysonStanley/furniture/b4e81298929febe89ee7d19c01fc40459171a2b0/data/nhanes_2010.rda -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Page not found (404) • furniture 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | 21 | 22 | 23 |
24 |
69 | 70 | 71 | 72 | 73 |
74 |
75 | 78 | 79 | Content not found. Please use links in the navbar. 80 | 81 |
82 | 83 | 87 | 88 |
89 | 90 | 91 | 92 |
96 | 97 |
98 |

99 |

Site built with pkgdown 2.0.7.

100 |
101 | 102 |
103 |
104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /docs/articles/Furniture_files/accessible-code-block-0.0.1/empty-anchor.js: -------------------------------------------------------------------------------- 1 | // Hide empty tag within highlighted CodeBlock for screen reader accessibility (see https://github.com/jgm/pandoc/issues/6352#issuecomment-626106786) --> 2 | // v0.0.1 3 | // Written by JooYoung Seo (jooyoung@psu.edu) and Atsushi Yasumoto on June 1st, 2020. 4 | 5 | document.addEventListener('DOMContentLoaded', function() { 6 | const codeList = document.getElementsByClassName("sourceCode"); 7 | for (var i = 0; i < codeList.length; i++) { 8 | var linkList = codeList[i].getElementsByTagName('a'); 9 | for (var j = 0; j < linkList.length; j++) { 10 | if (linkList[j].innerHTML === "") { 11 | linkList[j].setAttribute('aria-hidden', 'true'); 12 | } 13 | } 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /docs/articles/Table1_files/accessible-code-block-0.0.1/empty-anchor.js: -------------------------------------------------------------------------------- 1 | // Hide empty tag within highlighted CodeBlock for screen reader accessibility (see https://github.com/jgm/pandoc/issues/6352#issuecomment-626106786) --> 2 | // v0.0.1 3 | // Written by JooYoung Seo (jooyoung@psu.edu) and Atsushi Yasumoto on June 1st, 2020. 4 | 5 | document.addEventListener('DOMContentLoaded', function() { 6 | const codeList = document.getElementsByClassName("sourceCode"); 7 | for (var i = 0; i < codeList.length; i++) { 8 | var linkList = codeList[i].getElementsByTagName('a'); 9 | for (var j = 0; j < linkList.length; j++) { 10 | if (linkList[j].innerHTML === "") { 11 | linkList[j].setAttribute('aria-hidden', 'true'); 12 | } 13 | } 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /docs/articles/Table1_files/figure-html/tidyverse-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TysonStanley/furniture/b4e81298929febe89ee7d19c01fc40459171a2b0/docs/articles/Table1_files/figure-html/tidyverse-1.png -------------------------------------------------------------------------------- /docs/articles/index.html: -------------------------------------------------------------------------------- 1 | 2 | Articles • furniture 6 | 7 | 8 |
9 |
47 | 48 | 49 | 50 |
51 |
52 | 55 | 56 |
57 |

All vignettes

58 |

59 | 60 |
Furniture
61 |
62 |
Table 1
63 |
64 |
65 |
66 |
67 | 68 | 69 |
72 | 73 |
74 |

Site built with pkgdown 2.0.7.

75 |
76 | 77 |
78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /docs/authors.html: -------------------------------------------------------------------------------- 1 | 2 | Authors and Citation • furniture 6 | 7 | 8 |
9 |
47 | 48 | 49 | 50 |
51 |
52 |
53 | 56 | 57 | 58 |
  • 59 |

    Tyson S. Barrett. Author, maintainer. 60 |

    61 |
  • 62 |
  • 63 |

    Emily Brignone. Author. 64 |

    65 |
  • 66 |
  • 67 |

    Daniel J. Laxman. Author. 68 |

    69 |
  • 70 |
71 |
72 |
73 |

Citation

74 | 75 |
76 |
77 | 78 | 79 |

Barrett T, Brignone E (2017). 80 | “Furniture for Quantitative Scientists.” 81 | The R Journal, 9(2), 142–148. 82 | doi:10.32614/RJ-2017-037, https://journal.r-project.org/archive/2017/RJ-2017-037/RJ-2017-037.pdf. 83 |

84 |
@Article{RJ-2017-037,
 85 |   title = {Furniture for Quantitative Scientists},
 86 |   author = {Tyson S. Barrett and Emily Brignone},
 87 |   year = {2017},
 88 |   journal = {The R Journal},
 89 |   volume = {9},
 90 |   number = {2},
 91 |   doi = {10.32614/RJ-2017-037},
 92 |   url = {https://journal.r-project.org/archive/2017/RJ-2017-037/RJ-2017-037.pdf},
 93 |   pages = {142--148},
 94 | }
95 | 96 |
97 | 98 |
99 | 100 | 101 | 102 |
105 | 106 |
107 |

Site built with pkgdown 2.0.7.

108 |
109 | 110 |
111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /docs/bootstrap-toc.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) 3 | * Copyright 2015 Aidan Feldman 4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ 5 | 6 | /* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */ 7 | 8 | /* All levels of nav */ 9 | nav[data-toggle='toc'] .nav > li > a { 10 | display: block; 11 | padding: 4px 20px; 12 | font-size: 13px; 13 | font-weight: 500; 14 | color: #767676; 15 | } 16 | nav[data-toggle='toc'] .nav > li > a:hover, 17 | nav[data-toggle='toc'] .nav > li > a:focus { 18 | padding-left: 19px; 19 | color: #563d7c; 20 | text-decoration: none; 21 | background-color: transparent; 22 | border-left: 1px solid #563d7c; 23 | } 24 | nav[data-toggle='toc'] .nav > .active > a, 25 | nav[data-toggle='toc'] .nav > .active:hover > a, 26 | nav[data-toggle='toc'] .nav > .active:focus > a { 27 | padding-left: 18px; 28 | font-weight: bold; 29 | color: #563d7c; 30 | background-color: transparent; 31 | border-left: 2px solid #563d7c; 32 | } 33 | 34 | /* Nav: second level (shown on .active) */ 35 | nav[data-toggle='toc'] .nav .nav { 36 | display: none; /* Hide by default, but at >768px, show it */ 37 | padding-bottom: 10px; 38 | } 39 | nav[data-toggle='toc'] .nav .nav > li > a { 40 | padding-top: 1px; 41 | padding-bottom: 1px; 42 | padding-left: 30px; 43 | font-size: 12px; 44 | font-weight: normal; 45 | } 46 | nav[data-toggle='toc'] .nav .nav > li > a:hover, 47 | nav[data-toggle='toc'] .nav .nav > li > a:focus { 48 | padding-left: 29px; 49 | } 50 | nav[data-toggle='toc'] .nav .nav > .active > a, 51 | nav[data-toggle='toc'] .nav .nav > .active:hover > a, 52 | nav[data-toggle='toc'] .nav .nav > .active:focus > a { 53 | padding-left: 28px; 54 | font-weight: 500; 55 | } 56 | 57 | /* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */ 58 | nav[data-toggle='toc'] .nav > .active > ul { 59 | display: block; 60 | } 61 | -------------------------------------------------------------------------------- /docs/bootstrap-toc.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) 3 | * Copyright 2015 Aidan Feldman 4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ 5 | (function() { 6 | 'use strict'; 7 | 8 | window.Toc = { 9 | helpers: { 10 | // return all matching elements in the set, or their descendants 11 | findOrFilter: function($el, selector) { 12 | // http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/ 13 | // http://stackoverflow.com/a/12731439/358804 14 | var $descendants = $el.find(selector); 15 | return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])'); 16 | }, 17 | 18 | generateUniqueIdBase: function(el) { 19 | var text = $(el).text(); 20 | var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-'); 21 | return anchor || el.tagName.toLowerCase(); 22 | }, 23 | 24 | generateUniqueId: function(el) { 25 | var anchorBase = this.generateUniqueIdBase(el); 26 | for (var i = 0; ; i++) { 27 | var anchor = anchorBase; 28 | if (i > 0) { 29 | // add suffix 30 | anchor += '-' + i; 31 | } 32 | // check if ID already exists 33 | if (!document.getElementById(anchor)) { 34 | return anchor; 35 | } 36 | } 37 | }, 38 | 39 | generateAnchor: function(el) { 40 | if (el.id) { 41 | return el.id; 42 | } else { 43 | var anchor = this.generateUniqueId(el); 44 | el.id = anchor; 45 | return anchor; 46 | } 47 | }, 48 | 49 | createNavList: function() { 50 | return $(''); 51 | }, 52 | 53 | createChildNavList: function($parent) { 54 | var $childList = this.createNavList(); 55 | $parent.append($childList); 56 | return $childList; 57 | }, 58 | 59 | generateNavEl: function(anchor, text) { 60 | var $a = $(''); 61 | $a.attr('href', '#' + anchor); 62 | $a.text(text); 63 | var $li = $('
  • '); 64 | $li.append($a); 65 | return $li; 66 | }, 67 | 68 | generateNavItem: function(headingEl) { 69 | var anchor = this.generateAnchor(headingEl); 70 | var $heading = $(headingEl); 71 | var text = $heading.data('toc-text') || $heading.text(); 72 | return this.generateNavEl(anchor, text); 73 | }, 74 | 75 | // Find the first heading level (`

    `, then `

    `, etc.) that has more than one element. Defaults to 1 (for `

    `). 76 | getTopLevel: function($scope) { 77 | for (var i = 1; i <= 6; i++) { 78 | var $headings = this.findOrFilter($scope, 'h' + i); 79 | if ($headings.length > 1) { 80 | return i; 81 | } 82 | } 83 | 84 | return 1; 85 | }, 86 | 87 | // returns the elements for the top level, and the next below it 88 | getHeadings: function($scope, topLevel) { 89 | var topSelector = 'h' + topLevel; 90 | 91 | var secondaryLevel = topLevel + 1; 92 | var secondarySelector = 'h' + secondaryLevel; 93 | 94 | return this.findOrFilter($scope, topSelector + ',' + secondarySelector); 95 | }, 96 | 97 | getNavLevel: function(el) { 98 | return parseInt(el.tagName.charAt(1), 10); 99 | }, 100 | 101 | populateNav: function($topContext, topLevel, $headings) { 102 | var $context = $topContext; 103 | var $prevNav; 104 | 105 | var helpers = this; 106 | $headings.each(function(i, el) { 107 | var $newNav = helpers.generateNavItem(el); 108 | var navLevel = helpers.getNavLevel(el); 109 | 110 | // determine the proper $context 111 | if (navLevel === topLevel) { 112 | // use top level 113 | $context = $topContext; 114 | } else if ($prevNav && $context === $topContext) { 115 | // create a new level of the tree and switch to it 116 | $context = helpers.createChildNavList($prevNav); 117 | } // else use the current $context 118 | 119 | $context.append($newNav); 120 | 121 | $prevNav = $newNav; 122 | }); 123 | }, 124 | 125 | parseOps: function(arg) { 126 | var opts; 127 | if (arg.jquery) { 128 | opts = { 129 | $nav: arg 130 | }; 131 | } else { 132 | opts = arg; 133 | } 134 | opts.$scope = opts.$scope || $(document.body); 135 | return opts; 136 | } 137 | }, 138 | 139 | // accepts a jQuery object, or an options object 140 | init: function(opts) { 141 | opts = this.helpers.parseOps(opts); 142 | 143 | // ensure that the data attribute is in place for styling 144 | opts.$nav.attr('data-toggle', 'toc'); 145 | 146 | var $topContext = this.helpers.createChildNavList(opts.$nav); 147 | var topLevel = this.helpers.getTopLevel(opts.$scope); 148 | var $headings = this.helpers.getHeadings(opts.$scope, topLevel); 149 | this.helpers.populateNav($topContext, topLevel, $headings); 150 | } 151 | }; 152 | 153 | $(function() { 154 | $('nav[data-toggle="toc"]').each(function(i, el) { 155 | var $nav = $(el); 156 | Toc.init($nav); 157 | }); 158 | }); 159 | })(); 160 | -------------------------------------------------------------------------------- /docs/docsearch.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | // register a handler to move the focus to the search bar 4 | // upon pressing shift + "/" (i.e. "?") 5 | $(document).on('keydown', function(e) { 6 | if (e.shiftKey && e.keyCode == 191) { 7 | e.preventDefault(); 8 | $("#search-input").focus(); 9 | } 10 | }); 11 | 12 | $(document).ready(function() { 13 | // do keyword highlighting 14 | /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */ 15 | var mark = function() { 16 | 17 | var referrer = document.URL ; 18 | var paramKey = "q" ; 19 | 20 | if (referrer.indexOf("?") !== -1) { 21 | var qs = referrer.substr(referrer.indexOf('?') + 1); 22 | var qs_noanchor = qs.split('#')[0]; 23 | var qsa = qs_noanchor.split('&'); 24 | var keyword = ""; 25 | 26 | for (var i = 0; i < qsa.length; i++) { 27 | var currentParam = qsa[i].split('='); 28 | 29 | if (currentParam.length !== 2) { 30 | continue; 31 | } 32 | 33 | if (currentParam[0] == paramKey) { 34 | keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20")); 35 | } 36 | } 37 | 38 | if (keyword !== "") { 39 | $(".contents").unmark({ 40 | done: function() { 41 | $(".contents").mark(keyword); 42 | } 43 | }); 44 | } 45 | } 46 | }; 47 | 48 | mark(); 49 | }); 50 | }); 51 | 52 | /* Search term highlighting ------------------------------*/ 53 | 54 | function matchedWords(hit) { 55 | var words = []; 56 | 57 | var hierarchy = hit._highlightResult.hierarchy; 58 | // loop to fetch from lvl0, lvl1, etc. 59 | for (var idx in hierarchy) { 60 | words = words.concat(hierarchy[idx].matchedWords); 61 | } 62 | 63 | var content = hit._highlightResult.content; 64 | if (content) { 65 | words = words.concat(content.matchedWords); 66 | } 67 | 68 | // return unique words 69 | var words_uniq = [...new Set(words)]; 70 | return words_uniq; 71 | } 72 | 73 | function updateHitURL(hit) { 74 | 75 | var words = matchedWords(hit); 76 | var url = ""; 77 | 78 | if (hit.anchor) { 79 | url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor; 80 | } else { 81 | url = hit.url + '?q=' + escape(words.join(" ")); 82 | } 83 | 84 | return url; 85 | } 86 | -------------------------------------------------------------------------------- /docs/jquery.sticky-kit.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net 3 | */ 4 | (function(){var b,f;b=this.jQuery||window.jQuery;f=b(window);b.fn.stick_in_parent=function(d){var A,w,J,n,B,K,p,q,k,E,t;null==d&&(d={});t=d.sticky_class;B=d.inner_scrolling;E=d.recalc_every;k=d.parent;q=d.offset_top;p=d.spacer;w=d.bottoming;null==q&&(q=0);null==k&&(k=void 0);null==B&&(B=!0);null==t&&(t="is_stuck");A=b(document);null==w&&(w=!0);J=function(a,d,n,C,F,u,r,G){var v,H,m,D,I,c,g,x,y,z,h,l;if(!a.data("sticky_kit")){a.data("sticky_kit",!0);I=A.height();g=a.parent();null!=k&&(g=g.closest(k)); 5 | if(!g.length)throw"failed to find stick parent";v=m=!1;(h=null!=p?p&&a.closest(p):b("
    "))&&h.css("position",a.css("position"));x=function(){var c,f,e;if(!G&&(I=A.height(),c=parseInt(g.css("border-top-width"),10),f=parseInt(g.css("padding-top"),10),d=parseInt(g.css("padding-bottom"),10),n=g.offset().top+c+f,C=g.height(),m&&(v=m=!1,null==p&&(a.insertAfter(h),h.detach()),a.css({position:"",top:"",width:"",bottom:""}).removeClass(t),e=!0),F=a.offset().top-(parseInt(a.css("margin-top"),10)||0)-q, 6 | u=a.outerHeight(!0),r=a.css("float"),h&&h.css({width:a.outerWidth(!0),height:u,display:a.css("display"),"vertical-align":a.css("vertical-align"),"float":r}),e))return l()};x();if(u!==C)return D=void 0,c=q,z=E,l=function(){var b,l,e,k;if(!G&&(e=!1,null!=z&&(--z,0>=z&&(z=E,x(),e=!0)),e||A.height()===I||x(),e=f.scrollTop(),null!=D&&(l=e-D),D=e,m?(w&&(k=e+u+c>C+n,v&&!k&&(v=!1,a.css({position:"fixed",bottom:"",top:c}).trigger("sticky_kit:unbottom"))),eb&&!v&&(c-=l,c=Math.max(b-u,c),c=Math.min(q,c),m&&a.css({top:c+"px"})))):e>F&&(m=!0,b={position:"fixed",top:c},b.width="border-box"===a.css("box-sizing")?a.outerWidth()+"px":a.width()+"px",a.css(b).addClass(t),null==p&&(a.after(h),"left"!==r&&"right"!==r||h.append(a)),a.trigger("sticky_kit:stick")),m&&w&&(null==k&&(k=e+u+c>C+n),!v&&k)))return v=!0,"static"===g.css("position")&&g.css({position:"relative"}), 8 | a.css({position:"absolute",bottom:d,top:"auto"}).trigger("sticky_kit:bottom")},y=function(){x();return l()},H=function(){G=!0;f.off("touchmove",l);f.off("scroll",l);f.off("resize",y);b(document.body).off("sticky_kit:recalc",y);a.off("sticky_kit:detach",H);a.removeData("sticky_kit");a.css({position:"",bottom:"",top:"",width:""});g.position("position","");if(m)return null==p&&("left"!==r&&"right"!==r||a.insertAfter(h),h.remove()),a.removeClass(t)},f.on("touchmove",l),f.on("scroll",l),f.on("resize", 9 | y),b(document.body).on("sticky_kit:recalc",y),a.on("sticky_kit:detach",H),setTimeout(l,0)}};n=0;for(K=this.length;n 2 | 3 | 5 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /docs/pkgdown.js: -------------------------------------------------------------------------------- 1 | /* http://gregfranko.com/blog/jquery-best-practices/ */ 2 | (function($) { 3 | $(function() { 4 | 5 | $('.navbar-fixed-top').headroom(); 6 | 7 | $('body').css('padding-top', $('.navbar').height() + 10); 8 | $(window).resize(function(){ 9 | $('body').css('padding-top', $('.navbar').height() + 10); 10 | }); 11 | 12 | $('[data-toggle="tooltip"]').tooltip(); 13 | 14 | var cur_path = paths(location.pathname); 15 | var links = $("#navbar ul li a"); 16 | var max_length = -1; 17 | var pos = -1; 18 | for (var i = 0; i < links.length; i++) { 19 | if (links[i].getAttribute("href") === "#") 20 | continue; 21 | // Ignore external links 22 | if (links[i].host !== location.host) 23 | continue; 24 | 25 | var nav_path = paths(links[i].pathname); 26 | 27 | var length = prefix_length(nav_path, cur_path); 28 | if (length > max_length) { 29 | max_length = length; 30 | pos = i; 31 | } 32 | } 33 | 34 | // Add class to parent
  • , and enclosing
  • if in dropdown 35 | if (pos >= 0) { 36 | var menu_anchor = $(links[pos]); 37 | menu_anchor.parent().addClass("active"); 38 | menu_anchor.closest("li.dropdown").addClass("active"); 39 | } 40 | }); 41 | 42 | function paths(pathname) { 43 | var pieces = pathname.split("/"); 44 | pieces.shift(); // always starts with / 45 | 46 | var end = pieces[pieces.length - 1]; 47 | if (end === "index.html" || end === "") 48 | pieces.pop(); 49 | return(pieces); 50 | } 51 | 52 | // Returns -1 if not found 53 | function prefix_length(needle, haystack) { 54 | if (needle.length > haystack.length) 55 | return(-1); 56 | 57 | // Special case for length-0 haystack, since for loop won't run 58 | if (haystack.length === 0) { 59 | return(needle.length === 0 ? 0 : -1); 60 | } 61 | 62 | for (var i = 0; i < haystack.length; i++) { 63 | if (needle[i] != haystack[i]) 64 | return(i); 65 | } 66 | 67 | return(haystack.length); 68 | } 69 | 70 | /* Clipboard --------------------------*/ 71 | 72 | function changeTooltipMessage(element, msg) { 73 | var tooltipOriginalTitle=element.getAttribute('data-original-title'); 74 | element.setAttribute('data-original-title', msg); 75 | $(element).tooltip('show'); 76 | element.setAttribute('data-original-title', tooltipOriginalTitle); 77 | } 78 | 79 | if(ClipboardJS.isSupported()) { 80 | $(document).ready(function() { 81 | var copyButton = ""; 82 | 83 | $("div.sourceCode").addClass("hasCopyButton"); 84 | 85 | // Insert copy buttons: 86 | $(copyButton).prependTo(".hasCopyButton"); 87 | 88 | // Initialize tooltips: 89 | $('.btn-copy-ex').tooltip({container: 'body'}); 90 | 91 | // Initialize clipboard: 92 | var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', { 93 | text: function(trigger) { 94 | return trigger.parentNode.textContent.replace(/\n#>[^\n]*/g, ""); 95 | } 96 | }); 97 | 98 | clipboardBtnCopies.on('success', function(e) { 99 | changeTooltipMessage(e.trigger, 'Copied!'); 100 | e.clearSelection(); 101 | }); 102 | 103 | clipboardBtnCopies.on('error', function() { 104 | changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); 105 | }); 106 | }); 107 | } 108 | })(window.jQuery || window.$) 109 | -------------------------------------------------------------------------------- /docs/pkgdown.yml: -------------------------------------------------------------------------------- 1 | pandoc: 3.1.1 2 | pkgdown: 2.0.7 3 | pkgdown_sha: ~ 4 | articles: 5 | Furniture: Furniture.html 6 | Table1: Table1.html 7 | last_built: 2023-09-04T20:31Z 8 | 9 | -------------------------------------------------------------------------------- /docs/reference/Rplot001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TysonStanley/furniture/b4e81298929febe89ee7d19c01fc40459171a2b0/docs/reference/Rplot001.png -------------------------------------------------------------------------------- /docs/reference/figures/furniture_hex.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TysonStanley/furniture/b4e81298929febe89ee7d19c01fc40459171a2b0/docs/reference/figures/furniture_hex.jpg -------------------------------------------------------------------------------- /docs/reference/figures/furniture_hex.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TysonStanley/furniture/b4e81298929febe89ee7d19c01fc40459171a2b0/docs/reference/figures/furniture_hex.pdf -------------------------------------------------------------------------------- /docs/reference/figures/furniture_hex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TysonStanley/furniture/b4e81298929febe89ee7d19c01fc40459171a2b0/docs/reference/figures/furniture_hex.png -------------------------------------------------------------------------------- /docs/reference/figures/furniture_hex_v2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TysonStanley/furniture/b4e81298929febe89ee7d19c01fc40459171a2b0/docs/reference/figures/furniture_hex_v2.pdf -------------------------------------------------------------------------------- /docs/reference/figures/furniture_hex_v2_full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TysonStanley/furniture/b4e81298929febe89ee7d19c01fc40459171a2b0/docs/reference/figures/furniture_hex_v2_full.png -------------------------------------------------------------------------------- /docs/reference/figures/furniture_hex_v2_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TysonStanley/furniture/b4e81298929febe89ee7d19c01fc40459171a2b0/docs/reference/figures/furniture_hex_v2_small.png -------------------------------------------------------------------------------- /docs/reference/grapes-xt-grapes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Simple Crosstabs Operator — %xt% • furniture 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 48 | 49 | 50 | 51 | 52 | 53 |
    54 |
    55 | 108 | 109 | 110 |
    111 | 112 |
    113 |
    114 | 119 | 120 |
    121 | 122 |

    This operator takes two variables and computes a simple cross tab.

    123 | 124 |
    125 | 126 |
    lhs %xt% rhs
    127 | 128 |

    Arguments

    129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 |
    lhs

    the left hand side of the operator, a vector

    rhs

    the right hand side of the operator, a vector

    140 | 141 | 142 |

    Examples

    143 |
    144 | b = c(1,0,0,1,1,0,1,1,1,0) 145 | x = c(1,2,3,2,3,3,1,0,0,0) 146 | y = rnorm(10) 147 | z = c("Yes", "No", "Yes", "No", "No", "Yes", "No", "No", "Yes", "No") 148 | 149 | factor(x) %xt% factor(b)
    #> Warning: `%xt%` is now deprecated. Please use tableX() or tableF() instead.
    #> Error in factor(x): object 'x' not found
    150 |
    151 |
    152 | 161 |
    162 | 163 |
    164 | 167 | 168 |
    169 |

    Site built with pkgdown 1.3.0.

    170 |
    171 |
    172 |
    173 | 174 | 175 | 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /docs/reference/group_by.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | re-export dplyr group_by function — group_by • furniture 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 47 | 48 | 49 | 50 | 51 | 52 |
    53 |
    54 | 106 | 107 | 108 |
    109 | 110 |
    111 |
    112 | 117 | 118 |
    119 | 120 |

    re-export dplyr group_by function

    121 | 122 |
    123 | 124 | 125 | 126 |
    127 | 133 |
    134 | 135 |
    136 | 139 | 140 |
    141 |

    Site built with pkgdown.

    142 |
    143 | 144 |
    145 |
    146 | 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /docs/reference/index.html: -------------------------------------------------------------------------------- 1 | 2 | Function reference • furniture 6 | 7 | 8 |
    9 |
    47 | 48 | 49 | 50 |
    51 |
    52 | 55 | 56 | 60 | 63 | 64 | 67 | 68 | 71 | 72 | 75 | 76 | 79 | 80 | 83 | 84 | 87 | 88 | 91 | 92 | 95 | 96 | 99 | 100 | 103 | 104 | 107 | 108 | 111 | 112 | 115 | 116 |
    57 |

    All functions

    58 |

    59 |
    61 |

    furniture furniture-package

    62 |

    furniture

    65 |

    long()

    66 |

    Wide to Long Data Reshaping

    69 |

    nhanes_2010

    70 |

    NHANES 2009-2010

    73 |

    rowmeans()

    74 |

    Get Row Means

    77 |

    rowmeans.n()

    78 |

    Get Row Means With N Missing Values Per Row

    81 |

    rowsums()

    82 |

    Get Row Sums

    85 |

    rowsums.n()

    86 |

    Get Row Sums With N Missing Values Per Row

    89 |

    table1()

    90 |

    Table 1 for Simple and Stratified Descriptive Statistics

    93 |

    tableC()

    94 |

    Correlation Table

    97 |

    tableF()

    98 |

    Frequency Table

    101 |

    tableX()

    102 |

    Table X (for Cross-Tabs)

    105 |

    to_latex()

    106 |

    From Table 1 to Latex 2

    109 |

    washer()

    110 |

    Wash Your Data

    113 |

    wide()

    114 |

    Long to Wide Data Reshaping

    117 | 118 | 121 |
    122 | 123 | 124 |
    127 | 128 |
    129 |

    Site built with pkgdown 2.0.7.

    130 |
    131 | 132 |
    133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /docs/reference/mutate_rowmeans.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Get Row Means within a Pipe — mutate_rowmeans • furniture 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 54 | 55 | 56 | 57 | 58 | 59 | 60 |
    61 |
    62 | 114 | 115 | 116 | 117 |
    118 | 119 |
    120 |
    121 | 126 | 127 |
    128 |

    Does what rowMeans() does can be used one its own without dplyr::mutate() 129 | within a pipe.

    130 |
    131 | 132 |
    mutate_rowmeans(data, new_var, ..., na.rm = FALSE)
    133 | 134 |

    Arguments

    135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 |
    data

    the dataframe that contains the variables to get the row means from

    new_var

    the name of the new variable for which you'll put the row means in quotes

    ...

    the variables (unquoted) to be included in the row means

    na.rm

    should the missing values be ignored? default is FALSE

    154 | 155 |

    Value

    156 | 157 |

    the row means included within the data.frame

    158 | 159 |
    160 | 168 |
    169 | 170 | 171 |
    172 | 175 | 176 |
    177 |

    Site built with pkgdown 1.4.1.

    178 |
    179 | 180 |
    181 |
    182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /docs/reference/mutate_rowsums.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Get Row Sums within a Pipe — mutate_rowsums • furniture 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 54 | 55 | 56 | 57 | 58 | 59 | 60 |
    61 |
    62 | 114 | 115 | 116 | 117 |
    118 | 119 |
    120 |
    121 | 126 | 127 |
    128 |

    Does what rowSums() does can be used one its own without dplyr::mutate() 129 | within a pipe.

    130 |
    131 | 132 |
    mutate_rowsums(data, new_var, ..., na.rm = FALSE)
    133 | 134 |

    Arguments

    135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 |
    data

    the dataframe that contains the variables to get the row means from

    new_var

    the name of the new variable for which you'll put the row means in quotes

    ...

    the variables (unquoted) to be included in the row means

    na.rm

    should the missing values be ignored? default is FALSE

    154 | 155 |

    Value

    156 | 157 |

    the row means included within the data.frame

    158 | 159 |
    160 | 168 |
    169 | 170 | 171 |
    172 | 175 | 176 |
    177 |

    Site built with pkgdown 1.4.1.

    178 |
    179 | 180 |
    181 |
    182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /docs/reference/pipe.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | re-export magrittr pipe operator — %>% • furniture 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 47 | 48 | 49 | 50 | 51 | 52 |
    53 |
    54 | 106 | 107 | 108 |
    109 | 110 |
    111 |
    112 | 117 | 118 |
    119 | 120 |

    re-export magrittr pipe operator

    121 | 122 |
    123 | 124 | 125 | 126 |
    127 | 133 |
    134 | 135 |
    136 | 139 | 140 |
    141 |

    Site built with pkgdown.

    142 |
    143 | 144 |
    145 |
    146 | 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /docs/reference/selecting.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Selecting Function — selecting • furniture 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 50 | 51 | 52 | 53 | 54 | 55 |
    56 |
    57 | 110 | 111 | 112 |
    113 | 114 |
    115 |
    116 | 121 | 122 |
    123 | 124 |

    For internal use in table1() and tableC() to extract the right data. 125 | Can also be used much like dplyr::select(), although I'd recommend 126 | one to use dplyr::select() in general.

    127 | 128 |
    129 | 130 |
    selecting(d_, ...)
    131 | 132 |

    Arguments

    133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 |
    d_

    the data.frame

    ...

    the variables

    144 | 145 |

    Value

    146 | 147 |

    The data.frame with the selected variables

    148 | 149 | 150 |
    151 | 160 |
    161 | 162 |
    163 | 166 | 167 |
    168 |

    Site built with pkgdown 1.3.0.

    169 |
    170 |
    171 |
    172 | 173 | 174 | 175 | 176 | 177 | 178 | -------------------------------------------------------------------------------- /docs/reference/table1_format_condense.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Internal Table 1 Formatting Function (Condense) — table1_format_condense • furniture 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 |
    41 |
    42 | 89 | 90 | 91 |
    92 | 93 |
    94 |
    95 | 98 | 99 | 100 |

    For internal use in table1() to format table with condensing.

    101 | 102 | 103 |
    table1_format_condense(d, tab, tab2, tests, test, NAkeep, rounding_perc,
    104 |   format_output, second, nams, simple, output, f1)
    105 | 106 |

    Arguments

    107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 |
    d

    the data

    tab

    the summary statistics

    tab2

    the secondary summary statistics

    tests

    the tests

    test

    whether there should be significance tests performed

    NAkeep

    logical; should we keep the NA's in factor variables

    rounding_perc

    the number of decimal places to round the percentages

    format_output

    the output to be displayed (see table1())

    second

    the list of variables to apply FUN2

    nams

    the variables to which FUN2 is to be applied

    simple

    only percentages to be produced?

    output

    how to print the table (see table1())

    f1

    the formatting of the numbers

    162 | 163 |

    Value

    164 | 165 |

    A data.frame

    166 | 167 | 168 |
    169 | 178 |
    179 | 180 |
    181 | 184 | 185 |
    186 |

    Site built with pkgdown.

    187 |
    188 | 189 |
    190 |
    191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /docs/reference/table1_format_nocondense.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Internal Table 1 Formatting Function (No Condense) — table1_format_nocondense • furniture 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 |
    41 |
    42 | 89 | 90 | 91 |
    92 | 93 |
    94 |
    95 | 98 | 99 | 100 |

    For internal use in table1() to format table without condensing.

    101 | 102 | 103 |
    table1_format_nocondense(d, tab, tab2, tests, test, NAkeep, rounding_perc,
    104 |   format_output, second, nams, simple, output, f1)
    105 | 106 |

    Arguments

    107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 |
    d

    the data

    tab

    the summary statistics

    tab2

    the secondary summary statistics

    tests

    the tests

    test

    whether there should be significance tests performed

    NAkeep

    logical; should we keep the NA's in factor variables

    rounding_perc

    the number of decimal places to round the percentages

    format_output

    the output to be displayed (see table1())

    second

    the list of variables to apply FUN2

    nams

    the variables to which FUN2 is to be applied

    simple

    only percentages to be produced?

    output

    how to print the table (see table1())

    f1

    the formatting of the numbers

    162 | 163 |

    Value

    164 | 165 |

    A data.frame

    166 | 167 | 168 |
    169 | 178 |
    179 | 180 |
    181 | 184 | 185 |
    186 |

    Site built with pkgdown.

    187 |
    188 | 189 |
    190 |
    191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /docs/reference/table1_summarizing.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Internal Table 1 Summarizing Function — table1_summarizing • furniture 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 |
    41 |
    42 | 89 | 90 | 91 |
    92 | 93 |
    94 |
    95 | 98 | 99 | 100 |

    For internal use in table1() to summarize data.

    101 | 102 | 103 |
    table1_summarizing(d, num_fun, num_fun2, second, row_wise, test, NAkeep)
    104 | 105 |

    Arguments

    106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 |
    d

    the data

    num_fun

    the summarizing function

    num_fun2

    the second summarizing function

    second

    the variables to which FUN2 is to be applied

    row_wise

    the way to compute the percentages

    test

    should significance tests be run?

    NAkeep

    whether NA's should be shown in the output of categorical variables

    137 | 138 |

    Value

    139 | 140 |

    A data.frame

    141 | 142 | 143 |
    144 | 153 |
    154 | 155 |
    156 | 159 | 160 |
    161 |

    Site built with pkgdown.

    162 |
    163 | 164 |
    165 |
    166 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /docs/reference/to_latex.html: -------------------------------------------------------------------------------- 1 | 2 | From Table 1 to Latex 2 — to_latex • furniture 6 | 7 | 8 |
    9 |
    47 | 48 | 49 | 50 |
    51 |
    52 | 57 | 58 |
    59 |

    Internal table1() and tableC() function for providing output = "latex2"

    60 |
    61 | 62 |
    63 |
    to_latex(
     64 |   tab,
     65 |   caption,
     66 |   align,
     67 |   len,
     68 |   splitby,
     69 |   float,
     70 |   booktabs,
     71 |   label,
     72 |   total = FALSE,
     73 |   cor_type = NULL
     74 | )
    75 |
    76 | 77 |
    78 |

    Arguments

    79 |
    tab
    80 |

    the table1 object

    81 | 82 | 83 |
    caption
    84 |

    caption character vector

    85 | 86 | 87 |
    align
    88 |

    align character vector

    89 | 90 | 91 |
    len
    92 |

    the number of levels of the grouping factor

    93 | 94 | 95 |
    splitby
    96 |

    the name of the grouping factor

    97 | 98 | 99 |
    float
    100 |

    argument for latex formatting

    101 | 102 | 103 |
    booktabs
    104 |

    add booktabs to latex table

    105 | 106 | 107 |
    label
    108 |

    latex label option

    109 | 110 | 111 |
    total
    112 |

    is there a total column (from Table 1) to be printed?

    113 | 114 | 115 |
    cor_type
    116 |

    optional argument regarding the correlation type (for tableC)

    117 | 118 |
    119 | 120 |
    121 | 124 |
    125 | 126 | 127 |
    130 | 131 |
    132 |

    Site built with pkgdown 2.0.7.

    133 |
    134 | 135 |
    136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /docs/reference/wide.html: -------------------------------------------------------------------------------- 1 | 2 | Long to Wide Data Reshaping — wide • furniture 7 | 8 | 9 |
    10 |
    48 | 49 | 50 | 51 |
    52 |
    53 | 58 | 59 |
    60 |

    wide() is a wrapper of stats::reshape() that takes the data 61 | from a long format to a wide format.

    62 |
    63 | 64 |
    65 |
    wide(data, v.names, timevar, id = NULL)
    66 |
    67 | 68 |
    69 |

    Arguments

    70 |
    data
    71 |

    the data.frame containing the wide format data

    72 | 73 | 74 |
    v.names
    75 |

    the variable names in quotes of the measures to be separated into multiple columns based on the time variable

    76 | 77 | 78 |
    timevar
    79 |

    the variable name in quotes of the time variable

    80 | 81 | 82 |
    id
    83 |

    the ID variable name in quotes

    84 | 85 |
    86 |
    87 |

    See also

    88 | 89 |
    90 |
    91 |

    Author

    92 |

    Tyson S. Barrett

    93 |
    94 | 95 |
    96 | 99 |
    100 | 101 | 102 |
    105 | 106 |
    107 |

    Site built with pkgdown 2.0.7.

    108 |
    109 | 110 |
    111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /docs/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /404.html 5 | 6 | 7 | /articles/Furniture.html 8 | 9 | 10 | /articles/Table1.html 11 | 12 | 13 | /articles/index.html 14 | 15 | 16 | /authors.html 17 | 18 | 19 | /index.html 20 | 21 | 22 | /news/index.html 23 | 24 | 25 | /reference/furniture.html 26 | 27 | 28 | /reference/grapes-xt-grapes.html 29 | 30 | 31 | /reference/group_by.html 32 | 33 | 34 | /reference/index.html 35 | 36 | 37 | /reference/long.html 38 | 39 | 40 | /reference/mutate_rowmeans.html 41 | 42 | 43 | /reference/mutate_rowsums.html 44 | 45 | 46 | /reference/nhanes_2010.html 47 | 48 | 49 | /reference/pipe.html 50 | 51 | 52 | /reference/rowmeans.html 53 | 54 | 55 | /reference/rowmeans.n.html 56 | 57 | 58 | /reference/rowsums.html 59 | 60 | 61 | /reference/rowsums.n.html 62 | 63 | 64 | /reference/selecting.html 65 | 66 | 67 | /reference/table1.html 68 | 69 | 70 | /reference/table1_format_condense.html 71 | 72 | 73 | /reference/table1_format_nocondense.html 74 | 75 | 76 | /reference/table1_summarizing.html 77 | 78 | 79 | /reference/tableC.html 80 | 81 | 82 | /reference/tableF.html 83 | 84 | 85 | /reference/tableX.html 86 | 87 | 88 | /reference/to_latex.html 89 | 90 | 91 | /reference/washer.html 92 | 93 | 94 | /reference/wide.html 95 | 96 | 97 | -------------------------------------------------------------------------------- /furniture.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: XeLaTeX 14 | 15 | BuildType: Package 16 | PackageUseDevtools: Yes 17 | PackageInstallArgs: --no-multiarch --with-keep.source 18 | -------------------------------------------------------------------------------- /inst/CITATION: -------------------------------------------------------------------------------- 1 | bibentry(bibtype = "Article", 2 | title = "Furniture for Quantitative Scientists", 3 | author = c(person("Tyson S.", "Barrett"), 4 | person("Emily", "Brignone")), 5 | year = "2017", 6 | journal = "The R Journal", 7 | volume = "9", 8 | number = "2", 9 | doi = "10.32614/RJ-2017-037", 10 | url = "https://journal.r-project.org/archive/2017/RJ-2017-037/RJ-2017-037.pdf", 11 | key = "RJ-2017-037", 12 | pages = "142--148") -------------------------------------------------------------------------------- /man/figures/furniture_hex_v2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TysonStanley/furniture/b4e81298929febe89ee7d19c01fc40459171a2b0/man/figures/furniture_hex_v2.pdf -------------------------------------------------------------------------------- /man/figures/furniture_hex_v2_full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TysonStanley/furniture/b4e81298929febe89ee7d19c01fc40459171a2b0/man/figures/furniture_hex_v2_full.png -------------------------------------------------------------------------------- /man/figures/furniture_hex_v2_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TysonStanley/furniture/b4e81298929febe89ee7d19c01fc40459171a2b0/man/figures/furniture_hex_v2_small.png -------------------------------------------------------------------------------- /man/furniture.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/furniture.R 3 | \docType{package} 4 | \name{furniture} 5 | \alias{furniture} 6 | \alias{furniture-package} 7 | \title{furniture} 8 | \description{ 9 | The furniture package offers simple functions (i.e. pieces of furniture) and 10 | an operator that are aimed at helping applied researchers explore and 11 | communicate their data as well as clean their data in a tidy way. The package 12 | follows similar semantics to the "tidyverse" packages. It contains several 13 | table functions (\code{table1()}) being the core one. 14 | } 15 | \details{ 16 | \itemize{ 17 | \item \code{table1} provides a well-formatted descriptive table often seen 18 | as table 1 in academic journals (also a version that simplifies the 19 | output is available as \code{simple_table1}), 20 | \item \code{washer} provides a simple way to clean up data where there are 21 | placeholder values, and 22 | \item \code{\%xt\%} is an operator that takes two factor variables and 23 | creates a cross tabulation and tests for significance via a 24 | chi-square test. 25 | } 26 | 27 | Table 1 is the main function in furniture. It is useful in both data 28 | exploration and data communication. With minimal cleaning, the outputted 29 | table can be put into an academic, peer reviewed journal manuscript. As such, 30 | it is very useful in exploring your data when you have a stratifying 31 | variable. For example, if you are exploring whether the means of several 32 | demographic and behavioral characteristics are related to a health condition, 33 | the health condition (i.e. "yes" or "no"; "low", "mid", or "high"; or a list 34 | of conditions) as the stratifying variable. With little code, you can test 35 | for associations and check means or counts by the stratifying variable. 36 | See the vignette for more information. 37 | 38 | Note: furniture is meant to make life more comfortable and beautiful. 39 | In like manner, this package is designed to be "furniture" for quantitative 40 | research. 41 | } 42 | \examples{ 43 | \dontrun{ 44 | 45 | library(furniture) 46 | 47 | ## Table 1 48 | data \%>\% 49 | table1(var1, var2, var3, 50 | splitby = ~groupvar, 51 | test = TRUE) 52 | 53 | ## Table F 54 | data \%>\% 55 | tableF(var1) 56 | 57 | ## Washer 58 | x = washer(x, 7, 8, 9) 59 | x = washer(x, is.na, value=0) 60 | 61 | } 62 | 63 | } 64 | \author{ 65 | \strong{Maintainer}: Tyson S. Barrett \email{t.barrett88@gmail.com} (\href{https://orcid.org/0000-0002-2137-1391}{ORCID}) 66 | 67 | Authors: 68 | \itemize{ 69 | \item Emily Brignone 70 | \item Daniel J. Laxman 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /man/long.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/long_wide.R 3 | \name{long} 4 | \alias{long} 5 | \title{Wide to Long Data Reshaping} 6 | \usage{ 7 | long( 8 | data, 9 | ..., 10 | v.names = NULL, 11 | id = NULL, 12 | timevar = NULL, 13 | times = NULL, 14 | sep = "" 15 | ) 16 | } 17 | \arguments{ 18 | \item{data}{the data.frame containing the wide format data} 19 | 20 | \item{...}{the variables that are time-varying that are to be placed in 21 | long format, needs to be in the format 22 | \code{c("x1", "x2"), c("z1", "z2"), etc.}. If the data is 23 | unbalanced (e.g., there are three time points measured for one variable but 24 | only two for another), using the placeholder variable \code{miss}, 25 | helps fix this.} 26 | 27 | \item{v.names}{a vector of the names for the newly created variables (length 28 | same as number of vectors in \code{varying})} 29 | 30 | \item{id}{the ID variable in quotes} 31 | 32 | \item{timevar}{the column with the "time" labels} 33 | 34 | \item{times}{the labels of the \code{timevar} (default is numeric)} 35 | 36 | \item{sep}{the separating character between the wide format variable names 37 | (default is \code{""}); e.g. "x1" and "x2" would create the variable name of 38 | "x"; only applicable if \code{v.names}} 39 | } 40 | \description{ 41 | \code{long()} is a wrapper of \code{stats::reshape()} that takes 42 | the data from a wide format to a long format. It can also handle unbalanced 43 | data (where some measures have different number of "time points"). 44 | } 45 | \examples{ 46 | 47 | x1 <- runif(1000) 48 | x2 <- runif(1000) 49 | x3 <- runif(1000) 50 | y1 <- rnorm(1000) 51 | y2 <- rnorm(1000) 52 | z <- factor(sample(c(0,1), 1000, replace=TRUE)) 53 | a <- factor(sample(c(1,2), 1000, replace=TRUE)) 54 | b <- factor(sample(c(1,2,3,4), 1000, replace=TRUE)) 55 | df <- data.frame(x1, x2, x3, y1, y2, z, a, b) 56 | 57 | ## "Balanced" Data 58 | ldf1 <- long(df, 59 | c("x1", "x2"), c("y1", "y2"), 60 | v.names = c("x", "y")) 61 | 62 | ## "Unbalanced" Data 63 | ldf2 = long(df, 64 | c("x1", "x2", "x3"), c("y1", "y2", "miss"), 65 | v.names = c("x", "y")) 66 | 67 | 68 | } 69 | \seealso{ 70 | \code{stats::reshape()} and \code{sjmisc::to_long()} 71 | } 72 | \author{ 73 | Tyson S. Barrett 74 | } 75 | -------------------------------------------------------------------------------- /man/nhanes_2010.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/nhanes_data.R 3 | \docType{data} 4 | \name{nhanes_2010} 5 | \alias{nhanes_2010} 6 | \title{NHANES 2009-2010} 7 | \format{ 8 | A data frame with 1417 rows and 24 variables: 9 | \describe{ 10 | \item{id}{individual ID} 11 | \item{gen_health}{general health indicator with five levels} 12 | \item{mod_active}{minutes of moderate activity} 13 | \item{vig_active}{minutes of vigorous activity} 14 | \item{home_meals}{number of home meals a week} 15 | \item{gender}{gender of the individual (factor with "male" or "female")} 16 | \item{age}{age of the individual in years} 17 | \item{marijuana}{whether the individual has used marijuana} 18 | \item{illicit}{whether the individual has used illicit drugs} 19 | \item{rehab}{whether the individual has been to rehab for their drug usage} 20 | \item{asthma}{whether the individual has asthma} 21 | \item{overweight}{whether the individual is overweight} 22 | \item{cancer}{whether the individual has cancer} 23 | \item{low_int}{rating of whether the individual has low interest in things} 24 | \item{down}{rating of whether the individual has felt down} 25 | \item{sleeping}{rating of whether the individual has had trouble sleeping} 26 | \item{low_energy}{rating of whether the individual has low energy} 27 | \item{appetite}{rating of whether the individual has lost appetite} 28 | \item{feel_bad}{rating of whether the individual has felt bad} 29 | \item{no_con}{rating of whether the individual has felt no confidence} 30 | \item{speak_move}{rating of whether the individual has trouble speaking/moving} 31 | \item{dead}{rating of whether the individual has wished he/she was dead} 32 | \item{difficulty}{rating of whether the individual has felt difficulty from the previous conditions} 33 | \item{active}{minutes of vigorous or moderate activity} 34 | } 35 | } 36 | \source{ 37 | \url{https://wwwn.cdc.gov/nchs/nhanes/continuousnhanes/default.aspx?BeginYear=2009} 38 | } 39 | \usage{ 40 | nhanes_2010 41 | } 42 | \description{ 43 | A dataset containing information on health, healthcare, and demographics of adolescents 44 | aged 18 - 30 in the United States from 2009 to 2010. This is a cleaned dataset 45 | which is only a subset of the 2009-2010 data release of 46 | the National Health and Nutrition Examination Survey (NHANES). 47 | } 48 | \keyword{datasets} 49 | -------------------------------------------------------------------------------- /man/rowmeans.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rowmeans.R 3 | \name{rowmeans} 4 | \alias{rowmeans} 5 | \title{Get Row Means} 6 | \usage{ 7 | rowmeans(..., na.rm = FALSE) 8 | } 9 | \arguments{ 10 | \item{...}{the variables (unquoted) to be included in the row means} 11 | 12 | \item{na.rm}{should the missing values be ignored? default is FALSE} 13 | } 14 | \value{ 15 | the row means 16 | } 17 | \description{ 18 | Does what \code{rowMeans()} does but without having to cbind the variables. Makes it easier to use 19 | with the tidyverse 20 | } 21 | \examples{ 22 | 23 | \dontrun{ 24 | 25 | library(furniture) 26 | library(tidyverse) 27 | 28 | data <- data.frame( 29 | x = sample(c(1,2,3,4), 100, replace=TRUE), 30 | y = rnorm(100), 31 | z = rnorm(100) 32 | ) 33 | 34 | data2 <- data \%>\% 35 | mutate(y_z_mean = rowmeans(y, z)) 36 | data2 <- data \%>\% 37 | mutate(y_z_mean = rowmeans(y, z, na.rm=TRUE)) 38 | 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /man/rowmeans.n.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rowmeans.R 3 | \name{rowmeans.n} 4 | \alias{rowmeans.n} 5 | \title{Get Row Means With N Missing Values Per Row} 6 | \usage{ 7 | rowmeans.n(..., n) 8 | } 9 | \arguments{ 10 | \item{...}{the variables (unquoted) to be included in the row means} 11 | 12 | \item{n}{the number of values without missingness required to get the row mean} 13 | } 14 | \value{ 15 | the row means 16 | } 17 | \description{ 18 | Does what \code{furniture::rowmeans()} does while allowing a certain number (\code{n}) to have missing values. 19 | } 20 | \examples{ 21 | 22 | \dontrun{ 23 | 24 | library(furniture) 25 | library(dplyr) 26 | 27 | data <- data.frame( 28 | x = sample(c(1,2,3,4), 100, replace=TRUE), 29 | y = rnorm(100), 30 | z = rnorm(100) 31 | ) 32 | 33 | data2 <- mutate(data, x_y_z_mean = rowmeans.n(x, y, z, n = 2)) 34 | 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /man/rowsums.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rowmeans.R 3 | \name{rowsums} 4 | \alias{rowsums} 5 | \title{Get Row Sums} 6 | \usage{ 7 | rowsums(..., na.rm = FALSE) 8 | } 9 | \arguments{ 10 | \item{...}{the variables to be included in the row sums} 11 | 12 | \item{na.rm}{should the missing values be ignored? default is FALSE} 13 | } 14 | \value{ 15 | the row sums 16 | } 17 | \description{ 18 | Does what \code{rowSums()} does but without having to cbind the variables. Makes it easier to use 19 | with the tidyverse 20 | } 21 | \examples{ 22 | 23 | \dontrun{ 24 | 25 | library(furniture) 26 | library(tidyverse) 27 | 28 | data <- data.frame( 29 | x = sample(c(1,2,3,4), 100, replace=TRUE), 30 | y = rnorm(100), 31 | z = rnorm(100) 32 | ) 33 | 34 | data2 <- data \%>\% 35 | mutate(y_z_sum = rowsums(y, z)) 36 | data2 <- data \%>\% 37 | mutate(y_z_sum = rowsums(y, z, na.rm=TRUE)) 38 | 39 | } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /man/rowsums.n.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rowmeans.R 3 | \name{rowsums.n} 4 | \alias{rowsums.n} 5 | \title{Get Row Sums With N Missing Values Per Row} 6 | \usage{ 7 | rowsums.n(..., n) 8 | } 9 | \arguments{ 10 | \item{...}{the variables (unquoted) to be included in the row means} 11 | 12 | \item{n}{the number of values without missingness required to get the row mean} 13 | } 14 | \value{ 15 | the row sums 16 | } 17 | \description{ 18 | Does what \code{furniture::rowsums()} does while allowing a certain number (\code{n}) to have missing values. 19 | } 20 | \examples{ 21 | 22 | \dontrun{ 23 | 24 | library(furniture) 25 | library(dplyr) 26 | 27 | data <- data.frame( 28 | x = sample(c(1,2,3,4), 100, replace=TRUE), 29 | y = rnorm(100), 30 | z = rnorm(100) 31 | ) 32 | 33 | data2 <- mutate(data, x_y_z_mean = rowsums.n(x, y, z, n = 2)) 34 | 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /man/table1.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/Table1.R 3 | \name{table1} 4 | \alias{table1} 5 | \title{Table 1 for Simple and Stratified Descriptive Statistics} 6 | \usage{ 7 | table1( 8 | .data, 9 | ..., 10 | splitby = NULL, 11 | FUN = NULL, 12 | FUN2 = NULL, 13 | total = FALSE, 14 | second = NULL, 15 | row_wise = FALSE, 16 | test = FALSE, 17 | param = TRUE, 18 | header_labels = NULL, 19 | type = "pvalues", 20 | output = "text", 21 | rounding_perc = 1, 22 | digits = 1, 23 | var_names = NULL, 24 | format_number = FALSE, 25 | NAkeep = NULL, 26 | na.rm = TRUE, 27 | booktabs = TRUE, 28 | caption = NULL, 29 | align = NULL, 30 | float = "ht", 31 | export = NULL, 32 | label = NULL 33 | ) 34 | } 35 | \arguments{ 36 | \item{.data}{the data.frame that is to be summarized} 37 | 38 | \item{...}{variables in the data set that are to be summarized; unquoted names separated by commas (e.g. age, gender, race) or indices. If indices, it needs to be a single vector (e.g. c(1:5, 8, 9:20) instead of 1:5, 8, 9:20). As it is currently, it CANNOT handle both indices and unquoted names simultaneously. Finally, any empty rows (where the row is NA for each variable selected) will be removed for an accurate n count.} 39 | 40 | \item{splitby}{the categorical variable to stratify (in formula form \code{splitby = ~gender}) or quoted \code{splitby = "gender"}; instead, \code{dplyr::group_by(...)} can be used within a pipe (this is the default when the data object is a grouped data frame from \code{dplyr::group_by(...)}).} 41 | 42 | \item{FUN}{the function to be applied to summarize the numeric data; default is to report the means and standard deviations} 43 | 44 | \item{FUN2}{a secondary function to be applied to summarize the numeric data; default is to report the medians and 25\% and 75\% quartiles} 45 | 46 | \item{total}{whether a total (not stratified with the \code{splitby} or \code{group_by()}) should also be reported in the table} 47 | 48 | \item{second}{a vector or list of quoted continuous variables for which the \code{FUN2} should be applied} 49 | 50 | \item{row_wise}{how to calculate percentages for factor variables when \code{splitby != NULL}: if \code{FALSE} calculates percentages by variable within groups; if \code{TRUE} calculates percentages across groups for one level of the factor variable.} 51 | 52 | \item{test}{logical; if set to \code{TRUE} then the appropriate bivariate tests of significance are performed if splitby has more than 1 level. A message is printed when the variances of the continuous variables being tested do not meet the assumption of Homogeneity of Variance (using Breusch-Pagan Test of Heteroskedasticity) and, therefore, the argument `var.equal = FALSE` is used in the test.} 53 | 54 | \item{param}{logical; if set to \code{TRUE} then the appropriate parametric bivariate tests of significance are performed (if `test = TRUE`). For continuous variables, it is a t-test or ANOVA (depending on the number of levels of the group). If set to \code{FALSE}, the Kruskal-Wallis Rank Sum Test is performed for the continuous variables. Either way, the chi-square test of independence is performed for categorical variables.} 55 | 56 | \item{header_labels}{a character vector that renames the header labels (e.g., the blank above the variables, the p-value label, and test value label).} 57 | 58 | \item{type}{what is displayed in the table; a string or a vector of strings. Two main sections can be inputted: 1. if test = TRUE, can write "pvalues", "full", or "stars" and 2. can state "simple" and/or "condense". These are discussed in more depth in the details section below.} 59 | 60 | \item{output}{how the table is output; can be "text" or "text2" for regular console output or any of \code{kable()}'s options from \code{knitr} (e.g., "latex", "markdown", "pandoc"). A new option, \code{'latex2'}, although more limited, allows the variable name to show and has an overall better appearance.} 61 | 62 | \item{rounding_perc}{the number of digits after the decimal for percentages; default is 1} 63 | 64 | \item{digits}{the number of significant digits for the numerical variables (if using default functions); default is 1.} 65 | 66 | \item{var_names}{custom variable names to be printed in the table. Variable names can be applied directly in the list of variables.} 67 | 68 | \item{format_number}{default is FALSE; if TRUE, then the numbers are formatted with commas (e.g., 20,000 instead of 20000)} 69 | 70 | \item{NAkeep}{when set to \code{TRUE} it also shows how many missing values are in the data for each categorical variable being summarized (deprecated; use \code{na.rm})} 71 | 72 | \item{na.rm}{when set to \code{FALSE} it also shows how many missing values are in the data for each categorical variable being summarized} 73 | 74 | \item{booktabs}{when \code{output != "text"}; option is passed to \code{knitr::kable}} 75 | 76 | \item{caption}{when \code{output != "text"}; option is passed to \code{knitr::kable}} 77 | 78 | \item{align}{when \code{output != "text"}; option is passed to \code{knitr::kable}} 79 | 80 | \item{float}{the float applied to the table in Latex when output is \code{latex2}, default is "ht".} 81 | 82 | \item{export}{character; when given, it exports the table to a CSV file to folder named "table1" in the working directory with the name of the given string (e.g., "myfile" will save to "myfile.csv")} 83 | 84 | \item{label}{for \code{output == "latex2"}, this provides a table reference label for latex} 85 | } 86 | \value{ 87 | A table with the number of observations, means/frequencies and standard deviations/percentages is returned. The object is a \code{table1} class object with a print method. Can be printed in \code{LaTex} form. 88 | } 89 | \description{ 90 | Produces a descriptive table, stratified by an optional categorical variable, 91 | providing means/frequencies and standard deviations/percentages. 92 | It is well-formatted for easy transition to academic article or report. 93 | Can be used within the piping framework [see library(magrittr)]. 94 | } 95 | \details{ 96 | In defining \code{type}, 1. options are "pvalues" that display the p-values of the tests, "full" which also shows the test statistics, or "stars" which only displays stars to highlight significance with *** < .001 ** .01 * .05; and 97 | 2. "simple" then only percentages are shown for categorical variable and 98 | "condense" then continuous variables' means and SD's will be on the same line as the variable name and dichotomous variables only show counts and percentages for the reference category. 99 | } 100 | \examples{ 101 | 102 | ## Fictitious Data ## 103 | library(furniture) 104 | library(dplyr) 105 | 106 | x <- runif(1000) 107 | y <- rnorm(1000) 108 | z <- factor(sample(c(0,1), 1000, replace=TRUE)) 109 | a <- factor(sample(c(1,2), 1000, replace=TRUE)) 110 | df <- data.frame(x, y, z, a) 111 | 112 | ## Simple 113 | table1(df, x, y, z, a) 114 | 115 | ## Stratified 116 | ## all three below are the same 117 | table1(df, x, y, z, 118 | splitby = ~ a) 119 | table1(df, x, y, z, 120 | splitby = "a") 121 | 122 | ## With Piping 123 | df \%>\% 124 | table1(x, y, z, 125 | splitby = ~a) 126 | 127 | df \%>\% 128 | group_by(a) \%>\% 129 | table1(x, y, z) 130 | 131 | ## Adjust variables within function and assign name 132 | table1(df, 133 | x2 = ifelse(x > 0, 1, 0), z = z) 134 | 135 | } 136 | -------------------------------------------------------------------------------- /man/table1_gt.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/table1_gt.R 3 | \name{table1_gt} 4 | \alias{table1_gt} 5 | \title{gt output for table1} 6 | \usage{ 7 | table1_gt(tab, spanner = NULL) 8 | } 9 | \arguments{ 10 | \item{tab}{the table1 object} 11 | 12 | \item{spanner}{the label above the grouping variable (if table1 is grouped) 13 | or any label you want to include over the statistics column(s)} 14 | } 15 | \description{ 16 | This takes a table1 object and outputs a `gt` version. 17 | } 18 | \examples{ 19 | 20 | library(furniture) 21 | library(dplyr) 22 | 23 | data('nhanes_2010') 24 | nhanes_2010 \%>\% 25 | group_by(asthma) \%>\% 26 | table1(age, marijuana, illicit, rehab, na.rm = FALSE) \%>\% 27 | table1_gt(spanner = "Asthma") 28 | 29 | } 30 | \author{ 31 | Tyson S. Barrett 32 | } 33 | -------------------------------------------------------------------------------- /man/tableC.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/table_cor.R 3 | \name{tableC} 4 | \alias{tableC} 5 | \title{Correlation Table} 6 | \usage{ 7 | tableC( 8 | .data, 9 | ..., 10 | cor_type = "pearson", 11 | na.rm = FALSE, 12 | rounding = 3, 13 | output = "text", 14 | booktabs = TRUE, 15 | caption = NULL, 16 | align = NULL, 17 | float = "htb" 18 | ) 19 | } 20 | \arguments{ 21 | \item{.data}{the data frame containing the variables} 22 | 23 | \item{...}{the unquoted variable names to be included in the correlations} 24 | 25 | \item{cor_type}{the correlation type; default is "pearson", other option is "spearman"} 26 | 27 | \item{na.rm}{logical (default is \code{FALSE}); if set to \code{TRUE}, the correlations use the "complete.obs" methods option from \code{stats::cor()}} 28 | 29 | \item{rounding}{the value passed to \code{round} for the output of both the correlation and p-value; default is 3} 30 | 31 | \item{output}{how the table is output; can be "text" for regular console output, "latex2" for specialized latex output, or any of \code{kable()}'s options from \code{knitr} (e.g., "latex", "markdown", "pandoc").} 32 | 33 | \item{booktabs}{when \code{output != "text"}; option is passed to \code{knitr::kable}} 34 | 35 | \item{caption}{when \code{output != "text"}; option is passed to \code{knitr::kable}} 36 | 37 | \item{align}{when \code{output != "text"}; option is passed to \code{knitr::kable}} 38 | 39 | \item{float}{when \code{output == "latex2"} it controls the floating parameter (h, t, b, H)} 40 | } 41 | \description{ 42 | Correlations printed in a nicely formatted table. 43 | } 44 | \seealso{ 45 | stats::cor 46 | } 47 | -------------------------------------------------------------------------------- /man/tableF.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tableF.R 3 | \name{tableF} 4 | \alias{tableF} 5 | \title{Frequency Table} 6 | \usage{ 7 | tableF(.data, x, n = 20, splitby = NULL) 8 | } 9 | \arguments{ 10 | \item{.data}{the data frame containing the variable} 11 | 12 | \item{x}{the bare variable name (not quoted)} 13 | 14 | \item{n}{the number of values shown int he table} 15 | 16 | \item{splitby}{the stratifying variable} 17 | } 18 | \value{ 19 | a list of class \code{tableF} containing the frequency table(s) 20 | } 21 | \description{ 22 | Provides in-depth frequency counts and percentages. 23 | } 24 | \examples{ 25 | 26 | \dontrun{ 27 | 28 | library(furniture) 29 | 30 | data <- data.frame( 31 | x = sample(c(1,2,3,4), 100, replace=TRUE), 32 | y = rnorm(100) 33 | ) 34 | 35 | ## Basic Use 36 | tableF(data, x) 37 | tableF(data, y) 38 | 39 | ## Adjust the number of items shown 40 | tableF(data, y, n = 10) 41 | 42 | ## Add splitby 43 | tableF(data, x, splitby = y) 44 | 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /man/tableX.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tableX.R 3 | \name{tableX} 4 | \alias{tableX} 5 | \title{Table X (for Cross-Tabs)} 6 | \usage{ 7 | tableX(.data, x1, x2, type = "count", na.rm = FALSE, format_number = FALSE) 8 | } 9 | \arguments{ 10 | \item{.data}{the data frame containing the variables} 11 | 12 | \item{x1}{the first bare (not quoted) variable found in .data} 13 | 14 | \item{x2}{the second bare (not quoted) variable found in .data} 15 | 16 | \item{type}{the summarized output type; can be "count", "cell_perc", "row_perc", or "col_perc"} 17 | 18 | \item{na.rm}{logical; whether missing values should be removed} 19 | 20 | \item{format_number}{default is FALSE; if TRUE, then the numbers are formatted with commas (e.g., 20,000 instead of 20000)} 21 | } 22 | \description{ 23 | Provides a pipe-able, clean, flexible version of \code{table()}. 24 | } 25 | \examples{ 26 | 27 | \dontrun{ 28 | 29 | library(furniture) 30 | library(tidyverse) 31 | 32 | data <- data.frame( 33 | x = sample(c(1,2,3,4), 100, replace=TRUE), 34 | y = sample(c(0,1), 100, replace=TRUE) 35 | ) 36 | 37 | tableX(data, x, y) 38 | 39 | data \%>\% 40 | tableX(x, y) 41 | 42 | data \%>\% 43 | tableX(x, y, na.rm = TRUE) 44 | 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /man/to_latex.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/to_latex2.R 3 | \name{to_latex} 4 | \alias{to_latex} 5 | \title{From Table 1 to Latex 2} 6 | \usage{ 7 | to_latex( 8 | tab, 9 | caption, 10 | align, 11 | len, 12 | splitby, 13 | float, 14 | booktabs, 15 | label, 16 | total = FALSE, 17 | cor_type = NULL 18 | ) 19 | } 20 | \arguments{ 21 | \item{tab}{the table1 object} 22 | 23 | \item{caption}{caption character vector} 24 | 25 | \item{align}{align character vector} 26 | 27 | \item{len}{the number of levels of the grouping factor} 28 | 29 | \item{splitby}{the name of the grouping factor} 30 | 31 | \item{float}{argument for latex formatting} 32 | 33 | \item{booktabs}{add booktabs to latex table} 34 | 35 | \item{label}{latex label option} 36 | 37 | \item{total}{is there a total column (from Table 1) to be printed?} 38 | 39 | \item{cor_type}{optional argument regarding the correlation type (for tableC)} 40 | } 41 | \description{ 42 | Internal \code{table1()} and \code{tableC()} function for providing output = "latex2" 43 | } 44 | -------------------------------------------------------------------------------- /man/washer.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/washer.R 3 | \name{washer} 4 | \alias{washer} 5 | \title{Wash Your Data} 6 | \usage{ 7 | washer(x, ..., value = NA) 8 | } 9 | \arguments{ 10 | \item{x}{the variable to have values adjusted} 11 | 12 | \item{...}{the values in the variable that are to be replaced by either NA's or the value set by the user. Can be a function (or multiple functions) to specify values to change (e.g., is.nan(), is.na()).} 13 | 14 | \item{value}{(optional) if specified, the values in ... will be replaced by this value (must be a single value)} 15 | } 16 | \value{ 17 | the original vector (although if the original was a factor, it was changed to a character) with the values changed where indicated. 18 | } 19 | \description{ 20 | Washes the data by replacing values with either NA's or other values set by the user. 21 | Useful for replacing values such as 777's or 999's that represent missing values in survey research. 22 | Can also perform many useful functions on factors (e.g., removing a level, replacing a level, etc.) 23 | } 24 | \examples{ 25 | x = c(1:20, NA, NaN) 26 | washer(x, 9, 10) 27 | washer(x, 9, 10, value=0) 28 | washer(x, 1:10) 29 | washer(x, is.na, is.nan, value=0) 30 | washer(x, is.na, is.nan, 1:3, value=0) 31 | 32 | } 33 | -------------------------------------------------------------------------------- /man/wide.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/long_wide.R 3 | \name{wide} 4 | \alias{wide} 5 | \title{Long to Wide Data Reshaping} 6 | \usage{ 7 | wide(data, v.names, timevar, id = NULL) 8 | } 9 | \arguments{ 10 | \item{data}{the data.frame containing the wide format data} 11 | 12 | \item{v.names}{the variable names in quotes of the measures to be separated 13 | into multiple columns based on the time variable} 14 | 15 | \item{timevar}{the variable name in quotes of the time variable} 16 | 17 | \item{id}{the ID variable name in quotes} 18 | } 19 | \description{ 20 | \code{wide()} is a wrapper of \code{stats::reshape()} that takes 21 | the data from a long format to a wide format. 22 | } 23 | \seealso{ 24 | \code{stats::reshape()}, \code{tidyr::spread()} 25 | } 26 | \author{ 27 | Tyson S. Barrett 28 | } 29 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(furniture) 3 | 4 | test_check("furniture") 5 | -------------------------------------------------------------------------------- /tests/testthat/test_tableF.R: -------------------------------------------------------------------------------- 1 | library(furniture) 2 | library(testthat) 3 | 4 | test_that("tableF produces tableF", { 5 | x <- runif(1000) 6 | y <- rnorm(1000) 7 | z <- factor(sample(c(0,1), 1000, replace=TRUE)) 8 | a <- factor(sample(c(1,2), 1000, replace=TRUE)) 9 | b <- factor(sample(c(1,2,3,4), 1000, replace=TRUE)) 10 | c <- sample(c(rnorm(10), NA), 1000, replace=TRUE) 11 | df <- data.frame(x, y, z, a, b, c) 12 | 13 | x <- rep(0, times=7) 14 | d <- rep(0, times=7) 15 | 16 | ## no missing 17 | expect_s3_class(tableF(df, x), "tableF") 18 | ## missing 19 | expect_s3_class(tableF(df, c), "tableF") 20 | ## Testing splitby 21 | expect_s3_class(tableF(df, a, splitby=z), "tableF") 22 | }) 23 | 24 | -------------------------------------------------------------------------------- /tests/testthat/test_tableX.R: -------------------------------------------------------------------------------- 1 | library(furniture) 2 | library(testthat) 3 | 4 | test_that("tableX produces tableX", { 5 | x <- runif(100) 6 | y <- rnorm(100) 7 | z <- factor(sample(c(0,1), 100, replace=TRUE)) 8 | a <- factor(sample(c(1,2), 100, replace=TRUE)) 9 | b <- factor(sample(c(1,2,3,4), 100, replace=TRUE)) 10 | df <- data.frame(x, y, z, a, b) 11 | 12 | x <- rep(0, times=7) 13 | d <- rep(0, times=7) 14 | 15 | ## Simple 16 | expect_s3_class(tableX(df, a, b), "table") 17 | ## d not in df 18 | expect_error(tableX(df, d)) 19 | }) 20 | 21 | -------------------------------------------------------------------------------- /tests/testthat/test_table_cor.R: -------------------------------------------------------------------------------- 1 | library(furniture) 2 | library(testthat) 3 | 4 | test_that("table1 produces table1", { 5 | x <- runif(1000) 6 | y <- rnorm(1000) 7 | z <- rnorm(1000) 8 | a <- rnorm(1000) 9 | b <- rnorm(1000) 10 | df <- data.frame(x, y, z, a, b) 11 | 12 | x <- rep(0, times=7) 13 | d <- rep(0, times=7) 14 | 15 | ## Simple 16 | expect_s3_class(tableC(df, x, y, z, a, b), "table1") 17 | ## d not in df 18 | expect_error(tableC(df, d)) 19 | expect_s3_class(tableC(df, a, x, y, rounding = 4), "table1") 20 | expect_s3_class(tableC(df, a, x, y, cor_type = "spearman"), "table1") 21 | expect_s3_class(tableC(df, a, x, y, na.rm = TRUE), "table1") 22 | ## Other output types 23 | expect_s3_class(tableC(df, a, x, y, 24 | output = "markdown"), "knitr_kable") 25 | expect_s3_class(tableC(df, a, x, y, 26 | output = "latex2"), "latex2") 27 | }) 28 | 29 | 30 | -------------------------------------------------------------------------------- /tests/testthat/test_washer.R: -------------------------------------------------------------------------------- 1 | library(furniture) 2 | library(testthat) 3 | 4 | test_that("washer produces correct output vectors", { 5 | expect_equal(washer(c(1,2,3,4), 1), c(NA,2,3,4)) 6 | expect_equal(washer(c(1,2,3,4), 1, value=0), c(0,2,3,4)) 7 | expect_equal(washer(as.character(c(1,2,3,4)), 1, value=0), as.character(c(0,2,3,4))) 8 | }) 9 | 10 | -------------------------------------------------------------------------------- /tests/testthat/test_widelong.R: -------------------------------------------------------------------------------- 1 | library(furniture) 2 | library(testthat) 3 | library(dplyr) 4 | 5 | test_that("long and wide", { 6 | x1 <- runif(1000) 7 | x2 <- runif(1000) 8 | x3 <- runif(1000) 9 | y1 <- rnorm(1000) 10 | y2 <- rnorm(1000) 11 | z <- factor(sample(c(0,1), 1000, replace=TRUE)) 12 | a <- factor(sample(c(1,2), 1000, replace=TRUE)) 13 | b <- factor(sample(c(1,2,3,4), 1000, replace=TRUE)) 14 | df <- data.frame(x1, x2, x3, y1, y2, z, a, b) 15 | ldf <- long(df, c("x1", "x2", "x3"), c("y1", "y2", "miss"), 16 | v.names = c("x", "y")) 17 | 18 | ## Long 19 | expect_s3_class(long(df, 20 | c("x1", "x2"), c("y1", "y2"), 21 | sep = ""), "data.frame") 22 | expect_s3_class(long(df, 23 | c("x1", "x2"), c("y1", "miss"), 24 | v.names = c("x", "y"), 25 | sep = ""), "data.frame") 26 | expect_s3_class(long(df, 27 | c("x1", "x2", "x3"), c("y1", "y2", "miss"), 28 | v.names = c("x", "y")), "data.frame") 29 | ## Long Other Classes 30 | expect_s3_class(long(dplyr::as.tbl(df), 31 | c("x1", "x2"), c("y1", "y2"), 32 | sep = ""), "data.frame") 33 | expect_s3_class(long(dplyr::as.tbl(df), 34 | c("x1", "x2"), c("y1", "miss"), 35 | v.names = c("x", "y"), 36 | sep = ""), "data.frame") 37 | expect_s3_class(long(dplyr::as.tbl(df), 38 | c("x1", "x2", "x3"), c("y1", "y2", "miss"), 39 | v.names = c("x", "y")), "data.frame") 40 | ## Wide 41 | expect_s3_class(wide(ldf, 42 | v.names = c("x", "y"), 43 | timevar = "time"), "data.frame") 44 | expect_s3_class(wide(dplyr::as.tbl(ldf), 45 | v.names = c("x", "y"), 46 | timevar = "time"), "data.frame") 47 | 48 | }) 49 | 50 | -------------------------------------------------------------------------------- /vignettes/Furniture.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Furniture" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Furniture} 6 | \usepackage[utf8]{inputenc} 7 | %\VignetteEngine{knitr::rmarkdown} 8 | date: "`r Sys.Date()`" 9 | editor_options: 10 | chunk_output_type: console 11 | --- 12 | 13 | ```{r setup, include=FALSE} 14 | knitr::opts_chunk$set(echo = TRUE) 15 | ``` 16 | 17 | This vignette is current as of `furniture` `r packageVersion("furniture")`. 18 | 19 | ## Using `furniture` 20 | 21 | ```{r} 22 | library(furniture) 23 | ``` 24 | 25 | 26 | We will first make a fictitious data set: 27 | ```{r data} 28 | df <- data.frame(a = rnorm(1000, 1.5, 2), 29 | b = seq(1, 1000, 1), 30 | c = c(rep("control", 400), rep("Other", 70), rep("treatment", 500), rep("None", 30)), 31 | d = c(sample(1:1000, 900, replace=TRUE), rep(-99, 100))) 32 | ``` 33 | 34 | There are four functions that we'll demonstrate here: 35 | 36 | 1. `washer` 37 | 2. `table1` 38 | 3. `tableC` 39 | 4. `tableF` 40 | 41 | ## Washer 42 | 43 | `washer` is a great function for quick data cleaning. In situations where there are placeholders, extra levels in a factor, or several values need to be changed to another. 44 | ```{r washer, message=FALSE, warning=FALSE} 45 | library(dplyr) 46 | 47 | df <- df %>% 48 | mutate(d = washer(d, -99), ## changes the placeholder -99 to NA 49 | c = washer(c, "Other", "None", value = "control")) ## changes "Other" and "None" to "Control" 50 | ``` 51 | 52 | 53 | ## Table1 54 | 55 | Now that the data is "washed" we can start exploring and reporting. 56 | ```{r table1} 57 | table1(df, a, b, factor(c), d) 58 | ``` 59 | 60 | The variables must be numeric or factor. Since we use a special type of evaluation (i.e. Non-Standard Evaluation) we can change the variables in the function (e.g., `factor(c)`). This can be extended to making a whole new variable in the function as well. 61 | 62 | ```{r table1.2} 63 | table1(df, a, b, d, ifelse(a > 1, 1, 0)) 64 | ``` 65 | 66 | This is just the beginning though. Two powerful things the function can do are shown below: 67 | 68 | ```{r table1.3} 69 | table1(df, a, b, d, ifelse(a > 1, 1, 0), 70 | splitby=~factor(c), 71 | test=TRUE) 72 | ``` 73 | 74 | The `splitby = ~factor(c)` stratifies the means and counts by a factor variable (in this case either control or treatment). When we use this we can also automatically compute tests of significance using `test=TRUE`. 75 | 76 | We can also use it intuitively within the pipe (for more about this, see the "Table 1" vignette): 77 | ```{r table1.3.2, message=FALSE, warning=FALSE} 78 | df %>% 79 | group_by(c) %>% 80 | table1(a, b, d, ifelse(a > 1, 1, 0), 81 | test=TRUE) 82 | ``` 83 | In this case, we used the `group_by()` function from `dplyr` (within the `tidyverse`) and `table1()` knows to use that as the grouping variable in place of the `splitby` argument. 84 | 85 | If the parametric tests (default) are not appropriate, you can set `param = FALSE`. 86 | ```{r table1.3.3, message=FALSE, warning=FALSE} 87 | df %>% 88 | group_by(c) %>% 89 | table1(a, b, d, ifelse(a > 1, 1, 0), 90 | test=TRUE, 91 | param=FALSE) 92 | ``` 93 | 94 | 95 | Finally, you can polish it quite a bit using a few other options. For example, you can do the following: 96 | ```{r table1.4} 97 | table1(df, a, b, d, ifelse(a > 1, 1, 0), 98 | splitby=~factor(c), 99 | test=TRUE, 100 | var_names = c("A", "B", "D", "New Var"), 101 | type = c("simple", "condensed")) 102 | ``` 103 | 104 | Note that `var_names` can be used for more complex naming (e.g., with spaces, brackets) that otherwise cannot be used with data frames. Alternatively, for more simple naming, we can name them directly. 105 | ```{r table1.4.2} 106 | table1(df, A = a, B = b, D = d, A2 = ifelse(a > 1, 1, 0), 107 | splitby=~factor(c), 108 | test=TRUE, 109 | type = c("simple", "condensed")) 110 | ``` 111 | 112 | 113 | You can also format the numbers (adding a comma for big numbers such as in 20,000 instead of 20000): 114 | ```{r table1.5} 115 | table1(df, a, b, d, ifelse(a > 1, 1, 0), 116 | splitby=~factor(c), 117 | test=TRUE, 118 | var_names = c("A", "B", "D", "New Var"), 119 | format_number = TRUE) 120 | ``` 121 | 122 | The table can be exported directly to a folder in the working directory called "Table1". Using `export`, we provide it with a string that will be the name of the CSV containing the formatted table. 123 | ```{r table1.6, eval=FALSE} 124 | table1(df, a, b, d, ifelse(a > 1, 1, 0), 125 | splitby=~factor(c), 126 | test=TRUE, 127 | var_names = c("A", "B", "D", "New Var"), 128 | format_number = TRUE, 129 | export = "example_table1") 130 | ``` 131 | 132 | This can also be outputted as a latex, markdown, or pandoc table (matching all the output types of `knitr::kable`). Below shows how to do a latex table (not using `kable` however, but a built-in function that provides the variable name at the top of the table): 133 | ```{r table1.7} 134 | table1(df, a, b, d, "new var" = ifelse(a > 1, 1, 0), 135 | splitby = ~factor(c), 136 | test = TRUE, 137 | output = "latex2") 138 | ``` 139 | 140 | Last item to show you regarding `table1()` is that it can be printed in a simplified and condensed form. This instead of reporting counts and percentages for categorical variables, it reports only percentages and the table has much less white space. 141 | ```{r simple_table1.1} 142 | table1(df, a, b, d, "new var" = ifelse(a > 1, 1, 0), 143 | splitby = ~factor(c), 144 | test = TRUE, 145 | type = c("simple", "condensed")) 146 | ``` 147 | 148 | 149 | ## Table C 150 | 151 | This function is to create simple, beautiful correlation tables. The syntax is just like `table1()` in most respects. Below we include all the numeric variables to see their correlations. Since there are missing values in `d` we will use the natural `na.rm=TRUE`. 152 | 153 | ```{r tableC.1} 154 | tableC(df, 155 | a, b, d, 156 | na.rm = TRUE) 157 | ``` 158 | 159 | All the adjustments that you can make in `table1()` can be done here as well. For example, 160 | 161 | ```{r tableC.2} 162 | tableC(df, 163 | "A" = a, "B" = b, "D" = d, 164 | na.rm = TRUE, 165 | output = "html") 166 | ``` 167 | 168 | ## Table F 169 | 170 | This function is to create simple frequency tables. The syntax is just like `table1()` and `tableC()` in most respects, except that it uses only one variable instead of many. 171 | 172 | ```{r tableF.1} 173 | tableF(df, a) 174 | ``` 175 | 176 | Similarly to `table1()` we can use a `splitby` argument (or `group_by()`). 177 | 178 | ```{r tableF.2} 179 | tableF(df, d, splitby = c) 180 | ``` 181 | 182 | ```{r tableF.3} 183 | df %>% 184 | group_by(c) %>% 185 | tableF(d) 186 | ``` 187 | 188 | 189 | ## Table X 190 | 191 | Lastly, `tableX()` is a pipe-able two-way version of `table()` with a similar syntax to that of the rest of the `furniture` functions. 192 | 193 | ```{r tableX.1} 194 | df %>% 195 | tableX(c, ifelse(d > 500, 1, 0)) 196 | ``` 197 | 198 | By default, it provides the total counts for the rows and columns with flexibility as to what is displayed and where. 199 | 200 | 201 | ## Conclusion 202 | 203 | The four functions: `table1()`, `tableC()`, `tableF()`, and `washer()` add simplicity to cleaning up and understanding your data. Use these pieces of furniture to make your quantitative life a bit easier. 204 | 205 | -------------------------------------------------------------------------------- /vignettes/Table1.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Table 1" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Table 1} 6 | \usepackage[utf8]{inputenc} 7 | %\VignetteEngine{knitr::rmarkdown} 8 | date: "`r Sys.Date()`" 9 | editor_options: 10 | chunk_output_type: console 11 | --- 12 | 13 | ```{r setup, include=FALSE} 14 | knitr::opts_chunk$set(echo = TRUE) 15 | ``` 16 | 17 | # Making Table 1 18 | 19 | 20 | ```{r} 21 | library(furniture) 22 | ``` 23 | 24 | This vignette demonstrates the main function of the `furniture` package--`table1()`. This vignette is current as of `furniture` `r packageVersion("furniture")`. 25 | 26 | The main parts of the `table1()` are below: 27 | 28 | ```{r structure, eval=FALSE} 29 | table1(.data, ..., splitby, row_wise, test, type, output, format_number, na.rm) 30 | ``` 31 | 32 | It contains several useful features for summarizing your data: 33 | 34 | 1. It simply summarizes many variables succinctly providing means/counts and SD's/percentages. By providing variable names to the `medians` option, you can obtain the median and the first quartile/third quantile. 35 | 2. The descriptive statistics can be by a grouping factor (i.e., splitby). 36 | 3. It uses a similar API to the popular tidyverse groups of packages and can be used in a pipe. 37 | 4. It can give bivariate test results for the variable with the grouping variable, which provides the correct test type depending on the variable types. 38 | 5. It is flexible as to its output: can be printed in regular console output or it can be printed in latex (either through kable or through a built-in function), markdown, and pandoc (see `knitr::kable`). 39 | 6. Numbers can be formatted nicely. 40 | 7. Table has multiple formatting options to fit various needs using `output`, `format_output`, `simple` and `condense`. 41 | 8. The table can be exported to a CSV with `export = "file_name"`. 42 | 43 | To illustrate, we'll walk through the main arguments with an example on some fictitious data. 44 | 45 | ## Example 46 | 47 | ```{r data} 48 | set.seed(84332) 49 | ## Create Fictitious Data containing several types of variables 50 | df <- data.frame(a = sample(1:10000, 10000, replace = TRUE), 51 | b = runif(10000) + rnorm(10000), 52 | c = factor(sample(c(1,2,3,4,NA), 10000, replace=TRUE)), 53 | d = factor(sample(c(0,1,NA), 10000, replace=TRUE)), 54 | e = trunc(rnorm(10000, 20, 5)), 55 | f = factor(sample(c(0,1,NA), 10000, replace=TRUE))) 56 | ``` 57 | 58 | We will use `df` to show these main features of `table1`. 59 | 60 | ### The ... 61 | 62 | For `table1`, the ellipses (the `...`), are the variables to be summarized that are found in your data. Here, we have `a` through `e` in `df`. 63 | ```{r simple} 64 | table1(df, 65 | a, b, c, d, e) 66 | ``` 67 | 68 | ### Splitby 69 | 70 | To get means/count and SD's/percentages by a stratifying variable, simply use the `splitby` argument. The splitby can be a quoted variable (e.g., `"df"`) or can be a one-sided formula as shown below (e.g., `~d`). 71 | 72 | ```{r splitby} 73 | table1(df, 74 | a, b, c, 75 | splitby = ~d) 76 | ``` 77 | 78 | ### Row Wise 79 | 80 | You can get percentages by rows instead of by columns (i.e., groups) by using the `row_wise = TRUE` option. 81 | 82 | ```{r rowwise} 83 | table1(df, 84 | a, b, c, 85 | splitby = ~d, 86 | row_wise = TRUE) 87 | ``` 88 | 89 | ### Test 90 | 91 | It is easy to test for bivariate relationships, as in common in many Table 1's, using `test = TRUE`. 92 | 93 | ```{r test} 94 | table1(df, 95 | a, b, c, 96 | splitby = ~d, 97 | test = TRUE) 98 | ``` 99 | By default, only the p-values are shown but other options exist such as stars or including the test statistics with the p-values using the `format_output` argument. 100 | 101 | ## Simple and Condensed 102 | 103 | The table can be simplified by just producing percentages for categorical variables. Further, it can be condensed by providing only a reference group's percentages for binary variables and the means and SD's are provided on the same line as the variable name. 104 | ```{r s_c} 105 | table1(df, 106 | f, a, b, c, 107 | splitby = ~d, 108 | test = TRUE, 109 | type = c("simple", "condensed")) 110 | ``` 111 | 112 | 113 | ## Medians 114 | 115 | If the medians and the interquartile range is desired instead of means and SD's, simply use the `second` argument: 116 | 117 | ```{r meds} 118 | table1(df, 119 | f, a, b, c, 120 | splitby = ~d, 121 | test = TRUE, 122 | type = c("simple", "condensed"), 123 | second = c("a", "b")) 124 | ``` 125 | 126 | 127 | ### Output Type 128 | 129 | Several output types exist for the table (all of the `knitr::kable` options) including `html` as shown below. Others include: 130 | 131 | 1. "latex" 132 | 2. "markdown" 133 | 3. "pandoc" 134 | 135 | ```{r html} 136 | table1(df, 137 | a, b, c, 138 | splitby = ~d, 139 | test = TRUE, 140 | output = "html") 141 | ``` 142 | 143 | ### Format Number 144 | 145 | For some papers you may want to format the numbers by inserting a comma in as a placeholder in big numbers (e.g., 30,000 vs. 30000). You can do this by using `format_number = TRUE`. 146 | 147 | ```{r formatnumber} 148 | table1(df, 149 | a, b, c, 150 | splitby = ~d, 151 | test = TRUE, 152 | format_number = TRUE) 153 | ``` 154 | 155 | ### `na.rm` 156 | 157 | In order to explore the missingness in the factor variables, using `na.rm = FALSE` does the counts and percentages of the missing values as well. 158 | 159 | ```{r nakeep} 160 | table1(df, 161 | a, b, c, 162 | splitby = ~d, 163 | test = TRUE, 164 | na.rm = FALSE) 165 | ``` 166 | Here we do not have any missingness but it shows up as zeros to show that there are none there. 167 | 168 | 169 | ### Piping 170 | 171 | Finally, and very importantly, to make it easier to implement in the tidyverse of packages, a piping option is available. This option can use a `grouped_df` object output by `dplyr::group_by()` and use the groups indicated there as shown below. 172 | 173 | ```{r tidyverse, fig.width=5, message=FALSE, warning=FALSE} 174 | library(dplyr) 175 | 176 | df %>% 177 | filter(f == 1) %>% 178 | group_by(d) %>% 179 | table1(a, b, c, 180 | test = TRUE, 181 | type = c("simple", "condensed")) 182 | ``` 183 | 184 | This includes the ability to use multiple grouping variables. The first value is the first grouping variable, then an underscore, followed by the value of the second grouping variable. 185 | ```{r tidyverse2, fig.width=5, message=FALSE, warning=FALSE} 186 | df %>% 187 | group_by(d, f) %>% 188 | table1(a, b, c, 189 | test = TRUE, 190 | type = c("simple", "condensed")) 191 | ``` 192 | 193 | ### Variable Names 194 | 195 | You can also adjust the variable names from within the function as so: 196 | 197 | ```{r} 198 | table1(df, 199 | "Avar" = a, "Bvar" = b, "Cvar" = c, 200 | splitby = ~d, 201 | test = TRUE) 202 | ``` 203 | 204 | This is particularly useful when you adjust a variable within the function: 205 | 206 | ```{r, warning=FALSE, message=FALSE} 207 | df %>% 208 | group_by(d) %>% 209 | table1("A" = factor(ifelse(a > 500, 1, 0)), b, c, 210 | test = TRUE) 211 | ``` 212 | 213 | Here we changed `a` to a factor within the function. In order for the name to look better, we can assign a new name, otherwise it would be named something like `factor.ifelse.a...`. 214 | 215 | 216 | 217 | ## Final Note 218 | 219 | As a final note, the `"table1"` object can be coerced to a `data.frame` very easily: 220 | ```{r dataframe} 221 | tab1 <- table1(df, 222 | a, b, c, 223 | splitby = ~d, 224 | test = TRUE) 225 | as.data.frame(tab1) 226 | ``` 227 | 228 | 229 | 230 | ## Conclusions 231 | 232 | `table1` can be a valuable addition to the tools that are being utilized to analyze descriptive statistics. Enjoy this valuable piece of furniture! 233 | --------------------------------------------------------------------------------