本文へスキップ
からだにいいもの

Rのトピックスを中心に『まだ、まだ、知らない、役に立つ情報?』を発信します。

Rで解析:音韻カテゴリーの分離・重なりを複数指標で評価する「phontrast」パッケージの紹介

音声学や言語学の研究では、母音や子音といった音韻カテゴリーが、フォルマント値やMFCCなどの音響空間上でどれだけ明確に区別されているかを確認したい場面があります。しかし、複数の指標を一括で計算し、話者やグループごとのばらつきを考慮しながら評価するには手間がかかります。

「phontrast」パッケージは、多次元の音響空間における2つのカテゴリー間の分離度や重なり具合を、複数の指標を用いて一括で算出するパッケージです。Pillaiのトレースや Bhattacharyya 距離、Jensen-Shannon 情報量など複数の指標をまとめて計算でき、話者単位の階層ブートストラップによる年齢効果の検定も可能です。また、算出結果にもとづくカテゴリー空間の可視化や、主成分分析による高次元特徴量の投影図のプロットも可能です。本パッケージの利用で、音韻のコントラストを複数の指標から多角的に確認できるのではないかと考えます。

パッケージバージョンは2.4.0。Windows 11 x64 (build 26200)のR version 4.6.1で確認しています。

パッケージのインストール

下記コマンドを実行してください。

# パッケージのインストール
install.packages("phontrast")
# パッケージの読み込み
library("phontrast")
スポンサーリンク

コマンド例

詳細はコメント、パッケージのヘルプを確認してください。

本パッケージの中心となるのはphontrastコマンドで、2つの音韻カテゴリーについてPillaiのトレースやBhattacharyya距離、Jensen-Shannon情報量など複数の分離・重なり指標を一括で算出します。話者ごとの経年変化を調べたい場合はhier_boot_jsd_modelコマンドで階層ブートストラップモデルを当てはめられます。また、plot_contrastコマンドやplot_category_spaceコマンド、plot_category_pcaコマンドでカテゴリー間の分布を可視化でき、plot_overlap_metricsコマンドで複数の比較対象の指標をまとめて確認できます。配色にはphontrast_paletteコマンドとscale_colour_phontrastコマンドが用意されています。

本記事では、京都市右京区と与謝郡伊根町の高校生が発音した母音「い」「え」のフォルマント測定値を架空のデータとして作成し、記事全体を通して使用します。

# 乱数シードの固定
set.seed(2026)

# 右京区と伊根町の話者情報を作成
chiku <- rep(c("右京区", "伊根町"), each = 4)

wakate <- data.frame(
  speaker = paste0("sp", sprintf("%02d", 1:8)),
  chiku = chiku,
  age = rep(c(16, 17, 18, 17), 2)
)

# 話者ごとに「い」「え」を25回ずつ発音したデータの骨組みを作成
boin <- data.frame(
  speaker = rep(wakate$speaker, each = 50),
  vowel = rep(rep(c("い", "え"), each = 25), nrow(wakate))
)

# 話者情報を結合
boin <- merge(boin, wakate, by = "speaker", sort = FALSE)

# 母音と地区の違いを反映した第1フォルマント(F1)を生成
boin$f1 <- rnorm(nrow(boin),
                 mean = ifelse(boin$vowel == "い", 320, 480) +
                   ifelse(boin$chiku == "伊根町", 25, 0),
                 sd = 45)

# 母音と地区の違いを反映した第2フォルマント(F2)を生成
boin$f2 <- rnorm(nrow(boin),
                 mean = ifelse(boin$vowel == "い", 2400, 2050) +
                   ifelse(boin$chiku == "伊根町", -110, 0),
                 sd = 140)

# 第3フォルマント(F3)を生成
boin$f3 <- rnorm(nrow(boin), mean = ifelse(boin$vowel == "い", 3000, 2900), sd = 150)
# スペクトル傾動を生成

boin$tilt <- rnorm(nrow(boin),
                   mean = ifelse(boin$vowel == "い", -8, -5) +
                     ifelse(boin$chiku == "伊根町", -1, 0),
                   sd = 2)

2つのカテゴリー間の分離・重なりを複数指標で算出:phontrastコマンド

オプション意味初期値
dataカテゴリを表す列と音響特徴量の列を含むデータフレームなし
features数値の特徴量列を指定する文字列ベクトルなし
category_col比較する2つのカテゴリーが入った列名の文字列なし
group_colグループ化に使う列を指定する文字列ベクトル(複数可)。NULLなら全体で算出し、複数指定時はラベルを結合して扱うNULL
metrics算出する指標を選ぶ文字列ベクトル。jsd、js_distance、pillai、bhattacharyya、mahalanobis、overlapから選択でき、既定はすべて。bhattacharyyaはバタチャリヤ距離と近似度の両方を返すc(“jsd”, “js_distance”, “pillai”, “bhattacharyya”, “mahalanobis”, “overlap”)
min_tokens全体またはグループごとに必要な最小トークン数20
bwjsd_kde_nd()とpercent_overlap_kde()に渡すバンド幅選択法c(“Hpi”, “Hscv”, “Hpi.diag”, “scott.diag”)
eval_onjsd_kde_nd()とpercent_overlap_kde()に渡すKDE評価点の位置c(“pooled”, “group1”, “group2”, “pooled_sample”)
eval_nKDE評価点数の上限NULL
eval_seedKDE評価点のサブサンプリングに使う整数のシードNULL
engineKDE評価エンジン。fast_diagonalはfast_diagの別名として扱われるc(“ks”, “fast_diag”, “fast_diagonal”)
chunk_sizeengine = “fast_diag”のときのチャンクサイズ1000L
eps共分散にもとづく指標に用いる小さなリッジ定数1e-06
output出力形式。wideは比較ごとに1行、longは指標ごとに1行にまとめるc(“wide”, “long”)
do_boot論理値。TRUEならブートストラップで各指標の平均・標準偏差・信頼区間を算出FALSE
n_bootdo_boot = TRUEのときのブートストラップ再標本化の回数1000
conf_levelブートストラップ信頼区間の信頼水準0.95
progress論理値。TRUEならブートストラップの実行中に進捗メッセージを表示TRUE
methodjsdと重なり率の列に用いるKDE推定法。mc(既定)はモンテカルロのプラグイン推定、legacyは1.2.0より前の自己正規化推定。density = “mvnorm”のときは無視されるc(“mc”, “legacy”)
densityJensen-Shannon情報量と比率重なりの2指標が前提とする密度モデル。kde(既定)はカーネル密度推定、mvnormは各カテゴリーに多変量正規分布を当てはめモンテカルロ法で推定する。Pillai・Bhattacharyya・Mahalanobisの列はこの引数の影響を受けないc(“kde”, “mvnorm”)
mc_ndensity = “mvnorm”のとき、Jensen-Shannon情報量と重なり率のために各正規分布から抽出するモンテカルロ標本数10000L

2つの音韻カテゴリーに含まれる音響特徴量から、Pillaiのトレース、Bhattacharyya距離・近似度、Jensen-Shannon情報量とその平方根であるJensen-Shannon距離、Mahalanobis距離、比率重なりの各指標を一括で算出します。metricsで算出する指標を絞り込め、group_colを指定するとグループごとに算出できます。outputを”long”にすると指標ごとに1行の縦持ち形式になり、後述のplotコマンドやplot_overlap_metricsコマンドにそのまま渡せます。

# 右京区・伊根町の母音「い」「え」の分離度をまとめて算出(全列を表示)
print(phontrast(boin, features = c("f1", "f2"), category_col = "vowel"), width = Inf)
# A tibble: 1 × 10
  scope  n_tokens pillai pillai_p_value bhatt_dist bhatt_affinity   jsd
  <chr>     <int>  <dbl>          <dbl>      <dbl>          <dbl> <dbl>
1 global      400  0.814      8.44e-146       2.18          0.113 0.950
  js_distance mahalanobis_dist percent_overlap
        <dbl>            <dbl>           <dbl>
1       0.975             4.18          0.0238

話者ごとの階層ブートストラップでJensen-Shannon情報量の年齢依存性をモデル化:hier_boot_jsd_modelコマンド

オプション意味初期値
datagroup_col、category_col、features、および式で使う説明変数を含むデータフレームなし
group_colグループ化変数を表す列名の文字列(例:speaker)なし
category_col2水準を持つカテゴリー変数を表す列名の文字列(例:vowel)なし
features音響特徴量の列名を表す文字列ベクトルなし
formulafit_funに渡すモデル式(例:jsd_beta ~ s(age) + s(region, bs = “re”))なし
fit_fun(formula, data, …)を受け取り当てはめ済みモデルを返す関数。既定はmgcv::gamが使えればそれ、なければstats::lmNULL
n_outer階層ブートストラップの再標本化回数200
min_tokensグループ内で必要な最小トークン数20
epsBeta族を使う場合にJSDを(0, 1)へ収めるための小さなイプシロン1e-06
progress論理値。TRUEなら10回ごとに進捗を表示TRUE
fit_funに渡す追加の引数なし

話者をグループとしてリサンプリングしながら、話者ごとのJensen-Shannon情報量にformulaで指定したモデルを繰り返し当てはめます。戻り値は再標本化ごとの回帰係数の一覧で、係数のばらつきから年齢の効果の確からしさを確認できます。

# 乱数シードの固定
set.seed(2026)
# 話者ごとのJensen-Shannon情報量に年齢を説明変数とした回帰を階層ブートストラップで当てはめ
hier_boot_jsd_model(
  data = boin,
  group_col = "speaker",
  category_col = "vowel",
  features = "f1",
  formula = jsd_beta ~ age,
  fit_fun = stats::lm,
  n_outer = 5,
  min_tokens = 20,
  progress = FALSE
)
# A tibble: 10 × 3
   boot_id term        estimate
     <int> <chr>          <dbl>
 1       1 (Intercept)   0.584
 2       1 age           0.0226
 3       2 (Intercept)   1.81
 4       2 age          -0.0514
 5       3 (Intercept)   1.76
 6       3 age          -0.0506
 7       4 (Intercept)   1.13
 8       4 age          -0.0137
 9       5 (Intercept)   2.15
10       5 age          -0.0710

2つのカテゴリー間の分布を考慮した対比図のプロット:plot_contrastコマンド

オプション意味初期値
dataカテゴリを表す列と1〜2個の数値特徴量列を含むデータフレームなし
features1〜2個の数値特徴量列。1個なら密度曲線、2個なら密度領域を伴う特徴量空間の図になる。3次元以上を扱う場合はplot_category_pca()で射影する(指標自体は全次元で算出する)なし
category_col観測されたカテゴリーがちょうど2種類だけ入った列名の文字列なし
group_col任意で指定する文字列ベクトルのグループ化列。グループごとに1パネル、グループ単位の密度と注釈を表示NULL
density描画・注釈に使う密度モデル。kde(既定)またはmvnorm。指標関数のdensity引数に対応c(“kde”, “mvnorm”)
bwdensity = “kde”のときのバンド幅選択法。jsd_kde_nd()と同じ選択肢c(“Hpi”, “Hscv”, “Hpi.diag”, “scott.diag”)
levels描画する領域の確率水準を(0, 1)で指定する数値ベクトル。kdeでは最高密度領域、mvnormでは被覆楕円になるc(0.5, 0.8, 0.95)
points論理値。観測トークンを表示(2次元は点、1次元はラグ)TRUE
overlap論理値。2つのカテゴリー密度の各点での最小値に網掛け(1次元はリボン、2次元は淡いラスタ)。網掛けの強さはパネル間で正規化されるTRUE
annotate論理値。描画した密度モデルにもとづくJensen-Shannon情報量と比率重なりを各パネルに表示TRUE
n_boot注釈の信頼区間に用いるブートストラップ再標本化数。既定の0は点推定のみ表示0
conf_levelブートストラップ区間の信頼水準0.95
min_tokensグループあたりの最小トークン数。これを下回るグループは警告のうえ除外(指標関数と同じ規約)20
mc_ndensity = “mvnorm”の注釈に使うモンテカルロ標本数。指標関数に渡される10000L
eval_seed注釈値を再現可能にするため指標関数に渡す任意の整数シードNULL
grid_n密度評価のグリッド解像度(1軸あたりの点数)。既定は特徴量1個で512、2個で151NULL
point_alpha点(またはラグ)の透明度0.55
point_size2特徴量プロットでの点の大きさ1.6
reverse_x論理値。軸を反転する(例:母音空間の慣例に沿ったF2×F1表示)FALSE
reverse_y論理値。軸を反転する(例:母音空間の慣例に沿ったF2×F1表示)FALSE
facet_scalesgroup_col指定時にggplot2::facet_wrap()へ渡すscalesc(“fixed”, “free”, “free_x”, “free_y”)

featuresに2つの特徴量を指定すると、密度領域を重ねた特徴量空間の図になります。1つだけ指定した場合は密度曲線になります。overlapで2つのカテゴリー密度が重なる範囲に網掛けし、annotateでJensen-Shannon情報量と比率重なりをパネルに注釈します。

# ggplot2が利用可能であれば対比図を描画
if (requireNamespace("ggplot2", quietly = TRUE)) {
  # 母音空間の慣例に合わせてF2を横軸に反転した対比図
  plot_contrast(boin, c("f2", "f1"), "vowel", reverse_x = TRUE, reverse_y = TRUE)
  # F1のみを使った1次元の対比図
  plot_contrast(boin, "f1", "vowel")
}

phontrastの算出結果を直接プロット:plotコマンド

オプション意味初期値
xphontrast()が返すphontrast_contrastオブジェクトなし
plot_overlap_metrics()に渡すなし

phontrastコマンドの戻り値(output = “long”)にはplotコマンドが用意されています。内部でplot_overlap_metricsコマンドを呼び出し、算出済みの指標をそのままプロットします。

# ggplot2が利用可能であればphontrastの縦持ち結果をそのままプロット
if (requireNamespace("ggplot2", quietly = TRUE)) {
  plot(phontrast(boin, c("f1", "f2"), "vowel", output = "long"))
}

高次元の音響特徴量をPCAで低次元に投影してプロット:plot_category_pcaコマンド

オプション意味初期値
dataカテゴリを表す列と音響特徴量を含むデータフレームなし
featuresPCAに用いる2個以上の数値特徴量列を表す文字列ベクトルなし
category_colカテゴリーを表す列名の文字列なし
group_colパネル分割に使う任意のグループ化列NULL
componentsプロットする主成分を指定する2つの正の整数c(1L, 2L)
centerstats::prcomp()に渡すTRUE
scale.stats::prcomp()に渡すTRUE
points論理値。TRUEなら射影した観測値を表示TRUE
ellipses論理値。TRUEなら観測数が十分な場合に正規楕円を追加TRUE
point_alpha点の透明度0.65
point_size点の大きさ1.8
equal_axes論理値。TRUEなら座標比を固定TRUE
facet_scalesgroup_col指定時にggplot2::facet_wrap()へ渡すscalesc(“fixed”, “free”, “free_x”, “free_y”)

3個以上の音響特徴量を扱う場合に、主成分分析で2次元に投影してカテゴリーの分布を確認できます。componentsで表示する主成分を切り替えられます。

# ggplot2が利用可能であれば4つの音響特徴量をPCAで2次元に投影してプロット
if (requireNamespace("ggplot2", quietly = TRUE)) {
  plot_category_pca(boin, features = c("f1", "f2", "f3", "tilt"), category_col = "vowel")
}

音響空間における音韻カテゴリーのプロット:plot_category_spaceコマンド

オプション意味初期値
dataカテゴリを表す列と音響特徴量を含むデータフレームなし
featuresプロットする1〜2個の数値特徴量列なし
category_colカテゴリーを表す列名の文字列なし
group_colパネル分割に使う任意のグループ化列NULL
points論理値。TRUEなら観測トークンを表示TRUE
ellipses論理値。TRUEなら2特徴量プロットで観測数が十分な場合に正規楕円を追加TRUE
point_alpha点の透明度0.65
point_size点の大きさ1.8
reverse_x論理値。TRUEならx軸を反転FALSE
reverse_y論理値。TRUEならy軸を反転FALSE
equal_axes論理値。TRUEなら2特徴量プロットで座標比を固定FALSE
facet_scalesgroup_col指定時にggplot2::facet_wrap()へ渡すscalesc(“fixed”, “free”, “free_x”, “free_y”)

featuresに1〜2個の特徴量を指定し、観測トークンと正規楕円で音響空間上のカテゴリー分布をそのまま描画します。plot_contrastコマンドと異なり、密度領域や重なりの網掛けは表示しません。

# ggplot2が利用可能であればカテゴリ空間をプロット
if (requireNamespace("ggplot2", quietly = TRUE)) {
  # F1のみを使った1次元のカテゴリ空間
  plot_category_space(boin, features = "f1", category_col = "vowel")
  # 母音空間の慣例に合わせてF2とF1で2次元のカテゴリ空間
  plot_category_space(boin, features = c("f2", "f1"), category_col = "vowel",
                      reverse_x = TRUE, reverse_y = TRUE)
}

地区間で分離・重なり指標を比較する棒グラフの作成:plot_overlap_metricsコマンド

オプション意味初期値
metricsphontrast()が返すデータフレームなし
valueプロットする尺度。separationはseparation_valueを、estimateは指標の生の推定値を描画c(“separation”, “estimate”)
metric対象とする指標の表示名を指定する任意の文字列ベクトルNULL
group_colx軸に使う任意の列。既定は”group”列があればそれ、なければ”scope”NULL
show_ci論理値。TRUEならci_lower/ci_upper列がある場合に信頼区間を描画TRUE
facet論理値。TRUEなら指標ごとにパネル分割TRUE
sort論理値。TRUEなら描画値の平均で比較対象を並べ替えTRUE

phontrastコマンドの縦持ち出力(複数のグループを含むもの)を渡すと、指標ごとにグループ間の値を比較する棒グラフを描画します。show_ciで信頼区間を、sortで比較対象の並べ替えを制御します。

# 地区ごとの分離・重なり指標を縦持ち形式で算出
chiku_shihyo <- phontrast(boin, features = c("f1", "f2"), category_col = "vowel",
                          group_col = "chiku", output = "long")
# ggplot2が利用可能であれば地区間を比較する棒グラフを描画
if (requireNamespace("ggplot2", quietly = TRUE)) {
  plot_overlap_metrics(chiku_shihyo)
}

phontrastパッケージの標準カラーパレットを取得:phontrast_paletteコマンド

オプション意味初期値
n返す色数。既定はパレット全体NULL

nを指定しない場合はパッケージ標準の8色を返します。色覚多様性に配慮した配色になっています。

# 標準の8色を取得
phontrast_palette()
      blue vermillion      green     orange     purple    skyblue     yellow
 "#0072B2"  "#D55E00"  "#009E73"  "#E69F00"  "#CC79A7"  "#56B4E9"  "#F0E442"
      grey
 "#999999"

# 先頭の2色のみを取得
phontrast_palette(2)
      blue vermillion
 "#0072B2"  "#D55E00"

phontrastの配色をggplot2に適用する色スケール:scale_colour_phontrastコマンド

オプション意味初期値
ggplot2::discrete_scale()に渡す引数(name、labels、guideなど)なし

ggplot2のプロットにphontrastパッケージの配色とテーマをまとめて適用します。scale_colour_phontrastコマンドは離散スケール用で、scale_color_phontrastコマンドは同じ関数の別名です。

# ggplot2が利用可能であればphontrastの配色とテーマを適用
if (requireNamespace("ggplot2", quietly = TRUE)) {
  # 地区ごとに色分け
  ggplot2::ggplot(boin, ggplot2::aes(f2, f1, color = chiku)) +
    ggplot2::geom_point() +
    scale_colour_phontrast() +
    theme_phontrast()
}


この記事が誰かの役に立ちますように。

スポンサーリンク
価格および配送状況は変更される場合があります。購入時は商品ページをご確認ください。
当サイトに表示されている商品情報はAmazonから提供されたものであり、更新または削除される場合があります。
karada-goodはAmazonアソシエイトとして、適格販売により収入を得ています。