獣医疫学メモ帳

獣医疫学(に関係ないかもしれない)メモ帳。

group_by() + summarise() でgroupごとにベクトルを結合する

目的

library(tidyverse)

# これを
data <- tribble(~x, ~y,
                "a", c(1, 2),
                "a", c(),
                "a", c(3),
                "b", c(),
                "c", c(4),
                "c", c(5)
  )

# こうしたい
tribble(~x, ~y,
        "a", c(1, 2, 3),
        "b", c(),
        "c", c(4, 5)
)

これが簡単そうにみえて意外と手こずったのでメモ。

結論

list(do.call(c, y))

試行錯誤録

失敗

data |> 
  group_by(x) |> 
  summarise(y = c(y))
#> `summarise()` has grouped output by 'x'. You can override using the `.groups`
#> argument.
#> # A tibble: 6 × 2
#> # Groups:   x [3]
#>   x     y        
#>   <chr> <list>   
#> 1 a     <dbl [2]>
#> 2 a     <NULL>   
#> 3 a     <dbl [1]>
#> 4 b     <NULL>   
#> 5 c     <dbl [1]>
#> 6 c     <dbl [1]>

普通にc()で結合しようとしてもうまくいかない。

面倒くさい方法

data |> 
  group_by(x) |> 
  summarise(y = list(y)) |> 
  mutate(y = map(y, flatten_dbl))
#> # A tibble: 3 × 2
#>   x     y        
#>   <chr> <list>   
#> 1 a     <dbl [3]>
#> 2 b     <dbl [0]>
#> 3 c     <dbl [2]>

できてるっちゃできてるんだけど一見「なんでわざわざlist()した後にflatten()してるの?」と思うし、わざわざmutate()せずにsummarise()だけでできる方法がある気がする。

成功

data |> 
  group_by(x) |> 
  summarise(y = list(do.call(c, y)))
#> # A tibble: 3 × 2
#>   x     y        
#>   <chr> <list>   
#> 1 a     <dbl [3]>
#> 2 b     <NULL>   
#> 3 c     <dbl [2]>

これでOK。