【问题标题】:how to capture logic from case_when in dplyr如何从 dplyr 中的 case_when 捕获逻辑
【发布时间】:2022-01-22 09:25:36
【问题描述】:

我正在使用dplyr 中的case_when() 创建以下列result

z <- tibble(a = c(40, 30, NA), 
       b = c(NA, 20, 10))


z %>%
          mutate(result = case_when(
                    !is.na(a) ~ a,
                    is.na(a) & !is.na(b) ~ b
          )
          )  

上面给出了以下内容:

      a     b result
  <dbl> <dbl>  <dbl>
1    40    NA     40
2    30    20     30
3    NA    10     10   

但是,我想同时创建另一列result_logic,它显示result 中的值从哪里提取(a 或b)。输出将如下所示。

      a     b result result_logic
  <dbl> <dbl>  <dbl>        <chr>
1    40    NA     40          a
2    30    20     30          a
3    NA    10     10          b

有什么方法可以捕获在case_when() 中评估的这个逻辑?

谢谢

【问题讨论】:

  • 我认为您需要进行两次逻辑检查,因为mutate 每次都创建一个变量。在一个 mutate 函数中进行两项检查很容易(在下面的答案中添加) - 您是否有特殊原因要从一个 case_when 测试中获得两列输出?

标签: r dplyr tidyverse


【解决方案1】:

类似以下内容?

library(tidyverse)

z <- tibble(a = c(40, 30, NA), 
            b = c(NA, 20, 10))

z %>%
  mutate(result = case_when(
    !is.na(a) ~ str_c(a, "a", sep = " "),
    is.na(a) & !is.na(b) ~ str_c(b, "b", sep = " "))) %>% 
  separate(result, into=c("result", "result_logic"), convert = T)

#> # A tibble: 3 × 4
#>       a     b result result_logic
#>   <dbl> <dbl>  <int> <chr>       
#> 1    40    NA     40 a           
#> 2    30    20     30 a           
#> 3    NA    10     10 b

【讨论】:

  • 谢谢。我试图避免两个不同的“case_when()”调用。在我的真实数据集中,我的 case_when 有更多“案例”——如果有办法处理单个“case_when()”会简单得多……如果可能的话
  • @mdb_ftl:我已经更新了我的解决方案,现在它只使用了一个case_when。希望对你有帮助!
【解决方案2】:

这是一种替代方法,仅限dplyr

library(dplyr)

z %>% 
  mutate(result = case_when(
    !is.na(a) ~ a, 
    is.na(a) & !is.na(b) ~ b),
    across(-result, ~case_when(
    !is.na(.) ~ cur_column()), .names = 'new_{col}'),
    result_logic = coalesce(new_a, new_b), .keep="unused")
  a     b result result_logic
  <dbl> <dbl>  <dbl> <chr>       
1    40    NA     40 a           
2    30    20     30 a           
3    NA    10     10 b  

【讨论】:

    【解决方案3】:

    您可以颠倒上述两个步骤,让第二个步骤“简单地”选择所选值。这将只涉及一个case_when 调用:

    library(tidyverse)
    
    z <- tibble(a = c(40, 30, NA), 
                b = c(NA, 20, 10))
    
    z %>% 
      mutate(result_logic = case_when(
        !is.na(a) ~ "a",
        is.na(a) & !is.na(b) ~ "b"
      ),
      result = map2_dbl(row_number(), result_logic, ~ z[[.x, .y]]))
    
    #> # A tibble: 3 x 4
    #>       a     b result_logic result
    #>   <dbl> <dbl> <chr>         <dbl>
    #> 1    40    NA a                40
    #> 2    30    20 a                30
    #> 3    NA    10 b                10
    

    reprex package (v2.0.1) 于 2021-12-20 创建

    【讨论】:

      【解决方案4】:
      library(dplyr, warn.conflicts = FALSE)
      z <- tibble(a = c(40, 30, NA), 
             b = c(NA, 20, 10))
      
      z %>% 
        mutate(
          result = do.call(coalesce, across(a:b)),
          result_logic = 
            do.call(coalesce,
              across(a:b, ~ ifelse(is.na(.), NA, cur_column())))
        )
      #> # A tibble: 3 × 4
      #>       a     b result result_logic
      #>   <dbl> <dbl>  <dbl> <chr>       
      #> 1    40    NA     40 a           
      #> 2    30    20     30 a           
      #> 3    NA    10     10 b
      

      reprex package (v2.0.1) 于 2021 年 12 月 20 日创建

      【讨论】:

        猜你喜欢
        • 2020-09-16
        • 2018-05-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多