Найдите максимальное абсолютное значение по строке во фрейме данных R

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

В основном есть эквивалент функции pmax для получения абсолютных максимумов.

test_df <- tibble(
  some_identifier = c("apple", "tunafish", "turkey_sandwich"), 
  val_a =  c(-1, 2, 0), 
  val_b = c(-3, 3, NA), 
  val_c = c(2, 3, 1)

)

# this is what abs_max column should be 
test_df$abs_max <- c(-3, 3, 1)
test_df

# A tibble: 3 x 5
  some_identifier val_a val_b val_c abs_max
  <chr>           <dbl> <dbl> <dbl>   <dbl>
1 apple              -1    -3     2      -3
2 tunafish            2     3     3       3
3 turkey_sandwich     0    NA     1       1

Столбец abs_max — это то, что я хочу создать. Менее оптимальным решением может быть перебор каждой строки; но хотел связаться, чтобы определить возможный лучший метод.


person cavamic    schedule 15.08.2019    source источник


Ответы (1)


Вот способ использования max.col - спасибо @Gregor

f <- function(data) {
  tmp <- Filter(is.numeric, data)
  if(inherits(data, "tbl_df")) {
    tmp <- as.matrix(tmp)
  }
  tmp[cbind(1:nrow(tmp),
            max.col(replace(x <- abs(tmp), is.na(x), -Inf)))]
}

f(test_df)
# [1] -3  3  1

шаг за шагом

На первом этапе мы фильтруем числовые столбцы.

Filter(is.numeric, test_df)
#  val_a val_b val_c
#1    -1    -3     2
#2     2     3     3
#3     0    NA     1

(вызывается tmp в приведенной выше функции)

затем

replace(x <- abs(Filter(is.numeric, test_df)), is.na(x), -Inf))

возвращается

#  val_a val_b val_c
#1     1     3     2
#2     2     3     3
#3     0  -Inf     1

это data.frame, в котором NA были заменены на -Inf, а все отрицательные значения заменены их абсолютными значениями.

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

max.col(replace(x <- abs(Filter(is.numeric, test_df)), is.na(x), -Inf))
# [1] 2 2 3

Эта информация, наконец, используется для извлечения желаемых значений из Filter(is.numeric, test_df) с использованием числовой матрицы, т.е.

cbind(1:nrow(Filter(is.numeric, test_df)),
      max.col(replace(x <- abs(Filter(is.numeric, test_df)), is.na(x), -Inf)))
#     [,1] [,2]
#[1,]    1    2
#[2,]    2    2
#[3,]    3    3

данные

test_df <- data.frame(
  some_identifier = c("apple", "tunafish", "turkey_sandwich"), 
  val_a =  c(-1, 2, 0), 
  val_b = c(-3, 3, NA), 
  val_c = c(2, 3, 1), stringsAsFactors = FALSE)
person markus    schedule 15.08.2019
comment
Спасибо - это то практическое решение, которое я искал. Я не знал о функции max.col. Поведение Тиббла неожиданно, но полезно знать (обычно я работаю в tidyverse). > mtcars[cbind(1:3, 4:6)] [1] 110.00 3.90 2.32 > dplyr::as_tibble(mtcars)[cbind(1:3, 4:6)] Error: Must use a vector in `[`, not an object of class matrix. - person cavamic; 16.08.2019