【问题标题】:R - Detect end of observations in groups and remove redundant rowsR - 检测组中观察的结束并删除冗余行
【发布时间】:2019-04-06 18:46:12
【问题描述】:

我有一个 data.frame 由大约 300k 行组成,每个 ID 有 24 行 - 每行代表对该 ID 的每小时观察。我的问题在于,对于某些 ID,观察在 24 小时过去之前结束 - 但仍有 24 行,其余行在其 3 个观察变量中具有 NA。

在简化表中会是这样的

ID    HOUR    OBS_1    OBS_2    OBS_3    MISC    MISC_2
1      0       29        32       34      19       21
1      1       21        12       NA      19       21
1      2       NA        24       NA      19       21
1      3       NA        NA       NA      19       21
1      4       NA        NA       NA      19       21
2      0       41        16       21      13       24
2      1       NA        NA       NA      13       24
2      2       11        30       41      13       24
2      3       21        NA       NA      13       24
2      4       24        35       21      13       24
2      5       NA        NA       NA      13       24
2      6       NA        NA       NA      13       24
3      0       NA        NA       NA      35       46
3      1       23        34       24      35       46
3      2       NA        26       NA      35       46
3      3       NA        NA       24      35       46
3      4       12        29       42      35       46
3      5       NA        NA       NA      35       46
3      6       NA        NA       NA      35       46

在表格中,每个 ID 都代表一个应适当处理的场景:

  • ID 1:观察从第 0 小时开始,观察在第 3 小时结束 - 因此应删除该组的第 3 小时和第 4 小时的行

    李>
  • ID 2:有一个小时 (1),其中所有三个观察变量都设置为 NA,但观察恢复并在第 5 小时结束 - 因此应保留第 2 行 (由于注册错误而不是观察结束),应删除第 5 小时和第 6 小时的行。

  • ID 3:从所有三个观察变量中的 NA 行开始,但观察从下一个小时开始并在第 5 小时结束。这类似于 ID 2 的场景,但这次发生在最开始(而不是在观察的中间)。但是,这仍然表示注册错误,应保留该组中第 5 小时和第 6 小时的行。

从概念上讲,我认为一个可能的解决方案是执行 group_by ID,然后让 R 反向遍历组中的行(从下向上),直到遇到 "OBS_1"、"OBS_2" 的行和 "OBS_3" 不都是 NA 并在到达该行之前删除检查的行,然后继续检查下一组。

任何帮助将不胜感激!

【问题讨论】:

    标签: r dplyr data.table


    【解决方案1】:

    如果您的 MISC 和 MISC_2 值对于每个 ID 都是一致的,您可以 过滤所有具有 na 值的行,然后用completefill 填充缺失的数据。

    library(dplyr)
    library(tidyr)
    df %>% filter(!(is.na(OBS_1)&is.na(OBS_2)&is.na(OBS_3))) %>%
      group_by(ID) %>%
      complete(HOUR=0:max(HOUR)) %>%
      fill(MISC,MISC_2) %>% fill(MISC,MISC_2,.direction = "up")
    
    
    # A tibble: 13 x 7
    # Groups:   ID [3]
    #       ID  HOUR OBS_1 OBS_2 OBS_3  MISC MISC_2
    #    <int> <int> <int> <int> <int> <int>  <int>
    #  1     1     0    29    32    34    19     21
    #  2     1     1    21    12    NA    19     21
    #  3     1     2    NA    24    NA    19     21
    #  4     2     0    41    16    21    13     24
    #  5     2     1    NA    NA    NA    13     24
    #  6     2     2    11    30    41    13     24
    #  7     2     3    21    NA    NA    13     24
    #  8     2     4    24    35    21    13     24
    #  9     3     0    NA    NA    NA    35     46
    # 10     3     1    23    34    24    35     46
    # 11     3     2    NA    26    NA    35     46
    # 12     3     3    NA    NA    24    35     46
    # 13     3     4    12    29    42    35     46
    

    【讨论】:

    • MISC 和 MISC_2 应该在每个组的所有 24 行中具有相同的值 - 从某种意义上说,如果其中一个是 NA,那么另一个也是,它们在所有 24 行中都是 NA在那个组。两个后续问题 - 1. 如果 MISC 和 MISC_2 为 NA,代码会怎样?它似乎在简化表中仍然有效,但很好奇它是否会影响真实的data.frame。 2. 对于类似于 ID 2 的组,它会如何处理,但是对于 OBS_1、OBS_2 和 OBS_3 为 NA 的多行,它会在具有观察的行之间分布,直到真正的结束发生?
    • 1.它默认为 NA 所以我想它会很好。 2. 不重要,因为完整会添加从 0 到最大值或“真实结束”的值。如果您对任何工作原理感到好奇,我会查看 tidyr 文档。
    【解决方案2】:

    如果在此之后不存在当天的观察,则仅过滤缺失值,并保留所有未指示当天观察结束的缺失观察。这些还允许您的其他变量在一天中发生变化,因为它只是在观察结束时将它们删除。

     df %>% arrange(rev(as.numeric(rownames(.)))) %>% 
       group_by(ID) %>%
       mutate(rowNum = 1:n(),
              naObs = cumsum((is.na(OBS_1) & is.na(OBS_2) & is.na(OBS_3))), 
              missingBlock = naObs != rowNum) %>%
       slice(min(which(missingBlock)):n()) %>%
       ungroup() %>%
       arrange(rev(as.numeric(rownames(.)))) %>%
       select(-rowNum, -naObs, -missingBlock)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-03
      • 2020-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多