将函数传递给具有变量名称的字符向量

时间:2017-11-21 18:49:29

标签: r

我想在字符向量或带有变量名的列表上传递函数。我认为问题是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"

如果有人可以帮我解决这个问题,那将会很棒。

1 个答案:

答案 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"))