逻辑比较包含 NA 的数据框中的列?

Logically compare columns in a data frame that contain NA?

R 相对较新,我今天发现 1 == NA returns NA 而不是预期的 FALSE.

我广泛地查看了 this question 以寻求帮助,这很好,但是面向向量并且我正在使用数据帧。

这是我正在使用的简化示例:

library(tidyverse)

df_example <- expand_grid(shpmt = c(1:3), stoptype = c("P", "D"))
df_example$metgoal.ref <- c(1,NA,0,0,1,NA)
df_example$metgoal.tri <- c(1,NA,0,1,NA,1)

> df_example

# A tibble: 6 x 4
  shpmt stoptype metgoal.ref metgoal.tri
  <int> <chr>          <dbl>       <dbl>
1     1 P                  1           1
2     1 D                 NA          NA
3     2 P                  0           0
4     2 D                  0           1
5     3 P                  1          NA
6     3 D                 NA           1

我的目标是查看 .ref 和 .tri 不同的每个实例,包括 NA。我首先尝试了一个简单的(我认为)不等式:

> filter(df_example, metgoal.ref != metgoal.tri)  #Returns only inequalities without NAs.
# A tibble: 1 x 4
  shpmt stoptype metgoal.ref metgoal.tri
  <int> <chr>          <dbl>       <dbl>
1     2 D                  0           1

最初,我没有意识到我错过了 NA,但我现在知道我可以使用 is.na() 找到它们,这很重要,因为这种结构让我可以找到NA 在两列的 中(这就是为什么 that question 对它的向量帮助不大)。有点不利的是,它还给出了 两个 列都是 NA 的实例(我主要关心它们的不同):

> filter(df_example, is.na(metgoal.ref != metgoal.tri))

# A tibble: 3 x 4
  shpmt stoptype metgoal.ref metgoal.tri
  <int> <chr>          <dbl>       <dbl>
1     1 D                 NA          NA   #Not ideal -- I want only columns that disagree.
2     3 P                  1          NA
3     3 D                 NA           1

如果我把这两个结构放在一起,我可以得到我想要的,除了第 1 行的双 NA 列:

> filter(df_example, is.na(metgoal.ref != metgoal.tri) | (metgoal.ref != metgoal.tri))

# A tibble: 4 x 4
  shpmt stoptype metgoal.ref metgoal.tri
  <int> <chr>          <dbl>       <dbl>
1     1 D                 NA          NA   #Still not ideal
2     2 D                  0           1
3     3 P                  1          NA
4     3 D                 NA           1

但对于我认为只是一个不等式的输入和维护工作量很大,而且我还有许多其他列集要做,而且我还有其他条件要添加:

> filter(df_example, (is.na(metgoal.ref != metgoal.tri) | (metgoal.ref != metgoal.tri)) & stoptype == "D")  

#Added another condition, increasing complexity.

# A tibble: 3 x 4
  shpmt stoptype metgoal.ref metgoal.tri
  <int> <chr>          <dbl>       <dbl>
1     1 D                 NA          NA
2     2 D                  0           1
3     3 D                 NA           1

我认为 identical() 函数可能会有用,但如果有用,那我用错了,需要帮助:

> filter(df_example, !identical(df_example$metgoal.ref, df_example$metgoal.tri))  

#This does not work at all -- probably using it wrong.

# A tibble: 6 x 4
  shpmt stoptype metgoal.ref metgoal.tri
  <int> <chr>          <dbl>       <dbl>
1     1 P                  1           1
2     1 D                 NA          NA
3     2 P                  0           0
4     2 D                  0           1
5     3 P                  1          NA
6     3 D                 NA           1

我看到的针对这种情况的其他策略是将 NA 替换为可以按照我最初尝试的方式测试不平等的东西:

df_example2 <- df_example %>% 
  replace_na(list(metgoal.ref = 9, metgoal.tri = 9))  #Arbitrarily choosing 9 as replacement value

filter(df_example2, metgoal.ref != metgoal.tri)

# A tibble: 3 x 4
  shpmt stoptype metgoal.ref metgoal.tri
  <int> <chr>          <dbl>       <dbl>
1     2 D                  0           1
2     3 P                  1           9
3     3 D                  9           1

我怀疑最后一个解决方案是我可能得到的最好的解决方案,但我希望在 metgoal.* 列上进行聚合和汇总统计,并且它们应该保留可能是合适的NA。我可以在转换它之前返回到 df_example,但我牢记有更好的解决方案,它会改进我的学习。

提前感谢您提出的任何建议。

这似乎有效。请告诉我您的想法!

mapply(identical, df_example$metgoal.ref, df_example$metgoal.tri)

然后你可以用它来过滤你的原始数据。我添加 ! 是因为您对这些字段不相同的行感兴趣。

整理后可能看起来像这样

filter(df_example, !mapply(identical, df_example$metgoal.ref, df_example$metgoal.tri))

或在基础

df_example[!mapply(identical, df_example$metgoal.ref, df_example$metgoal.tri),]