【データハンドリング】pivot_longer()を使ってロング形式のパネルデータを作る【使い方】

ワイドからロングへ、データを変換します。

R
データ処理
公開

2024年9月17日

最終更新

2025年3月24日

はじめに

今回はtidyrpivot_longer()を使ってワイド形式のデータをロング形式にする方法をご紹介します。

使用するパッケージ

tidyverseを使用します。tidyverseにはdplyrtidyrをはじめとした諸パッケージが含まれているので、一括でやるのが便利で僕は好きです。

library(tidyverse)

データの準備

今回は適当に作成していきます。

df <- tibble(
  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)
)
表 1: ワイド形式のパネルデータ
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_long <- df |> 
  pivot_longer(
    cols = starts_with(c("income_", "population_")), 
    names_to = c(".value", "year"), 
    names_sep = "_"
  )

colsではロング形式に変換したい変数を指定しています。dplyrstarts_with()を使えば、複数年分の変数を一括で指定することができます。今回はincome_population_で始まる変数という意味です。

names_toは新しい列名をどうするかを指定しています。names_sepで分割の区切りを指定しているのですが(この場合はアンダースコア)、その区切り前なら.value(すなわち、もとの名前のまま1)、区切り後はYearという列に格納するという意味です。

できたデータフレームは次のようになります。

表 2: ロング形式のパネルデータ
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

もし仮に、ロング形式に変換したい変数がすべてアンダースコアで区切られている場合2cols = contain("_")とすれば、変数が多くても一気に指定することができます。ただ今回の場合、Region_idがありますからうまくいきませんね。使える場面は限られそうです。

もしくは

今は具体的にincome_などと指定しましたが、変数がたくさんあると手動で書くのも大変かと思います。もし何列目を変えたいのかわかっていれば、列の番号で指定することも可能です。

df_long <- df |> 
  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つ以上ある場合

df <- tibble(
  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_long <- df |> 
  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_long <- df |> 
  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()を使う時いつも何を指定すればいいんだっけ?となりがちです😅

ご参考まで。

  1. この場合ならincomepopulation↩︎

  2. 逆に言うと、ほかの変数はアンダースコアが用いられていない場合↩︎