【问题标题】:How can I remove all cells with "NA" value by columns如何按列删除所有具有“NA”值的单元格
【发布时间】:2018-01-04 16:51:56
【问题描述】:

这个问题不是重复的,因为我的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 的所有单元格(可能是 apply)并得到结果。或者也许是一个简单的排序?

谢谢。

更新:

A   B   C
1       3
    2   
4       3

    1   2

3       5
        4
    9   
7       1

【问题讨论】:

  • 试试data.frame(lapply(df1, na.omit))
  • 每列的 NA 数是否相同?如果没有,您将遇到问题,因为 data.frames 需要相同长度的列。您可以只使用普通列表。
  • 不,有很多 NA 和很少的实际值,它们不是同一个数字。

标签: r


【解决方案1】:

OP 已请求按列删除NAs,但指出每列中可能有不同数量的 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

因此,每个列的末尾不可避免地会有一些NAs,因为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.frames 和 cbind() 期望所有列向量具有相同的长度。这是一个没有data.table 的替代解决方案,它使用rowr 包中的cbind.fill() 函数,该函数用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")

【讨论】:

    【解决方案2】:

    您可以尝试,基于@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
    

    【讨论】:

    • 感谢您的帮助。使用 this 后我得到一个空变量/文件。是否需要将初始 dat 转换为任何特定的(data.frame、list、matrix)?或者我在这里错过了什么。
    • @user413734 我假设您正在使用 data.frame
    • 是的,我愿意。运行您的代码后,我在 Rstudio 的环境面板中得到 chr[0, 1:255] 。我的原始数据中有 255 列。之前的所有转换都显示相同数量的列和行。似乎这段代码摆脱了 NA 所在的所有行以及列中所有出现的 NA 。任何我可以尝试的想法。感谢您的帮助。
    • 我刚刚使用更新的示例文件尝试了您的代码,尽管它原则上做了预期的操作,但它忽略了 A 行中的值 7 和 C 行中的 5、4、1。我相信它必须是相同数量的值 (3)。但对我来说,这些行是否保留在原始文件中并不重要。
    • @UweBlock 阅读更新后的问题并编辑我的答案~谢谢你的帮助~ :)
    猜你喜欢
    • 2022-01-11
    • 2021-10-16
    • 2022-01-16
    • 2018-10-21
    • 2014-11-13
    • 2022-06-13
    • 2019-01-06
    • 2019-11-14
    • 1970-01-01
    相关资源
    最近更新 更多