geom_histogramのビン幅を動的に決定する

カテゴリ: r

TL; DR

geom_histogram(binwidth = ) はデータを受け取ってビン幅を返す関数を受け付けるよ。

ggplot2のヒストグラムはビン数30が既定

なぜ……。調整するには bins でビン数を変えるか、 binwidth でビン幅を変える。両方指定すると binwidth が優先される。

library(ggplot2)
ggplot(diamonds, aes(price)) + geom_histogram()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

参考: https://stats.biopapyrus.jp/r/ggplot/geom_histogram.html

ビン幅を動的に決めたい

という話は随分前にQiitaでもした。事前に頻度分布を集計した結果をデータフレームとして ggplot() に与えるというもの。

https://qiita.com/Atsushi776/items/f71a6f011118031f6e0a

facet した変数ごとにbin幅を変える方法の決定版は今でもこれだと思う。

facet した変数ごとにbin幅を変える必要がなければ、@hoxo_m氏から頂いたコメントも有用。こちらでは、stat_bin(breaks = ) を利用する。ただし、同じデータに二度参照せねばならず、もう一歩といった感がある。

ggplot(diamonds, aes(x = price)) + 
  stat_bin(breaks = hist(diamonds$price, plot = FALSE)$breaks)

geom_histogram(binwidth = ) に関数を指定

じゃあどうするのという話なのだが、geom_histogram(binwidth = ) は関数を受け付けることを利用するといい。

x軸に指定した値を元にビン幅を返す関数を好きに定義しよう。

以下は平方根選択した例。

library(ggplot2)
ggplot(diamonds, aes(price)) + 
  geom_histogram(binwidth = function(x) ceiling((max(x) - min(x)) / sqrt(length(x))))

ビン幅を決める関数を定義

世の中には平方根選択以外にも色々なビン幅の決め方があります。個人的な推しはScottの選択ですね。

実装にはWikipediaのヒストグラム#ビンの個数と幅あたりを参考にしてもいいですが、 Scottの選択などによるビン数を求める関数であれば、 grDevicesパッケージに定義されています。

hist() のビン数も、grDevicesパッケージを利用して決めているので、 geom_histogram() でも利用しない手はないでしょう。

  • Sturgesの選択: nclass.Sturges()
  • Scottの選択: nclass.scott()
  • Freedman-Diaconisの選択: nclass.FD()

以下のように、ビン数をビン幅に直す関数を定義しておきます。

library(grDevices)
bw = function(x, f) ceiling((max(x) - min(x)) / f(x))
FD = function(x) bw(x, nclass.FD)
scott = function(x) bw(x, nclass.scott)
sturges = function(x) bw(x, nclass.Sturges)

テスト

library(ggplot2)
g <- ggplot(diamonds, aes(price)) + 
  coord_cartesian(xlim=c(0, 2e4), ylim = c(0, 2e4))
g_FD <- g + geom_histogram(binwidth = FD) + ggtitle('FD')
g_Sc <- g + geom_histogram(binwidth = scott) + ggtitle('Scott')
g_St <- g + geom_histogram(binwidth = sturges) + ggtitle('Sturges')

Enjoy!