【问题标题】:How to disregard all rows after and including a whole row of NAs?如何忽略并包括一整行 NA 之后的所有行?
【发布时间】:2018-03-15 06:45:30
【问题描述】:

我之所以问这个问题是因为我在一个实验室工作,我的同事在其中对 Microsoft-Excel 电子表格进行一些分析。我有时会在电子表格列的底部找到一个 Microsoft Excel 分析表。为了我的目的,我可以毫不费力地将这些电子表格读入 R。模式是电子表格中总会有至少一整行空单元格或 NA,因此任何跟随并包括整行 NA 的内容都不应解释为 R,因为它不是原始数据。

想象一个像这样的简单数字数据框 (df)。

我添加了一个“#”来显示我想要排除的行。

    x  y  z  comments
1   8  5  4     <NA>
2   3  6  5     <NA>
3   7  7  3     <NA>
4   9  3 10     Well
5   4 NA  6     <NA>
6   5  9  8     <NA>
7   1  4  7     Yeah
8  10  2  2     <NA>
9   2 10  9     <NA>
10  6  1  1 I guess 
11 NA NA NA     <NA> # whole row of NAs/empty cells. # exclude
12  8  3  4  Summary # exclude 
13  1  1  2     <NA> # exclude
14 NA NA NA     <NA> # exclude 

如果我只是排除所有包含 NA 的行,我会丢失很多信息:

print(na.omit(df))
   x y  z comments
4  9 3 10     Well
7  1 4  7     Yeah
10 6 1  1 I guess 

我不想因为 cmets 可能不完整而忽略它们。

但是看到整行 NA,在本例中出现在第 11 行信号中以排除以下行,因此我想要包含的电子表格包含这么多:

    x  y  z comments
1   8  5  4     <NA>
2   3  6  5     <NA>
3   7  7  3     <NA>
4   9  3 10     Well
5   4 NA  6     <NA>
6   5  9  8     <NA>
7   1  4  7     Yeah
8  10  2  2     <NA>
9   2 10  9     <NA>
10  6  1  1 I guess 

这里只是模拟数据,但我必须经常这样做,所以这是我向您展示的模拟数据:

structure(list(x = c(8, 3, 7, 9, 4, 5, 1, 10, 2, 6, NA, 8, 1, 
NA), y = c(5, 6, 7, 3, NA, 9, 4, 2, 10, 1, NA, 3, 1, NA), z = c(4, 
5, 3, 10, 6, 8, 7, 2, 9, 1, NA, 4, 2, NA), comments = c(NA, NA, 
NA, "Well", NA, NA, "Yeah", NA, NA, "I guess ", NA, "Summary", 
NA, NA)), .Names = c("x", "y", "z", "comments"), row.names = c(NA, 
14L), class = "data.frame")

如何在任何类型的数据框中排除所有行,包括并跟随一整行 NA(空单元格)?

谢谢。

【问题讨论】:

    标签: r


    【解决方案1】:

    我们可以使用Reduce&amp; 来创建用于子集数据集的逻辑向量

    df[!cumsum(Reduce(`&`, lapply(df, is.na))),]
    #   x  y  z comments
    #1   8  5  4     <NA>
    #2   3  6  5     <NA>
    #3   7  7  3     <NA>
    #4   9  3 10     Well
    #5   4 NA  6     <NA>
    #6   5  9  8     <NA>
    #7   1  4  7     Yeah
    #8  10  2  2     <NA>
    #9   2 10  9     <NA>
    #10  6  1  1 I guess 
    

    【讨论】:

    • 我正想问你“&”是做什么的?谢谢你的解释。
    • 我喜欢这种单线解决方案!
    • 我选择了这个解决方案,因为我喜欢它不涉及在子集中创建任何新变量的方式。另一种解决方案在计算机科学方面非常合乎逻辑,但是这个解决方案强大地使用了包装函数。您是如何想到这一点的,您能详细说明一下吗?
    • @xyz123 谢谢,lapply(df, is.na) 的输出是逻辑向量的list,检查每列值是否为 NA。因此,TRUE 将对应于 NA,FALSE 将对应于非 NA。通过使用Reduce&amp;,通过比较每个list 的对应元素,将其简化为单个逻辑向量。实际上,如果一行全部为 NA,这将返回 TRUE,而所有其他行都返回 FALSE。用cumsum 包裹将其转换为数字向量cumsum(Reduce('&amp;', lapply(df, is.na)))# [1] 0 0 0 0 0 0 0 0 0 0 1 1 1 2
    • @xyz123 请注意,第一行之前的所有元素都是 NA,其他元素都大于 0。通过否定 (!),我们将 0 转换为 TRUE,其他所有元素都转换为 FALSE . !cumsum(Reduce(&, lapply(df, is.na)))# [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE FALSE FALSE FALSE FALSE 用于对行进行子集
    【解决方案2】:

    一个基本的 R 选项是首先计算 NA 值的所有行总和,然后检查哪些总和等于列数。然后,找到具有所有 NA 值的 第一 行,然后对数据框进行子集化,从头到尾取所有行,直到减去所有 NA 值的第一行。

    # TRUE if a given row has NA in every column
    x <- rowSums(is.na(df)) != ncol(df)
    
    # the row immediately before the FIRST all NA row, or the final row,
    # if no rows are all NA
    last_row <- ifelse(length(which(!x)) == 0, nrow(df), which(!x)[1] - 1)
    
    # subset the data frame
    df[1:last_row, ]
    

    Demo

    我更新以涵盖数据框中没有行具有所有 NA 值的边缘情况。在这种情况下,子集应该只生成整个原始数据帧。

    【讨论】:

    • 我认为 OP 还希望排除晚于所有 NA 的行的行。
    • 这只会删除所有 NA 行,而不是后面的行。你能更新你的答案吗?
    • dat[1:min(which(!rowSums(is.na(dat)) != ncol(dat))) - 1, ] 可以解决我的问题。提交了修改 Tim!
    • 感谢您的帮助。
    猜你喜欢
    • 2015-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-30
    • 1970-01-01
    • 2018-12-16
    • 2016-02-21
    • 1970-01-01
    相关资源
    最近更新 更多