使用R中的任何NA查看所有列名称

Gab*_*yLP 8 r sapply

我需要获取至少有1个NA的列的名称.

df<-data.frame(a=1:3,b=c(NA,8,6), c=c('t',NA,7))
Run Code Online (Sandbox Code Playgroud)

我需要得到"b,c".

我找到了这段代码:

sapply(df, function(x) any(is.na(x)))
Run Code Online (Sandbox Code Playgroud)

但我只需要有任何NA的变量.

我试过这个:

sapply(df, function(x) colnames(df[,any(is.na(x))]))
Run Code Online (Sandbox Code Playgroud)

但我得到了所有的列名.

Pau*_*tra 8

你非常接近.你的第一次尝试产生一个boolean载体,您可以使用索引namesdf:

contains_any_na = sapply(df, function(x) any(is.na(x)))
names(df)[contains_any_na]
# [1] "b" "c"
Run Code Online (Sandbox Code Playgroud)

更新2017年1月14日:从R版本3.1.0开始,anyNA()可以作为替代any(is.na(.)),并且上面的代码可以简化为

names(df)[sapply(df, anyNA)]
# [1] "b" "c"
Run Code Online (Sandbox Code Playgroud)


ags*_*udy 7

另一种杂技解决方案(只是为了好玩):

colnames(df)[!complete.cases(t(df))]
[1] "b" "c"
Run Code Online (Sandbox Code Playgroud)

这个想法是:获得具有至少1个NA的A列相当于得到t(A)至少具有NA的行. complete.cases根据定义(非常有效,因为它只是对C函数的调用)给出没有任何缺失值的行.


rns*_*nso 6

尝试 data.table 版本:

library(data.table)
setDT(df)
names(df)[df[,sapply(.SD, function(x) any(is.na(x))),]]
[1] "b" "c"
Run Code Online (Sandbox Code Playgroud)

使用@akrun 的代码进行微基准测试:

set.seed(49)
df1 <- as.data.frame(matrix(sample(c(NA,1:200), 1e4*5000, replace=TRUE), ncol=5000))
setDT(df1)


f1 <- function() {contains_any_na = sapply(df1, function(x) any(is.na(x)))
           names(df1)[contains_any_na]}

f2 <- function() {colnames(df1)[!complete.cases(t(df1))] }
f3 <- function() { names(df1)[!!colSums(is.na(df1))] }

f4 <- function() { names(df1)[df1[,sapply(.SD, function(x) any(is.na(x))),]] }

microbenchmark(f1(), f2(), f3(), f4(), unit="relative")   
# Unit: relative
#  expr       min        lq    median       uq      max neval
#  f1()  1.000000  1.000000  1.000000 1.000000 1.000000   100
#  f2() 10.459124 10.928821 10.955986 9.858967 7.069066   100
#  f3()  3.323144  3.805183  4.159624 3.775549 2.797329   100
#  f4() 10.108998 10.242207 10.121022 9.117067 6.576976   100
Run Code Online (Sandbox Code Playgroud)

@agstudy:此解决方案的速度与 colnames(df1)[!complete.cases(t(df1))].


akr*_*run 5

 names(df)[!!colSums(is.na(df))]
 #[1] "b" "c"
Run Code Online (Sandbox Code Playgroud)

说明

colSums(is.na(df)) #gives you the number of missing value per each columns
#a b c 
#0 1 1 
Run Code Online (Sandbox Code Playgroud)

通过使用!,我们正在创建一个逻辑索引

!colSums(is.na(df))   #here the value of `0` will be `TRUE` and all other values `>0` FALSE
 #   a     b     c 
 #TRUE FALSE FALSE 
Run Code Online (Sandbox Code Playgroud)

但是,我们需要选择那些至少包含一列的列NA,所以!再次否定

!!colSums(is.na(df))
#   a     b     c 
#FALSE  TRUE  TRUE 
Run Code Online (Sandbox Code Playgroud)

并使用此逻辑索引来获取至少有一个的名称 NA

基准

 set.seed(49)
 df1 <- as.data.frame(matrix(sample(c(NA,1:200), 1e4*5000, replace=TRUE), ncol=5000))

 library(microbenchmark)

 f1 <- function() {contains_any_na = sapply(df1, function(x) any(is.na(x)))
            names(df1)[contains_any_na]}

 f2 <- function() {colnames(df1)[!complete.cases(t(df1))] }
 f3 <- function() { names(df1)[!!colSums(is.na(df1))] }

 microbenchmark(f1(), f2(), f3(), unit="relative")
 #Unit: relative
 #expr      min       lq   median       uq      max neval
 #f1() 1.000000 1.000000 1.000000 1.000000 1.000000   100
 #f2() 8.921109 7.289053 6.852122 6.210826 4.889684   100
 #f3() 3.248072 3.105798 2.984453 2.774513 2.599745   100
Run Code Online (Sandbox Code Playgroud)

编辑性能说明:

也许sapply基于令人惊讶 的解决方案是胜利者,因为如下面的@flodel评论中所述,其他2个解决方案在场景后面创建了一个矩阵(t(df)is.na(df))创建矩阵.