我想在字符向量或带有变量名的列表上传递函数。我认为问题是R在这种情况下不识别变量名。我有一个简单的例子,但我打算用大数据框来做。
示例数据:
> DF
A B C
1 11 22 88
2 11 22 47
3 2 30 21
4 3 30 21
> v
[1] "DF,A,B" "DF,A,C" "DF,B,C" "DF,A,B,C"
我有Romain Francois的功能: Loop within string in r to output expressions with vectorized values
library(purrr)
library(glue)
library(rlang)
tests <- function(data, ...){
names <- map_chr(quos(...), f_name)
map( names, ~{
glue( "{name} == {values}", name = ., values = data[[.]] )
}) %>%
reduce(paste, sep = " & " )
}
最后,我想在每个v元素上传递函数,所以我这样做并得到错误的输出:
> output=sapply(v,tests)
> output
$`DF,A,B`
NULL
$`DF,A,C`
NULL
$`DF,B,C`
NULL
$`DF,A,B,C`
NULL
输出结果为:
c(
tests( DF, A, B),
tests( DF, A, C),
tests( DF, B, C),
tests( DF, A, B, C)
)
#> [1] "A == 11 & B == 22" "A == 11 & B == 22"
#> [3] "A == 2 & B == 30" "A == 3 & B == 30"
#> [5] "A == 11 & C == 88" "A == 11 & C == 47"
#> [7] "A == 2 & C == 21" "A == 3 & C == 21"
#> [9] "B == 22 & C == 88" "B == 22 & C == 47"
#> [11] "B == 30 & C == 21" "B == 30 & C == 21"
#> [13] "A == 11 & B == 22 & C == 88" "A == 11 & B == 22 & C == 47"
#> [15] "A == 2 & B == 30 & C == 21" "A == 3 & B == 30 & C == 21"
如果有人可以帮我解决这个问题,那将会很棒。
答案 0 :(得分:2)
&#39; v&#39;是一个字符串。它需要分开。以下是使用base R
tests <- function(data, ...){
colN <- c(...)
tmp <- get(data, envir = parent.frame())[colN]
Reduce(function(...) paste(..., sep=" & "),
Map(paste, names(tmp), tmp, MoreArgs = list(sep=" == ")))
}
r1 <- c(sapply(strsplit(v, ","), function(x) tests(x[1], x[-1])))
r1
#[1] "A == 11 & B == 22" "A == 11 & B == 22" "A == 2 & B == 30" "A == 3 & B == 30"
#[5] "A == 11 & C == 88" "A == 11 & C == 47" "A == 2 & C == 21" "A == 3 & C == 21"
#[9] "B == 22 & C == 88" "B == 22 & C == 47" "B == 30 & C == 21" "B == 30 & C == 21"
#[13] "A == 11 & B == 22 & C == 88" "A == 11 & B == 22 & C == 47" "A == 2 & B == 30 & C == 21" "A == 3 & B == 30 & C == 21"
同样,我们可以在OP的帖子中更改功能。此处不需要使用quos
,因为我们的输入列名称是strsplit
中的字符串,可以直接在glue
tests <- function(data, ...){
names <- c(...)
#object name i.e. data is a string
#so using get to return the value of the object
tmp <- get(data, envir = parent.frame())
map(names, ~{
glue( "{name} == {values}", name = ., values = tmp[[.]] )}) %>%
reduce(paste, sep = " & " )
}
r2 <- c(sapply(strsplit(v, ","), function(x) tests(x[1], x[-1])))
identical(r1, r2)
#[1] TRUE
v <- c("DF,A,B", "DF,A,C", "DF,B,C", "DF,A,B,C")
DF <- structure(list(A = c(11L, 11L, 2L, 3L), B = c(22L, 22L, 30L,
30L), C = c(88L, 47L, 21L, 21L)), .Names = c("A", "B", "C"),
class = "data.frame", row.names = c("1", "2", "3", "4"))