如何按列删除“NA”值的所有单元格

时间:2017-07-28 14:52:03

标签: r

这个问题不重复,因为我的data.frame 在所有列中的NA都不相同,因此该问题中提到的解决方案不起作用。

我有一个data.frame,其中包含很多NA个值,我想删除所有具有NA值的单元格(重要:不是行或列,单元格)。原件看起来像这样:

A  B
1  NA
NA 2
2  NA
NA NA
NA NA
NA 4
3  5

期望的结果如下所示:

A  B
1  2
2  4 
3  5

列数必须保持不变,但如果值保留在同一行上则无关紧要。他们可以向上移动。

我可以想象一个可以删除条件为NA的所有单元格(可能是应用)并获得结果。或者也许是简单的排序?

感谢。

更新

A   B   C
1       3
    2   
4       3

    1   2

3       5
        4
    9   
7       1

2 个答案:

答案 0 :(得分:1)

您可以尝试,根据@ UweBlock的数据和您更新的问题。

dat=as.data.frame(na.omit(apply(dat,2,function (x) x[order(is.na(x))])))

dat
  A B C
1 1 2 3
2 4 1 3
3 3 9 2

答案 1 :(得分:1)

OP要求按列删除NA,但已指出每列中可能有不同数量的NA。

这可以通过两个步骤使用data.table来解决:

library(data.table)
# step 1: coerce to data.table in place, move NAs to the bottom of each column, 
# maintain the original order of non-NA values
result <- data.table(DF)[, lapply(.SD, function(x) x[order(is.na(x))])]
     A  B  C
 1:  1  2  3
 2:  4  1  3
 3:  3  9  2
 4:  7 NA  5
 5: NA NA  4
 6: NA NA  1
 7: NA NA NA
 8: NA NA NA
 9: NA NA NA
10: NA NA NA
# step 2: trim result
# either using Reduce
result[!result[, Reduce(`&`, lapply(.SD, is.na))]]

# or using zoo::na.trim()
zoo::na.trim(result, is.na = "all")
    A  B C
1:  1  2 3
2:  4  1 3
3:  3  9 2
4:  7 NA 5
5: NA NA 4
6: NA NA 1

因此,不可避免地会在每个列的末尾有一些NA因为data.frame中的所有列都具有相同的长度。

或者,也可以使用is.na参数na.trim()仅保留完整的行:

zoo::na.trim(result, is.na = "any")
   A B C
1: 1 2 3
2: 4 1 3
3: 3 9 2

另一种解决方案

如前所述,data.framecbind()期望所有列向量具有相同的长度。这是一个没有data.table的替代解决方案,该解决方案使用cbind.fill()包中的rowr函数,该函数将具有fill值的向量填充到相同的长度:

setNames(do.call(function(...) rowr::cbind.fill(..., fill = NA), lapply(DF, na.omit)),
         colnames(DF))
   A  B C
1  1  2 3
2  4  1 3
3  3  9 2
4  7 NA 5
5 NA NA 4
6 NA NA 1

数据

由更新中的OP提供:

DF <- structure(list(A = c(1L, NA, 4L, NA, NA, NA, 3L, NA, NA, 7L), 
    B = c(NA, 2L, NA, NA, 1L, NA, NA, NA, 9L, NA), C = c(3L, 
    NA, 3L, NA, 2L, NA, 5L, 4L, NA, 1L)), .Names = c("A", "B", 
"C"), row.names = c(NA, -10L), class = "data.frame")