Skip to contents

freq() and cross_tab() are the core tabulation functions in spicy. They handle factors, labelled variables (from haven or labelled), weights, and missing values out of the box. This article covers the main options using the bundled sochealth dataset.

Frequency tables with freq()

Basic usage

Pass a data frame and a variable name to get counts and percentages:

freq(sochealth, education)
#> Frequency table: education
#> 
#>  Category   │ Values               Freq.    Percent 
#> ────────────┼───────────────────────────────────────
#>  Valid      │ Lower secondary        261       21.8 
#>             │ Upper secondary        539       44.9 
#>             │ Tertiary               400       33.3 
#> ────────────┼───────────────────────────────────────
#>  Total      │                       1200      100.0 
#> 
#> Label: Highest education level
#> Class: ordered, factor
#> Data: sochealth

Sorting

Sort by frequency with sort = "-" (decreasing) or sort = "+" (increasing). Sort alphabetically with sort = "name+" or sort = "name-":

freq(sochealth, education, sort = "-")
#> Frequency table: education
#> 
#>  Category   │ Values               Freq.    Percent 
#> ────────────┼───────────────────────────────────────
#>  Valid      │ Upper secondary        539       44.9 
#>             │ Tertiary               400       33.3 
#>             │ Lower secondary        261       21.8 
#> ────────────┼───────────────────────────────────────
#>  Total      │                       1200      100.0 
#> 
#> Label: Highest education level
#> Class: ordered, factor
#> Data: sochealth

Sort alphabetically:

freq(sochealth, education, sort = "name+")
#> Frequency table: education
#> 
#>  Category   │ Values               Freq.    Percent 
#> ────────────┼───────────────────────────────────────
#>  Valid      │ Lower secondary        261       21.8 
#>             │ Tertiary               400       33.3 
#>             │ Upper secondary        539       44.9 
#> ────────────┼───────────────────────────────────────
#>  Total      │                       1200      100.0 
#> 
#> Label: Highest education level
#> Class: ordered, factor
#> Data: sochealth

Cumulative percentages

Add cumulative columns with cum = TRUE:

freq(sochealth, smoking, cum = TRUE)
#> Frequency table: smoking
#> 
#>  Category   │ Values      Freq.    Percent    Valid Percent    Cum. Percent 
#> ────────────┼───────────────────────────────────────────────────────────────
#>  Valid      │ No            926       77.2             78.8            77.2 
#>             │ Yes           249       20.8             21.2            97.9 
#>  Missing    │ NA             25        2.1                            100.0 
#> ────────────┼───────────────────────────────────────────────────────────────
#>  Total      │              1200      100.0            100.0           100.0 
#> 
#>  Category   │ Values      Cum. Valid Percent 
#> ────────────┼────────────────────────────────
#>  Valid      │ No                        78.8 
#>             │ Yes                      100.0 
#>  Missing    │ NA                             
#> ────────────┼────────────────────────────────
#>  Total      │                          100.0 
#> 
#> Label: Current smoker
#> Class: factor
#> Data: sochealth

Weighted frequencies

Supply a weight variable with weights. By default (rescale = FALSE), the table shows the raw weighted counts:

freq(sochealth, education, weights = weight)
#> Frequency table: education
#> 
#>  Category   │ Values               Freq.    Percent 
#> ────────────┼───────────────────────────────────────
#>  Valid      │ Lower secondary        258       21.6 
#>             │ Upper secondary        545       45.5 
#>             │ Tertiary               394       32.9 
#> ────────────┼───────────────────────────────────────
#>  Total      │                       1196      100.0 
#> 
#> Label: Highest education level
#> Class: ordered, factor
#> Data: sochealth
#> Weight: weight

Set rescale = TRUE to adjust the weighted total to match the unweighted sample size:

freq(sochealth, education, weights = weight, rescale = TRUE)
#> Frequency table: education
#> 
#>  Category   │ Values               Freq.    Percent 
#> ────────────┼───────────────────────────────────────
#>  Valid      │ Lower secondary        259       21.6 
#>             │ Upper secondary        546       45.5 
#>             │ Tertiary               395       32.9 
#> ────────────┼───────────────────────────────────────
#>  Total      │                       1200      100.0 
#> 
#> Label: Highest education level
#> Class: ordered, factor
#> Data: sochealth
#> Weight: weight (rescaled)

Labelled variables

When a variable has value labels (e.g., imported from SPSS or Stata with haven), freq() shows them by default with the [code] label format. Control this with labelled_levels:

# Create a labelled version of the smoking variable
sh <- sochealth
sh$smoking_lbl <- labelled::labelled(
  ifelse(sh$smoking == "Yes", 1L, 0L),
  labels = c("Non-smoker" = 0L, "Current smoker" = 1L)
)

# Default: [code] label
freq(sh, smoking_lbl)
#> Frequency table: smoking_lbl
#> 
#>  Category   │ Values                  Freq.    Percent    Valid Percent 
#> ────────────┼───────────────────────────────────────────────────────────
#>  Valid      │ [0] Non-smoker            926       77.2             78.8 
#>             │ [1] Current smoker        249       20.8             21.2 
#>  Missing    │ NA                         25        2.1                  
#> ────────────┼───────────────────────────────────────────────────────────
#>  Total      │                          1200      100.0            100.0 
#> 
#> Class: haven_labelled, vctrs_vctr, integer
#> Data: sh

# Labels only (no codes)
freq(sh, smoking_lbl, labelled_levels = "labels")
#> Frequency table: smoking_lbl
#> 
#>  Category   │ Values              Freq.    Percent    Valid Percent 
#> ────────────┼───────────────────────────────────────────────────────
#>  Valid      │ Non-smoker            926       77.2             78.8 
#>             │ Current smoker        249       20.8             21.2 
#>  Missing    │ NA                     25        2.1                  
#> ────────────┼───────────────────────────────────────────────────────
#>  Total      │                      1200      100.0            100.0 
#> 
#> Class: haven_labelled, vctrs_vctr, integer
#> Data: sh

# Codes only (no labels)
freq(sh, smoking_lbl, labelled_levels = "values")
#> Frequency table: smoking_lbl
#> 
#>  Category   │ Values      Freq.    Percent    Valid Percent 
#> ────────────┼───────────────────────────────────────────────
#>  Valid      │ 0             926       77.2             78.8 
#>             │ 1             249       20.8             21.2 
#>  Missing    │ NA             25        2.1                  
#> ────────────┼───────────────────────────────────────────────
#>  Total      │              1200      100.0            100.0 
#> 
#> Class: haven_labelled, vctrs_vctr, integer
#> Data: sh

Custom missing values

Raw data files often store nonresponse as an ordinary level – a “Refused” or “Don’t know” answer sitting next to the substantive categories. na_val reclassifies such a value as missing: it moves to the Missing block and valid percentages are computed without it.

# Simulate a raw file where nonresponse was typed as a level
sh$income_raw <- as.character(sochealth$income_group)
sh$income_raw[is.na(sh$income_raw)] <- "Refused"

# "Refused" counts as a valid answer...
freq(sh, income_raw)
#> Frequency table: income_raw
#> 
#>  Category   │ Values            Freq.    Percent 
#> ────────────┼────────────────────────────────────
#>  Valid      │ High                219       18.2 
#>             │ Low                 247       20.6 
#>             │ Lower middle        388       32.3 
#>             │ Refused              18        1.5 
#>             │ Upper middle        328       27.3 
#> ────────────┼────────────────────────────────────
#>  Total      │                    1200      100.0 
#> 
#> Class: character
#> Data: sh

# ...until na_val reclassifies it as missing
freq(sh, income_raw, na_val = "Refused")
#> Frequency table: income_raw
#> 
#>  Category   │ Values            Freq.    Percent    Valid Percent 
#> ────────────┼─────────────────────────────────────────────────────
#>  Valid      │ High                219       18.2             18.5 
#>             │ Low                 247       20.6             20.9 
#>             │ Lower middle        388       32.3             32.8 
#>             │ Upper middle        328       27.3             27.7 
#>  Missing    │ NA                   18        1.5                  
#> ────────────┼─────────────────────────────────────────────────────
#>  Total      │                    1200      100.0            100.0 
#> 
#> Class: character
#> Data: sh

Declared missing values

Survey files imported with haven often declare codes as missing at the source – 8 = Refused, 9 = Don't know – through na_values/na_range (SPSS-style) or tagged NAs (Stata-style). The two behave differently in R. SPSS-style codes are not NA, so most packages silently treat them as valid answers. Stata-style tagged NAs are genuine NAs, but most packages collapse them into a single undifferentiated NA count. spicy honors both declarations by default: the codes are excluded from valid percentages and statistics, and freq() shows them as labelled rows of its Missing block instead of erasing them.

sh2 <- sochealth
sh2$trust <- labelled::labelled_spss(
  c(1, 2, 8, 1, 9, 2, 1, 8, 2, 1, rep(c(1, 2), 595)),
  labels = c("Low" = 1, "High" = 2, "Refused" = 8, "Don't know" = 9),
  na_values = c(8, 9)
)
freq(sh2, trust)
#> Frequency table: trust
#> 
#>  Category   │ Values              Freq.    Percent    Valid Percent 
#> ────────────┼───────────────────────────────────────────────────────
#>  Valid      │ [1] Low               599       49.9             50.0 
#>             │ [2] High              598       49.8             50.0 
#>  Missing    │ [8] Refused             2        0.2                  
#>             │ [9] Don't know          1        0.1                  
#> ────────────┼───────────────────────────────────────────────────────
#>  Total      │                      1200      100.0            100.0 
#> 
#> Class: haven_labelled_spss, haven_labelled, vctrs_vctr, double
#> Data: sh2

Set user_na = FALSE to treat SPSS-style declared codes as ordinary categories instead; tagged NAs are genuine NAs either way, so for them it only collapses the per-tag breakdown into the regular NA count. The same argument, with the same default, exists in cross_tab(), the descriptive helpers table_categorical(), table_continuous() and table_continuous_lm(), and the row-wise functions mean_n(), sum_n() and count_n(). (table_regression() takes a fitted model, not raw data, so the argument does not apply there.) cross_tab() and the descriptive helpers disclose the exclusion in the table note; the row-wise functions return bare numeric vectors, so they count the declared codes as missing without any note. See the “Declared missing values” section of ?freq for the full contract.

Cross-tabulations with cross_tab()

Basic two-way table

Cross two variables to get a contingency table with a chi-squared test and effect size:

cross_tab(sochealth, smoking, education)
#> Crosstable: smoking x education (N)
#> 
#>  Values   │   Lower secondary    Upper secondary    Tertiary │   Total 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  No       │               179                415         332 │     926 
#>  Yes      │                78                112          59 │     249 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  Total    │               257                527         391 │    1175 
#> 
#> Chi-2(2) = 21.6, p <.001
#> Cramer's V = 0.14
#> Missing values removed: smoking (25).

Row and column percentages

Use percent = "row" or percent = "column" to display percentages instead of raw counts:

cross_tab(sochealth, smoking, education, percent = "column")
#> Crosstable: smoking x education (Column %)
#> 
#>  Values   │   Lower secondary    Upper secondary    Tertiary │   Total 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  No       │              69.6               78.7        84.9 │    78.8 
#>  Yes      │              30.4               21.3        15.1 │    21.2 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  Total    │             100.0              100.0       100.0 │   100.0 
#>  N        │               257                527         391 │    1175 
#> 
#> Chi-2(2) = 21.6, p <.001
#> Cramer's V = 0.14
#> Missing values removed: smoking (25).
cross_tab(sochealth, smoking, education, percent = "row")
#> Crosstable: smoking x education (Row %)
#> 
#>  Values   │   Lower secondary    Upper secondary    Tertiary │   Total       N 
#> ──────────┼──────────────────────────────────────────────────┼─────────────────
#>  No       │              19.3               44.8        35.9 │   100.0     926 
#>  Yes      │              31.3               45.0        23.7 │   100.0     249 
#> ──────────┼──────────────────────────────────────────────────┼─────────────────
#>  Total    │              21.9               44.9        33.3 │   100.0    1175 
#> 
#> Chi-2(2) = 21.6, p <.001
#> Cramer's V = 0.14
#> Missing values removed: smoking (25).

Grouping with by

Stratify the table by a third variable:

cross_tab(sochealth, smoking, education, by = sex)
#> Crosstable: smoking x education (N) | sex = Female
#> 
#>  Values   │   Lower secondary    Upper secondary    Tertiary │   Total 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  No       │                95                220         160 │     475 
#>  Yes      │                38                 62          31 │     131 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  Total    │               133                282         191 │     606 
#> 
#> Chi-2(2) = 7.1, p = .029
#> Cramer's V = 0.11
#> Missing values removed: smoking (14).
#> 
#> Crosstable: smoking x education (N) | sex = Male
#> 
#>  Values   │   Lower secondary    Upper secondary    Tertiary │   Total 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  No       │                84                195         172 │     451 
#>  Yes      │                40                 50          28 │     118 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  Total    │               124                245         200 │     569 
#> 
#> Chi-2(2) = 15.6, p <.001
#> Cramer's V = 0.17
#> Missing values removed: smoking (11).

For more than one grouping variable, use interaction():

cross_tab(sochealth, smoking, education,
          by = interaction(sex, age_group))
#> Crosstable: smoking x education (N) | sex x age_group = Female.25-34
#> 
#>  Values   │   Lower secondary    Upper secondary    Tertiary │   Total 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  No       │                23                 49          29 │     101 
#>  Yes      │                 9                  9           7 │      25 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  Total    │                32                 58          36 │     126 
#> 
#> Chi-2(2) = 2.1, p = .356
#> Cramer's V = 0.13
#> Missing values removed: smoking (4).
#> 
#> Crosstable: smoking x education (N) | sex x age_group = Male.25-34
#> 
#>  Values   │   Lower secondary    Upper secondary    Tertiary │   Total 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  No       │                 9                 42          32 │      83 
#>  Yes      │                11                 11           4 │      26 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  Total    │                20                 53          36 │     109 
#> 
#> Chi-2(2) = 14.2, p <.001
#> Cramer's V = 0.36
#> Missing values removed: smoking (3).
#> 
#> Crosstable: smoking x education (N) | sex x age_group = Female.35-49
#> 
#>  Values   │   Lower secondary    Upper secondary    Tertiary │   Total 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  No       │                24                 73          48 │     145 
#>  Yes      │                10                 20           8 │      38 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  Total    │                34                 93          56 │     183 
#> 
#> Chi-2(2) = 3.0, p = .223
#> Cramer's V = 0.13
#> Missing values removed: smoking (7).
#> 
#> Crosstable: smoking x education (N) | sex x age_group = Male.35-49
#> 
#>  Values   │   Lower secondary    Upper secondary    Tertiary │   Total 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  No       │                33                 59          60 │     152 
#>  Yes      │                14                 17           7 │      38 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  Total    │                47                 76          67 │     190 
#> 
#> Chi-2(2) = 6.9, p = .032
#> Cramer's V = 0.19
#> Missing values removed: smoking (3).
#> 
#> Crosstable: smoking x education (N) | sex x age_group = Female.50-64
#> 
#>  Values   │   Lower secondary    Upper secondary    Tertiary │   Total 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  No       │                28                 63          45 │     136 
#>  Yes      │                 8                 16           6 │      30 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  Total    │                36                 79          51 │     166 
#> 
#> Chi-2(2) = 2.0, p = .360
#> Cramer's V = 0.11
#> Missing values removed: smoking (3).
#> 
#> Crosstable: smoking x education (N) | sex x age_group = Male.50-64
#> 
#>  Values   │   Lower secondary    Upper secondary    Tertiary │   Total 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  No       │                28                 58          42 │     128 
#>  Yes      │                 8                 13           5 │      26 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  Total    │                36                 71          47 │     154 
#> 
#> Chi-2(2) = 2.1, p = .343
#> Cramer's V = 0.12
#> Missing values removed: smoking (4).
#> 
#> Crosstable: smoking x education (N) | sex x age_group = Female.65-75
#> 
#>  Values   │   Lower secondary    Upper secondary    Tertiary │   Total 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  No       │                20                 35          38 │      93 
#>  Yes      │                11                 17          10 │      38 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  Total    │                31                 52          48 │     131 
#> 
#> Chi-2(2) = 2.5, p = .282
#> Cramer's V = 0.14
#> 
#> Crosstable: smoking x education (N) | sex x age_group = Male.65-75
#> 
#>  Values   │   Lower secondary    Upper secondary    Tertiary │   Total 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  No       │                14                 36          38 │      88 
#>  Yes      │                 7                  9          12 │      28 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  Total    │                21                 45          50 │     116 
#> 
#> Chi-2(2) = 1.4, p = .499
#> Cramer's V = 0.11
#> Missing values removed: smoking (1).

Ordinal variables

When both variables are ordered factors, cross_tab() automatically switches from Cramer’s V to Kendall’s Tau-b:

cross_tab(sochealth, self_rated_health, education)
#> Crosstable: self_rated_health x education (N)
#> 
#>  Values      │   Lower secondary    Upper secondary    Tertiary │   Total 
#> ─────────────┼──────────────────────────────────────────────────┼─────────
#>  Poor        │                28                 28           5 │      61 
#>  Fair        │                86                118          62 │     266 
#>  Good        │               102                263         193 │     558 
#>  Very good   │                44                118         133 │     295 
#> ─────────────┼──────────────────────────────────────────────────┼─────────
#>  Total       │               260                527         393 │    1180 
#> 
#> Chi-2(6) = 73.2, p <.001
#> Kendall's Tau-b = 0.20
#> Missing values removed: self_rated_health (20).

You can override the automatic selection with assoc_measure:

cross_tab(sochealth, self_rated_health, education, assoc_measure = "gamma")
#> Crosstable: self_rated_health x education (N)
#> 
#>  Values      │   Lower secondary    Upper secondary    Tertiary │   Total 
#> ─────────────┼──────────────────────────────────────────────────┼─────────
#>  Poor        │                28                 28           5 │      61 
#>  Fair        │                86                118          62 │     266 
#>  Good        │               102                263         193 │     558 
#>  Very good   │                44                118         133 │     295 
#> ─────────────┼──────────────────────────────────────────────────┼─────────
#>  Total       │               260                527         393 │    1180 
#> 
#> Chi-2(6) = 73.2, p <.001
#> Goodman-Kruskal Gamma = 0.31
#> Missing values removed: self_rated_health (20).

Confidence intervals for effect sizes

Add a 95% confidence interval for the association measure with assoc_ci = TRUE:

cross_tab(sochealth, smoking, education, assoc_ci = TRUE)
#> Crosstable: smoking x education (N)
#> 
#>  Values   │   Lower secondary    Upper secondary    Tertiary │   Total 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  No       │               179                415         332 │     926 
#>  Yes      │                78                112          59 │     249 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  Total    │               257                527         391 │    1175 
#> 
#> Chi-2(2) = 21.6, p <.001
#> Cramer's V = 0.14, 95% CI [0.08, 0.19]
#> Missing values removed: smoking (25).

Weighted cross-tabulations

Weights are supplied via weights, just like in freq(), and both functions share the same default: rescale = FALSE (raw weighted counts).

cross_tab(sochealth, smoking, education, weights = weight)
#> Crosstable: smoking x education (N)
#> 
#>  Values   │   Lower secondary    Upper secondary    Tertiary │   Total 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  No       │               176                417         324 │     917 
#>  Yes      │                79                114          60 │     253 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  Total    │               254                531         384 │    1170 
#> 
#> Chi-2(2) = 21.3, p <.001
#> Cramer's V = 0.13
#> Weight: weight
#> Missing values removed: smoking (25).

Pass rescale = TRUE to make the weighted total match the unweighted sample size:

cross_tab(sochealth, smoking, education, weights = weight, rescale = TRUE)
#> Crosstable: smoking x education (N)
#> 
#>  Values   │   Lower secondary    Upper secondary    Tertiary │   Total 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  No       │               176                419         325 │     921 
#>  Yes      │                79                115          60 │     254 
#> ──────────┼──────────────────────────────────────────────────┼─────────
#>  Total    │               256                534         386 │    1175 
#> 
#> Chi-2(2) = 21.4, p <.001
#> Cramer's V = 0.13
#> Weight: weight (rescaled)
#> Missing values removed: smoking (25).

Monte Carlo simulation

The chi-squared test relies on an asymptotic approximation that degrades when expected cell counts are small. cross_tab() checks Cochran’s rule and warns when a table is too sparse – as in this student subsample:

students <- subset(sochealth, employment_status == "Student")
cross_tab(students, self_rated_health, education)
#> Crosstable: self_rated_health x education (N)
#> 
#>  Values      │   Lower secondary    Upper secondary    Tertiary │   Total 
#> ─────────────┼──────────────────────────────────────────────────┼─────────
#>  Poor        │                 2                  3           0 │       5 
#>  Fair        │                11                 14           4 │      29 
#>  Good        │                 5                 43          28 │      76 
#>  Very good   │                 4                 12          14 │      30 
#> ─────────────┼──────────────────────────────────────────────────┼─────────
#>  Total       │                22                 72          46 │     140 
#> 
#> Chi-2(6) = 23.4, p <.001
#> Kendall's Tau-b = 0.28
#> Warning: 5 expected cells < 5 (41.7%). 1 expected cell < 1. Minimum expected = 0.79. Consider `simulate_p = TRUE` or set globally via `options(spicy.simulate_p = TRUE)`.
#> Missing values removed: self_rated_health (3).

The warning itself names the remedy: simulate_p = TRUE replaces the asymptotic p-value with one estimated by Monte Carlo simulation (simulate_B random tables). A simulated test has no degrees of freedom, which is why the statistic prints as Chi-2(NA):

cross_tab(students, self_rated_health, education,
          simulate_p = TRUE, simulate_B = 5000)
#> Crosstable: self_rated_health x education (N)
#> 
#>  Values      │   Lower secondary    Upper secondary    Tertiary │   Total 
#> ─────────────┼──────────────────────────────────────────────────┼─────────
#>  Poor        │                 2                  3           0 │       5 
#>  Fair        │                11                 14           4 │      29 
#>  Good        │                 5                 43          28 │      76 
#>  Very good   │                 4                 12          14 │      30 
#> ─────────────┼──────────────────────────────────────────────────┼─────────
#>  Total       │                22                 72          46 │     140 
#> 
#> Chi-2(NA) = 23.4, p <.001 (simulated)
#> Kendall's Tau-b = 0.28
#> Missing values removed: self_rated_health (3).

Data frame output

Set output = "data.frame" to get a plain data frame for further processing. The same argument works in freq(), and its two values (“default”, “data.frame”) are shared with the output argument of the table_*() family – but the rendered engines that family also accepts (“tinytable”, “gt”, “flextable”, …) are not available here:

cross_tab(sochealth, smoking, education,
          percent = "column", output = "data.frame")
#>   Values Lower secondary Upper secondary Tertiary
#> 1     No            69.6            78.7     84.9
#> 2    Yes            30.4            21.3     15.1

Setting global defaults

You can set tabulation defaults with options() so you don’t have to repeat arguments. spicy.rescale is read by cross_tab(), freq(), and table_categorical(); spicy.percent and spicy.simulate_p are read by cross_tab():

options(
  spicy.percent   = "column",
  spicy.simulate_p = TRUE,
  spicy.rescale   = TRUE
)

Learn more