Multidimensional workflows

phontrast can estimate category separation in feature spaces with more than two dimensions, such as MFCC vectors, formants plus duration, or other acoustic embeddings. The key distinction is that metrics and plots answer different questions:

library(phontrast)

set.seed(2026)
features <- paste0("feature_", 1:6)
tokens <- data.frame(
  speaker = rep(c("s01", "s02"), each = 80),
  category = rep(rep(c("A", "B"), each = 40), 2),
  matrix(rnorm(160 * length(features)), ncol = length(features))
)
names(tokens)[-(1:2)] <- features
tokens[tokens$category == "B", features[1:3]] <-
  tokens[tokens$category == "B", features[1:3]] + 0.65

Compute metrics in all dimensions.

metrics <- phontrast(
  data = tokens,
  features = features,
  category_col = "category",
  group_col = "speaker",
  output = "long"
)

metrics[, 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.209   separation             0.209
#>  2 s02   Pillai trace               0.411   separation             0.411
#>  3 s01   Bhattacharyya distance     0.325   separation             0.325
#>  4 s02   Bhattacharyya distance     0.487   separation             0.487
#>  5 s01   Bhattacharyya affinity     0.722   overlap                0.278
#>  6 s02   Bhattacharyya affinity     0.615   overlap                0.385
#>  7 s01   Jensen-Shannon divergence  0.987   separation             0.987
#>  8 s02   Jensen-Shannon divergence  0.976   separation             0.976
#>  9 s01   Jensen-Shannon distance    0.994   separation             0.994
#> 10 s02   Jensen-Shannon distance    0.988   separation             0.988
#> 11 s01   Mahalanobis distance       1.01    separation             1.01 
#> 12 s02   Mahalanobis distance       1.65    separation             1.65 
#> 13 s01   Percent overlap            0.00314 overlap                0.997
#> 14 s02   Percent overlap            0.00629 overlap                0.994

Visualize a projection without changing the metric estimand.

plot_category_pca(
  data = tokens,
  features = features,
  category_col = "category",
  group_col = "speaker"
)

For a specific pair of interpretable dimensions, use plot_category_space().

plot_category_space(
  data = tokens,
  features = c("feature_1", "feature_2"),
  category_col = "category",
  group_col = "speaker"
)

PCA plots are useful for sanity checks and presentations, but they can hide separation that lives outside the first two principal components. Use them as a visual diagnostic; report metric estimates from the intended full feature set.

PB52 note

The Peterson and Barney 1952 data in phonTools::pb52 are useful for global vowel contrasts. For example, a global I/i comparison in F1/F2 has many tokens. Per-speaker I/i F1/F2 comparisons are not estimable with KDE-based metrics because each speaker has only two repetitions per vowel.

data(pb52, package = "phonTools")
pb_i <- subset(pb52, as.character(vowel) %in% c("I", "i"))

phontrast(
  data = pb_i,
  features = c("f1", "f2"),
  category_col = "vowel"
)