使用带有apply()的which.min时,如何保留NA值?

时间:2014-03-12 20:01:49

标签: r na

假设我有一个数据框,其中整个列都是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()时获得的输出?

4 个答案:

答案 0 :(得分:6)

你说得对,如果x没有非NA,which.min会返回0。您仍然可以像这样使用applywhich.min

apply(data, 2, function(x) {if (all(is.na(x))) {NA}  else {which.min(x)} }) 

答案 1 :(得分:2)

请注意,在data.frame上调用apply会导致在应用函数之前将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

答案 2 :(得分:0)

第一个示例没有给出NA值,因为它检测到向量中的NA并将它们作为最小值返回,它给出了NA,因为数据的C列中没有数字框架,以便它不能返回一个数字到数字向量min的位置3返回。 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

答案 3 :(得分:0)

以下是一个解决方法的示例:

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