tidyverse tips

よく使う&いつも忘れるtidyverseのイディオム集。

# 複数列を一挙に処理する
多変量データを扱う場合には、各変数をチマチマ処理していたのではらちがあかない(IS2010ベースライン特徴量は1592もある)。そこで \_all とか \_at の出番。

## 各列を標準化する
Sepal.Length列からPetal.Width列までをそれぞれ標準化(平均0,標準偏差1)する。[mutate\_at](https://dplyr.tidyverse.org/reference/mutate_all.html)を使う。mutate\_each は古いやり方。

```r
library(tidyverse)
iris %>%
  mutate_at(vars(Sepal.Length:Petal.Width), scale)
```

```console
    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) という関数を [~](https://adv-r.hadley.nz/functionals.html#purrr-shortcuts) で作ればよい。

```r
iris %>%
  mutate_at(vars(Sepal.Length:Petal.Width), ~ (. - mean(.)))
```

```console
    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列までの平均を品種ごとに求める。

```r
iris %>%
  group_by(Species) %>%
  summarise_at(vars(Sepal.Length:Petal.Width),mean)
```

```console
  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](https://dplyr.tidyverse.org/reference/summarise.html) は使えない。1つの変数だけなら [mutate](https://dplyr.tidyverse.org/reference/mutate.html) で簡単だが、複数列に対して一挙に生成したい場合には、 mutate\_at の[関数リスト](https://dplyr.tidyverse.org/reference/funs.html)を指定するところで、新しい列の名前に付ける接尾辞を指定する。下の例では、各列の品種ごとの平均値を表す列に `_mu` を付けるように指定している。

```r
iris %>%
  group_by(Species) %>%
  mutate_at(vars(Sepal.Length:Petal.Width),funs(mu=mean))
```

```console
  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
.
.
.
```

複数の関数を適用してそれぞれ新しい列として加えたい場合には、関数リストに関数名を並べて書く。このときは、新しい列の名前に付ける接尾辞は省略してもよい(勝手に関数名と同じ接尾辞が付く)。

```r
iris %>%
  group_by(Species) %>%
  mutate_at(vars(Sepal.Length:Petal.Width),funs(mean,sd))
```

```console
  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データセットを利用して適当に作ったデータで説明する。

```r
anscombe %>%
  select(y1:y4) %>%
  mutate(id=rownames(.)) -> data
print(data)
```

```console
      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
```

戦略は以下の通り。

1. long形式にする前にidを振っておく。(各例に名前が付いたデータなら不要)
1. [pivot\_longer](https://tidyr.tidyverse.org/reference/pivot_longer.html) でlong形式に変換する。以前ならgatherを使う場面。これで、各例ごとに1変数1行のデータになる。
1. 各例ごとに which.maxで何行目が最大かを見つけ、[slice](https://dplyr.tidyverse.org/reference/slice.html) でその行だけ取り出す。
1. これを元のwide形式のデータに [right_join](https://dplyr.tidyverse.org/reference/join.html) で注入する。

```r
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)
```

```console
   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
```

(続く)