
Tabulate a check-all-that-apply (multi-select) question as percentages
Source:R/percentage.R
calc_percentage_multi.RdMulti-select questions arrive as a block of columns sharing a prefix, each holding the chosen option (or blank). This computes, per option, the share of respondents who selected it – so the percentages can (and usually do) sum to more than 100. The denominator is the number of distinct respondents who selected at least one option.
Usage
calc_percentage_multi(
data = NULL,
prefix,
id = NULL,
by = NULL,
sort = c("none", "desc", "asc"),
digits = 0,
drop = NULL,
clean_names = TRUE,
split = "auto"
)Arguments
- data
A data frame.
- prefix
Common column-name prefix identifying the option block, e.g.
"motivations_".- id
Optional respondent identifier column (unquoted) used as the distinct-respondent denominator. If omitted, each row is treated as one respondent.
- by
Optional grouping column(s); percentages are computed within group.
- sort, digits
As in
calc_percentage(). Sorting acts on theoptionlabels.- drop
Optional character vector of option labels to remove before counting (matched against the cleaned labels, case-insensitive). Defaults to the
drop_answersoption. Seedrop_items().- clean_names
If
TRUE(default), tidy the option labels by strippingprefixand un-mangling exporter artefacts ("A...B"->"A / B").- split
How to handle a question that arrives packed into a single cell per respondent (
"Speed; Drivers")."auto"(default) detects";","|"or","and splits on it; pass a string to force a delimiter, orFALSEnever to split. Only ever applies whenprefixselects exactly one column.
Value
A tibble with option, n (respondents choosing
it) and pct.
Details
The crucial difference from calc_percentage() is the denominator: it is the
number of distinct respondents who picked any option in the block, not the
number of ticks. So if 700 of 1,000 respondents selected at least one
motivation, each option's percentage is "out of 700", and the percentages can
(and usually do) sum to more than 100. Supply id to count distinct
respondents exactly; without it, each row counts as one respondent. With
clean_names = TRUE the option labels are stripped of prefix and exporter
artefacts like "A...B" are turned back into "A / B".
Two export shapes are handled. The usual one is a block of columns, one per
option, named with a shared prefix; that is what prefix selects. The other
is a single column holding every answer a respondent ticked, joined by a
delimiter, which is what Google Forms and most spreadsheet exports produce. If
prefix matches exactly one column and a delimiter is found in it, that
column is unpacked automatically and the answer text itself becomes the option
label (clean_names is not applied, since the answers are real wording rather
than mangled column names). Behaviour on a column block is unchanged. Use
split_multi() when you want those unpacked columns kept for other work.
Examples
calc_percentage_multi(podracing_survey, "motivations_",
id = respondent_id, sort = "desc")
#> # A tibble: 5 × 3
#> option n pct
#> <fct> <int> <dbl>
#> 1 speed 772 79
#> 2 drivers 533 54
#> 3 social 437 45
#> 4 tradition 349 36
#> 5 betting 295 30
# a spreadsheet export that packs every answer into one cell
packed <- data.frame(
respondent = 1:4,
motivations = c("Speed; Drivers", "Speed", "", "Betting; Speed")
)
calc_percentage_multi(packed, "motivations", id = respondent, sort = "desc")
#> # A tibble: 3 × 3
#> option n pct
#> <fct> <int> <dbl>
#> 1 Speed 3 100
#> 2 Betting 1 33
#> 3 Drivers 1 33