R: Нарезка сгруппированного фрейма данных при условии столбца

#r #dplyr

#r #dplyr

Вопрос:

У меня есть фрейм данных с группой, условие, которое отличается для каждой группы, и индекс внутри каждой группы:

 df <- data.frame(group = c(rep(c("A", "B", "C"), each = 3)), 
                 condition = rep(c(0,1,1), each = 3), 
                 index = c(1:3,1:3,2:4))

> df
  group condition index
1     A         0     1
2     A         0     2
3     A         0     3
4     B         1     1
5     B         1     2
6     B         1     3
7     C         1     2
8     C         1     3
9     C         1     4
  

Я хотел бы нарезать данные внутри каждой группы, отфильтровывая все, кроме строки с наименьшим индексом. Однако этот фильтр следует применять только тогда, когда применяется условие, т. Е. condition == 1 . Мое решение состояло в том, чтобы вычислить ранжирование по индексу внутри каждой группы и фильтровать по комбинации условия и ранга:

 df %>%
  group_by(group) %>%
  mutate(rank = order(index)) %>%
  filter(case_when(condition == 0 ~ TRUE,
                   condition == 1 amp; rank == 1 ~ TRUE))

# A tibble: 5 x 4
# Groups:   group [3]
  group condition index  rank
  <chr>     <dbl> <int> <int>
1 A             0     1     1
2 A             0     2     2
3 A             0     3     3
4 B             1     1     1
5 C             1     2     1
  

Это заставило меня задуматься, существует ли более быстрое решение, которое не требует отдельной переменной ранжирования и потенциально использует slice_min() вместо этого.

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

1. Вы можете использовать slice с which.min()

2. Возможно, я не совсем понимаю, как работает which.min(), но это не учитывает условие, не так ли?

Ответ №1:

Вы можете использовать filter() для сохранения всех случаев, когда условие равно нулю или индекс равен минимальному индексу.

 library(dplyr)

df %>%
  group_by(group) %>%
  filter(condition == 0 | index == min(index))

# A tibble: 5 x 3
# Groups:   group [3]
  group condition index
  <chr>     <dbl> <int>
1 A             0     1
2 A             0     2
3 A             0     3
4 B             1     1
5 C             1     2
  

Ответ №2:

Опция с slice

 library(dplyr)
df %>%
    group_by(group) %>% 
    slice(unique(c(which(condition == 0), which.min(index))))
  

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

1. У меня есть вопрос, очень похожий на OP, но вместо фильтрации мне нужно было бы применить функцию. Например, используя group_map , я применяю пользовательскую функцию к моему сгруппированному фрейму данных. Это работает. Но теперь внутри этой группы мне нужно было бы применить ту же функцию частями по 12 вместо полной группы df. Например, если в группе 30 строк. Я хотел бы применить функцию частями по 12, т. е. 12 12 6 … таким образом, было бы получено 3 разных вывода для одной и той же группы. Интересно, отвечали ли вы ранее на этот вопрос? любые выводы были бы полезны.