tidyr

tidyr #

tidyrは字の如く,与えられたデータフレーム(tibble)をtidy dataに整形するのに抜群の効果を発揮します.

wide dataとlong data #

実際にtidyではないデータを用いて,tidyrの力を実感してみましょう. 以下の表は,ある生徒のテスト成績表です.

namemathscience
Alice8090
Bob7085
Charlie3040

この表は一見 tidy data に見えますが,原則に合致していない部分があります.

tidy dataの3原則
  1. 一つの変数は一つの列に(Each variable must have its own column.)
  2. 一つの観測は一つの行に(Each observation must have its own row.)
  3. 一つの値は一つのセルに(Each value must have its own cell.)

この表では,2と3の原則は保たれていますが,1番目の 一つの変数は一つの列に(Each variable must have its own column.) の原則が厳密には満たされていません. mathの列を例に見てみると,この列は数学の得点の列です.単位をつけるとするならば点数の列であり,数学そのものの属性を表している列ではありません.仮にmath_scoreのように列名をつけるとすると,単位と列名が合致している分,辻褄は取れています.しかし数学の得点と言う列は,教科と得点と言う二つの要素が混ざった列になってしまっています.

そこで以下の表のように,教科と得点と言う混ざった2要素を,subjectscoreと言う2つの列にそれぞれ分割します.こうすることで,元の表の内容を保ったまま,tidy dataに整形することができました.

namesubjectscore
Alicemath80
Alicescience90
Bobmath70
Bobscience85
Charliemath30
Charliescience40

このように,二つに分割される前の横長の表データのことをwide data,分割後の縦長のデータをlong data (narrow data)といいます.それぞれがtidy dataの原則と合致するわけではないのですが,long dataの方がtidyであることが多い印象です.また,人間の目からしてみるとwide dataの方が直感的なことが多いです.そのため,wide dataの方が人間にとっては見やすいけどlong data形式にしないと解析がしづらいといった問題が度々生じ得ます.この2つの形式を,互いに変換しあって,上手く乗りこなしていく必要があります.

pivot_longer #

それでは実際にwide dataをlong dataに書き直してみましょう.それにはtidyrpivot_longer関数を使います.

library(tidyverse)

wide_data <- tibble(
    name = c("Alice", "Bob", "Charlie"),
    math = c(80, 70, 30),
    science = c(90, 85, 40),
)

long_data <- wide_data |>
                pivot_longer(
                    cols = c(math, science),
                    names_to = "subject",
                    values_to = "score"
                )

print(long_data)

このコードの動きは上の動画を見ていただくとわかりやすいと思います.cols引数で指定された元の表の列名が,新しい表ではsubject列に収まっています.また,元の表の値は新しく指定されたscore列に収まっています.このように,cols引数で,分割したい元の列名を指定し,それぞれ収納先の列名を新しくつけてやる必要があります.

colsの指定方法

上記の例の他にもう一つ,colsの指定方法があります.それは,分割したくない列名の頭に!をつけることです.!論理型の説明にもあったように否定を表す記号です.こうすることによって以下の例ではname列以外を分割するように指定できます.

long dataに変換する際は多くの列名を指定することが多いため,分割しない列名を指定した方が記述がスッキリします.

df |>
    pivot_longer(
        cols = !name,
        names_to = "subject",
        values_to = "score"
    )

pivot_wider #

pivot_wider関数はpivot_longer関数の逆の操作をします.つまりはlong dataからwide dataへの変換を行うことができます.

library(tidyverse)

wide_data <- long_data |>
                pivot_wider(
                    names_from = subject,
                    values_from = score
                )

print(wide_data)

names_fromで指定した列から新たな列名を作り,values_fromで指定した列から新たな値を取り出します.

このようにpivot_longerpivot_widerは,それぞれ逆の操作となっています.