よく使う&いつも忘れるtidyverseのイディオム集。
複数列を一挙に処理する
多変量データを扱う場合には、各変数をチマチマ処理していたのではらちがあかない(IS2010ベースライン特徴量は1592もある)。そこで _all とか _at の出番。
各列を標準化する
Sepal.Length列からPetal.Width列までをそれぞれ標準化(平均0,標準偏差1)する。mutate_atを使う。mutate_each は古いやり方。
library(tidyverse)
iris %>%
mutate_at(vars(Sepal.Length:Petal.Width), scale)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 -0.89767388 1.01560199 -1.33575163 -1.3110521482 setosa
2 -1.13920048 -0.13153881 -1.33575163 -1.3110521482 setosa
3 -1.38072709 0.32731751 -1.39239929 -1.3110521482 setosa
4 -1.50149039 0.09788935 -1.27910398 -1.3110521482 setosa
.
.
.
標準化でなく中心化(平均0)をしたい場合、x - mean(x) という関数を ~ で作ればよい。
iris %>%
mutate_at(vars(Sepal.Length:Petal.Width), ~ (. - mean(.)))
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 -0.74333333 0.44266667 -2.358 -0.9993333333 setosa
2 -0.94333333 -0.05733333 -2.358 -0.9993333333 setosa
3 -1.14333333 0.14266667 -2.458 -0.9993333333 setosa
4 -1.24333333 0.04266667 -2.258 -0.9993333333 setosa
各列の平均と標準偏差を求める
Sepal.Length列からPetal.Width列までの平均を品種ごとに求める。
iris %>%
group_by(Species) %>%
summarise_at(vars(Sepal.Length:Petal.Width),mean)
Species Sepal.Length Sepal.Width Petal.Length Petal.Width
1 setosa 5.01 3.43 1.46 0.246
2 versicolor 5.94 2.77 4.26 1.33
3 virginica 6.59 2.97 5.55 2.03
品種ごとの平均を元のデータに新しい列として加えたい場合には summarise は使えない。1つの変数だけなら mutate で簡単だが、複数列に対して一挙に生成したい場合には、 mutate_at の関数リストを指定するところで、新しい列の名前に付ける接尾辞を指定する。下の例では、各列の品種ごとの平均値を表す列に _mu
を付けるように指定している。
iris %>%
group_by(Species) %>%
mutate_at(vars(Sepal.Length:Petal.Width),funs(mu=mean))
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
.
.
.
Sepal.Length_mu Sepal.Width_mu Petal.Length_mu Petal.Width_mu
1 5.006 3.428 1.462 0.246
2 5.006 3.428 1.462 0.246
3 5.006 3.428 1.462 0.246
4 5.006 3.428 1.462 0.246
.
.
.
複数の関数を適用してそれぞれ新しい列として加えたい場合には、関数リストに関数名を並べて書く。このときは、新しい列の名前に付ける接尾辞は省略してもよい(勝手に関数名と同じ接尾辞が付く)。
iris %>%
group_by(Species) %>%
mutate_at(vars(Sepal.Length:Petal.Width),funs(mean,sd))
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
.
.
.
Sepal.Length_mean Sepal.Width_mean Petal.Length_mean
1 5.006 3.428 1.462
2 5.006 3.428 1.462
3 5.006 3.428 1.462
4 5.006 3.428 1.462
.
.
.
Petal.Width_mean Sepal.Length_sd Sepal.Width_sd Petal.Length_sd
1 0.246 0.3524897 0.3790644 0.173664
2 0.246 0.3524897 0.3790644 0.173664
3 0.246 0.3524897 0.3790644 0.173664
4 0.246 0.3524897 0.3790644 0.173664
.
.
.
Petal.Width_sd
1 0.1053856
2 0.1053856
3 0.1053856
4 0.1053856
最大値を取る列を見つける
anscombeデータセットを利用して適当に作ったデータで説明する。
anscombe %>%
select(y1:y4) %>%
mutate(id=rownames(.)) -> data
print(data)
y1 y2 y3 y4 id
1 8.04 9.14 7.46 6.58 1
2 6.95 8.14 6.77 5.76 2
3 7.58 8.74 12.74 7.71 3
4 8.81 8.77 7.11 8.84 4
5 8.33 9.26 7.81 8.47 5
6 9.96 8.10 8.84 7.04 6
7 7.24 6.13 6.08 5.25 7
8 4.26 3.10 5.39 12.50 8
9 10.84 9.13 8.15 5.56 9
10 4.82 7.26 6.42 7.91 10
11 5.68 4.74 5.73 6.89 11
戦略は以下の通り。
- long形式にする前にidを振っておく。(各例に名前が付いたデータなら不要)
- pivot_longer でlong形式に変換する。以前ならgatherを使う場面。これで、各例ごとに1変数1行のデータになる。
- 各例ごとに which.maxで何行目が最大かを見つけ、slice でその行だけ取り出す。
- これを元のwide形式のデータに right_join で注入する。
data %>%
mutate(id=rownames(.)) %>%
group_by(id) %>%
pivot_longer(y1:y4,names_to="variable",values_to="value") %>%
mutate(variable=as_factor(variable)) %>%
slice(which.max(value)) %>%
rename(argmax=variable,max=value) %>%
ungroup() %>%
right_join(data,by="id") %>%
select(-id)
argmax max y1 y2 y3 y4
1 y2 9.14 8.04 9.14 7.46 6.58
2 y2 8.14 6.95 8.14 6.77 5.76
3 y3 12.74 7.58 8.74 12.74 7.71
4 y4 8.84 8.81 8.77 7.11 8.84
5 y2 9.26 8.33 9.26 7.81 8.47
6 y1 9.96 9.96 8.10 8.84 7.04
7 y1 7.24 7.24 6.13 6.08 5.25
8 y4 12.50 4.26 3.10 5.39 12.50
9 y1 10.84 10.84 9.13 8.15 5.56
10 y4 7.91 4.82 7.26 6.42 7.91
11 y4 6.89 5.68 4.74 5.73 6.89
(続く)