twg*_*er2 7 functional-programming nested r 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
Run Code Online (Sandbox Code Playgroud)
但是,我怎么会用purrr映射mean到mtcars被拆分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
Run Code Online (Sandbox Code Playgroud)
我理解为什么这不起作用:split创建一个列表,现在我正在尝试map mean新列表的每个元素,即data.frames.这种mapping操作等同于(必要时纠正我):
mean(mtcars_split[1])
mean(mtcars_split[2])
mean(mtcars_split[3])
Run Code Online (Sandbox Code Playgroud)
这显然不起作用 - 你不能只是采取mean一个data.frame.我真正想要的是做到这一点:
mtcars_split[[1]] %>% map(mean)
mtcars_split[[2]] %>% map(mean)
mtcars_split[[3]] %>% map(mean)
Run Code Online (Sandbox Code Playgroud)
问题是,我无法绕过如何做到这一点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
Run Code Online (Sandbox Code Playgroud)
rapply递归apply显然是我的答案的关键 - 我相信我需要嵌套的maps - 一个提取data.frame我的三个s中的每一列mtcars_split,然后一个mean在每个提取的列上运行.但是,我无法做到这一点.
我认为这是由Jenny Bryan在她的purrr教程中解决的,她使用map()内部a map(),但我不能按照她正在做的事情.她注意到这个例子可能在本教程前面没有充分解释,我已经在这里要求她详细说明,但还没有回答(我知道她很忙!).
这种问题的答案总是相同的:
分解问题,针对个别情况解决,然后再由内而外放回去。
如您mtcars %>% split(.$cyl)所见,为您提供了一个列表列表(data.frames列表)。要映射mean过内部列表。
因此,让我们首先针对一个列表进行操作:
mtcars_split[[1]] %>% map_dbl(mean)
# Or, equivalently:
map_dbl(mtcars_split[[1]], mean)
Run Code Online (Sandbox Code Playgroud)
这可行。我们已经分解了问题并成功解决了个别情况:换句话说,给定一个列表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)
Run Code Online (Sandbox Code Playgroud)
让我们做完全相同的事情,分别用x和f替换为mtcars_split和map_dbl(mean):
mtcars_split %>% map(~ .x %>% map_dbl(mean))
# or, equivalently:
mtcars_split %>% map(~ map_dbl(.x, mean))
Run Code Online (Sandbox Code Playgroud)
可以像上面的示例一样简化此操作:
mtcars_split %>% map(map_dbl, mean)
Run Code Online (Sandbox Code Playgroud)