对R数据框进行子集操作导致出现神秘的NA行

78

我遇到了一个我认为是bug的问题。虽然不是个大问题,但我很好奇是否还有其他人遇到过这个问题。不幸的是,我的数据是机密的,所以我必须举一个例子,但它可能并不会太有帮助。

在对我的数据进行子集操作时,偶尔会出现神秘的NA行,而这些行在我的原始数据框中是不存在的。即使是行名称也是NA。例如:

example <- data.frame("var1"=c("A", "B", "A"), "var2"=c("X", "Y", "Z"))
example

  var1 var2
1    A    X
2    B    Y
3    A    Z

然后我运行:

example[example$var1=="A",]

  var1 var2
1    A    X
3    A    Z
NA<NA> <NA>

当然,上面的例子实际上并没有给你这个神秘的NA行;我在这里添加它是为了说明我在处理数据时遇到的问题。

也许这与我使用Google的read.xlsx包导入原始数据集,然后执行宽变长重塑再进行子集化有关。

谢谢


9
如果没有看到你的数据,很难确定问题,但几乎肯定是因为你的一些索引大于数据中的行数。例如,使用上面提供的数据框尝试 example[c(1, 2, 4),]example[c(TRUE, TRUE, FALSE, TRUE),]。检查用于子集化行的向量的长度(如果是布尔型)和最大值(如果是数字型)。 - David Robinson
8
...并且/或者你的指标本身有缺失值(NA)。 - joran
1
正如David所说,我们需要了解更多...但查看str(yourdata)summary(yourdata)将会对你有很大帮助。我有一种感觉你的var列中至少有一个NA。测试一下:example <- data.frame("var1"=c("A", "B", "A", NA), "var2"=c("Q", "X", "Y", "Z")); example[example$var=='A',] - Justin
5
如果你的代码类似于这个例子(形式为 d[d$v == x, ]),那么问题几乎肯定是列中存在缺失值(NA)。 - David Robinson
11
回答了!我的索引列中有NA值。我不敢相信我以前从未遇到过这种情况。有趣的是,当你在索引列中遇到NA时,R会“审查”其他列中的数据(甚至是行名!)。我是StackOverflow上的新手,所以需要一分钟时间来弄清如何标记此问题已解决。 - chrisg
显示剩余2条评论
7个回答

79

将条件用 which 包裹:

df[which(df$number1 < df$number2), ]

它的工作原理:

它返回符合条件(即TRUE)的行号,并根据这些行对数据框进行子集筛选。

假设有以下情况:

which(df$number1 < df$number2)

返回行号 1, 2, 3, 45

因此,写入:

df[which(df$number1 < df$number2), ]

与写作下面的代码是一样的:

df[c(1, 2, 3, 4, 5), ]

或者更简单的版本是:

df[1:5, ]

38

我发现这个问题已经被原帖的作者回答过了,但是由于他的评论被深深埋藏在评论区中,所以我试图解决这个问题(至少对于我的数据而言,我的数据也出现了类似的情况)。

首先,这里是一些样本数据:

> df <- data.frame(name = LETTERS[1:10], number1 = 1:10, number2 = c(10:3, NA, NA))
> df
   name number1 number2
1     A       1      10
2     B       2       9
3     C       3       8
4     D       4       7
5     E       5       6
6     F       6       5
7     G       7       4
8     H       8       3
9     I       9      NA
10    J      10      NA

现在来介绍一个简单的筛选器:

> df[df$number1 < df$number2, ]
     name number1 number2
1       A       1      10
2       B       2       9
3       C       3       8
4       D       4       7
5       E       5       6
NA   <NA>      NA      NA
NA.1 <NA>      NA      NA

这里的问题在于第三列存在NA,导致R将整行重写为NA。尽管如此,数据框的维度得以保留。以下是我的修复方法,需要知道哪一列包含NA

> df[df$number1 < df$number2 & !is.na(df$number2), ]
  name number1 number2
1    A       1      10
2    B       2       9
3    C       3       8
4    D       4       7
5    E       5       6

1
这是我一直处理这个问题的方式,但是否有一种方法将!is.na和<组合成一个命令? - Nova
@Nova,我不这么认为,因为它们是两个不同的逻辑测试。虽然我很乐意被证明是错误的。 - Waldir Leoncio
5
上面已经回答过,which() 函数可能适合这个角色,但它还不够令人满意。我强烈认为这是一个缺陷,在我看来这很不幸,因为这个“特性”(NA 选择混乱)不会被修复。 - Chris
这对于理解为什么这种情况总是发生在我身上非常有帮助。我同意其他人的看法,认为这是一个错误。希望 R 核心团队中的某个人也能够认同。 - colin
@colin,我不确定这是否是一个错误,现在我只会将其称为R背后的设计哲学不默认丢弃NA值的结果。相反,R通常会执行“哦,在这个向量上有一个NA,所以我要将整个向量显示为NA,因为我不知道NA的值代表什么以及它如何影响向量的其余部分”。例如,取mean(c(1, 3, NA))。R将打印NA,因为它不知道第三个值是什么,因此无法告诉您平均值是多少。如果用户想要删除NA,则必须显式设置na.rm=TRUE - Waldir Leoncio

14

当我使用类似于您发布的代码时,遇到了相同的问题。使用函数subset()

subset(example,example$var1=="A")

相反,NA行被排除在外。


6
这很有帮助,但请注意在非交互式的R会话中使用subset可能存在潜在问题。根据该函数的帮助页面,“这是一个方便的函数,旨在供交互式使用。对于编程,最好使用标准的子集函数如[, 特别是 subset 参数的非标准评估可能会产生意外后果。” - Waldir Leoncio

6
使用dplyr:
library(dplyr)
filter(df, number1 < number2)

确实,该库不会受到NA缺陷的影响。 - Chris

5

我发现使用 %in$ 而不是 == 可以解决这个问题,虽然我仍然想知道为什么。 例如,不要用: df[df$num == 1,] 而用: df[df$num %in% c(1),] 就可以解决。


2020年,我在使用R 3.6.3进行编程,并使用df[df$col1 %in% c("Whatever"), ]获取一个没有空的NA索引行的表格。但是,如果像这样使用等号:df[df$col1 == "Whatever", ],就会出现初始问题。筛选后的表格中存在带有NA索引的空行。 - Corina Roca

1
   > example <- data.frame("var1"=c("A", NA, "A"), "var2"=c("X", "Y", "Z"))
    > example
      var1 var2
    1    A    X
    2 <NA>    Y
    3    A    Z
    > example[example$var1=="A",]
       var1 var2
    1     A    X
    NA <NA> <NA>
    3     A    Z

也许这就是您期望的结果...尝试使用在条件之前使用 which 条件以避免 NA 值

  example[which(example$var1=="A"),]
      var1 var2
    1    A    X
    3    A    Z

0

另一个可能的原因是您错误地设置了条件,例如检查因子列是否等于不在其级别之间的值。这困扰了我一段时间。


亲爱的投票者,请解释一下你们投反对票的原因,谢谢! - Jan Šimbera

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接