146  実践 pivot_widerで複数列を横にする

library(tidyverse)

続けて、pivot_widerで複数列に対応する場合を考えてみましょう。

例えば、

dat <- tibble(
  age = c("<20","20-30","30-40",">40","<20","20-30","30-40",">40"),
  grp = c("A","B","A","B","A","B","A","B"),
  sex = c("m","m","m","m","f","f","f","f"),
  val = c(1:8)
)

dat
# A tibble: 8 × 4
  age   grp   sex     val
  <chr> <chr> <chr> <int>
1 <20   A     m         1
2 20-30 B     m         2
3 30-40 A     m         3
4 >40   B     m         4
5 <20   A     f         5
6 20-30 B     f         6
7 30-40 A     f         7
8 >40   B     f         8

このデータ、横持ちにしたときに、列名の部分をという形にしたいばあい、実は、pivot_widerのnames_fromに複数変数を与えてあげると自動的に処理をしてくれます。なので、

dat %>% 
  pivot_wider(
    id_cols = grp, 
    names_from = age,
    values_from = val
  )
Warning: Values from `val` are not uniquely identified; output will contain list-cols.
• Use `values_fn = list` to suppress this warning.
• Use `values_fn = {summary_fun}` to summarise duplicates.
• Use the following dplyr code to identify duplicates.
  {data} %>%
  dplyr::group_by(grp, age) %>%
  dplyr::summarise(n = dplyr::n(), .groups = "drop") %>%
  dplyr::filter(n > 1L)
# A tibble: 2 × 5
  grp   `<20`     `20-30`   `30-40`   `>40`    
  <chr> <list>    <list>    <list>    <list>   
1 A     <int [2]> <NULL>    <int [2]> <NULL>   
2 B     <NULL>    <int [2]> <NULL>    <int [2]>

重複するデータがあるのでListが作られていますが、

dat %>% 
  pivot_wider(
    id_cols = grp,
    names_from = c(age, sex),
    values_from = val
  )
# A tibble: 2 × 9
  grp   `<20_m` `20-30_m` `30-40_m` `>40_m` `<20_f` `20-30_f` `30-40_f` `>40_f`
  <chr>   <int>     <int>     <int>   <int>   <int>     <int>     <int>   <int>
1 A           1        NA         3      NA       5        NA         7      NA
2 B          NA         2        NA       4      NA         6        NA       8

names_fromに複数変数を与えてあげると問題が起こりません。

尚、変数名の間は、初期設定では_が挿入されていますが、

dat %>% 
  pivot_wider(
    id_cols = grp,
    names_from = c(age, sex),
    values_from = val,
    names_sep = "@@"
  )
# A tibble: 2 × 9
  grp   `<20@@m` `20-30@@m` `30-40@@m` `>40@@m` `<20@@f` `20-30@@f` `30-40@@f`
  <chr>    <int>      <int>      <int>    <int>    <int>      <int>      <int>
1 A            1         NA          3       NA        5         NA          7
2 B           NA          2         NA        4       NA          6         NA
# ℹ 1 more variable: `>40@@f` <int>

で変更可能です。

dat %>% 
  pivot_wider(
    id_cols = grp,
    names_from = c(age, sex),
    values_from = val,
    names_sep = "―――",
    values_fill = 0
  )
# A tibble: 2 × 9
  grp   `<20―――m` `20-30―――m` `30-40―――m` `>40―――m` `<20―――f` `20-30―――f`
  <chr>     <int>       <int>       <int>     <int>     <int>       <int>
1 A             1           0           3         0         5           0
2 B             0           2           0         4         0           6
# ℹ 2 more variables: `30-40―――f` <int>, `>40―――f` <int>

後は、値がNAでなくて、何か別の値で埋めたい場合はvalues_fillに値を与えてあげると自動的に埋めてくれます。