Tabulates a "check all that apply" question: one row per item, with the
number of respondents who chose it and their percentage, a row for the
respondents who chose none of the items when there are any (see
none_row), then a row with the number of respondents the percentages
are computed on. The items are the indicator columns of the question,
selected with tidyselect syntax.
With by, the counts and percentages are given per group and in a
Total margin, each item gets a test across the groups (the
chi-squared, or Fisher's exact test when an expected count is below 5),
and the question gets a global test of all its items together, valid
although one respondent can choose several items.
Multiple output formats are available via output: a printed ASCII
table ("default"), a wide or long numeric data.frame
("data.frame", "long"), or publication-ready tables
("tinytable", "gt", "flextable", "excel", "clipboard",
"word").
Usage
table_multiresponse(
data,
select,
by = NULL,
counted = NULL,
percent = c("cases", "responses", "both"),
base = c("valid", "answered", "all"),
none_row = TRUE,
sort = c("", "+", "-", "name+", "name-"),
test = c("auto", "chisq", "fisher", "midp", "n1"),
p_value = NULL,
global_test = c("rs2", "bootstrap"),
boot_n = 1999L,
p_adjust = "holm",
statistic = FALSE,
labels = getOption("spicy.var_labels", FALSE),
note_labels = NULL,
percent_digits = 1,
p_digits = 3,
decimal_mark = ".",
align = c("decimal", "center", "right"),
title = NULL,
note = NULL,
note_add = NULL,
output = c("default", "data.frame", "long", "tinytable", "gt", "flextable", "excel",
"clipboard", "word"),
excel_path = NULL,
excel_sheet = NULL,
clipboard_delim = "\t",
word_path = NULL,
style = NULL
)Arguments
- data
A data frame, one row per respondent.
- select
The indicator columns of the question, one per item, in tidyselect syntax or as a character vector of column names. Their order is the order of the rows, unless
sortsorts them. Thebycolumn is not part of the selection: a selection helper skips it, and naming it, or giving its position, is an error. A name that is not a column ofdatais an error (classspicy_missing_column), and so is an empty selection.- by
Optional grouping column, unquoted or as a string. Factor levels keep their declared order, a declared level with no respondent included; any other column is sorted, as in
table_categorical(): text in the C locale,FALSEbeforeTRUE, numbers ascending, whatever the order of the rows, and a labelled column is named and ordered by its value labels as there. The missing answers to the question are counted (seebaseandnone_row), as a table that counts does (seedrop_naintable_categorical()), but a missingbyhas no group to be counted in: rows with a missingbyare removed from the whole table, and the note listsbywith their count ("Missing values removed: sex (2)."), so this table has nodrop_na; abythat no observation holds is an error (classspicy_invalid_data). A level displayed with the label of theTotalmargin is an error, as intable_categorical().- counted
The value that marks a choice.
NULL(the default) reads logical columns (TRUEis chosen) and numeric columns coded 0 and 1 (1is chosen) as they are; any other column needscounted, and the error names it. When supplied,countedapplies to every selected column: a factor or character column is chosen where it equalscounted(counted = "Yes"), a labelled column where its code or its value label does (counted = 1orcounted = "Yes"). Any other non-missing value is "not chosen", and a missing value stays missing. Acountedthat matches no value of any selected column is an error.- percent
The percentage shown beside each count:
"cases"(the default), the percentage of respondents, which can sum to more than 100;"responses", the percentage of all the choices made in the group, which sums to 100; or"both", two columns.- base
The respondents the percentages of cases are computed on; the note names the base the table uses.
"valid"(the default): the respondents with at least one non-missing indicator, so that a respondent who chose nothing counts and one who skipped the question does not, asexpsscounts its valid cases."answered": the respondents who chose at least one item, the default of SPSSMULT RESPONSE(MISSING = TABLE) and of Stata'smrtab, whoseincludeoption gives"valid"(Jann, 2005, pp. 98 and 107-108), where choosing nothing cannot be told from skipping."all": every row of the group, asquestionr::multi.table()counts.
In a "check all that apply" question, an item left unchecked cannot tell "none applies" from "skipped":
"valid"reads a respondent with no item chosen as "none applies","answered"(the convention of SPSS and Stata) as nonresponse."answered"suits a questionnaire with neither a "None of these" option nor a required answer. An export that leaves every unchecked box missing gives both bases the same respondents, and only"answered"describes them in the note. A filter code that is not declared missing (for example -1 "not applicable" kept as an ordinary value) counts as "not chosen" and keeps the filtered respondents in the base: recode it toNAfirst (SPSS user-missing values declared as such are already read as missing).- none_row
Logical. If
TRUE(the default), the respondents of the base who chose no item get a row of their own, after the items and before theRespondentsrow: "(No item chosen)" underbase = "valid"and"all", and, under"all", "(No data for the question)" for the respondents with every indicator missing. Each row appears only when its count is above 0.base = "answered"leaves both groups out of the base and shows neither row. A row gives the count and the percentage of cases of each group and of the margin, on the base of the column, as the items do. Its percentage of responses and its test cells show a dash: these respondents gave no answer, and the rows take no part in the tests or insort. The note then no longer counts the respondents a row shows.FALSEgives these counts in the note only.- sort
Sorting method for items, as in
freq():""- no sorting (default)"+"- increasing frequency"-"- decreasing frequency"name+"- alphabetical A-Z"name-"- alphabetical Z-A
With no sorting, the rows keep the order in which
selectdelivers the columns: their order indatawith a helper such asstarts_with(), or the order written inc(). The function cannot know the questionnaire, so its order comes from the order of the columns or the order written inselect. The frequency is the total count of each item, and items with the same count keep the order ofselect. The alphabetical sort reads the labels displayed in the rows (the column names, or the labels set bylabels) in the C locale, the same on every platform: capitals before lower case, accented letters afterz.- test
The test of each item's p-value, as in
table_categorical():"auto"(the default) takes Pearson's chi-squared test when every expected count of the item's table is at least 5 and Fisher's exact test otherwise;"chisq"and"fisher"take one test for every item;"midp"takes the Fisher mid-p test for an item of a two-group table;"n1"takes the N-1 chi-squared test for an item of a two-group table whose expected counts are all at least 1, and Fisher's exact test for one with a smaller count. With more groups,"midp"and"n1"follow"auto". The note names the test of each item. See Tests.- p_value
Logical or
NULL. Withby,NULL(the default) andTRUEshow the itempcolumn and the global test in the note.FALSEremoves both from every output, thepcolumn of the data frame and thep.valuecolumn of the long output included.p_valueandstatisticare independent, as intable_continuous(). Ignored withoutby, with a warning whenTRUE.- global_test
The global test:
"rs2"(the default), the sum of the item chi-squared statistics with the second-order Rao-Scott correction; or"bootstrap", the same sum referred to its bootstrap distribution. See Tests.- boot_n
Number of bootstrap resamples for
global_test = "bootstrap": a positive whole number, as intable_regression()andtable_continuous_lm(). Defaults to1999, the defaultBofMI.test()in theMRCVpackage for the same bootstrap test (reference manual ofMRCV0.4-0). Typed withglobal_test = "rs2", or in a table without a global test, it is ignored with a warning (classspicy_ignored_arg).- p_adjust
Multiple-comparison adjustment of the item
pcolumn, applied to the family of the items tested:"holm"(the default),"none", or another method ofstats::p.adjust()("hochberg","hommel","bonferroni","BH"/"fdr","BY"), as intable_categorical(). See Multiple-comparison adjustment. Typing it when the table has no test to adjust (noby, orp_value = FALSE) is an error.- statistic
Logical. If
TRUE, adds aTestcolumn with each item's chi-squared statistic and its degrees of freedom, with or without the p-values ofp_value; an item whose p-value comes from Fisher's exact test or its mid-p version has no statistic and shows a dash, and an item tested by the N-1 chi-squared shows that statistic. Defaults toFALSE.- labels
How each variable is named in the table: in the rows, in the title, and in the notes. Four forms:
labels = FALSEshows the column name.labels = TRUEshows the column'slabelattribute (as set byhaven,labelled, orlabel_from_names()) when it is present, notNA, and not empty, and the column name otherwise.labels = c(bmi = "Body mass index"), a named character vector, gives the columns it names these labels. Every other column followsoptions(spicy.var_labels): its name when the option is unset orFALSE, itslabelattribute when it isTRUE.labels = var_labels(bmi = "BMI (kg/m2)")gives the columns it names these labels, and every other column itslabelattribute, whatever the option says.var_labels()alone islabels = TRUE.
Names that match no column are ignored, so one vector can serve every table of a project. The default reads
options(spicy.var_labels), and aTRUEorFALSEtyped in the call wins over it. Any other value,NULLincluded, is an error. A variable label documents the data file; a published table carries the wording you set here.note_labelsgives a variable a shorter label in the title and the notes.- note_labels
The label a variable takes where the table names it in a sentence, in the title and in the notes, in place of the one
labelsgives it: a named character vector,note_labels = c(sex = "sex at birth"), or avar_labels()object, which reads as one.labelscan then name a row with a whole question while the note says "Missing values removed: sex at birth (2).". The rows, the column headers and the spanners keep the labels oflabels, and so do the title and the notes for a variablenote_labelsdoes not name. Names that match no column are ignored, as inlabels, andNULL(the default) renames nothing. A note label that another variable of the table shows is an error (classspicy_label_collision): choose another one, or relabel the other variable.- percent_digits
Number of digits for percentages in report outputs. Defaults to
1. A whole number: a fraction is an error, as for every*_digitsargument.- p_digits
Integer >= 1. Number of decimal places used to render p-values in the
pcolumn (default:3, the APA Publication Manual standard). Both the displayed precision and the small-p threshold derive from this argument:p_digits = 3prints.045and<.001;p_digits = 4prints.0451and<.0001. Leading zeros are always stripped, following APA convention.- decimal_mark
The decimal mark, a single character:
"."(the default) or","in most styles; the Lancet style ofspicy_style()uses the middle dot.- align
Horizontal alignment of the numeric columns in the console and in the rendered outputs:
"decimal"(the default),"center", or"right", as intable_categorical().- title
The table title.
NULL(the default) gives "Multiple responses", followed by "by" and thebyvariable under thelabelscontract (or its label innote_labels); a single string replaces it, andFALSEremoves it, as intable_regression().- note
The table note.
NULL(the default) builds it, opening with "Note.": what the percentages sum to, the base with the respondents it holds or leaves out, the rows removed for a missingbyand the items with no data in a group, then the tests, and the sentences ofnote_add. A single string replaces it, printed as typed after the lead-in ("Note.", unless the string opens with one),note_addafter it, andFALSEremoves it, as in every table function.- note_add
Sentences to add to the note: a character vector of one or more strings, each printed as typed (no period is added) and joined to the note by a space. They close its paragraph, after the definitions of the abbreviations and before the legend of the stars, in every output and in
attr(x, "note"), and the sentences the table writes stay. With a string innote, they follow it, so a wrapper can add a house sentence to every table while one table replaces its note. AnNAor an empty string is an error, and so isnote_addwithnote = FALSE, which leaves no note to add to.- output
Output format. One of:
"default"(an ASCII table object, printed when the call is bare)"data.frame"(the displayed table, numeric)"long"(a long numericdata.frame)"tinytable"(requirestinytable)"gt"(requiresgt)"flextable"(requiresflextable)"excel"(requiresopenxlsx2)"clipboard"(requiresclipr)"word"(requiresflextableandofficer)
- excel_path
Path for
output = "excel", ending in".xlsx", in a directory that exists. Defaults toNULL.- excel_sheet
Sheet name for Excel export.
NULL(the default) uses"Multiple responses".- clipboard_delim
Delimiter for clipboard text export. Defaults to
"\t". A cell holding the delimiter itself, a double quote or a line break is quoted RFC 4180-style, so the grid survives whatever delimiter you choose.- word_path
File path for
output = "word". Defaults toNULL.- style
A journal style: a theme name (
"jama","nejm","lancet","annals","apa","aer"), aspicy_style()object, orNULL(the default). A style only changes DEFAULTS – any argument you pass explicitly wins over it. Setoptions(spicy.style = )for document-wide scope. A theme covers numeric formatting, the word that opens the note and the abbreviations the note defines, not full editorial conformity;?spicy_stylelists the exact rules each one encodes and the official document they come from. An unknown name is an error.
Value
Depends on output:
"default": aspicy_multiresponse_table(adata.framesubclass), with the rendering metadata as attributes, returned visibly, so a bare call prints the ASCII table."data.frame": the displayed table with its numbers, what as.data.frame() of the default object returns: one row per item, the rows ofnone_row, and a last row with the base. Columns:variable(the item's column,"none","no_data", or"nobs"on the base row),label(the label the row displays),.row_role(what the row is:"summary"for an item,"none"for "(No item chosen)","missing"for "(No data for the question)","fit_stat"for the base, the roles ofas_structured()), then the printed columns: the count and the percentage of each group ofbyand of theTotalmargin (<group> nand<group> %, or<group> % of casesand<group> % of responsesunderpercent = "both";nand%withoutby),Test(the chi-squared of the item, withdfbeside it) understatistic = TRUE, andpwithp_value."long": one row per item and group, then one per row ofnone_rowand group, with columnsvariable(the item's column,"none"or"no_data"on the rows ofnone_row),label(the label the row displays),.row_roleas above, withbygroup,.group_role(the role ofgroup:"group", or"total"for the margin) andtotal(TRUEon the rows of the margin),n,base(the respondents of the group; in the margin, those of the groups with data for the item), the percentage named by its base:pct_cases(of the respondents) orpct_responses(of the choices made), aspercentasks, both underpercent = "both", and, when the item tests ran (forp_valueor forstatistic),test_type(the test of the item, as intable_categorical():"chi_squared","n1_chi_squared","fisher_exact","fisher_midp","fisher_exact_mc"),statisticanddf(NAfor an item tested by an exact test),p.valuewithp_value, andp_unadjustedunder an adjustment. The rows ofnone_rowareNAin the test columns."tinytable","gt","flextable": the rendered table object."excel"/"word": writes to disk and returns the file path invisibly."clipboard": copies the table and returns the displaydata.frameinvisibly.
The default object and the data frames carry the note as printed in
attr(x, "note") (its lead-in included, NULL under note = FALSE)
and, when the table has a global test,
attr(x, "global_test"): a one-row data frame with
test, statistic, df, p.value, boot_n, n_items (the items
tested), n_groups, rs_mean and rs_cv (the design-effect summary of
global_test = "rs2"), and boot_redraws (the resamples drawn again
under global_test = "bootstrap"); see Tests. as_structured() reads
the default object, with the same .row_role and a .variable of
"none" and "no_data" on the rows of none_row;
tidy() reads the items only.
Tests
With by, the table tests multiple marginal independence: that the
probability of choosing each item is the same in every group. Each
item gets the Pearson chi-squared statistic of its \(r \times 2\)
table (group by chose the item) with \(r - 1\) degrees of freedom:
the arithmetic of chisq.test(correct = FALSE), with no continuity
correction and no constant added to an empty cell (Agresti and Liu,
1999).
The item p-value comes from the test test chooses, as in
table_categorical(). Under "auto", the default, it is that
chi-squared test when every expected count of the item's table is at
least 5, and Fisher's exact test (stats::fisher.test()) otherwise;
when the exact enumeration fails, the p-value is its Monte Carlo
estimate over 2000 tables, which draws from the session's RNG. An item
tested by Fisher's exact test has no statistic: its Test cell shows
a dash, and statistic and df are NA in the long output. Without
p-values (p_value = FALSE), statistic = TRUE shows the chi-squared
statistic of every item. The global test sums the Pearson statistics
of the items whatever test chooses for their p-values, since its
correction and its bootstrap are defined for that sum.
With two groups, an item's table is 2x2. test = "midp" then gives it
the Fisher mid-p test of Fagerland, Lydersen and Laake (2017, section
4.4.6), and test = "n1" the N-1 chi-squared test of Campbell (2007)
when its expected counts are all at least 1 and Fisher's exact test
otherwise, both defined under Tests in table_categorical(). With
more groups, the items follow "auto". An item tested by the mid-p
test has no statistic (a dash); one tested by the N-1 chi-squared shows
that statistic, on 1 degree of freedom.
The global test sums the item statistics,
\(X^2_S = \sum_j X^2_j\), a value that does not depend on which
answer of an item is coded as chosen (Agresti and Liu, 1999). One
respondent can choose several items, so the items are correlated and
\(X^2_S\) is not chi-squared under the null (Loughin and Scherer,
1998): its asymptotic distribution is a weighted sum of chi-squared
variables, the weights being the eigenvalues of a design-effect matrix
(Bilder, Loughin and Nettleton, 2000, Appendix A). global_test = "rs2"
matches its first two moments, the second-order Rao-Scott correction
of Thomas and Decady (2004, pp. 48 and 58-59):
$$X^2_{RS2} = \frac{c(r-1)\,X^2_S}{\sum_k \lambda_k^2}, \qquad \nu = \frac{c^2(r-1)^2}{\sum_k \lambda_k^2}$$
referred to a chi-squared distribution with \(\nu\) degrees of
freedom, usually fractional. Here \(c\) is the number of items tested
and the \(\lambda_k\) are the eigenvalues of the design-effect matrix,
in the second-order form of Bilder and Loughin (2004). The within-group
covariance of the indicators is centered at the group means, the
unrestricted estimate of Bilder and Loughin (2004) that the MRCV
package also uses, whereas Thomas and Decady (2004) center it at the
pooled proportions with divisor \(n(n - 1)\), which gives p = .068
instead of .063 on the Kansas farmer data of Loughin and Scherer
(1998). The result is deterministic. attr(x, "global_test") reports
rs_mean, the mean of the \(\lambda_k\), which is 1 in the
population under the null and which the correction takes as 1 (Thomas
and Decady, 2004, p. 48), and rs_cv, the \(\hat a\) of Thomas and
Decady (2004, p. 59), defined by
\(1 + \hat a^2 = \sum_k \lambda_k^2 / (c(r-1))\): the coefficient of
variation of the \(\lambda_k\) when their mean is 1, and NA when
that ratio falls below 1.
global_test = "bootstrap" refers \(X^2_S\) to its distribution over
boot_n resamples of whole response vectors, drawn with replacement
from the pooled respondents with the group sizes held fixed (Loughin
and Scherer, 1998). The p-value is the share of resamples whose
statistic is at least the observed one. A resample in which an item is
chosen by every respondent or by none gives that item no statistic: it
is discarded and drawn again, the practice of Bilder, Loughin and
Nettleton (2000, p. 1298) for resamples whose marginal table has an
empty row or column, and attr(x, "global_test")$boot_redraws counts
the resamples drawn again. When 100 times boot_n draws do not yield
boot_n usable resamples, the function stops with an error. The
bootstrap held its level in most published settings, with exceptions
reported by Bilder, Loughin and Nettleton (2000, p. 1305), and no study
of multiple marginal independence compares it with the second-order
test. It is random: call set.seed() first to reproduce it.
An item chosen by every respondent, or by none, has no test: its p
cell shows a dash, it leaves the global test, and the note names it.
Its row stays. An item with no data in a group (see Base and missing
values) is tested on the groups with data for it, has no test with
fewer than two (its p cell is then blank), and leaves the global
test, which compares every group on the same items. With fewer than
two groups holding respondents there is nothing to compare, and the
table shows no test. The note names the global test with its
statistic, degrees of freedom, and p-value.
Multiple-comparison adjustment
The items of one question form a natural family of tests, read
together, so the item p column is adjusted by Holm's method by
default. In table_categorical(), each test belongs to a different
variable and the default is "none". Holm's method controls the
family-wise error rate whatever the dependence between the items, and
its smallest adjusted p-value equals the Bonferroni global p-value of
Agresti and Liu (1999). The raw p-values stay in the data frames as
p_unadjusted, and in col_meta$p$p_unadjusted of as_structured().
The note names the method and the number of items adjusted together,
in the sentence of table_categorical(). The global test is never
adjusted.
Base and missing values
Within the base, a missing indicator counts as not chosen, for the
percentages and for the tests alike, so the table and its tests
describe the same respondents: those with at least one non-missing
indicator under base = "valid", those who chose at least one item
under base = "answered", every row under base = "all". The counts
are the same under the three bases; the percentages of cases and the
tests are not. The Respondents row gives the base of each group, and
the note says which base the table uses, with two counts, all groups
together: the respondents with no data for the question (every
indicator missing) and those with no item chosen (data, but no item
chosen). The base holds the second and leaves out the first under
"valid", leaves out both under "answered", and holds both under
"all"; a count of zero is not mentioned. Under none_row = TRUE, the
default, the respondents of these two kinds that the base holds are
rows of the table, "(No item chosen)" and "(No data for the question)",
with their count and percentage in each group, and the note counts only
those the base leaves out. An item displayed with the label of a row the
table adds is an error (class spicy_label_collision): choose another
label in labels, or give the row another label, for example
options(spicy.labels = list(row_multiresponse_base = "Base")).
Declared missing values of a labelled column (na_values, na_range)
are missing, as under the user_na = TRUE default of
table_categorical().
An item missing for every respondent of a group (typically an item not
asked there) has no data in that group: its cells there show a dash,
its Total counts the other groups only, and the note says so, in one
sentence for the items with no data in the same groups. Without by,
an item with no observed value at all
shows a dash. A group with no data for any item was not asked the
question: all its cells, Respondents included, show a dash, and its
respondents leave the base, the Total, the tests and the count of
the respondents with no data for the question.
A percentage carries no more digits than its denominator, so a base of
fewer than 100 respondents takes whole percentages (American Medical
Association, 2020, section 4.1.8): percent_digits = 0 prints them.
References
Agresti, A., & Liu, I.-M. (1999). Modeling a categorical variable allowing arbitrarily many category choices. Biometrics, 55(3), 936-943. doi:10.1111/j.0006-341x.1999.00936.x
American Medical Association. (2020). AMA Manual of Style: A Guide for Authors and Editors (11th ed.). Oxford University Press. doi:10.1093/jama/9780190246556.001.0001
Bilder, C. R., & Loughin, T. M. (2004). Testing for marginal independence between two categorical variables with multiple responses. Biometrics, 60(1), 241-248. doi:10.1111/j.0006-341x.2004.00147.x
Bilder, C. R., Loughin, T. M., & Nettleton, D. (2000). Multiple marginal independence testing for pick any/c variables. Communications in Statistics - Simulation and Computation, 29(4), 1285-1316. doi:10.1080/03610910008813665
Campbell, I. (2007). Chi-squared and Fisher-Irwin tests of two-by-two tables with small sample recommendations. Statistics in Medicine, 26(19), 3661-3675. doi:10.1002/sim.2832
Fagerland, M. W., Lydersen, S., & Laake, P. (2017). Statistical Analysis of Contingency Tables. Chapman and Hall/CRC. doi:10.1201/9781315374116
Jann, B. (2005). Tabulation of multiple responses. The Stata Journal, 5(1), 92-122. doi:10.1177/1536867x0500500113
Loughin, T. M., & Scherer, P. N. (1998). Testing for association in contingency tables with multiple column responses. Biometrics, 54(2), 630-637. doi:10.2307/3109769
Thomas, D. R., & Decady, Y. J. (2004). Testing for association using multiple response survey data: Approximate procedures based on the Rao-Scott approach. International Journal of Testing, 4(1), 43-59. doi:10.1207/s15327574ijt0401_3
See also
table_categorical() for single-response variables; the article
Multiple-response questions.
Examples
# The five info_* items of sochealth answer one "check all that apply"
# question: the sources of health information used in the past 12 months.
table_multiresponse(sochealth, select = starts_with("info_"))
#> Multiple responses
#>
#> Variable │ n %
#> ────────────────────┼────────────────
#> info_doctor │ 721 61.9
#> info_pharmacist │ 256 22.0
#> info_internet │ 523 44.9
#> info_family │ 360 30.9
#> info_media │ 141 12.1
#> (No item chosen) │ 67 5.8
#> ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
#> Respondents │ 1164
#>
#> Note. Multiple answers possible: percentages can sum to more than 100%. Base: respondents with data for the question (excluded: 36 with no data for the question).
# The labels of the items, sorted by decreasing count.
table_multiresponse(
sochealth,
select = starts_with("info_"),
labels = TRUE,
sort = "-"
)
#> Multiple responses
#>
#> Variable │ n %
#> ───────────────────────────────────────┼────────────────
#> Doctor or other health professional │ 721 61.9
#> Internet, websites or apps │ 523 44.9
#> Family or friends │ 360 30.9
#> Pharmacist │ 256 22.0
#> Television, radio or newspapers │ 141 12.1
#> (No item chosen) │ 67 5.8
#> ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
#> Respondents │ 1164
#>
#> Note. Multiple answers possible: percentages can sum to more than 100%. Base: respondents with data for the question (excluded: 36 with no data for the question).
# By age group: a test per item and a global test of the question.
table_multiresponse(
sochealth,
select = starts_with("info_"),
by = age_group
)
#> Multiple responses by age_group
#>
#> Variable │ 25-34 n 25-34 % 35-49 n 35-49 % 50-64 n 50-64 %
#> ──────────────────┼──────────────────────────────────────────────────────
#> info_doctor │ 113 48.5 208 55.6 215 67.8
#> info_pharmacist │ 53 22.7 74 19.8 69 21.8
#> info_internet │ 156 67.0 200 53.5 109 34.4
#> info_family │ 72 30.9 119 31.8 99 31.2
#> info_media │ 9 3.9 36 9.6 41 12.9
#> (No item chosen) │ 12 5.2 22 5.9 22 6.9
#> ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
#> Respondents │ 233 374 317
#>
#> Variable │ 65-75 n 65-75 % Total n Total % p
#> ──────────────────┼───────────────────────────────────────────
#> info_doctor │ 185 77.1 721 61.9 <.001
#> info_pharmacist │ 60 25.0 256 22.0 .982
#> info_internet │ 58 24.2 523 44.9 <.001
#> info_family │ 70 29.2 360 30.9 .982
#> info_media │ 55 22.9 141 12.1 <.001
#> (No item chosen) │ 11 4.6 67 5.8 –
#> ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
#> Respondents │ 240 1164
#>
#> Note. Multiple answers possible: percentages can sum to more than 100%. Base: respondents with data for the question (excluded: 36 with no data for the question). Item p-values: Pearson chi-squared test of each item by group. P-values adjusted for 5 tests (Holm method). Overall group comparison: Rao-Scott second-order corrected chi-squared test of multiple marginal independence, χ²(14.40) = 203.03, p < .001.
# A descriptive table by sex, on the respondents who chose at least one
# source: percentages of cases and of responses, no tests.
table_multiresponse(
sochealth,
select = starts_with("info_"),
by = sex,
percent = "both",
base = "answered",
p_value = FALSE
)
#> Multiple responses by sex
#>
#> Variable │ Female n Female % of cases Female % of responses Male n
#> ─────────────────┼────────────────────────────────────────────────────────────
#> info_doctor │ 377 66.4 34.9 344
#> info_pharmacist │ 137 24.1 12.7 119
#> info_internet │ 268 47.2 24.8 255
#> info_family │ 219 38.6 20.3 141
#> info_media │ 78 13.7 7.2 63
#> ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
#> Respondents │ 568 529
#>
#> Variable │ Male % of cases Male % of responses Total n
#> ─────────────────┼───────────────────────────────────────────────
#> info_doctor │ 65.0 37.3 721
#> info_pharmacist │ 22.5 12.9 256
#> info_internet │ 48.2 27.7 523
#> info_family │ 26.7 15.3 360
#> info_media │ 11.9 6.8 141
#> ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
#> Respondents │ 1097
#>
#> Variable │ Total % of cases Total % of responses
#> ─────────────────┼────────────────────────────────────────
#> info_doctor │ 65.7 36.0
#> info_pharmacist │ 23.3 12.8
#> info_internet │ 47.7 26.1
#> info_family │ 32.8 18.0
#> info_media │ 12.9 7.0
#> ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
#> Respondents │
#>
#> Note. Multiple answers possible: percentages of cases can sum to more than 100%, and percentages of responses sum to 100%. Base: respondents with at least one item chosen (excluded: 36 with no data for the question and 67 with no item chosen).
# Items coded "Yes" and "No" need `counted`, the value that marks a choice.
yes_no <- as.data.frame(lapply(
sochealth[startsWith(names(sochealth), "info_")],
function(x) factor(x, levels = c(FALSE, TRUE), labels = c("No", "Yes"))
))
table_multiresponse(yes_no, select = everything(), counted = "Yes")
#> Multiple responses
#>
#> Variable │ n %
#> ────────────────────┼────────────────
#> info_doctor │ 721 61.9
#> info_pharmacist │ 256 22.0
#> info_internet │ 523 44.9
#> info_family │ 360 30.9
#> info_media │ 141 12.1
#> (No item chosen) │ 67 5.8
#> ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
#> Respondents │ 1164
#>
#> Note. Multiple answers possible: percentages can sum to more than 100%. Base: respondents with data for the question (excluded: 36 with no data for the question).
# Bootstrap global test: set a seed to reproduce its p-value.
set.seed(1)
table_multiresponse(
sochealth,
select = starts_with("info_"),
by = sex,
global_test = "bootstrap",
boot_n = 999
)
#> Multiple responses by sex
#>
#> Variable │ Female n Female % Male n Male % Total n Total % p
#> ──────────────────┼─────────────────────────────────────────────────────────────
#> info_doctor │ 377 62.9 344 60.9 721 61.9 1.000
#> info_pharmacist │ 137 22.9 119 21.1 256 22.0 1.000
#> info_internet │ 268 44.7 255 45.1 523 44.9 1.000
#> info_family │ 219 36.6 141 25.0 360 30.9 <.001
#> info_media │ 78 13.0 63 11.2 141 12.1 1.000
#> (No item chosen) │ 31 5.2 36 6.4 67 5.8 –
#> ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┼╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
#> Respondents │ 599 565 1164
#>
#> Note. Multiple answers possible: percentages can sum to more than 100%. Base: respondents with data for the question (excluded: 36 with no data for the question). Item p-values: Pearson chi-squared test of each item by group. P-values adjusted for 5 tests (Holm method). Overall group comparison: bootstrap test of multiple marginal independence (999 resamples), χ² = 20.38, p = .002.
# Wide data frame.
table_multiresponse(
sochealth,
select = starts_with("info_"),
by = sex,
output = "data.frame"
)
#> variable label .row_role Female n Female % Male n
#> 1 info_doctor info_doctor summary 377 62.938230 344
#> 2 info_pharmacist info_pharmacist summary 137 22.871452 119
#> 3 info_internet info_internet summary 268 44.741235 255
#> 4 info_family info_family summary 219 36.560935 141
#> 5 info_media info_media summary 78 13.021703 63
#> 6 none (No item chosen) none 31 5.175292 36
#> 7 nobs Respondents fit_stat 599 NA 565
#> Male % Total n Total % p
#> 1 60.884956 721 61.941581 1.000000e+00
#> 2 21.061947 256 21.993127 1.000000e+00
#> 3 45.132743 523 44.931271 1.000000e+00
#> 4 24.955752 360 30.927835 9.285636e-05
#> 5 11.150442 141 12.113402 1.000000e+00
#> 6 6.371681 67 5.756014 NA
#> 7 NA 1164 NA NA
# \donttest{
if (requireNamespace("tinytable", quietly = TRUE)) {
tt <- table_multiresponse(
sochealth,
select = starts_with("info_"),
by = sex,
labels = TRUE,
output = "tinytable"
)
}
# }