计算具有至少一个NA的数据帧中的行数的最快方法

时间:2016-11-21 20:30:15

标签: r

当您拥有数据集时,通常您希望看到数据集中至少有一个NA(或缺失值)的行的比例。

在R中,我所做的是以下内容:

TR = apply(my_data,1,anyNA)
sum(TR)/length(TR)

但我发现如果我的数据集有100万行,则需要一些时间。我想知道在R中是否有最快的方法来实现这个目标?

1 个答案:

答案 0 :(得分:1)

在开始之前,请注意这里的代码都不是我的。我只是对评论中的代码着迷,并想知道哪一个真的表现得最好。

我怀疑有些时候正忙于将数据帧转换为applyrowSums的矩阵,所以我也完成了矩阵上的大多数解决方案来说明通过在数据框上运行这些解决方案来应用惩罚。

# Make a data frame of 10,000 rows and set random values to NA

library(dplyr)
set.seed(13)
MT <- mtcars[sample(1:nrow(mtcars), size = 10000, replace = TRUE), ]

MT <- lapply(MT,
       function(x) { x[sample(1:length(x), size = 100)] <- NA; x }) %>%
  bind_cols()

MT_mat <- as.matrix(MT)

library(microbenchmark)
microbenchmark(
  apply(MT,1,anyNA),
  apply(MT_mat,1,anyNA),  # apply on a matrix
  row_sum = rowSums(is.na(MT)) > 0,
  row_sum_mat = rowSums(is.na(MT_mat)), # rowSums on a matrix
  reduce = Reduce('|', lapply(MT, is.na)) ,
  complete_case = !complete.cases(MT),
  complete_case_mat = !complete.cases(MT_mat) # complete.cases on a matrix
)

Unit: microseconds
                    expr       min        lq       mean     median         uq       max neval  cld
     apply(MT, 1, anyNA) 12126.013 13422.747 14930.6022 13927.5695 14589.1320 60958.791   100    d
 apply(MT_mat, 1, anyNA) 11662.390 12546.674 14758.1266 13336.6785 14083.7225 66075.346   100    d
                 row_sum  1541.594  1581.768  2233.1150  1617.3985  1647.8955 49114.588   100  bc 
             row_sum_mat   579.161   589.131   707.3710   618.7490   627.5465  3235.089   100 a c 
                  reduce  2028.969  2051.696  2252.8679  2084.8320  2102.8670  4271.127   100   c 
           complete_case   321.984   330.195   346.8692   342.5115   351.3090   436.057   100 a   
       complete_case_mat   348.083   358.640   384.1671   379.0205   406.8790   503.503   100 ab 

#* Verify that they all return the same result
MT$apply <- apply(MT, 1, anyNA)
MT$apply_mat <- apply(MT_mat, 1, anyNA)
MT$row_sum <- rowSums(is.na(MT)) > 0
MT$row_sum_mat <- rowSums(is.na(MT_mat)) > 0
MT$reduce <- Reduce('|', lapply(MT, is.na)) 
MT$complete_case <- !complete.cases(MT)
MT$complete_case_mat <- !complete.cases(MT_mat)

all(MT$apply == MT$apply_mat)
all(MT$apply == MT$row_sum)
all(MT$apply == MT$row_sum_mat)
all(MT$apply == MT$reduce)
all(MT$apply == MT$complete_case)
all(MT$apply == MT$complete_case_mat)

complete.cases似乎是明显的赢家,适用于数据框架和矩阵。事实证明,complete.cases调用了一个C例程,这可能占其速度的很大一部分。查看rowSumsapplyReduce会显示R代码。

applyrowSums可能与rowSums针对特定任务进行优化可能有什么关系。 rowSums知道它会返回一个数字,apply没有这样的保证。我怀疑这是否存在所有差异 - 我主要在猜测。

我无法开始告诉你Reduce是如何运作的。