从NA最少的列中删除包含NA的行

时间:2019-04-24 02:10:11

标签: r dplyr tidyr

我有一个数据框,最终将其转换为xts对象。第一列包含日期数据,而所有其他列均包含数字数据。但是,并非所有数字列都具有相同数量的值/相同的长度。某些列比其他列包含更多的行。

我想通过删除具有最少数量的NA的列中包含NA的行来过滤我的数据帧,但对于我选择的所有其他列,仍然保留包含NA的行。例如,下面的grpA列具有最少数量的NA。我想删除包含NA的数据帧的前2行,但无论它们是什么,都保留grpB中的值。

我所拥有的:

Date        grpA    grpB
2007-11-06  NA      NA
2007-11-07  NA      NA
2007-11-09  1.66    NA
2007-11-12  1.64    NA
2007-11-13  1.61    1.28
2007-11-14  1.60    1.30
2007-11-15  1.57    1.27
2007-11-16  1.56    1.25
2007-11-19  1.55    1.25
2007-11-20  1.55    1.25
2007-11-21  1.52    1.22
2007-11-22  1.50    1.21
2007-11-23  1.51    1.21
2007-11-26  1.52    1.25
2007-11-27  1.50    1.25
2007-11-28  1.50    1.23
2007-11-29  1.52    1.24
2007-11-30  1.56    1.25
2007-12-03  1.56    1.22
2007-12-04  1.56    1.23

我想要什么:

Date        grpA    grpB
2007-11-09  1.66    NA
2007-11-12  1.64    NA
2007-11-13  1.61    1.28
2007-11-14  1.60    1.30
2007-11-15  1.57    1.27
2007-11-16  1.56    1.25
2007-11-19  1.55    1.25
2007-11-20  1.55    1.25
2007-11-21  1.52    1.22
2007-11-22  1.50    1.21
2007-11-23  1.51    1.21
2007-11-26  1.52    1.25
2007-11-27  1.50    1.25
2007-11-28  1.50    1.23
2007-11-29  1.52    1.24
2007-11-30  1.56    1.25
2007-12-03  1.56    1.22
2007-12-04  1.56    1.23

数据帧的可重现示例如下:

df <- data.frame(Date = structure(c(1194307200, 1194393600, 1194566400, 
                                    1194825600, 1194912000, 1194998400, 1195084800, 1195171200, 1195430400, 
                                    1195516800, 1195603200, 1195689600, 1195776000, 1196035200, 1196121600, 
                                    1196208000, 1196294400, 1196380800, 1196640000, 1196726400), class = c("POSIXct", 
                                                                                                           "POSIXt"), tzone = "UTC"), 
                 grpA = c(NA, NA, 1.66, 1.64, 1.61, 1.6, 1.57, 1.56, 1.55, 1.55, 1.52, 1.5, 1.51, 1.52, 1.5, 1.5, 1.52, 1.56, 1.56, 1.56), 
                 grpB = c(NA, NA, NA, NA, 1.28, 1.3, 1.27, 1.25, 1.25, 1.25, 1.22, 1.21, 1.21, 1.25, 1.25, 1.23, 1.24, 1.25, 1.22, 1.23))

我已经尝试过drop_na包中的tidyr函数,并且可以正常工作:

df2 <- drop_na(df, grpA)

但是,我将在Shiny App中使用上述过滤器,并且我事先不知道用户会选择哪些列中包含NA的行数最少。

我已经尝试了以下方法来确定其中包含NA的行数最少的列,但是它为我提供了非NA行的数目,而不是列名:

max(colSums(!is.na(df[-1])))

我尝试使用以下方法提取列的名称,但遇到错误:

colnames(df)[which(colSums(!is.na(df[-1]))) == max(colSums(!is.na(df[-1])))]

我认为这是一项简单的任务,但它变得相当复杂。我需要能够在闪亮的反应式表达中使用答案。

非常感谢!

1 个答案:

答案 0 :(得分:4)

我们首先可以找到数量最少为NA的列名称,然后从该列中删除NA行。

col <- names(which.min(colSums(is.na(df[-1]))))
df[!is.na(df[col]), ]


#         Date grpA grpB
#3  2007-11-09 1.66   NA
#4  2007-11-12 1.64   NA
#5  2007-11-13 1.61 1.28
#6  2007-11-14 1.60 1.30
#7  2007-11-15 1.57 1.27
#8  2007-11-16 1.56 1.25
#9  2007-11-19 1.55 1.25
#10 2007-11-20 1.55 1.25
#11 2007-11-21 1.52 1.22
#12 2007-11-22 1.50 1.21
#13 2007-11-23 1.51 1.21
#14 2007-11-26 1.52 1.25
#15 2007-11-27 1.50 1.25
#16 2007-11-28 1.50 1.23
#17 2007-11-29 1.52 1.24
#18 2007-11-30 1.56 1.25
#19 2007-12-03 1.56 1.22
#20 2007-12-04 1.56 1.23

也可以单行完成,而无需创建其他变量

df[!is.na(df[names(which.min(colSums(is.na(df[-1]))))]), ]

使用相同的逻辑,dplyr方法可能会使用filter_at

library(dplyr)

df %>%
   filter_at(df %>%
   summarise_at(-1, ~sum(is.na(.))) %>%
   which.min %>% names, ~!is.na(.))

或与tidyr::drop_na

一起使用
tidyr::drop_na(df, df %>%
                  summarise_at(-1, ~sum(is.na(.))) %>%
                  which.min %>% names)