仅当列存在时才执行dplyr操作

问题描述 投票:10回答:4

根据对conditional dplyr evaluation的讨论,我想根据传入数据帧中是否存在引用列,有条件地在管道中执行一个步骤。

Example

1)2)产生的结果应该是相同的。

现有专栏

# 1)
mtcars %>% 
  filter(am == 1) %>%
  filter(cyl == 4)

# 2)
mtcars %>%
  filter(am == 1) %>%
  {
    if("cyl" %in% names(.)) filter(cyl == 4) else .
  }

不可用的列

# 1)
mtcars %>% 
  filter(am == 1)

# 2)    
mtcars %>%
  filter(am == 1) %>%
  {
    if("absent_column" %in% names(.)) filter(absent_column == 4) else .
  }

Problem

对于可用列,传递的对象与初始数据帧不对应。原始代码返回错误消息:

filter(cyl == 4)中的错误:找不到对象'cyl'

我尝试了其他语法(没有运气):

>> mtcars %>%
...   filter(am == 1) %>%
...   {
...     if("cyl" %in% names(.)) filter(.$cyl == 4) else .
...   }
 Show Traceback

 Rerun with Debug
 Error in UseMethod("filter_") : 
  no applicable method for 'filter_' applied to an object of class "logical" 

Follow-up

我想扩大这个问题,这个问题可以解释==电话中filter右侧的评估。例如,下面的语法试图过滤第一个可用值。 mtcars%>%

filter({
    if ("does_not_ex" %in% names(.))
      does_not_ex
    else
      NULL
  } == {
    if ("does_not_ex" %in% names(.))
      unique(.[['does_not_ex']])
    else
      NULL
  })

预计,调用将评估错误消息:

filter_impl(.data, quo)中的错误:结果的长度必须为32,而不是0

应用于现有列时:

mtcars %>%
  filter({
    if ("mpg" %in% names(.))
      mpg
    else
      NULL
  } == {
    if ("mpg" %in% names(.))
      unique(.[['mpg']])
    else
      NULL
  })

它使用警告消息:

  mpg cyl disp  hp drat   wt  qsec vs am gear carb
1  21   6  160 110  3.9 2.62 16.46  0  1    4    4

警告消息:在{中:较长的对象长度不是较短对象长度的倍数

后续问题

是否有一种扩展现有语法的简洁方法,以便在qazxsw poi调用的右侧获得条件评估,理想情况是保持在dplyr工作流程中?

r function dataframe dplyr lazy-evaluation
4个回答
14
投票

由于此处作用域的工作方式,您无法从filter语句中访问数据框。幸运的是,你不需要。

尝试:

if

在这里,您可以在条件中使用'mtcars %>% filter(am == 1) %>% filter({if("cyl" %in% names(.)) cyl else NULL} == 4) '对象,以便检查列是否存在,如果存在,则可以将列返回到.函数。

编辑:根据docendo discimus'对问题的评论,你可以访问数据框但不是隐含的 - 即你必须用filter专门引用它


2
投票

我知道我迟到了,但这里的答案更符合你最初的想法:

.

基本上,你错过了mtcars %>% filter(am == 1) %>% { if("cyl" %in% names(.)) filter(., cyl == 4) else . } .。请注意这是因为管道没有将filter添加到.,因为它位于filter(expr)包围的表达式中。


0
投票

编辑:不幸的是,这太好了,不可能

我可能有点迟到了。但是

{}

一个办法?


0
投票

这段代码可以解决问题并且非常灵活。 ^和$是正则表达式,用于执行完全匹配。

mtcars %>% 
 filter(am == 1) %>%
 try(filter(absent_column== 4))
© www.soinside.com 2019 - 2024. All rights reserved.