【问题标题】:Comparing Column Values With NA将列值与 NA 进行比较
【发布时间】:2019-12-27 03:25:45
【问题描述】:

下面的输入表包含NA 的数据点。我理解在R 中,当一个值与NA 进行比较时,它会导致输出为NA

还有办法让我仍然可以使用ifelse() 进行比较,并确保正在比较的值之一是NA,那么它仍然会提供输出,就好像NA 是一个字符/字符串一样比较?

输入原始数据

data <- read.table(header = TRUE, text = "A B
                    NA  TEST
                   TEST TEST
                   Abaxasdas Test")

输入数据表

 A       B
<NA>   TEST
TEST   TEST
Abaxasdas Test

代码

data$Output <- ifelse(as.character(data$A) == as.character(data$B), "YES", "NO")

输出

 A    B   Output
<NA> TEST  <NA>
TEST TEST  YES
Abaxasdas Test NO

预期输出

 A    B   Output
<NA> TEST  NO
TEST TEST  YES
Abaxasdas Test NO

【问题讨论】:

  • 当 A 和 B 都是 NA 时,期望的输出是什么?
  • @JamesMartherus - True。不确定我是否在那里短视,但对于我使用的数据,我使用的两个列值都是 NA 意味着两者都是空白的,这对我来说是 TRUE

标签: r dataframe


【解决方案1】:

为了简单起见,我们先用stringsAsFactors=FALSE重新定义数据框:

df <- read.table(header = TRUE, text = "A B
                     NA  TEST
                    TEST TEST
                    Abaxasdas Test", stringsAsFactors=FALSE)

您可以使用identicalNA-安全的方式比较列:

mapply(identical, df$A, df$B)

用“YES”和“NO”而不是TRUEFALSE获得输出:

ifelse(mapply(identical, df$A, df$B), "YES", "NO")

输出

> df$Output <- ifelse(mapply(identical, df$A, df$B), "YES", "NO")
> df
          A    B Output
1      <NA> TEST     NO
2      TEST TEST    YES
3 Abaxasdas Test     NO

另一种选择

正如 joran 在评论中建议的那样,将 NA 替换为一个值会使比较更容易。如果您不想更改数据框中的值(但也许您应该这样做!),您可以使用这样的辅助函数:

rna <- function(x) replace(x, is.na(x), "")
ifelse(rna(df$A)==rna(df$B), "YES", "NO")

【讨论】:

  • @joran - 你和@JamesMartherus 让我思考。不确定我是否在那里短视,但对于我使用的数据,我使用的两个列值都是 NA 意味着两者都是空白的,这对我来说是 TRUE
  • @IceCreamToucan 感谢您指出这一点。我认为避免使用 data 之类的名称是一个好习惯,它是包 utils 中的一个函数。但是话又说回来,当然,我不应该使用df,它是stats(F 分布的密度函数)中的一个函数。所以可能很难完全避免名称冲突。
  • @joran - 同意。但是我不是通过将NA 替换为non-NA 来比较两个相同的值吗?您看到的是与编码标准相关的问题吗?
  • identical 的解决方案也适用于两个 NA:identical(NA, NA) 的计算结果为 TRUE。我不确定它在技术上这样工作是否好,我认为,您不知道两个NA 是否相同,因为实际值未知。但这是一个不同的问题。
  • @joran 我有点同意,但话又说回来,这正是 OP 中要求的那种技术比较。对于实际数据值,如果按其预期含义使用 NA,则说“TEST”和NA 不相同是不正确的。这两个值也可以相同,只是我们不知道,所以比较的结果应该是NA。所以我同意使用identical 在某种意义上是一种hack,但从这个意义上说,整个问题都是hacky-ish,所以为什么不在这里使用hack :)
【解决方案2】:

@lebatsnok 有一个很好的答案。 如果我们不需要ifelse,我会这样做:

data <- read.table(header = TRUE, text = "A B
                        NA  TEST
                       TEST TEST
                       Abaxasdas Test")

    data$output <- NA
    data$output[as.character(data$A) == as.character(data$B)] <- "YES"
    data$output[as.character(data$A) != as.character(data$B)] <- "NO"
    data$output[is.na(as.character(data$A)) | is.na(as.character(data$B))] <- "NO"

> data
          A    B output
1      <NA> TEST     NO
2      TEST TEST    YES
3 Abaxasdas Test     NO

【讨论】:

    【解决方案3】:

    您可以使用来自 dplyr 的 case_when。将第一个案例输出调整为您想要的任何内容。

    library(dplyr)
    
    df %>% 
      mutate(output = case_when(is.na(A) & is.na(B) ~ NA_character_,
                                is.na(A) | is.na(B) ~ 'NO', 
                                A == B ~ 'YES',
                                TRUE ~ 'NO'))
    #           A    B output
    # 1      <NA> TEST     NO
    # 2      TEST TEST    YES
    # 3 Abaxasdas Test     NO
    

    【讨论】:

      猜你喜欢
      • 2022-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多