我正在努力更好地理解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
但我如何使用purrr
将mean
映射到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.frame
内mtcars_split
来解决这个问题,但我不能理解她在做什么。她注意到这个例子可能在本教程前面没有充分解释,我已经让她详细说明了here,但还没有回答(我知道她很忙!)。
答案 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)
让我们做完全相同的事情,用x
和f
分别替换mtcars_split
和map_dbl(mean)
:
mtcars_split %>% map(~ .x %>% map_dbl(mean))
# or, equivalently:
mtcars_split %>% map(~ map_dbl(.x, mean))
这可以通过与我们上面的示例相同的方式进行简化:
mtcars_split %>% map(map_dbl, mean)