当前位置: 首页 > 知识库问答 >
问题:

仅当列存在时执行dplyr操作

锺功
2023-03-14

根据对条件dplyr评估的讨论,我想根据传递的数据帧中是否存在参考列,有条件地在管道中执行一个步骤。

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 .
  }

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

过滤器中出错(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" 

我想扩展这个问题,以解释过滤器调用中=右侧的评估。例如,下面的语法试图过滤第一个可用值。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

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

为了在过滤器调用的右侧获得条件求值,最好是保持在dplyr工作流中,是否有一种扩展现有语法的简洁方法?

共有3个答案

凌展
2023-03-14

我知道我来晚了,但这里有一个更符合你最初想法的答案:

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

基本上,你错过了 过滤器中。注意这是因为管道没有添加过滤器(expr),因为它位于一个被{}包围的表达式中。

纪勇军
2023-03-14
匿名用户

在dplyr中跨()使用

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

删除cyl后,它会抛出一个错误:

mtcars %>% 
  select(!cyl) %>% 
  filter(am == 1) %>% 
  filter(cyl == 4)

使用any_of(注意您必须编写"cyl"而不是cyl):

mtcars %>% 
  select(!cyl) %>% 
  filter(am == 1) %>% 
  filter(across(any_of("cyl"), ~.x == 4))
#N.B. this is equivalent to just filtering by `am == 1`.

慕迪
2023-03-14

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

尝试:

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

在这里,您可以使用“”。条件中的'对象,因此您可以检查列是否存在,如果存在,您可以将列返回给filter函数。

编辑:根据docendo discimus对该问题的评论,您可以访问数据帧,但不能隐式访问,即您必须使用专门引用它

 类似资料:
  • 我在Java 8中使用SPARK-SQL-2.4.1v。我有一个场景,我将被传递列名为list/seq,对于这些列,我只需要执行某些操作,如sum、avg、percentages等。 数据库中的示例数据。 上述逻辑仅适用于在选择列中“column1”可用时。这在第二个集合中是失败的,因为“column1”不是select,所以我需要一些理解为什么这只适用于作为“column1”的选定列是可用的。我

  • 问题内容: 我有2张桌子- : 第二张桌子- : 我只需要选择未取消的预订(在此示例中仅为ID 3)。我可以轻松地选择带有简单条件的已取消,但由于未在此处取消工作,因此我在努力避免未取消。 问题答案: 要么: 第一个版本更直观,但是我认为第二个版本通常可以获得更好的性能(假设您在联接中使用的列上有索引)。 第二个版本有效,因为返回第一个表中所有行的一行。当条件成功,这些行会包括从第二表中的列,就像

  • 问题内容: 我有一个http服务器(使用启动),我想做一些操作。 我该怎么做(在Linux上)?在ctrl-C的情况下可以进行那些操作吗? 我不熟悉Unix信号,因此答案可能很简单。 问题答案: 您可以使用信号包订购TERM和INT信号。但是请注意,只有在明确终止进程时才发送这些信号。正常退出(由流程本身启动)不涉及任何信号。我认为,对于正常退出,只需在主例程中执行某些操作即可(该例程应该生成工作

  • 问题内容: 我正在使用自定义的CreateView(CourseCreate)和UpdateView(CourseUpdate)保存和更新课程。保存课程后,我想采取措施。我将在新课程的讲师和用户之间建立新的多对多关系(如果尚不存在)。 因此,我想将“课程”另存为课程,然后使用“ course.faculty”创建该新关系。做到这一点的最佳地点在哪里? 我正在尝试在视图的form_valid中执行此

  • 问题内容: 我有2个简单的mysql表。前1个称为mail,具有2行: 第二个称为块,并具有1行: 我想从发送鲍勃电子邮件但未在阻止表中阻止的第一个表中选择发件人。因此结果应为: 我尝试了以下查询,但未返回结果: 问题答案: 左联接将产生不匹配的行。 这些是您需要过滤的行。 以固定值进行联接有点麻烦,但是(根据您的表)更常见的联接是:

  • 我已经在GitHub操作中设置了一个工作流来运行我的测试并创建测试覆盖的工件。我的YAML文件的精简版本如下所示: 问题是当测试失败时,工件不会被创建。 我从文档中找到了关于的条件,但这也会导致在我的步骤失败时运行此步骤。我不希望发生这种情况,因为在这种情况下没有什么可归档的。 如果上一步已经运行(成功或失败),我如何才能运行此步骤?