【问题标题】:Deal with missing data in row-wise manipulation在逐行操作中处理缺失数据
【发布时间】:2022-06-10 17:38:51
【问题描述】:
ID <- 1:6
math <- c("YES","NO","YES","NO",NA,NA)
history <- c(NA,NA,"NO","NO","YES",NA)

dt <- data.frame(ID, math, history)

  ID math history
1  1  YES    <NA>
2  2   NO    <NA>
3  3  YES      NO
4  4   NO      NO
5  5 <NA>     YES
6  6 <NA>    <NA>

我想做一个额外的列(“通过”)如下

  1. 如果学生至少有一次“是”:“是” (不管其他主体是否缺少数据。)

  2. 如果学生没有得到“是”

    • 如果两个受试者都缺少数据:NA
    • 如果主题之一是“否”:“否”

所以,列会是这样的: (我可以使用这个最小的示例手动执行此操作。 但不是我的真实数据)

> dt
  ID math history pass
1  1  YES    <NA>  YES
2  2   NO    <NA>   NO
3  3  YES      NO  YES
4  4   NO      NO   NO
5  5 <NA>     YES  YES
6  6 <NA>    <NA> <NA>

我尝试使用

dt$pass <- ifelse(rowSums(dt[,-1]=="YES",na.rm=T)>0,"YES","NO")

这段代码,但它很棘手 因为如果我输入na.rm=TRUE,他们认为 NA 是“否” (ID 6 学生将是“否”)

如果我输入na.rm=FALSE,则只考虑同时拥有两个学科数据的学生。

在我的数据中,我有很多列,不仅是数学和历史。

【问题讨论】:

    标签: r row rowsum rowwise


    【解决方案1】:
    library(tidyverse)
    
    ID <- 1:6
    math <- c("YES", "NO", "YES", "NO", NA, NA)
    history <- c(NA, NA, "NO", "NO", "YES", NA)
    
    dt <- data.frame(ID, math, history)
    
    dt |> 
      rowwise() |> 
      mutate(pass = case_when(
        sum(c_across(-ID) == "YES", na.rm = TRUE) >= 1 ~ "YES",
        sum(c_across(-ID) == "NO", na.rm = TRUE) >= 1  ~ "No",
        TRUE                                           ~ NA_character_
      ))
    #> # A tibble: 6 × 4
    #> # Rowwise: 
    #>      ID math  history pass 
    #>   <int> <chr> <chr>   <chr>
    #> 1     1 YES   <NA>    YES  
    #> 2     2 NO    <NA>    No   
    #> 3     3 YES   NO      YES  
    #> 4     4 NO    NO      No   
    #> 5     5 <NA>  YES     YES  
    #> 6     6 <NA>  <NA>    <NA>
    

    reprex package (v2.0.1) 于 2022-06-10 创建

    【讨论】:

      【解决方案2】:

      似乎顺序很重要:

      dt$pass <- NA
      dt$pass[dt$math == "NO" | dt$history=="NO"] <- "NO"
      dt$pass[dt$math == "YES" | dt$history=="YES"] <- "YES"
      
      > dt
        ID math history pass
      1  1  YES    <NA>  YES
      2  2   NO    <NA>   NO
      3  3  YES      NO  YES
      4  4   NO      NO   NO
      5  5 <NA>     YES  YES
      6  6 <NA>    <NA> <NA>
      

      【讨论】:

      • 如果超过2个科目,需要写一堆行来识别通过与否。
      • 是的,我的回答是在编辑之前。我同意@Carl 的回答更具概括性。
      【解决方案3】:

      试试这个

      library(dplyr)
      dt %>% mutate(pass = case_when(math == "YES" | history == "YES" ~ "YES" ,
       is.na(math) & is.na(history) ~ NA_character_ ,
       TRUE ~ "NO"))
      

      【讨论】:

      • 如果超过2个科目,需要写一堆行来识别通过与否。
      【解决方案4】:

      一个 tidyverse 解决方案,在主题的数量(和名称)方面是稳健的:

      library(tidyverse)
      
      dt %>% 
        mutate(
          pass=dt %>% 
                 pivot_longer(-ID) %>% 
                 group_by(ID) %>% 
                 summarise(
                   anyYes=sum(value == "YES", na.rm=T), 
                   anyNo=sum(value == "NO", na.rm=T)
                 ) %>% 
                 mutate(
                   pass=ifelse(
                          anyYes >= 1, 
                          "YES", 
                          ifelse(anyNo >= 1, "NO", NA)
                         )
                 ) %>% 
                 pull(pass)
        )
        ID math history pass
      1  1  YES    <NA>  YES
      2  2   NO    <NA>   NO
      3  3  YES      NO  YES
      4  4   NO      NO   NO
      5  5 <NA>     YES  YES
      6  6 <NA>    <NA> <NA>
      

      关键是pivoting转长格式。

      【讨论】:

        【解决方案5】:

        一个简单的base 解决方案是

        dt$pass <- apply(dt[-1], 1, \(x) sort(x, dec = TRUE)[1])
        
        # > dt
        #   ID math history pass
        # 1  1  YES    <NA>  YES
        # 2  2   NO    <NA>   NO
        # 3  3  YES      NO  YES
        # 4  4   NO      NO   NO
        # 5  5 <NA>     YES  YES
        # 6  6 <NA>    <NA> <NA>
        

        它的dplyr 等效项是

        library(dplyr)
        
        dt %>%
          rowwise() %>%
          mutate(pass = sort(c_across(-1), dec = TRUE)[1]) %>%
          ungroup()
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-02-10
          • 1970-01-01
          • 2023-02-08
          • 2018-11-07
          • 2017-07-07
          • 2015-12-10
          相关资源
          最近更新 更多