箱ひげ図の読み方
箱ひげ図は分布全体を 5 つの数値に圧縮し、それをひとつのコンパクトな図形として描きます。読み方は 30 秒で覚えられるので、まずそこから始めましょう。それぞれの部分には正確な意味があります。
- 箱の中の太い線 は 中央値 です。データの半分がその下に、半分が上にあります。
- 箱そのもの は 四分位範囲 (IQR) を表します。第 1 四分位数(データの 25% がその下)から第 3 四分位数(75% がその下)までです。データの中央の半分が箱の中にあります。
- ひげ は箱から伸びる線です。それぞれ、箱の端から 1.5 × IQR 以内に収まる最も極端なデータ点まで届きます。つまり、データの全範囲ではなく「通常の範囲」を覆っています。
- ひげの外側にある個々の点 は、箱から 1.5 × IQR より離れた値です。外れ値の疑い があるものとして印が付けられ、数えられるように 1 つずつ描かれます。
箱が縦に長ければデータが散らばっていることを、箱の中で中央値の線が中心からずれていれば歪みがあることを、片方のひげの先に点が連なっていればその側の裾が厚いことを意味します。ヒストグラムは同じ分布をより詳しく示しますが、箱ひげ図の真骨頂は 10 個以上を横に並べられることであり、それがグループ比較に 最適な グラフである理由です。
1 変数の箱ひげ図
関数は boxplot() で、単一の数値ベクトルなら 1 回の呼び出しで済みます。
scores <- c(52, 55, 58, 60, 61, 63, 64, 66, 68, 70, 72, 95)
boxplot(scores,
main = "Test scores",
ylab = "Score")
これが描く絵は次のとおりです。59 から 69 までの箱、その中の 63.5 にある中央値の線、下は 52、上は 72 まで届くひげ、そして 95 にぽつんと浮かぶ 1 点 — 平均と標準偏差による要約なら静かに飲み込んでしまったであろう外れ値です。この「1 つの値だけが他と違う」という即座の気づきこそ、箱ひげ図の存在意義です。
(この章のどのページとも同じく、作図の呼び出しは静的なスニペットです。下の実行環境はテキスト出力しか表示しません。絵を見るにはローカルで実行してください。)
グループの比較: formula インターフェース
日常での本当の用途はグループごとに箱を 1 つ描くことで、そのために boxplot() は formula を受け取ります。y ~ group と書き、「グループで分けた y」と読みます。R 組み込みの ToothGrowth データセット — オレンジジュース (OJ) またはアスコルビン酸 (VC) でビタミン C を与えた 60 匹のモルモットの歯の長さ — が定番のデモです。
boxplot(len ~ supp,
data = ToothGrowth,
main = "Tooth growth by supplement",
xlab = "Supplement",
ylab = "Tooth length")
共通の縦軸上に 2 つの箱が現れます。OJ の箱は VC の箱よりはっきり高い位置にあり、中央値はおよそ 22 対 19 です。両方の箱が 1 つの軸を共有しているため、この比較は構造上ごまかしがありません。尺度の異なる 2 枚のグラフで一方のグループを実際より良く見せる余地がないのです。グループ化する列は因子(または文字列ベクトル)であるべきで、各水準が 1 つの箱になります。
formula は入れ子にもできます。boxplot(len ~ supp * dose, data = ToothGrowth) はサプリメントと用量の組み合わせごとに 1 つずつ、計 6 つの箱を描きます。箱の上でグループ差が本物らしく見えたとき、自然に次に来る問い — それはノイズ以上のものか? — に答えるのが t 検定です。
ラベル、色、横向きの箱ひげ図
装飾用の引数は base の作図の慣習に従います。names は箱にラベルを付け、col は箱を塗ります。ベクトルを渡せばグループごとに色を変えられます。
boxplot(len ~ supp,
data = ToothGrowth,
names = c("Orange juice", "Ascorbic acid"),
col = c("orange", "lightblue"),
main = "Tooth growth by supplement",
ylab = "Tooth length")
さらに 2 つのスイッチが役に立ちます。
horizontal = TRUEはグラフ全体を回転させ、箱を横軸に沿って並べます。グループ名が長いときは必ずこうしましょう。縦書きのラベルが衝突する場面でも、横書きなら読めます。notch = TRUEは各中央値の周りにくびれを刻みます。2 つのグループのくびれが重ならないなら、それらの中央値は異なっている可能性が高いといえます。ただし検定ではなく、視覚的なヒントとして扱ってください。
箱の背後にある数値
グラフが描くものはすべて、出力できる数値から来ています。quantile() は五数要約を返し、boxplot.stats() は外れ値も含めて、グラフが使うものを そのまま 返します。これはここで実行できます。
この 2 つは双子ではなく、いとこ同士である点に注意してください。quantile() は真の最小値と最大値を報告しますが、s$stats は ひげ — 1.5 × IQR の柵の内側にある最も極端な点 — で終わります。両者の差がまさに s$out であり、ここでは 95 の 1 つだけです。「その外れ値の点はどの行なのか?」と聞かれたときは、x[x %in% boxplot.stats(x)$out] — あるいは柵の値でのフィルタ — が答えになります。
ggplot2 での箱ひげ図
ggplot2 では、グループ化は formula ではなく審美的マッピングに入ります。
library(ggplot2)
ggplot(ToothGrowth, aes(x = supp, y = len, fill = supp)) +
geom_boxplot() +
labs(title = "Tooth growth by supplement",
x = "Supplement", y = "Tooth length")
同じ 2 つの箱に、凡例とテーマがおまけで付いてきます。ggplot2 版はグラフが育つほど有利になります。dose でファセットに分け、geom_jitter(width = 0.1) で生データの点を重ねても、コードは宣言的なままです。分析中の一度きりの比較なら、boxplot(y ~ g, data = df) が最も速く打てるものであり続けます。
この章のまとめ
- 箱の解剖学: 中央値の線、箱 = IQR、ひげ = 1.5 × IQR 以内の最も極端な点、その外の点 = 外れ値の疑い。
- 1 変数なら
boxplot(x)、共通の公正な尺度上でグループを横に並べて比較するならboxplot(y ~ group, data = df)。 names、グループごとのcolベクトル、そしてラベルが長いときのhorizontal = TRUEで装飾しましょう。boxplot.stats(x)$statsと$outは数値としてのグラフです。グラフが指し示す外れ値を取り出すのに使えます。- ggplot2 では、グループを
xまたはfillにマッピングしたgeom_boxplot()を使います。
次は散布図 — 1 変数の分布から、2 変数の関係へと進みます。
よくある質問
R で箱ひげ図を作るにはどうしますか?
箱を 1 つだけ描くなら数値ベクトルに対して boxplot(x) を呼びます。グループごとに箱を横に並べるなら formula インターフェース boxplot(y ~ group, data = df) を使います。どちらも base R に同梱されており、パッケージは不要です。
箱ひげ図の各部分は何を意味しますか?
箱の中の太い線は中央値です。箱は第 1 四分位数から第 3 四分位数までの四分位範囲を表します。ひげは、箱から IQR の 1.5 倍以内にある最も極端なデータ点まで伸びます。ひげの外側にあるものは個々の点として描かれ、外れ値の疑いがあることを示します。
R でグループ別の箱ひげ図を作るにはどうしますか?
formula を使います。boxplot(len ~ supp, data = ToothGrowth) は supp の水準ごとに箱を 1 つ描きます。グループ化変数は因子または文字列の列であるべきで、各水準が共通の尺度上の 1 つの箱になります。
箱ひげ図が示す外れ値を求めるにはどうしますか?
boxplot.stats(x)$out は、グラフがひげの外の点として描くまさにその値を返します。また boxplot.stats(x)$stats は箱の背後にある 5 つの数値(ひげの端、ヒンジ、中央値)を返します。