Tidyなデータ処理

Kanazawa.R #1

伊東宏樹

2024-06-29

[CC-BY-SA]

内容

  • Tidy data(整然データ)とは

  • tidyverseの紹介(一部)

    • tidyrパッケージ

    • dplyrパッケージ

  • さらに知るには(参考情報)

Tidy data(整然データ)

解析で扱いやすいデータ形式

Tidy dataの条件

  1. 個々の変数が1つの列をなす

  2. 個々の観測が1つの行をなす

  3. 個々の観測の構成単位の類型が1つの表をなす

  4. 個々の値が1つのセルをなす

(西原史暁 整然データとは何か)

Tidyでないデータ

=Messy data(雑然データ)の例

地点 6時 12時 18時
札幌 ☀ ☀ ☁
東京 ☁ ☂ ☂
福岡 ☂ ☀ ☀

(西原史暁 整然データとは何か)

Tidyなデータ(整然データ)

地点 時刻 天気
札幌 6時 ☀
札幌 12時 ☀
札幌 18時 ☁
東京 6時 ☁
東京 12時 ☂
東京 18時 ☂
福岡 6時 ☂
福岡 12時 ☀
福岡 18時 ☀

現実にはtidyでないデータが多い

環境省「越前岬測定所の2009年における空間放射線量率測定結果(1時間値)の確定値」https://housyasen.env.go.jp/csv/181_AB_01s_2009.csv

→ まずはデータの整形 (tidy化)

データサイエンスのプロセス

(Wickham H. et al. (2023) R for Data Science (2nd ed.), CC-BY-NC-ND 3.0)

tidyverse

データ処理に一貫性をもって使えるパッケージ群、あるいはそのコアとなるパッケージを集めたメタパッケージ

library(tidyverse)
── Attaching core tidyverse packages ────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.1     ✔ tibble    3.2.1
✔ lubridate 1.9.3     ✔ tidyr     1.3.1
✔ purrr     1.0.2     
── Conflicts ──────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors

tidyrパッケージ

  • データの変形

  • tidy化

Tidy化の例

例として「世界銀行による各国の人口データ」を整形する

data(world_bank_pop)
print(world_bank_pop, width = 66)
# A tibble: 1,064 × 20
   country indicator        `2000`  `2001`  `2002`  `2003`  `2004`
   <chr>   <chr>             <dbl>   <dbl>   <dbl>   <dbl>   <dbl>
 1 ABW     SP.URB.TOTL      4.16e4 4.20e+4 4.22e+4 4.23e+4 4.23e+4
 2 ABW     SP.URB.GROW      1.66e0 9.56e-1 4.01e-1 1.97e-1 9.46e-2
 3 ABW     SP.POP.TOTL      8.91e4 9.07e+4 9.18e+4 9.27e+4 9.35e+4
 4 ABW     SP.POP.GROW      2.54e0 1.77e+0 1.19e+0 9.97e-1 9.01e-1
 5 AFE     SP.URB.TOTL      1.16e8 1.20e+8 1.24e+8 1.29e+8 1.34e+8
 6 AFE     SP.URB.GROW      3.60e0 3.66e+0 3.72e+0 3.71e+0 3.74e+0
 7 AFE     SP.POP.TOTL      4.02e8 4.12e+8 4.23e+8 4.34e+8 4.45e+8
 8 AFE     SP.POP.GROW      2.58e0 2.59e+0 2.61e+0 2.62e+0 2.64e+0
 9 AFG     SP.URB.TOTL      4.31e6 4.36e+6 4.67e+6 5.06e+6 5.30e+6
10 AFG     SP.URB.GROW      1.86e0 1.15e+0 6.86e+0 7.95e+0 4.59e+0
# ℹ 1,054 more rows
# ℹ 13 more variables: `2005` <dbl>, `2006` <dbl>, `2007` <dbl>,
#   `2008` <dbl>, `2009` <dbl>, `2010` <dbl>, `2011` <dbl>,
#   `2012` <dbl>, `2013` <dbl>, `2014` <dbl>, `2015` <dbl>,
#   `2016` <dbl>, `2017` <dbl>

こうしたい

country year SP.URB.TOTL SP.URB.GROW SP.POP.TOTL SP.POP.GROW
ABW 2000 41625 1.66 89101 2.54
ABW 2001 42025 0.956 90691 1.77
  : :   :   :   :   :  
ABW 2017 45648 0.772 105439 0.537
AFE 2000 115551653 3.60 401600588 2.58
  : :   :   :   :   :  
ZWE 2017 4755312 1.86 14751101 2.04

pivot_longer

2000から2017までの列を、各年のデータが縦に並ぶように変形する(year列に年が入る)

pop_long <- world_bank_pop |>
  pivot_longer(cols = `2000`:`2017`, names_to = "year")
print(pop_long)
# A tibble: 19,152 × 4
   country indicator   year  value
   <chr>   <chr>       <chr> <dbl>
 1 ABW     SP.URB.TOTL 2000  41625
 2 ABW     SP.URB.TOTL 2001  42025
 3 ABW     SP.URB.TOTL 2002  42194
 4 ABW     SP.URB.TOTL 2003  42277
 5 ABW     SP.URB.TOTL 2004  42317
 6 ABW     SP.URB.TOTL 2005  42399
 7 ABW     SP.URB.TOTL 2006  42555
 8 ABW     SP.URB.TOTL 2007  42729
 9 ABW     SP.URB.TOTL 2008  42906
10 ABW     SP.URB.TOTL 2009  43079
# ℹ 19,142 more rows

パイプ演算子

‘|>’ : 結果の値を次の関数の第1引数として送る

標準のパイプ演算子が導入される前は

‘%>%’ : magrittrパッケージのパイプ演算子

pivot_wider

indicator列の値を変数名に、value列を値として列に展開する

pop_tidy <- pop_long |>
  pivot_wider(names_from = indicator, values_from = value)
print(pop_tidy)
# A tibble: 4,788 × 6
   country year  SP.URB.TOTL SP.URB.GROW SP.POP.TOTL SP.POP.GROW
   <chr>   <chr>       <dbl>       <dbl>       <dbl>       <dbl>
 1 ABW     2000        41625      1.66         89101       2.54 
 2 ABW     2001        42025      0.956        90691       1.77 
 3 ABW     2002        42194      0.401        91781       1.19 
 4 ABW     2003        42277      0.197        92701       0.997
 5 ABW     2004        42317      0.0946       93540       0.901
 6 ABW     2005        42399      0.194        94483       1.00 
 7 ABW     2006        42555      0.367        95606       1.18 
 8 ABW     2007        42729      0.408        96787       1.23 
 9 ABW     2008        42906      0.413        97996       1.24 
10 ABW     2009        43079      0.402        99212       1.23 
# ℹ 4,778 more rows

dplyrパッケージ

データの集計・抽出・並べ替えなど

以下、dplyrパッケージの主要な関数を紹介します

mutate —新しい列をつくる—

SP.POP.TOTLとSP.URB.TOTLの差をpop_non_urbという新しい変数にする

pop_new <- pop_tidy |>
  mutate(pop_non_urb = SP.POP.TOTL - SP.URB.TOTL)
pop_new
# A tibble: 4,788 × 7
   country year  SP.URB.TOTL SP.URB.GROW SP.POP.TOTL SP.POP.GROW
   <chr>   <chr>       <dbl>       <dbl>       <dbl>       <dbl>
 1 ABW     2000        41625      1.66         89101       2.54 
 2 ABW     2001        42025      0.956        90691       1.77 
 3 ABW     2002        42194      0.401        91781       1.19 
 4 ABW     2003        42277      0.197        92701       0.997
 5 ABW     2004        42317      0.0946       93540       0.901
 6 ABW     2005        42399      0.194        94483       1.00 
 7 ABW     2006        42555      0.367        95606       1.18 
 8 ABW     2007        42729      0.408        96787       1.23 
 9 ABW     2008        42906      0.413        97996       1.24 
10 ABW     2009        43079      0.402        99212       1.23 
# ℹ 4,778 more rows
# ℹ 1 more variable: pop_non_urb <dbl>

select —列を抽出する—

pop_newから、country, year, SP.POP.TOTL, SP.URB.TOTL, pop_non_urbの5つの列(変数)を残す

pop_new |>
  select(country, year, SP.POP.TOTL, SP.URB.TOTL, pop_non_urb)
# A tibble: 4,788 × 5
   country year  SP.POP.TOTL SP.URB.TOTL pop_non_urb
   <chr>   <chr>       <dbl>       <dbl>       <dbl>
 1 ABW     2000        89101       41625       47476
 2 ABW     2001        90691       42025       48666
 3 ABW     2002        91781       42194       49587
 4 ABW     2003        92701       42277       50424
 5 ABW     2004        93540       42317       51223
 6 ABW     2005        94483       42399       52084
 7 ABW     2006        95606       42555       53051
 8 ABW     2007        96787       42729       54058
 9 ABW     2008        97996       42906       55090
10 ABW     2009        99212       43079       56133
# ℹ 4,778 more rows

filter —条件にあう行を抽出する—

前の結果から、yearが2017かつSP.POP.TOTLが1億以上の行を抽出する

pop_new |>
  select(country, year, SP.POP.TOTL, SP.URB.TOTL, pop_non_urb) |>
  filter(year == 2017, SP.POP.TOTL >= 1e+8)
# A tibble: 58 × 5
   country year  SP.POP.TOTL SP.URB.TOTL pop_non_urb
   <chr>   <chr>       <dbl>       <dbl>       <dbl>
 1 AFE     2017    632746296   223732118   409014178
 2 AFW     2017    431138704   198494008   232644696
 3 ARB     2017    423664839   247298631   176366208
 4 BGD     2017    161793964    58016080   103777884
 5 BRA     2017    208504960   179958546    28546414
 6 CEB     2017    102740078    63954111    38785967
 7 CHN     2017   1396215000   809246214   586968786
 8 EAP     2017   2080968782  1138074091   942894691
 9 EAR     2017   3252529883  1453160846  1799369037
10 EAS     2017   2327134580  1354328520   972806060
# ℹ 48 more rows

arrange —行を並べ替える—

さらにSP.POP.TOTLで降順に並べ替える

pop_new |>
  select(country, year, SP.POP.TOTL, SP.URB.TOTL, pop_non_urb) |>
  filter(year == 2017, SP.POP.TOTL >= 1e+8) |>
  arrange(desc(SP.POP.TOTL))
# A tibble: 58 × 5
   country year  SP.POP.TOTL SP.URB.TOTL pop_non_urb
   <chr>   <chr>       <dbl>       <dbl>       <dbl>
 1 WLD     2017   7578157615  4147418821  3430738794
 2 IBT     2017   6401367406  3189667379  3211700027
 3 LMY     2017   6322861019  3131897864  3190963155
 4 MIC     2017   5679375318  2922044655  2757330663
 5 IBD     2017   4776473096  2596413659  2180059437
 6 EAR     2017   3252529883  1453160846  1799369037
 7 LMC     2017   3225575822  1324700256  1900875566
 8 UMC     2017   2453799496  1597344399   856455097
 9 EAS     2017   2327134580  1354328520   972806060
10 LTE     2017   2286564636  1407844671   878719965
# ℹ 48 more rows

summarise(summarize) —集計する—

pop_tidyについてcountryごとにSP.POP.TOTLの平均を求め、mean_popという変数に入れる

pop_tidy |>
  group_by(country) |>
  summarise(mean_pop = mean(SP.POP.TOTL))
# A tibble: 266 × 2
   country   mean_pop
   <chr>        <dbl>
 1 ABW         98149.
 2 AFE     508006585.
 3 AFG      27344241.
 4 AFW     344981567.
 5 AGO      22558192 
 6 ALB       2958262.
 7 AND         73219.
 8 ARB     352168137.
 9 ARE       6582948.
10 ARG      40454868.
# ℹ 256 more rows

グラフ化

さらに上位10地域を棒グラフに

pop_tidy |>
  group_by(country) |>
  summarise(mean_pop = mean(SP.POP.TOTL)) |>
  arrange(desc(mean_pop)) |>
  slice(1:10) |>
  ggplot(aes(x = country, y = mean_pop)) +
  geom_bar(stat = "identity")

グラフ化

その他、よくつかう関数

  • bind_rows: データセットを縦につなげる

  • bind_cols: データセットを横につなげる

  • *_join: 2つのデータセットをキー列を参照して結合する

    • inner_join, left_join, right_join, full_join, …

さらに知るには