今回の目標
今回利用するパッケージを読み込む。ggplot2は tidyverse に含まれているので、library()
で tidyverse を読み込めばよい。パッケージをインストール済みでない場合は、読み込みの前にまずinstall.packages()
でインストールする。
#install.packages("tidyverse", dependencies = TRUE)
library(tidyverse)
ggplot2 で図を作るためには、データフレーム (data frame) と呼ばれる形式のデータが必要である。 そこで、まずデータフレームについて説明する。
CSV形式で保存されたデータセットをもっているなら、readr::read_csv()
や read.csv()
などでそのデータを読み込めば、データフレームができる。
例として、これまでの授業でも使った fake-data-01.csv を読み込んでみよう。プロジェクト内の data ディレクトリ(フォルダ)に fake-data-01.csv
があることを想定している。
<- read_csv("data/fake-data-01.csv") myd
##
## ── Column specification ────────────────────────────────────────────────────────
## cols(
## id = col_double(),
## gender = col_character(),
## age = col_double(),
## height = col_double(),
## weight = col_double(),
## income = col_double()
## )
これがデータフレームかどうか確かめるために、is.data.frame()
を使う。
is.data.frame(myd)
## [1] TRUE
TRUE (真)という答えが返され、myd がデータフレームであることがわかる。
データフレームの中身は、tibble::glimpse()
で確認できる。
glimpse(myd)
## Rows: 100
## Columns: 6
## $ id <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, …
## $ gender <chr> "male", "male", "male", "male", "male", "male", "male", "male",…
## $ age <dbl> 52, 33, 22, 33, 26, 37, 50, 30, 62, 51, 55, 36, 66, 42, 36, 47,…
## $ height <dbl> 174.0, 175.3, 175.0, 170.1, 167.4, 159.3, 173.3, 162.5, 160.2, …
## $ weight <dbl> 63.1, 70.2, 82.6, 81.8, 51.2, 57.8, 68.6, 47.2, 68.2, 59.4, 66.…
## $ income <dbl> 3475810, 457018, 1627793, 6070642, 1083052, 2984929, 1481061, 1…
id
, gender
, age
, height
, weight
, income
という6つの変数があり、gender
が
データフレームの中身を確認する方法は他にもいくつかある。 View()
を使うと、表計算ソフトのスプレッドシートと同じように、データを表形式で表示してくれる。 Souce ペインに表示されるので確認が終わったらタブを閉じるようにしよう。 この関数は R Markdown ファイルではなく、Console に直接入力したほうが良い。
View(myd)
ひとつひとつの変数が列(縦方向の並び)を構成し、観測個体がが行(横方向の並び)を構成していることがわかる。 View()
の代わりに、RStudio の右下のペインにある Environment たぶで、Data という項目に表示されているデータの右端にあるボタンを押して、データを表示することもできる。
データフレームの各列の名前(つまり、変数名)を知りたいときは、names()
を使う。
names(myd)
## [1] "id" "gender" "age" "height" "weight" "income"
これで、どのような名前で変数が記録されているかがわかる。
この例では変数が6つしかないので自分で変数の数を数えるのも容易である。しかし、変数の数が多い場合には、自分で数えるのは面倒だ。そのようなときは、ncol()
を使う(ncol は the number of columns [列の数] の略である)。
ncol(myd)
## [1] 6
これで、myd
には変数が6つあることがわかる。
また、データに含まれる観測個体の数は、nrow()
で確かめることができる (the number of rows [行の数] の略である)。
nrow(myd)
## [1] 100
myd
は100行あることがわかる。
dim()
を使えば、行数と列数を1度に調べることができる。
dim(myd)
## [1] 100 6
実は、行数と列数は、上でglimpse(myd)
を実行したときにも表示されていた。
データの先頭の数行を表示して変数の中身を確認したいときは、head()
を使う。
head(myd)
## # A tibble: 6 x 6
## id gender age height weight income
## <dbl> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 1 male 52 174 63.1 3475810
## 2 2 male 33 175. 70.2 457018
## 3 3 male 22 175 82.6 1627793
## 4 4 male 33 170. 81.8 6070642
## 5 5 male 26 167. 51.2 1083052
## 6 6 male 37 159. 57.8 2984929
このように、デフォルトでは最初の6行が表示される。表示する行数は、自分で指定できる。引数 n
を使う。
head(myd, n = 4)
## # A tibble: 4 x 6
## id gender age height weight income
## <dbl> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 1 male 52 174 63.1 3475810
## 2 2 male 33 175. 70.2 457018
## 3 3 male 22 175 82.6 1627793
## 4 4 male 33 170. 81.8 6070642
同様に、データの末尾は tail()
で表示できる。
tail(myd, n = 5)
## # A tibble: 5 x 6
## id gender age height weight income
## <dbl> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 96 female 65 161. 46.8 6127136
## 2 97 female 45 161. 48.7 1062663
## 3 98 female 53 166. 64.2 10154200
## 4 99 female 43 158. 48.5 8287163
## 5 100 female 48 154. 42 1125390
データの中身をさらに詳しく知りたい場合には、str()
(structure) を使う。
str(myd)
## spec_tbl_df[,6] [100 × 6] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ id : num [1:100] 1 2 3 4 5 6 7 8 9 10 ...
## $ gender: chr [1:100] "male" "male" "male" "male" ...
## $ age : num [1:100] 52 33 22 33 26 37 50 30 62 51 ...
## $ height: num [1:100] 174 175 175 170 167 ...
## $ weight: num [1:100] 63.1 70.2 82.6 81.8 51.2 57.8 68.6 47.2 68.2 59.4 ...
## $ income: num [1:100] 3475810 457018 1627793 6070642 1083052 ...
## - attr(*, "spec")=
## .. cols(
## .. id = col_double(),
## .. gender = col_character(),
## .. age = col_double(),
## .. height = col_double(),
## .. weight = col_double(),
## .. income = col_double()
## .. )
この情報はR初心者にはわかりにくいと思われるので、最初は glimpse()
を使った方がいいだろう。
データセットをRに読み込んだら、glimpse()
をはじめとするさまざまな関数を使って、データの中身を確認する習慣を身につけよう。
データフレームは、data.frame()
を使ってRで作ることもできる。データフレームの代わりにtibble と呼ばれる形式のデータを使うこともできる。tibble は、tibble::tibble()
で作れる。
練習のために、df1という名前のデータフレームと、df2という名前のtibble を作ってみよう。まず、x とy という2つの変数をもつ df1
を作る。
<- data.frame(x = 1:100,
df1 y = 100:1)
is.data.frame(df1)
## [1] TRUE
このデータの中身を確認してみよう。
glimpse(df1)
## Rows: 100
## Columns: 2
## $ x <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 2…
## $ y <int> 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84,…
x
と y
という変数があり、それぞれが
次に、v1, v2, v3 という3つの変数をもつ df2 を作る。rnorm(n, mean, sd)
で、平均がmean
、標準偏差がsd
の正規分布から n
個の乱数を生成することができる(詳しくは、「シミュレーション」の回に説明する)。
<- tibble(v1 = rnorm(100, mean = 0, sd = 5),
df2 v2 = rnorm(100, mean = -4, sd = 5),
v3 = rnorm(100, mean = 0, sd = 1))
is.data.frame(df2)
## [1] TRUE
df2
の中身を確認しておこう。
glimpse(df2)
## Rows: 100
## Columns: 3
## $ v1 <dbl> -3.4588462, 3.6477649, -1.1223656, -3.8149316, 7.3289872, -2.920685…
## $ v2 <dbl> 4.5036501, -0.8644444, -12.8516999, -4.9967586, 1.5024545, -5.40636…
## $ v3 <dbl> -0.501376988, 0.489839417, -1.052405132, -0.930425648, -0.396721603…
v1
, v2
, v3
という3つの変数があり、それぞれが
このように、data.frame()
と tibble()
を使って、df1とdf2のという “data.frame” (データフレーム)を作ることができた。基本的にはどちらの方法でデータフレームを作っても良いが、 特にdata.frame()
のほうを好む理由がなければ、今後は tibble()
でデータフレーム (tibble) を作ろう。 (tibble を優先する理由の説明は割愛するが、Consoleに直接 df1
[これは data.frame である] と入力して実行した結果と、 同じく df2
[これは tibble である] と入力して実行した結果を比べると、tibble のほうが良い理由の1つがわかるだろう。)
Rにはあらかじめいくつかの(多くの!)データフレームが用意されている。たとえば、自動車に関するデータセットであるmtcarsというものがある。このデータは、data()
で呼び出すことができる。
data(mtcars)
これを実行すると、RStudio 右下ペインの Environement タブの中で、Values という項目のところに、mtcars
が表示されるはずだ。この中身を確認してみよう。
glimpse(mtcars)
## Rows: 32
## Columns: 11
## $ mpg <dbl> 21.0, 21.0, 22.8, 21.4, 18.7, 18.1, 14.3, 24.4, 22.8, 19.2, 17.8,…
## $ cyl <dbl> 6, 6, 4, 6, 8, 6, 8, 4, 4, 6, 6, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 8,…
## $ disp <dbl> 160.0, 160.0, 108.0, 258.0, 360.0, 225.0, 360.0, 146.7, 140.8, 16…
## $ hp <dbl> 110, 110, 93, 110, 175, 105, 245, 62, 95, 123, 123, 180, 180, 180…
## $ drat <dbl> 3.90, 3.90, 3.85, 3.08, 3.15, 2.76, 3.21, 3.69, 3.92, 3.92, 3.92,…
## $ wt <dbl> 2.620, 2.875, 2.320, 3.215, 3.440, 3.460, 3.570, 3.190, 3.150, 3.…
## $ qsec <dbl> 16.46, 17.02, 18.61, 19.44, 17.02, 20.22, 15.84, 20.00, 22.90, 18…
## $ vs <dbl> 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,…
## $ am <dbl> 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,…
## $ gear <dbl> 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 3, 3,…
## $ carb <dbl> 4, 4, 1, 1, 2, 1, 4, 2, 2, 4, 4, 3, 3, 3, 4, 4, 4, 1, 2, 1, 1, 2,…
32行11列のデータであることがわかる。この時点で、 Environement タブの中で Data 項目の中に mtcars が移動し、データフレームとして認識されていることがわかる。念のために確認しておこう。
is.data.frame(mtcars)
## [1] TRUE
このデータの詳細を確認したければ、次のコマンドで。
?mtcars
他にどんなデータが利用可能か確認したければ、以下を実行する。
data()
ggplot2 は、Rで綺麗な図を作るためのパッケージである。 RStudio のChief Scientist である Hadley Wickham が大学院生時代に開発・公開し、アップデートを重ねてきたものである(Hadley は tidyverse などの重要パッケージ開発の中心人物であり、世界中のRユーザから最も尊敬されている人物だと考えられる。日本の一部のRユーザは彼を「羽鳥先生」と呼ぶ)。
ggplot2 の gg は grammar of graphics(図のための文法) という意味で、一貫した方法で様々な図が作れるように工夫されている。 最初は文法を覚えるのに少し苦労するかもしれない。しかし、一度文法を身につけてしまえば、様々な図を簡単に作れるようになるので、とても便利である。また、デフォルト(既定)の設定でそれなりに綺麗な図が作れるのも魅力である(某表計算ソフトのように、何も考えずに 3D棒グラフのような醜い図を作ってしまうということが防げる)。
ggplot2 についての詳しい説明は、Hadley自身が書いた ggplot2: Elegant Graphics for Data Analysis, 2nd ed. (Springer) で読める(PDFファイル が無料で公開されている)。
また、チートシート(日本語版; 英語版)が公開されているので、ダウンロードしていつでも見られるようにしておくと、便利である。
このページの冒頭に書いたとおり、。ggplot2は tidyverse に含まれているので、library()
で tidyverse を読み込めばよい。上で実行したなら、再度実行する必要はない。パッケージをインストール済みでない場合は、読み込みの前にまずinstall.packages()
でインストールする。
#install.packages("tidyverse", dependencies = TRUE)
library(tidyverse)
次に日本語が正しく表示されるようにするため、theme_set()
で使用する文字フォントを指定する。OSによって命令がやや異なるので注意されたい。 以下のチャンクは、どのOSでも動くように適切に場合分けを行う(ただし、Windows の場合には fontregisterer というパッケージをあらかじめインストールしておく必要がある。これについては前回の実習資料を参照)。 また、以下はあくまで例であり、他のフォントを使用しても良い(各自のパソコンにインストールされているフォントは私にはわからないので、変えたいなら自分で調べる。もちろん、日本語が表示できるフォントが必要)。また、RStudio Cloud を利用している場合は、日本語を表示することができない(一応表示する方法もあるが、ものすごく面倒なので割愛する)ので、諦めて英語を使おう(この授業では、レポートの本文が日本語で図のラベルが英語でも許容する。しかし、本来は日本語のレポートなら図のラベルもすべて日本語にすべきである。あるいは、英語で図を作るなら、本文も英語にすべきである)。
ggplot2::ggplot()
を使って図を作る手順は次のとおりである。
ggplot()
に入力する
geom_xxx()
で図の層を加える(xxx の部分はグラフの種類によって変わる)plot()
で図を表示する順番にやってみよう。
例1:散布図
上で読み込んだ mtcars は自動車に関するデータである。例として、燃費 (mile per gallon; mpg) と車の重量 (weight; wt) の関係を散布図にしてみよう。
まず、 作図対象となるデータを指定する。また、作図の対象となる変数を指定する。ここでは、散布図の横軸 x
に wt、縦軸y
に mpg を指定する。
<- ggplot(data = mtcars,
p1_1 mapping = aes(x = wt, y = mpg))
同じことだが、data
とmapping
は書略して
<- ggplot(mtcars, aes(x = wt, y = mpg)) p1_1
と書くことが多い。
この時点で図を表示してみる。
plot(p1_1)
指定した通り、横軸にwt、縦軸にmpgをとった図を描く準備ができているが、グラフ自体はまだない。
ここに、散布図を作るための層 (layer) を加える。図を作るためには、geom_xxx()
のように、geom から始まる関数で新たな層 (layer) を加える必要がある。geom とは geometry(形状)のことである。たとえば、ヒストグラム (histogram) を作るときはgeom_histogram()
を、箱ひげ図 (box[-and-whisker] plot) を作るときは geom_boxplot()
を使う。
散布図は、geom_point()
でできる。
<- p1_1 + geom_point() p1_2
このように、前に作ったものに +
で何かを加えることで、ggplot に新たな要素を追加することができる。この時点で、作った図を表示してみよう。
plot(p1_2)
散布図ができた。
次に、ラベルをわかりやすいものに変える。labs()
で変更する。(注意: RStudio Cloud を使っている場合は日本語不可。日本語を正しく表示するために事前準備が必要。上の説明を参照。)
<- p1_2 +
p1_3 labs(x = "重量 (1000 lbs)",
y = "燃費 (Miles / US gallon)")
表示してみる。
plot(p1_3)
これで散布図ができた。
慣れてきたら、一度にコマンドを書いてもよい。
<- ggplot(mtcars, aes(x = wt, y = mpg)) +
p1 geom_point() +
labs(x = "重量 (1000 lbs)",
y = "燃費 (Miles / US gallon)")
plot(p1)
例2:ヒストグラム
引き続き mtcars を使う。燃費 (mile per gallon; mpg) のヒストグラムを作ってみよう。
まず、作図対象となるデータを入力する。また、作図対象となる変数を指定する。ヒストグラムは1つの変数を可視化するグラフなので、aes にはx
のみ指定する。
<- ggplot(mtcars, aes(x = mpg)) p2_1
この時点で図を表示してみる。
plot(p2_1)
指定した通り、横軸にmpgをとった図を描く準備ができているが、グラフ自体はまだない。また、縦軸は指定していないので何もない。
ここに、ヒストグラムを作るための層 (layer) を加える。ヒストグラムは、geom_histogram()
でできる。
<- p2_1 + geom_histogram() p2_2
この時点で表示してみよう。
plot(p2_2)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
ヒストグラム自体はできている。しかし、ビン(ヒストグラムの一つひとつの棒)の幅が狭すぎるので、binwidth
で調整する(binwidth
を指定しないと、stat_bin()
using … というメッセージが表示され、適切な binwidth
を設定するよう促される)。ここでは、2.5 mpgごとに1つのビン(ヒストグラムの棒)を作ってみよう。
<- p2_1 + geom_histogram(binwidth = 2.5)
p2_3 plot(p2_3)
ビンの境が見えにくいので、ビンの縁に黒色をつけよう。ビンの縁取りは color
で指定する。color
で指定するのはビンの中身の色ではないので注意しよう。
<- p2_1 + geom_histogram(binwidth = 2.5, color = "black")
p2_4 plot(p2_4)
ビンの区切りがちょうどいい位置にないので、boundary
でビンの境界をどの位置に置きくか指定する。今回はビンの幅が2.5 なので、境界線が\(5, 7.5, 10, \dots\) になるように 5 を指定する。
<- p2_1 +
p2_5 geom_histogram(binwidth = 2.5,
color = "black",
boundary = 5)
plot(p2_5)
次に、ラベルをわかりやすいものに変える。(注意: RStudio Cloud を使っている場合は日本語不可。)
<- p2_5 + labs(x = "燃費 (Miles / US gallon)", y = "度数")
p2_6 plot(p2_6)
これで縦軸が度数 (count, frequency) のヒストグラムができた。
ヒストグラムの縦軸を確率密度 (probability density) に変えたいときは、aes()
で y = after_stat(density)
を指定する。ついでに、ビンの色をドジャーブルーに変えてみる(必要ではない。Go, Dodgers!)
<- ggplot(mtcars,
p2_dens aes(x = mpg, y = after_stat(density))) +
geom_histogram(binwidth = 2.5, boundary = 5,
color = "black", fill = "dodgerblue") +
labs(x = "燃費 (Miles / US gallon)", y = "確率密度")
plot(p2_dens)
指定可能な色は、このページ で確認できる。
例3:箱ひげ図
Rに用意されている、ダイヤモンドのデータ diamonds を使ってみよう。
data(diamonds)
glimpse(diamonds)
## Rows: 53,940
## Columns: 10
## $ carat <dbl> 0.23, 0.21, 0.23, 0.29, 0.31, 0.24, 0.24, 0.26, 0.22, 0.23, 0.…
## $ cut <ord> Ideal, Premium, Good, Premium, Good, Very Good, Very Good, Ver…
## $ color <ord> E, E, E, I, J, J, I, H, E, H, J, J, F, J, E, E, I, J, J, J, I,…
## $ clarity <ord> SI2, SI1, VS1, VS2, SI2, VVS2, VVS1, SI1, VS2, VS1, SI1, VS1, …
## $ depth <dbl> 61.5, 59.8, 56.9, 62.4, 63.3, 62.8, 62.3, 61.9, 65.1, 59.4, 64…
## $ table <dbl> 55, 61, 65, 58, 58, 57, 57, 55, 61, 61, 55, 56, 61, 54, 62, 58…
## $ price <int> 326, 326, 327, 334, 335, 336, 336, 337, 337, 338, 339, 340, 34…
## $ x <dbl> 3.95, 3.89, 4.05, 4.20, 4.34, 3.94, 3.95, 4.07, 3.87, 4.00, 4.…
## $ y <dbl> 3.98, 3.84, 4.07, 4.23, 4.35, 3.96, 3.98, 4.11, 3.78, 4.05, 4.…
## $ z <dbl> 2.43, 2.31, 2.31, 2.63, 2.75, 2.48, 2.47, 2.53, 2.49, 2.39, 2.…
class(diamonds)
## [1] "tbl_df" "tbl" "data.frame"
詳細については、?diamonds
で確認できる。
ダイヤモンドのカットの質 (cut) ごとの 深さ (depth) のばらつきを可視化するため、箱ひげ図 (box[-and-whisker] plot) を作ってみよう。
まず、データとマッピングを指定する。
<- ggplot(diamonds, aes(x = cut, y = depth))
p3_1 plot(p3_1)
指定通り、横軸に cut、縦軸に depth を可視化する準備ができている。
次に、geom_boxplot()
で箱ひげ図の層を加える。
<- p3_1 + geom_boxplot()
p3_2 plot(p3_2)
軸ラベルを日本語にする (RStudio Cloud 以外)。
<- p3_2 + labs(x = "カット", y = "深さ")
p3_3 plot(p3_3)
Fair, Good なども日本語にすることもできるが、今回は覚えなくて良い(私にはダイヤモンドの知識がまったくないのでよくわからないが、ネットで検索した限りだと、Fair の訳は フェア、Good の訳は グッド、 … で日本語にする意味がなさそう)。一応できるということを見せるために、コードは載せておく(このコードは今は理解しなくてよい)。
<- diamonds %>%
p3_3a mutate(cut_jp = factor(
cut, levels = c("Fair", "Good", "Very Good", "Premium", "Ideal"),
labels = c("フェア", "グッド", "ベリーグッド",
"プレミアム", "アイディアル"))) %>%
ggplot(aes(x = cut_jp, y = depth)) +
geom_boxplot() +
labs(x = "カット", y = "深さ")
plot(p3_3a)
箱ひげ図の向きを横向きにしたいときは、作った図に coord_flip()
を使えば良い。
<- p3_3 + coord_flip()
p3_4 plot(p3_4)
このように、coord_flip()
は横軸と縦軸を入れ替えてくれる。箱ひげ図以外でも使える。
また、aes()
の x
とy
を入れ替えることで、向きを変えることもできる。
<- ggplot(diamonds, aes(x = depth, y = cut)) +
p4 geom_boxplot() +
labs(x = "カット", y = "深さ")
plot(p4)
これらの例からわかるとおり、作図に用いる変数の指定は、aes()
で行う。aes とは aesthetics(美感)のことである。この aes()
の指定の仕方は、作る図によって異なる。したがって、ggplot2 の使い方をマスターするには、geom ごとに異なるaes の使い方を覚える必要がある。覚えるといっても、必ずしも暗記する必要なない。頻繁に使うものは覚えたほうが楽(自然に覚える)が、その他のものについてはチートシート(日本語版; 英語版)やインターネット上にまとめられた情報(たとえば、ココ やココ)で確認すればよい。
作成した図は、PDFファイルやPNGファイルなどの外部ファイルに保存することができる。プロジェクト内に、図を保存するための figs とういディレクトリ(フォルダ)を新たに作り、図をその中に保存しよう。
dir.create("figs")
図を保存するための関数は Windows とmacOSでやや異なるので、別々に説明する(Linux については省略 [Linux を使える人は自分で調べられるでしょう])。また、図はPDFとして保存することが望ましい(理由の説明は省略するが、一言で述べれば「ベクター画像」が望ましいから)ので、PDFファイルでの保存方法のみ説明する。
また、図のファイルを作るときは、あらかじめ図のサイズ(高さと幅)を決めておくことが重要である。いいかげんなサイズで図を作り、後で拡大・縮小すると、軸ラベルの文字などが伸びたり縮んだりして汚くなるので、スマートではない。
先ほど作ったヒストグラム p2_6
を、PDFファイルに保存しよう。図を保存するためのPDFファイルは、ggplot2::ggsave()
で作る。 ファイル名は、hist_eg1.pdf
にしよう。図の大きさは、A4用紙の半ページよりやや小さくなるように、高さ (height) を4インチ (101.6mm)、幅 (width) を5インチ (127.0mm) にする。また、軸ラベルに日本語を使っているので、日本語を表示できるフォントを指定する必要がある(上で実行済み)。
図の保存は次のように行う。
ggsave(file = "figs/hist_eg1.pdf", plot = p2_6, device = "pdf",
height = 4, width = 5)
file
の figs/
という部分が、figs ディレクトリ(フォルダ)の中にファイルを作ることを指示している。
これで図 (p2_6
) が保存されるはずだ。figsディレクトリの中に、hist_eg1.pdf
というPDFファイルができていることを確かめよう。また、PDFファイルを開いて図が保存されていることも確認しよう。
基本的には、以下の3つのステップで図を保存する。
これら3つのステップはセットで行う。R Markdown を使っている場合は特に注意が必要で、各ステップを1つずつ実行しても図が保存されない。 そこで、3つのスッテプをつのコードチャンクの中にまとめて書き、以下のいずれかの方法でチャンク全体を一挙に実行する必要がある。
Mac で図を保存するには、quartz()
という関数を使うのが便利でる。 先ほど作ったヒストグラム p2_6 を、PDFファイルに保存しよう。 ファイル名は、hist_eg1.pdf
にしよう。PDFファイルで保存するために、type = "pdf"
を指定する。 図の大きさは、A4用紙の半ページよりやや小さくなるように、高さ (height) を4インチ (101.6mm)、幅 (width) を5インチ (127.0mm) にする。また、軸ラベルに日本語を使っているので、日本語を表示できるフォントを指定する必要がある。ここでは family = "sans"
(サンセリフ体)を指定しよう。上で library("tidyverse")
を実行した直後に、theme_set()
で HiraginoSans-W3 を指定したので、ヒラギノ角ゴシックが使われる。 第1ステップの内容をまとめると、次のようになる(第1ステップだけで実行しない!!!)。
quartz(file = "figs/hist_eg1.pdf", type = "pdf",
height = 4, width = 5, family = "sans")
file の figs/
という部分が、figs ディレクトリ(フォルダ)の中にファイルを作ることを指示している。
第2ステップは、第1ステップの直後に print(p2_6)
とすればよい。
最後に、ファイルを閉じるために、dev.off()
を実行する。
以上をまとめると、次のようになる。R Markdown では、以下のコードチャンクを一挙に実行する必要がある(Rスクリプトでは1行ずつ実行してよい)。
quartz(file = "figs/hist_eg1.pdf", type = "pdf",
height = 4, width = 5, family = "sans")
print(p2_6)
dev.off()
これで図が保存されるはずだ。figsディレクトリの中に、hist_eg1.pdf
というPDFファイルができていることを確かめよう。また、PDFファイルを開き、図が保存されていることも確認しよう。
ggplotの使い方を身につけるために、統計学でよく使う基本的な図を作ってみよう。
例として、fake-score.csv という架空のデータを使おう。このデータに含まれる変数は、以下の通りである。
まず、データを保存するためのディレクトリを作る。既にプロジェクト内に data ディレクトリがある場合(これまでの実習をすべて実行していれば、既にあるはずである)、このコマンドは実行しなくてよい。
dir.create("data")
次に、データをダウンロードする。以下のコードはWindows では失敗する可能性が高いので、ココを右クリック して対象をファイルに保存する。保存先はプロジェクトフォルダの中の data フォルダにする(ダウンロードした後にファイルを移動してもよい)。
download.file(
url = "http://yukiyanai.github.io/jp/classes/stat2/contents/data/fake-score.csv",
destfile = "data/fake-score.csv"
)
データを読み込む。
<- read_csv("data/fake-score.csv") myd
##
## ── Column specification ────────────────────────────────────────────────────────
## cols(
## id = col_double(),
## class = col_double(),
## gender = col_character(),
## math = col_double(),
## english = col_double(),
## chemistry = col_double()
## )
データの中身を確認する。
glimpse(myd)
## Rows: 400
## Columns: 6
## $ id <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 1…
## $ class <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
## $ gender <chr> "female", "female", "female", "female", "female", "female", …
## $ math <dbl> 100, 43, 80, 52, 63, 45, 74, 54, 59, 74, 65, 41, 71, 75, 75,…
## $ english <dbl> 68, 59, 67, 60, 72, 59, 69, 66, 72, 73, 77, 52, 69, 65, 57, …
## $ chemistry <dbl> 97, 60, 75, 60, 57, 67, 62, 63, 69, 67, 70, 48, 59, 76, 84, …
正しくデータが読み込めたようだ。このデータを使い、作図の方法を学習しよう。
この時点でデータが正しく読み込めていない場合は、ウェブブラウザで fake-score.csv をダウンロードし、ダウンロードしたファイルを手動でプロジェクト内のデータフォルダの中に移動してから、以下を実行し直そう。 もう一度データを読み込む。
<- read_csv("data/fake-score.csv") myd
##
## ── Column specification ────────────────────────────────────────────────────────
## cols(
## id = col_double(),
## class = col_double(),
## gender = col_character(),
## math = col_double(),
## english = col_double(),
## chemistry = col_double()
## )
glimpse(myd)
## Rows: 400
## Columns: 6
## $ id <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 1…
## $ class <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
## $ gender <chr> "female", "female", "female", "female", "female", "female", …
## $ math <dbl> 100, 43, 80, 52, 63, 45, 74, 54, 59, 74, 65, 41, 71, 75, 75,…
## $ english <dbl> 68, 59, 67, 60, 72, 59, 69, 66, 72, 73, 77, 52, 69, 65, 57, …
## $ chemistry <dbl> 97, 60, 75, 60, 57, 67, 62, 63, 69, 67, 70, 48, 59, 76, 84, …
棒グラフ (bar plot) は geom_bar()
で作る。まず、クラスごとの人数を棒グラフにしてみよう。 横軸にクラス、縦軸にはクラスの人数を表示する。そのために、次のコマンドを使う。
<- ggplot(myd, aes(x = class)) +
bar1 geom_bar() +
labs(x = "クラス", y = "人数")
表示してみよう。
plot(bar1)
各クラスの人数が、等しく50人ずつであることがわかる。
横軸のクラスの数字1から8のうち、表示されていない数字がある。scale_x_continuous()
を使って、すべて表示させよう。既に作った bar1 を基に、新しい図を作る。
<- bar1 + scale_x_continuous(breaks = 1:8) bar2
表示してみよう。
plot(bar2)
クラスの数字をすべて表示することができた。
男女の内訳はどうなっているだろうか。男女を色分けして描き、図で確かめよう。 データセットに含まれる gender という変数を使って色分けするために、aes
の中で fill
を指定する。
<- ggplot(myd, aes(x = class, fill = gender)) +
bar3 geom_bar() +
labs(x = "クラス", y = "人数") +
scale_x_continuous(breaks = 1:8)
plot(bar3)
女子の方が多いクラスと男子の方が多いクラスがあるようだ。 凡例 (legend) が英語になっているので、日本語に直そう。
<- bar3 +
bar4 scale_fill_discrete(name = "性別", labels = c("女", "男"))
plot(bar4)
この棒グラフでは男女の数の比較が難しいので、男女の棒を並べて描きたい。そのために、position = "dodge"
を指定する。
<- ggplot(myd, aes(x = class, fill = gender)) +
bar5 geom_bar(position = "dodge") +
labs(x = "クラス", y = "人数") +
scale_x_continuous(breaks = 1:8) +
scale_fill_discrete(name = "性別", labels = c("女", "男"))
plot(bar5)
これで、クラス1からクラス4までは女子が20人で男子が30人だが、残りのクラスでは男女の数が逆転していることがわかる。
ヒストグラム (histogram) は、ある変数の分布の仕方を確かめる際に最も便利な図である。 既に説明した通り、ヒストグラムを作るには geom_histogram()
を使う。
基本的な使い方
まず、数学の点数をヒストグラムにしてみよう。
<- ggplot(myd, aes(x = math)) +
hist1 geom_histogram() +
labs(x = "数学の点数", y = "人数")
plot(hist1)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
このままだと、ヒストグラムの一つひとつの棒 (bin) の区切りが分かりにくいので、棒の縁に色をつけよう。 既に説明したとおり、縁取りの色はcolor
で指定する。このとき、変数によって色を変えるのではなく、自分で設定した色を使うため、aes
の外で color
を指定する(上での棒グラフの例では、aes
の中で fill
を指定した)。
<- ggplot(myd, aes(x = math)) +
hist2 geom_histogram(color = "black") +
labs(x = "数学の点数", y = "人数")
plot(hist2)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
次に棒の幅 (bin width) を変えてみよう。binwidth を指定することで、棒の幅を設定できる。試しに、10点ごとにしてみよう。
<- ggplot(myd, aes(x = math)) +
hist3 geom_histogram(color = "black", binwidth = 10) +
labs(x = "数学の点数", y = "人数")
plot(hist3)
縦軸を確率密度に変える
上で説明したとおり、y
に after_stat(density)
と書くことで、縦軸を確率密度に変えることができる。
<- ggplot(myd, aes(x = math, y = after_stat(density))) +
hist4 geom_histogram(color = "black", binwidth = 10) +
labs(x = "数学の点数", y = "確率密度")
plot(hist4)
縦軸が確率密度のヒストグラムができた。
複数の geom を重ねる
数学の点数の平均値は、
mean(myd$math)
## [1] 55.6
である。これを図に書き加えよう。
まず、geom_vline()
で、平均値の位置に縦線を加える。 vlineのv はvertical(垂直)を示す。 geom_vline()
で縦線の位置を決めるために、xintercept(x切片、つまり、線が横軸と交わる位置)を指定する。
<- hist3 +
hist5 geom_vline(xintercept = mean(myd$math), color = "red")
plot(hist5)
次に、平均値の値を(小数第一位までに丸めて [round] して)書き込む。
<- hist5 +
hist6 geom_text(aes(x = 70, y = 90,
label = str_c("平均値:", round(mean(myd$math), 1))),
color = "red",
family = my_font)
表示する。
plot(hist6)
facet でグループを分ける
数学の点数のヒストグラムを、クラスごとに分けて描いてみよう。そのために、facet_wrap()
を使う
<- hist3 + facet_wrap(vars(class))
hist7 plot(hist7)
このように、クラスごとにヒストグラムができる。
ヒストグラムは分布の形状を確かめるのに便利だが、上で作った hist7
のように、複数のグループの分布を比較するのには少し不便である。 そこで異なるグループの分布を比較するときによく使われるのが、箱ひげ図 (box[-and-whisker] plot) である。箱ひげ図は、五数要約(最小値、第1四分位数、中央値、第3四分位数、最大値)と外れ値(「1.5 \(\times\) IQRルール」で判定される)を図で表現するものである。
箱ひげ図は、geom_boxplot()
で作る。このとき、aes には x
(比較するグループを表す変数)とy
(作図の対象となる変数)を指定する(x
の代わりに group
を使うこともできる)。ここで、class の中身の数字には数値としての意味はなく、単にクラス分けのための記号にすぎないことを gpplotに伝えるために as.factor()
を使う(本当はデータ前処理の時点で id と class は factor にしておくことが望ましいが、今回はこれで妥協する)。既に説明したとおり、横向きにしたいときは、x
とy
を入れ替えれば良い。
<- ggplot(myd, aes(x = as.factor(class), y = math)) +
box1 geom_boxplot() +
labs(x = "クラス", y = "数学の点数")
plot(box1)
これで、グループ間で数学の点数の五数を比較しやすくなった。
箱ひげ図でグループ間比較がしやすくなったが、ヒストグラムとは異なり、分布の形状がわからなくなってしまった。この不満を解消してくれるのが、バイオリンプロット (violin plot) である。geom_violin()
で作る。
<- ggplot(myd, aes(x = as.factor(class), y = math)) +
vln1 geom_violin() +
labs(x = "クラス", y = "数学の点数")
plot(vln1)
この図は、ヒストグラムを横倒しにしてその概形を滑らかな線で表したものと、それを鏡に写したものが合わさってできている。バイオリンプロットの幅が広い(狭い)ところが、ヒストグラムの山が高い(低い)ところである。
バイオリンプロットは、分布の形状がわからないという箱ひげ図の弱点を克服しているものの、箱ひげ図では一目でわかった中央値や四分位範囲がわからないという弱点がある。両者の長所を活かすため、二つの図を重ねて描いてみよう。
<- ggplot(myd, aes(x = as.factor(class), y = math)) +
bv1 geom_boxplot() +
geom_violin() +
labs(x = "クラス", y = "数学の点数")
plot(bv1)
バイロリンプロットが箱ひげ図の線に重なり、箱ひげ図がよく見えない。箱ひげ図をバイオリンプロットの上に(手前に)描いたほうがよさそうだ。ggplotでは、後に加えた要素(層)が上になるので、geom_violin()
の後に geom_boxplot()
を書く。
<- ggplot(myd, aes(x = as.factor(class), y = math)) +
bv2 geom_violin() +
geom_boxplot() +
labs(x = "クラス", y = "数学の点数")
plot(bv2)
今度は、箱がバイオリンの線をに重なってしまっている。geom_boxplot()
で width を指定し、箱の幅を狭くしてみよう。
<- ggplot(myd, aes(x = as.factor(class), y = math)) +
bv3 geom_violin() +
geom_boxplot(width = 0.3) +
labs(x = "クラス", y = "数学の点数")
plot(bv3)
これで、箱ひげ図とバイロリンプロットが同時に確認できるようになった。しかし、このままでは箱ひげ図が目立たないので、色を変えよう。
<- ggplot(myd, aes(x = as.factor(class), y = math)) +
bv4 geom_violin() +
geom_boxplot(width = 0.3, fill = "gray") +
labs(x = "クラス", y = "数学の点数")
plot(bv4)
この図を見れば、数学の点数の分布をクラス間で比較できる。
箱ひげ図とバイオリンプロットで、グループ間の分布を比較できるようになった。しかし、観測値が実際にどの値をとったかはわからない。この問題を克服するために使われるのが、ビースウォームプロット (bee swarm plot) である。
ggplotを使ってビースウォームプロットを描くには、ggbeeswarm というパッケージを導入するのが簡単だ。 まず、インストールする(既にインストール済みなら、このコマンドは実行しなくてよい)。
install.packages("ggbeeswarm")
インストールが済んだら、パッケージを読み込む。
library(ggbeeswarm)
ビースウォームプロットは、geom_beeswarm()
またはgeom_quasirandom()
で描く。 これら二つの違いは、点の散らし方である。実際に作って比べてみよう。
<- ggplot(myd, aes(x = as.factor(class), y = math)) +
bee1 geom_beeswarm() +
labs(x = "クラス", y = "数学の点数")
plot(bee1)
<- ggplot(myd, aes(x = as.factor(class), y = math)) +
bee2 geom_quasirandom() +
labs(x = "クラス", y = "数学の点数")
plot(bee2)
ビースウォームプロットでは、全く同じか近い値をとった観測値が重ならないよう、点を散らして (jittering) くれる。その散らし方が、二つの geom で異なる。
これらの図により、分布の中で実際に観測値がどこにあるかが明らかになった。ビースウォームプロットを、箱ひげ図とバイロリンプロットに重ねてみよう。
<- bv4 + geom_quasirandom()
bee3 plot(bee3)
点のせいで箱ひげ図がの線が見えにくいなら、(1) 点の色を変えるか、(2) 点の透明度を上げてみよう。透明度は alpha
で指定する。alpha = 1/3
とすると、点が3つ重なったときに透明度が0(つまり、普通の色)になるなるようになる。
両方同時にやってみよう。
<- bv4 +
bee4 geom_quasirandom(color = "skyblue", alpha = 3/5)
plot(bee4)
男女の点の色を変えてみよう。
<- bv4 +
bee5 geom_quasirandom(aes(color = gender), alpha = 2/3) +
scale_color_discrete(name = "性別", labels = c("女", "男"))
plot(bee5)
これで、分布の形状と五数だけでなく、実際の観測値がどこにあるかまで明らかにできた。
ここまでは、1つの変数を可視化するグラフを作ってきた。続いて、2変数の関係を可視化してみよう。
2変数(2つの量的変数)の関係を可視化するための最も基本的な図は散布図 (scatter plot) である。散布図は、geom_point()
で作る。散布図のaes
には、横軸の変数 x
と縦軸の変数 y
を指定する。
数学の点数(横軸)と英語の点数(縦軸)の関係を散布図にしみてよう。
<- ggplot(myd, aes(x = math, y = english)) +
scat1 geom_point() +
labs(x = "数学の得点", y = "英語の得点")
plot(scat1)
英語も数学も100点満点の試験なのに、図が横長になっていて数学の得点の範囲の方が広く見えてしまう。 この点を改善するために、xlim()
と ylim()
で横軸と縦軸の範囲を指定し、coord_fixed(ratio = 1)
で縦横比を1:1にしよう(ratio = 1 はデフォルトなので、単に coord_fixed()
でもいいが、比がはっきりわかるようにここでは明示しておく)。
<- scat1 + xlim(0, 100) + ylim(0, 100) +
scat2 coord_fixed(ratio = 1)
plot(scat2)
男女の点を、色 (color) と形 (shape) で区別してみよう。
まず、色で区別する。
<- ggplot(myd, aes(x = math, y = english, color = gender)) +
scat3 geom_point() +
labs(x = "数学の得点", y = "英語の得点") +
scale_color_discrete(name = "性別", labels = c("女", "男")) +
xlim(0, 100) + ylim(0, 100) + coord_fixed(ratio = 1)
plot(scat3)
これで一応色分けはできたが、色があまり気に入らない。 特に、赤と緑を区別できない人がいると思われるので、scale_color_brewer()
で色使い (color paletter) を Accent に変えてみよう。指定できるパレットについては、このページ を参照されたい。
<- ggplot(myd, aes(x = math, y = english, color = gender)) +
scat3a geom_point() +
labs(x = "数学の得点", y = "英語の得点") +
scale_color_brewer(palette = "Accent", name = "性別", labels = c("女", "男")) +
xlim(0, 100) + ylim(0, 100) + coord_fixed(ratio = 1)
plot(scat3a)
色分けができた。試しにもう1つ異なるパレットを作ってみよう。Set1
を使ってみる。
<- ggplot(myd, aes(x = math, y = english, color = gender)) +
scat3b geom_point() +
labs(x = "数学の得点", y = "英語の得点") +
scale_color_brewer(palette = "Set1", name = "性別", labels = c("女", "男")) +
xlim(0, 100) + ylim(0, 100) + coord_fixed(ratio = 1)
plot(scat3b)
「男は青で女は赤」というステレオタイプが気にいらないなら、色を逆にしてみよう。パレットに用意された色を使う順番を、direction = -1
で逆順にできる。
<- ggplot(myd, aes(x = math, y = english, color = gender)) +
scat3c geom_point() +
labs(x = "数学の得点", y = "英語の得点") +
scale_color_brewer(palette = "Set1", direction = -1,
name = "性別", labels = c("女", "男")) +
xlim(0, 100) + ylim(0, 100) + coord_fixed(ratio = 1)
plot(scat3c)
次に、形で区別する。
<- ggplot(myd, aes(x = math, y = english, shape = gender)) +
scat4 geom_point() +
labs(x = "数学の得点", y = "英語の得点") +
scale_shape_discrete(name = "性別", labels = c("女", "男")) +
xlim(0, 100) + ylim(0, 100) + coord_fixed(ratio = 1)
plot(scat4)
最後に、色と形で区別する。
<- ggplot(myd, aes(x = math, y = english, color = gender, shape = gender)) +
scat5 geom_point() +
labs(x = "数学の得点", y = "英語の得点") +
scale_color_brewer(palette = "Accent", direction = -1,
name = "性別", labels = c("女", "男")) +
scale_shape_discrete(name = "性別", labels = c("女", "男")) +
xlim(0, 100) + ylim(0, 100) + coord_fixed(ratio = 1)
plot(scat5)
このように、ggplot2を使えば簡単に綺麗な図を作ることができる。
慣れるまではggplot2での作図を面倒に感じるかもしれないが、慣れてしまえばggplotが手放せなくなるだろう。