論文作成・統計

【R初心者向け】慣れると便利なtidyrのpivot_longerとgatherをやさしく解説!

データの構造を変える時に有用なのがtidyrというパッケージです。横に広いデータを縦長のデータに変更するpivot_longerまたはgatherを使います。

tidyr本家のホームページにはgatherやspreadの関数の代わりに、
pivot_longer()をpivot_wider()を使うことが推奨されています。

Development on gather() is complete, and for new code we recommend switching to pivot_longer(), which is easier to use, more featureful, and still under active development.

https://tidyr.tidyverse.org/reference/gather.html

pivotal_longerだけ覚えたいという方は途中のgatherを読み飛ばしてください

便利なtidyverseに入っていますので、これを利用していきましょう。ではRStudioを開いて準備をしていきます。

データセットの準備

crop diverse female students fulfilling homework together in park

まずは作業ディレクトリをセットして、tidyverseを起動しています。

setwd("~/Rpractice/")
library(tidyverse)

次にアヤメのサンプルデータを使っていきましょう。head()でデータのはじめのほうを表示します。

a <- iris
> head(a)
  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
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa

summary()も便利です。

> summary(a)
  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width          Species  
 Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100   setosa    :50  
 1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300   versicolor:50  
 Median :5.800   Median :3.000   Median :4.350   Median :1.300   virginica :50  
 Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199                  
 3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800                  
 Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500                  
> 

Minは最小値、1st Quは第一四分位数、Medianは中央値、Meanは平均値、3rd Quは第三四分位数、Maxは最大値です。QuはQuartileですね。

Speciesにsetosa、versicolor、virginicaがあり、それぞれ50ずつのデータが入っていることもわかります。データすべてを確認するには、View()を使ってみてください。

View(a)

データのはじめにIDを入れる

time for change sign with led light

これから並び替えをしますので、IDを入れておくと混乱は避けることができます。またspreadを使うときにもIDとなるものが必要です。

tidyverseの中のdplyrを使ってみます。その中にmutateというファンクションがあります。

a2 <- a %>%
dplyr::mutate(a, ID=rownames(a)) 

またはtibbleというパッケージのrownames_to_columnでもいけます

tibbleもtidyverseの中の一つです。

a2 <- a %>%
tibble::rownames_to_column(var = "ID")

初心者の間はこういうものがあるんだ、くらいの感覚でいいと思います。またわからなくなったらここに戻ってきて参照してください。

%>%はパイプまたはパイプ演算子と呼びます。一つ前の出力を次のプログラムに代入します。

パイプを使うことでデータを指定すべきことを省略できます。一つ前の出力をそのまま代入できる便利モノです。下の2つは同じ意味です。

a2 <- a %>%
tibble::rownames_to_column(var = "ID")
a2 <- tibble::rownames_to_column(a, var = "ID")

RStudioではShift + Ctrl + Mを押すと%>%が出てきます。出力を縦に流れるようにつないで行くことができます。

x <- a %>% 
  group_by(Species) %>% 
  dplyr::summarise_each(funs(mean, sd), Sepal.Length, Sepal.Width)

> x
# A tibble: 3 x 5
  Species    Sepal.Length_mean Sepal.Width_mean Sepal.Length_sd Sepal.Width_sd
  <fct>                  <dbl>            <dbl>           <dbl>          <dbl>
1 setosa                  5.01             3.43           0.352          0.379
2 versicolor              5.94             2.77           0.516          0.314
3 virginica               6.59             2.97           0.636          0.322
> 

gatherで縦のデータにする

tidyrパッケージのgatherを使っていきましょう

df %>% gather("key", "value", x, y, z)で使います。それではアヤメデータで使っていきましょう。

b <- a2 %>%
  tidyr::gather(key = FlowerAtt, 
                value = Values, 
                Sepal.Length:Petal.Width)

> head(b)
  ID Species    FlowerAtt Values
1  1  setosa Sepal.Length    5.1
2  2  setosa Sepal.Length    4.9
3  3  setosa Sepal.Length    4.7
4  4  setosa Sepal.Length    4.6
5  5  setosa Sepal.Length    5.0
6  6  setosa Sepal.Length    5.4
> 

このkey、valueがはじめのうちはよくわからないと思います。

後ろ(下)から説明をします。

3番目の入力Sepal.Length:Petal.Widthは縦に並べたい変数名です。

2番目のvalueは変数名で、数値の入った列に名前をつけます

最初のkeyは横並びしていた変数名が縦に並んだ、その列について名前をつけます

FlowerAttのAttはAttributeですが、keyは自分の付けたい名前をつけることができます。

コロンの使い方は、例えばABCDEと並んでいたときに、A:Eと書くというもので、下の書き方と同じです。

Sepal.Length:Petal.WidthはSepal.Length、Sepal.Width、Petal.Length、Petal.Widthになります。

b <- a2 %>%
  tidyr::gather(key = FlowerAtt, 
                Value = Values, 
                Sepal.Length, Sepal.Width, Petal.Length, Petal.Width)

次になにかを残したいときは、項目名の前に-をつけます。例えばSepal.WidthとPetal.Lengthを残したいときには次のようにかきます。

c <- a2 %>%
  tidyr::gather(key = FlowerAtt, 
                value = Values, 
                Sepal.Length:Petal.Width, 
                -Sepal.Width, -Petal.Length)

> head(c)
  ID Sepal.Width Petal.Length Species  FlowerAtt Values
1  1         3.5          1.4  setosa Sepal.Length    5.1
2  2         3.0          1.4  setosa Sepal.Length    4.9
3  3         3.2          1.3  setosa Sepal.Length    4.7
4  4         3.1          1.5  setosa Sepal.Length    4.6
5  5         3.6          1.4  setosa Sepal.Length    5.0
6  6         3.9          1.7  setosa Sepal.Length    5.4
>

除外したSepal.WidthとPetal.Lengthが残っているのがわかります。

Pivotal_longerで縦長のデータに変形をする

gatherは直感的にわかりにくく、また引数も覚えにくいので、開発者自身も毎回ドキュメンテーションを見ないといけない、という趣旨のことが書いてあります(笑)。

それをより使いやすくしたのが、pivot_longerです。こちらだけ覚えていいと思います。

pivot_longer(data, cols, names_to = "name", values_to = "value")

colsは縦長に変形をする列を記載します(アヤメのデータではSepal.Length、Sepal.Widthなどです)。

names_toでは、縦長にした列名の列に新しい名前をつけます(上の例ではFlowerAttとつけていました)。

values_toは縦長になった変数の列に名前をつけます(Valuesとつけていました)。

ではやってみましょう。

A <- a2 %>% 
  pivot_longer(cols = Sepal.Length:Petal.Width, 
               names_to = "FlowerAtt", 
               values_to = "Values")

> head(A)
# A tibble: 6 x 4
  ID    Species FlowerAtt    Values
  <chr> <fct>   <chr>         <dbl>
1 1     setosa  Sepal.Length    5.1
2 1     setosa  Sepal.Width     3.5
3 1     setosa  Petal.Length    1.4
4 1     setosa  Petal.Width     0.2
5 2     setosa  Sepal.Length    4.9
6 2     setosa  Sepal.Width     3  
> 

colsの複数指定の方法はいくつかあるようですが、 個別に指定する方法を示します。
cols = c()で項目名を個別に指定をすることができます。

A <- a2 %>% 
  pivot_longer(cols = c(Sepal.Length, Sepal.Width, 
                        Petal.Length, Petal.Width),
               names_to = "FlowerAtt", 
               values_to = "Values")

変形する列をcolsで指定しましたが、変形しない列を-で指定することもできます。

B <- a2 %>% 
  pivot_longer(cols = -c(ID, Species), 
               names_to = "Measurement", 
               values_to = "Values")

> head(B)
# A tibble: 6 x 4
  ID    Species Measurement  Values
  <chr> <fct>   <chr>         <dbl>
1 1     setosa  Sepal.Length    5.1
2 1     setosa  Sepal.Width     3.5
3 1     setosa  Petal.Length    1.4
4 1     setosa  Petal.Width     0.2
5 2     setosa  Sepal.Length    4.9
6 2     setosa  Sepal.Width     3  
> 

今回細かいオプションは説明をしていませんが、これらができれば十分に便利だと思います。また別の記事でspreadとpivot_widerを紹介します。

お役に立ちましたら幸いです。