Browse Source

New README

tags/0.3.0
Maxime Wack 2 years ago
parent
commit
a7549c044d
2 changed files with 58 additions and 1132 deletions
  1. +24
    -338
      README.Rmd
  2. +34
    -794
      README.md

+ 24
- 338
README.Rmd View File

@@ -7,363 +7,49 @@ output: github_document
knitr::opts_chunk$set(message = F, warning = F)
```

[![Travis-CI Build Status](https://travis-ci.org/MaximeWack/desctable.svg?branch=master)](https://travis-ci.org/MaximeWack/desctable) [![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/desctable)](https://cran.r-project.org/package=desctable) [![CRAN RStudio mirror downloads](http://cranlogs.r-pkg.org/badges/desctable)](https://www.r-pkg.org:443/pkg/desctable)
[![Travis-CI Build Status](https://travis-ci.org/desctable/desctable.svg?branch=master)](https://travis-ci.org/desctable/desctable) [![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/desctable)](https://cran.r-project.org/package=desctable) [![CRAN RStudio mirror downloads](http://cranlogs.r-pkg.org/badges/desctable)](https://www.r-pkg.org:443/pkg/desctable)

# Introduction

Desctable is a comprehensive descriptive and comparative tables generator for R.
**Warning to existing users**
*This version introduces a new API that should make the creation of tables more flexible.
The old API is still present but in a deprecated mode.
See the roadmap below, and the website for the new usage.
Suggestions about this change are welcome !*

Every person doing data analysis has to create tables for descriptive summaries of data (a.k.a. Table.1), or comparative tables.

Many packages, such as the aptly named **tableone**, address this issue. However, they often include hard-coded behaviors, have outputs not easily manipulable with standard R tools, or their syntax are out-of-style (e.g. the argument order makes them difficult to use with the pipe (`%>%`)).
# Introduction

Enter **desctable**, a package built with the following objectives in mind:
Desctable aims to be a simple and expressive interface to building statistical tables in R.

* generate descriptive and comparative statistics tables with nesting
* keep the syntax as simple as possible
* have good reasonable defaults
* be entirely customizable, using standard R tools and functions
* produce the simplest (as a data structure) output possible
* provide helpers for different outputs
* integrate with "modern" R usage, and the **tidyverse** set of tools
* apply functional paradigms
See [desctable.github.io](https://desctable.github.io) for usage ond documentation.

# Installation

Install from CRAN with
Install from CRAN (0.1.9) with

```
install.packages("desctable")
```

or install the development version from github with

```
devtools::install_github("maximewack/desctable")
```

# Loading

```{r}
library(desctable)
```

It is recommended to read this manual through its vignette:
```{r}
vignette("desctable")
```

----

# Descriptive tables

## Simple usage

**desctable** uses and exports the pipe (`%>%`) operator (from packages **magrittr** and **dplyr** fame), though it is not mandatory to use it.

The single interface to the package is its eponymous `desctable` function.

When used on a data.frame, it returns a descriptive table:

```{r}
iris %>%
desctable()

desctable(mtcars)
```
<br>

As you can see with these two examples, `desctable` describes every variable, with individual levels for factors. It picks statistical functions depending on the type and distribution of the variables in the data, and applies those statistical functions only on the relevant variables.

## Output

The object produced by `desctable` is in fact a list of data.frames, with a "desctable" class.
Methods for reduction to a simple dataframe (`as.data.frame`, automatically used for printing), conversion to markdown (`pander`), and interactive html output with **DT** (`datatable`) are provided:

```{r}
iris %>%
desctable() %>%
pander()
```
<br>

To use `pander` you need to load the package yourself.

Calls to `pander` and `datatable` with "regular" dataframes will not be affected by the defaults used in the package, and you can modify these defaults for **desctable** objects.
or install the development version (0.3) from github with

The `datatable` wrapper function for desctable objects comes with some default options and formatting such as freezing the row names and table header, export buttons, and rounding of values. Both `pander` and `datatable` wrapper take a *digits* argument to set the number of decimals to show. (`pander` uses the *digits*, *justify* and *missing* arguments of `pandoc.table`, whereas `datatable` calls `prettyNum` with the `digits` parameter, and removes `NA` values. You can set `digits = NULL` if you want the full table and format it yourself)

Subsequent outputs in this README will use **pander**.

## Advanced usage

`desctable` automatically chooses statistical functions if none is provided, using the following algorithm:

* always show N
* if there are factors, show %
* if there are normally distributed variables, show Mean and SD
* if there are non-normally distributed variables, show Median and IQR

For each variable in the table, compute the relevant statistical functions in that list (non-applicable functions will safely return `NA`).

You can specify the statistical functions yourself with the *stats* argument. This argument can either be:

* a function for automatic selection of appropriate statistical functions, depending on the data
* a named list of functions/formulas

The functions/formulas leverage the **tidyverse** way of working with anonymous functions, i.e.:

If a *function*, is is used as is.
If a *formula*, e.g. '~ .x + 1' or `~ . + 1`, it is converted to a function. There are three ways to refer to the arguments:

* For a single argument function, use '.'
* For a two argument function, use '.x' and '.y'
* For more arguments, use '..1', '..2', '..3' etc

This syntax allows you to create very compact anonymous functions, and is the same as in the `map` family of functions from **purrr**.

**Conditional formulas (`condition ~ if_T | if F`) from previous versions are no longer supported!**

### Automatic function

The default value for the *stats* argument is `stats_auto`, provided in the package.

Several other "automatic statistical functions" are defined in this package: `stats_auto`, `stats_default`, `stats_normal`, `stats_nonnormal`.

You can also provide your own automatic function, which needs to

* accept a dataframe as its argument (whether to use this dataframe or not in the function is your choice), and
* return a named list of statistical functions to use, as defined in the subsequent paragraphs.

```{r}
# Strictly equivalent to iris %>% desctable() %>% pander()
iris %>%
desctable(stats = stats_auto) %>%
pander()
```
<br>

For reference, here is the body of the `stats_auto` function in the package:
```{r, echo = F}
print(stats_auto)
```
<br>

### Statistical functions

Statistical functions can be **any** function defined in R that you want to use, such as `length` or `mean`.

The only condition is that they return a single numerical value. One exception is when they return a vector of length `1 + nlevels(x)` when applied to factors, as is needed for the `percent` function.

As mentioned above, they need to be used inside a **named list**, such as

```{r}
mtcars %>%
desctable(stats = list("N" = length, "Mean" = mean, "SD" = sd)) %>%
pander()
devtools::install_github("desctable/desctable")
```
<br>

The names will be used as column headers in the resulting table, and the functions will be applied safely on the variables (errors return `NA`, and for factors the function will be used on individual levels).

Several convenience functions are included in this package.

* `percent`, which prints percentages of levels in a factor
* `IQR`, which re-implements `stats::IQR` but works better with `NA` values
* `is.normal`, which tests for normality using the following method: `length(na.omit(x)) > 30 & shapiro.test(x)$p.value > .1`

Be aware that **all functions will be used on variables stripped of their `NA` values!**
This is necessary for most statistical functions to be useful, and makes **N** (`length`) show only the number of observations in the dataset for each variable.
# Roadmap

### Labels
## 0.3

It is often the case that variable names are not "pretty" enough to be used as-is in a table.
Although you could still edit the variable labels in the table afterwards using sub-setting or string replacement functions, we provide a facility for this using the **labels** argument.

The **labels** argument is a named character vector associating variable names and labels.
You don't need to provide labels for all the variables, and extra labels will be silently discarded. This allows you to define a "global" labels vector and use it for multiple tables even after variable selections.

```{r}
mtlabels <- c(mpg = "Miles/(US) gallon",
cyl = "Number of cylinders",
disp = "Displacement (cu.in.)",
hp = "Gross horsepower",
drat = "Rear axle ratio",
wt = "Weight (1000 lbs)",
qsec = "¼ mile time",
vs = "V/S",
am = "Transmission",
gear = "Number of forward gears",
carb = "Number of carburetors")

mtcars %>%
dplyr::mutate(am = factor(am, labels = c("Automatic", "Manual"))) %>%
desctable(labels = mtlabels) %>%
pander()
```
<br>

----

# Comparative tables

## Simple usage

Creating a comparative table (between groups defined by a factor) using `desctable` is as easy as creating a descriptive table.

It leverages the `group_by` function from **dplyr**:

```{r}
iris %>%
group_by(Species) %>%
desctable() -> iris_by_Species

iris_by_Species
```
<br>

The result is a table containing a descriptive sub-table for each level of the grouping factor (the statistical functions rules are applied to each sub-table independently), with the statistical tests performed, and their p values.

When displayed as a flat dataframe, the grouping header appears in each variable name.

You can also see the grouping headers by inspecting the resulting object, which is a nested list of dataframes, each dataframe being named after the grouping factor and its levels (with sample size for each).

```{r}
str(iris_by_Species)
```
<br>

You can specify groups based on any variable, not only factors:

```{r}
# With pander output
mtcars %>%
group_by(cyl) %>%
desctable() %>%
pander()
```
<br>

You can also specify groups based on an expression

```{r}
iris %>%
group_by(Petal.Length > 5) %>%
desctable() %>%
pander()
```
<br>

Multiple nested groups are also possible:

```{r, message = F, warning = F}
mtcars %>%
dplyr::mutate(am = factor(am, labels = c("Automatic", "Manual"))) %>%
group_by(vs, am, cyl) %>%
desctable() %>%
pander()
```
<br>

In the case of nested groups (a.k.a. sub-group analysis), statistical tests are performed only between the groups of the deepest grouping level.

Statistical tests are automatically selected depending on the data and the grouping factor.

## Advanced usage

`desctable` automatically chooses statistical functions if none is provided, using the following algorithm:

* if the variable is a factor, use `fisher.test`
* if the grouping factor has only one level, use the provided `no.test` (which does nothing)
* if the grouping factor has two levels
* and the variable presents homoskedasticity (p value for `var.test` > .1) and normality of distribution in both groups, use `t.test(var.equal = T)`
* and the variable does not present homoskedasticity (p value for `var.test` < .1) but normality of distribution in both groups, use `t.test(var.equal = F)`
* else use `wilcox.test`
* if the grouping factor has more than two levels
* and the variable presents homoskedasticity (p value for `bartlett.test` > .1) and normality of distribution in all groups, use `oneway.test(var.equal = T)`
* and the variable does not present homoskedasticity (p value for `bartlett.test` < .1) but normality of distribution in all groups, use `oneway.test(var.equal = F)`
* else use `kruskal.test`

You can specify the statistical test functions yourself with the *tests* argument. This argument can either be:

* a function for automatic selection of appropriate statistical test functions, depending on the data
* a named list of statistical test functions

Please note that the statistical test functions **must** be given as *formulas* so as to capture the name of the test to display in the table.
**purrr** style formulas are also accepted, as with the statistical functions.
This also allows to specify optional arguments of such functions, and go around non-standard test functions (see **Statistical test functions**).

### Automatic function

The default value for the *tests* argument is `tests_auto`, provided in the package.

You can also provide your own automatic function, which needs to

* accept a variable and a grouping factor as its arguments, and
* return a single-term formula containing a statistical test function.

This function will be used on every variable and every grouping factor to determine the appropriate test.

```{r}
# Strictly equivalent to iris %>% group_by(Species) %>% desctable() %>% pander()
iris %>%
group_by(Species) %>%
desctable(tests = tests_auto) %>%
pander()
```
<br>

For reference, here is the body of the `tests_auto` function in the package:
```{r, echo = F}
print(tests_auto)
```
<br>

### Statistical test functions

You can provide a named list of statistical functions, but here the mechanism is a bit different from the *stats* argument.

The list must contain either `.auto` or `.default`.

* `.auto` needs to be an automatic function, such as `tests_auto`. It will be used by default on all variables to select a test
* `.default` needs to be a single-term formula containing a statistical test function that will be used on all variables

You can also provide overrides to use specific tests for specific variables.
This is done using list items named as the variable and containing a single-term formula function.

```{r}
iris %>%
group_by(Petal.Length > 5) %>%
desctable(tests = list(.auto = tests_auto,
Species = ~chisq.test)) %>%
pander()
```
<br>

```{r}
mtcars %>%
dplyr::mutate(am = factor(am, labels = c("Automatic", "Manual"))) %>%
group_by(am) %>%
desctable(tests = list(.default = ~wilcox.test,
mpg = ~t.test)) %>%
pander()
```

Here's an example of **purrr** style function:

```{r}
iris %>%
group_by(Petal.Length > 5) %>%
desctable(tests = list(.auto = tests_auto,
Petal.Width = ~oneway.test(., var.equal = T)))
```
<br>
This new version introduces a new internal representation as well as an entirely new API for desctable !
The original `desctable` function and usage remains until 1.0, but begins deprecation.

As with statistical functions, **any** statistical test function defined in R can be used.
This new API is more flexible and more simple at the same time. Combine `group_by`, `desc_table`, `desc_tests`, and `desc_output` to create descriptive and comparative statistics tables and output them to various formats.

The conditions are that the function
The internal representation is now a simple dataframe in the simple descriptive case, and a nested dataframe with list-columns for comparative tables, allowing easier manipulation by the user.

* accepts a formula (`variable ~ grouping_variable`) as a first positional argument (as is the case with most tests, like `t.test`), and
* returns an object with a `p.value` element.
## Next

Several convenience function are provided: formula versions for `chisq.test` and `fisher.test` using generic S3 methods (thus the behavior of standard calls to `chisq.test` and `fisher.test` are not modified), and `ANOVA`, a partial application of `oneway.test` with parameter *var.equal* = T.
- Add a `desc_output` for {gt}
- Implement a way to make tables for survival analysis.
- Implement a way to make tables for multivariate models.
- Allow univariate tests for simple tables
- add a column for totals in grouped tables

+ 34
- 794
README.md View File

@@ -2,818 +2,58 @@ Desctable
================

[![Travis-CI Build
Status](https://travis-ci.org/MaximeWack/desctable.svg?branch=master)](https://travis-ci.org/MaximeWack/desctable)
Status](https://travis-ci.org/desctable/desctable.svg?branch=master)](https://travis-ci.org/desctable/desctable)
[![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/desctable)](https://cran.r-project.org/package=desctable)
[![CRAN RStudio mirror
downloads](http://cranlogs.r-pkg.org/badges/desctable)](https://www.r-pkg.org:443/pkg/desctable)

# Introduction

Desctable is a comprehensive descriptive and comparative tables
generator for R.
**Warning to existing users**
*This version introduces a new API that should make the creation of
tables more flexible.
The old API is still present but in a deprecated mode.
See the roadmap below, and the website for the new usage.
Suggestions about this change are welcome !*

Every person doing data analysis has to create tables for descriptive
summaries of data (a.k.a. Table.1), or comparative tables.

Many packages, such as the aptly named **tableone**, address this issue.
However, they often include hard-coded behaviors, have outputs not
easily manipulable with standard R tools, or their syntax are
out-of-style (e.g. the argument order makes them difficult to use with
the pipe (`%>%`)).
# Introduction

Enter **desctable**, a package built with the following objectives in
mind:
Desctable aims to be a simple and expressive interface to building
statistical tables in R.

- generate descriptive and comparative statistics tables with nesting
- keep the syntax as simple as possible
- have good reasonable defaults
- be entirely customizable, using standard R tools and functions
- produce the simplest (as a data structure) output possible
- provide helpers for different outputs
- integrate with “modern” R usage, and the **tidyverse** set of tools
- apply functional paradigms
See [desctable.github.io](https://desctable.github.io) for usage ond
documentation.

# Installation

Install from CRAN with
Install from CRAN (0.1.9) with

install.packages("desctable")

or install the development version from github with

devtools::install_github("maximewack/desctable")

# Loading

``` r
library(desctable)
```

It is recommended to read this manual through its vignette:

``` r
vignette("desctable")
```

------------------------------------------------------------------------

# Descriptive tables

## Simple usage

**desctable** uses and exports the pipe (`%>%`) operator (from packages
**magrittr** and **dplyr** fame), though it is not mandatory to use it.

The single interface to the package is its eponymous `desctable`
function.

When used on a data.frame, it returns a descriptive table:

``` r
iris %>%
desctable()
```

##   N % Mean sd Med IQR
## 1 Sepal.Length 150 NA NA NA 5.80 1.3
## 2 Sepal.Width 150 NA 3.057333 0.4358663 3.00 0.5
## 3 Petal.Length 150 NA NA NA 4.35 3.5
## 4 Petal.Width 150 NA NA NA 1.30 1.5
## 5 Species 150 NA NA NA NA NA
## 6 Species: setosa 50 33.33333 NA NA NA NA
## 7 Species: versicolor 50 33.33333 NA NA NA NA
## 8 Species: virginica 50 33.33333 NA NA NA NA

``` r
desctable(mtcars)
```

##   N Mean sd Med IQR
## 1 mpg 32 20.090625 6.0269481 19.200 7.37500
## 2 cyl 32 NA NA 6.000 4.00000
## 3 disp 32 NA NA 196.300 205.17500
## 4 hp 32 NA NA 123.000 83.50000
## 5 drat 32 3.596563 0.5346787 3.695 0.84000
## 6 wt 32 NA NA 3.325 1.02875
## 7 qsec 32 17.848750 1.7869432 17.710 2.00750
## 8 vs 32 NA NA 0.000 1.00000
## 9 am 32 NA NA 0.000 1.00000
## 10 gear 32 NA NA 4.000 1.00000
## 11 carb 32 NA NA 2.000 2.00000

<br>

As you can see with these two examples, `desctable` describes every
variable, with individual levels for factors. It picks statistical
functions depending on the type and distribution of the variables in the
data, and applies those statistical functions only on the relevant
variables.

## Output

The object produced by `desctable` is in fact a list of data.frames,
with a “desctable” class.
Methods for reduction to a simple dataframe (`as.data.frame`,
automatically used for printing), conversion to markdown (`pander`), and
interactive html output with **DT** (`datatable`) are provided:

``` r
iris %>%
desctable() %>%
pander()
```

|   | N | % | Mean | sd | Med | IQR |
|:---------------|:----|:----|:-----|:-----|:----|:----|
| Sepal.Length | 150 | | | | 5.8 | 1.3 |
| Sepal.Width | 150 | | 3.1 | 0.44 | 3 | 0.5 |
| Petal.Length | 150 | | | | 4.3 | 3.5 |
| Petal.Width | 150 | | | | 1.3 | 1.5 |
| **Species** | 150 | | | | | |
|     setosa | 50 | 33 | | | | |
|     versicolor | 50 | 33 | | | | |
|     virginica | 50 | 33 | | | | |

<br>

To use `pander` you need to load the package yourself.

Calls to `pander` and `datatable` with “regular” dataframes will not be
affected by the defaults used in the package, and you can modify these
defaults for **desctable** objects.

The `datatable` wrapper function for desctable objects comes with some
default options and formatting such as freezing the row names and table
header, export buttons, and rounding of values. Both `pander` and
`datatable` wrapper take a *digits* argument to set the number of
decimals to show. (`pander` uses the *digits*, *justify* and *missing*
arguments of `pandoc.table`, whereas `datatable` calls `prettyNum` with
the `digits` parameter, and removes `NA` values. You can set
`digits = NULL` if you want the full table and format it yourself)

Subsequent outputs in this README will use **pander**.

## Advanced usage

`desctable` automatically chooses statistical functions if none is
provided, using the following algorithm:

- always show N
- if there are factors, show %
- if there are normally distributed variables, show Mean and SD
- if there are non-normally distributed variables, show Median and IQR

For each variable in the table, compute the relevant statistical
functions in that list (non-applicable functions will safely return
`NA`).

You can specify the statistical functions yourself with the *stats*
argument. This argument can either be:

- a function for automatic selection of appropriate statistical
functions, depending on the data
- a named list of functions/formulas

The functions/formulas leverage the **tidyverse** way of working with
anonymous functions, i.e.:

If a *function*, is is used as is. If a *formula*, e.g. ‘\~ .x + 1’ or
`~ . + 1`, it is converted to a function. There are three ways to refer
to the arguments:

- For a single argument function, use ‘.’
- For a two argument function, use ‘.x’ and ‘.y’
- For more arguments, use ‘..1’, ‘..2’, ‘..3’ etc

This syntax allows you to create very compact anonymous functions, and
is the same as in the `map` family of functions from **purrr**.

**Conditional formulas (`condition ~ if_T | if F`) from previous
versions are no longer supported!**

### Automatic function

The default value for the *stats* argument is `stats_auto`, provided in
the package.

Several other “automatic statistical functions” are defined in this
package: `stats_auto`, `stats_default`, `stats_normal`,
`stats_nonnormal`.

You can also provide your own automatic function, which needs to

- accept a dataframe as its argument (whether to use this dataframe or
not in the function is your choice), and
- return a named list of statistical functions to use, as defined in
the subsequent paragraphs.

``` r
# Strictly equivalent to iris %>% desctable() %>% pander()
iris %>%
desctable(stats = stats_auto) %>%
pander()
```

|   | N | % | Mean | sd | Med | IQR |
|:---------------|:----|:----|:-----|:-----|:----|:----|
| Sepal.Length | 150 | | | | 5.8 | 1.3 |
| Sepal.Width | 150 | | 3.1 | 0.44 | 3 | 0.5 |
| Petal.Length | 150 | | | | 4.3 | 3.5 |
| Petal.Width | 150 | | | | 1.3 | 1.5 |
| **Species** | 150 | | | | | |
|     setosa | 50 | 33 | | | | |
|     versicolor | 50 | 33 | | | | |
|     virginica | 50 | 33 | | | | |

<br>

For reference, here is the body of the `stats_auto` function in the
package:

## function (data)
## {
## shapiro <- data %>% Filter(f = is.numeric) %>% lapply(is.normal) %>%
## unlist()
## if (length(shapiro) == 0) {
## normal <- F
## nonnormal <- F
## }
## else {
## normal <- any(shapiro)
## nonnormal <- any(!shapiro)
## }
## fact <- data %>% lapply(is.factor) %>% unlist() %>% any()
## if (fact & normal & !nonnormal)
## stats_normal(data)
## else if (fact & !normal & nonnormal)
## stats_nonnormal(data)
## else if (fact & !normal & !nonnormal)
## list(N = length, `%` = percent)
## else if (!fact & normal & nonnormal)
## list(N = length, Mean = ~if (is.normal(.)) mean(.), sd = ~if (is.normal(.)) sd(.),
## Med = stats::median, IQR = ~if (!is.factor(.)) IQR(.))
## else if (!fact & normal & !nonnormal)
## list(N = length, Mean = mean, sd = stats::sd)
## else if (!fact & !normal & nonnormal)
## list(N = length, Med = stats::median, IQR = IQR)
## else stats_default(data)
## }
## <bytecode: 0x56144fe581a8>
## <environment: namespace:desctable>

<br>

### Statistical functions

Statistical functions can be **any** function defined in R that you want
to use, such as `length` or `mean`.

The only condition is that they return a single numerical value. One
exception is when they return a vector of length `1 + nlevels(x)` when
applied to factors, as is needed for the `percent` function.

As mentioned above, they need to be used inside a **named list**, such
as

``` r
mtcars %>%
desctable(stats = list("N" = length, "Mean" = mean, "SD" = sd)) %>%
pander()
```

|   | N | Mean | SD |
|:-----|:----|:-----|:-----|
| mpg | 32 | 20 | 6 |
| cyl | 32 | 6.2 | 1.8 |
| disp | 32 | 231 | 124 |
| hp | 32 | 147 | 69 |
| drat | 32 | 3.6 | 0.53 |
| wt | 32 | 3.2 | 0.98 |
| qsec | 32 | 18 | 1.8 |
| vs | 32 | 0.44 | 0.5 |
| am | 32 | 0.41 | 0.5 |
| gear | 32 | 3.7 | 0.74 |
| carb | 32 | 2.8 | 1.6 |

<br>

The names will be used as column headers in the resulting table, and the
functions will be applied safely on the variables (errors return `NA`,
and for factors the function will be used on individual levels).

Several convenience functions are included in this package.

- `percent`, which prints percentages of levels in a factor
- `IQR`, which re-implements `stats::IQR` but works better with `NA`
values
- `is.normal`, which tests for normality using the following method:
`length(na.omit(x)) > 30 & shapiro.test(x)$p.value > .1`

Be aware that **all functions will be used on variables stripped of
their `NA` values!** This is necessary for most statistical functions to
be useful, and makes **N** (`length`) show only the number of
observations in the dataset for each variable.

### Labels

It is often the case that variable names are not “pretty” enough to be
used as-is in a table.
Although you could still edit the variable labels in the table
afterwards using sub-setting or string replacement functions, we provide
a facility for this using the **labels** argument.

The **labels** argument is a named character vector associating variable
names and labels.
You don’t need to provide labels for all the variables, and extra labels
will be silently discarded. This allows you to define a “global” labels
vector and use it for multiple tables even after variable selections.

``` r
mtlabels <- c(mpg = "Miles/(US) gallon",
cyl = "Number of cylinders",
disp = "Displacement (cu.in.)",
hp = "Gross horsepower",
drat = "Rear axle ratio",
wt = "Weight (1000 lbs)",
qsec = "¼ mile time",
vs = "V/S",
am = "Transmission",
gear = "Number of forward gears",
carb = "Number of carburetors")

mtcars %>%
dplyr::mutate(am = factor(am, labels = c("Automatic", "Manual"))) %>%
desctable(labels = mtlabels) %>%
pander()
```

|   | N | % | Mean | sd | Med | IQR |
|:------------------------|:----|:----|:-----|:-----|:----|:-----|
| Miles/(US) gallon | 32 | | 20 | 6 | 19 | 7.4 |
| Number of cylinders | 32 | | | | 6 | 4 |
| Displacement (cu.in.) | 32 | | | | 196 | 205 |
| Gross horsepower | 32 | | | | 123 | 84 |
| Rear axle ratio | 32 | | 3.6 | 0.53 | 3.7 | 0.84 |
| Weight (1000 lbs) | 32 | | | | 3.3 | 1 |
| ¼ mile time | 32 | | 18 | 1.8 | 18 | 2 |
| V/S | 32 | | | | 0 | 1 |
| **Transmission** | 32 | | | | | |
|     Automatic | 19 | 59 | | | | |
|     Manual | 13 | 41 | | | | |
| Number of forward gears | 32 | | | | 4 | 1 |
| Number of carburetors | 32 | | | | 2 | 2 |

<br>

------------------------------------------------------------------------

# Comparative tables

## Simple usage

Creating a comparative table (between groups defined by a factor) using
`desctable` is as easy as creating a descriptive table.

It leverages the `group_by` function from **dplyr**:

``` r
iris %>%
group_by(Species) %>%
desctable() -> iris_by_Species

iris_by_Species
```

##   Species: setosa (n=50) / N Species: setosa (n=50) / Mean
## 1 Sepal.Length 50 5.006
## 2 Sepal.Width 50 3.428
## 3 Petal.Length 50 NA
## 4 Petal.Width 50 NA
## Species: setosa (n=50) / sd Species: setosa (n=50) / Med
## 1 0.3524897 5.0
## 2 0.3790644 3.4
## 3 NA 1.5
## 4 NA 0.2
## Species: setosa (n=50) / IQR Species: versicolor (n=50) / N
## 1 0.400 50
## 2 0.475 50
## 3 0.175 50
## 4 0.100 50
## Species: versicolor (n=50) / Mean Species: versicolor (n=50) / sd
## 1 5.936 0.5161711
## 2 2.770 0.3137983
## 3 4.260 0.4699110
## 4 NA NA
## Species: versicolor (n=50) / Med Species: versicolor (n=50) / IQR
## 1 5.90 0.700
## 2 2.80 0.475
## 3 4.35 0.600
## 4 1.30 0.300
## Species: virginica (n=50) / N Species: virginica (n=50) / Mean
## 1 50 6.588
## 2 50 2.974
## 3 50 5.552
## 4 50 NA
## Species: virginica (n=50) / sd Species: virginica (n=50) / Med
## 1 0.6358796 6.50
## 2 0.3224966 3.00
## 3 0.5518947 5.55
## 4 NA 2.00
## Species: virginica (n=50) / IQR tests / p tests / test
## 1 0.675 1.505059e-28 oneway.test(., var.equal = F)
## 2 0.375 4.492017e-17 oneway.test(., var.equal = T)
## 3 0.775 4.803974e-29 kruskal.test
## 4 0.500 3.261796e-29 kruskal.test

<br>

The result is a table containing a descriptive sub-table for each level
of the grouping factor (the statistical functions rules are applied to
each sub-table independently), with the statistical tests performed, and
their p values.

When displayed as a flat dataframe, the grouping header appears in each
variable name.

You can also see the grouping headers by inspecting the resulting
object, which is a nested list of dataframes, each dataframe being named
after the grouping factor and its levels (with sample size for each).

``` r
str(iris_by_Species)
```

## List of 5
## $ Variables :'data.frame': 4 obs. of 1 variable:
## ..$ Variables: chr [1:4] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width"
## $ Species: setosa (n=50) :'data.frame': 4 obs. of 5 variables:
## ..$ N : int [1:4] 50 50 50 50
## ..$ Mean: num [1:4] 5.01 3.43 NA NA
## ..$ sd : num [1:4] 0.352 0.379 NA NA
## ..$ Med : num [1:4] 5 3.4 1.5 0.2
## ..$ IQR : num [1:4] 0.4 0.475 0.175 0.1
## $ Species: versicolor (n=50):'data.frame': 4 obs. of 5 variables:
## ..$ N : int [1:4] 50 50 50 50
## ..$ Mean: num [1:4] 5.94 2.77 4.26 NA
## ..$ sd : num [1:4] 0.516 0.314 0.47 NA
## ..$ Med : num [1:4] 5.9 2.8 4.35 1.3
## ..$ IQR : num [1:4] 0.7 0.475 0.6 0.3
## $ Species: virginica (n=50) :'data.frame': 4 obs. of 5 variables:
## ..$ N : int [1:4] 50 50 50 50
## ..$ Mean: num [1:4] 6.59 2.97 5.55 NA
## ..$ sd : num [1:4] 0.636 0.322 0.552 NA
## ..$ Med : num [1:4] 6.5 3 5.55 2
## ..$ IQR : num [1:4] 0.675 0.375 0.775 0.5
## $ tests :'data.frame': 4 obs. of 2 variables:
## ..$ p : num [1:4] 1.51e-28 4.49e-17 4.80e-29 3.26e-29
## ..$ test: chr [1:4] "oneway.test(., var.equal = F)" "oneway.test(., var.equal = T)" "kruskal.test" "kruskal.test"
## - attr(*, "class")= chr "desctable"

<br>

You can specify groups based on any variable, not only factors:

``` r
# With pander output
mtcars %>%
group_by(cyl) %>%
desctable() %>%
pander()
```

|   | cyl: 4 (n=11)<br/>N | <br/>Med | <br/>IQR | cyl: 6 (n=7)<br/>N | <br/>Med | <br/>IQR | cyl: 8 (n=14)<br/>N | <br/>Med | <br/>IQR | tests<br/>p | <br/>test |
|:-----|:--------------------|:---------|:---------|:-------------------|:---------|:---------|:--------------------|:---------|:---------|:------------|:-------------|
| mpg | 11 | 26 | 7.6 | 7 | 20 | 2.4 | 14 | 15 | 1.8 | 2.6e-06 | kruskal.test |
| disp | 11 | 108 | 42 | 7 | 168 | 36 | 14 | 350 | 88 | 1.6e-06 | kruskal.test |
| hp | 11 | 91 | 30 | 7 | 110 | 13 | 14 | 192 | 65 | 3.3e-06 | kruskal.test |
| drat | 11 | 4.1 | 0.35 | 7 | 3.9 | 0.56 | 14 | 3.1 | 0.15 | 0.00075 | kruskal.test |
| wt | 11 | 2.2 | 0.74 | 7 | 3.2 | 0.62 | 14 | 3.8 | 0.48 | 1.1e-05 | kruskal.test |
| qsec | 11 | 19 | 1.4 | 7 | 18 | 2.4 | 14 | 17 | 1.5 | 0.0062 | kruskal.test |
| vs | 11 | 1 | 0 | 7 | 1 | 1 | 14 | 0 | 0 | 3.2e-05 | kruskal.test |
| am | 11 | 1 | 0.5 | 7 | 0 | 1 | 14 | 0 | 0 | 0.014 | kruskal.test |
| gear | 11 | 4 | 0 | 7 | 4 | 0.5 | 14 | 3 | 0 | 0.0062 | kruskal.test |
| carb | 11 | 2 | 1 | 7 | 4 | 1.5 | 14 | 3.5 | 1.8 | 0.0017 | kruskal.test |

<br>

You can also specify groups based on an expression

``` r
iris %>%
group_by(Petal.Length > 5) %>%
desctable() %>%
pander()
```

|   | Petal.Length \> 5: FALSE (n=108)<br/>N | <br/>% | <br/>Mean | <br/>sd | <br/>Med | <br/>IQR | Petal.Length \> 5: TRUE (n=42)<br/>N | <br/>% | <br/>Mean | <br/>sd | <br/>Med | <br/>IQR | tests<br/>p | <br/>test |
|:---------------|:---------------------------------------|:-------|:----------|:--------|:---------|:---------|:-------------------------------------|:-------|:----------|:--------|:---------|:---------|:------------|:------------|
| Sepal.Length | 108 | | | | 5.5 | 1 | 42 | | | | 6.7 | 0.85 | 1.6e-15 | wilcox.test |
| Sepal.Width | 108 | | 3.1 | 0.48 | 3 | 0.6 | 42 | | | | 3 | 0.4 | 0.69 | wilcox.test |
| Petal.Length | 108 | | | | 3.5 | 3 | 42 | | | | 5.6 | 0.67 | 2.1e-21 | wilcox.test |
| Petal.Width | 108 | | | | 1 | 1.2 | 42 | | 2.1 | 0.28 | 2.1 | 0.47 | 1.6e-19 | wilcox.test |
| **Species** | 108 | | | | | | 42 | | | | | | 2.5e-26 | fisher.test |
|     setosa | 50 | 46 | | | | | 0 | 0 | | | | | | |
|     versicolor | 49 | 45 | | | | | 1 | 2.4 | | | | | | |
|     virginica | 9 | 8.3 | | | | | 41 | 98 | | | | | | |

<br>

Multiple nested groups are also possible:

``` r
mtcars %>%
dplyr::mutate(am = factor(am, labels = c("Automatic", "Manual"))) %>%
group_by(vs, am, cyl) %>%
desctable() %>%
pander()
```

|   | vs: 0 (n=18)<br/>am: Automatic (n=12)<br/>cyl: 8 (n=12)<br/>N | <br/><br/><br/>Med | <br/><br/><br/>IQR | <br/><br/>tests<br/>p | <br/><br/><br/>test | <br/>am: Manual (n=6)<br/>cyl: 4 (n=1)<br/>N | <br/><br/><br/>Med | <br/><br/><br/>IQR | <br/><br/>cyl: 6 (n=3)<br/>N | <br/><br/><br/>Med | <br/><br/><br/>IQR | <br/><br/>cyl: 8 (n=2)<br/>N | <br/><br/><br/>Med | <br/><br/><br/>IQR | <br/><br/>tests<br/>p | <br/><br/><br/>test | vs: 1 (n=14)<br/>am: Automatic (n=7)<br/>cyl: 4 (n=3)<br/>N | <br/><br/><br/>Med | <br/><br/><br/>IQR | <br/><br/>cyl: 6 (n=4)<br/>N | <br/><br/><br/>Med | <br/><br/><br/>IQR | <br/><br/>tests<br/>p | <br/><br/><br/>test | <br/>am: Manual (n=7)<br/>cyl: 4 (n=7)<br/>N | <br/><br/><br/>Med | <br/><br/><br/>IQR | <br/><br/>tests<br/>p | <br/><br/><br/>test |
|:-----|:--------------------------------------------------------------|:-------------------|:-------------------|:----------------------|:--------------------|:---------------------------------------------|:-------------------|:-------------------|:-----------------------------|:-------------------|:-------------------|:-----------------------------|:-------------------|:-------------------|:----------------------|:--------------------|:------------------------------------------------------------|:-------------------|:-------------------|:-----------------------------|:-------------------|:-------------------|:----------------------|:--------------------|:---------------------------------------------|:-------------------|:-------------------|:----------------------|:--------------------|
| mpg | 12 | 15 | 2.6 | | no.test | 1 | 26 | 0 | 3 | 21 | 0.65 | 2 | 15 | 0.4 | 0.11 | kruskal.test | 3 | 23 | 1.5 | 4 | 19 | 1.7 | 0.057 | wilcox.test | 7 | 30 | 6.3 | | no.test |
| disp | 12 | 355 | 113 | | no.test | 1 | 120 | 0 | 3 | 160 | 7.5 | 2 | 326 | 25 | 0.11 | kruskal.test | 3 | 141 | 13 | 4 | 196 | 66 | 0.05 | wilcox.test | 7 | 79 | 24 | | no.test |
| hp | 12 | 180 | 44 | | no.test | 1 | 91 | 0 | 3 | 110 | 32 | 2 | 300 | 36 | 0.11 | kruskal.test | 3 | 95 | 18 | 4 | 116 | 14 | 0.05 | wilcox.test | 7 | 66 | 36 | | no.test |
| drat | 12 | 3.1 | 0.11 | | no.test | 1 | 4.4 | 0 | 3 | 3.9 | 0.14 | 2 | 3.9 | 0.34 | 0.33 | kruskal.test | 3 | 3.7 | 0.11 | 4 | 3.5 | 0.92 | 0.85 | wilcox.test | 7 | 4.1 | 0.2 | | no.test |
| wt | 12 | 3.8 | 0.81 | | no.test | 1 | 2.1 | 0 | 3 | 2.8 | 0.13 | 2 | 3.4 | 0.2 | 0.12 | kruskal.test | 3 | 3.1 | 0.36 | 4 | 3.4 | 0.061 | 0.05 | wilcox.test | 7 | 1.9 | 0.53 | | no.test |
| qsec | 12 | 17 | 0.67 | | no.test | 1 | 17 | 0 | 3 | 16 | 0.76 | 2 | 15 | 0.05 | 0.17 | kruskal.test | 3 | 20 | 1.4 | 4 | 19 | 0.89 | 0.23 | wilcox.test | 7 | 19 | 0.62 | | no.test |
| gear | 12 | 3 | 0 | | no.test | 1 | 5 | 0 | 3 | 4 | 0.5 | 2 | 5 | 0 | 0.29 | kruskal.test | 3 | 4 | 0.5 | 4 | 3.5 | 1 | 0.84 | wilcox.test | 7 | 4 | 0 | | no.test |
| carb | 12 | 3 | 2 | | no.test | 1 | 2 | 0 | 3 | 4 | 1 | 2 | 6 | 2 | 0.26 | kruskal.test | 3 | 2 | 0.5 | 4 | 2.5 | 3 | 0.85 | wilcox.test | 7 | 1 | 1 | | no.test |

<br>

In the case of nested groups (a.k.a. sub-group analysis), statistical
tests are performed only between the groups of the deepest grouping
level.

Statistical tests are automatically selected depending on the data and
the grouping factor.

## Advanced usage

`desctable` automatically chooses statistical functions if none is
provided, using the following algorithm:

- if the variable is a factor, use `fisher.test`
- if the grouping factor has only one level, use the provided
`no.test` (which does nothing)
- if the grouping factor has two levels
- and the variable presents homoskedasticity (p value for
`var.test` \> .1) and normality of distribution in both groups,
use `t.test(var.equal = T)`
- and the variable does not present homoskedasticity (p value for
`var.test` \< .1) but normality of distribution in both groups,
use `t.test(var.equal = F)`
- else use `wilcox.test`
- if the grouping factor has more than two levels
- and the variable presents homoskedasticity (p value for
`bartlett.test` \> .1) and normality of distribution in all
groups, use `oneway.test(var.equal = T)`
- and the variable does not present homoskedasticity (p value for
`bartlett.test` \< .1) but normality of distribution in all
groups, use `oneway.test(var.equal = F)`
- else use `kruskal.test`

You can specify the statistical test functions yourself with the *tests*
argument. This argument can either be:

- a function for automatic selection of appropriate statistical test
functions, depending on the data
- a named list of statistical test functions

Please note that the statistical test functions **must** be given as
*formulas* so as to capture the name of the test to display in the
table. **purrr** style formulas are also accepted, as with the
statistical functions. This also allows to specify optional arguments of
such functions, and go around non-standard test functions (see
**Statistical test functions**).

### Automatic function

The default value for the *tests* argument is `tests_auto`, provided in
the package.

You can also provide your own automatic function, which needs to

- accept a variable and a grouping factor as its arguments, and
- return a single-term formula containing a statistical test function.

This function will be used on every variable and every grouping factor
to determine the appropriate test.

``` r
# Strictly equivalent to iris %>% group_by(Species) %>% desctable() %>% pander()
iris %>%
group_by(Species) %>%
desctable(tests = tests_auto) %>%
pander()
```

|   | Species: setosa (n=50)<br/>N | <br/>Mean | <br/>sd | <br/>Med | <br/>IQR | Species: versicolor (n=50)<br/>N | <br/>Mean | <br/>sd | <br/>Med | <br/>IQR | Species: virginica (n=50)<br/>N | <br/>Mean | <br/>sd | <br/>Med | <br/>IQR | tests<br/>p | <br/>test |
|:-------------|:-----------------------------|:----------|:--------|:---------|:---------|:---------------------------------|:----------|:--------|:---------|:---------|:--------------------------------|:----------|:--------|:---------|:---------|:------------|:------------------------------|
| Sepal.Length | 50 | 5 | 0.35 | 5 | 0.4 | 50 | 5.9 | 0.52 | 5.9 | 0.7 | 50 | 6.6 | 0.64 | 6.5 | 0.67 | 1.5e-28 | oneway.test(., var.equal = F) |
| Sepal.Width | 50 | 3.4 | 0.38 | 3.4 | 0.48 | 50 | 2.8 | 0.31 | 2.8 | 0.48 | 50 | 3 | 0.32 | 3 | 0.38 | 4.5e-17 | oneway.test(., var.equal = T) |
| Petal.Length | 50 | | | 1.5 | 0.18 | 50 | 4.3 | 0.47 | 4.3 | 0.6 | 50 | 5.6 | 0.55 | 5.5 | 0.78 | 4.8e-29 | kruskal.test |
| Petal.Width | 50 | | | 0.2 | 0.1 | 50 | | | 1.3 | 0.3 | 50 | | | 2 | 0.5 | 3.3e-29 | kruskal.test |

<br>

For reference, here is the body of the `tests_auto` function in the
package:

## function (var, grp)
## {
## grp <- factor(grp)
## if (nlevels(grp) < 2)
## ~no.test
## else if (is.factor(var)) {
## if (tryCatch(is.numeric(fisher.test(var ~ grp)$p.value),
## error = function(e) F))
## ~fisher.test
## else ~chisq.test
## }
## else {
## all_normal <- all(tapply(var, grp, is.normal))
## if (nlevels(grp) == 2) {
## if (all_normal) {
## if (tryCatch(stats::var.test(var ~ grp)$p.value >
## 0.1, warning = function(e) F, error = function(e) F))
## ~t.test(., var.equal = T)
## else ~t.test(., var.equal = F)
## }
## else ~wilcox.test
## }
## else {
## if (all_normal) {
## if (tryCatch(stats::bartlett.test(var ~ grp)$p.value >
## 0.1, warning = function(e) F, error = function(e) F))
## ~oneway.test(., var.equal = T)
## else ~oneway.test(., var.equal = F)
## }
## else ~kruskal.test
## }
## }
## }
## <bytecode: 0x56144cbe3948>
## <environment: namespace:desctable>

<br>

### Statistical test functions

You can provide a named list of statistical functions, but here the
mechanism is a bit different from the *stats* argument.

The list must contain either `.auto` or `.default`.

- `.auto` needs to be an automatic function, such as `tests_auto`. It
will be used by default on all variables to select a test
- `.default` needs to be a single-term formula containing a
statistical test function that will be used on all variables

You can also provide overrides to use specific tests for specific
variables.
This is done using list items named as the variable and containing a
single-term formula function.

``` r
iris %>%
group_by(Petal.Length > 5) %>%
desctable(tests = list(.auto = tests_auto,
Species = ~chisq.test)) %>%
pander()
```

|   | Petal.Length \> 5: FALSE (n=108)<br/>N | <br/>% | <br/>Mean | <br/>sd | <br/>Med | <br/>IQR | Petal.Length \> 5: TRUE (n=42)<br/>N | <br/>% | <br/>Mean | <br/>sd | <br/>Med | <br/>IQR | tests<br/>p | <br/>test |
|:---------------|:---------------------------------------|:-------|:----------|:--------|:---------|:---------|:-------------------------------------|:-------|:----------|:--------|:---------|:---------|:------------|:------------|
| Sepal.Length | 108 | | | | 5.5 | 1 | 42 | | | | 6.7 | 0.85 | 1.6e-15 | wilcox.test |
| Sepal.Width | 108 | | 3.1 | 0.48 | 3 | 0.6 | 42 | | | | 3 | 0.4 | 0.69 | wilcox.test |
| Petal.Length | 108 | | | | 3.5 | 3 | 42 | | | | 5.6 | 0.67 | 2.1e-21 | wilcox.test |
| Petal.Width | 108 | | | | 1 | 1.2 | 42 | | 2.1 | 0.28 | 2.1 | 0.47 | 1.6e-19 | wilcox.test |
| **Species** | 108 | | | | | | 42 | | | | | | 2.7e-24 | chisq.test |
|     setosa | 50 | 46 | | | | | 0 | 0 | | | | | | |
|     versicolor | 49 | 45 | | | | | 1 | 2.4 | | | | | | |
|     virginica | 9 | 8.3 | | | | | 41 | 98 | | | | | | |

<br>

``` r
mtcars %>%
dplyr::mutate(am = factor(am, labels = c("Automatic", "Manual"))) %>%
group_by(am) %>%
desctable(tests = list(.default = ~wilcox.test,
mpg = ~t.test)) %>%
pander()
```

|   | am: Automatic (n=19)<br/>N | <br/>Med | <br/>IQR | am: Manual (n=13)<br/>N | <br/>Med | <br/>IQR | tests<br/>p | <br/>test |
|:-----|:---------------------------|:---------|:---------|:------------------------|:---------|:---------|:------------|:------------|
| mpg | 19 | 17 | 4.2 | 13 | 23 | 9.4 | 0.0014 | t.test |
| cyl | 19 | 8 | 2 | 13 | 4 | 2 | 0.0039 | wilcox.test |
| disp | 19 | 276 | 164 | 13 | 120 | 81 | 0.00055 | wilcox.test |
| hp | 19 | 175 | 76 | 13 | 109 | 47 | 0.046 | wilcox.test |
| drat | 19 | 3.1 | 0.63 | 13 | 4.1 | 0.37 | 0.00014 | wilcox.test |
| wt | 19 | 3.5 | 0.41 | 13 | 2.3 | 0.84 | 4.3e-05 | wilcox.test |
| qsec | 19 | 18 | 2 | 13 | 17 | 2.1 | 0.27 | wilcox.test |
| vs | 19 | 0 | 1 | 13 | 1 | 1 | 0.36 | wilcox.test |
| gear | 19 | 3 | 0 | 13 | 4 | 1 | 7.6e-06 | wilcox.test |
| carb | 19 | 3 | 2 | 13 | 2 | 3 | 0.74 | wilcox.test |
or install the development version (0.3) from github with

Here’s an example of **purrr** style function:
devtools::install_github("desctable/desctable")

``` r
iris %>%
group_by(Petal.Length > 5) %>%
desctable(tests = list(.auto = tests_auto,
Petal.Width = ~oneway.test(., var.equal = T)))
```
# Roadmap

##   Petal.Length > 5: FALSE (n=108) / N
## 1 Sepal.Length 108
## 2 Sepal.Width 108
## 3 Petal.Length 108
## 4 Petal.Width 108
## 5 Species 108
## 6 Species: setosa 50
## 7 Species: versicolor 49
## 8 Species: virginica 9
## Petal.Length > 5: FALSE (n=108) / % Petal.Length > 5: FALSE (n=108) / Mean
## 1 NA NA
## 2 NA 3.066667
## 3 NA NA
## 4 NA NA
## 5 NA NA
## 6 46.296296 NA
## 7 45.370370 NA
## 8 8.333333 NA
## Petal.Length > 5: FALSE (n=108) / sd Petal.Length > 5: FALSE (n=108) / Med
## 1 NA 5.5
## 2 0.4800701 3.0
## 3 NA 3.5
## 4 NA 1.0
## 5 NA NA
## 6 NA NA
## 7 NA NA
## 8 NA NA
## Petal.Length > 5: FALSE (n=108) / IQR Petal.Length > 5: TRUE (n=42) / N
## 1 1.0 42
## 2 0.6 42
## 3 3.0 42
## 4 1.2 42
## 5 NA 42
## 6 NA 0
## 7 NA 1
## 8 NA 41
## Petal.Length > 5: TRUE (n=42) / % Petal.Length > 5: TRUE (n=42) / Mean
## 1 NA NA
## 2 NA NA
## 3 NA NA
## 4 NA 2.061905
## 5 NA NA
## 6 0.000000 NA
## 7 2.380952 NA
## 8 97.619048 NA
## Petal.Length > 5: TRUE (n=42) / sd Petal.Length > 5: TRUE (n=42) / Med
## 1 NA 6.7
## 2 NA 3.0
## 3 NA 5.6
## 4 0.2802023 2.1
## 5 NA NA
## 6 NA NA
## 7 NA NA
## 8 NA NA
## Petal.Length > 5: TRUE (n=42) / IQR tests / p
## 1 0.850 1.553676e-15
## 2 0.400 6.927432e-01
## 3 0.675 2.076978e-21
## 4 0.475 3.982443e-24
## 5 NA 2.453675e-26
## 6 NA NA
## 7 NA NA
## 8 NA NA
## tests / test
## 1 wilcox.test
## 2 wilcox.test
## 3 wilcox.test
## 4 oneway.test(., var.equal = T)
## 5 fisher.test
## 6 <NA>
## 7 <NA>
## 8 <NA>
## 0.3

<br>
This new version introduces a new internal representation as well as an
entirely new API for desctable !
The original `desctable` function and usage remains until 1.0, but
begins deprecation.

As with statistical functions, **any** statistical test function defined
in R can be used.
This new API is more flexible and more simple at the same time. Combine
`group_by`, `desc_table`, `desc_tests`, and `desc_output` to create
descriptive and comparative statistics tables and output them to various
formats.

The conditions are that the function
The internal representation is now a simple dataframe in the simple
descriptive case, and a nested dataframe with list-columns for
comparative tables, allowing easier manipulation by the user.

- accepts a formula (`variable ~ grouping_variable`) as a first
positional argument (as is the case with most tests, like `t.test`),
and
- returns an object with a `p.value` element.
## Next

Several convenience function are provided: formula versions for
`chisq.test` and `fisher.test` using generic S3 methods (thus the
behavior of standard calls to `chisq.test` and `fisher.test` are not
modified), and `ANOVA`, a partial application of `oneway.test` with
parameter *var.equal* = T.
- Add a `desc_output` for {gt}
- Implement a way to make tables for survival analysis.
- Implement a way to make tables for multivariate models.
- Allow univariate tests for simple tables
- add a column for totals in grouped tables

Loading…
Cancel
Save