Накопительное время со сбросом - PullRequest
0 голосов
/ 20 декабря 2018

У меня есть набор данных, который выглядит следующим образом:

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

Я не уверен, чтолучший способ вычислить временной интервал (без успеха с 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

Ответы [ 2 ]

0 голосов
/ 22 декабря 2018

Я полагаю, что вы после:

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

as.numeric(datetime) преобразует его в секунд , поэтому мы используем 86400 для преобразования в дней .

Несколько более «официальным» в смысле непосредственного использования классов времени / даты является использование 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 объектами в качестве входных данных.

См. также:

0 голосов
/ 21 декабря 2018

Я не мог воспроизвести комментарий @ 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() это заранее).

Обтеканием этоговнутри ifelse я проверяю, что land и предыдущий land не были 0 (и что мы не в первой строке id, или lag(anything) будет отсутствовать).

Затем я просто повторно использую функцию lag(), чтобы получить переменную cumtime.land.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...