Как выбрать максимальное числовое значение из числовых символов?

#r #dplyr #data.table #max #min

#r #dplyr #данные.таблица #макс #минимум

Вопрос:

У меня есть набор данных, в котором я сгруппирован по Gene столбцу. Некоторые значения сгруппированы в каждой строке, ., поэтому я удаляю их, оставляя только несколько числовых символов в строке и столбце.

Для этого я кодирую:

 #Group by Gene:
data <- setDT(df2)[, lapply(.SD, paste, collapse = ", "), by = Genes]

#Remove ., from anywhere in the dataframe
dat <- data.frame(lapply(data, function(x) {
  gsub("\.,|\.$|\,$|(, .$)", "", x)
}))
 

Мои данные до удаления ., и после группировки Gene выглядят следующим образом:

 Gene    col1                     col2                  col3           col4
ACE     0.3, 0.4, 0.5, 0.5       .                      ., ., .        1, 1, 1, 1, 1
NOS2    ., .                     .                      ., ., ., .     0, 0, 0, 0, 0
BRCA1   .                                               ., .           1, 1, 1, 1, 1
HER2    .                        0.1, ., .,  0.2, 0.1   .              1, 1, 1, 1, 1
 

После удаления ., моих данных выглядит так:

 Gene    col1                 col2               col3     col4
ACE     0.3, 0.4, 0.5, 0.5                               1, 1, 1, 1, 1
NOS2                                                     0, 0, 0, 0, 0
BRCA1                                                    1, 1, 1, 1, 1
HER2                         0.1,      0.2, 0.1          1, 1, 1, 1, 1

 

Сейчас я пытаюсь выбрать минимальное или максимальное значение для строки и столбца.

Ожидаемый пример вывода:

 Gene    col1                 col2            col3    col4
ACE     0.5                                           1
NOS2                                                  0
BRCA1                                                 1
HER2                          0.1                     1

#For col1 I need the max value per row (so for ACE 0.5 is selected)
#For col2 I need the min value per row
 

К сведению, мои фактические данные составляют 100 столбцов и 20 000 строк — для разных столбцов требуются либо максимальные, либо минимальные значения для каждого выбранного гена.

Однако с кодом, который я использую, я получаю только ожидаемый результат col4 , и мои другие столбцы повторяют выбранное значение дважды (я получаю 0.5, 0.5 и 0.1, 0.1 и я не могу понять, почему).

Код, который я использую для выбора минимальных / максимальных значений, является:

 #Max value per feature and row
max2 = function(x) if(all(is.na(x))) NA else max(x,na.rm = T)
getmax = function(col) str_extract_all(col,"[0-9\.-] ") %>%
  lapply(.,function(x)max2(as.numeric(x)) ) %>%
  unlist() 

#Min value per feature and row
min2 = function(x) if(all(is.na(x))) NA else min(x,na.rm = T)
getmin = function(col) str_extract_all(col,"[0-9\.-] ") %>%
  lapply(.,function(x)min2(as.numeric(x)) ) %>%
  unlist() 

data <- dt %>%
  mutate_at(names(dt)[2],getmax)

data <- dt %>%
  mutate_at(names(dt)[3],getmin)

data <- dt %>%
  mutate_at(names(dt)[4],getmax)
 

Почему эти функции выбора не работают для всех моих столбцов? Все столбцы являются классом символов. Мне также интересно, нужно ли мне ., вообще удалять, и я могу просто перейти прямо к выбору максимального / минимального значения для строки и столбца?

Пример входных данных:

 structure(list(Gene = c("ACE", "NOS2", "BRCA1", "HER2"), col1 = c("0.3, 0.4, 0.5, 0.5", 
"", "", ""), col2 = c("", "", "", "  0.1,      0.2 0.,1"), col3 = c(NA, 
NA, NA, NA), col4 = c("                         1, 1, 1, 1, 1", 
"                                     0, 0, 0, 0, 0", "                                     1, 1, 1, 1, 1", 
"     1, 1, 1, 1, 1")), row.names = c(NA, -4L), class = c("data.table", 
"data.frame"))
 

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

1. Я не уверен, где начинаются ваши данные, но это может быть более эффективно dt[, lapply(.SD, max), Gene] . Поскольку ваши данные выглядят как символ, использование функции function(x) max(as.numeric(x), na.rm = TRUE) может помочь. В принципе, попробуйте посмотреть, можете ли вы пропустить свертывание, за которым следует регулярное выражение, путем прямого применения функций к вашим необработанным данным.

Ответ №1:

Вы можете использовать type.convert и задать его аргумент na.strings "." равным . Вы также можете использовать range функцию, чтобы получить как минимальное, так и максимальное значение за один раз.

Предположим, что ваш data.table выглядит так

 > dt
    Gene               col1                 col2       col3          col4
1:   ACE 0.3, 0.4, 0.5, 0.5                    .    ., ., . 1, 1, 1, 1, 1
2:  NOS2               ., .                    . ., ., ., . 0, 0, 0, 0, 0
3: BRCA1                  .                            ., . 1, 1, 1, 1, 1
4:  HER2                  . 0.1, ., .,  0.2, 0.1          . 1, 1, 1, 1, 1
 

Рассмотрим функцию, подобную этой

 library(data.table)
library(stringr)

get_range <- function(x) {
  x <- type.convert(str_split(x, ",\s ", simplify = TRUE), na.strings = ".")
  x <- t(apply(x, 1L, function(i) {
    i <- i[!is.na(i)]
    if (length(i) < 1L) c(NA_real_, NA_real_) else range(i)
  }))
  dimnames(x)[[2L]] <- c("min", "max")
  x
}
 

Тогда вы можете просто

 dt[, c(Gene = .(Gene), lapply(.SD, get_range)), .SDcols = -"Gene"]
 

Вывод

     Gene col1.min col1.max col2.min col2.max col3.min col3.max col4.min col4.max
1:   ACE      0.3      0.5       NA       NA       NA       NA        1        1
2:  NOS2       NA       NA       NA       NA       NA       NA        0        0
3: BRCA1       NA       NA       NA       NA       NA       NA        1        1
4:  HER2       NA       NA      0.1      0.2       NA       NA        1        1
 

Обратите внимание, что нет необходимости делать это с помощью Gene , поскольку функция get_range уже векторизована.