#r #dplyr #group-by #sequence
#r #dplyr #групповое-по #последовательность
Вопрос:
У меня есть данные, которые сгруппированы по «идентификатору». Каждый «идентификатор» имеет разные лекарства на разные даты. В каждом последовательном прогоне «наркотика» я хотел бы сохранить только первый ряд. Это должно быть сделано по группам, то есть внутри каждого «идентификатора». В данных показаны два примера:
ID date drug
1 01/01/2020 A # first row in run 1 of 'A' for ID 1: keep
1 07/01/2020 A # 2nd row in run 1 of 'A' for ID 1: drop
1 09/01/2020 B
1 15/01/2020 A
2 01/02/2020 C
2 13/02/2020 D
2 17/02/2020 C # first row in run 2 of 'C' of ID 2: keep
2 18/03/2020 C # 2nd row in run 2 of 'C' of ID 2: drop
2 19/03/2020 E
Желаемый результат:
ID date drug
1 01/01/2020 A
1 09/01/2020 B
1 15/01/2020 A
2 01/02/2020 C
2 13/02/2020 D
2 17/02/2020 C
2 19/03/2020 E
Я пробовал следующее, но я не могу заставить его работать, так как он удалит те лекарства, которые относятся к той же группе, но появятся позже, например, он упадет 15/01/2020, 17/02/2020 и 18/03/2020, поскольку требуется только первое наблюдение по группам.
df_selection <- df %>%
group_by(ID) %>%
arrange(ID,date) %>%
group_by(ID, drug) %>%
slice(1L) %>%
arrange(ID,date)
Я перепробовал много комбинаций, но не могу заставить ее работать. Я был бы очень признателен за помощь!
Дополнительный пример для демонстрации случая, когда последний «препарат» в одном «идентификаторе» совпадает с первым в следующем «идентификаторе», здесь препарат «B»:
ID date drug
1 01/01/2020 A
1 07/01/2020 A
1 09/01/2020 B # first row in a run of 'B' for ID 1: keep
1 15/01/2020 B # 2nd row in a run of 'B' for ID 1: drop
2 01/02/2020 B # first row in a run of 'B' for ID 2: keep
2 13/02/2020 B # 2nd: drop
2 17/02/2020 B # 3rd: drop
2 18/03/2020 E
2 19/03/2020 E
Комментарии:
1. Что, если лекарство A является последним obs для ID1, а также первым obs для ID2? Сохранить это? Некоторые ответы до сих пор основывались на условии, что ID2 начинается с другого лекарства, чем заканчивается ID1.
2. @JonSpring Действительно, я полагаю, мы должны рассмотреть запуски в пределах ‘id’. Это не указано в вопросе, но код может это предположить.
Ответ №1:
Используя data.table
:
setDT(df)[rowid(rleid(drug)) == 1]
# ID date drug
# 1: 1 01/01/2020 A
# 2: 1 09/01/2020 B
# 3: 1 15/01/2020 A
# 4: 2 01/02/2020 C
# 5: 2 13/02/2020 D
# 6: 2 17/02/2020 C
# 7: 2 19/03/2020 E
Если прогоны ‘drug’ следует учитывать в каждом ‘ID’, который нам нужен…
df[rowid(rleid(ID, drug)) == 1]
…для обработки таких случаев, как:
ID date drug
1: 1 01/01/2020 A
2: 1 07/01/2020 A
3: 1 09/01/2020 B
4: 1 15/01/2020 B # This 'B' belongs to 2nd run in ID 1
5: 2 01/02/2020 B # This 'B' belongs to 1st run in ID 2
6: 2 13/02/2020 B
7: 2 17/02/2020 B
8: 2 18/03/2020 E
9: 2 19/03/2020 E
Ответ №2:
df %>% filter(drug != lag(drug, default = ""))
Или, если вы хотите сохранить первое появление препарата для одного идентификатора, даже если он совпадает с последним препаратом для предыдущего идентификатора (например, допустим, первым препаратом ID2 был A, и поэтому мы хотели сохранить его.):
df %>%
filter(drug != lag(drug, default = "") |
ID != lag(ID, default = 0))
Ответ №3:
Используя base R
с rle
subset(df, with(rle(drug), !duplicated(rep(seq_along(values), lengths))))
Ответ №4:
Надеюсь, этот код сработает для ваших общих случаев
> subset(df, sequence(rle(drug)$lengths) == 1)
ID date drug
1 1 01/01/2020 A
3 1 09/01/2020 B
4 1 15/01/2020 A
5 2 01/02/2020 C
6 2 13/02/2020 D
7 2 17/02/2020 C
9 2 19/03/2020 E