我怀疑这是一件显而易见的事情,但是我无法弄清楚该怎么做,也找不到任何适合我在这个社区或其他地方的信息。
vs
是包含变量的数据框:
cs <- seq(0,1,0.2)
vs <- expand.grid(cs,cs,cs)
[顺便说一句,我已经在现阶段产生了疑问:expand.grid
命令的写效率是否可以提高,因为我的向量cs
的3倍?但是可以,不是重点。]
fn
是将向量作为输入的函数的示例(实际的向量要复杂得多,向量的长度为16):
fn <- function(p) {(p[1]+exp(p[2])+p[3]^2)/(sum(exp(p)))}
现在我想将fn
应用于vs
,基本上使向量从fn
的每一行传递到vs
。
对于1行,这很明显:
fn(c(vs[1,1],vs[1,2],vs[1,3]))
[1] -0.3333333
但是,如果我想为vs
中的所有行自动执行该操作怎么办?
查阅文档后,do.call
似乎是显而易见的选择,实际上,当我使用示例函数(paste
)时,它起作用了:
head(do.call(paste,vs))
[1] "0 0 0" "0.2 0 0" "0.4 0 0"
[4] "0.6 0 0" "0.8 0 0" "1 0 0"
当然,它不适用于fn
,但是我发现这是由于paste
接受了n个参数,而我的函数接受了1个参数。
那是我被困住的地方。我以为可以创建一个新列,其中包含由vs
的3列组成的向量,然后在其上运行fn
。但是我不知道该怎么做。我尝试用c
或list
申请,致电。但无济于事。
有什么建议吗?
谢谢!
答案 0 :(得分:0)
我们可以将apply
与MARGIN
一起使用为1,以循环遍历行并应用'fn'
out1 <- apply(vs, 1, fn)
由于该函数中只有一个参数,因此do.call
可能无效
将函数的参数从1更改为3后,另一个选项是pmap
library(purrr)
fn1 <- function(p1, p2, p3) {(p1+exp(p2)+p3^2)/(sum(exp(c(p1, p2, p3))))}
out2 <- pmap_dbl(setNames(vs, c('p1', 'p2', 'p3')), fn1)
或者另一个选择是使用输入作为提取了列的数据集来创建函数
fn2 <- function(dat) {(dat[[1]] + exp(dat[[2]]) + dat[[3]]^2)/rowSums(exp(dat))}
out3 <- fn2(vs)
identical(out1, out2)
#[1] TRUE
identical(out1, out3)
#[1] TRUE
library(microbenchmark)
microbenchmark(apply = apply(vs, 1, fn),
pmap = pmap_dbl(setNames(vs, c('p1', 'p2', 'p3')), fn1),
colWise = fn2(vs),
unit = 'relative', times = 10L)
Unit: relative
# expr min lq mean median uq max neval cld
# apply 5.148858 5.137562 3.890306 4.237701 2.901886 3.222972 10 c
# pmap 2.837697 2.752563 2.189115 2.269152 1.963476 1.889337 10 b
# colWise 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 10 a
当我们要复制expand.grid
次'cs'向量时,以紧凑的方式编写n
n <- 3
vs <- expand.grid(rep(list(cs), n))