6.5 NA 存在时进行向量或因子比较
6.5.1 问题
你想在 NA
存在的情况下比较比较两个向量或因子并返回 TRUE
或 FALSE
(而不是 NA
)。
6.5.2 方案
假设你有一个两列(包含布尔值)的列表:
df <- data.frame(a = c(TRUE, TRUE, TRUE, FALSE, FALSE, FALSE,
NA, NA, NA), b = c(TRUE, FALSE, NA, TRUE, FALSE, NA,
TRUE, FALSE, NA))
df
#> a b
#> 1 TRUE TRUE
#> 2 TRUE FALSE
#> 3 TRUE NA
#> 4 FALSE TRUE
#> 5 FALSE FALSE
#> 6 FALSE NA
#> 7 NA TRUE
#> 8 NA FALSE
#> 9 NA NA
通常情况下,当你比较两个包含NA
值的向量或因子时,原始值是NA
,结果也将有NA
。根据你的目的,这或许是是你想要的结果。
df$a == df$b
#> [1] TRUE FALSE NA FALSE TRUE NA NA NA
#> [9] NA
# 同样的比较,但是可以生成列表的另一列:
data.frame(df, isSame = (df$a == df$b))
#> a b isSame
#> 1 TRUE TRUE TRUE
#> 2 TRUE FALSE FALSE
#> 3 TRUE NA NA
#> 4 FALSE TRUE FALSE
#> 5 FALSE FALSE TRUE
#> 6 FALSE NA NA
#> 7 NA TRUE NA
#> 8 NA FALSE NA
#> 9 NA NA NA
6.5.2.1 可以与 NA 相比的函数
这个比较函数会把NA
赋予另一个值。如果一个向量的两项都是 NA
,则返回 TRUE
;如果其中一个是 NA
,则返回 FALSE
;所有其他比较(无NA
之间)的方式是一样的。
# 这个函数将会返回 TRUE,当两个元素相同(包括两个
# NA),其他情况返回 FALSE
compareNA <- function(v1, v2) {
same <- (v1 == v2) | (is.na(v1) & is.na(v2))
same[is.na(same)] <- FALSE
return(same)
}
6.5.2.2 使用该函数的例子
比较两个布尔向量:
compareNA(df$a, df$b)
#> [1] TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE
#> [9] TRUE
# 同样的比较,生成另一列
data.frame(df, isSame = compareNA(df$a, df$b))
#> a b isSame
#> 1 TRUE TRUE TRUE
#> 2 TRUE FALSE FALSE
#> 3 TRUE NA FALSE
#> 4 FALSE TRUE FALSE
#> 5 FALSE FALSE TRUE
#> 6 FALSE NA FALSE
#> 7 NA TRUE FALSE
#> 8 NA FALSE FALSE
#> 9 NA NA TRUE
它也能用于因子,即使因子的水平处于不同的次序:
# 创建一个含因子的列表
df1 <- data.frame(a = factor(c("x", "x", "x", "y", "y",
"y", NA, NA, NA)), b = factor(c("x", "y", NA, "x", "y",
NA, "x", "y", NA)))
# 比较
data.frame(df1, isSame = compareNA(df1$a, df1$b))
#> a b isSame
#> 1 x x TRUE
#> 2 x y FALSE
#> 3 x <NA> FALSE
#> 4 y x FALSE
#> 5 y y TRUE
#> 6 y <NA> FALSE
#> 7 <NA> x FALSE
#> 8 <NA> y FALSE
#> 9 <NA> <NA> TRUE
# 也能用于因子,即使因子的水平处于不同的次序
df1$b <- factor(df1$b, levels = c("y", "x"))
data.frame(df1, isSame = compareNA(df1$a, df1$b))
#> a b isSame
#> 1 x x TRUE
#> 2 x y FALSE
#> 3 x <NA> FALSE
#> 4 y x FALSE
#> 5 y y TRUE
#> 6 y <NA> FALSE
#> 7 <NA> x FALSE
#> 8 <NA> y FALSE
#> 9 <NA> <NA> TRUE