R: фрейм данных подмножества для всех строк после выполнения условия

#r #dplyr #subset

#r #дплыр #подмножество #dplyr

Вопрос:

Итак, у меня есть набор данных следующего вида:

 ID    Var1   Var2
1      2      0
1      8      0
1      12     0
1      11     1
1      10     1
2      5      0
2      8      0
2      7      0
2      6      1
2      5      1
  

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

 ID    Var1   Var2
1      12     0
1      11     1
2      8      0
2      7      0
2      6      1
  

Исходный набор данных содержит несколько NAS, и функция должна просто игнорировать их. Также, если Var2 никогда не достигает «1» для группы, следует просто добавить все строки в новый фрейм данных (конечно, только те, которые после того, как Var1 достигнет своего группового максимума).
Однако я не могу обернуть свою руку вокруг программирования. Кто-нибудь знает помощь?

Ответ №1:

dplyr Решение на cumsum основе filter будет делать то, что требует вопрос.

 library(dplyr)

df1 %>%
  group_by(ID) %>%
  filter(cumsum(Var1 == max(Var1)) == 1, cumsum(Var2) <= 1)
## A tibble: 5 x 3
## Groups:   ID [2]
#     ID  Var1  Var2
#  <int> <int> <int>
#1     1    12     0
#2     1    11     1
#3     2     8     0
#4     2     7     0
#5     2     6     1
  

Редактировать

Вот решение, которое пытается ответить на комментарий OP и редактировать вопрос.

 df1 %>%
  group_by(ID) %>%
  mutate_at(vars(starts_with('Var')), ~replace_na(., 0L)) %>%
  filter(cumsum(Var1 == max(Var1)) == 1, cumsum(Var2) <= 1)
  

Данные

 df1 <- read.table(text = "
ID    Var1   Var2
1      2      0
1      8      0
1      12     0
1      11     1
1      10     1
2      5      0
2      8      0
2      7      0
2      6      1
2      5      1
", header = TRUE)
  

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

1. большое спасибо за ваш ответ. Однако это не работает на 100% правильно для фактического набора данных. Для большинства групп остается только одна строка, чего не может быть. Как решение справляется с NAs и если в Var2 нет «1»? Я просто отредактировал вопрос, чтобы сделать это более понятным

2. @philipp.kn_98 Посмотрите, отвечает ли решение в редактировании на вопрос.

Ответ №2:

Использование data.table с .I

 library(data.table)
setDT(df1)[df1[, .I[cumsum(Var1 == max(Var1)) amp; cumsum(Var2) <= 1], by="ID"]$V1]
#   ID Var1 Var2
#1:  1   12    0
#2:  1   11    1
#3:  2    8    0
#4:  2    7    0
#5:  2    6    1
  

данные

 df1 <- structure(list(ID = c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L), 
    Var1 = c(2L, 8L, 12L, 11L, 10L, 5L, 8L, 7L, 6L, 5L), Var2 = c(0L, 
    0L, 0L, 1L, 1L, 0L, 0L, 0L, 1L, 1L)), class = "data.frame",
    row.names = c(NA, 
-10L))
  

Ответ №3:

Вот data.table перевод рабочего решения Руи Баррадаса:

 library(data.table)

dat <- fread(text = "
ID    Var1   Var2
1      2      0
1      8      0
1      12     0
1      11     1
1      10     1
2      5      0
2      8      0
2      7      0
2      6      1
2      5      1
", header = TRUE)

dat[, .SD[cumsum(Var1 == max(Var1)) amp; cumsum(Var2) <= 1], by="ID"]