ggplot2を使って、データ分布を要約する-4
R グラフィックス クックブック 18回目
ggplot2パッケージを利用して、データ分布を可視化していきます。
利用するデータ
2つのデータセットを使います。
1つ目:R: Old Faithful Geyser Data
間欠泉の噴出時間(eruptions)と次に噴出までの間隔(waiting)です。
> str(faithful) 'data.frame': 272 obs. of 2 variables: $ eruptions: num 3.6 1.8 3.33 2.28 4.53 ... $ waiting : num 79 54 74 62 85 55 88 85 51 85 ... > head(faithful) eruptions waiting 1 3.600 79 2 1.800 54 3 3.333 74 4 2.283 62 5 4.533 85 6 2.883 55
2つ目:
> str(heightweight) 'data.frame': 236 obs. of 5 variables: $ sex : Factor w/ 2 levels "f","m": 1 1 1 1 1 1 1 1 1 1 ... $ ageYear : num 11.9 12.9 12.8 13.4 15.9 ... $ ageMonth: int 143 155 153 161 191 171 185 142 160 140 ... $ heightIn: num 56.3 62.3 63.3 59 62.5 62.5 59 56.5 62 53.8 ... $ weightLb: num 85 105 108 92 112 ... > head(heightweight) sex ageYear ageMonth heightIn weightLb 1 f 11.92 143 56.3 85.0 2 f 12.92 155 62.3 105.0 3 f 12.75 153 63.3 108.0 4 f 13.42 161 59.0 92.0 5 f 15.92 191 62.5 112.5 6 f 14.25 171 62.5 112.0
ドットプロット
ドットプロット - Wikipedia
ヒストグラムと同じです。データをビン詰めして、ドットで積み上げています。
ドットプロットを作成するには、geom_dotplot()を使います。
ggplot(faithful, aes(x=eruptions)) + geom_dotplot()
他グラフと同様に、塗りつぶしはfill、線の色は、colourを指定します。
ggplot(faithful, aes(x=eruptions)) + geom_dotplot(fill="lightblue",colour="grey60") + theme_bw()
ビンの幅は、デフォルトでデータ範囲の1/30となっています。
ビンの幅を変更するには、binwidthを指定します。
#eruptionsの範囲を取って、差を30で割る binSize <- diff(range(faithful$eruptions)) / 30 #binwidth引数を指定する #データ範囲を30で割ったビン幅なので、デフォルトと同じ ggplot(faithful, aes(x=eruptions)) + geom_dotplot(binwidth = binSize, fill="lightblue",colour="grey60") + theme_bw()
このドットプロットですが、y軸の目盛りがおかしいです。
本によると、ggplot2の技術的な問題らしく、
y軸を表示させない回避策を取っています。(回避策なのか?)
おかしいスケールのy軸を消します。
ggplot(faithful, aes(x=eruptions)) + geom_dotplot(binwidth = binSize, fill="lightblue",colour="grey60") + theme_bw() + scale_y_continuous(breaks = NULL) + #目盛りを除く theme(axis.title.y = element_blank()) #軸ラベルを除く
さらに、グラフをよく見ると、x軸に対してドットが等間隔でないです。
妙に横とくっついているドットもあれば、離れているドットもあります。
これは、ビンを決めるアルゴリズムによって決まります。
デフォルトでは、dotdensityになっています。*1
変更するためには、method引数を指定します。
ggplot(faithful, aes(x=eruptions)) + geom_dotplot(binwidth = binSize, fill="lightblue",colour="grey60", method = "histodot") + #ヒストグラムと同じ theme_bw() + scale_y_continuous(breaks = NULL) + theme(axis.title.y = element_blank())
x軸に対して等間隔にしましたが、y軸に対してセンタリングすることもできます。
stackdir引数を指定します。
ggplot(faithful, aes(x=eruptions)) + geom_dotplot(binwidth = binSize, fill="lightblue",colour="grey60", method = "histodot", stackdir = "center") + #y軸に対して中央揃え theme_bw()
上のグラフは、y軸に対してセンタリングされています。
そのため、ドットが奇数の列と偶数の列では、y軸に対してずれています。
奇数/偶数の列でそろえる場合は、centerwholeを指定します。
ggplot(faithful, aes(x=eruptions)) + geom_dotplot(binwidth = binSize, fill="lightblue",colour="grey60", method = "histodot", stackdir = "centerwhole") + #奇数/偶数の列を揃える theme_bw()
今までは、x軸でビンを区切り、y軸方向に積み上げてきましたが、
ドットプロットは、y軸でビンを区切り、x軸方向に積み上げることができます。
(y軸でビンを区切ることで、おかしい目盛りがでないです)
グループ化したドットプロットで、x軸方向にビン積み上げをしてみます。
グループ化したドットプロット
グループ化したドットプロットを作るために、
x軸に離散値を、y軸に連続値をマッピングして、binaxis引数を指定します。
ggplot(heightweight, aes(x=sex, y=heightIn)) + geom_dotplot(binaxis = "y", binwidth = .5, stackdir = "center", fill="lightblue", colour="grey60")
上のグラフは、y軸でセンタリングしていますが、
下のグラフを見ると、理由が分かると思います。
(y軸でセンタリングしないと、まとめる意味が…)
このy軸方向に積み上げた、ドットプロットですが
箱ひげ図と重ねてみるのが慣例っぽいです。
ggplot(heightweight, aes(x=sex,y =heightIn)) + geom_boxplot(outliner.colour=NA,width=.4)+ geom_dotplot(binaxis = "y",binwidth = .5,stackdir = "center", fill="lightblue",alpha=.5,colour="grey60")
ドットプロットも箱ひげ図も観測値ですが、両方あることで納得感が増すかな。
さすがに、バイオリンプロットまで重ねると、色の調整が大変です。
ggplot(heightweight, aes(x=sex,y =heightIn)) + geom_boxplot(outliner.colour=NA,width=.4)+ geom_violin(fill="lightgreen",alpha=.2,trim=FALSE)+ geom_dotplot(binaxis = "y",binwidth = .5,stackdir = "center", fill="black",alpha=.5,colour="grey60")
上記の様に重ねてみる場合は、それぞれのグラフをx軸方向にずらすと良いです。
ggplot(heightweight, aes(x=sex,y=heightIn)) + geom_violin(aes(x=as.numeric(sex) + .25, group=sex), width=.5,fill="blue", alpha=.2,trim=FALSE) + geom_boxplot(aes(x=as.numeric(sex) + .25, group=sex),width=.25, fill="cornsilk")+ geom_dotplot(aes(x=as.numeric(sex) - .3, group=sex),binaxis = "y", binwidth=.5,stackdir="center")+ scale_x_continuous(breaks=1:nlevels(heightweight$sex), labels=levels(heightweight$sex))
次回は、2次元の密度推定をプロットし、
データ分布の最後にしたいと思います。