根据外部值有条件地应用管道步骤

Posted

技术标签:

【中文标题】根据外部值有条件地应用管道步骤【英文标题】:Conditionally apply pipeline step depending on external value 【发布时间】:2017-10-15 13:13:10 【问题描述】:

鉴于 dplyr 工作流程:

require(dplyr)                                      
mtcars %>% 
    tibble::rownames_to_column(var = "model") %>% 
    filter(grepl(x = model, pattern = "Merc")) %>% 
    group_by(am) %>% 
    summarise(meanMPG = mean(mpg))

我有兴趣根据applyFilter 的值有条件地应用filter

解决方案

对于applyFilter <- 1,使用"Merc" 字符串过滤行,不返回过滤器所有行。

applyFilter <- 1


mtcars %>%
  tibble::rownames_to_column(var = "model") %>%
  filter(model %in%
           if (applyFilter) 
             rownames(mtcars)[grepl(x = rownames(mtcars), pattern = "Merc")]
            else
           
             rownames(mtcars)
           ) %>%
  group_by(am) %>%
  summarise(meanMPG = mean(mpg))

问题

建议的解决方案效率低下,因为总是评估 ifelse 调用;一种更理想的方法只会评估applyFilter &lt;- 1filter 步骤。

尝试

低效的工作解决方案如下所示:

mtcars %>% 
    tibble::rownames_to_column(var = "model") %>% 
    # Only apply filter step if condition is met
    if (applyFilter)  
        filter(grepl(x = model, pattern = "Merc"))
        
    %>% 
    # Continue 
    group_by(am) %>% 
    summarise(meanMPG = mean(mpg))

当然,上面的语法是不正确的。这只是一个说明,理想的工作流程应该是什么样子。


想要的答案

我对创建临时对象不感兴趣;工作流程应该类似于:

startingObject
    %>%
    ...
    conditional filter
    ...
    final object

理想情况下,我想找到一个解决方案,我可以控制是否正在评估 filter 调用

【问题讨论】:

基于ifelse() 的解决方案中有一个错误:ifelse(1, rownames(mtcars)[grepl(x = rownames(mtcars), pattern = "Merc")], rownames(mtcars)) 给出了[1] "Merc 240D",而不是预期的[1] "Merc 240D" "Merc 230" "Merc 280" "Merc 280C" "Merc 450SE" [6] "Merc 450SL" "Merc 450SLC"ifelse() 的值与test 的长度相同。例如,ifelse(c(T, F), 1:3, 4:9) 给出了[1] 1 5 并且没有警告出现了什么问题。 @Aurèle 谢谢,已修复。 【参考方案1】:

这个方法怎么样:

mtcars %>% 
    tibble::rownames_to_column(var = "model") %>% 
    filter(if(applyfilter== 1) grepl(x = model, pattern = "Merc") else TRUE) %>% 
    group_by(am) %>% 
    summarise(meanMPG = mean(mpg))

这意味着 grepl 仅在 applyfilter 为 1 时才被评估,否则 filter 只会回收 TRUE


或者另一种选择是使用

mtcars %>% 
  tibble::rownames_to_column(var = "model") %>% 
  if(applyfilter == 1) filter(., grepl(x = model, pattern = "Merc")) else . %>% 
  group_by(am) %>% 
  summarise(meanMPG = mean(mpg))

显然还有另一种可能的方法,您只需打破管道,有条件地进行过滤,然后继续管道(我知道 OP 并没有要求这样做,只是想为其他读者举一个例子)

mtcars %<>% 
  tibble::rownames_to_column(var = "model")

if(applyfilter == 1) mtcars %<>% filter(grepl(x = model, pattern = "Merc"))

mtcars %>% 
  group_by(am) %>% 
  summarise(meanMPG = mean(mpg))

【讨论】:

感谢您的贡献,我想到了一些返回所有T 的方法。我很乐意接受;但是,在实践中,我在考虑是否可以强制dplyr 有条件地跳过 一步。在您的回答中,filter() 被评估为所有T @Konrad,我添加了另一种方法 非常感谢,这很有趣也很有用。 我不知道%&lt;&gt;% 运算符。太好了。

以上是关于根据外部值有条件地应用管道步骤的主要内容,如果未能解决你的问题,请参考以下文章

使用 Rails 3.1 资产管道有条件地使用某些 css

詹金斯管道中的条件步骤/阶段

jenkins 管道脚本中 docker 容器的 if else 条件

将 Azure 数据工厂管道有条件地部署到另一个资源组

根据 selectOneMenu 值有条件地渲染组件

根据 selectOneMenu 值有条件地渲染组件