Расчет разницы между двумя датами, сгруппированными по переменной - PullRequest
1 голос
/ 01 мая 2019

Мне нужна помощь в написании более эффективного кода.У меня есть следующий набор данных.

Report| ReportPeriod|ObsDate
1     |     15      |2017-12-31 00:00:00
1     |     15      |2017-12-31 06:00:00
1     |     15      |2017-12-31 12:30:00
2     |     11      |2018-01-01 07:00:00
2     |     11      |2018-01-01 13:00:00
2     |     11      |2018-01-01 16:30:00

Первый столбец - «Отчет», который является уникальным идентификатором для определенного отчета.В наборе данных есть только два отчета (1 и 2).Второй столбец - «ReportPeriod», то же самое для конкретного отчета.Отчет 1 длится 15 часов, а отчет 2 - 11 часов.Третий столбец «ObsDate» - это разные наблюдения в конкретном отчете.

Проблема: мне нужно выяснить разницу во времени между наблюдениями, сгруппированными по «Отчет».Я сделал это с помощью следующего кода:

example<- data.frame(Report=c(1,1,1,2,2,2), ReportPeriod=c(15,15,15,11,11,11),
                     ObsDate=c(as.POSIXct("2017-12-31 00:00:00"), as.POSIXct("2017-12-31 06:00:00"),
                               as.POSIXct("2017-12-31 12:30:00"), as.POSIXct("2018-01-01 07:00:00"),
                               as.POSIXct("2018-01-01 13:00:00"), as.POSIXct("2018-01-01 16:30:00")))

example<- example %>% group_by(Report) %>% 
  mutate(DiffPeriod= (ObsDate-lag(ObsDate)))

Вывод:

Report| ReportPeriod|ObsDate            |DiffPeriod
1     |     15      |2017-12-31 00:00:00|NA
1     |     15      |2017-12-31 06:00:00|6.0
1     |     15      |2017-12-31 12:30:00|6.5
2     |     11      |2018-01-01 07:00:00|NA
2     |     11      |2018-01-01 13:00:00|6.0
2     |     11      |2018-01-01 16:30:00|3.5

Теперь первые две записи «Отчета» - это NA.Эти значения должны быть суммой DiffPeriod, вычтенной из общего отчетного периода «ReportPeriod».

Я сделал это, используя следующий код.

xyz<- data.frame()
for (i in unique(example$Report)) {
  df<- example %>% filter(Report==i)
  hrs<- sum(df$DiffPeriod, na.rm = TRUE)
  tot<- df$ReportPeriod[1]
  bal<- tot-hrs
  df$DiffPeriod[1]<- bal
  xyz<- xyz %>% bind_rows(df)
}

Окончательный результат:

Report| ReportPeriod|ObsDate            |DiffPeriod
1     |     15      |2017-12-31 00:00:00|2.5
1     |     15      |2017-12-31 06:00:00|6.0
1     |     15      |2017-12-31 12:30:00|6.5
2     |     11      |2018-01-01 07:00:00|1.5
2     |     11      |2018-01-01 13:00:00|6.0
2     |     11      |2018-01-01 16:30:00|3.5

Есть ли лучший / более эффективный способ сделать то, что я делал в цикле for выше в tidyverse?

Спасибо.

1 Ответ

2 голосов
/ 01 мая 2019

Предполагая, что ReportPeriod всегда будет в часах, мы можем сначала получить разницу между ObsDate и lag(ObsDate), а затем replace NA, которая будет только первой строкой, принимая разницу между первым значением ReportPeriod с sum из DiffPeriod для каждой группы (Report).

library(dplyr)

example %>% 
  group_by(Report) %>% 
  mutate(DiffPeriod= difftime(ObsDate, lag(ObsDate), units = "hours"), 
         DiffPeriod = replace(DiffPeriod, is.na(DiffPeriod), 
                      ReportPeriod[1] - sum(DiffPeriod, na.rm = TRUE)))


# Report ReportPeriod ObsDate             DiffPeriod
#   <dbl>        <dbl> <dttm>              <time>    
#1      1           15 2017-12-31 00:00:00 2.5 hours 
#2      1           15 2017-12-31 06:00:00 6.0 hours 
#3      1           15 2017-12-31 12:30:00 6.5 hours 
#4      2           11 2018-01-01 07:00:00 1.5 hours 
#5      2           11 2018-01-01 13:00:00 6.0 hours 
#6      2           11 2018-01-01 16:30:00 3.5 hours 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...