【问题标题】:Extract the first and last observation of each group, every time that group appears within a large dataset?每次该组出现在大型数据集中时,提取每个组的第一个和最后一个观察值?
【发布时间】:2022-01-19 20:58:57
【问题描述】:

我有一个大型的鱼类检测数据集(约 300,000 行)。每个检测都有一个日期、一个站点(位置)和一个 tagID,以及许多其他变量,例如温度、深度等。我想在每次鱼访问该站点时提取每个站点的第一个和最后一个检测。最终目标是在每个站点移动之前计算每个站点的驻留时间,并在它返回时再次计算。

这是数据的一个小例子

tagID <- c("8272", "8272", "8272", "8272", "8272", "8272", "8272", "8272", "8272", "8272")
date <- c("2020-07-12", "2020-07-12", "2020-07-13", "2020-07-13", "2020-07-16", "2020-07-17", "2020-07-20", "2020-07-29", "2020-07-30", "2020-08-04")
station <- c("4", "4", "4", "5", "5", "6", "6", "6", "4", "4")
temp <- c("10", "9", "11", "12", "10", "12", "11", "12", "12", "9")
depth <- c("6.14", "34.2", "21", "23.5", "15.4", "54", "32.4", "23", "33.3", "32.7")
df <- data.frame(tagID, date, station, temp, depth)

数据框看起来像:

 tagID       date station temp depth
1   8272 2020-07-12       4   10  6.14
2   8272 2020-07-12       4    9  34.2
3   8272 2020-07-13       4   11    21
4   8272 2020-07-13       5   12  23.5
5   8272 2020-07-16       5   10  15.4
6   8272 2020-07-17       6   12    54
7   8272 2020-07-20       6   11  32.4
8   8272 2020-07-29       6   12    23
9   8272 2020-07-30       4   12  33.3
10  8272 2020-08-04       4    9  32.7

我想找到一种有效的方法来遍历所有 300K 行并提取如下内容:

 tagID       date station temp depth
1   8272 2020-07-12       4   10  6.14
3   8272 2020-07-13       4   11    21
4   8272 2020-07-13       5   12  23.5
5   8272 2020-07-16       5   10  15.4
6   8272 2020-07-17       6   12    54
8   8272 2020-07-29       6   12    23
9   8272 2020-07-30       4   12  33.3
10  8272 2020-08-04       4    9  32.7

这显示了鱼在第 4 站时的第一次和最后一次检测,然后当鱼在本赛季晚些时候回到第 4 站时再次进行第一次和最后一次检测。

我查看了诸如 Select first and last row from grouped dataSelect the first and last row by group in a data frame 之类的问题,以及其他类似问题,但这些问题都不是该组的第二次(第三次、第四次、第...次)(在我的情况下:车站) 出现在数据中。

如果您能提供帮助,请告诉我。谢谢你。 (这是我关于堆栈溢出的第一个问题,对未来问题的任何提示都会有所帮助)

【问题讨论】:

标签: r for-loop dplyr grouping subset


【解决方案1】:

这是data.table 方法。正如 @Henrik 在 cmets 中所提到的,您可以使用 rleid 创建一个新列进行分组,而不是使用 station 作为 station 的重复值。 rleid。然后,对于每个组,它将包括第一个和最后一个 .N 值。请注意,添加unique 是为了考虑给定组可能仅存在一行数据的情况。我希望这可能是您的快速解决方案。

library(data.table)

setDT(df)

df[ , id := rleid(station)][ , .SD[unique(c(1, .N))], by = id]

输出

   id tagID       date station temp depth
1:  1  8272 2020-07-12       4   10  6.14
2:  1  8272 2020-07-13       4   11    21
3:  2  8272 2020-07-13       5   12  23.5
4:  2  8272 2020-07-16       5   10  15.4
5:  3  8272 2020-07-17       6   12    54
6:  3  8272 2020-07-29       6   12    23
7:  4  8272 2020-07-30       4   12  33.3
8:  4  8272 2020-08-04       4    9  32.7

【讨论】:

    【解决方案2】:

    我在这里的方法是标记鱼改变站点的每个场合,然后计算这些变化的累积次数。然后我们可以按鱼和站点变化的数量进行分组,并过滤​​每个的第一个和最后一个。

    library(dplyr)
    df %>%
      group_by(tagID) %>%
      mutate(station_chg = station != lag(station, default = ""),
             station_cuml = cumsum(station_chg)) %>%
      group_by(tagID, station_cuml) %>%
      slice(1, n()) %>%
      ungroup()
    

    结果

    # A tibble: 8 x 7
      tagID date       station temp  depth station_chg station_cuml
      <chr> <chr>      <chr>   <chr> <chr> <lgl>              <int>
    1 8272  2020-07-12 4       10    6.14  TRUE                   1
    2 8272  2020-07-13 4       11    21    FALSE                  1
    3 8272  2020-07-13 5       12    23.5  TRUE                   2
    4 8272  2020-07-16 5       10    15.4  FALSE                  2
    5 8272  2020-07-17 6       12    54    TRUE                   3
    6 8272  2020-07-29 6       12    23    FALSE                  3
    7 8272  2020-07-30 4       12    33.3  TRUE                   4
    8 8272  2020-08-04 4       9     32.7  FALSE                  4
    

    【讨论】:

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