将函数列表应用于值列表

Apply list of functions to list of values

参考 ,我试图找出将函数列表应用于值列表的最简单方法。基本上,一个嵌套的 lapply。例如,这里我们将 sdmean 应用于内置数据集 trees:

funs <- list(sd=sd, mean=mean)
sapply(funs, function(x) sapply(trees, x))

得到:

              sd     mean
Girth   3.138139 13.24839
Height  6.371813 76.00000
Volume 16.437846 30.17097

但我希望避免内部 function 并有类似的东西:

sapply(funs, sapply, X=trees)

这不起作用,因为 X 匹配第一个 sapply 而不是第二个。我们可以用 functional::Curry:

sapply(funs, Curry(sapply, X=trees))

但我希望也许有一种聪明的方法可以通过我所缺少的位置和名称匹配来做到这一点。

您基本上需要某种匿名函数,因为没有其他方法可以区分两个不同 sapply 调用的命名参数。您已经展示了一个显式匿名函数和 Curry 方法。您也可以使用 magrittr

 library(magrittr)
 sapply(funs, . %>%  sapply(trees, .))
 # or .. funs %>% sapply(. %>%  sapply(trees, .))

但重点是您需要 某些东西 来进行拆分。 "problem" 是 sapply 分派到 lapply,这是一个 internal function,它似乎决定将变化的值作为函数调用的开始。您需要一些东西来重新排序参数,并且由于相同的参数名称集,如果没有辅助函数来消除歧义,就不可能将其分开。

mapply 函数确实允许您将列表传递给 "MoreArgs",这允许绕过命名参数冲突的方法。这旨在将您应该矢量化的项目和固定的项目分开。这样你就可以

mapply(sapply, funs, MoreArgs=list(X=trees))
#               sd     mean
# Girth   3.138139 13.24839
# Height  6.371813 76.00000
# Volume 16.437846 30.17097

由于 mapply 使用省略号 ... 传递向量(原子或列表)而不是像 sapply, lapply, etc ... 中那样的命名参数 (X),因此您不需要命名参数X = trees 如果您使用 mapply 而不是 sapply :

funs <- list(sd = sd, mean = mean)

x <- sapply(funs, function(x) sapply(trees, x))

y <- sapply(funs, mapply, trees)

> y
              sd     mean
Girth   3.138139 13.24839
Height  6.371813 76.00000
Volume 16.437846 30.17097
> identical(x, y)
[1] TRUE

您距离找到您要找的东西还差一个字母! :)

请注意,我为 funs 使用了一个列表,因为我无法创建函数的数据框,所以出现错误。

> R.version.string
[1] "R version 3.1.3 (2015-03-09)"

虽然不像@Floo0 提出的解决方案那样有启发性也不像解决方案那样优雅,但这里还有另一个使用 tidyr and dplyr:

library(dplyr)
library(tidyr)

fns <- funs(sd = sd, mean = mean)
trees %>% 
    gather(property, value, everything()) %>% 
    group_by(property) %>% 
    summarise_all(fns)

#   A tibble: 3 x 3
#   property        sd     mean
#      <chr>     <dbl>    <dbl>
# 1    Girth  3.138139 13.24839
# 2   Height  6.371813 76.00000
# 3   Volume 16.437846 30.17097

这一系列操作在表达意图方面做得不错,但代价是过于冗长。

另一种使用 purrr 的方法是:

require(purrr)

funs <- list(sd=sd, mean=mean)
trees %>% map_df(~invoke_map(funs, ,.), .id="id")

重要:注意 invoke_map 的空第二个参数以按位置匹配。请参阅 ?purrr::invoke_map 个示例。

这给你:

Source: local data frame [3 x 3]

      id        sd     mean
   <chr>     <dbl>    <dbl>
1  Girth  3.138139 13.24839
2 Height  6.371813 76.00000
3 Volume 16.437846 30.17097

此方法不是行名,而是为您提供包含原始列的列 id