Сопоставление значений с NA - пропущенные значения - с использованием mutate - PullRequest
6 голосов
/ 17 июня 2019

Я немного застрял.Есть ли лучший способ, чем приведенный ниже, выполнить сопоставление значений, рассматривая NA как "реальные значения" в пределах mutate?

library(dplyr)

data_foo <- data.frame(A= c(1:2, NA, 4, NA), B = c(1, 3, NA, NA, 4))

Не требуемый результат:

data_foo %>% mutate(irr = A==B)

#>    A  B   irr
#> 1  1  1  TRUE
#> 2  2  3 FALSE
#> 3 NA NA    NA
#> 4  4 NA    NA
#> 5 NA  4    NA

data_foo %>% rowwise() %>% mutate(irr = A%in%B)

#> Source: local data frame [5 x 3]
#> Groups: <by row>
#> 
#> # A tibble: 5 x 3
#>       A     B irr  
#>   <dbl> <dbl> <lgl>
#> 1     1     1 TRUE 
#> 2     2     3 FALSE
#> 3    NA    NA FALSE
#> 4     4    NA FALSE
#> 5    NA     4 FALSE

Требуемый вывод : ниже показан желаемый столбец, irr.Я использую это несколько громоздкие вспомогательные столбцы.Есть ли более короткий путь?

data_foo %>% 
  mutate(NA_A = is.na(A), 
         NA_B = is.na(B), 
         irr = if_else(is.na(A)|is.na(B), NA_A == NA_B, A == B))

#>    A  B  NA_A  NA_B   irr
#> 1  1  1 FALSE FALSE  TRUE
#> 2  2  3 FALSE FALSE FALSE
#> 3 NA NA  TRUE  TRUE  TRUE
#> 4  4 NA FALSE  TRUE FALSE
#> 5 NA  4  TRUE FALSE FALSE

Ответы [ 4 ]

5 голосов
/ 17 июня 2019

Используя map2

library(tidyverse)
data_foo %>%
   mutate(irr = map2_lgl(A, B, `%in%`))
#   A  B   irr
#1  1  1  TRUE
#2  2  3 FALSE
#3 NA NA  TRUE
#4  4 NA FALSE
#5 NA  4 FALSE

Или с setequal

data_foo %>% 
   rowwise %>%
   mutate(irr = setequal(A, B))

Вышеуказанный метод является кратким, но также и цикличным.Мы можем заменить NA другим значением, а затем сделать ==

data_foo %>%
     mutate_all(list(new = ~ replace_na(., -999))) %>%
     transmute(A, B, irr = A_new == B_new)
#   A  B   irr
#1  1  1  TRUE
#2  2  3 FALSE
#3 NA NA  TRUE
#4  4 NA FALSE
#5 NA  4 FALSE

или bind_cols и reduce

data_foo %>%
    mutate_all(replace_na, -999) %>% 
    reduce(`==`) %>% 
    bind_cols(data_foo, irr = .)
3 голосов
/ 17 июня 2019

Возможно, проще, чем ответ Акруна ?
Любой из двух способов, приведенных ниже, даст ожидаемый результат.Обратите внимание, что as.character этого не сделает, потому что возвращаемое значение as.character(NA) равно NA_character_.

data_foo %>%
  mutate(irr = paste(A) == paste(B))

data_foo %>%
  mutate(irr = sQuote(A) == sQuote(B))

#Source: local data frame [5 x 3]
#Groups: <by row>
#
## A tibble: 5 x 3
#      A     B irr  
#  <dbl> <dbl> <lgl>
#1     1     1 TRUE 
#2     2     3 FALSE
#3    NA    NA TRUE 
#4     4    NA FALSE
#5    NA     4 FALSE

Редактировать.

  1. Следуя комментариям ниже, я обновил код, и теперь он следует предложению Акруна.
  2. В ответе tmfmnk также есть отличная идея .Я использую аналогичный еще один способ решения проблемы вопроса.

В документации all.equal сказано, что

Не используйте all.equal непосредственно в if выражений - либо используйте isTRUE(all.equal(....)) или identical, если необходимо.

Хотя в mutate нет выражения if, я считаю, что оно более стабильно, чем identical, иимеет тот же эффект, если сравниваемые значения (вроде / фактически) равны.

data_foo %>%
  mutate(irr = isTRUE(all.equal(A, B)))
2 голосов
/ 17 июня 2019

Возможна также возможность:

data_foo %>%
 rowwise() %>%
 mutate(irr = identical(A, B)) %>%
 ungroup()

      A     B irr  
  <dbl> <dbl> <lgl>
1     1     1 TRUE 
2     2     3 FALSE
3    NA    NA TRUE 
4     4    NA FALSE
5    NA     4 FALSE
1 голос
/ 17 июня 2019

Функция объединения полезна, если вы хотите выполнить действие, когда значение равно NA

data_foo %>% 
  mutate(irr = coalesce(A == B, is.na(A) & is.na(B)))

#    A  B   irr
# 1  1  1  TRUE
# 2  2  3 FALSE
# 3 NA NA  TRUE
# 4  4 NA FALSE
# 5 NA  4 FALSE

То же самое для> 2 столбцов

data_foo %>% 
  mutate(irr = coalesce(reduce(., `==`), rowMeans(is.na(.)) == 1))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...