首页 > 解决方案 > 根据从第二个数据集收集的时间间隔对 gps-track 数据集进行子集

问题描述

我有一个大型 gps-track 数据集,我只想提取观察员值班时的位置。换句话说,我需要在观察者正在观看的几个样带中切割 gps 轨迹。观看时段在第二个数据库中,观察者在其中记录(大约每小时)观看时段的开始和结束,因此每天注册的开始时间和结束时间标志着当天的观看时段的开始和结束。在大多数情况下。但是,可能会因为某种原因暂停观看,然后在同一天稍后的某个时间重新开始,因此两个连续的注释之间可能会有时间间隔。

我正在尝试使用 match() 和 dplyr:filter() 函数,但无法找到解决方案。任何想法将不胜感激。

下面是一个简化的例子

DB1(非常大的 gps 跟踪到子集)

   date         time   lat      lon     
1  18/04/2017   6:10   34.01    -53.07
2  18/04/2017   6:20   34.02    -53.09
3  18/04/2017   6:30   34.04    -53.10
4  18/04/2017   6:40   34.05    -53.11
5  18/04/2017   6:50   34.07    -53.13
6  18/04/2017   7:00   34.08    -53.14
7  18/04/2017   7:10   34.01    -53.07
8  18/04/2017   7:20   34.02    -53.09
9  18/04/2017   7:30   34.04    -53.10
.      .         .       .         .
.      .         .       .         .
.      .         .       .         .
n   19/04/2017  6:10   34.05    -53.11
n+1 19/04/2017  6:20   34.07    -53.13
n+2 19/04/2017  6:30   34.08    -53.14

DB2(观看时段)

    date          start.watch   end.watch
1   2017-04-18    05:00         06:10
2   2017-04-18    06:10         06:30
3   2017-04-18    06:30         06:45
4   2017-04-18    07:20         08:20
.      .            .             . 
.      .            .             . 
.      .            .             . 
n   2017-04-19    06:20         07:20
n+1 2017-04-19    07:20         08:40

结果数据库应该是:`

1  18/04/2017   6:10   34.01    -53.07
2  18/04/2017   6:20   34.02    -53.09
3  18/04/2017   6:30   34.04    -53.10
4  18/04/2017   6:40   34.05    -53.11

8  18/04/2017   7:20   34.02    -53.09
9  18/04/2017   7:30   34.04    -53.10

n   19/04/2017  6:10   34.05    -53.11
n+1 19/04/2017  6:20   34.07    -53.13
n+2 19/04/2017  6:30   34.08    -53.14

标签: rdatetimematchsubset

解决方案


这是基于时间重叠进行基于范围(模糊)连接的替代方法。它使用data.table::foverlaps,它确实需要(至少对于此连接)两个框架是正确的data.table对象,因为它需要明确设置键。

这种方法有几个要求:

  1. 所有时间戳都可以很容易地在数字上进行比较,我会将它们转换为POSIXt对象;
  2. 至少为第二个表设置了键(并且可能对第一个表有所帮助)。每个的最后两个键必须是每个时间间隔的开始和结束;和
  3. 是的,你没看错,即使是“单次观察”也需要两个时间戳字段。

注意:我magrittr仅用于将流程分解为各种管道;它根本不是必需的,只是让它更容易阅读。另外,我使用copy()然后setDT分配给一个新变量主要是因为(1)我迭代了几次,但每次都想从新数据开始;更重要的是(2),因为data.table副作用中运行,我想鼓励你尝试这个但不要杀死你的本地数据,直到你适应它的副作用。data.table事后你可以很容易地取消它。

首先,我将设置所需的条件。

library(data.table)
library(magrittr)

DB1dt <- copy(DB1) %>%
  setDT() %>%
  .[, dt := as.POSIXct(paste(date, time), format = "%d/%m/%Y %H:%M") ] %>%
  # remove unneeded columns
  .[, c("date", "time") := NULL ] %>%
  .[, dt2 := dt ] %>%
  setkey(dt, dt2)

DB2dt <- copy(DB2) %>%
  setDT() %>%
  .[, startdt := as.POSIXct(paste(date, start.watch), format = "%Y-%m-%d %H:%M") ] %>%
  .[, enddt := as.POSIXct(paste(date, end.watch), format = "%Y-%m-%d %H:%M") - 1e-5 ] %>%
  # remove unneeded columns
  .[, c("date", "start.watch", "end.watch") := NULL ] %>%
  setkey(startdt, enddt)

DB1dt[1:2,]
#      lat    lon                  dt                 dt2
# 1: 34.01 -53.07 2017-04-18 06:10:00 2017-04-18 06:10:00
# 2: 34.02 -53.09 2017-04-18 06:20:00 2017-04-18 06:20:00
DB2dt[1:2,]
#                startdt               enddt
# 1: 2017-04-18 05:00:00 2017-04-18 06:09:59
# 2: 2017-04-18 06:10:00 2017-04-18 06:29:59

仅供参考:使用-1e-5是因为“内部”连接在两端都是封闭的([a,b]与 open-right 形成对比[a,b)),因此相等性enddt会匹配。如果你想保留这个,交给你。

从这里开始,重叠连接很简单:

foverlaps(DB1dt, DB2dt, type = "within", nomatch = NULL)
#                startdt               enddt   lat    lon                  dt                 dt2
# 1: 2017-04-18 06:10:00 2017-04-18 06:29:59 34.01 -53.07 2017-04-18 06:10:00 2017-04-18 06:10:00
# 2: 2017-04-18 06:10:00 2017-04-18 06:29:59 34.02 -53.09 2017-04-18 06:20:00 2017-04-18 06:20:00
# 3: 2017-04-18 06:30:00 2017-04-18 06:44:59 34.04 -53.10 2017-04-18 06:30:00 2017-04-18 06:30:00
# 4: 2017-04-18 06:30:00 2017-04-18 06:44:59 34.05 -53.11 2017-04-18 06:40:00 2017-04-18 06:40:00
# 5: 2017-04-18 07:20:00 2017-04-18 08:19:59 34.02 -53.09 2017-04-18 07:20:00 2017-04-18 07:20:00
# 6: 2017-04-18 07:20:00 2017-04-18 08:19:59 34.04 -53.10 2017-04-18 07:30:00 2017-04-18 07:30:00
# 7: 2017-04-19 06:20:00 2017-04-19 07:19:59 34.07 -53.13 2017-04-19 06:20:00 2017-04-19 06:20:00
# 8: 2017-04-19 06:20:00 2017-04-19 07:19:59 34.08 -53.14 2017-04-19 06:30:00 2017-04-19 06:30:00

样本数据:

DB1 <- read.table(stringsAsFactors = FALSE, header = TRUE, text = "
date         time   lat      lon     
18/04/2017   6:10   34.01    -53.07
18/04/2017   6:20   34.02    -53.09
18/04/2017   6:30   34.04    -53.10
18/04/2017   6:40   34.05    -53.11
18/04/2017   6:50   34.07    -53.13
18/04/2017   7:00   34.08    -53.14
18/04/2017   7:10   34.01    -53.07
18/04/2017   7:20   34.02    -53.09
18/04/2017   7:30   34.04    -53.10
19/04/2017   6:10   34.05    -53.11
19/04/2017   6:20   34.07    -53.13
19/04/2017   6:30   34.08    -53.14")

DB2 <- read.table(stringsAsFactors = FALSE, header = TRUE, text = "
date          start.watch   end.watch
2017-04-18    05:00         06:10
2017-04-18    06:10         06:30
2017-04-18    06:30         06:45
2017-04-18    07:20         08:20
2017-04-19    06:20         07:20
2017-04-19    07:20         08:40")

相关阅读:


推荐阅读