#r #dplyr
#r #dplyr
Вопрос:
У меня есть некоторые данные, которые выглядят следующим образом:
> df
time region place action
1 2019-01-14 16:00:08 A G START
2 2019-01-14 16:00:08 A I STOP
3 2019-01-14 16:00:16 A H START
4 2019-01-14 16:00:16 A G STOP
5 2019-01-14 16:01:40 A H STOP
6 2019-01-14 16:01:40 A G START
7 2019-01-14 16:01:54 A G STOP
8 2019-01-14 16:02:21 A D START
9 2019-01-14 16:02:31 A C START
10 2019-01-14 16:02:54 A D STOP
11 2019-01-14 16:03:12 A C STOP
12 2019-01-14 16:03:13 A E START
13 2019-01-14 16:03:34 A E STOP
14 2019-01-14 16:03:34 A A START
15 2019-01-14 16:04:12 A A STOP
16 2019-01-14 16:04:12 A E START
17 2019-01-14 16:04:17 A E STOP
18 2019-01-14 16:04:55 A F START
19 2019-01-14 16:05:08 A B START
20 2019-01-14 16:05:08 A F STOP
Я хочу разницу между НАЧАЛОМ и остановкой между местами в каждом регионе. (например. разница между временем в строке 1 и временем в строке 4, потому что это ближайшая ОСТАНОВКА для этого места). Вот что у меня получилось на данный момент: то, что я пытаюсь сделать в ifelse-construct, — это найти следующую строку с ОСТАНОВКОЙ в столбце действия.
df %>% group_by(region, place) %>%
mutate(difference = ifelse(action == "STOP", NA, time[which(action == "STOP")[which.max(which(action == "STOP") > row_number())]] - time))
# A tibble: 20 x 5
# Groups: region, place [9]
time region place action difference
<dttm> <fct> <fct> <chr> <dbl>
1 2019-01-14 16:00:08 A g START 8.52
2 2019-01-14 16:00:08 A i STOP NA
3 2019-01-14 16:00:16 A h START 84.2
4 2019-01-14 16:00:16 A g STOP NA
5 2019-01-14 16:01:40 A h STOP NA
6 2019-01-14 16:01:40 A g START -84.2
7 2019-01-14 16:01:54 A g STOP NA
8 2019-01-14 16:02:21 A d START 32.9
9 2019-01-14 16:02:31 A c START 40.8
10 2019-01-14 16:02:54 A d STOP NA
11 2019-01-14 16:03:12 A c STOP NA
12 2019-01-14 16:03:13 A e START 21.3
13 2019-01-14 16:03:34 A e STOP NA
14 2019-01-14 16:03:34 A a START 38.0
15 2019-01-14 16:04:12 A a STOP NA
16 2019-01-14 16:04:12 A e START -38.5
17 2019-01-14 16:04:17 A e STOP NA
18 2019-01-14 16:04:55 A f START 13.4
19 2019-01-14 16:05:08 A b START NA
20 2019-01-14 16:05:08 A f STOP NA
Разница во времени верна, за исключением двух отрицательных значений (они должны быть ~ 14 и ~ 5). У кого-нибудь есть идея, почему это происходит? Спасибо!
Данные:
df <- structure(
list(
time = structure(
c(
1547478008.024,
1547478008.225,
1547478016.168,
1547478016.542,
1547478100.374,
1547478100.758,
1547478114.589,
1547478141.86,
1547478151.972,
1547478174.757,
1547478192.723,
1547478193.077,
1547478214.37,
1547478214.562,
1547478252.523,
1547478252.907,
1547478257.458,
1547478295.109,
1547478308.358,
1547478308.547
),
class = c("POSIXct", "POSIXt"),
tzone = ""
),
region = structure(
c(
1L,
1L,
1L,
1L,
1L,
1L,
1L,
1L,
1L,
1L,
1L,
1L,
1L,
1L,
1L,
1L,
1L,
1L,
1L,
1L
),
.Label = "A",
class = "factor"
),
place = structure(
c(
7L,
9L,
8L,
7L,
8L,
7L,
7L,
4L,
3L,
4L,
3L,
5L,
5L,
1L,
1L,
5L,
5L,
6L,
2L,
6L
),
.Label = c("a",
"b", "c", "d", "e", "f", "g", "h", "i"),
class = "factor"
),
action = c(
"START",
"STOP",
"START",
"STOP",
"STOP",
"START",
"STOP",
"START",
"START",
"STOP",
"STOP",
"START",
"STOP",
"START",
"STOP",
"START",
"STOP",
"START",
"START",
"STOP"
)
),
row.names = c(NA, 20L),
class = "data.frame"
)
Комментарии:
1. Всегда ли будет не более одной остановки после каждого запуска и перед следующим запуском в том же месте? Потому что, если ответ положительный, вы можете просто упорядочить по времени, региону и месту и использовать
lead()
.
Ответ №1:
Предполагая, что всегда есть ровно одна ОСТАНОВКА после каждого запуска и перед следующим запуском, это будет работать:
df %>% group_by(region, place) %>%
arrange(time) %>%
mutate(difference=ifelse(action=="STOP", NA, difftime(lead(time),time,units="secs")))
# A tibble: 20 x 5
# Groups: region, place [9]
time region place action difference
<dttm> <fct> <fct> <chr> <dbl>
1 2019-01-14 10:00:08 A g START 8.52
2 2019-01-14 10:00:08 A i STOP NA
3 2019-01-14 10:00:16 A h START 84.2
4 2019-01-14 10:00:16 A g STOP NA
5 2019-01-14 10:01:40 A h STOP NA
6 2019-01-14 10:01:40 A g START 13.8
7 2019-01-14 10:01:54 A g STOP NA
8 2019-01-14 10:02:21 A d START 32.9
9 2019-01-14 10:02:31 A c START 40.8
10 2019-01-14 10:02:54 A d STOP NA
11 2019-01-14 10:03:12 A c STOP NA
12 2019-01-14 10:03:13 A e START 21.3
13 2019-01-14 10:03:34 A e STOP NA
14 2019-01-14 10:03:34 A a START 38.0
15 2019-01-14 10:04:12 A a STOP NA
16 2019-01-14 10:04:12 A e START 4.55
17 2019-01-14 10:04:17 A e STOP NA
18 2019-01-14 10:04:55 A f START 13.4
19 2019-01-14 10:05:08 A b START NA
20 2019-01-14 10:05:08 A f STOP NA
Примечание: Если вы на 100% уверены в точности предположения, вы можете использовать следующее, которое добавляет еще одно ifelse
, чтобы убедиться, что следующая строка после START является STOP , в противном случае давая NA:
df %>% group_by(region, place) %>%
arrange(time) %>%
mutate(difference=ifelse(action=="STOP", NA,
ifelse(lead(action)=="STOP",difftime(lead(time),time,units="secs"),NA)))
Комментарии:
1. Я на 99% уверен, что это всегда СТАРТ-СТОП-СТАРТ-СТОП-…, я проверю реальные данные. Но посмотрите на разницу для h, она изменилась с 84,2 на 1,4, так что раньше это было правильно, а теперь неправильно, это странно, не так ли? Но в остальном все верно, это отличное начало!
2. Это 1,4 минуты, значение правильное. Спасибо!
3. Правильно, исправил приведенный выше код, чтобы он всегда выдавал значение в единицах секунды. Теперь мне любопытно, почему в вашем коде не возникло такой же проблемы…
4. И теперь добавлена версия, которая должна работать, даже если предположение неверно.