匹配条件时写入其他列

Writing other columns when matching a condition

我想创建一个新列,仅在它符合特定条件时记录它(此处 x > 2 ),然后 直接 覆盖另一个现有列(此处auxiliary) 对于条件 (x > 2) 返回 TRUE 的这些行。

df <- tibble(x = 1:5, y = 1:5, auxiliary = NA)


# A tibble: 5 x 3
  x     y auxiliary
<int> <dbl> <lgl>    
1      1     NA       
2      2     NA       
3      3     NA       
4      4     NA       
5      5     NA  

我可以在 mutate() 内的两个不同调用中成功完成此操作:

df %>% 
    mutate(result = if_else(condition = x > 2,
                      true = x+y,
                      false = NA_real_),
     auxiliary = if_else(condition = x > 2,
                         true = "Calculation done", 
                         false = NA_character_))

# A tibble: 5 x 4
  x     y auxiliary        result
<int> <dbl> <chr>             <dbl>
1     1      NA                   NA
2     2      NA                   NA
3     3      Calculation done      6
4     4      Calculation done      8
5     5      Calculation done      10

但是有一些代码重复(condition = x > 2),在更复杂的情况下,这使得阅读代码非常困难并且容易出错,尤其是在有多个条件时。

有没有办法通过不重复条件来简化上面的代码? :

看起来像这样的东西:

df %>% 
   mutate(result = case_when(
            x > 2 ~ x + y & auxiliary == "Calculation done", # we'd add the column reference here...
            TRUE ~ NA_real & auxiliary = NA_character_))


非常感谢!来自 tidyverse 的任何解决方案都是理想的。

我建议将应该多次使用的条件保存为字符串,然后在代码中使用该字符串作为变量,例如:

condition <- "x>2"
df %>% 
  mutate(result = ifelse(eval(parse(text=condition)),
                          x+y,
                          NA),
         auxiliary = ifelse(eval(parse(text=condition)),
                             "Calculation done", 
                             NA))

请注意,我使用的是基本 ifelse 语句,以避免我必须在列中使用相同类型的限制(“dplyr::if_else 专门用于强制您使用相同的类型输入你的真假论点。”)。查看更多信息,例如Different behavior of if else statement and if_else.

您可以将条件的结果保存在列中并使用它来避免一次又一次地评估相同的条件。

library(dplyr)

df <- tibble(x = 1:5, y = 1:5)

df %>% 
  mutate(condition = x > 2,
         result = if_else(condition,
                          true = x+y,
                          false = NA_integer_),
         auxiliary = if_else(condition,
                             true = "Calculation done", 
                             false = NA_character_))

#      x     y condition result auxiliary       
#  <int> <int> <lgl>      <int> <chr>           
#1     1     1 FALSE         NA NA              
#2     2     2 FALSE         NA NA              
#3     3     3 TRUE           6 Calculation done
#4     4     4 TRUE           8 Calculation done
#5     5     5 TRUE          10 Calculation done

可以实现您想要的那种抽象,但确实需要更多的设置。 mutate 其实比你想象的要灵活。您可以将脚本传递给它。假设你写了类似 A %>% mutate({...}) 的东西。如果脚本 {...} returns 一个数据框,那么它的列将直接在 A 中创建,或者如果它们共享相同的名称,则替换 A 中的现有列。所以你可以做

df %>% mutate({
  cond <- x > 2
  out <- tibble(.rows = n())
  mapply(
    \(var, true, false) out[[var]] <<- if_else(cond, true, false), 
    var = c("result", "auxiliary"), 
    true = list(x + y, "Calculation done"), 
    false = list(NA_integer_, NA_character_)
  )
  out
})

输出

# A tibble: 5 x 4
      x     y auxiliary        result
  <int> <int> <chr>             <int>
1     1     1 NA                   NA
2     2     2 NA                   NA
3     3     3 Calculation done      6
4     4     4 Calculation done      8
5     5     5 Calculation done     10