Разделить значение, разделенное запятыми, и оценить максимальное значение в R

#r #na #csv

#r #na #csv

Вопрос:

Мой набор данных выглядит следующим образом:

 id  Protein IDs         Coverage [%]    Coverage2 [%]   Max
0   A0A075B6I0                  14.8            20.49   20.49
1   A0A075B6I9;P04211           21.4            NA;NA   
2   A0A075B6J9                  24.6      24.58;22.48   24.58
3   A0A075B6K4                  28.7               NA   
4   A0A075B6K2;A0A075B6K5       49.6         44.22;NA   44.22
 

В столбце Max я пытаюсь получить максимальное значение между всеми значениями в «Coverage2 [%]», используя следующий код:

 dt$Max <- sapply(strsplit(as.character(dt$`Coverage2 [%]`),";"), function(x) ifelse( !all(is.na(x)), max(as.numeric(x), na.rm=T), NA) )
 

Но, как можно видеть в разделе данных выше, если есть NA только один или несколько NA s, я ничего не получаю, в то время как желаемый результат будет одним NA (в обоих случаях). Предположим, что dt это приведенный выше набор данных без столбца Max.

Что я делаю не так, пожалуйста? Следует отметить, что я получаю следующие две ошибки в консоли: Warning in ifelse(!all(is.na(x)), max(as.numeric(x), na.rm = T), NA) : NAs introduced by coercion и Warning in max(as.numeric(x), na.rm = T) : no non-missing arguments to max; returning -Inf

Ответ №1:

Мы можем использовать separate_rows with convert = TRUE from tidyr для разделения столбца, а также для изменения типа, затем выполнить группировку по max и либо выполнить a right_join , либо использовать bind_cols для создания столбца в исходных данных

 library(dplyr)
library(tidyr)
dt %>%
   separate_rows(`Coverage2 [%]`, convert = TRUE) %>%
   group_by(id) %>%
   summarise(Max = if(all(is.na(`Coverage2 [%]`))) NA_real_ else 
          max(`Coverage2 [%]`, na.rm = TRUE), .groups = 'drop') %>%
   right_join(dt) %>%
   select(names(dt), Max)
 

-вывод

 # A tibble: 5 x 5
#     id `Protein IDs`         `Coverage [%]` `Coverage2 [%]`   Max
#  <int> <chr>                          <dbl> <chr>           <dbl>
#1     0 A0A075B6I0                      14.8 20.49            20.5
#2     1 A0A075B6I9;P04211               21.4 NA;NA            NA  
#3     2 A0A075B6J9                      24.6 24.58;22.48      24.6
#4     3 A0A075B6K4                      28.7 <NA>             NA  
#5     4 A0A075B6K2;A0A075B6K5           49.6 44.22;NA         44.2
 

В коде OP мы получаем предупреждение, и это можно предотвратить, если мы используем if/else

 sapply(strsplit(as.character(dt$`Coverage2 [%]`),";"), function(x) {
       x1 <- as.numeric(x)
       if(all(is.na(x1))) NA_real_ else max(x1, na.rm = TRUE)
  })
#[1] 20.49    NA 24.58    NA 44.22
 

данные

 dt <- structure(list(id = 0:4, `Protein IDs` = c("A0A075B6I0", "A0A075B6I9;P04211", 
"A0A075B6J9", "A0A075B6K4", "A0A075B6K2;A0A075B6K5"), `Coverage [%]` = c(14.8, 
21.4, 24.6, 28.7, 49.6), `Coverage2 [%]` = c("20.49", "NA;NA", 
"24.58;22.48", NA, "44.22;NA")), class = "data.frame", row.names = c(NA, 
-5L))