【问题标题】:Deleting duplicates in data based on the conditions of a date column and a different column in r根据日期列和r中不同列的条件删除数据中的重复项
【发布时间】:2022-09-23 08:25:43
【问题描述】:

在我的数据中,我们测量了 15 只动物的临床症状,每一种都有 10 个独特的样本日期。对于每个日期,两个人为每只动物记录临床症状(体温、肿胀等)。考虑到数据的所有其他部分,每只动物都有四行具有相同的采样日期。对于其中两行,有一个首字母,而对于另外两行,有一个不同的首字母或一个 NA(当那个采样器当天缺席时)。我在数据中的目标是删除在同一日期,在 4 行中的 2 行(每个唯一动​​物)中具有一组首字母的行,但在其他 2 行中具有相同日期的 NA(对于相同的动物)。

澄清:我想在 Initials 列中留下其他 NA。例如,对于动物 6,我想在所有 NA 中留下。但是对于其他有 4 行的动物,其中两行填充了首字母,另外两行有 NA,我想删除 NA 行。谢谢!

这是一些示例代码:

Data <- data.frame(matrix(ncol = 3, nrow = 24))
colnames(Data) <- c(\'AnimalID\', \'DateSampled\', \'Initials\')

Data$AnimalID <- c(1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6)

Data$DateSampled <- as.Date(c(\"2021-10-13\", \"2021-10-13\", \"2021-10-13\", \"2021-10-13\", \"2021-10-27\", \"2021-10-27\", \"2021-10-27\", \"2021-10-27\", \"2021-11-10\", \"2021-11-10\", \"2021-11-10\", \"2021-11-10\", \"2021-11-24\", \"2021-11-24\", \"2021-11-24\", \"2021-11-24\", \"2021-12-01\", \"2021-12-01\", \"2021-12-01\", \"2021-12-01\", \"2021-12-05\", \"2021-12-05\"))

Data$Initials <- c(\"AB\", \"AB\", NA, NA, \"AB\", \"AB\", \"CD\", \"CD\", \"AB\", \"AB\", NA, NA, \"AB\", \"AB\", \"CD\", \"CD\", \"AB\", \"AB\", NA, NA, NA, NA, NA, NA)

期望的输出:

AnimalID  |  DateSampled  | Initials
1         |  \"2021-10-13\" |  AB
1         |  \"2021-10-13\" |  AB
2         |  \"2021-10-27\" |  AB
2         |  \"2021-10-27\" |  AB
2         |  \"2021-10-27\" |  CD
2         |  \"2021-10-27\" |  CD
3         |  \"2021-11-10\" |  AB
3         |  \"2021-11-10\" |  AB
4         |  \"2021-11-24\" |  AB
4         |  \"2021-11-24\" |  AB
4         |  \"2021-11-24\" |  CD
4         |  \"2021-11-24\" |  CD
5         |  \"2021-12-01\" |  AB
5         |  \"2021-12-01\" |  AB
6         |  \"2021-12-05\" |  NA
6         |  \"2021-12-05\" |  NA

无论是 for 循环还是条件向量,如果对于相同的动物 id 和采样日期有一个 \"AB\"(或任何其他首字母集)和一个 \"NA\",我很想删除那些其中有 NA。谢谢您的帮助!

    标签: r duplicates conditional-statements delete-row


    【解决方案1】:

    如果你能提供预期的输出,我会更好。

    过滤的逻辑有点难以理解。

    据我所知,如果您只想删除 Initials 列中的所有 NA 数据并删除重复的行

    Data <- Data[!is.na(Data$Initials),]
    Data <- Data[!duplicated(Data),]
    

    这就是我猜你想要使用tidyverse 实现的目标:

    • distinct 将只输出数据中不同的行
    • filter 将删除 Initials 字段中任何带有 NA 的行
    library(tidyverse)
    Data %>%
      distinct() %>%
      filter(!is.na(Initials))
    # EweID DateSampled Initials
    # 1     1  2021-10-13       AB
    # 2     2  2021-10-27       AB
    # 3     2  2021-10-27       CD
    # 4     3  2021-11-10       AB
    # 5     4  2021-11-24       AB
    # 6     4  2021-11-24       CD
    # 7     5  2021-12-01       AB
    

    如果您仍想包含 EweID 在 NA 旁边没有任何其他首字母的 NA 行。只需添加另一个步骤即可找到在 Initials 列中只有 NA 的 EweID-DateSampled

    Data %>% distinct() %>%
      group_by(EweID, DateSampled) %>%
      summarise("var"=paste(Initials, collapse='-'))
    # EweID DateSampled   var
    # 1     1  2021-10-13 AB-NA
    # 2     2  2021-10-27 AB-CD
    # 3     3  2021-11-10 AB-NA
    # 4     4  2021-11-24 AB-CD
    # 5     5  2021-12-01 AB-NA
    # 6     6  2021-12-02    NA
    

    过滤 NA 行并将rbind 过滤到上面的输出

    Data %>% distinct() %>%
      group_by(EweID, DateSampled) %>%
      summarise("var"=paste(Initials, collapse='-')) %>%
      filter(var=="NA")
    # EweID DateSampled var
    # 1     6  2021-12-02  NA
    
    

    【讨论】:

      【解决方案2】:

      这是使用dplyr 实现此目的的一种方法。 filter(!is.na(Initials)) 将删除所有带有 NA 的行。 distinct() 将删除重复的行:

      library(dplyr)
      
      Data %>% 
        filter(!is.na(Initials)) %>% 
        distinct()
      
        EweID DateSampled Initials
      1     1  2021-10-13       AB
      2     2  2021-10-27       AB
      3     2  2021-10-27       CD
      4     3  2021-11-10       AB
      5     4  2021-11-24       AB
      6     4  2021-11-24       CD
      7     5  2021-12-01       AB
      

      更新


      感谢您澄清您的输出,这是一种实现方法。首先是为每只动物创建一个中间数据框并计算每组NA 的数量:

      Number_of_NA = Data %>%
        group_by(AnimalID)%>%
        summarise(n = sum(is.na(Initials)))
      
      > Number_of_NA
      # A tibble: 7 x 2
        AnimalID     n
           <dbl> <int>
      1        1     2
      2        2     0
      3        3     2
      4        4     0
      5        5     2
      6        6     4
      7        7     4
      

      如果我理解正确,您希望与NA 保持一致的组将始终具有 4 个 NA 值。您可以像以前一样使用它来过滤数据框中的所有NA,然后加入只有 4 个 NA 的组:

      Data %>% filter(!is.na(Initials)) %>%
        full_join(filter(Data, AnimalID %in% Number_of_NA$AnimalID[Number_of_NA$n == 4]))
      
         AnimalID DateSampled Initials
      1         1  2021-10-13       AB
      2         1  2021-10-13       AB
      3         2  2021-10-27       AB
      4         2  2021-10-27       AB
      5         2  2021-10-27       CD
      6         2  2021-10-27       CD
      7         3  2021-11-10       AB
      8         3  2021-11-10       AB
      9         4  2021-11-24       AB
      10        4  2021-11-24       AB
      11        4  2021-11-24       CD
      12        4  2021-11-24       CD
      13        5  2021-12-01       AB
      14        5  2021-12-01       AB
      15        6  2021-12-05     <NA>
      16        6  2021-12-05     <NA>
      17        6  2021-12-05     <NA>
      18        6  2021-12-05     <NA>
      19        7  2021-12-15     <NA>
      20        7  2021-12-15     <NA>
      21        7  2021-12-15     <NA>
      22        7  2021-12-15     <NA>
      

      数据


      Data = structure(list(AnimalID = c(1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 
      3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7), DateSampled = structure(c(18913, 
      18913, 18913, 18913, 18927, 18927, 18927, 18927, 18941, 18941, 
      18941, 18941, 18955, 18955, 18955, 18955, 18962, 18962, 18962, 
      18962, 18966, 18966, 18966, 18966, 18976, 18976, 18976, 18976
      ), class = "Date"), Initials = c("AB", "AB", NA, NA, "AB", "AB", 
      "CD", "CD", "AB", "AB", NA, NA, "AB", "AB", "CD", "CD", "AB", 
      "AB", NA, NA, NA, NA, NA, NA, NA, NA, NA, NA)), row.names = c(NA, 
      -28L), class = "data.frame")
      

      更新 2


      这是与您的过滤匹配的修改。在第一个数据框中我们group_by()动物ID和日期,然后计算NA的数量(with_NA)和观察总数total_n。在这种情况下,如果with_NA 等于total_n,这意味着只有 NA 可用于此 ID 和 Date,因此这些 NA 将被保留。

      library(dplyr)
      
      df_filt = Data %>%
        group_by(AnimalID, DateSampled)%>%
        summarise(with_NA = sum(is.na(Initials)), total_n = n(), 
                  to_filter = with_NA == total_n) %>% 
        filter(to_filter == TRUE)
      
      # A tibble: 3 x 5
      # Groups:   AnimalID [3]
        AnimalID DateSampled with_NA total_n to_filter
           <dbl> <date>        <int>   <int> <lgl>    
      1        3 2021-11-11        1       1 TRUE     
      2        6 2021-12-05        4       4 TRUE     
      3        7 2021-12-16        2       2 TRUE 
      

      然后我们可以使用类似于上次的东西来过滤数据帧中的所有 NA,然后根据上面的数据帧加入我们想要保留的那个:

      Data %>% filter(!is.na(Initials)) %>%
        full_join(filter(Data, AnimalID %in% df_filt$AnimalID & DateSampled %in% df_filt$DateSampled))%>%
        arrange(AnimalID)
      
         AnimalID DateSampled Initials
      1         1  2021-10-13       AB
      2         1  2021-10-13       AB
      3         2  2021-10-27       AB
      4         2  2021-10-27       AB
      5         2  2021-10-27       CD
      6         2  2021-10-27       CD
      7         3  2021-11-10       AB
      8         3  2021-11-10       AB
      9         3  2021-11-11     <NA>
      10        4  2021-11-24       AB
      11        4  2021-11-24       AB
      12        4  2021-11-24       CD
      13        4  2021-11-24       CD
      14        5  2021-12-01       AB
      15        5  2021-12-01       AB
      16        6  2021-12-05     <NA>
      17        6  2021-12-05     <NA>
      18        6  2021-12-05     <NA>
      19        6  2021-12-05     <NA>
      20        7  2021-12-15       CB
      21        7  2021-12-16     <NA>
      22        7  2021-12-16     <NA>
      

      在这种情况下,所有具有匹配 Date 和 AnimalID 与 Initial 的 NA 将被丢弃,并且仅保留该日期没有实际 Initial 的 NA。

      请注意,我在这里稍微修改了数据以反映所需的输出

      数据 2


      > Data
         AnimalID DateSampled Initials
      1         1  2021-10-13       AB
      2         1  2021-10-13       AB
      3         1  2021-10-13     <NA>
      4         1  2021-10-13     <NA>
      5         2  2021-10-27       AB
      6         2  2021-10-27       AB
      7         2  2021-10-27       CD
      8         2  2021-10-27       CD
      9         3  2021-11-10       AB
      10        3  2021-11-10       AB
      11        3  2021-11-10     <NA>
      12        3  2021-11-11     <NA>
      13        4  2021-11-24       AB
      14        4  2021-11-24       AB
      15        4  2021-11-24       CD
      16        4  2021-11-24       CD
      17        5  2021-12-01       AB
      18        5  2021-12-01       AB
      19        5  2021-12-01     <NA>
      20        5  2021-12-01     <NA>
      21        6  2021-12-05     <NA>
      22        6  2021-12-05     <NA>
      23        6  2021-12-05     <NA>
      24        6  2021-12-05     <NA>
      25        7  2021-12-15       CB
      26        7  2021-12-15     <NA>
      27        7  2021-12-16     <NA>
      28        7  2021-12-16     <NA>
      
      Data = structure(list(AnimalID = c(1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 
                                         3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7), DateSampled = structure(c(18913, 
                                                                                                                       18913, 18913, 18913, 18927, 18927, 18927, 18927, 18941, 18941, 
                                                                                                                       18941, 18942, 18955, 18955, 18955, 18955, 18962, 18962, 18962, 
                                                                                                                       18962, 18966, 18966, 18966, 18966, 18976, 18976, 18977, 18977
                                         ), class = "Date"), Initials = c("AB", "AB", NA, NA, "AB", "AB", 
                                                                          "CD", "CD", "AB", "AB", NA, NA, "AB", "AB", "CD", "CD", "AB", 
                                                                          "AB", NA, NA, NA, NA, NA, NA, "CB", NA, NA, NA)), row.names = c(NA, 
                                                                                                                                        -28L), class = "data.frame")
      

      【讨论】:

      • 您好,感谢您的回复!我现在会更新这个问题。我想将数据集中的其他 NA 留在 Initials 列中,它们是独立的,并且在同一日期没有另一个首字母。在我的数据框上实施此解决方案将删除我的姓名缩写列中的所有 NA。但我只想删除在同一日期有另一组首字母的 NA。谢谢!如果这没有意义,请告诉我!
      • 感谢您澄清您的输出,我更新了答案以遵循您的预期结果。这是你想要的 ?我还扩展了数据以包含另一个 NA 组,请参阅“数据”部分。
      • 非常感谢您的更新!这是非常有帮助的。不幸的是,并非我的所有数据都具有总是在一个日期出现 4 个的 NA,但我希望有一种方法可以过滤并仅删除 4 个日期实例的行,2 个带有首字母,2 个带有 NA。例如,如果对于相同的日期(有 4 行相同的日期),有 2 行带有 NA,2 行带有一组首字母,只保留首字母。请让我知道是否有任何其他方式可以澄清!
      • 我在答案中加入了“更新 2”。这次将保留所有在同一日期和动物 ID 没有首字母的 NA,并删除具有相同日期的首字母的 NA。
      猜你喜欢
      • 2021-09-09
      • 2020-06-22
      • 2021-06-20
      • 2021-01-10
      • 2021-03-20
      • 2021-12-15
      • 1970-01-01
      • 2016-04-26
      相关资源
      最近更新 更多