如何使用 case_when 而不是 if_else [我的代码有错误?]

how to use case_when rather then if_else [Error in my code?]

我想知道为什么我不能使用 dplyr::case_when 而不是 dplyr::if_else
可能我错过了什么。让我解释一下:

我得到了这个工作正常的操作:

df %>%
  mutate(
    keep = if_else(
      assembly_level != "Complete Genome" | genome_rep != "Full",
      FALSE,
      ifelse(
        version_status == "suppressed",
        FALSE,
        if_else(
          refseq_category %in% c("reference genome", "representative genome"),
          TRUE,
          if_else(
            rpseudo > 0.4,
            FALSE,
            TRUE
          )
        )
      )
    )
  )

但是,当我尝试以这种方式使用 case_when

df %>%
  mutate(
    keep = case_when(
      assembly_level != "Complete Genome" | genome_rep != "Full" ~ FALSE, 
      version_status == "suppressed" ~ FALSE,
      refseq_category %in% c("reference genome", "representative genome") ~ TRUE, 
      rpseudo > 0.4 ~ FALSE,
      TRUE ~ TRUE
    )
  )

我得到了不同的结果。

我认为问题出在功能的使用上。

如果您需要数据,它是一般public数据,可以在这里下载:ftp://ftp.ncbi.nlm.nih.gov/genomes/ASSEMBLY_REPORTS/assembly_summary_refseq.txt

获得:

read_tsv("ftp://ftp.ncbi.nlm.nih.gov/genomes/ASSEMBLY_REPORTS/assembly_summary_refseq.txt", 
         comment = "#",
         col_names = c(
           "assembly", "bioproject", "biosample", 
           "wgs_master", "refseq_category", "taxid", 
           "species_taxid", "organism_name", "infraspecific_name", 
           "isolate", "version_status", "assembly_level", 
           "release_type", "genome_rep", "seq_rel_date", 
           "asm_name", "submitter", "gbrs_paired_asm", 
           "paired_asm_comp", "ftp_path", "excluded_from_refseq", "relation_to_type_material"
         )
) %>%
  select(assembly, refseq_category, 
         assembly_level, genome_rep, 
         version_status, release_type) %>%
  mutate(
    rpseudo = runif(nrow(.), 0, 1)
  ) -> df
# it will got some warnings

提前致谢,

数据中有 NA 个。将 if_else 的输出存储在 df1 中,将 case_when 的输出存储在 df2 中。 df1$keepdf2$keep 之间的唯一区别是 df1$keep 中的 NA 很少,而 case_when 在那些地方有一些实际值。检查

table(df1$keep, useNA = "always")
# FALSE   TRUE   <NA> 
#156616  10386     79 

table(df2$keep, useNA = "always")
# FALSE   TRUE   <NA> 
#156647  10434      0 

如果你这样做

(156647 - 156616) + (10434 - 10386) #It gives exactly
#[1] 79

此外,如果您删除那些 NA 值,然后检查 df1df2 中的值,它们是否相同。

all(df1$keep[!is.na(df1$keep)] == df2$keep[!is.na(df1$keep)])
#[1] TRUE

NAif_elsecase_when 中的处理方式不同。考虑这个简化的例子以便更好地理解。

library(dplyr)
df <- data.frame(a = c(1:3, NA, 4:7), b = c(NA, letters[1:7]))

现在让我们创建一些随机条件进行测试。使用 if_else

df %>%
  mutate(res = if_else(a > 3, "Yes", 
                   if_else(b == "c", "No", 
                           if_else(a > 5, "Maybe", "Done"))))

#   a    b  res
#1  1 <NA> <NA>
#2  2    a Done
#3  3    b Done
#4 NA    c <NA>
#5  4    d  Yes
#6  5    e  Yes
#7  6    f  Yes
#8  7    g  Yes

但是,使用 case_when 你得到的输出是

df %>%
   mutate(res = case_when(a > 3 ~ "Yes", 
                          b == "c"~"No", 
                          a > 5 ~ "Maybe", 
                          TRUE ~ "Done"))

#   a    b  res
#1  1 <NA> Done
#2  2    a Done
#3  3    b Done
#4 NA    c   No
#5  4    d  Yes
#6  5    e  Yes
#7  6    f  Yes
#8  7    g  Yes

因此,如果您在 if_else 中注意到如果遇到 NA,它会立即 returns NA。但是,在 case_when 中,它将 NA 视为 FALSE,因此如果遇到 NA,它将转到下一个条件,直到满足任何条件,否则 return 的值 TRUE.

数据

set.seed(1234)
read_tsv("ftp://ftp.ncbi.nlm.nih.gov/genomes/ASSEMBLY_REPORTS/assembly_summary_refseq.txt",
comment = "#",
col_names = c(
       "assembly", "bioproject", "biosample", 
       "wgs_master", "refseq_category", "taxid", 
       "species_taxid", "organism_name", "infraspecific_name", 
       "isolate", "version_status", "assembly_level", 
       "release_type", "genome_rep", "seq_rel_date", 
       "asm_name", "submitter", "gbrs_paired_asm", 
       "paired_asm_comp", "ftp_path", "excluded_from_refseq", "relation_to_type_material"
     )
) %>%
select(assembly, refseq_category, 
      assembly_level, genome_rep, 
     version_status, release_type) %>%
 mutate(
  rpseudo = runif(nrow(.), 0, 1)
 ) -> df