在嵌套数据框的列上实现map()

时间:2017-04-22 23:56:25

标签: r dplyr tidyverse magrittr purrr

我正在教自己R tidyverse purr()包,并且在嵌套数据框列上实现map()时遇到问题。有人可以解释我错过了什么吗?

使用基础R ChickWeight数据集作为示例,如果我第一次过滤饮食#1,我可以轻松获得饮食#1下每个时间点的观察次数:

library(tidyverse) 
ChickWeight %>%
  filter(Diet == 1) %>% 
  group_by(Time) %>% 
  summarise(counts = n_distinct(Chick))

这很棒,但我想立刻为每种饮食做这件事,我认为嵌套数据并用map()迭代它将是一个很好的方法。 这就是我所做的:

example <- ChickWeight %>% 
  nest(-Diet) 

实现这个地图功能,然后实现我的目标:

map(example$data, ~ .x %>% group_by(Time) %>% summarise(counts = n_distinct(Chick))) 

但是,当我尝试使用管道将相同的命令放入原始数据框的另一列时,它会失败。

example %>% 
   mutate(counts = map(data, ~ .x %>% group_by(Time) %>%  summarise(counts = n_distinct(Chick))))
Error in eval(substitute(expr), envir, enclos) : 
  variable 'Chick' not found

为什么会这样?

我也尝试将数据框拆分成一个列表但它不起作用。

ChickWeight %>% 
  split(.$Diet) %>% 
  map(data, ~ .x %>% group_by(Time) %>%  summarise(counts = n_distinct(Chick)))

1 个答案:

答案 0 :(得分:4)

因为您在dplyr NSE中使用了dplyr非标准评估,所以对于搜索Chick的环境感到困惑。它可能是一个错误,真的,但可以通过开发版本的新.data代词来避免它,它指定了要查看的位置:

library(tidyverse)

ChickWeight %>% 
    nest(-Diet) %>% 
    mutate(counts = map(data, 
                        ~.x %>% group_by(Time) %>% 
                            summarise(counts = n_distinct(.data$Chick))))
#> # A tibble: 4 × 3
#>     Diet               data            counts
#>   <fctr>             <list>            <list>
#> 1      1 <tibble [220 × 3]> <tibble [12 × 2]>
#> 2      2 <tibble [120 × 3]> <tibble [12 × 2]>
#> 3      3 <tibble [120 × 3]> <tibble [12 × 2]>
#> 4      4 <tibble [118 × 3]> <tibble [12 × 2]>

要通过列表管道,将map的第一个参数留空以传递到要迭代的列表中:

ChickWeight %>% 
    split(.$Diet) %>% 
    map(~ .x %>% group_by(Time) %>%  summarise(counts = n_distinct(Chick))) %>% .[[1]]

#> # A tibble: 12 × 2
#>     Time counts
#>    <dbl>  <int>
#> 1      0     20
#> 2      2     20
#> 3      4     19
#> 4      6     19
#> 5      8     19
#> 6     10     19
#> 7     12     19
#> 8     14     18
#> 9     16     17
#> 10    18     17
#> 11    20     17
#> 12    21     16

更简单的选择是按两列分组:

ChickWeight %>% group_by(Diet, Time) %>% summarise(counts = n_distinct(Chick))

#> Source: local data frame [48 x 3]
#> Groups: Diet [?]
#> 
#>      Diet  Time counts
#>    <fctr> <dbl>  <int>
#> 1       1     0     20
#> 2       1     2     20
#> 3       1     4     19
#> 4       1     6     19
#> 5       1     8     19
#> 6       1    10     19
#> 7       1    12     19
#> 8       1    14     18
#> 9       1    16     17
#> 10      1    18     17
#> # ... with 38 more rows