棒グラフはカテゴリを比較する
棒グラフは「それぞれどれくらいか?」に答えます。カテゴリごとに棒 1 本、棒の長さがそのカテゴリの値を表します。R の base の関数は barplot() で、入力は単に高さのベクトルです。ベクトルに名前を付ければ、その名前が棒の下のラベルになります。
visits <- c(Mon = 42, Tue = 51, Wed = 47, Thu = 60, Fri = 78)
barplot(visits,
main = "Store visits by day",
ylab = "Visits")
曜日でラベル付けされた灰色の棒が 5 本、控えめな月曜からほぼ 2 倍の高さの金曜のピークへと上がっていきます。インストールも設定も不要です。名前付きのベクトルを作れるなら、それをグラフにできます。
このページの実行可能なエディタはテキスト出力しか表示しないので、ここでの barplot() の呼び出しはローカルの R セッションに貼り付けるための静的なスニペットです。ただしその前の数え上げの手順は問題なく実行でき、そちらこそ最も重要な手順です。
実際のワークフロー: まず table()、次に barplot()
実務では、きれいに集計済みの高さが手元にあることはめったにありません。あるのはカテゴリラベルの生の列 — アンケート回答ごと、注文ごと、ユーザーごとに 1 行 — であり、数え上げこそが実際の作業です。table() はそれを 1 回の呼び出しで行い、その出力は度数の名前付きベクトル、つまり barplot() が求めるもの そのもの です。
そのあと、グラフはもう 1 行です。
barplot(sort(t, decreasing = TRUE),
main = "Survey responses",
ylab = "Count")
この 2 段階 — table() してから barplot() — が R で最もよく使われる棒グラフの流れです。先に table を並べ替えるのは安上がりな改善です。高さ順に並んだ棒はアルファベット順の棒より速く読めます。ただしカテゴリに自然な順序がある場合(曜日、月、用量の水準)は別で、その場合は水準を適切に順序付けた因子にしておけば table() にアルファベット順にされずに済みます。行数の数え上げではなく本当の集約(グループごとの合計や平均)が必要な棒には、先にグループ化と集約を行い、その結果を barplot() に渡します。
ラベルと装飾
ラベルは通常ベクトルの名前から取られますが、names.arg がそれを上書きします。データのコードが読み手向きでないときに便利です。
barplot(visits,
names.arg = c("Monday", "Tuesday", "Wednesday",
"Thursday", "Friday"),
col = "steelblue",
border = NA,
main = "Store visits by day",
las = 2)
colは棒を塗ります。ベクトルを渡せば棒ごとに色を変えられますが、既定で虹色にするのは避けましょう。色は、話題にしている 1 本の棒を目立たせるなど、何かを意味すべきです。border = NAは棒の輪郭を消し、すっきりした見た目にします。las = 2は軸ラベルを軸に垂直に回転させます。長いカテゴリ名同士が重なるときの解決策です。名前が本当に長い場合は、下側の余白を広げる設定(par(mar = c(8, 4, 4, 2)))と組み合わせましょう。
行列から作るグループ化棒と積み上げ棒
2 つのカテゴリの次元を同時に示すには — たとえば四半期ごと、チャネルごとの売上 — barplot() に行列を渡します。各 列 がカテゴリ軸上の 1 つの位置になり、行が下位の棒になります。
sales <- matrix(c(12, 18, 15, 22, 20, 19, 24, 27),
nrow = 2,
dimnames = list(c("Online", "Retail"),
c("Q1", "Q2", "Q3", "Q4")))
# Grouped: rows stand next to each other within each quarter
barplot(sales, beside = TRUE,
col = c("steelblue", "orange"),
legend.text = rownames(sales),
main = "Sales by channel and quarter")
# Stacked: rows pile up into one total bar per quarter (the default)
barplot(sales, beside = FALSE,
col = c("steelblue", "orange"),
legend.text = rownames(sales))
beside = TRUE は各四半期の中で 2 つのチャネルを肩を並べて配置します。チャネル同士を直接比較したいときに最適です。既定の積み上げは四半期ごとの 合計 を強調し、その内訳を各棒の中に示します。合計については誠実ですが、内側のセグメントは基線がずれるため棒をまたいだ比較が難しくなります。legend.text = rownames(sales) はどちらの版も読めるようにする凡例を追加します。
もうひとつのスイッチ: horiz = TRUE は棒を横軸に沿って寝かせます。名前の長いカテゴリが多数あるときに最も親切なレイアウトです。すべてのラベルが自分の棒の隣に 1 行ずつ収まり、回転は不要になります。
棒グラフか、ヒストグラムか?
検索する人はこの 2 つを絶えず混同しますが、区別は 30 秒かける価値があります。棒グラフ は 別々のカテゴリ を比較します。軸はラベルの集合で、棒は離れており、並べ替えても構いません。ヒストグラム は 1 つの数値変数 をビン分割します。軸は連続尺度で、ビンが連続する区間なので棒は接し、並べ替えは無意味です。列に単語("Yes"、"Chrome"、"Q3")が入っているなら barplot(table(x)) を、測定値(身長、価格、応答時間)が入っているならヒストグラムと hist(x) を使います。
ggplot2: geom_col と geom_bar
ggplot2 版は、数え上げが済んでいるかどうかで 2 つの geom に分かれます。
library(ggplot2)
# geom_bar(): raw observations in, counting done for you
ggplot(survey, aes(x = response)) +
geom_bar(fill = "steelblue")
# geom_col(): heights already computed, one row per bar
totals <- data.frame(day = c("Mon", "Tue", "Wed", "Thu", "Fri"),
visits = c(42, 51, 47, 60, 78))
ggplot(totals, aes(x = day, y = visits)) +
geom_col(fill = "steelblue")
geom_bar() はグラフに table() を組み込んだものです。観測値ごとに 1 行を受け取り、集計します。geom_col() は集計済みのデータを受け取り、y の列を棒の高さにマッピングします。従来の barplot() に相当します。集計済みのデータを geom_bar() に渡すのが定番の初心者向けの落とし穴です。行 を(それぞれ 1 つずつ)数えるので、すべての棒が同じ高さになってしまいます。
この章のまとめ
barplot(heights)は名前付きベクトルをグラフにします。そしてtable(x)は生のカテゴリデータからまさにその形を作るので、barplot(table(x))が中核のイディオムです。- 描く前に table を並べ替える(または因子の水準を設定する)こと。棒の順序はメッセージの一部です。
- 行列を渡すとグループ化 (
beside = TRUE) または積み上げ(既定)の棒になります。legend.text = rownames(m)を追加しましょう。 names.arg、col、las = 2、horiz = TRUEがラベル付けを担います。名前が長いときは横向きの棒が最適です。- カテゴリ → 棒グラフ、数値のビン → ヒストグラム。ggplot2 では、生の行 →
geom_bar()、計算済みの高さ →geom_col()。
次は ggplot2 そのもの — これらすべてのグラフと、さらに多くのものを、同じ少数の組み合わせ可能な部品から組み立てる文法です。
よくある質問
R で棒グラフを作るにはどうしますか?
高さのベクトルに対して barplot() を呼びます。ベクトルに名前を付けるか、出力がすでに名前付きである table() で作れば、各要素がラベル付きの棒 1 本になります: barplot(table(df$category))。
R でグループ化棒グラフや積み上げ棒グラフを作るにはどうしますか?
行列を渡します。各列がカテゴリ軸上の 1 つの位置になります。beside = TRUE は行を隣り合う棒として描き(グループ化)、既定の beside = FALSE は積み上げます。読み手が行を区別できるよう legend.text = rownames(m) を追加しましょう。
R の barplot() と hist() の違いは何ですか?
barplot() は別々のカテゴリを比較します。カテゴリごとに棒 1 本で、棒は離れています。hist() は 1 つの数値変数を連続する区間にビン分割します。軸が連続尺度なので棒は接します。変数が単語なら barplot(table(x))、数値なら hist(x) です。
ggplot2 では geom_bar と geom_col のどちらを使うべきですか?
geom_bar() は数え上げまで行います。生の観測値を渡すと各カテゴリを集計します。geom_col() はすでに計算済みの値をプロットします。棒 1 本につき 1 行と高さの列を渡します。集計済みのデータを geom_bar() に渡すのが典型的な間違いで、その場合は geom_col() が必要です。