Most analyses should start with a token-level table: one row per
observation, one column for the category contrast, and one or more
numeric acoustic features. phontrast() is the preferred
entry point because it returns the main overlap and separation metrics
side by side.
library(phontrast)
set.seed(2026)
vowels <- data.frame(
speaker = rep(c("s01", "s02"), each = 60),
vowel = rep(rep(c("ih", "eh"), each = 30), 2),
f1 = c(
rnorm(30, 500, 55), rnorm(30, 560, 60),
rnorm(30, 510, 60), rnorm(30, 575, 65)
),
f2 = c(
rnorm(30, 1980, 150), rnorm(30, 1880, 155),
rnorm(30, 1960, 160), rnorm(30, 1840, 165)
)
)The wide output is useful for analysis tables and joining to speaker metadata.
metrics_wide <- phontrast(
data = vowels,
features = c("f1", "f2"),
category_col = "vowel",
group_col = "speaker",
output = "wide"
)
metrics_wide
#> # A tibble: 2 × 11
#> scope group n_tokens pillai pillai_p_value bhatt_dist bhatt_affinity jsd
#> <chr> <chr> <int> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 group s01 60 0.316 0.0000198 0.276 0.758 0.288
#> 2 group s02 60 0.250 0.000278 0.166 0.847 0.164
#> # ℹ 3 more variables: js_distance <dbl>, mahalanobis_dist <dbl>,
#> # percent_overlap <dbl>The long output is easier to rank, filter, and plot.
separation_value puts all metrics on a separation-oriented
scale: larger values mean greater category separation, even for overlap
metrics such as percent overlap and Bhattacharyya affinity.
metrics_long <- phontrast(
data = vowels,
features = c("f1", "f2"),
category_col = "vowel",
group_col = "speaker",
output = "long"
)
metrics_long[, c("group", "metric", "estimate", "orientation", "separation_value")]
#> # A tibble: 14 × 5
#> group metric estimate orientation separation_value
#> <chr> <chr> <dbl> <chr> <dbl>
#> 1 s01 Pillai trace 0.316 separation 0.316
#> 2 s02 Pillai trace 0.250 separation 0.250
#> 3 s01 Bhattacharyya distance 0.276 separation 0.276
#> 4 s02 Bhattacharyya distance 0.166 separation 0.166
#> 5 s01 Bhattacharyya affinity 0.758 overlap 0.242
#> 6 s02 Bhattacharyya affinity 0.847 overlap 0.153
#> 7 s01 Jensen-Shannon divergence 0.288 separation 0.288
#> 8 s02 Jensen-Shannon divergence 0.164 separation 0.164
#> 9 s01 Jensen-Shannon distance 0.537 separation 0.537
#> 10 s02 Jensen-Shannon distance 0.406 separation 0.406
#> 11 s01 Mahalanobis distance 1.34 separation 1.34
#> 12 s02 Mahalanobis distance 1.13 separation 1.13
#> 13 s01 Percent overlap 0.425 overlap 0.575
#> 14 s02 Percent overlap 0.643 overlap 0.357If ggplot2 is installed, the same objects can be
visualized directly.
plot_category_space(
data = vowels,
features = c("f2", "f1"),
category_col = "vowel",
group_col = "speaker",
reverse_x = TRUE,
reverse_y = TRUE
)For uncertainty intervals, use do_boot = TRUE.
Bootstrapping recomputes every metric on every resample, so use a larger
n_boot for final analyses than for interactive
examples.