R-删除在某些列中具有所有NA的行

时间:2018-07-30 14:47:59

标签: r dataframe

假设您有一个9列的数据框。您要删除在5:9栏中具有所有NA的案例。 1:4列中是否有NA根本不相关。

到目前为止,我已经找到了可以删除列5:9的 any 中具有NA的行的函数,但是我特别需要仅删除那些具有 all 的行。 em> 5:9栏中的NA。

我编写了自己的函数来执行此操作,但是由于我有300k +行,因此速度非常慢。我想知道是否有更有效的方法?这是我的代码:

remove.select.na<-function(x, cols){
  nrm<-vector("numeric")
  for (i in 1:nrow(x)){
    if (sum(is.na(x[i,cols]))<length(cols)){
      nrm<-c(nrm,i)
    }
    #Console output to track the progress
    cat('\r',paste0('Checking row ',i,' of ',nrow(x),' (', format(round(i/nrow(x)*100,2), nsmall = 2),'%).'))
    flush.console()
  }
  x<-x[nrm,]
  rm(nrm)
  return(x)
}

其中x是数据帧,而cols是一个向量,其中包含应检查NA的列的名称。

5 个答案:

答案 0 :(得分:4)

您可以将allapply一起使用,以查找所有值为NA的行:

x[!apply(is.na(x[,5:9]), 1, all),]

或否定is.na并测试any

x[apply(!is.na(x[,5:9]), 1, any),]

或使用@RHertel之类的rowSums,而无需计算选定的行数:

x[rowSums(!is.na(x[,5:9])) > 0,]

答案 1 :(得分:2)

这是删除5至9之间所有列中带有NA的行的一种方法。通过将rowSums()is.na()组合在一起,很容易检查这5列中的所有条目是否都是{{ 1}}:

NA

答案 2 :(得分:0)

lines=
   'V1   V2   V3   V4  
    A    10   20   NA   
    B    NA   NA   NA   
    C     5   20   3     
    D    15   20   4    
    E    NA   10   5'

df = read.table(textConnection(lines), header = T)

df[is.na(df)] = 'X'


attach(df)

x = subset(df, V2 == 'X'   &   V3 == 'X'   &   V4 == 'X')
df_new = df[-as.numeric(row.names(x)),]
df_new

#  V1 V2 V3 V4
#1  A 10 20  X
#3  C  5 20  3
#4  D 15 20  4
#5  E  X 10  5

detach(df)

答案 3 :(得分:0)

我不知道它的运行速度比您的函数快,但是也许您可以对数据帧的每一行使用!anyis.na。对于此示例数据:

set.seed(1234)
x = do.call(cbind, lapply(1:9, function(x) runif(10)))
x[sample(length(x), size = 70)] <- NA
x <- data.frame(x)

> x
     X1 X2   X3   X4   X5   X6   X7   X8  X9
1  0.11 NA   NA 0.46 0.55 0.07   NA   NA  NA
2  0.62 NA   NA   NA   NA   NA 0.04   NA  NA
3    NA NA   NA 0.30   NA   NA   NA 0.01  NA
4  0.62 NA 0.04 0.51   NA   NA   NA   NA  NA
5  0.86 NA   NA 0.18   NA   NA   NA   NA 0.2
6  0.64 NA   NA   NA   NA 0.50   NA 0.52  NA
7    NA NA   NA   NA 0.68   NA   NA   NA  NA
8    NA NA   NA   NA   NA   NA   NA   NA  NA
9    NA NA   NA   NA   NA 0.17   NA   NA  NA
10   NA NA 0.05   NA   NA   NA   NA   NA  NA

应该删除第4、8和10行。因此,您可以使用apply遍历每一行以查看条件是否得到满足-第5至9列中除NA以外的任何值的任何行都将返回TRUE,因此您可以将其用作数据框的索引器。

keep.rows <- apply(x[, 5:9], 1, FUN = function(row){
  any(!is.na(row))
})

> x[keep.rows, ]
    X1 X2 X3   X4   X5   X6   X7   X8  X9
1 0.11 NA NA 0.46 0.55 0.07   NA   NA  NA
2 0.62 NA NA   NA   NA   NA 0.04   NA  NA
3   NA NA NA 0.30   NA   NA   NA 0.01  NA
5 0.86 NA NA 0.18   NA   NA   NA   NA 0.2
6 0.64 NA NA   NA   NA 0.50   NA 0.52  NA
7   NA NA NA   NA 0.68   NA   NA   NA  NA
9   NA NA NA   NA   NA 0.17   NA   NA  NA

再次,不确定它是否比您的功能更快,但是...也许?

答案 4 :(得分:0)

这里有两个dplyr选项:

library(dplyr)
df <- data_frame(a = c(0, NA, 0, 4, NA, 0, 6), b = c(1, NA, 0, 4, NA, 0, NA), c = c(1, 0, 1, NA, NA, 0, NA))


# columns b and c would be the columns you don't want all NAs

df %>% 
  filter_at(vars(b, c), any_vars(!is.na(.)))

df %>% 
  filter_at(vars(b, c), any_vars(complete.cases(.)))

# A tibble: 5 x 3
      a     b     c
  <dbl> <dbl> <dbl>
1     0     1     1
2    NA    NA     6
3     0     6     1
4     4     4    NA
5     0     0     0