case_when在mutate管道中

时间:2016-07-29 02:16:35

标签: r dplyr

似乎dplyr::case_whendplyr::mutate调用中的行为不像其他命令。例如:

library(dplyr)

case_when(mtcars$carb <= 2 ~ "low",
          mtcars$carb > 2 ~ "high") %>% 
  table

工作的:

.
high  low 
  15   17 

但是将case_when放在mutate链中:

mtcars %>% 
  mutate(cg = case_when(carb <= 2 ~ "low",
                        carb > 2 ~ "high"))

你得到:

 Error: object 'carb' not found

虽然这很好用

mtcars %>% 
  mutate(cg = carb %>% 
           cut(c(0, 2, 8)))

6 个答案:

答案 0 :(得分:36)

0.7.0的版本dplyr开始,case_whenmutate内工作如下:

library(dplyr) # >= 0.7.0
mtcars %>% 
  mutate(cg = case_when(carb <= 2 ~ "low",
                        carb > 2  ~ "high"))

有关详细信息:http://dplyr.tidyverse.org/reference/case_when.html

答案 1 :(得分:16)

我们可以使用.$

mtcars %>%  
     mutate(cg = case_when(.$carb <= 2 ~ "low",  .$carb > 2 ~ "high")) %>%
    .$cg %>%
    table()
# high  low 
#  15   17 

答案 2 :(得分:6)

感谢@sumedh:@hadley has explained这是TimeZone的一个众所周知的缺点:

  

[]()仍然有点实验,目前无效   在case_when内。这将在未来版本中修复。

答案 3 :(得分:1)

就我而言,准引号很有帮助。您可以预先创建一组定义了变异规则的带引号的公式(可以使用第一个公式中的已知列名,也可以使用!!并像第二个公式中那样动态创建规则),然后利用该公式在mutate-case_when之类的组合中

    library(dplyr)
    library(rlang)
    pattern <- quos(gear == 3L ~ "three", !!sym("gear") == 4L ~ "four", gear == 5L ~ "five")
    # Or
    # pattern <- list(
    #     quo(gear == 3L ~ "three"), 
    #     quo(!!sym("gear") == 4L ~ "four"),
    #     quo(gear == 5L ~ "five"))
    #
    mtcars %>% mutate(test = case_when(!!!pattern)) %>% head(10L)
#>     mpg cyl  disp  hp drat    wt  qsec vs am gear carb  test
#> 1  21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4  four
#> 2  21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4  four
#> 3  22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1  four
#> 4  21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1 three
#> 5  18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2 three
#> 6  18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1 three
#> 7  14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4 three
#> 8  24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2  four
#> 9  22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2  four
#> 10 19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4  four

我更喜欢这样的解决方案,因为它允许创建复杂的规则,例如将map2与LHS条件和RHS值一起使用以生成引用的公式

    library(rlang)
    library(purrr)
    map2(c(3, 4, 5), c("three", "four", "five"), ~quo(gear == !!.x ~ !!.y))
#> [[1]]
#> <quosure>
#> expr: ^gear == 3 ~ "three"
#> env:  0000000014286520
#> 
#> [[2]]
#> <quosure>
#> expr: ^gear == 4 ~ "four"
#> env:  000000001273D0E0
#> 
#> [[3]]
#> <quosure>
#> expr: ^gear == 5 ~ "five"
#> env:  00000000125870E0

并在不同的地方使用它,将其应用于不同的数据集,而无需在每次需要复杂的突变时都手动键入所有规则。

作为该问题的最终答案,另外7个符号和两个括号解决了该问题

library(rlang)
library(dplyr)
mtcars %>% 
    mutate(test = case_when(!!!quos(gear == 3L ~ "three", gear != 3L ~ "not three"))) %>% 
    head(10L)
#>     mpg cyl  disp  hp drat    wt  qsec vs am gear carb      test
#> 1  21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4 not three
#> 2  21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4 not three
#> 3  22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1 not three
#> 4  21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1     three
#> 5  18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2     three
#> 6  18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1     three
#> 7  14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4     three
#> 8  24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2 not three
#> 9  22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2 not three
#> 10 19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4 not three

reprex package(v0.2.1.9000)于2019-01-16创建

答案 4 :(得分:-2)

除了@ akrun上面的回答之外,请注意case_when() 的右括号不能将其放在自己的行上。

例如,这可以正常工作:

mtcars %>%  
   mutate(cg = case_when(
      .$carb <= 2 ~ "low",  .$carb > 2 ~ "high")) 

但这不是:

mtcars %>%  
   mutate(cg = case_when(
      .$carb <= 2 ~ "low",  .$carb > 2 ~ "high")
      ) 

答案 5 :(得分:-2)

library(dplyr)#加载dplyr软件包

    content150_fortified <- content150 %>% #creating a new variable
     mutate(number_yn = case_when( #creating a new column using mutate
        number >= 18 & number <=25 ~ "no", # if number is "none", make number_yn "no"
        number!="none" ~ "yes"  # if number is not "none", make number_yn "yes"
        )
      )