假设下面有一个类似于foo的R函数。这个函数有4个固定参数,以及在...中定义的任意数量的参数。
foo参数的所有输入值都存储在这 CSV文件中。
在下面的代码中,我可以使用从foo循环中从CSV文件导入的4个固定参数成功地运行lapply。但是,我想知道如何在lapply命令中插入...中定义的参数?
foo <- function(n = NULL, r = NULL, post, control, ...){ ## the function
data.frame(n = n, r = r, post, control, ...)
}
D <- read.csv("https://raw.githubusercontent.com/izeh/i/master/j.csv", h = T) # CSV file
L <- split(D, D$study.name) ; L[[1]] <- NULL
# the fixed args values:
n <- lapply(1:length(L), function(i) L[[i]]$n)
r <- lapply(1:length(L), function(i) L[[i]]$r)
post <- lapply(1:length(L), function(i) L[[i]]$post)
control <- lapply(1:length(L), function(i) L[[i]]$control)
# names of args defined in `...`:
dot.names <- names(L[[1]])[!names(L[[1]]) %in% formalArgs(foo)][-1]
# the `...` args values:
a <- lapply(dot.names, function(i) lapply(L, function(j) j[grep(i, names(j))]))
## RUN `foo` function:
lapply(1:length(L), function(i) foo(n = n[[i]], r = r[[i]], post = post[[i]],
control = control[[i]])) # BUT! how can I insert the
# arguments defined in `...`
# in the function?发布于 2019-06-22 18:10:30
我们也可以将Map与do.call结合使用。我们可以在对foo的单个调用中提取lapply的参数,方法是根据‘dot.name’的输出提取列'n‘、'r’、'post‘、控制和额外列(...),然后从transpose (来自purrr --或者使用与提到的这里相同的方法)将其传递给Map。
args <- lapply(L, function(x) unclass(x[c("n", "r", "post", "control", dot.names)]))
library(purrr)
unname(do.call(Map, c(f = foo, transpose(args))))
#[[1]]
# n r post control ESL prof scope type
#1 13 0.5 1 FALSE 1 2 0 1
#2 13 0.5 2 FALSE 1 2 0 1
#3 15 0.5 1 FALSE 1 2 0 1
#4 15 0.5 2 FALSE 1 2 0 1
#5 16 0.5 1 TRUE 1 2 0 1
#6 16 0.5 2 TRUE 1 2 0 1
#[[2]]
# n r post control ESL prof scope type
#1 13 0.5 1 FALSE 0 1 1 0
#2 13 0.5 2 FALSE 0 1 1 0
#3 15 0.5 1 FALSE 0 1 1 0
#4 15 0.5 2 FALSE 0 1 1 0
#5 16 0.5 1 TRUE 0 1 1 0
#6 16 0.5 2 TRUE 0 1 1 0
#[[3]]
# n r post control ESL prof scope type
#1 13 0.5 1 FALSE 1 3 0 1
#2 13 0.5 2 FALSE 1 3 0 1
#3 13 0.5 3 FALSE 1 3 0 1
#4 15 0.5 1 FALSE 1 3 0 1
#5 15 0.5 2 FALSE 1 3 0 1
#6 15 0.5 3 FALSE 1 3 0 1
#7 16 0.5 1 TRUE 1 3 0 1
#8 16 0.5 2 TRUE 1 3 0 1
#9 16 0.5 3 TRUE 1 3 0 1OP提到了用一个transpose选项替换base R
m1 <- simplify2array(lapply(names(args[[1]]), function(nm)
lapply(args, function(l1) l1[nm])))
do.call(Map, c(f = foo, unname(split(m1, col(m1)))))如果我们可以使用tidyverse
library(tidyverse)
map(L, ~
.x %>%
select(n, r, post, control, dot.names) %>%
as.list) %>%
transpose %>%
pmap(., foo)
#$Ellis.sh1
# n r post control ESL prof scope type
#1 13 0.5 1 FALSE 1 2 0 1
#2 13 0.5 2 FALSE 1 2 0 1
#3 15 0.5 1 FALSE 1 2 0 1
#4 15 0.5 2 FALSE 1 2 0 1
#5 16 0.5 1 TRUE 1 2 0 1
#6 16 0.5 2 TRUE 1 2 0 1
#$Goey1
# n r post control ESL prof scope type
#1 13 0.5 1 FALSE 0 1 1 0
#2 13 0.5 2 FALSE 0 1 1 0
#3 15 0.5 1 FALSE 0 1 1 0
#4 15 0.5 2 FALSE 0 1 1 0
#5 16 0.5 1 TRUE 0 1 1 0
#6 16 0.5 2 TRUE 0 1 1 0
#$kabla
# n r post control ESL prof scope type
#1 13 0.5 1 FALSE 1 3 0 1
#2 13 0.5 2 FALSE 1 3 0 1
#3 13 0.5 3 FALSE 1 3 0 1
#4 15 0.5 1 FALSE 1 3 0 1
#5 15 0.5 2 FALSE 1 3 0 1
#6 15 0.5 3 FALSE 1 3 0 1
#7 16 0.5 1 TRUE 1 3 0 1
#8 16 0.5 2 TRUE 1 3 0 1
#9 16 0.5 3 TRUE 1 3 0 1更新
基于示例显示的这里,结构略有不同,因此我们可以将list转换为names (对于base R)。
argsT <- setNames(lapply(names(args[[1]]),
function(nm) lapply(args, `[[`, nm)), names(args[[1]]))
out1 <- unname(do.call(Map, c(f = d.prepos, argsT)))
out2 <- unname(do.call(Map, c(f = d.prepos, purrr::transpose(args))))
identical(out1, out2)
#[1] TRUE发布于 2019-06-22 18:03:08
对于这类问题,请使用mapply。
在下面的代码中,我改变了您定义n、r、post和control的方式。
n <- lapply(L, `[[`, 'n')
r <- lapply(L, `[[`, 'r')
post <- lapply(L, `[[`, 'post')
control <- lapply(L, `[[`, 'control')唯一的区别是这些结果有它们的names属性集。
然后还更改列表a的创建方式。交换这两个周期。
a <- lapply(L, function(i) lapply(dot.names, function(k) i[grep(k, names(i))]))现在解决问题的办法。设置SIMPLIFY = FALSE是强制性的,默认的TRUE提供了非常糟糕的输出。
mapply(FUN = foo, n, r, post, control, a, SIMPLIFY = FALSE)https://stackoverflow.com/questions/56717677
复制相似问题