library(tidyverse)
はじめに
今回はtidyr
のpivot_longer()
を使ってワイド形式のデータをロング形式にする方法をご紹介します。
使用するパッケージ
tidyverse
を使用します。tidyverse
にはdplyr
やtidyr
をはじめとした諸パッケージが含まれているので、一括でやるのが便利で僕は好きです。
データの準備
今回は適当に作成していきます。
<- tibble(
df Region_id = 1:2,
Region = c("Region1", "Region2"),
income_2000 = c(40000, 35000),
income_2005 = c(42000, 37000),
income_2010 = c(45000, 39000),
population_2000 = c(500000, 450000),
population_2005 = c(520000, 460000),
population_2010 = c(540000, 470000)
)
Region_id | Region | income_2000 | income_2005 | income_2010 | population_2000 | population_2005 | population_2010 |
---|---|---|---|---|---|---|---|
1 | Region1 | 40000 | 42000 | 45000 | 500000 | 520000 | 540000 |
2 | Region2 | 35000 | 37000 | 39000 | 450000 | 460000 | 470000 |
2つの地域について収入と人口のデータを作りました。
ポイントは、主要なデータにおいて変数名_年
となっていることです。
pivot_longer()
を使う
一番ベーシックなやり方は次の通りです。
<- df |>
df_long pivot_longer(
cols = starts_with(c("income_", "population_")),
names_to = c(".value", "year"),
names_sep = "_"
)
cols
ではロング形式に変換したい変数を指定しています。dplyr
のstarts_with()
を使えば、複数年分の変数を一括で指定することができます。今回はincome_
とpopulation_
で始まる変数という意味です。
names_to
は新しい列名をどうするかを指定しています。names_sep
で分割の区切りを指定しているのですが(この場合はアンダースコア)、その区切り前なら.value
(すなわち、もとの名前のまま1)、区切り後はYear
という列に格納するという意味です。
できたデータフレームは次のようになります。
Region_id | Region | year | income | population |
---|---|---|---|---|
1 | Region1 | 2000 | 40000 | 500000 |
1 | Region1 | 2005 | 42000 | 520000 |
1 | Region1 | 2010 | 45000 | 540000 |
2 | Region2 | 2000 | 35000 | 450000 |
2 | Region2 | 2005 | 37000 | 460000 |
2 | Region2 | 2010 | 39000 | 470000 |
もし仮に、ロング形式に変換したい変数がすべてアンダースコアで区切られている場合2、cols = contain("_")
とすれば、変数が多くても一気に指定することができます。ただ今回の場合、Region_id
がありますからうまくいきませんね。使える場面は限られそうです。
もしくは
今は具体的にincome_
などと指定しましたが、変数がたくさんあると手動で書くのも大変かと思います。もし何列目を変えたいのかわかっていれば、列の番号で指定することも可能です。
<- df |>
df_long pivot_longer(
cols = 3:8,
names_to = c(".value", "year"),
names_sep = "_"
)
Region_id | Region | year | income | population |
---|---|---|---|---|
1 | Region1 | 2000 | 40000 | 500000 |
1 | Region1 | 2005 | 42000 | 520000 |
1 | Region1 | 2010 | 45000 | 540000 |
2 | Region2 | 2000 | 35000 | 450000 |
2 | Region2 | 2005 | 37000 | 460000 |
2 | Region2 | 2010 | 39000 | 470000 |
cols = 3:8
で3~8列目を対象に変換するということが可能になっています。
アンダースコアが2つ以上ある場合
<- tibble(
df id = 1,
income_hoge_2020 = 100,
income_hoge_2021 = 110,
population_fuga_2020 = 1000,
population_fuga_2021 = 1050
)
id | income_hoge_2020 | income_hoge_2021 | population_fuga_2020 | population_fuga_2021 |
---|---|---|---|---|
1 | 100 | 110 | 1000 | 1050 |
こんな感じでアンダースコアが2つ以上ある場合に先ほどのコードを使うと、意図せぬ分割が起きてしまう可能性があります。そうした場合は正規表現を用いて指定することで対処可能です。
ここでは変数の末がhoge_fuga_2025
のようになんちゃら_年
のような形になっていることを仮定します。
<- df |>
df_long pivot_longer(
cols = 2:5,
names_to = c(".value", "year"),
names_pattern = "^(.*)_(\\d{4})$"
)
id | year | income_hoge | population_fuga |
---|---|---|---|
1 | 2020 | 100 | 1000 |
1 | 2021 | 110 | 1050 |
このようにnames_pattern = "^(.*)_(\d{4})$"
とすること1つ目のアンダースコアを残したまま変換することが可能です。正規表現はややこしいので、このおまじないで最後のアンダースコアを境に分離できるんだ、くらいの解釈でよいと思います。
あまりないかもしれませんが、2つのアンダースコアで挟まれた部分が要らない場合は
<- df |>
df_long pivot_longer(
cols = 2:5,
names_to = c(".value", "year"),
names_pattern = "^(.*)_.*_(\\d{4})$"
)
id | year | income | population |
---|---|---|---|
1 | 2020 | 100 | 1000 |
1 | 2021 | 110 | 1050 |
とすれば省くこともできます。正規表現が少し長くなってるのが違いです。
おまけ
この方法でロング形式にしたデータはyear
がキャラクター型になっているので、mutate(year = as.integer(year))
等でクラスを変えておくことをお忘れなく…。
income
などの値はnumeric型になっています。
おわりに
今回はワイド形式のデータフレームをロング形式に変換する方法をご紹介しました。
僕自身pivot_longer()
を使う時いつも何を指定すればいいんだっけ?となりがちです😅
ご参考まで。