1

我有一个如下所示的数据集:

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))]

我在这里尝试了解决方案的变体: 计算 R 中的累积时间

我不确定计算时间间隔的最佳方法(使用difftimeor没有成功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
4

2 回答 2

1

我无法复制@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()表中采用“正上方行”的函数(这意味着您必须arrange()事先使用它)。

通过将 this 包裹在 中ifelse,我正在检查land和 previousland不是0(并且我们不在 的第一行id,或者lag(anything)将丢失)。

然后我只是重用该lag()函数来获取cumtime.land变量。

于 2018-12-21T12:28:06.180 回答
0

我相信你在追求:

DT[land == 1, cumtime.land = 
     cumsum(c(0, diff(as.numeric(datetime))))/86400, by = id]

as.numeric(datetime)将其转换为seconds所以我们使用 86400 转换为days

在直接利用时间/日期类的意义上,更“官方”的是使用difftimeand 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作为输入的对象。

也可以看看:

于 2018-12-21T23:15:31.190 回答