我正在处理一个带有处理过的GPS位置的数据框架。我有三个变量。id
对应于每个人的标识符。TimeStamp
表示gps信号的时刻,和。perimeter
表示信号是否发生在给定的周界内。我想建立一个表格,按照正确的发生顺序列出在给定周界内或外花费的时间。
这是一个可重复的例子。
df <- data.frame(id=rep(1, 10),
TimeStamp=seq(as.POSIXct("2020-01-01 12:00:00"),
as.POSIXct("2020-01-01 16:30:00"),
length.out = 10),
perimeter=c(NA, NA, NA, "p1", "p1", "p1", NA, NA, "p2", "p2"))
我想要的输出结果是这样的
id perimeter time
1 NA 1.5
1 "p1" 1.5
1 NA 1
1 "p2" 1
我已经接近了一个解决方案,使用 rle()
函数。
df[is.na(df$perimeter),]$perimeter <- "OUT"
data.frame(perimeter=rle(df$perimeter)$value,
time=(rle(df$perimeter)$length*30)/60)
然而,它是根据向量中重复序列的长度来估计时间的,由于我有缺失的值,所以从最后一个重复序列中减去第一个重复序列的TimeStamp会更准确。
一个dplyr的解决方案。
df %>%
mutate(perimeter = forcats::fct_explicit_na(df$perimeter),
visit = cumsum(perimeter != lag(perimeter) | is.na(lag(perimeter)))) %>%
group_by(id, visit, perimeter) %>%
summarise(time = difftime(max(TimeStamp) + 1800, min(TimeStamp), unit = "hour")) %>%
ungroup() %>% select(-visit)
#> # A tibble: 4 x 3
#> id perimeter time
#> <dbl> <fct> <drtn>
#> 1 1 (Missing) 1.5 hours
#> 2 1 p1 1.5 hours
#> 3 1 (Missing) 1.0 hours
#> 4 1 p2 1.0 hours
这里有一个... data.table
解决办法。
library(data.table)
setDT(df)
df[, nextTimeStamp := shift(TimeStamp, -1L), by = id]
df[, .( unclass(nextTimeStamp[.N] - TimeStamp[1L]) / 60^2), by = .(id, rleid(perimeter))]
# id rleid V1
# 1: 1 1 1.5
# 2: 1 2 1.5
# 3: 1 3 1.0
# 4: 1 4 NA