Как сохранить значения NA при использовании which.min () с apply ()?

Скажем, у меня есть фрейм данных, в котором целые столбцы имеют NA, например:

set.seed(0)
data <- data.frame(A = rnorm(10, 10, 1),
                   B = rnorm(10, 12, 2),
                   C = rep(NA, 10))

Если я применяю min() по столбцам, я получаю результат, на который надеялся:

apply(data, 2, min)
#        A        B        C 
# 8.460050 9.524923       NA 

Однако, когда я применяю which.min(), мой вывод представляет собой список, а столбец C дает integer(0):

apply(data, 2, which.min)
# $A
# [1] 6
# $B
# [1] 10
# $C
# integer(0)

Я могу заставить его выглядеть так, как я хочу, с помощью этого довольно уродливого обходного пути:

which.mins <- unlist(apply(data, 2, which.min))
which.mins[names(data)[!(names(data) %in% names(which.mins))]] <- NA
which.mins
#  A  B  C 
#  6 10 NA 

Есть ли лучший способ сделать это, имитирующий результат, который я получаю при использовании apply() с min()?


r na
person sudo make install    schedule 12.03.2014    source источник


Ответы (4)


Вы правы, which.min возвращает 0, если x не имеет не-НА. Вы все еще можете использовать apply и which.min вот так:

apply(data, 2, function(x) {if (all(is.na(x))) {NA}  else {which.min(x)} }) 
person koekenbakker    schedule 12.03.2014
comment
опередить меня на 6 секунд =) Я собирался предложить which.mins ‹- apply (data, 2, function (x) if (length (which.min (x)) == 0) {NA} else {which.min (Икс)}) - person James Tobin; 13.03.2014
comment
Идеально! Кроме того, очень приятно узнать о функции all () - это может оказаться очень кстати. Спасибо! - person sudo make install; 13.03.2014

Обратите внимание, что вызов apply для data.frame приводит к принуждению data.frame к матрице перед применением функции. Вместо этого вы должны использовать sapply (или vapply), иначе вы можете получить странные ошибки, потому что все столбцы вашего data.frame будут приведены к общему типу (часто символу).

Просто проверьте, равна ли длина результата which.min нулю, и в этом случае верните NA.

> # if() evaluates to FALSE if length(wm) is 0 because as.logical(0) is FALSE
> sapply(data, function(x) if(length(wm <- which.min(x))) wm else NA)
 A  B  C 
 6 10 NA
person Joshua Ulrich    schedule 12.03.2014
comment
Спасибо за совет о приведении файла data.frame в матрицу с помощью apply () - это то, на что нужно обратить внимание четыре. - person sudo make install; 13.03.2014

Первый пример не дает значения NA, потому что он обнаруживает NA в вашем векторе и возвращает их как минимальное значение, он дает NA, потому что в столбце C вашего фрейма данных нет чисел, поэтому он не может вернуть число в позицию Возвращается 3 числового вектора min. which.min() возвращает список списков позиций минимального значения:

str(apply(data, 2, which.min)[1])
List of 1
 $ A: int 6

И поскольку в столбце C нет минимального значения, он возвращает список длиной 0, что дает результат integer(0).

Ваш обходной путь в порядке, если вы это пытаетесь сделать. В качестве альтернативы вы можете просто обернуть все это функцией

whichMinNAs <- function(x){
  if(FALSE %in% is.na(x)){
    return(which.min(x))
  } else {
    return(NA)
  }
}

apply(data, 2, whichMinNAs)

 A  B  C 
 6 10 NA
person TomR    schedule 12.03.2014

Вот пример обходного пути:

apply(data, 2, FUN=function(x) ifelse(length(test<-which.min(x))>0, test, NA))

> apply(data, 2, FUN=function(x) ifelse(length(test<-which.min(x))>0, test, NA))
 A  B  C 
 6 10 NA
person Teemu Daniel Laajala    schedule 12.03.2014