如何从 dplyr 中的 case_when 捕获逻辑
Posted
技术标签:
【中文标题】如何从 dplyr 中的 case_when 捕获逻辑【英文标题】:how to capture logic from case_when in dplyr 【发布时间】: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
测试中获得两列输出?
【参考方案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 日创建
【讨论】:
以上是关于如何从 dplyr 中的 case_when 捕获逻辑的主要内容,如果未能解决你的问题,请参考以下文章
在 dplyr 中使用 case_when 改变新列时遇到问题
R语言dplyr包使用case_when函数和mutate函数生成新的数据列实战:基于单列生成新的数据列基于多列生成新的数据列