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

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

Rで解析:箱ひげ図に有意差バーを付ける「ggsignif」パッケージ

「ggplot2」パッケージで作ったプロットに、群と群をつなぐ有意差バーを重ねられるパッケージです。比べたい2群の名前をlistで渡すと、検定を実行して、結果を表す記号までプロットに載せます。バーの位置と載せる文字を自分で決めることもできます。「ggsignif」パッケージは「ggplot2」パッケージの上で動くため、あわせて読み込んでおく必要があります。箱ひげ図や棒グラフに検定結果を添えたいときに、扱いやすいのではないかと考えます。

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

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

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

# パッケージのインストール
install.packages("ggsignif")
スポンサーリンク

コマンド例

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

略語=日本語の意味:
・aes:Aesthetic mappingの略で、データの列をプロットの見た目へ対応づける仕組み
・Brix:果汁や搾汁に溶けている糖の量を表す単位
・p値:検定で得られる確率で、小さいほど群の間の差が偶然では説明しにくい

有意差バーは、2つの群をつなぐ横棒と、その上に載せる記号の組み合わせです。アスタリスクの数はp値の小ささを表し、「***」が0.001未満、「**」が0.01未満、「*」が0.05未満という割り当てがよく使われます。

まず、例で共通して使うデータとプロットを作ります。京都市内で収穫した九条ねぎの糖度を、露地・トンネル・ハウスの3つの栽培方法ごとに30点ずつ集めた想定の架空データです。

# パッケージの読み込み
library("ggplot2")
library("ggsignif")

# 乱数を固定
set.seed(1204)

# 京都市内で収穫した九条ねぎの糖度を、栽培方法ごとにまとめたデータ
TestData <- data.frame(
  Field = rep(c("露地", "トンネル", "ハウス"), each = 30),
  Brix = c(
    round(rnorm(30, mean = 8.4, sd = 1.1), 1),
    round(rnorm(30, mean = 9.6, sd = 1.0), 1),
    round(rnorm(30, mean = 10.8, sd = 1.2), 1)
  )
)

# 栽培方法の並び順を固定
TestData$Field <- factor(TestData$Field, levels = c("露地", "トンネル", "ハウス"))

# 先頭3行を確認
head(TestData, 3)
  Field Brix
1  露地  8.3
2  露地  8.6
3  露地  9.0

# 有意差バーを重ねるもとになる箱ひげ図を作る
# バーが切れないように、上側の余白を広げる
BoxPlot <- ggplot(TestData, aes(x = Field, y = Brix)) +
  geom_boxplot(fill = "#a8d5a2") +
  labs(x = "栽培方法", y = "糖度(Brix)") +
  scale_y_continuous(expand = expansion(mult = c(0.05, 0.15)))

検定結果を有意差バーで重ねる:geom_signifコマンド

comparisonsオプションに比べたい2群の名前を渡すと、testオプションで指定した検定を実行し、結果をバーとしてプロットに重ねます。

オプション意味初期値
mappingaes()で作る見た目の対応づけ。inherit.aes = TRUEなら、プロット側の対応づけと合わせて使われるNULL
dataこの層で使うデータ。NULLならggplot()に渡したデータを引き継ぐNULL
statこの層で使う統計処理の名前“signif”
position位置の調整方法“identity”
na.rmFALSEなら欠損値を警告付きで取り除く。TRUEなら警告を出さずに取り除くFALSE
show.legendこの層を凡例に入れるか。NAなら見た目の対応づけがあるときだけ入れるNA
inherit.aesFALSEならプロット側の対応づけを引き継がず、この層の指定だけを使うTRUE
comparisons比べる2群を並べたベクトルのlist。群の名前か、x軸での位置を表す整数で指定するNULL
test2群に当てる検定の名前。t.test、wilcox.testなどを文字列で渡す“wilcox.test”
test.args検定に追加で渡すオプションNULL
annotationsバーに載せる文字。指定するとtestオプションは使われないNULL
map_signif_levelp値をそのまま載せるか、アスタリスクに置き換えるか。c(“***” = 0.001, “**” = 0.01, “*” = 0.05)の形で割り当てを決めることもできるFALSE
y_positionバーを置く高さNULL
xminバーの左端の位置NULL
xmaxバーの右端の位置NULL
margin_topデータの最大値からどれだけ上にバーを置くか。プロットの高さに対する割合で指定する0.05
step_increase比較を増やすときに、バーを何割ずつ上へずらすか0
extend_lineバーの横線を縮める(負の値)か伸ばす(正の値)か0
tip_lengthバー両端の縦線の長さ。プロットの高さに対する割合で指定する0.03
sizeバーの線の太さ0.5
textsize文字の大きさ3.88
family文字に使うフォント“”
vjustバーに対して文字を上下に動かす量0
parseTRUEなら文字を数式として解釈して表示するFALSE
manualバーの位置をdata.frameで渡すときにTRUEにする。facetごとに違う文字を載せるときに使うFALSE
orientation層の向き。NAなら見た目の対応づけから自動で決まる。決まらないときは”x”か”y”を指定するNA
…layerに渡すその他のオプション。colour = “red”のように見た目を固定する指定もここに書くなし

露地とハウスの2群だけを比べます。map_signif_levelをTRUEにすると、p値の代わりにアスタリスクが載ります。

# 2群を比べて有意差バーを重ねる:geom_signifコマンド
BoxPlot +
  geom_signif(
    # 比べる2群の組み合わせを指定:comparisonsオプション
    comparisons = list(c("露地", "ハウス")),
    # 当てる検定を指定:testオプション
    test = "t.test",
    # 結果をアスタリスクに置き換える:map_signif_levelオプション
    map_signif_level = TRUE,
    # バーの線の太さと文字の大きさ:size,textsizeオプション
    size = 0.8,
    textsize = 5,
    colour = "red"
  )

2群を比べて有意差バーを重ねる:geom_signifコマンド

comparisonsのlistを増やすと、複数の組み合わせをまとめて重ねられます。そのままではバーが同じ高さで重なるため、step_increaseオプションで段違いにずらします。

# 3つの組み合わせをまとめて重ねる:geom_signifコマンド
BoxPlot +
  geom_signif(
    comparisons = list(c("露地", "トンネル"), c("トンネル", "ハウス"), c("露地", "ハウス")),
    # 当てる検定を指定:testオプション
    test = "wilcox.test",
    # アスタリスクの割り当てを自分で決める:map_signif_levelオプション
    map_signif_level = c("***" = 0.001, "**" = 0.01, "*" = 0.05),
    # バーを段違いにずらす:step_increaseオプション
    step_increase = 0.12,
    # バー両端の縦線を短くする:tip_lengthオプション
    tip_length = 0.01,
    size = 0.8,
    textsize = 5,
    colour = "red"
  )

3つの組み合わせをまとめて重ねる:geom_signifコマンド

位置と文字を自分で決める:stat_signifコマンド

検定を実行せず、自分で用意した文字をバーに載せるときに使います。annotationsオプションに文字を渡し、xmin・xmax・y_positionオプションでバーを置く位置を決めます。

オプション意味初期値
mappingaes()で作る見た目の対応づけ。inherit.aes = TRUEなら、プロット側の対応づけと合わせて使われるNULL
dataこの層で使うデータ。NULLならggplot()に渡したデータを引き継ぐNULL
position位置の調整方法“identity”
na.rmFALSEなら欠損値を警告付きで取り除く。TRUEなら警告を出さずに取り除くFALSE
show.legendこの層を凡例に入れるか。NAなら見た目の対応づけがあるときだけ入れるNA
inherit.aesFALSEならプロット側の対応づけを引き継がず、この層の指定だけを使うTRUE
comparisons比べる2群を並べたベクトルのlist。群の名前か、x軸での位置を表す整数で指定するNULL
test2群に当てる検定の名前。t.test、wilcox.testなどを文字列で渡す“wilcox.test”
test.args検定に追加で渡すオプションNULL
annotationsバーに載せる文字。指定するとtestオプションは使われないNULL
map_signif_levelp値をそのまま載せるか、アスタリスクに置き換えるか。c(“***” = 0.001, “**” = 0.01, “*” = 0.05)の形で割り当てを決めることもできるFALSE
y_positionバーを置く高さNULL
xminバーの左端の位置NULL
xmaxバーの右端の位置NULL
margin_topデータの最大値からどれだけ上にバーを置くか。プロットの高さに対する割合で指定する0.05
step_increase比較を増やすときに、バーを何割ずつ上へずらすか0
tip_lengthバー両端の縦線の長さ。プロットの高さに対する割合で指定する0.03
sizeバーの線の太さ0.5
textsize文字の大きさ3.88
family文字に使うフォント“”
vjustバーに対して文字を上下に動かす量0
parseTRUEなら文字を数式として解釈して表示するFALSE
manualバーの位置をdata.frameで渡すときにTRUEにする。facetごとに違う文字を載せるときに使うFALSE
orientation層の向き。NAなら見た目の対応づけから自動で決まる。決まらないときは”x”か”y”を指定するNA
…layerに渡すその他のオプション。colour = “red”のように見た目を固定する指定もここに書くなし

露地を基準にした糖度の差を計算し、その値をそのままバーに載せます。

# 露地を基準にした糖度の差を求める
MeanBrix <- tapply(TestData$Brix, TestData$Field, mean)
DiffText <- paste0("+", round(MeanBrix[-1] - MeanBrix[1], 2), " Brix")

# 求めた文字を確認
DiffText
[1] "+0.91 Brix" "+1.83 Brix"

# 検定を使わず、自分で決めた文字をバーに載せる:stat_signifコマンド
BoxPlot +
  stat_signif(
    # バーに載せる文字:annotationsオプション
    annotations = DiffText,
    # バーの左端と右端の位置:xmin,xmaxオプション
    xmin = c(1, 1),
    xmax = c(2, 3),
    # バーを置く高さ:y_positionオプション
    y_position = c(13.4, 14.6),
    size = 0.8,
    textsize = 4.5,
    colour = "red"
  )

検定を使わず、自分で決めた文字をバーに載せる:stat_signifコマンド


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

スポンサーリンク

コメント(1)

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