#r #dplyr #lapply #posixct
#r #dplyr #lapply #posixct
Вопрос:
TLDR: необходимо создать последовательность отдельных строк, но возникают проблемы с временными последовательностями
У меня есть список фреймов данных, каждый из которых выглядит примерно так (df1):
sector1 = data.frame(date = rep(seq.POSIXt(as.POSIXct("2001-01-01 00:00:00"),format = "%Y/%m/%d %H:%M:%S",
as.POSIXct("2001-01-01 04:00:00"),format = "%Y/%m/%d %H:%M:%S","hour"),
length.out = 7), order = rep(1,length.out = 7))
sector2 = data.frame(date = rep(seq.POSIXt(as.POSIXct("2001-02-01 04:30:00"),format = "%Y/%m/%d %H:%M:%S",
as.POSIXct("2001-02-01 06:00:00"),format = "%Y/%m/%d %H:%M:%S","hour"),
length.out = 7), order = rep(2,length.out = 7))
sector3 = data.frame(date = rep(seq.POSIXt(as.POSIXct("2001-03-01 06:30:00"),format = "%Y/%m/%d %H:%M:%S",
as.POSIXct("2001-03-01 10:00:00"),format = "%Y/%m/%d %H:%M:%S","hour"),
length.out = 7), order = rep(3,length.out = 7))
# binding sectors
df1 = rbind(sector1,sector2,sector3) %>% distinct(date,order)
В основном у них есть «порядок» и дата (а также другие столбцы). Что мне нужно, так это извлечь последовательность строк с самой ранней датой, на которую порядок переходит из одного состояния в другое (в конечном итоге возвращая только уникальный порядок; таким образом, в этом случае я ожидал бы 3 строки), а затем вычислить, сколько времени потребовалось для изменения этого состояния. Для целей этого примера я буду выполнять действия с одним фреймом данных, но каким бы ни был ответ, имейте в виду, что он будет применен с использованием lapply к списку.
Настройка фрейма данных repex:
#adding spurious row with order 3 but date that precedes order 2
df1[12,] = data.frame(date = as.POSIXct("2001-02-01 03:30:00"), order = 3)
# extracting rows of length(unique(df1$order))
df2 = df1 %>% group_by(order) %>% slice_min(order_by = date, n = 1)
df2 = df2 %>% arrange(date)
Первоначально я достиг этого, хотя и довольно медленно, используя:
df2 %>% group_by(order) %>% slice_min(order_by = date, n = 1) %>%
as.data.frame() %>% mutate(time_between = as.numeric(date-lag(date), units = 'hours'))
То, что делается выше, — это группировка по порядку, а затем нарезка первой строки (в основном это соответствует раннему времени, поскольку обычно это происходит в порядке времени). Затем я вычисляю время между каждым изменением порядка.
Это результат:
date order time_between
1 2001-01-01 00:00:00 1 NA
2 2001-02-01 04:30:00 2 748.5
3 2001-02-01 03:30:00 3 -1.0
Хотя вышеуказанное работает в большинстве случаев (это довольно медленно), возникают проблемы, когда дата из последующего заказа (3 в приведенном выше примере) помечается по времени до предыдущего заказа (2 в приведенном выше случае). Это означает, что у меня отрицательное значение времени (-1.0), что не имеет смысла.
То, что я хотел бы сделать, это вместо простой группировки по порядку, тогда нарезка первой строки — это своего рода логическая операция, при которой, если дата / время строки, которая должна была быть извлечена, предшествует строке предыдущего порядка, она отбрасывается, и первая строка после выбора времени, в этом случаев случае, если это будет 2001-03-01 06:30:00 3
date order time_between
1 2001-01-01 00:00:00 1 NA
2 2001-02-01 04:30:00 2 748.5
3 2001-03-01 06:30:00 3 674.0
Как уже упоминалось, я выполнял вышеуказанное для списка фреймов данных, поэтому реализовал следующим образом:
lapply(list1, function(x) {x %>% group_by(order) %>% slice_min(order_by = date, n = 1) %>% ungroup()})
lapply(list1, function(x) {x %>% mutate(time_between = as.numeric(date-lag(date), units = 'hours'))})
Дополнительный пример фрейма данных:
df1 = data.frame(datetime = as.POSIXct(c("2019-04-11 21:46:55",
"2019-04-13 00:19:23",
"2019-04-15 01:20:41",
"2019-04-15 04:18:12",
"2019-04-23 00:50:45",
"2019-04-22 08:44:41",
"2019-04-24 05:54:17",
"2019-04-23 07:21:36")), order = c(1,3,4,5,6,7,9,7))
Ответ №1:
Я не уверен точно, какой шаг замедляет процесс, но, начиная с df1
этого, вы можете сохранить одну строку для каждой даты, используя distinct
, а затем вычесть время, используя lag
и as.numeric
.
library(dplyr)
df1 %>%
mutate(date = lubridate::ymd_hms(date)) %>%
arrange(order, date) %>%
distinct(order, .keep_all = TRUE) %>%
mutate(time_between = as.numeric(date - lag(date), units = 'hours'))
# date order only_date time_between
#1 2001-01-01 00:00:00 1 2001-01-01 NA
#2 2001-02-01 04:30:00 2 2001-02-01 748.5
#3 2001-03-01 06:30:00 3 2001-03-01 674.0
Очевидно, что для списка фреймов данных используйте его с lapply
/ map
:
lapply(list1, function(x) {
x %>%
mutate(date = lubridate::ymd_hms(date)) %>%
arrange(order, date) %>%
distinct(order, .keep_all = TRUE) %>%
mutate(time_between = as.numeric(date - lag(date), units = 'hours'))
})
Комментарии:
1. Ronak. Спасибо за ввод. Я должен был быть более ясным. Меня интересует не только дата, но и время. Таким образом, строка для определенного порядка может иметь более раннее время (чем строка для предыдущего порядка), если это так, я хочу проигнорировать это и использовать первую строку, чтобы иметь время после этого. Другими словами, мне нужно, чтобы порядок был последовательным, а время — последовательным, так как тогда я могу успешно вычислить разницу. Извините, это довольно запутанно.
2. Медленная часть — это то, где я сгруппировал по порядку и нарезал min ()
3. @Dasr Хорошо, так что добавление
arrange(date) %>%
передdistinct
помощью? Чтобы вы всегда получали минимальное время для каждой даты при использованииdistinct
?4. Хорошо, я попытаюсь описать, используя цели: 1) Мне нужно извлечь все отдельные заказы, появляющиеся в фрейме данных (в этом примере 3) 2) Мне нужна одна строка для каждого заказа, который будет отображаться в отфильтрованном фрейме данных 3) Мне нужно, чтобы разница во времени вычислялась между строкой до и строкой после (исключая первую строку, для которой это невозможно) 4) каждая строка должна быть репрезентативной для самого раннего времени, когда конкретный порядок присутствовал в нефильтрованном фрейме данных, если это время не предшествует предыдущей строке, если это так, оно должно бытьпосмотрите ниже в исходном df и выберите другую строку с …
5. тот же порядок, но более позднее время