【问题标题】:Writing other columns when matching a condition匹配条件时写入其他列
【发布时间】:2022-01-06 09:35:42
【问题描述】:

我想创建一个新列,仅在它匹配特定条件时记录它(此处为 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 &gt; 2),在更复杂的情况下,这使得阅读代码非常不安并且容易出错,尤其是当有多个条件时。

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

  • 创建新变量 (mutate())
  • 仅在条件匹配时记录(​​if_elsecase_when()
  • 仅当行的条件匹配时才写入另一列的值。 (我被困在这里

看起来像这样的东西:

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 中的任何解决方案都是理想的。

【问题讨论】:

    标签: r dplyr conditional-statements


    【解决方案1】:

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

    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
    

    【讨论】:

    • 这看起来是一个不错的折衷方案。在验证这个类似于下面的@JKupzig 之前,我会等一下看看是否还有其他解决方案
    【解决方案2】:

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

    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 专门用于强制您在 true 和 false 中使用相同的类型论据。”)。请参阅有关此的更多信息,例如Different behavior of if else statement and if_else.

    【讨论】:

      【解决方案3】:

      实现您想要的那种抽象是可能的,但它确实需要更多的设置。 mutate 实际上比你想象的更灵活。您可以将脚本传递给它。假设你写了类似A %&gt;% mutate({...}) 的东西。如果脚本{...} 返回一个数据框,那么它的列将直接在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
      

      【讨论】:

      • 这看起来很整洁,但是粘贴后我无法运行代码。它说找不到out
      • 我正在使用 R 4.1.2 和 dplyr 1.0.7。尝试将两者都升级到最新版本。如果您无法升级,请在脚本周围使用另一个包装器,例如 mutate(local({...}))。 @mikacrem
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-20
      • 1970-01-01
      • 2023-03-10
      • 2021-12-21
      • 1970-01-01
      • 2015-06-06
      • 1970-01-01
      相关资源
      最近更新 更多