如何计算拆分为数据帧不同行的事件的持续时间
How can I compute the duration of events splited in different rows of a dataframe
我正在处理一个处理过 gps 位置的数据框。我有三个变量:id
,它对应于每个人的标识符,TimeStamp
,它表示 gps 信号的时刻,perimeter
表示信号是否发生在给定的范围内周长。我想创建一个 table,其中以正确的出现顺序在给定周界内或之外花费的时间。
这是一个可重现的例子:
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)
但是,它会根据向量中重复序列的长度来估计时间,并且由于我有缺失值,所以从最后一个重复项中减去第一个重复项的时间戳会更准确。
这是一个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
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
我正在处理一个处理过 gps 位置的数据框。我有三个变量:id
,它对应于每个人的标识符,TimeStamp
,它表示 gps 信号的时刻,perimeter
表示信号是否发生在给定的范围内周长。我想创建一个 table,其中以正确的出现顺序在给定周界内或之外花费的时间。
这是一个可重现的例子:
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)
但是,它会根据向量中重复序列的长度来估计时间,并且由于我有缺失值,所以从最后一个重复项中减去第一个重复项的时间戳会更准确。
这是一个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
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