用一行dplyr代码替换%语句中的多个%

时间:2017-12-06 02:01:50

标签: r dplyr

我想创建一个标志,如果13列中的任何一个包含大量代码中的任何一个,则为1,否则为0。我需要使用dplyr,因为我的数据在数据库中。我可以在%语句中使用%%之后完成我的工作。我想知道是否有更简洁的方法来编写此代码。是否存在%in%的版本,允许左侧有多个变量?

以下代码给出了正确的结果。为简洁起见,我只包括5列和2行。

library(dplyr)

match_dx <- c(paste0("C0", 0:9), paste0("C", 10:20))

df <- tibble(dx1 = c("C00", "G01"),
   dx2 = c("C50", "Z11"),
   dx3 = c("D20", "D22"),
   dx4 = c("A40", "C21"),
   dx13 = c("G20", "C30"))

df %>% 
 mutate(flag = case_when(
      dx1 %in% match_dx ~ 1,
      dx2 %in% match_dx ~ 1,
      dx3 %in% match_dx ~ 1,
      dx4 %in% match_dx ~ 1,
      dx13 %in% match_dx ~ 1,
      T ~ 0
 ))

我想知道是否有像

这样的东西
df %>% 
 mutate(flag = case_when(
      any(vars(dx1:dx13) %in% match_dx) ~ 1,
      T ~ 0
 ))

这确实有效,但也许有类似或其他方法可以实现这一点,而不需要每个变量一行。

谢谢!

4 个答案:

答案 0 :(得分:4)

这是gather长期&#39;的一个选项。然后将spread格式化为&#39; wide&#39;

library(tidyverse)
df %>% 
    rownames_to_column('rn') %>%
    gather(key, val, -rn) %>% group_by(rn) %>%
    mutate(flag = as.integer(any(val %in% match_dx))) %>%
    spread(key, val)
# A tibble: 2 x 7 
# Groups:   rn [2]
#     rn  flag   dx1  dx13   dx2   dx3   dx4
#* <chr> <int> <chr> <chr> <chr> <chr> <chr>
#1     1     1   C00   G20   C50   D20   A40
#2     2     0   G01   C30   Z11   D22   C21

或者使用mutate_all创建逻辑列,然后reduce将其设置为单个逻辑向量,并mutate创建&#39;标记&#39;

df %>% 
  mutate_all(funs(. %in% match_dx)) %>% 
  reduce(`|`) %>%
  as.integer %>%
  mutate(df, flag = .)
# A tibble: 2 x 6
#     dx1   dx2   dx3   dx4  dx13  flag
#    <chr> <chr> <chr> <chr> <chr> <int>
#1   C00   C50   D20   A40   G20     1
#2   G01   Z11   D22   C21   C30     0

或使用@thelatemail

建议的Reduce/lapply base R选项
df$flag <- as.integer(Reduce(`|`, lapply(df, is.element, set=match_dx))) 

或使用%in%

as.integer(Reduce(`|`, lapply(df, `%in%`, match_dx))) 

答案 1 :(得分:3)

我们可以applymutate一起使用来比较所有列。

library(dplyr)

df %>%
  mutate(flag = apply(., 1, function(x) any(x %in% match_dx) * 1))
# # A tibble: 2 x 6
#     dx1   dx2   dx3   dx4  dx13  flag
#   <chr> <chr> <chr> <chr> <chr> <dbl>
# 1   C00   C50   D20   A40   G20     1
# 2   G01   Z11   D22   C21   C30     0

答案 2 :(得分:3)

注意:我忽略了这些是in-db SQL操作的必要性。这不适用于此。

library(dplyr)
library(purrrlyr)
library(purrr)

df %>% 
  by_row(~{ as.numeric(any(. %in% match_dx)) }, .to="flag") %>% 
  mutate(flag = flatten_dbl(flag))
## # A tibble: 2 x 6
##     dx1   dx2   dx3   dx4  dx13  flag
##   <chr> <chr> <chr> <chr> <chr> <dbl>
## 1   C00   C50   D20   A40   G20     1
## 2   G01   Z11   D22   C21   C30     0

答案 3 :(得分:2)

另一种使用purrr的替代方案:

library(dplyr)
library(purrr)

df %>% mutate(flag = map_int(transpose(.), ~ any(. %in% match_dx)))
#> # A tibble: 2 x 6
#>     dx1   dx2   dx3   dx4  dx13  flag
#>   <chr> <chr> <chr> <chr> <chr> <int>
#> 1   C00   C50   D20   A40   G20     1
#> 2   G01   Z11   D22   C21   C30     0