我需要获取至少有1个NA的列的名称。
df<-data.frame(a=1:3,b=c(NA,8,6), c=c('t',NA,7))
我需要“b,c”。
我找到了this code:
sapply(df, function(x) any(is.na(x)))
但我只需要有任何NA的变量。
我试过了:
sapply(df, function(x) colnames(df[,any(is.na(x))]))
但是我得到了所有的列名。
答案 0 :(得分:7)
你非常接近。您的第一次尝试会产生boolean
向量,您可以使用该向量来对names
的{{1}}进行索引:
df
2017年1月14日更新:自R版本3.1.0起,contains_any_na = sapply(df, function(x) any(is.na(x)))
names(df)[contains_any_na]
# [1] "b" "c"
可用作anyNA()
的替代方案,上述代码可简化为
any(is.na(.))
答案 1 :(得分:7)
另一种杂技解决方案(仅为了好玩):
colnames(df)[!complete.cases(t(df))]
[1] "b" "c"
这个想法是:获得具有至少1个NA的A列相当于得到t(A)至少具有NA的行。
根据定义complete.cases
(非常有效,因为它只是对C函数的调用)给出了没有任何缺失值的行。
答案 2 :(得分:5)
names(df)[!!colSums(is.na(df))]
#[1] "b" "c"
colSums(is.na(df)) #gives you the number of missing value per each columns
#a b c
#0 1 1
通过使用!
,我们正在创建一个逻辑索引
!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 <- 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
也许令人惊讶的基于sapply
的解决方案在这里获胜是因为如下面@flodel评论中所述,其他2个解决方案在场景后面创建了一个矩阵(t(df)
和is.na(df)
)创建矩阵
答案 3 :(得分:4)
尝试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
@agstudy:此解决方案的速度与colnames(df1)[!complete.cases(t(df1))]
类似。
答案 4 :(得分:0)
一个简单的一个班轮就是:
colnames(df[,sapply(df, function(x) any(is.na(x)))])
说明:
sapply(df, function(x) any(is.na(x)))
对于具有至少1 NA的列,返回True / False。 df[,sapply(df, function(x) any(is.na(x)))]
获取数据框的子集,其所有列的列均为至少1 NA。 colnames
给出了这些列的名称。