ヒストグラムが示すもの
ヒストグラムは、1 つの数値変数についてひとつの問いに答えます。値はどのように分布しているか? データの範囲を連続する区間(ビン)に切り分け、それぞれに何個の観測値が入るかを数え、その度数を高さとするバーをビンごとに描きます。データが密なところではバーが高く、まばらなところでは低くなります。
この 1 枚の絵は、平均と標準偏差では分からないことを教えてくれます。ピークが 1 つなのか 2 つなのか、左右対称なのか片方の裾に歪んでいるのか、他から大きく離れた外れ値があるのか。新しいデータセットに出会ったとき、記述統計の数値と並んで、たいてい真っ先に描くグラフです。
R での関数は hist() で、1 行で済みます。
hist() で最初のヒストグラムを描く
200 人の身長をシミュレートしてみましょう。平均 170 cm、標準偏差 10 の正規分布に従います(set.seed() と rnorm() の働きについては乱数を参照してください)。
set.seed(42)
heights <- rnorm(200, mean = 170, sd = 10)
hist(heights)
R は自らビンを選び、釣鐘型に積み上がったバーを描きます。145 cm 付近では低く、160 台にかけて上昇し、170 前後でピークに達し、190 を過ぎると対称的に下がっていきます。縦軸には "Frequency"(生の度数)とラベルが付き、タイトルと軸ラベルは変数名から取られます。
既定の見た目は意図的に素朴です。おなじみの装飾用引数はここでもすべて使えます。
hist(heights,
main = "Distribution of heights",
xlab = "Height (cm)",
col = "steelblue",
border = "white")
col はバーを塗り、border は輪郭を着色します。border = "white" にすると、多くの出版物で見かける、バーがすっきり分離した見た目になります。plot() のガイドで述べた色とタイトルの話は、そのままここにも当てはまります。
ビン幅: breaks 引数
hist() で最も重要な引数は breaks です。ビン幅がグラフの語る物語を決めるからです。同じデータで 2 つの設定を比べてみましょう。
hist(heights, breaks = 5) # five wide bins: a crude, blocky bell
hist(heights, breaks = 30) # thirty narrow bins: detail, plus noise
breaks = 5 ではヒストグラムが粗すぎて、すべてが滑らかなひとつの山に見えます。第 2 のクラスタやデータの隙間があっても見えません。breaks = 30 では細かい構造が見えますが、ランダムな揺らぎが特徴のふりをし始めます。どちらが「正解」ということはありません。誠実なやり方は、いくつかの設定を試し、どの特徴が生き残るかを見ることです。
breaks は 3 つの形式を受け取ります。
- 数値 —
breaks = 30— ビン数の 提案 です。R はきりの良い境界に落ちるよう調整するので、28 や 33 のビンになることがあります。これには誰もが一度は驚きます。 - 区切り点のベクトル —
breaks = seq(140, 200, by = 5)— 交渉の余地のない、正確なビンの境界です。比較する複数のヒストグラムでビンを揃える必要があるときに使います。 - 規則の名前 — Freedman–Diaconis なら
breaks = "FD"。データの散らばりと標本サイズから幅を選び、歪んだデータでも良好に振る舞います。
密度ヒストグラムと正規曲線
既定ではバーの高さは度数です(freq = TRUE)。freq = FALSE にすると、バーの合計 面積 が 1 になるようスケールし直されます。密度スケールです。形は変わりませんが、縦軸が変わります。これを行う意義は、密度ヒストグラムが確率密度関数と同じ尺度の上に載るため、理論的な曲線をデータの上に直接重ねられることにあります。
hist(heights,
freq = FALSE,
col = "gray90",
main = "Heights vs. a normal curve",
xlab = "Height (cm)")
curve(dnorm(x, mean = mean(heights), sd = sd(heights)),
add = TRUE, col = "tomato", lwd = 2)
add = TRUE を付けた curve() は、既存のヒストグラムの上に釣鐘曲線を描きます(dnorm(x, ...) の中の x は curve() が埋めるプレースホルダであり、あなたの変数ではありません)。バーが曲線に沿っていれば正規モデルは妥当です。曲線から膨らんでいるところ — 厚い裾、第 2 のピーク — があれば、モデルは何かを見落としています。freq = FALSE を省くと、度数と密度では尺度が違うため、曲線はグラフの底を這うだけで役に立ちません。
バーの背後にある数値
hist() は描くだけではなく、ビン分割をリストとして返します。plot = FALSE を付けると描画を完全に飛ばして計算だけを行うので、これはここでそのまま実行できます。
h$counts はデータとしてのヒストグラムです。それぞれの数値がバー 1 本の高さです。table(cut(...)) の行はテキストモードでの同等物で、cut() が値をビンに分け、table() が各ビンを数えます。グラフの前に、あるいはグラフの代わりに出力する健全性チェックとして十分使えます。plot = FALSE を付けずに代入すると(h <- hist(heights))、R は描画 も してリストを返します。代入したからといってグラフが抑制されるわけではありません。
ggplot2 でのヒストグラム
ggplot2 版は breaks の代わりに binwidth を使います。多くの場合こちらの方が自然なつまみです。いくつのビンが欲しいかではなく、1 つのビンがデータの単位で何幅かを指定します。
library(ggplot2)
ggplot(data.frame(heights), aes(x = heights)) +
geom_histogram(binwidth = 5, fill = "steelblue", color = "white") +
labs(title = "Distribution of heights", x = "Height (cm)", y = "Count")
binwidth = 5 は、どのバーも 5 cm 分を覆うという意味です。binwidth を指定しないと ggplot2 は警告を出し、こっそり 30 ビンを既定として使います。この警告には従いましょう。既定値があなたのデータにとって適切な幅であることはめったにありません。1 変数をざっと見るだけなら hist() の方が入力量が少なくて済みます。ggplot2 が価値を発揮するのは、ヒストグラムにファセットやグループ、あるいは他の図と一貫したテーマが必要なときです。
この章のまとめ
- ヒストグラムは 1 つの数値変数の分布を示します。
hist(x)だけで完了です。 - 重要なのは
breaks引数です。数値は提案にすぎず、ベクトルは正確な境界を指定し、"FD"は根拠のある幅を選びます。必ず複数の設定を試しましょう。 freq = FALSEは密度スケールに切り替えます。これによってcurve(dnorm(...), add = TRUE)による正規曲線の重ね描きが意味を持ちます。hist(x, plot = FALSE)はビンをデータとして返します($breaks、$counts、$mids)。table(cut(x, breaks))はテキストのみの同等物です。- ggplot2 では
geom_histogram(binwidth = ...)を使い、binwidthは自分で設定しましょう。
次は箱ひげ図 — グループを横に並べて比較するときに本領を発揮する分布のグラフです。
よくある質問
R でヒストグラムを作るにはどうしますか?
数値ベクトルに対して hist(x) を呼びます。R は x の範囲をビン(階級)に分割し、ビンごとに 1 本のバーを描きます。バーの高さは、そのビンに入る値の個数を表します。ビンの数を制御するには breaks =、バーに色を付けるには col = を追加します。
hist() の breaks 引数は何をしますか?
ビン分割を制御します。breaks = 30 のような単一の数値は使うビン数の「提案」であり(R はきりの良い境界に丸めます)、breaks = seq(140, 200, by = 5) のようなベクトルは正確な区切り点を指定し、breaks = "FD" は Freedman–Diaconis の規則を使います。
R でヒストグラムに正規曲線を重ねるにはどうしますか?
freq = FALSE で密度スケールのヒストグラムを描き、続いて curve(dnorm(x, mean = mean(data), sd = sd(data)), add = TRUE) で曲線を追加します。度数スケールのままだと曲線はゼロ付近に張り付いて役に立たないので、freq = FALSE が不可欠です。
ヒストグラムと棒グラフの違いは何ですか?
ヒストグラムは 1 つの数値変数をビンに分けるので、横軸は連続的な尺度になり、バーは隣接して接します。棒グラフは別々のカテゴリを比較するので、バーは離れています。R では、数値には hist()、カテゴリの度数には barplot() を使います。