Package 'freqtables'

Title: Make Quick Descriptive Tables for Categorical Variables
Description: Quickly make tables of descriptive statistics (i.e., counts, percentages, confidence intervals) for categorical variables. This package is designed to work in a Tidyverse pipeline, and consideration has been given to get results from R to Microsoft Word ® with minimal pain.
Authors: Brad Cannell [aut, cre]
Maintainer: Brad Cannell <[email protected]>
License: MIT + file LICENSE
Version: 0.2.0.9000
Built: 2026-09-19 11:07:57 UTC
Source: https://github.com/brad-cannell/freqtables

Help Index


Add confidence intervals to frequency counts

Description

These helpers add intervals to freq_tbl() output, and are also used by freq_table(). Both retain the package's Student-t convention: SE = sqrt(p * (1 - p) / (N - 1)), with N - 1 degrees of freedom. For within-group intervals, N is that group's denominator; for overall intervals, N is the total input size. This is a compatibility convention, not the usual normal-z binomial Wald interval.

Usage

wald_ci(.data, percent_ci = 95, se = FALSE, critical_value = FALSE)

logit_ci(.data, percent_ci = 95, se = FALSE, critical_value = FALSE)

Arguments

.data

A frequency table from freq_tbl() or freq_table(). A plain data frame is also accepted if it contains n and n_group with prop_group/percent_group, or n_total with prop/percent. Optional overall columns use n_total with prop_total/percent_total. An ungrouped compact table needs its original freqtables metadata or an explicit n_total; totals are never reconstructed by summing a possibly filtered table. Counts must be finite nonnegative integers no larger than their denominators. Displayed proportions must agree with those counts.

percent_ci

Confidence level as a percentage, strictly between 0 and 100; default 95. Independent of the table's proportion/percentage scale.

se

Logical. Include standard errors? Default FALSE.

critical_value

Logical. Include Student-t critical values in t_crit, t_crit_group, and/or t_crit_total? Default FALSE.

Details

wald_ci() returns ⁠p +/- t * SE⁠ without clipping to the unit interval. logit_ci() transforms ⁠log(p / (1 - p)) +/- t * SE / (p * (1 - p))⁠ back to the proportion scale with stats::plogis(). At p = 0 or 1, logit bounds are missing (no continuity correction); Wald bounds equal p. With N <= 1, SE, critical values, and both types of bounds are missing.

Value

The input table with lcl/ucl, lcl_group/ucl_group, and/or lcl_total/ucl_total for each proportion present. Bounds and standard errors use the input scale; critical values do not scale. Repeated calls replace interval/detail columns for the same proportions, including removal of unrequested optional detail columns.

Examples

freq_tbl(mtcars, am) |> wald_ci()
freq_tbl(mtcars, am) |> logit_ci(percent_ci = 99, se = TRUE)
mtcars |> dplyr::group_by(cyl) |>
  freq_tbl(am, percent = TRUE, overall = TRUE) |>
  logit_ci(critical_value = TRUE)

Format statistics for presentation

Description

Append a character column composed from existing table columns and literal text. Works with compact proportions, percentages, grouped results, and freq_test() output. Calculations retain full precision; rounding happens only in the new display column.

Usage

freq_format(.data, recipe, name = NA, digits = NA)

Arguments

.data

A data frame, commonly from freq_tbl() or freq_table().

recipe

One quoted string containing column-name tokens and literal text, e.g. "n (percent%)" or "prop_group (lcl_group - ucl_group)". Tokens use word boundaries; names containing spaces/punctuation should be renamed first. Unmatched tokens remain literal text.

name

Name of the appended column. Default NA selects "formatted_stats". An existing column with this name is replaced.

digits

Nonnegative integer number of decimal places. Default NA uses character conversion without explicit rounding. When supplied, doubles are rounded with trailing zeros and thousands separators; integer counts retain their integer representation. Character categories are not rounded.

Value

The input data frame with one character column added or replaced.

Examples

freq_table(mtcars, am, percent = TRUE) |>
  freq_format("percent (lcl - ucl)", name = "percent_ci", digits = 2)
mtcars |> dplyr::group_by(cyl) |> freq_table(am) |>
  freq_format("n: prop_group (lcl_group - ucl_group)", digits = 3)

Simulated study data.

Description

This is the code to create the study data - a simulated datas et that can be used to demonstrate how to use the freqtables package.

Usage

freq_study

Format

A data frame with 100 rows and 6 variables:

id

Participant's study identification number

age_group

Participant's age at the time of enrollment categorized as "Younger than 30" or "30 and Older"

sex

Biological sex of the participant assigned at birth, female/male

bmi_4cat

Participant's bmi at date of enrollment categorized as "Underweight", "Normal", "Overweight", or "Obese"

exposure

Participant was exposed to a hypothetical risk factor of interest, Yes/No

outcome

Participant experienced a hypothetical outcome of interest, Yes/No


Frequency tables with confidence intervals

Description

Combine freq_tbl() with logit_ci() or wald_ci(). Accept one outcome; supply groups using dplyr::group_by(). Defaults are compact proportions with confidence intervals. See vignette("migration") for the transition from the old percentage-scale, two-variable interface.

Usage

freq_table(
  .data,
  .freq_var,
  ...,
  percent_ci = 95,
  ci_type = "logit",
  drop = FALSE,
  percent = FALSE,
  overall = FALSE,
  se = FALSE,
  critical_value = FALSE,
  generic_col_names = FALSE
)

Arguments

.data

A local data frame or grouped data frame. Rowwise data is not supported; call dplyr::ungroup() first.

.freq_var

One unquoted column name (or a string naming a column). In a wrapper function, use {{ variable }}.

...

Reserved for detecting obsolete multiple-outcome calls and misspelled options. Must be empty; options must be named.

percent_ci

Confidence level as a percentage, strictly between 0 and 100; default 95. Independent of the table's proportion/percentage scale.

ci_type

Interval method: "logit" (default) or "wald". Both methods support ungrouped and grouped data. Supply a string.

drop

Logical. If FALSE (default), retain unobserved factor levels and empty factor groups with zero counts. If TRUE, retain observed combinations only. Does not remove missing values.

percent

Logical. If FALSE, return proportions in prop, prop_group, and (when requested) prop_total. If TRUE, use percent, percent_group, and percent_total on the 0–100 scale.

overall

Logical. For grouped data, append n_total and prop_total (or percent_total): the cell count divided by the total input rows, not the outcome's marginal proportion. For ungrouped data, append only n_total; prop is already the overall proportion.

se

Logical. Include standard errors? Default FALSE.

critical_value

Logical. Include Student-t critical values in t_crit, t_crit_group, and/or t_crit_total? Default FALSE.

generic_col_names

Logical. If TRUE, replace each group column with group_01_col/group_01_cat, etc., and the outcome with col/cat. Category columns become character for stacking tables.

Value

An ungrouped tibble with the freq_tbl() columns plus confidence limits. Classes are freq_table_one_way (no groups), freq_table_two_way (one group), or freq_table_n_way (multiple groups), together with freq_tbl and tibble classes. freq_test() supports the first two cases; multiple grouping variables do not imply a particular statistical test.

Examples

freq_table(mtcars, am)
mtcars |> dplyr::group_by(cyl) |> freq_table(am)
mtcars |> dplyr::group_by(cyl, vs) |>
  freq_table(am, ci_type = "wald", percent_ci = 90)
freq_table(mtcars, am, percent = TRUE, overall = TRUE,
           se = TRUE, critical_value = TRUE, generic_col_names = TRUE)

Compact counts and proportions

Description

Count one outcome within zero, one, or multiple groups supplied by dplyr::group_by(). Each observation contributes once, including missing outcomes and missing group values. Use dplyr::filter() before counting to exclude missing observations explicitly.

Usage

freq_tbl(
  .data,
  .freq_var,
  ...,
  drop = FALSE,
  percent = FALSE,
  overall = FALSE,
  generic_col_names = FALSE
)

Arguments

.data

A local data frame or grouped data frame. Rowwise data is not supported; call dplyr::ungroup() first.

.freq_var

One unquoted column name (or a string naming a column). In a wrapper function, use {{ variable }}.

...

Reserved for detecting obsolete multiple-outcome calls and misspelled options. Must be empty; options must be named.

drop

Logical. If FALSE (default), retain unobserved factor levels and empty factor groups with zero counts. If TRUE, retain observed combinations only. Does not remove missing values.

percent

Logical. If FALSE, return proportions in prop, prop_group, and (when requested) prop_total. If TRUE, use percent, percent_group, and percent_total on the 0–100 scale.

overall

Logical. For grouped data, append n_total and prop_total (or percent_total): the cell count divided by the total input rows, not the outcome's marginal proportion. For ungrouped data, append only n_total; prop is already the overall proportion.

generic_col_names

Logical. If TRUE, replace each group column with group_01_col/group_01_cat, etc., and the outcome with col/cat. Category columns become character for stacking tables.

Value

An ungrouped tibble of class freq_tbl. Ungrouped defaults are outcome, n, prop; grouped defaults are group columns, outcome, n, n_group, prop_group. n_group is the total number of observations in that group, across all outcome categories. Zero denominators produce NA_real_ proportions. Variable types are preserved unless generic headers are requested. Metadata retains the original total for subsequent confidence-interval calculations even after filtering rows. Analysis column names that collide with generated columns are rejected; rename them before calling.

Examples

freq_tbl(mtcars, am)
mtcars |> dplyr::group_by(cyl) |> freq_tbl(am)
mtcars |> dplyr::group_by(cyl, vs) |> freq_tbl(am, percent = TRUE)
freq_tbl(mtcars, am, generic_col_names = TRUE, overall = TRUE)

Hypothesis tests for frequency tables

Description

Test equal category probabilities for an ungrouped table, or independence between one grouping variable and the outcome for a two-way table. Pearson's statistic is uncorrected (no Yates correction). For a two-way table with any expected count <= 5, also return Fisher's exact p-value and emit a message. The table is constructed from category identities, with omitted cells filled with zero, so row order and non-binary groups work.

Usage

freq_test(.data, ...)

## S3 method for class 'freq_table_one_way'
freq_test(.data, ...)

## S3 method for class 'freq_table_two_way'
freq_test(.data, ...)

## Default S3 method:
freq_test(.data, ...)

Arguments

.data

A complete freq_table_one_way or freq_table_two_way result from freq_table(), with its metadata and category/count columns intact. Missing values count as categories unless filtered before making the table. Tables stacked from different outcomes are not supported. Two-way tests require at least two observed categories on each axis and no zero marginal totals; use drop = TRUE to omit empty factor levels.

...

Reserved; no extra arguments are currently supported by either method. Nonempty ... produces an error rather than being ignored.

Value

The input with expected counts, per-cell chi-square contributions, the overall Pearson statistic, degrees of freedom, and p_chi2_pearson. Two-way output also has n_col, r, c, and (when expected counts are small) p_fisher. Omitted zero-count cells contribute to the statistic even though they are absent from the output. Fisher's exact calculation can fail for very large tables; the error from stats::fisher.test() is propagated.

Examples

freq_table(mtcars, am) |> freq_test()
mtcars |> dplyr::group_by(am) |> freq_table(cyl) |> freq_test()
mtcars |> dplyr::group_by(cyl) |>
  freq_table(am, generic_col_names = TRUE) |> freq_test()

Contingency count matrices and grouped arrays

Description

Cross-tabulate two columns, with exposure in rows and outcome in columns. Groups supplied by dplyr::group_by() become additional array dimensions in the supplied order. Every input row contributes once, including missing values; filter observations explicitly before counting to exclude them.

Usage

freq_xtab(.data, exposure, outcome, ..., margins = TRUE, drop = FALSE)

Arguments

.data

A local data frame or grouped data frame. Rowwise data is not supported; call dplyr::ungroup() first.

exposure, outcome

Two distinct unquoted column names, or strings naming columns. Forward columns in wrappers with {{ }}. Neither column may also be a grouping variable. Columns must be one-dimensional atomic vectors (for example factors, character, numeric, logical, or Date vectors).

...

Must be empty. Options must be named; derived columns should be created with dplyr::mutate() before calling.

margins

Logical. If TRUE (default), append a total row and column to each matrix, labeled Sum. If that label already exists on an axis, use the first available Sum.1, Sum.2, etc. Group dimensions have no margins. Use FALSE to obtain only the cell counts for further analysis.

drop

Logical. If FALSE (default), retain unused factor levels on every axis. If TRUE, remove globally unused levels, overriding the input's grouping drop setting. Both settings fill absent combinations with zero so every group has the same matrix dimensions. Missing values are retained independently of this option.

Value

A numeric matrix for ungrouped input, or a numeric array with dimensions exposure, outcome, then each grouping variable. Dimension names are the original column names. Factor categories follow level order; other categories are sorted (character values in C-locale order), with missing values last. Labels are character representations of categories; ambiguous representations of distinct values are rejected. Missing labels are actual NA_character_, distinct from literal strings such as "NA". Select a missing category by position using which(is.na(dimnames(x)[[i]])).

Unobserved combinations, including empty group combinations, have zero counts. Empty input retains factor levels when drop = FALSE; other axes have length zero before margins. Thus empty ungrouped character input is a 1-by-1 zero matrix with margins, or a 0-by-0 matrix without. A grouped result with a zero-length grouping axis has no matrix slices. Singleton dimensions are retained in the returned object; use drop = FALSE when subsetting if those dimensions should remain.

Examples

freq_xtab(mtcars, vs, am)
freq_xtab(mtcars, "vs", "am", margins = FALSE)
mtcars |> dplyr::group_by(cyl) |> freq_xtab(vs, am)
mtcars |> dplyr::group_by(cyl, gear) |> freq_xtab(vs, am, drop = TRUE)

Formatted Group Sample Size for Tables

Description

Given a tibble and a filter expression, get_group_n returns the group sample size formatted as "N = XXXX". Made to work in a dplyr pipeline, and used when creating tables for publications / reports.

Usage

get_group_n(.data, ...)

Arguments

.data

A local data frame or tibble, optionally grouped. Grouped input returns one label per retained group, in dplyr group order.

...

Zero or more dplyr::filter expressions, combined with AND. With no expressions, count all input rows. Missing logical results are excluded by filter(). Expressions may use dplyr data masking.

Value

A character vector of formatted counts. Ungrouped input returns one label, including "N = 0" when no observations remain.

Examples

library(dplyr)
library(freqtables)

data(mtcars)

# Get sample size for cars with 4 cylinders
mtcars %>% get_group_n(cyl == 4)

#> [1] "N = 11"