Skip to contents

A comprehensive function for comparing groups using publication-ready visualizations and statistical tests. Creates `ggbetweenstats` plots from the ggstatsplot package with automatic test selection based on the number of groups:

For 2 groups: t-test (parametric) or Mann-Whitney U (nonparametric). For 3+ groups: ANOVA (parametric) or Kruskal-Wallis (nonparametric) with post-hoc pairwise comparisons. Also supports Bayesian analysis, equivalence testing (TOST), and stratified analyses using repeat_category.

Usage

compare_groups(
  data,
  category,
  Vars = NULL,
  category_sep = " | ",
  repeat_category = NULL,
  compare_by = NULL,
  compare_mode = c("between", "within"),
  repeat_combine = TRUE,
  repeat_levels = NULL,
  plots = TRUE,
  plot_style = c("points", "boxplot", "bar", "violin", "ggstatsplot"),
  table = TRUE,
  type = "auto",
  bayesian = FALSE,
  equivalence = FALSE,
  equivalence_bounds = c(-0.5, 0.5),
  nonparametric = FALSE,
  p_adjust_method = "fdr",
  posthoc = TRUE,
  posthoc_method = "games-howell",
  posthoc_table = FALSE,
  posthoc_format = c("wide", "long", "both"),
  pairwise_display = "significant",
  pivot = FALSE,
  pivot_by = c("category", "repeat_category"),
  pivot_stat = c("mean", "mean_sd", "median", "n"),
  pivot_stars = TRUE,
  pivot_split_level = TRUE,
  min_threshold = 0.05,
  min_subcategory = 5,
  colors = NULL,
  verbose = TRUE,
  combined_table = TRUE,
  format = c("gt", "plain", "markdown", "latex", "kable"),
  show_header = TRUE,
  interpret = FALSE,
  ...
)

Arguments

data

A data frame containing the variables to analyze.

category

Character. Name(s) of the grouping variable(s). Can be a single variable (e.g., "gender") or multiple variables for interaction groups (e.g., c("gender", "treatment") creates "Male | Treatment", etc.).

Vars

Column specification for variables to compare. Can be NULL (default, all numeric columns), a character vector of column names, a numeric vector of column indices, or a single number (from that column to end).

category_sep

Character. Separator for combined group labels when multiple variables are passed to category. Default: " | ".

repeat_category

Optional character. Name of a stratification variable. When provided, separate analyses are performed for each level (e.g., analyze gender differences separately for each country). Used with compare_mode = "between".

compare_by

Optional character vector. Factors to test within each category level. Used with compare_mode = "within". For example, if category = "llm" and compare_by = c("pronoun", "support"), tests whether pronoun and support have effects within each LLM dataset separately.

compare_mode

Character. Analysis mode: "between" (default) - compare category levels (e.g., GPT vs Mistral vs Qwen), "within" - test compare_by factors within each category level (e.g., test pronoun effect within GPT, within Mistral, within Qwen separately).

repeat_combine

Logical. When multiple repeat_category variables are provided with compare_mode = "between", should they be combined into one grouping (e.g., "he/him | High")? Default TRUE.

repeat_levels

Optional character vector. Specific levels of repeat_category to include in the analysis. If NULL (default), all levels are used.

plots

Logical. Generate visualizations? Default TRUE.

plot_style

Character. Style of plots: "points" (default, jittered with CI), "boxplot", "bar", "violin", or "ggstatsplot" (requires ggstatsplot package).

table

Logical. Generate summary statistics table? Default TRUE.

type

Character. Type of statistical test: "auto" (default), "parametric"/"p", "nonparametric"/"np", "kw" (Kruskal-Wallis), "mw" (Mann-Whitney), or "bayes"/"bf".

bayesian

Logical. Compute Bayesian t-tests with Bayes Factors? Default: FALSE. Requires the BayesFactor package. Can also use `type = "bayes"`.

equivalence

Logical. Perform equivalence testing (TOST)? Default: FALSE. Requires the TOSTER package.

equivalence_bounds

Numeric vector of length 2. Equivalence bounds in Cohen's d units for TOST. Default: c(-0.5, 0.5).

nonparametric

Logical. Use nonparametric tests? Default: FALSE. When TRUE, uses Mann-Whitney U (2 groups) or Kruskal-Wallis (3+ groups).

p_adjust_method

Method for multiple comparison correction. Options: "none", "bonferroni", "holm", "hochberg", "hommel", "BH", "BY", "fdr". Default: "fdr" (Benjamini-Hochberg False Discovery Rate). Applied to both tables and post-hoc tests.

posthoc

Logical. Compute post-hoc pairwise comparisons for 3+ groups? Default: TRUE. Results include a comparison table and text report.

posthoc_method

Method for post-hoc comparisons: "games-howell" (default, does not assume equal variances) or "tukey" (Tukey's HSD, assumes equal variances).

posthoc_table

Logical. Include detailed post-hoc pairwise comparison table in the output? Default FALSE.

posthoc_format

Character. Format for post-hoc table when pivot = TRUE: "wide" (default, comparisons as columns), "long" (one row per comparison), or "both" (return both formats).

pairwise_display

Which pairwise comparisons to show on plots? Options: "significant" (default), "all", "none".

pivot

Logical. Pivot to wide format? Default FALSE. When TRUE, creates a wide table based on pivot_by parameter.

pivot_by

Character. Which variable to pivot to columns: "category" (default) - category groups become columns (e.g., GPT, Mistral, Qwen), "repeat_category" - repeat_category levels become columns (e.g., he/him, she/her).

pivot_stat

Character. Statistic to display in pivoted cells: "mean" (default), "mean_sd" (mean with SD in parentheses), "median", or "n" (count).

pivot_stars

Logical. Show significance stars in pivot table? Default TRUE when pivot = TRUE.

pivot_split_level

Logical. When multiple repeat_category variables are combined (e.g., "he/him | High"), split them back into separate columns? Default TRUE. When FALSE, keeps the combined "level" column.

min_threshold

Numeric. Minimum proportion (0-1) of total sample required to include a repeat_category level. Default: 0.05 (5 percent).

min_subcategory

Integer. Minimum observations required per group. Groups with fewer observations are excluded from analysis. Default: 5.

colors

Character vector of colors for groups. Default: NULL uses a built-in palette.

verbose

Logical. Print progress messages? Default: TRUE.

combined_table

Logical. When `repeat_category` is used, combine all results into a single table? Default: TRUE. The combined table shows all repeat_category levels together with bold highest means and red significant p-values.

format

Character. Output format for tables: "gt" (default, publication-ready), "plain" (data frame), "markdown", "latex", or "kable".

show_header

Logical. Show title/subtitle header? Default TRUE. Set to FALSE to hide the table header.

interpret

Logical. Pass results to AI for automatic interpretation? Default FALSE. When TRUE, generates clean Methods and Results text using AI. Requires API key setup (see set_api_key).

...

Additional arguments passed to pass when interpret = TRUE (e.g., provider, model, context).

Value

A list with class "comparison_results" containing: plots (named list of ggplot objects), grid_plot (combined plot grid if multiple variables), summary_table (formatted gt table), and summary_data (data frame with raw statistics). For stratified analysis (with repeat_category), returns a named list where each element corresponds to a level of repeat_category. When pivot = TRUE, additional elements are returned:

  • pivot_table: gt table with groups as columns and factor levels as rows

  • posthoc_pivot_wide: Post-hoc comparisons in wide format (if posthoc_table = TRUE)

  • posthoc_pivot_long: Post-hoc comparisons in long format (if posthoc_format = "long" or "both")

See also

ggbetweenstats for the underlying plot function

Examples

if (FALSE) { # \dontrun{
# ============================================================
# EXAMPLE 1: Basic Two-Group Comparison (t-test)
# ============================================================
data <- data.frame(
  gender = rep(c("Male", "Female"), each = 50),
  score = c(rnorm(50, mean = 100, sd = 15),
            rnorm(50, mean = 105, sd = 15))
)

results <- compare_groups(
  data = data,
  category = "gender",
  Vars = c("score")
)

# View the plot
results$plots$gender_vs_score

# View summary statistics
results$summary_data

# ============================================================
# EXAMPLE 2: Three-Group Comparison (ANOVA with post-hoc)
# ============================================================
data <- data.frame(
  country = rep(c("USA", "UK", "Germany"), each = 40),
  score1 = c(rnorm(40, 75, 10), rnorm(40, 70, 11), rnorm(40, 85, 9)),
  score2 = c(rnorm(40, 50, 8), rnorm(40, 55, 9), rnorm(40, 48, 7))
)

results <- compare_groups(
  data = data,
  category = "country",
  Vars = c("score1", "score2"),
  posthoc = TRUE,
  posthoc_method = "tukey",
  pairwise_display = "all"
)

# View post-hoc pairwise comparisons
results$summary_data$posthoc_results[[1]]

# Print full ANOVA report
cat(results$summary_data$anova_report[1])

# ============================================================
# EXAMPLE 3: Bayesian Analysis
# ============================================================
results <- compare_groups(
  data = data,
  category = "country",
  Vars = c("score1"),
  bayesian = TRUE
)

# View Bayes Factors
results$summary_data[, c("country", "mean", "bf10", "bf_interpretation")]

# ============================================================
# EXAMPLE 4: Nonparametric Tests
# ============================================================
results <- compare_groups(
  data = data,
  category = "country",
  Vars = c("score1"),
  nonparametric = TRUE  # Uses Kruskal-Wallis + pairwise Wilcoxon
)

# ============================================================
# EXAMPLE 5: Stratified Analysis (separate tests per subgroup)
# ============================================================
data <- data.frame(
  country = rep(c("USA", "UK", "Germany"), each = 60),
  gender = rep(c("Male", "Female"), times = 90),
  score = rnorm(180, mean = 100, sd = 15)
)

# Compare gender WITHIN each country
results <- compare_groups(
  data = data,
  category = "gender",
  Vars = c("score"),
  repeat_category = "country"
)

# Access results by country
results$USA$summary_data
results$UK$plots$gender_vs_score
results$Germany$summary_table

# ============================================================
# EXAMPLE 6: Equivalence Testing (TOST)
# ============================================================
results <- compare_groups(
  data = data,
  category = "gender",
  Vars = c("score"),
  equivalence = TRUE,
  equivalence_bounds = c(-0.3, 0.3)  # Small effect bounds
)

# Check equivalence conclusions
results$summary_data[, c("gender", "mean", "equivalence_conclusion")]

# ============================================================
# EXAMPLE 7: Combined/Interaction Groups
# ============================================================
data <- data.frame(
  strength = rep(c("Strong", "Weak"), each = 60),
  gender = rep(c("Male", "Female"), times = 60),
  score = rnorm(120, mean = 100, sd = 15)
)

# Pass multiple variables to category for interaction groups
results <- compare_groups(
  data = data,
  category = c("strength", "gender"),  # Creates "Strong | Male", "Strong | Female", etc.
  Vars = c("score")
)

# Custom separator
results <- compare_groups(
  data = data,
  category = c("strength", "gender"),
  category_sep = " x ",  # Creates "Strong x Male", etc.
  Vars = c("score")
)

# ============================================================
# EXAMPLE 8: Pivoted Table (groups as columns)
# ============================================================
# LLM comparison data
data <- data.frame(
  Support_level = c(rnorm(100, 4, 1), rnorm(100, 6.5, 1), rnorm(100, 4.8, 1)),
  pronoun = rep(c("he/him", "she/her", "they/them"), each = 100),
  LA_activity = rep(c("Negative", "Positive"), 150),
  llm = rep(c("GPT", "Mistral", "Qwen"), each = 100)
)

# Basic pivot - groups become columns
results <- compare_groups(
  data = data,
  category = "llm",                    # Becomes columns: GPT | Mistral | Qwen
  Vars = "Support_level",
  repeat_category = "pronoun",         # Rows: he/him, she/her, they/them
  pivot = TRUE                         # Enable pivot mode
)

# Access the pivot table
results$pivot_table

# ============================================================
# EXAMPLE 9: Pivot with Mean and SD
# ============================================================
results <- compare_groups(
  data = data,
  category = "llm",
  Vars = "Support_level",
  repeat_category = c("pronoun", "LA_activity"),
  pivot = TRUE,
  pivot_stat = "mean_sd"              # Shows "4.32 (1.21)"
)

# ============================================================
# EXAMPLE 10: Pivot with Post-hoc Comparisons Table
# ============================================================
results <- compare_groups(
  data = data,
  category = "llm",
  Vars = "Support_level",
  repeat_category = "pronoun",
  pivot = TRUE,
  posthoc = TRUE,
  posthoc_table = TRUE,               # Include post-hoc table
  posthoc_format = "wide"             # "wide", "long", or "both"
)

# Access tables
results$pivot_table              # Main pivoted means table
results$posthoc_pivot_wide       # Post-hoc comparisons (wide format)

# ============================================================
# EXAMPLE 11: Different P-value Adjustment Methods
# ============================================================
# Available methods: "none", "bonferroni", "holm", "hochberg",
#                   "hommel", "BH", "BY", "fdr" (default)
results <- compare_groups(
  data = data,
  category = "llm",
  Vars = "Support_level",
  repeat_category = "pronoun",
  pivot = TRUE,
  p_adjust_method = "bonferroni"
)
} # }