Я пытаюсь фильтровать пары (обозначенные id
) на основе условий. У меня есть следующий фрейм данных,
id <- c(1,1,2,2,1,1,3,3,4,4)
PorF <- c("start","fail","start","pass","start","pass","start","pass","start","fail")
timest <- c(as.POSIXct("2021-05-08 08:15:07"),
as.POSIXct("2021-05-08 08:15:45"),
as.POSIXct("2021-05-28 08:17:09"),
as.POSIXct("2021-05-28 08:17:25"),
as.POSIXct("2021-05-28 08:32:07"),
as.POSIXct("2021-05-28 08:32:12"),
as.POSIXct("2021-05-28 08:33:14"),
as.POSIXct("2021-05-28 08:33:45"),
as.POSIXct("2021-05-28 08:34:12"),
as.POSIXct("2021-05-28 08:34:56"))
testdf <- data.frame(id, PorF, timest)
testdf
> testdf
id PorF timest
1 1 start 2021-05-08 08:15:07
2 1 fail 2021-05-08 08:15:45
3 2 start 2021-05-28 08:17:09
4 2 pass 2021-05-28 08:17:25
5 1 start 2021-05-28 08:32:07
6 1 pass 2021-05-28 08:32:12
7 3 start 2021-05-28 08:33:14
8 3 pass 2021-05-28 08:33:45
9 4 start 2021-05-28 08:34:12
10 4 fail 2021-05-28 08:34:56
Я хочу отфильтровать те идентификаторы, у которых есть начало и проход. Все пары со стартом и неудачей должны быть отфильтрованы.
Мой ожидаемый результат должен выглядеть так:
> filtered_testdf
id PorF timest
2 start 2021-05-28 08:17:09
2 pass 2021-05-28 08:17:25
1 start 2021-05-28 08:32:07
1 pass 2021-05-28 08:32:12
3 start 2021-05-28 08:33:14
3 pass 2021-05-28 08:33:45
То, что я пытаюсь сделать, не дает того, что я хочу,
testdf |>
group_by(id) |>
filter(PorF == "start" & PorF == "pass")
Есть идеи, как добиться ожидаемого результата?
После arrange(id)
вы увидите последовательную пару с одинаковым идентификатором. Я хочу, чтобы пара имела последовательность «старт-пасс».
arrange
не поможет. Наоборот, это усугубит проблему, потому что тогда у вас будет 4 строки с id = 1 и программно невозможно отличить две пары строк друг от друга с помощью предоставленной вами информации (если вы не учтете, например, временная метка). Если временная метка разделяет пары, укажите эту информацию в своем вопросе.
Вы можете сделать:
library(tidyverse)
testdf |>
mutate(id_helper = cumsum(PorF == "start")) |>
filter(any(PorF == "start") & any(PorF == "pass"), .by = id_helper)
Или эквивалентно:
testdf |>
mutate(id_helper = cumsum(PorF == "start")) |>
filter(!any(PorF == "fail"), .by = id_helper)
id PorF timest id_helper
1 2 start 2021-05-28 08:17:09 2
2 2 pass 2021-05-28 08:17:25 2
3 1 start 2021-05-28 08:32:07 3
4 1 pass 2021-05-28 08:32:12 3
5 3 start 2021-05-28 08:33:14 4
6 3 pass 2021-05-28 08:33:45 4
Обратите внимание, что мне пришлось создать дополнительную переменную id, поскольку (см. мой комментарий выше) существует несколько пар строк с одним и тем же идентификатором (т. е. id 1 имеет две пары).
ты тоже можешь использовать id_helper = consecutive_id(id)
Ого вау! Я не знал этой функции. Кажется, это действительно очень хороший помощник.
Вы можете написать небольшую вспомогательную функцию, которая разбивает данные на две части на основе первой (начало) или второй (результат) строки каждой «пары» (при условии, что ваши пары смежны), а затем находит строки во второй переданной строке ( или не удалось). Затем объедините их.
filter_pair <- function(data, result) {
df <- split(data, 1:2)
idx <- which(df[[2]][,'PorF']==result)
rbind(df[[1]][idx,], df[[2]][idx,]) |>
dplyr::arrange(id, timest)
}
filter_pair(testdf, "pass")
id PorF timest
1 1 start 2021-05-28 08:32:07
2 1 pass 2021-05-28 08:32:12
3 2 start 2021-05-28 08:17:09
4 2 pass 2021-05-28 08:17:25
5 3 start 2021-05-28 08:33:14
6 3 pass 2021-05-28 08:33:45
filter_pair(testdf, "fail")
id PorF timest
1 1 start 2021-05-08 08:15:07
2 1 fail 2021-05-08 08:15:45
3 4 start 2021-05-28 08:34:12
4 4 fail 2021-05-28 08:34:56
Вместо `dplyr::arrange(id, timest)` мы могли бы написать sort_by(~id+timest)
?
Базовый вариант R, но он следует той же философии, что и решение Дешена
> subset(testdf, !ave(PorF == "fail", cumsum(PorF == "start")))
id PorF timest
3 2 start 2021-05-28 08:17:09
4 2 pass 2021-05-28 08:17:25
5 1 start 2021-05-28 08:32:07
6 1 pass 2021-05-28 08:32:12
7 3 start 2021-05-28 08:33:14
8 3 pass 2021-05-28 08:33:45
У вас есть несколько пар с одинаковым идентификатором, например. id 1 имеет пару с запуском/прохождением И запуском/сбоем. Как определить последовательную группу?