在R中,如何应用以向量为输入的函数,其中必须从数据帧的多列构建向量?

时间:2018-11-22 19:29:11

标签: r

我怀疑这是一件显而易见的事情,但是我无法弄清楚该怎么做,也找不到任何适合我在这个社区或其他地方的信息。

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。但是我不知道该怎么做。我尝试用clist申请,致电。但无济于事。

有什么建议吗?

谢谢!

1 个答案:

答案 0 :(得分:0)

我们可以将applyMARGIN一起使用为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))