【tidyr】gather?, spread? もう古い。時代はpivot


# tidyr 1.0.0公開
皆さん、**Tidyverse**使ってますか？網羅的な統計処理を遂行するためにR, 特にTidyverseは非常に有効なツールです。先日Tidyverseの作成者である**Hadley(神)**がtidyrのアップデートを行いました。その中でも一番大きい変化は今まで用いられてきた```gather()```, ```spread()```関数が```pivot_longer()```, ```pivot_wider()```に変更されたことではないでしょうか？
**今回の記事ではこれらの関数が今までのものとどのように変わったかを簡単に解説します。**また、次回以降の記事ではpivot_*()についてのユニークな機能についても書いていこうと思っています。

# TL;DR

**基本的な使い方に関して、大きな変更は無いよ！** でも引数がよりわかりやすくなったからコードの可読性がアップしたよ！やったね！

# gather(), spread() → pivot_longer(), pivot_wider()
```gather()```関数はみなさんもよくご存じの通り、messy data (雑然データ)を**tidy data (整然データ)**とするために必須と言える関数です(```reshape2::melt()```みたいなものもありますが)。例えば、

```{messy.R}
library(tidyverse)

df <- tibble("country" = c("a", "b", "c"),
             "1999" = c(0.7, 0.3, 1.0),
             "2000" = c(1.0, 2.0, 4.8),
             "2001" = c(2.0, 5.0, 7.0))
df

# A tibble: 3 x 4
  country `1999` `2000` `2001`
  <chr>    <dbl>  <dbl>  <dbl>
1 a          0.7    1        2
2 b          0.3    2        5
3 c          1      4.8      7
```

というようなmessy dataを考えてみましょう。これをtidy dataとするには、

```{gather.R}
library(tidyverse)

df %>%
  gather(-country, key = "year", value = "amount")

# A tibble: 9 x 3
  country year  amount
  <chr>   <chr>  <dbl>
1 a       1999     0.7
2 b       1999     0.3
3 c       1999     1  
4 a       2000     1  
5 b       2000     2  
6 c       2000     4.8
7 a       2001     2  
8 b       2001     5  
9 c       2001     7  
```

とすることで見事にデータ処理のしやすいtidy dataが出力されます。この```gather()```関数は引数として、```data, key, value```を取ります。今回の場合ですと、*「country列以外の列についてyear列を新たに設定し、表中の値をamount列に格納する」*という処理を施しています。...が、これらの処理を引数から予測しづらいことが問題となっていました。実際に、公式のドキュメントにおいても、

>For some time, it’s been obvious that there is something fundamentally wrong with the design of spread() and gather(). Many people don’t find the names intuitive and find it hard to remember which direction corresponds to spreading and which to gathering. It also seems surprisingly hard to remember the arguments to these functions, meaning that many people (including me!) have to consult the documentation every time.

テキトー訳
> どう見ても明らかなように```spread()```, ```gather()```関数は**根本的な設計ミスってた**わ。関数名がわかりにくく、どのように表が変化していくかを予測しにくいし、引数なんて覚えらんないから自分含め多くの人がドキュメント見てるわ。

とまぁ、惨憺な言われようです。そこで神が作り出したのが**```pivot_*()```**関数です。従来の```gather()```に相当するものは```pivot_longer()``` です。使い方を見てみましょう。

```{pivot_longer.R}
library(tidyverse)

df_longer <- df %>%
  pivot_longer(col = -country, names_to = "year", values_to = "amount")

df_longer

# A tibble: 9 x 3
  country year  amount
  <chr>   <chr>  <dbl>
1 a       1999     0.7
2 a       2000     1  
3 a       2001     2  
4 b       1999     0.3
5 b       2000     2  
6 b       2001     5  
7 c       1999     1  
8 c       2000     4.8
9 c       2001     7 
```

基本的に、 ```pivot_longer()```は```gather()```と同様の書き方をすれば良いことがわかります。しかし引数の名前が```data, key, value```から```col, names_to, values_to```という比較的容易に引数から内容を把握できるものに改善されています。もし、このtidy dataをもとに戻したい場合は```pivot_wider()```を使います。従来では```spread()```がその役割を担っていました。しかし、その引数がまたもや```data, key, value```だったので、```pivot_wider()```では```col, names_from, values_from```に変更となりました。

```{pivot_wider.R}
library(tidyverse)

df_wider <- df_longer %>%
  pivot_wider(names_from = "year", values_from = "amount")

df_wider

# A tibble: 3 x 4
  country `1999` `2000` `2001`
  <chr>    <dbl>  <dbl>  <dbl>
1 a          0.7    1        2
2 b          0.3    2        5
3 c          1      4.8      7
```

このように、引数名がより明確になったことでコードの可読性が向上したことがわかります。基本的な記法は変化していないことから、従来からtidyrを使用している人たちも簡単に移行できると思います。[次回](https://qiita.com/yanami/items/c9a5161fc84871c0445f)は```pivot_longer()```のユニークな機能について書いていこうと思います。