このページに対応するRmdファイル:GitHub
パッケージには大別すると次の3種類がある:
base::c
,
utils::str
, etc.)MASS::Boston
,
Matrix::Cholesky
, etc.)
library(パッケージ名)
で読み込んで 関数名
で呼び出すか,パッケージを読み込まずに パッケージ名::関数名
で呼び出すtidyverse
,
data.table
, etc.)
install.packages("パッケージ名")
でインストールし(最初の一度だけ実行),library(パッケージ名)
で読み込む(Rを起動する度に実行)install.packages
が使えない場合,PC
がインターネットに接続されていることを確認したうえで,CRAN
レポジトリを変更してリトライ:Tools > Global Options > Packages
> Primary CRAN repository を 「Japan (Tokyo)」 などに変更(参考:Setting
CRAN repository options)補足:同じ名前の関数が複数のパッケージで使用されている場合があるので,常に
パッケージ名::関数名
の形式でパッケージを指定するのを好む人もいる.
tidyverse
packageデータの整理・操作は tidyverse
というパッケージに含まれる関数を使うのが一般的.
tidyverse
は dplyr
(読み方:“dee-ply-er”) や ggplot2
などの複数のパッケージを束ねたものtidyverse
をインストール/ロードすれば
dplyr
や ggplot2
などが同時にインストール/ロードされるパッケージのインストールは R のインストール後に一度だけ実行する.
install.packages("tidyverse") # run for the first time only
インストール後に R に読み込む. こちらはパッケージのインストールと異なり,R (または RStudio)を起動するたびに実行する.
library(tidyverse)
dplyr
packageデータのハンドリング(または data wrangling)を行うパッケージ.
filter
… 条件に合致する行を抽出select
… 条件に合致する列(変数)を抽出mutate
… 新しい列(変数)を作成rename
… 列(変数)の名前を変更left_join
… 2つのデータセットを統合summarise
… データを要約group_by
… 行をグルーピング
group_by
はそれ単体で使われるわけではなく,通常は
summarise
関数と併用されるこれらの関数は %>%
で表される「パイプ」と呼ばれる演算子と組み合わせて利用されることが多い.
このパイプは tidyverse
パッケージ群を構成するパッケージの一つ magrittr
によって提供されているが,この授業では細かいことを理解する必要はない.
ggplot2
packageデータ可視化のためのパッケージ. plot
のようなデフォルトで使える関数と比べて文法に癖があるが,慣れれば論文に使える程度に綺麗な図を出力できる.
plot
関数はこれ単体でグラフを描画してくれるが,ggplot2
パッケージを使用する場合は ggplot
関数でデータと属性(X軸の変数,Y軸の変数,色に対応する変数,サイズに対応する変数)を指定し,次いで
geom_xxx
関数でジオメトリ(点,線,棒,etc.)を指定するという2段階で描画する.
詳細は Kabacoff (2024) Modern Data Visualization with R などを参照.
data.frame
で作成したデータフレームのオブジェクトよりも少し扱いやすいデータフレーム型オブジェクトを
tibble::tibble
関数で作成できる.
beatles <- tibble::tibble(
name = c("John", "Paul", "George", "Ringo"),
born = c(1940, 1942, 1943, 1940),
decease = c(1980, NA, NA, NA),
height = c(179, 180, 178, 170)
)
beatles
## # A tibble: 4 × 4
## name born decease height
## <chr> <dbl> <dbl> <dbl>
## 1 John 1940 1980 179
## 2 Paul 1942 NA 180
## 3 George 1943 NA 178
## 4 Ringo 1940 NA 170
%>%
tidyverse
スタイルのデータハンドリングでは「パイプ(演算子)」と呼ばれるものが用いられる.
%>%
(大なり記号をパーセント記号で挟んだもの)がパイプと呼ばれる.
「data %>% function
」の形で使用し,パイプの前にある
data
をパイプの後の関数に渡す機能を持つ.
x %>% f()
は f(x)
と(概ね)同じ.デフォルトでは関数の第一引数に渡す.x %>% f(z)
は f(x, z)
と(概ね)同じ.z %>% f(x, .)
は f(x, z)
と(概ね)同じ.第一引数以外の引数に渡す際は .
を使う.mean(x = 1:2) # これまでの書き方.mean(c(1, 2)) と同じ
## [1] 1.5
1:2 %>% mean(x = .) # "." でデータを受ける
## [1] 1.5
1:2 %>% mean() # . が1つ目の引数なら省略可
## [1] 1.5
1:2 %>% mean # () も省略可
## [1] 1.5
c(1, 2, NA) %>% mean(na.rm = TRUE) # option も指定可
## [1] 1.5
逐次的な処理をパイプを用いて表現することができる.
sd(1:2)
## [1] 0.7071068
round(sd(1:2), 2)
## [1] 0.71
1:2 %>% sd %>% round(2)
## [1] 0.71
以下のようにネストが深い場合はパイプを使うことで処理の順序が理解しやすくなる.
\[ \frac{1}{n} \sum_i \log_{10} \sqrt{ |x_i| } \quad \mbox{を小数第2位まで表示} \]
round(mean(log(sqrt(abs(rnorm(n = 1000, mean = 1))), base = 10), na.rm = TRUE), 2)
## [1] -0.05
rnorm(n = 1000, mean = 1) %>% abs %>% sqrt %>% log(base = 10) %>% mean(na.rm = TRUE) %>% round(2)
## [1] -0.05
要するに,パイプを使う目的は,全く新しい種類の計算をすることではなく,既存の計算処理を順序通りに記述する(パイプライン処理する)ことにある.
tidyverse
で提供される関数と組み合わせて以下のサブセクションのように使われることが一般的.filter
残す行(observation)の条件を指定する.
beatles %>% filter(born >= 1941) # 一般的な書き方
## # A tibble: 2 × 4
## name born decease height
## <chr> <dbl> <dbl> <dbl>
## 1 Paul 1942 NA 180
## 2 George 1943 NA 178
filter(beatles, born >= 1941) # 計算結果は同じ
## # A tibble: 2 × 4
## name born decease height
## <chr> <dbl> <dbl> <dbl>
## 1 Paul 1942 NA 180
## 2 George 1943 NA 178
beatles[beatles$born >= 1941, ] # もちろんこれも同じ
## # A tibble: 2 × 4
## name born decease height
## <chr> <dbl> <dbl> <dbl>
## 1 Paul 1942 NA 180
## 2 George 1943 NA 178
filter
を適用した後のデータセットを新しいオブジェクトに割り当てるには
<-
を用いる(上書きも可;以下同様).
beatles_ver2 <- beatles %>% filter(born >= 1941)
beatles_ver2
## # A tibble: 2 × 4
## name born decease height
## <chr> <dbl> <dbl> <dbl>
## 1 Paul 1942 NA 180
## 2 George 1943 NA 178
複数の条件を指定することもできる.
beatles %>% filter(born >= 1941 & height < 180)
## # A tibble: 1 × 4
## name born decease height
## <chr> <dbl> <dbl> <dbl>
## 1 George 1943 NA 178
select
残す列(変数)の名前を指定する.
beatles %>% select(name)
## # A tibble: 4 × 1
## name
## <chr>
## 1 John
## 2 Paul
## 3 George
## 4 Ringo
beatles %>% select(name, born)
## # A tibble: 4 × 2
## name born
## <chr> <dbl>
## 1 John 1940
## 2 Paul 1942
## 3 George 1943
## 4 Ringo 1940
マイナス記号 -
を使って「-変数名
」と指定すると当該変数以外が残る.
beatles %>% select(-height)
## # A tibble: 4 × 3
## name born decease
## <chr> <dbl> <dbl>
## 1 John 1940 1980
## 2 Paul 1942 NA
## 3 George 1943 NA
## 4 Ringo 1940 NA
mutate
新しく列(変数)を作成する.
beatles %>% mutate(primary_role = c("vocal", "vocal", "guitar", "drum"))
## # A tibble: 4 × 5
## name born decease height primary_role
## <chr> <dbl> <dbl> <dbl> <chr>
## 1 John 1940 1980 179 vocal
## 2 Paul 1942 NA 180 vocal
## 3 George 1943 NA 178 guitar
## 4 Ringo 1940 NA 170 drum
既存の変数を利用して新しい変数を作成することもできる.
beatles %>% mutate(age_at_debut = 1962 - born)
## # A tibble: 4 × 5
## name born decease height age_at_debut
## <chr> <dbl> <dbl> <dbl> <dbl>
## 1 John 1940 1980 179 22
## 2 Paul 1942 NA 180 20
## 3 George 1943 NA 178 19
## 4 Ringo 1940 NA 170 22
rename
列(変数)の名前を変える.
beatles %>% rename(birth_year = born)
## # A tibble: 4 × 4
## name birth_year decease height
## <chr> <dbl> <dbl> <dbl>
## 1 John 1940 1980 179
## 2 Paul 1942 NA 180
## 3 George 1943 NA 178
## 4 Ringo 1940 NA 170
left_join
別のデータセットと統合する.
beatles_primary_role <- tibble::tibble(name = c("John", "Paul", "George", "Ringo"),
primary_role = c("vocal", "vocal", "guitar", "drum"))
beatles_primary_role
## # A tibble: 4 × 2
## name primary_role
## <chr> <chr>
## 1 John vocal
## 2 Paul vocal
## 3 George guitar
## 4 Ringo drum
beatles %>% left_join(beatles_primary_role, by = "name")
## # A tibble: 4 × 5
## name born decease height primary_role
## <chr> <dbl> <dbl> <dbl> <chr>
## 1 John 1940 1980 179 vocal
## 2 Paul 1942 NA 180 vocal
## 3 George 1943 NA 178 guitar
## 4 Ringo 1940 NA 170 drum
一方のデータフレームにしかない行がある場合,主たるデータフレーム(マージされる側)の行はそのまま残る.
補足:コードの文法上左側にあるデータセットに合わせてマージするので
left_join
という関数名が使われている.右側に合わせる場合は
right_join
,積集合でマージするのは
inner_join
,和集合でマージするのは
full_join
.
Case 1. 担当楽器のデータセットに欠損がある場合.
beatles_primary_role_wo_paul <- tibble::tibble(name = c("John", "George", "Ringo"),
primary_role = c("vocal", "guitar", "drum"))
beatles_primary_role_wo_paul
## # A tibble: 3 × 2
## name primary_role
## <chr> <chr>
## 1 John vocal
## 2 George guitar
## 3 Ringo drum
beatles %>% left_join(beatles_primary_role_wo_paul, by = "name")
## # A tibble: 4 × 5
## name born decease height primary_role
## <chr> <dbl> <dbl> <dbl> <chr>
## 1 John 1940 1980 179 vocal
## 2 Paul 1942 NA 180 <NA>
## 3 George 1943 NA 178 guitar
## 4 Ringo 1940 NA 170 drum
Case 2. 逆に,主なデータフレームの方に欠損がある場合.
beatles %>%
filter(name != "Paul") %>%
left_join(beatles_primary_role, by = "name")
## # A tibble: 3 × 5
## name born decease height primary_role
## <chr> <dbl> <dbl> <dbl> <chr>
## 1 John 1940 1980 179 vocal
## 2 George 1943 NA 178 guitar
## 3 Ringo 1940 NA 170 drum
summarise
データを要約する.
beatles %>% summarise(mean_height = mean(height),
std_dev_height = sd(height),
sample_size = n())
## # A tibble: 1 × 3
## mean_height std_dev_height sample_size
## <dbl> <dbl> <int>
## 1 177. 4.57 4
group_by
summarise
関数と組み合わせて使うことで,グループごとの要約統計量を計算したり何らかの統計処理を行うことができる.
beatles %>%
group_by(born) %>%
summarise(mean_height = mean(height),
std_dev_height = sd(height),
sample_size = n())
## # A tibble: 3 × 4
## born mean_height std_dev_height sample_size
## <dbl> <dbl> <dbl> <int>
## 1 1940 174. 6.36 2
## 2 1942 180 NA 1
## 3 1943 178 NA 1
まずは ggplot
だけ実行してみる.
データが何も描かれていないキャンバスだけが表示される.
ggplot(data = beatles, mapping = aes(x = born, y = height))
ここに点のレイヤーを geom_point
関数で追加する.
ggplot(data = beatles, mapping = aes(x = born, y = height)) +
geom_point()
軸のラベルを変更する.
ggplot(data = beatles, mapping = aes(x = born, y = height)) +
geom_point() +
xlab("Year of birth")
キャンバスのテーマを変える.
ggplot(data = beatles, mapping = aes(x = born, y = height)) +
geom_point() +
theme_classic()
titanic <- read.csv("https://raw.githubusercontent.com/kurodaecon/bs/main/data/titanic3_csv.csv")
filter
titanic %>% filter(age > 75)
## pclass survived sex age sibsp parch fare embarked
## 1 1 1 male 80 0 0 30.00 S
## 2 1 1 female 76 1 0 78.85 S
group_by
and summarise
性別ごとの生存率.
titanic %>%
group_by(sex) %>%
summarise(survival_rate = mean(survived),
sample_size = n())
## # A tibble: 2 × 3
## sex survival_rate sample_size
## <chr> <dbl> <int>
## 1 female 0.727 466
## 2 male 0.191 843
性別と客室等級ごとの生存率.
titanic %>%
group_by(sex, pclass) %>%
summarise(survival_rate = mean(survived),
sample_size = n())
## # A tibble: 6 × 4
## # Groups: sex [2]
## sex pclass survival_rate sample_size
## <chr> <int> <dbl> <int>
## 1 female 1 0.965 144
## 2 female 2 0.887 106
## 3 female 3 0.491 216
## 4 male 1 0.341 179
## 5 male 2 0.146 171
## 6 male 3 0.152 493
性別と年齢層ごとの生存率.
titanic %>%
mutate(age_group = cut(age, breaks = c(0, 20, 60, 100), right = FALSE)) %>%
group_by(sex, age_group) %>%
summarise(survival_rate = mean(survived),
sample_size = n())
## # A tibble: 8 × 4
## # Groups: sex [2]
## sex age_group survival_rate sample_size
## <chr> <fct> <dbl> <int>
## 1 female [0,20) 0.699 103
## 2 female [20,60) 0.770 274
## 3 female [60,100) 0.818 11
## 4 female <NA> 0.603 78
## 5 male [0,20) 0.279 122
## 6 male [20,60) 0.193 507
## 7 male [60,100) 0.103 29
## 8 male <NA> 0.141 185
性別と客室等級と年齢層ごとの生存率.
titanic %>%
mutate(age_group = cut(age, breaks = c(0, 20, 60, 100), right = FALSE)) %>%
group_by(sex, pclass, age_group) %>%
summarise(survival_rate = mean(survived),
sample_size = n())
## # A tibble: 24 × 5
## # Groups: sex, pclass [6]
## sex pclass age_group survival_rate sample_size
## <chr> <int> <fct> <dbl> <int>
## 1 female 1 [0,20) 0.938 16
## 2 female 1 [20,60) 0.972 108
## 3 female 1 [60,100) 0.889 9
## 4 female 1 <NA> 1 11
## 5 female 2 [0,20) 0.958 24
## 6 female 2 [20,60) 0.885 78
## 7 female 2 [60,100) 0 1
## 8 female 2 <NA> 0.667 3
## 9 female 3 [0,20) 0.540 63
## 10 female 3 [20,60) 0.420 88
## # ℹ 14 more rows
カテゴリー数が多いためにすべて表示されていない. 以下のように表示数を調整できる.
titanic %>%
mutate(age_group = cut(age, breaks = c(0, 20, 60, 100), right = FALSE)) %>%
group_by(sex, pclass, age_group) %>%
summarise(survival_rate = mean(survived),
sample_size = n()) %>%
print(n = 30)
## # A tibble: 24 × 5
## # Groups: sex, pclass [6]
## sex pclass age_group survival_rate sample_size
## <chr> <int> <fct> <dbl> <int>
## 1 female 1 [0,20) 0.938 16
## 2 female 1 [20,60) 0.972 108
## 3 female 1 [60,100) 0.889 9
## 4 female 1 <NA> 1 11
## 5 female 2 [0,20) 0.958 24
## 6 female 2 [20,60) 0.885 78
## 7 female 2 [60,100) 0 1
## 8 female 2 <NA> 0.667 3
## 9 female 3 [0,20) 0.540 63
## 10 female 3 [20,60) 0.420 88
## 11 female 3 [60,100) 1 1
## 12 female 3 <NA> 0.531 64
## 13 male 1 [0,20) 0.6 10
## 14 male 1 [20,60) 0.363 124
## 15 male 1 [60,100) 0.118 17
## 16 male 1 <NA> 0.286 28
## 17 male 2 [0,20) 0.444 27
## 18 male 2 [20,60) 0.0806 124
## 19 male 2 [60,100) 0.143 7
## 20 male 2 <NA> 0.154 13
## 21 male 3 [0,20) 0.188 85
## 22 male 3 [20,60) 0.166 259
## 23 male 3 [60,100) 0 5
## 24 male 3 <NA> 0.111 144
年齢の平均を計算しようとすると NA
が返ってくる.
titanic %>%
summarise(age_mean = mean(age))
## age_mean
## 1 NA
これは年齢変数 age
に NA
が含まれるため.
na.rm = TRUE
引数を追加する.
titanic %>%
summarise(age_mean = mean(age, na.rm = TRUE))
## age_mean
## 1 29.88114
相関係数行列.
titanic %>%
select(age, fare, parch) %>%
cor(use = "complete.obs")
## age fare parch
## age 1.0000000 0.1787399 -0.1502409
## fare 0.1787399 1.0000000 0.2167232
## parch -0.1502409 0.2167232 1.0000000
ggplot2
年齢.
ggplot(data = titanic, mapping = aes(x = age)) +
geom_histogram()
性別ごとに分ける.
ggplot(data = titanic, mapping = aes(x = age, fill = sex)) +
geom_histogram(position = "dodge") +
scale_fill_grey() + # grey scale
theme_classic()
ggplot2
出港地ごとの人数.
titanic %>%
filter(embarked != "") %>%
group_by(embarked) %>%
summarise(person = n()) %>%
ggplot(mapping = aes(x = embarked, y = person)) +
geom_bar(stat = "identity") +
theme_classic()
性別ごとに分ける. ついでにX軸のラベルも修正しておく.
titanic %>%
filter(embarked != "") %>%
group_by(embarked, sex) %>%
summarise(person = n()) %>%
ggplot(mapping = aes(x = embarked, y = person, fill = sex)) +
geom_bar(stat = "identity", position = "dodge") +
scale_x_discrete(labels = c("Cherbourg", "Queenstown", "Southampton")) +
scale_fill_grey() +
theme_classic()
ggplot2
出港地ごとの人数.
titanic %>%
filter(embarked != "") %>%
group_by(embarked) %>%
summarise(person = n()) %>%
ggplot(mapping = aes(x = "x", y = person, fill = embarked)) +
geom_bar(stat = "identity", position = "stack") +
coord_polar(theta = "y") +
scale_fill_brewer(labels = c("Cherbourg", "Queenstown", "Southampton")) +
theme_classic()
ggplot2
性別ごとの年齢.
ggplot(data = titanic, mapping = aes(x = sex, y = age)) +
geom_boxplot()
性別・客室等級ごとの年齢.
ggplot(data = titanic, mapping = aes(x = sex, y = age, fill = factor(pclass))) +
geom_boxplot() +
scale_fill_grey(start = 0.4, end = 0.9) +
theme_classic()
データの分布が複雑な場合(多峰など),バイオリンプロットという選択肢がある.
ggplot(data = titanic, mapping = aes(x = sex, y = age)) +
geom_violin()
ggplot2
ビートルズやSwissデータと同様に散布図を描き,スムージング曲線を追加する.
点同士が重なってしまうため geom_jitter
関数でY軸方向にばらつかせて描画.
ggplot(data = titanic, mapping = aes(x = age, y = survived)) +
geom_point() +
geom_jitter(height = .05, width = 0) +
geom_smooth()
Y軸の survived
は 0/1 の binary 変数なので jitter
は違和感がある. Binned plot はよい代替案だろう.
ggplot(data = titanic, mapping = aes(x = age, y = survived)) +
stat_summary_bin()
性別による死亡率の違いを示す.
ggplot(data = titanic, mapping = aes(x = age, y = survived, color = sex, shape = sex, linetype = sex)) +
geom_point(size = 0.5) +
geom_jitter(height = .05, width = 0) +
geom_smooth(se = FALSE) +
scale_color_brewer(palette = "Dark2") + # colorblind-friendly palette
theme_classic()
50歳代からサンプルサイズが大きく低下するため,フィッティングの曲線は参考にならない点に注意.
客室等級による死亡率の違いを示す.
pclass
は連続変数なので factor
関数で因子型の変数に変換して使う.ggplot(data = titanic, mapping = aes(x = age, y = survived, color = factor(pclass),
shape = factor(pclass), linetype = factor(pclass))) +
geom_point() +
geom_jitter(height = .05, width = 0) +
geom_smooth(se = FALSE) +
scale_color_brewer(palette = "Dark2") +
theme_classic()
Base R (Rインストール時にbuilt-inされている標準パッケージのみを使用し,追加のパッケージを手動でインストールしない状態)でも pipe が使える.
tidyverse
スタイルの
%>%
を用いたデータハンドリングが普及したことを受けて2021年頃に実装された.|>
と書く.|>
|>
は %>%
と同様に直前の値を関数の第一引数に渡す.
1:2 |> mean(x = _) # "_" でデータを受ける
## [1] 1.5
1:2 |> mean() # _ が1つ目の引数なら省略可(注:カッコは省略不可)
## [1] 1.5
c(1, 2, NA) |> mean(na.rm = TRUE) # option も指定可
## [1] 1.5
titanic |> head(2)
## pclass survived sex age sibsp parch fare embarked
## 1 1 1 female 29.00 0 0 211.3375 S
## 2 1 1 male 0.92 1 2 151.5500 S
titanic[, c("survived", "age")] |> cor(use = "complete.obs") |> round(2)
## survived age
## survived 1.00 -0.06
## age -0.06 1.00
subset
corresponding to filter
titanic %>% filter(age >= 75)
## pclass survived sex age sibsp parch fare embarked
## 1 1 1 male 80 0 0 30.00 S
## 2 1 1 female 76 1 0 78.85 S
titanic |> subset(age >= 75)
## pclass survived sex age sibsp parch fare embarked
## 15 1 1 male 80 0 0 30.00 S
## 62 1 1 female 76 1 0 78.85 S
transform
corresponding to mutate
titanic %>% mutate(family = sibsp + parch) %>% head(2)
## pclass survived sex age sibsp parch fare embarked family
## 1 1 1 female 29.00 0 0 211.3375 S 0
## 2 1 1 male 0.92 1 2 151.5500 S 3
titanic |> transform(family = sibsp + parch) |> head(2)
## pclass survived sex age sibsp parch fare embarked family
## 1 1 1 female 29.00 0 0 211.3375 S 0
## 2 1 1 male 0.92 1 2 151.5500 S 3
aggregate
corresponding to group_by
+
summarise
titanic %>% group_by(pclass) %>% summarise(survived_rate = mean(survived))
## # A tibble: 3 × 2
## pclass survived_rate
## <int> <dbl>
## 1 1 0.619
## 2 2 0.430
## 3 3 0.255
titanic |> aggregate(survived ~ pclass, data = _, FUN = mean)
## pclass survived
## 1 1 0.6191950
## 2 2 0.4296029
## 3 3 0.2552891
注:上記の対比だけを見ると tidyverse
スタイルのデータ処理が不要であるかのように見えるかもしれないが,実際にはそんなことはない.
上記のような単純な処理であれば Base R
の標準的な関数だけでも事足りる場合もあるが,複雑な処理をする上では
tidyverse
を使った方がよい.