【问题标题】:Create column identifying minimum character from within a group and label ties创建从组中识别最小字符的列并标记关系
【发布时间】:2015-11-06 13:59:08
【问题描述】:

我有 10 个主题的配对数据(有些缺失,有些并列)。我的目标是选择具有最佳disc_grade(A > B > C)的eye,并从下面的数据框中相应地标记关系。

我不知道如何使用 R 代码为每个主题选择具有最佳 disc_grade 的行。

df <- structure(list(patientID = c(1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 
6, 7, 7, 8, 8, 9, 9, 10, 10), eye = c("R", "L", "R", "L", "R", 
"L", "R", "L", "R", "L", "R", "L", "R", "L", "R", "L", "R", "L", 
"R", "L"), disc_grade = c(NA, "B", "C", "B", "B", "C", "B", "C", 
"B", "A", "B", "B", "C", "B", NA, NA, "B", "C", "B", "C")), .Names = c("patientID", "eye", "disc_grade"), class = c("tbl_df", "data.frame"), row.names = c(NA, -20L))

想要的输出是:

   patientID   eye disc_grade
2          1   L          B
4          2   L          B
5          3   R          B
7          4   R          B
10         5   L          A
11         6   Tie        B
14         7   L          B
17         9   R          B
19        10   R          B

【问题讨论】:

    标签: r data.table dplyr subset


    【解决方案1】:

    这似乎有效:

    df %>% 
      group_by(patientID) %>% 
      filter(disc_grade == min(disc_grade, na.rm=TRUE)) %>%
      summarise(eye = if (n()==1) eye else "Tie", disc_grade = first(disc_grade))
    
      patientID   eye disc_grade
          (dbl) (chr)      (chr)
    1         1     L          B
    2         2     L          B
    3         3     R          B
    4         4     R          B
    5         5     L          A
    6         6   Tie          B
    7         7     L          B
    8         9     R          B
    9        10     R          B
    

    第 8 组有一个警告,但由于filterNAs 上的工作方式,我们得到了预期的结果。


    带data.table:

    setDT(df)[, 
      .SD[ disc_grade == min(disc_grade, na.rm=TRUE) ][,
        .( eye = if (.N==1) eye else "Tie", disc_grade = disc_grade[1] )
      ]
    , by=patientID]
    

    同样,有一个警告,但现在我们确实得到了第 8 组的一行,因为 [ 不会忽略 NAs。为了解决这个问题,您可以在操作之前或之后过滤 NA(如其他答案所示)。我在主要操作期间执行此操作的最佳想法非常复杂:

    setDT(df)[, 
      .SD[ which(disc_grade == min(disc_grade, na.rm=TRUE)) ][,
        if (.N >= 1) list( eye = if (.N==1) eye else "Tie", disc_grade = disc_grade[1] )
      ]
    , by=patientID]
    

    【讨论】:

      【解决方案2】:

      data.table 的一个选项

      library(data.table)
      na.omit(setDT(df))[, eye:=if(uniqueN(disc_grade)==1 & 
                  .N >1)  'Tie'  else eye, patientID
               ][order(factor(disc_grade, levels=c('A', 'B', 'C'))),
                    .SD[1L] ,patientID][order(patientID)]
      #    patientID eye disc_grade
      #1:         1   L          B
      #2:         2   L          B
      #3:         3   R          B
      #4:         4   R          B
      #5:         5   L          A
      #6:         6 Tie          B
      #7:         7   L          B
      #8:         9   R          B
      #9:        10   R          B
      

      【讨论】:

        【解决方案3】:
        library(dplyr)
        
        df <- structure(list(patientID = c(1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 
                                           6, 7, 7, 8, 8, 9, 9, 10, 10), eye = c("R", "L", "R", "L", "R", 
                                                                                 "L", "R", "L", "R", "L", "R", "L", "R", "L", "R", "L", "R", "L", 
                                                                                 "R", "L"), disc_grade = c(NA, "B", "C", "B", "B", "C", "B", "C", 
                                                                                                           "B", "A", "B", "B", "C", "B", NA, NA, "B", "C", "B", "C")), .Names = c("patientID", "eye", "disc_grade"), class = c("tbl_df", "data.frame"), row.names = c(NA, -20L))
        
        
        
        df %>%
          filter(!is.na(disc_grade)) %>%                     ## remove rows with NAs
          group_by(patientID) %>%                            ## for each patient
          filter(disc_grade == min(disc_grade)) %>%          ## keep the row (his eye) that has the best score
          mutate(eye_upd = ifelse(n() > 1, "tie", eye)) %>%  ## if you kept both eyes you have a tie
          select(patientID,eye_upd,disc_grade) %>%
          distinct()
        
        #    patientID eye_upd disc_grade
        #        (dbl)   (chr)     (fctr)
        # 1         1       L          B
        # 2         2       L          B
        # 3         3       R          B
        # 4         4       R          B
        # 5         5       L          A
        # 6         6     tie          B
        # 7         7       L          B
        # 8         9       R          B
        # 9        10       R          B
        

        【讨论】:

        • 与@JasonAizkalns 非常相似 :-)
        【解决方案4】:

        当然有更好的方法来做到这一点,但这可以完成工作......需要更多咖啡......

        df_orig <- df
        
        library(dplyr)
        
        df %>%
          filter(!is.na(disc_grade)) %>%
          group_by(patientID) %>%
          summarise(best = min(disc_grade)) %>%
          left_join(., df_orig, by = c("patientID" = "patientID",
                                       "best" = "disc_grade")) %>%
          group_by(patientID) %>%
          mutate(eye = ifelse(n() > 1, "tie", eye)) %>%
          distinct(patientID) %>% 
          select(patientID, eye, best)
        

        注意:由于类型对话,我能够逃脱 min(disc_grade)。考虑看看as.numeric(as.factor(df$disc_grade))

        【讨论】:

          猜你喜欢
          • 2013-10-18
          • 1970-01-01
          • 2016-08-13
          • 1970-01-01
          • 1970-01-01
          • 2021-05-21
          • 2011-08-25
          • 2022-01-16
          • 2021-09-06
          相关资源
          最近更新 更多