累计复位时间
Cumulative time with reset
我有一个如下所示的数据集:
id land datetime
pb1 0 2004-04-05 01:44:00
pb1 1 2004-04-05 02:00:00
pb1 1 2004-04-05 16:00:00
pb2 1 2004-04-05 18:01:00
pb2 1 2004-04-05 20:00:00
library(data.table)
DT = data.table(
id = c("pb1", "pb1", "pb1", "pb2", "pb2"),
land = c(0L, 1L, 1L, 1L, 1L),
datetime = sprintf("2004-04-05 %02d:%02d:00",
c(1, 2, 16, 18, 20),
c(44, 0, 0, 1, 0))
)
我想制作一个累积增加时间(以天为单位)的列,但前提是 land
列中有“1”。我还希望在 id
更改时重置计数。
我尝试了多种使用 data.table
、rleid
甚至嵌套 for
循环的方法,但都没有成功。我在使用这样的代码时遇到错误:
DT[, total :=land*diff(as.numeric(datetime)), .(id, rleid(land))]
我在这里尝试了多种解决方案:
我不确定计算时间间隔的最佳方法(difftime
或 lubridate
均未成功)。
我希望最终结果如下所示:
id land datetime cumtime.land
pb1 0 2004-04-05 01:44:00 0
pb1 1 2004-04-05 02:00:00 0
pb1 1 2004-04-06 16:00:00 1.58333
pb2 1 2004-04-05 18:00:00 0
pb2 1 2004-04-05 20:00:00 0.08333
我无法复制@Japp 的评论,但您可以使用 dplyr
轻松做到这一点。
根据您的确切预期输出,您可以在 summarize
调用之前停止:
library(dplyr)
df=read.table(text=
"id land datetime
pb1 0 '2004-04-05 01:44:00'
pb1 1 '2004-04-05 02:00:00'
pb1 1 '2004-04-06 16:00:00'
pb1 1 '2004-04-07 16:00:00'
pb2 1 '2004-04-05 18:00:00'
pb2 1 '2004-04-05 20:00:00'", header=T) %>%
mutate(datetime=as.POSIXct(datetime,format='%Y-%m-%d %H:%M:%S'))
x = df %>%
group_by(id) %>%
arrange(id, datetime) %>%
mutate(time.land=ifelse(land==0 | is.na(lag(land)) | lag(land)==0,
0,
difftime(datetime, lag(datetime), units="days"))) %>%
mutate(cumtime.land=time.land + ifelse(is.na(lag(time.land)), 0, lag(time.land)))
id land datetime time.land cumtime.land
<fct> <int> <dttm> <dbl> <dbl>
1 pb1 0 2004-04-05 01:44:00 0 0
2 pb1 1 2004-04-05 02:00:00 0 0
3 pb1 1 2004-04-06 16:00:00 1.58 1.58
4 pb1 1 2004-04-07 16:00:00 1 2.58
5 pb2 1 2004-04-05 18:00:00 0 0
6 pb2 1 2004-04-05 20:00:00 0.0833 0.0833
关键是使用 dplyr::lag()
函数,它在 table 中获取 "line just above" (这意味着您必须事先 arrange()
它)。
通过将其包装在 ifelse
内,我正在检查 land
和之前的 land
不是 0
(并且我们不在第一行的 id
或 lag(anything)
将丢失)。
然后我只是重新使用 lag()
函数来获取 cumtime.land
变量。
我相信你在追求:
DT[land == 1, cumtime.land =
cumsum(c(0, diff(as.numeric(datetime))))/86400, by = id]
as.numeric(datetime)
将其转换为 秒 所以我们使用 86400 转换为 天.
在利用time/date的意义上更多"official" 类直接使用difftime
和shift
:
DT[land == 1, by = id,
cumtime.land :=
cumsum(as.double(difftime(
datetime, shift(datetime, fill = datetime[1L]), units = 'days'
)))]
我调换了 by
参数的顺序只是为了帮助格式化。
我们使用datetime[1L]
进行填充,使得初始差为0;我们需要 as.double
因为 cumsum
错误,因为它不确定如何处理 difftime
对象作为输入。
另请参阅:
Calculate cumsum() while ignoring NA values
我有一个如下所示的数据集:
id land datetime
pb1 0 2004-04-05 01:44:00
pb1 1 2004-04-05 02:00:00
pb1 1 2004-04-05 16:00:00
pb2 1 2004-04-05 18:01:00
pb2 1 2004-04-05 20:00:00
library(data.table)
DT = data.table(
id = c("pb1", "pb1", "pb1", "pb2", "pb2"),
land = c(0L, 1L, 1L, 1L, 1L),
datetime = sprintf("2004-04-05 %02d:%02d:00",
c(1, 2, 16, 18, 20),
c(44, 0, 0, 1, 0))
)
我想制作一个累积增加时间(以天为单位)的列,但前提是 land
列中有“1”。我还希望在 id
更改时重置计数。
我尝试了多种使用 data.table
、rleid
甚至嵌套 for
循环的方法,但都没有成功。我在使用这样的代码时遇到错误:
DT[, total :=land*diff(as.numeric(datetime)), .(id, rleid(land))]
我在这里尝试了多种解决方案:
我不确定计算时间间隔的最佳方法(difftime
或 lubridate
均未成功)。
我希望最终结果如下所示:
id land datetime cumtime.land
pb1 0 2004-04-05 01:44:00 0
pb1 1 2004-04-05 02:00:00 0
pb1 1 2004-04-06 16:00:00 1.58333
pb2 1 2004-04-05 18:00:00 0
pb2 1 2004-04-05 20:00:00 0.08333
我无法复制@Japp 的评论,但您可以使用 dplyr
轻松做到这一点。
根据您的确切预期输出,您可以在 summarize
调用之前停止:
library(dplyr)
df=read.table(text=
"id land datetime
pb1 0 '2004-04-05 01:44:00'
pb1 1 '2004-04-05 02:00:00'
pb1 1 '2004-04-06 16:00:00'
pb1 1 '2004-04-07 16:00:00'
pb2 1 '2004-04-05 18:00:00'
pb2 1 '2004-04-05 20:00:00'", header=T) %>%
mutate(datetime=as.POSIXct(datetime,format='%Y-%m-%d %H:%M:%S'))
x = df %>%
group_by(id) %>%
arrange(id, datetime) %>%
mutate(time.land=ifelse(land==0 | is.na(lag(land)) | lag(land)==0,
0,
difftime(datetime, lag(datetime), units="days"))) %>%
mutate(cumtime.land=time.land + ifelse(is.na(lag(time.land)), 0, lag(time.land)))
id land datetime time.land cumtime.land
<fct> <int> <dttm> <dbl> <dbl>
1 pb1 0 2004-04-05 01:44:00 0 0
2 pb1 1 2004-04-05 02:00:00 0 0
3 pb1 1 2004-04-06 16:00:00 1.58 1.58
4 pb1 1 2004-04-07 16:00:00 1 2.58
5 pb2 1 2004-04-05 18:00:00 0 0
6 pb2 1 2004-04-05 20:00:00 0.0833 0.0833
关键是使用 dplyr::lag()
函数,它在 table 中获取 "line just above" (这意味着您必须事先 arrange()
它)。
通过将其包装在 ifelse
内,我正在检查 land
和之前的 land
不是 0
(并且我们不在第一行的 id
或 lag(anything)
将丢失)。
然后我只是重新使用 lag()
函数来获取 cumtime.land
变量。
我相信你在追求:
DT[land == 1, cumtime.land =
cumsum(c(0, diff(as.numeric(datetime))))/86400, by = id]
as.numeric(datetime)
将其转换为 秒 所以我们使用 86400 转换为 天.
在利用time/date的意义上更多"official" 类直接使用difftime
和shift
:
DT[land == 1, by = id,
cumtime.land :=
cumsum(as.double(difftime(
datetime, shift(datetime, fill = datetime[1L]), units = 'days'
)))]
我调换了 by
参数的顺序只是为了帮助格式化。
我们使用datetime[1L]
进行填充,使得初始差为0;我们需要 as.double
因为 cumsum
错误,因为它不确定如何处理 difftime
对象作为输入。
另请参阅:
Calculate cumsum() while ignoring NA values