查看R中具有任何NA的所有列名
我需要得到至少有1个NA的列的名称查看R中具有任何NA的所有列名,r,sapply,R,Sapply,我需要得到至少有1个NA的列的名称 df<-data.frame(a=1:3,b=c(NA,8,6), c=c('t',NA,7)) 但我只需要有NA的变量 我试过这个: sapply(df, function(x) colnames(df[,any(is.na(x))])) 但是我知道所有的列名 names(df)[!!colSums(is.na(df))] #[1] "b" "c" 解释 通过使用,我们正在创建逻辑索引 !colSums(is.na(df)) #here
df<-data.frame(a=1:3,b=c(NA,8,6), c=c('t',NA,7))
但我只需要有NA的变量
我试过这个:
sapply(df, function(x) colnames(df[,any(is.na(x))]))
但是我知道所有的列名
names(df)[!!colSums(is.na(df))]
#[1] "b" "c"
解释
通过使用代码>,我们正在创建逻辑索引
!colSums(is.na(df)) #here the value of `0` will be `TRUE` and all other values `>0` FALSE
# a b c
#TRUE FALSE FALSE
但是,我们需要选择那些至少有一个NA
的列,所以代码>再次否定
!!colSums(is.na(df))
# a b c
#FALSE TRUE TRUE
并使用此逻辑索引获取至少有一个NA
基准
set.seed(49)
df1你们非常接近。您的第一次尝试将产生一个布尔
向量,您可以使用该向量为df的名称
建立索引:
contains_any_na = sapply(df, function(x) any(is.na(x)))
names(df)[contains_any_na]
# [1] "b" "c"
更新日期2017年1月14日:自R版本3.1.0起,anyNA()
可作为any(is.na()
的替代,上述代码可简化为
names(df)[sapply(df, anyNA)]
# [1] "b" "c"
另一个杂技解决方案(只是为了好玩):
其思想是:获取A中至少有1na的列相当于获取t(A)中至少有NA的行。
完成。根据定义,cases
(非常有效,因为它只是对C函数的调用)给出的行没有任何缺失值。请尝试使用data.table版本:
library(data.table)
setDT(df)
names(df)[df[,sapply(.SD, function(x) any(is.na(x))),]]
[1] "b" "c"
使用@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
set.seed(49)
df1对于这一点,一个简单的一行是:
colnames(df[,sapply(df, function(x) any(is.na(x)))])
说明:
sapply(df, function(x) any(is.na(x)))
对于至少为1 NA的列,返回True/Falsedf[,sapply(df,函数(x)any(is.na(x)))]
获取数据帧的子集,该子集的所有列至少为1 na。而colnames
给出了这些列的名称。您能否提供一些更详细的说明,说明您的解决方案的工作原理,例如,取一个逻辑向量的和得到的真值的数量,代码>表示不是。这将使答案对OP和其他人更有用。@Paul Hiemstra感谢您的评论。我添加了一些解释。谢谢,但是为什么我不能使用名称(colSums(is.na(df))>0)?但是我得到:>names(colSums(is.na(df))>0)[1]“a”“b”“c”你的两个解决方案比较慢,因为t(df)
和is.na(df)
创建矩阵。这将是最慢的解决方案:)@rnso我只是开玩笑,我的评论只是说,并不是因为您使用data.table,您将获得最快的解决方案+1用于您和akrun的基准测试。此处花费的时间是由于.SD
是df1
的深度副本。这可以通过
避免,以提高操作速度,而无需。请参阅。@Arun当然。。请参阅akrun答案中的我的编辑(性能说明)。@Arun因为性能是由akrun完成的,而我的回答是以“acrobatic solution”开始的,OP接受了它,我不知道为什么(声誉是):),但请随意编辑它!
library(data.table)
setDT(df)
names(df)[df[,sapply(.SD, function(x) any(is.na(x))),]]
[1] "b" "c"
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
colnames(df[,sapply(df, function(x) any(is.na(x)))])
sapply(df, function(x) any(is.na(x)))