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

我可以在给定的case_when真子句中做多个作业吗?

章玮
2023-03-14

更新:显然这个特性现在计划在dplyr上使用,正如这里讨论的:https://github.com/tidyverse/dplyr/pull/6145

在SQL中,当验证了给定的情况时,可以分配多个变量,比如var1和var2,构造如下

条件then var1 = x,var2 = y时的情况

dplyr::case_when(或tidyverse中的其他任何东西)是否支持这个有用的功能),如果是这样,如何?!

请注意,在下面的示例中,var1、var2和var3具有完全相同的测试条件,即物种=="setosa",退化情况为TRUE。我想通过不重复这些条件来减少这种冗余:对case_when(或类似)的一次调用,尽管分别对var1、var2和var3使用不同的eval_on_true表达式。显然,在这个例子中,冗余不是问题,但是我的case_when在现实生活中的例子中变得非常大和复杂。

library(tidyverse)

# create example data
set.seed(1337)
data <- iris %>%
  sample_n(5) %>%
  select(Petal.Length, Petal.Width, Species) %>%
  as_tibble()
data
#> # A tibble: 5 × 3
#>   Petal.Length Petal.Width Species   
#>          <dbl>       <dbl> <fct>     
#> 1          5.5         1.8 virginica 
#> 2          5           1.9 virginica 
#> 3          1.5         0.2 setosa    
#> 4          5.9         2.3 virginica 
#> 5          4.1         1.3 versicolor
data %>%
  mutate(var1 = case_when(Species == "setosa" ~ "green", TRUE ~ "blue"),
         var2 = case_when(Species == "setosa" ~ Petal.Length * 99, TRUE ~ Petal.Length),
         var3 = case_when(Species == "setosa" ~ as.Date("2002-12-01"), TRUE ~ as.Date("2003-12-02")))
#> # A tibble: 5 × 6
#>   Petal.Length Petal.Width Species    var1   var2 var3      
#>          <dbl>       <dbl> <fct>      <chr> <dbl> <date>    
#> 1          5.5         1.8 virginica  blue    5.5 2003-12-02
#> 2          5           1.9 virginica  blue    5   2003-12-02
#> 3          1.5         0.2 setosa     green 148.  2002-12-01
#> 4          5.9         2.3 virginica  blue    5.9 2003-12-02
#> 5          4.1         1.3 versicolor blue    4.1 2003-12-02

由reprex包(v2.0.1)于2022-02-09创建

共有3个答案

殷永嘉
2023-03-14

也许这有帮助:

library(tidyverse)

# create example data
set.seed(1337)
data <- iris %>%
  sample_n(5) %>%
  as_tibble()
data
#> # A tibble: 5 x 5
#>   Sepal.Length Sepal.Width Petal.Length Petal.Width Species   
#>          <dbl>       <dbl>        <dbl>       <dbl> <fct>     
#> 1          6.4         3.1          5.5         1.8 virginica 
#> 2          6.3         2.5          5           1.9 virginica 
#> 3          5.3         3.7          1.5         0.2 setosa    
#> 4          6.8         3.2          5.9         2.3 virginica 
#> 5          5.7         2.8          4.1         1.3 versicolor

data %>%
  mutate(
    sepal_size = case_when(
      Sepal.Length > 6 & Sepal.Width > 3 ~ "big",
      Sepal.Width > 3 ~ "medium",
      TRUE ~ "small"
    ),
    petal_size = case_when(
      Petal.Length > 5 ~ "big",
      TRUE ~ "small"
    ),
    is_fancy = TRUE
  )
#> # A tibble: 5 x 8
#>   Sepal.Length Sepal.Width Petal.Length Petal.Width Species    sepal_size
#>          <dbl>       <dbl>        <dbl>       <dbl> <fct>      <chr>     
#> 1          6.4         3.1          5.5         1.8 virginica  big       
#> 2          6.3         2.5          5           1.9 virginica  small     
#> 3          5.3         3.7          1.5         0.2 setosa     medium    
#> 4          6.8         3.2          5.9         2.3 virginica  big       
#> 5          5.7         2.8          4.1         1.3 versicolor small     
#> # … with 2 more variables: petal_size <chr>, is_fancy <lgl>

< sup >创建于2022-02-08,由reprex软件包(2.0.1版)要执行相反的操作,您可以:

iris %>%
  mutate(
    selected = Species == "setosa",
    var1 = ifelse(selected, Petal.Length * 99, Petal.Length),
    var2 = ifelse(selected, as.Date("2002-12-01"), as.Date("2003-12-02"))
  )
牟稳
2023-03-14

如果我们想通过将具有不同值的单个列相乘来创建新列,一种tidyverse方法是使用imap(默认情况下,默认. y是序列,如果我们传递未命名元素)循环遍历乘数值,返回带有transmute的单个列,然后将这些列与原始数据绑定

library(purrr)
library(dplyr)
library(stringr)
imap_dfc(c(10, 99), ~ data %>% 
   transmute(!! str_c('var', .y) := 
   case_when(Species == "setosa"~ Petal.Length * .x, 
              TRUE ~ Petal.Length))) %>% 
   bind_cols(data, .)

-输出

# A tibble: 5 × 7
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species     var1  var2
         <dbl>       <dbl>        <dbl>       <dbl> <fct>      <dbl> <dbl>
1          6.4         3.1          5.5         1.8 virginica    5.5   5.5
2          6.3         2.5          5           1.9 virginica    5     5  
3          5.3         3.7          1.5         0.2 setosa      15   148. 
4          6.8         3.2          5.9         2.3 virginica    5.9   5.9
5          5.7         2.8          4.1         1.3 versicolor   4.1   4.1
王飞虎
2023-03-14

case_when的问题在于接受长度nrow 或 1 的值。因此,您必须通过生成 nrow 1 行数据帧列表来欺骗case_when。访问器函数 lod(定义如下)构造一个 1 行数据帧的列表:

lod <- function(...) {
  args <- list(...)
  do.call(function(...) mapply(data.frame, ..., SIMPLIFY = FALSE), args)
}

lod(x = 1:4, y = letters[1:4])

[[1]]
  x y
1 1 a

[[2]]
  x y
1 2 b

[[3]]
  x y
1 3 c

[[4]]
  x y
1 4 d

然后编写case_when语句,使用 lod 对变量进行分组,如下所示:

data |>
  mutate(case_when(Species == "setosa" ~
                     lod(var1 = "green",
                         var2 = Petal.Length * 99,
                         var3 = as.Date("2002-12-01")),
                   TRUE ~
                     lod(var1 = "blue",
                         var2 = Petal.Length,
                         var3 = as.Date("2003-12-02"))) |>
         bind_rows())

+ # A tibble: 5 x 6
  Petal.Length Petal.Width Species    var1   var2 var3      
         <dbl>       <dbl> <fct>      <chr> <dbl> <date>    
1          5.5         1.8 virginica  blue    5.5 2003-12-02
2          5           1.9 virginica  blue    5   2003-12-02
3          1.5         0.2 setosa     green 148.  2002-12-01
4          5.9         2.3 virginica  blue    5.9 2003-12-02
5          4.1         1.3 versicolor blue    4.1 2003-12-02

最后的< code>bind_rows是< code>mutate接受新变量所必需的。

 类似资料:
  • 问题内容: 我想检查布尔值是否为真,然后在WHERE子句中确定要使用的条件。 假设布尔变量是@checkbool: 有否否定条件的方法?像在C ++中一样,您可以执行!(condition)。 如果不是,解决此问题的最佳方法是什么? 谢谢! 问题答案: SQL在C中的等效项是。但是,在您的情况下,您还需要其他东西:您需要建立一个条件,该条件根据的值在两个选择之间做出决定,如下所示:

  • 问题内容: 在Java中,我想做这样的事情: …代替: 有什么办法吗? 问题答案: 从Java 7开始,这已经成为可能。多捕获块的语法为: 但是请记住,如果所有异常都属于同一类层次结构,则可以简单地捕获该基本异常类型。 还要注意,如果从ExceptionA直接或间接继承了ExceptionB,则不能在同一块中同时捕获ExceptionA和ExceptionB。编译器会抱怨:

  • 这段代码 产生如下数据帧: 我想看到的结果是这个数据框: 因为对于行C有两个条件为真,所以我希望为它们中的每一个创建一行。我怎样才能做到这一点?

  • 当我从Oracle Java教程中读到这篇文章时,我正在查看一个经常重复的谣言,即JVM上的守护进程线程以某种特殊的方式处理块(它们不会,好吗?): 注意:如果在执行或代码时JVM退出,那么块可能不会执行。同样,如果执行或代码的线程被中断或终止,则块可能不会执行,即使应用程序作为一个整体继续。 (重点是我的。)被打断的那一点引起了我的注意! 我认为,如果一个线程处于try/catch代码中并被中断

  • 问题内容: 我想在我的MySQL服务器上执行以下操作: 这在控制台上工作正常,但在我的Java PreparedStatement中却无法正常工作。它在’;’处引发带有语法错误的异常。分离语句。我喜欢该变量,因为我不必重复查找子句,但是如有必要,我可以重写它。与UNION子句相对应的JOIN也有点尴尬。 谢谢, 约书亚记 问题答案: JDBC从未支持解析定界查询。每次调用都是一次数据库访问。也许您

  • 问题内容: 我最近设法将几个手动创建的作业转换为DSL脚本(内联为临时的“种子”作业),并且感到惊讶的是它如此简单。现在,我想摆脱 多个 种子工作,并尝试更整洁地构建事物。 为此,我创建了一个新的存储库,并将所有Groovy DSL脚本提交给它。然后,我创建了一个Jenkins作业,该作业从存储库中提取,并且只有一个 Process Job DSLs 步骤。此步骤已选中 “在文件系统 上 查找”