首页 > 解决方案 > 根据 R 中 30 分钟或更长的时间差识别离散事件

问题描述

当在特定位置检测到单个动物 (ID) 时,我有一个时间戳数据框。以下是数据示例:

timestampUTC    location    ID
2017-10-02 19:23:27 JB12    A69-1601-47272
2017-10-02 19:26:48 JB12    A69-1601-47272
2017-10-02 19:27:23 JB12    A69-1601-47272
2017-10-02 19:31:46 JB12    A69-1601-47272
2017-10-02 23:52:15 JB12    A69-1601-47272
2017-10-02 23:53:26 JB12    A69-1601-47272
2017-10-02 23:55:13 JB12    A69-1601-47272
2017-10-03 19:53:50 JB13    A69-1601-47272
2017-10-03 19:55:23 JB13    A69-1601-47272
2017-10-03 19:58:26 JB13    A69-1601-47272
2017-10-04 13:15:13 JB12    A69-1601-47280
2017-10-04 13:16:42 JB12    A69-1601-47280
2017-10-04 13:21:39 JB12    A69-1601-47280
2017-10-04 19:34:54 JB12    A69-1601-47280
2017-10-04 19:55:28 JB12    A69-1601-47280
2017-10-04 20:08:23 JB12    A69-1601-47280
2017-10-04 20:21:43 JB12    A69-1601-47280
2017-10-05 04:55:48 JB13    A69-1601-47280
2017-10-05 04:57:04 JB13    A69-1601-47280
2017-10-05 05:18:40 JB13    A69-1601-47280
2017-10-07 21:24:19 JB13    A69-1601-47280
2017-10-07 21:25:36 JB13    A69-1601-47280
2017-10-07 21:29:25 JB13    A69-1601-47280

我的真实数据框有将近 200,000 行长,有 4 个不同的位置和 13 个不同的 ID。

我想根据 timestampUTC 列将这些事件分类为具有开始和结束时间的离散事件(位置 ID),当在该位置对该 ID 的下一次检测超过半小时后,事件以时间戳UTC 结束。下一个事件在下一个日期时间开始。

使用上面的示例数据,我想生成另一个看起来像这样的数据框:

ID             location event start         event end
A69-1601-47272  JB12    2017-10-02 19:23:27 2017-10-02 19:31:46
A69-1601-47272  JB12    2017-10-02 23:52:15 2017-10-02 23:55:13
A69-1601-47272  JB13    2017-10-03 19:53:50 2017-10-03 19:58:26
A69-1601-47280  JB12    2017-10-04 13:15:13 2017-10-04 13:21:39
A69-1601-47280  JB12    2017-10-04 19:34:54 2017-10-04 20:21:43
A69-1601-47280  JB13    2017-10-05 04:55:48 2017-10-05 05:18:40
A69-1601-47280  JB13    2017-10-07 21:24:19 2017-10-07 21:29:25

如果在某个位置检测到 ID,它会给出 ID、位置以及该位置的开始和结束时间。

例如,您可以看到在同一天 (2017-10-02) 发生在位置 JB12 的 ID 47272 的 2 个离散事件,但第一个事件的结束和第二个事件的开始之间的差异 >30分钟(约 4 小时 20 分钟),因此它们是单独的事件。

我会添加我尝试过的代码,但我不知道从哪里开始。

提前致谢!

标签: rdatetime

解决方案


这是一个选项

library(tidyverse)
df %>%
    mutate(
        timestampUTC = as.POSIXct(timestampUTC),
        diff = c(0, diff(timestampUTC) / 60),
        grp = cumsum(diff > 30)) %>%
    group_by(grp) %>%
    summarise(
        ID = first(ID),
        location = first(location),
        `event start` = first(timestampUTC),
        `event end` = last(timestampUTC))
## A tibble: 7 x 5
#    grp ID             location `event start`       `event end`
#  <int> <fct>          <fct>    <dttm>              <dttm>
#1     0 A69-1601-47272 JB12     2017-10-02 19:23:27 2017-10-02 19:31:46
#2     1 A69-1601-47272 JB12     2017-10-02 23:52:15 2017-10-02 23:55:13
#3     2 A69-1601-47272 JB13     2017-10-03 19:53:50 2017-10-03 19:58:26
#4     3 A69-1601-47280 JB12     2017-10-04 13:15:13 2017-10-04 13:21:39
#5     4 A69-1601-47280 JB12     2017-10-04 19:34:54 2017-10-04 20:21:43
#6     5 A69-1601-47280 JB13     2017-10-05 04:55:48 2017-10-05 05:18:40
#7     6 A69-1601-47280 JB13     2017-10-07 21:24:19 2017-10-07 21:29:25

我保留了一些中间步骤(列)以帮助提高可读性和理解性。简而言之,我们将时间戳转换为POSIXct,然后用 计算连续时间戳之间的时间差(以分钟为diff单位),根据下一个时间戳是否在> 30几分钟之外创建观察组。剩下的就是对grp相关列中的条目进行分组和汇总。


一样,更简洁(也许以牺牲可读性为代价)

df %>%
    group_by(grp = cumsum(c(0, diff(as.POSIXct(timestampUTC)) / 60) > 30)) %>%
    summarise(
        ID = first(ID),
        location = first(location),
        `event start` = first(timestampUTC),
        `event end` = last(timestampUTC)) %>%
    select(-grp)

样本数据

df <- read.table(text =
    "timestampUTC    location    ID
'2017-10-02 19:23:27' JB12    A69-1601-47272
'2017-10-02 19:26:48' JB12    A69-1601-47272
'2017-10-02 19:27:23' JB12    A69-1601-47272
'2017-10-02 19:31:46' JB12    A69-1601-47272
'2017-10-02 23:52:15' JB12    A69-1601-47272
'2017-10-02 23:53:26' JB12    A69-1601-47272
'2017-10-02 23:55:13' JB12    A69-1601-47272
'2017-10-03 19:53:50' JB13    A69-1601-47272
'2017-10-03 19:55:23' JB13    A69-1601-47272
'2017-10-03 19:58:26' JB13    A69-1601-47272
'2017-10-04 13:15:13' JB12    A69-1601-47280
'2017-10-04 13:16:42' JB12    A69-1601-47280
'2017-10-04 13:21:39' JB12    A69-1601-47280
'2017-10-04 19:34:54' JB12    A69-1601-47280
'2017-10-04 19:55:28' JB12    A69-1601-47280
'2017-10-04 20:08:23' JB12    A69-1601-47280
'2017-10-04 20:21:43' JB12    A69-1601-47280
'2017-10-05 04:55:48' JB13    A69-1601-47280
'2017-10-05 04:57:04' JB13    A69-1601-47280
'2017-10-05 05:18:40' JB13    A69-1601-47280
'2017-10-07 21:24:19' JB13    A69-1601-47280
'2017-10-07 21:25:36' JB13    A69-1601-47280
'2017-10-07 21:29:25' JB13    A69-1601-47280", header = T)

推荐阅读