【问题标题】:do.call with filter functiondo.call 带过滤功能
【发布时间】:2015-09-11 23:06:20
【问题描述】:

我希望能够动态地将搜索参数传递给 dplyr 的过滤器函数。我可以手动进行这样的搜索:

filter(df, sex=='F', country=='USA')

但我需要能够动态地执行此操作。

我试过do.call,像这样:

do.call('filter',list(df,country=='USA'))

但这给了我一个错误:

找不到对象国家

如果我将国家/地区放在引号中,我不会收到错误消息,但不会从过滤器返回任何结果。

【问题讨论】:

  • 你能举一个更具体的例子来说明你需要这个的情况吗?您可能需要改用filter_ 进行标准评估,请参阅this answer 和此vignette 了解更多信息。

标签: r dplyr


【解决方案1】:

根据我提出的 aosmith 建议:

 df <- data.frame(
          sex = sample(c('M','F'),10, replace = TRUE),
          country = sample(c('USA','UK'),10, replace = TRUE)
                 )

 filter_criteria <- ~ country == 'USA'
 do.call(filter_,list(df,filter_criteria))

【讨论】:

  • 我投了赞成票,但在使用~-函数将多个标准构造为表达式的情况下,我没有看到使用这种方法的明显阐述。我尝试列出这些标准,但由于lazy.eval 不愿意处理列表或配对列表,所以它出错了。
  • 使用~do.call 使用多个条件看起来像:do.call(filter_,list(df, .dots = list(filter_criterion1, filter_criterion2)))
【解决方案2】:

我最近使用包 lazyeval 解决了在 Shiny 的动态情况下使用 filter_(请参阅答案 here)。尽管您的实际情况可能更简单,但这可能是相关的,具体取决于您在做什么。

您可以通过创建一个包含您想要作为条件的变量的向量以及与每个变量的条件具有相同长度的向量来做类似的事情。

library(lazyeval)

variables = c("country", "sex")
conditions = c("USA", "F")

然后您可以遍历变量/条件,使用interp 创建您要过滤的条件列表。

dots = lapply(1:length(variables),
             function(crit) interp(~y == z, 
                                .values = list(y = as.name(variables[crit]), 
                                            z = conditions[crit])))
dots
[[1]]
~country == "USA"
<environment: 0x02eed660>

[[2]]
~sex == "F"
<environment: 0x02c6b388>

然后只需在filter.dots 参数中使用结果列表。我在这里使用@joshuagordon 的df

filter_(df, .dots = dots)
  sex country
1   F     USA
2   F     USA
3   F     USA
4   F     USA

【讨论】:

    【解决方案3】:

    我看到请求希望能够有多个条件。我需要使用单个标准的字符表示和带有“&”的paste 来获得成功。尝试了几种不同的方法来使用公式对象,但始终失败:

    filter_criterion1 <- "country == 'USA'"
    filter_criterion2 <- "sex == 'F'"
    do.call(filter_, list(df,paste(filter_criterion2, filter_criterion1, sep="&")))
      sex country
    1   F     USA
    2   F     USA
    3   F     USA
    

    感谢 aosmith 指出 .dots 参数将接受字符或公式规范的列表:

      do.call(filter_, list(df,.dots=list(filter_criterion2, filter_criterion1)))
      sex country
    1   F     USA
    2   F     USA
    3   F     USA
    

    【讨论】:

    • 我想我对在 OP 中使用 do.call 并没有清楚的了解 - 我使用 filter_(df, .dots = list(filter_criterion1, filter_criterion2))do.call 得到相同的结果,它可以使用引号中的条件或使用@mr.joshuagordon 答案中的公式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-26
    • 2016-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多