将函数列表应用于值列表
Apply list of functions to list of values
参考 ,我试图找出将函数列表应用于值列表的最简单方法。基本上,一个嵌套的 lapply
。例如,这里我们将 sd
和 mean
应用于内置数据集 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
。
参考 lapply
。例如,这里我们将 sd
和 mean
应用于内置数据集 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
。