HOWTO · R
R でグループ化された箱ひげ図を作成する
この記事では、R でグループ化された箱ひげ図を作成する方法を紹介します
このページの内容
ggplot2 でグループ化箱ひげ図を作成するうえで重要なのは、比較したいグループにデータを分ける変数をどれにするかという一点です。その変数を fill エステティックにマップすれば、geom_boxplot() が各 x 位置の中に箱を横並びで描きます。あるいは facet_wrap() でデータを個別のパネルに分割してもかまいません。以下の例では gapminder データセットと dplyr パッケージを使います。どちらの方法でも、自分の列に合わせて調整できるグループ化箱ひげ図を作成できます。
geom_boxplot() でグループ化された箱ひげ図を作成する
箱ひげ図オブジェクトは、一般に ggplot 関数と geom_boxplot を組み合わせて作成します。ggplot の第 1 引数はデータセット、第 2 引数は aes で作成するエステティックマッピングのリストです。以下のマッピングでは、x と y が gapminder の continent 列と lifeExp 列を指しており、データは dplyr の関数で選択した 3 つの年に絞り込んでいます。なお、コード例と、コード内で表示される軸ラベルなどの文字列は英語のままです。
if (requireNamespace("ggplot2", quietly = TRUE) &&
requireNamespace("gapminder", quietly = TRUE) &&
requireNamespace("dplyr", quietly = TRUE)) {
library(ggplot2)
library(gapminder)
library(dplyr)
dat <- gapminder %>%
filter(year %in% c(1972, 1992, 2007))
print(ggplot(dat, aes(x = continent, y = lifeExp)) +
geom_boxplot() +
scale_y_continuous(name = "Average Life Expectancy") +
scale_x_discrete(labels = abbreviate, name = "Continent"))
}
この呼び出しは大陸ごとに 1 つの箱を描きます。すでに x 変数でグループ化されていますが、各大陸の中の年はまだ 1 つにまとめられたままです。次のステップは、2 つ目のグループ化変数を追加することです。requireNamespace によるガードのおかげで、描画パッケージがインストールされていない環境でもスクリプトは正常に終了します。その場合は描画がスキップされるため、このコードは構文の例として扱い、記事の後半に掲載したレンダリング済みの図を参照してください。
fill エステティックへのマッピングで箱をグループ化する
列を fill にマップすると、geom_boxplot は各 x 位置の中でグループごとに別々の箱を描きます。ただし 1 つ注意点があります。fill が明確なグループを作るのは、マップした変数が離散型の場合だけです。gapminder の year 列は数値型なので、fill = year は連続的なカラーグラデーションとして扱われ、プロットは年ごとの箱に分割されません。factor で包むと、数値がカテゴリー型の水準に変換され、意図した横並びの箱が得られます。この違いは R 単体のコード例で確認できます。なお、コード例と出力に表示される値や文字列は英語のままです。
year <- c(1972, 1992, 2007)
print(class(year))
print(class(factor(year)))
print(levels(factor(year)))
[1] "numeric"
[1] "factor"
[1] "1972" "1992" "2007"
数値の year は連続値のままですが、factor(year) は名前付きの水準を持ちます。そして、fill が別々の箱に展開するのは後者の形式だけです。ggplot2 でも同じ区別がレイアウトを決めます。
if (requireNamespace("ggplot2", quietly = TRUE) &&
requireNamespace("gridExtra", quietly = TRUE) &&
requireNamespace("gapminder", quietly = TRUE) &&
requireNamespace("dplyr", quietly = TRUE)) {
library(ggplot2)
library(gridExtra)
library(gapminder)
library(dplyr)
dat <- gapminder %>%
filter(year %in% c(1972, 1992, 2007))
p1 <- ggplot(dat, aes(x = continent, y = lifeExp, fill = year)) +
geom_boxplot() +
scale_y_continuous(name = "Average Life Expectancy") +
scale_x_discrete(labels = abbreviate, name = "Continent")
p2 <- ggplot(dat, aes(x = continent, y = lifeExp, fill = factor(year))) +
geom_boxplot() +
scale_y_continuous(name = "Average Life Expectancy") +
scale_x_discrete(labels = abbreviate, name = "Continent")
grid.arrange(p1, p2, nrow = 2)
}
上のパネルは year を数値のままにしているためグループ化されません。一方、下のパネルは factor(year) を使い、選択した各年につき 1 つずつ、大陸ごとに 3 つの箱を表示しています。
facet_wrap() でグループをパネルに分割する
facet_wrap 関数は、選択した変数でグループ化された箱ひげ図を描くもう 1 つの方法です。ここでは年ごとに 1 つのパネルを作成します。facet_wrap は fill マッピングがなくても動作しますが、fill = factor(year) を残して箱に色を付けると、パネルどうしを見分けやすくなります。なお、コード例と、コード内で表示される軸ラベルなどの文字列は英語のままです。
if (requireNamespace("ggplot2", quietly = TRUE) &&
requireNamespace("gapminder", quietly = TRUE) &&
requireNamespace("dplyr", quietly = TRUE)) {
library(ggplot2)
library(gapminder)
library(dplyr)
dat <- gapminder %>%
filter(year %in% c(1972, 1992, 2007))
p3 <- ggplot(dat, aes(x = continent, y = lifeExp, fill = factor(year))) +
geom_boxplot() +
facet_wrap(~year) +
scale_y_continuous(name = "Average Life Expectancy") +
scale_x_discrete(labels = abbreviate, name = "Continent")
print(p3)
}
デフォルトでは、facet_wrap が生成するすべてのパネルで同じスケールが共有されるため、パネル間で値を直接比較できます。scales = "free" を渡すと、各パネルが含まれるデータに合わせて軸を個別に調整します。範囲の狭いパネルでも細部を見やすくできる一方、同じ高さが同じ値を意味しなくなるため、パネル間の比較が誤解を招く可能性があります。
if (requireNamespace("ggplot2", quietly = TRUE) &&
requireNamespace("gapminder", quietly = TRUE) &&
requireNamespace("dplyr", quietly = TRUE)) {
library(ggplot2)
library(gapminder)
library(dplyr)
dat <- gapminder %>%
filter(year %in% c(1972, 1992, 2007))
p4 <- ggplot(dat, aes(x = continent, y = lifeExp, fill = factor(year))) +
geom_boxplot() +
facet_wrap(~year, scales = "free") +
scale_y_continuous(name = "Average Life Expectancy") +
scale_x_discrete(labels = abbreviate, name = "Continent")
print(p4)
}
レイアウトを選んで結果を確認する
グループの数が少なく、各 x カテゴリーの中で直接比較したい場合は fill によるグループ化を使います。グループが多い場合や、各サブセットに独立したパネルを割り当てたい場合は facet_wrap を使います。どの変数を fill にマップし、どの変数でファセットするかを入れ替えることもできます。以下の例ではフィルタリングしていない gapminder データセットに戻り、continent を fill にマップし、facet_wrap には利用可能なすべての年を渡します。なお、コード例と、コード内で表示される軸ラベルなどの文字列は英語のままです。
if (requireNamespace("ggplot2", quietly = TRUE) &&
requireNamespace("gapminder", quietly = TRUE)) {
library(ggplot2)
library(gapminder)
p5 <- ggplot(gapminder, aes(x = continent, y = lifeExp, fill = continent)) +
facet_wrap(~year) +
geom_boxplot() +
scale_y_continuous(name = "Average Life Expectancy") +
scale_x_discrete(labels = abbreviate, name = "Continent")
print(p5)
}
どのレイアウトを選んでも、レンダリングされたプロットで、グループごとの箱やパネルの数が想定どおりかを確認してください。数値列が個別の箱ではなく連続的なカラー凡例を生成した場合は、まず factor で変換します。また、パネルの形は同じでも位置が異なる場合は、グラフから値を読み取る前にスケールが共有されていることを確認してください。