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

#r #dplyr

#r #dplyr

Вопрос:

У меня есть набор данных, который выглядит как:

 Group   Gene    Score   direct_count    secondary_count SD_per_group
  1    AQP11    0.31          4                5           0.12
  1    CLNS1A   0.27          0                2           0.12
  1    RSF1     0.49          3                6           0.12
  2    CFDP1    0.58          1                2           0.02
  2    CHST6    0.59          1                3           0.02
  2    UBL      0.56          1                3           0.02
  3    ACE      0.634         1                1           0.001
  3    NOS2     0.6345        1                1           0.001
  4    Gene1    0.1           10              20           0.45
  4    Gene2    0.68          3                1           0.45
  4    Gene3    0.7           0                1           0.45
  5    AGT      0.75          0                0           0.00
  

Я выбираю определенные гены для каждой группы на основе их Score по отношению к SD_per_group последующим их direct_count , и secondary_count если на каждом шаге фильтрации выбирается более 1 гена.

Я пытаюсь выбрать ген для каждой группы на первом этапе фильтрации, если наивысший балл> SD_per_group оценка по сравнению с другими в группе (затем, если выбрано более 1 гена, я выбираю гены на основе count столбцов, сохраняя только несколько генов на группу, если они также имеют совпадающие столбцы прямого и вторичного подсчета).

Я кодирую это с помощью:

 new_df <- df %>% 
  group_by(Group) %>% 
  filter((max(Score) - Score)<SD_per_group) %>% 
  slice_max(direct_count, n = 1) %>% 
  slice_max(secondary_count, n = 1) %>% 
  ungroup()
  

Однако, в случае, когда в группе для начала есть только 1 ген, а SD_per_group равен 0.00, этот единственный ген не выбирается для этой группы, но мне это нужно.

Как я могу использовать filter((max(Score) - Score)<SD_Per_Group) с учетом групп, имеющих только 1 ген для начала? В приведенных в моем примере данных мой код ничего не выбирает для группы 5.

Входные данные:

 structure(list(Group = c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 4L, 
4L, 4L, 5L), Gene = c("AQP11", "CLNS1A", "RSF1", "CFDP1", "CHST6", 
"UBL", "ACE", "NOS2", "Gene1", "Gene2", "Gene3", "AGT"), Score = c(0.31, 
0.27, 0.49, 0.58, 0.59, 0.56, 0.634, 0.6345, 0.1, 0.68, 0.7, 
0.75), direct_count = c(4L, 0L, 3L, 1L, 1L, 1L, 1L, 1L, 10L, 
3L, 0L, 0L), secondary_count = c(5L, 2L, 6L, 2L, 3L, 3L, 1L, 
1L, 20L, 1L, 1L, 0L), SD_per_group = c(0.12, 0.12, 0.12, 0.02, 
0.02, 0.02, 0.001, 0.001, 0.45, 0.45, 0.45, 0)), row.names = c(NA, 
-12L), class = c("data.table", "data.frame"))
  

Ожидаемый результат:

     
  Group Gene Score     direct_count secondary_count     SD_per_group
    1   RSF1    0.4900      3             6                0.120     #highest score >SD_per_group
    2   CHST6   0.5900      1             3                0.020     #highest secondary count
    3   ACE     0.6340      1             1                0.001     #ACE and NOS2 <SD diff and matching both counts
    3   NOS2    0.6345      1             1                0.001
    4   Gene2   0.6800      3             1                0.450    #highest direct count
    5   AGT     0.75        0             0                0.00     #only gene in the group so must be selected

  

Ответ №1:

Вы можете включить оба параметра фильтрации, используя if else .

 df %>% group_by(Group) %>% filter(if(n() > 1) {(max(Score) - Score) < SD_per_group} else TRUE) %>% 
   slice_max(direct_count, n = 1) %>% 
   slice_max(secondary_count, n = 1) %>% 
   ungroup()
# A tibble: 6 x 6
  Group Gene  Score direct_count secondary_count SD_per_group
  <int> <chr> <dbl>        <int>           <int>        <dbl>
1     1 RSF1  0.49             3               6        0.12 
2     2 CHST6 0.59             1               3        0.02 
3     3 ACE   0.634            1               1        0.001
4     3 NOS2  0.634            1               1        0.001
5     4 Gene2 0.68             3               1        0.45 
6     5 AGT   0.75             0               0        0    
> 
  

Ответ №2:

Если я правильно понимаю вашу необходимую логику, вы хотите сохранить любые строки, в которых для этой группы есть только 1 строка?

Если это так, вы можете добавить or оператор в свой фильтр, чтобы также сохранить любые строки, в которых есть только количество 1 (т. Е. n() == 1 ) Для приведенного ниже:

код

 new_df <- df %>% 
  group_by(Group) %>% 
  filter((max(Score) - Score)<SD_per_group | n() == 1) %>% 
  slice_max(direct_count, n = 1) %>% 
  slice_max(secondary_count, n = 1) %>% 
  ungroup()
  

ВЫВОД

 > new_df
# A tibble: 6 x 6
  Group Gene  Score direct_count secondary_count SD_per_group
  <int> <chr> <dbl>        <int>           <int>        <dbl>
1     1 RSF1  0.49             3               6        0.12 
2     2 CHST6 0.59             1               3        0.02 
3     3 ACE   0.634            1               1        0.001
4     3 NOS2  0.634            1               1        0.001
5     4 Gene2 0.68             3               1        0.45 
6     5 AGT   0.75             0               0        0