使用purrr

时间:2017-09-24 16:28:23

标签: r functional-programming nested purrr

我正在努力更好地理解R中的函数式编程。我想坚持purrr,但我将使用rapply来展示我正在寻找的内容。首先,我想要了解的一个简单例子:

您可以使用map获取mtcars数据集的每列的平均值:

library(tidyverse)
mtcars %>% map_dbl(mean)

   mpg        cyl       disp         hp       drat         wt       qsec  
 20.090625   6.187500 230.721875 146.687500   3.596563   3.217250  17.848750 
    vs         am       gear       carb 
 0.437500   0.406250   3.687500   2.812500 

但我如何使用purrrmean映射到mtcars的{​​{1}}?

cyl

我理解为什么这不起作用:library(tidyverse) mtcars_split <- mtcars %>% split(.$cyl) mtcars_split %>% map(mean) $`4` [1] NA $`6` [1] NA $`8` [1] NA Warning messages: 1: In mean.default(.x[[i]], ...) : argument is not numeric or logical: returning NA 2: In mean.default(.x[[i]], ...) : argument is not numeric or logical: returning NA 3: In mean.default(.x[[i]], ...) : argument is not numeric or logical: returning NA 创建一个列表,现在我正在尝试split map到该新列表的每个元素,{{1 }}秒。 mean ping的此尝试相当于(必要时纠正我):

data.frame

显然不起作用 - 您不能只使用map的{​​{1}}。我真正想要的是做到这一点:

mean(mtcars_split[1])
mean(mtcars_split[2])
mean(mtcars_split[3])

问题是,我无法在mean中解决如何执行此操作的问题。在寻找这个(看似非常基本的)问题的解决方案时,我找到了data.frame,这似乎做了我想要的,但在mtcars_split[[1]] %>% map(mean) mtcars_split[[2]] %>% map(mean) mtcars_split[[3]] %>% map(mean) 之外(并且输出不完全是我的格式) “我愿意,但那不是重点”:

purrr

rapply递归purrr显然是我答案的关键 - 我相信我需要嵌套rapply(mtcars_split, mean, how = "unlist") 4.mpg 4.cyl 4.disp 4.hp 4.drat 4.wt 26.6636364 4.0000000 105.1363636 82.6363636 4.0709091 2.2857273 4.qsec 4.vs 4.am 4.gear 4.carb 6.mpg 19.1372727 0.9090909 0.7272727 4.0909091 1.5454545 19.7428571 6.cyl 6.disp 6.hp 6.drat 6.wt 6.qsec 6.0000000 183.3142857 122.2857143 3.5857143 3.1171429 17.9771429 6.vs 6.am 6.gear 6.carb 8.mpg 8.cyl 0.5714286 0.4285714 3.8571429 3.4285714 15.1000000 8.0000000 8.disp 8.hp 8.drat 8.wt 8.qsec 8.vs 353.1000000 209.2142857 3.2292857 3.9992143 16.7721429 0.0000000 8.am 8.gear 8.carb 0.1428571 3.2857143 3.5000000 s - 一个来提取三个rapply中的每一列我的apply,然后在每个提取的列上运行map。但是,我无法做到这一点。

我认为Jenny Bryan在她purrr tutorial中使用data.framemtcars_split来解决这个问题,但我不能理解她在做什么。她注意到这个例子可能在本教程前面没有充分解释,我已经让她详细说明了here,但还没有回答(我知道她很忙!)。

1 个答案:

答案 0 :(得分:3)

解决此类问题的方法始终相同:

  

分解问题,针对个案解决问题,然后再由内而外放回去。

如您所见,mtcars %>% split(.$cyl)为您提供了一个列表列表(data.frames列表)。您想将mean映射到内部列表

因此,我们首先为一个列表进行操作:

mtcars_split[[1]] %>% map_dbl(mean)
# Or, equivalently:
map_dbl(mtcars_split[[1]], mean)

这有效。我们已经分解了问题,并成功解决了个别情况:换句话说,给定列表x和转换f,我们通过执行以下操作来解决x[[1]]的问题f(x[[1]])(相当于x[[1]] %>% f())。

是时候将其推广到所有情况了。我们已经知道如何将元素x[[1]]转换为整个列表x:在该列表上使用map

x %>% map(~ .x %>% f())
# or, equivalently:
x %>% map(~ f(.x))
# or, equivalently:
map(x, ~ f(.x))
# or, finally:
map(x, f)

让我们做完全相同的事情,用xf分别替换mtcars_splitmap_dbl(mean)

mtcars_split %>% map(~ .x %>% map_dbl(mean))
# or, equivalently:
mtcars_split %>% map(~ map_dbl(.x, mean))

这可以通过与我们上面的示例相同的方式进行简化:

mtcars_split %>% map(map_dbl, mean)