Как удалить все строки, которые не соответствуют всем условиям (для каждой группы)?

#r #tidyverse

#r #tidyverse

Вопрос:

Для начала, извините, если этот вопрос задавался раньше (я уверен, что задавался, я просто не могу найти правильный ответ)

Допустим, у меня есть следующий фрейм данных. В этом случае бегун Тим получил травму на втором круге. Что я хочу сделать, так это удалить круг № 2 у всех бегунов, поскольку его данные больше нельзя сравнивать.

 race <- data.frame("Runner" = c("John","John","Elsa","Elsa","Tim","Tim"),
                "Time" = c(1,2,3,4,5,NA),
                "Lap" = c(1,2,1,2,1,2)
                )
> race
  Runner Time Lap
1   John    1   1
2   John    2   2
3   Elsa    3   1
4   Elsa    4   2
5    Tim    5   1
6    Tim   NA   2
  

Итак, в основном, я хочу закончить с фреймом данных с 3 строками. По одной для Джона, Эльзы и Тима, в каждой строке указано время из круга № 1.

Мне нравится работать с tidyverse, поэтому, если есть ответ, который использует dplyr или что-нибудь подобное, я был бы очень признателен.

Комментарии:

1. попробуйте race[race$Lap == 1, ]

2. Спасибо за ваши ответы. Извините, что не добавил в исходном сообщении, что я хочу, чтобы код работал и с другими наборами данных. Я знаю, что я мог бы использовать filter с Lap == 1 или подмножество с базой R, но это не будет работать с большими наборами данных с гораздо большим количеством бегунов, кругов и т.д.

Ответ №1:

Попробуйте это:

 race <- race%>%
  filter(Lap == 1)
  

Комментарии:

1. @DarrenTsai полностью верно, нет необходимости, сила привычки, я думаю. сейчас редактирую.

2. Кстати, добавлено в качестве ответа, потому что я пока не могу оставлять комментарии 🙂

3. Спасибо за ваш ответ. Да, я знаю, что в этом случае я могу просто выполнить фильтрацию, выбрав круг 1, но было бы неплохо получить код, который также работал бы с большими наборами данных, где становится очень сложно просто вручную выбрать определенное значение.

Ответ №2:

Более безопасным подходом было бы сначала найти, Lap когда кто-либо получил травму ( NA в Time ), а затем удалить все данные с этого Lap момента и далее

 subset(race[order(race$Lap), ], Lap < Lap[which.max(is.na(Time))])


#  Runner Time Lap
#1   John    1   1
#2   Elsa    3   1
#3    Tim    5   1
  

и с dplyr это было бы

 library(dplyr)

race %>%
 arrange(Lap) %>%
 filter(Lap < Lap[which.max(is.na(Time))])
  

Сначала данные упорядочиваются по Lap , which.max(is.na(Time) определяется индекс, по которому они были обнаружены впервые NA , мы берем соответствующий Lap и сохраняем все строки меньшего размера, чем это Lap .

Это все равно сработало бы, если у вас в наборе данных 10 Lap секунд, а какой-то игрок получил травму в 6-й Lap .

Комментарии:

1. На самом деле это отличный ответ. Я только что попробовал это с большим набором данных, но да, это имеет полный смысл. Теперь я чувствую себя глупо из-за того, что не думал так, как ты. Я пробовал группировать по Runner и другим вещам, которые ни к чему меня не привели, но ваш подход был намного лучше.

Ответ №3:

Вот способ сделать это через базу R. Мы разделяем на Runner после очистки из NAs. Затем мы intersect вычеркиваем Lap и сохраняем только те, которые найдены в этом пересечении, т.Е.

 race[race$Lap %in% Reduce(intersect, split(race$Lap[!is.na(race$Time)], race$Runner[!is.na(race$Time)])),]
#  Runner Time Lap
#1   John    1   1
#3   Elsa    3   1
#5    Tim    5   1
  

Комментарии:

1. Интересно. Я пытался использовать функцию intersect, но у меня не получилось заставить ее работать (ну, по крайней мере, не так, как я хотел, чтобы она работала). Хотя это имеет смысл. Я думаю, единственная проблема заключается в том, что было бы сложнее использовать это в конвейере.

Ответ №4:

Мы также можем использовать subset из base R

 subset(race, Lap == 1)