Skip to contents

Computes a two-way cross-tabulation with optional weights, grouping (including combinations of multiple variables), percentage displays, and inferential statistics.

cross_tab() produces weighted or unweighted contingency tables with row or column percentages, optional grouping via by, and associated Chi-squared tests with Cramer's V and diagnostic information.

Both x and y variables are required. For one-way frequency tables, use freq() instead.

Usage

cross_tab(
  data,
  x,
  y = NULL,
  by = NULL,
  weights = NULL,
  rescale = FALSE,
  percent = c("none", "column", "row"),
  include_stats = TRUE,
  correct = FALSE,
  simulate_p = FALSE,
  simulate_B = 2000,
  digits = NULL,
  styled = TRUE,
  show_n = TRUE
)

Arguments

data

A data frame. Alternatively, a vector when using the vector-based interface.

x

Row variable (unquoted).

y

Column variable (unquoted). Mandatory; for one-way tables, use freq().

by

Optional grouping variable or expression. Can be a single variable or a combination of multiple variables (e.g. interaction(vs, am)).

weights

Optional numeric weights.

rescale

Logical. If TRUE, rescales weights so total weighted N matches raw N (default FALSE).

percent

One of "none", "row", "column".

include_stats

Logical; compute Chi-squared and Cramer's V (default TRUE).

correct

Logical; apply Yates continuity correction to the Chi-squared test. Only applicable to 2x2 tables. Default is FALSE.

simulate_p

Logical; use Monte Carlo p-value simulation (default FALSE).

simulate_B

Integer; number of replicates for Monte Carlo (default 2000).

digits

Number of decimals (default 1 for percentages, 0 for counts).

styled

Logical; if TRUE, returns a "spicy_cross_table" object (for printing).

show_n

Logical; if TRUE, adds marginal N totals when percent != "none".

Value

A data.frame, list of data.frames, or spicy_cross_table object. When by is used, returns a spicy_cross_table_list.

Global Options

The function recognizes the following global options that modify its default behavior:

The function recognizes the following global options that modify its default behavior:

  • options(spicy.percent = "column") Sets the default percentage mode for all calls to cross_tab(). Valid values are "none", "row", and "column". Equivalent to setting percent = "column" (or another choice) in each call.

  • options(spicy.simulate_p = TRUE) Enables Monte Carlo simulation for all Chi-squared tests by default. Equivalent to setting simulate_p = TRUE in every call.

  • options(spicy.rescale = TRUE) Automatically rescales weights so that total weighted N equals the raw N. Equivalent to setting rescale = TRUE in each call.

These options are convenient for users who wish to enforce consistent behavior across multiple calls to cross_tab() and other spicy table functions. They can be disabled or reset by setting them to NULL: options(spicy.percent = NULL, spicy.simulate_p = NULL, spicy.rescale = NULL).

Example:

options(spicy.simulate_p = TRUE, spicy.rescale = TRUE)
cross_tab(mtcars, cyl, gear, weights = mtcars$mpg)

Examples

# Basic crosstab
cross_tab(mtcars, cyl, gear)
#> Crosstable: cyl x gear (N)
#> 
#>  Values             3        4       5       Total 
#> ─────────────┼──────────────────────────┼────────────
#>  4                  1        8       2          11 
#>  6                  2        4       1           7 
#>  8                 12        0       2          14 
#> ─────────────┼──────────────────────────┼────────────
#>  Total             15       12       5          32 
#> 
#> Chi-2: 18.0 (df = 4), p = 0.001
#> Cramer's V: 0.53
#> Warning: 6 expected cells < 5 (66.7%). Minimum expected = 1.09. Consider `simulate_p = TRUE` or set globally via `options(spicy.simulate_p = TRUE)`.

# Weighted (rescaled)
cross_tab(mtcars, cyl, gear, weights = mtcars$mpg, rescale = TRUE)
#> Crosstable: cyl x gear (N)
#> 
#>  Values             3        4       5       Total 
#> ─────────────┼──────────────────────────┼────────────
#>  4                  1       11       3          15 
#>  6                  2        4       1           7 
#>  8                  9        0       2          11 
#> ─────────────┼──────────────────────────┼────────────
#>  Total             12       15       6          32 
#> 
#> Chi-2: 17.7 (df = 4), p = 0.001
#> Cramer's V: 0.53
#> Warning: 7 expected cells < 5 (77.8%). Minimum expected = 1.14. Consider `simulate_p = TRUE` or set globally via `options(spicy.simulate_p = TRUE)`.
#> Weight: mpg (rescaled)

# Grouped
cross_tab(mtcars, cyl, gear, by = am)
#> Crosstable: cyl x gear (N) | am = 0
#> 
#>  Values             3       4       5       Total 
#> ─────────────┼─────────────────────────┼────────────
#>  4                  1       2       0           3 
#>  6                  2       2       0           4 
#>  8                 12       0       0          12 
#> ─────────────┼─────────────────────────┼────────────
#>  Total             15       4       0          19 
#> 
#> Chi-2: NA (df = 4), p = NA
#> Cramer's V: NA
#> Warning: 8 expected cells < 5 (88.9%). 5 expected cells < 1. Minimum expected = 0. Consider `simulate_p = TRUE` or set globally via `options(spicy.simulate_p = TRUE)`.
#> 
#> Crosstable: cyl x gear (N) | am = 1
#> 
#>  Values            3       4       5       Total 
#> ─────────────┼────────────────────────┼────────────
#>  4                 0       6       2           8 
#>  6                 0       2       1           3 
#>  8                 0       0       2           2 
#> ─────────────┼────────────────────────┼────────────
#>  Total             0       8       5          13 
#> 
#> Chi-2: NA (df = 4), p = NA
#> Cramer's V: NA
#> Warning: 9 expected cells < 5 (100%). 4 expected cells < 1. Minimum expected = 0. Consider `simulate_p = TRUE` or set globally via `options(spicy.simulate_p = TRUE)`.

# Grouped by an interaction
cross_tab(mtcars, cyl, gear, by = interaction(vs, am))
#> Crosstable: cyl x gear (N) | vs x am = 0.0
#> 
#>  Values             3       4       5       Total 
#> ─────────────┼─────────────────────────┼────────────
#>  4                  0       0       0           0 
#>  6                  0       0       0           0 
#>  8                 12       0       0          12 
#> ─────────────┼─────────────────────────┼────────────
#>  Total             12       0       0          12 
#> 
#> Chi-2 and Cramer's V not computed: insufficient data (only one non-empty row/column).
#> 
#> Crosstable: cyl x gear (N) | vs x am = 1.0
#> 
#>  Values            3       4       5       Total 
#> ─────────────┼────────────────────────┼────────────
#>  4                 1       2       0           3 
#>  6                 2       2       0           4 
#>  8                 0       0       0           0 
#> ─────────────┼────────────────────────┼────────────
#>  Total             3       4       0           7 
#> 
#> Chi-2: NA (df = 4), p = NA
#> Cramer's V: NA
#> Warning: 9 expected cells < 5 (100%). 5 expected cells < 1. Minimum expected = 0. Consider `simulate_p = TRUE` or set globally via `options(spicy.simulate_p = TRUE)`.
#> 
#> Crosstable: cyl x gear (N) | vs x am = 0.1
#> 
#>  Values            3       4       5       Total 
#> ─────────────┼────────────────────────┼────────────
#>  4                 0       0       1           1 
#>  6                 0       2       1           3 
#>  8                 0       0       2           2 
#> ─────────────┼────────────────────────┼────────────
#>  Total             0       2       4           6 
#> 
#> Chi-2: NA (df = 4), p = NA
#> Cramer's V: NA
#> Warning: 9 expected cells < 5 (100%). 6 expected cells < 1. Minimum expected = 0. Consider `simulate_p = TRUE` or set globally via `options(spicy.simulate_p = TRUE)`.
#> 
#> Crosstable: cyl x gear (N) | vs x am = 1.1
#> 
#>  Values            3       4       5       Total 
#> ─────────────┼────────────────────────┼────────────
#>  4                 0       6       1           7 
#>  6                 0       0       0           0 
#>  8                 0       0       0           0 
#> ─────────────┼────────────────────────┼────────────
#>  Total             0       6       1           7 
#> 
#> Chi-2 and Cramer's V not computed: insufficient data (only one non-empty row/column).

# Set default percent mode globally
options(spicy.percent = "column")

# Now this will display column percentages by default
cross_tab(mtcars, cyl, gear)
#> Crosstable: cyl x gear (Column %)
#> 
#>  Values                3           4           5       Total 
#> ─────────────┼────────────────────────────────────┼────────────
#>  4                   6.7        66.7        40.0        34.4 
#>  6                  13.3        33.3        20.0        21.9 
#>  8                  80.0         0.0        40.0        43.8 
#> ─────────────┼────────────────────────────────────┼────────────
#>  Total             100.0       100.0       100.0       100.0 
#>  N                    15          12           5          32 
#> 
#> Chi-2: 18.0 (df = 4), p = 0.001
#> Cramer's V: 0.53
#> Warning: 6 expected cells < 5 (66.7%). Minimum expected = 1.09. Consider `simulate_p = TRUE` or set globally via `options(spicy.simulate_p = TRUE)`.

# Reset to default behavior
options(spicy.percent = NULL)

# 2x2 table with Yates correction
cross_tab(mtcars, vs, am, correct = TRUE)
#> Crosstable: vs x am (N)
#> 
#>  Values             0        1       Total 
#> ─────────────┼──────────────────┼────────────
#>  0                 12        6          18 
#>  1                  7        7          14 
#> ─────────────┼──────────────────┼────────────
#>  Total             19       13          32 
#> 
#> Chi-2: 0.3 (df = 1), p = 0.556
#> Cramer's V: 0.10
#> Yates continuity correction applied.