Почему пропущенные значения преобразуются в символьные строки («NA») с использованием case_when в R?

#r

Вопрос:

У меня возникла проблема, когда пропущенные значения преобразуются в фактическую символьную строку «NA» после использования case_when — может ли кто-нибудь, пожалуйста, сообщить мне, где мой код неверен, и, возможно, предложить альтернативный метод, который не преобразует пропущенные значения в символьные строки?

Вот пример:

 # make the tibble
df <- structure(list(animal = c("cat", "dog", "mouse", "rat", 
"pidgeon", "fish"), value = c(-2.71, -2.63, 
-2.66, -6.99, -2.11, -6.44), ID = c("2700", 
NA, NA, "4821", "55117", NA)), row.names = c(NA, -6L
), class = c("tbl_df", "tbl", "data.frame"))

df
# A tibble: 6 x 3
  animal  value ID   
  <chr>   <dbl> <chr>
1 cat     -2.71 2700 
2 dog     -2.63 NA   
3 mouse   -2.66 NA   
4 rat     -6.99 4821 
5 pidgeon -2.11 55117
6 fish    -6.44 NA   

# check that it has two NA values
sum(is.na(df$ID))
# [1] 3


# create a separate tibble to merge it with
new_vals <- structure(list(animal = c("dog", "pidgeon"), ID_new = c("123456", "25255")), row.names = c(NA, -2L), class = c("tbl_df", 
"tbl", "data.frame"))

new_vals
# A tibble: 2 x 2
  animal  ID_new
  <chr>   <chr> 
1 dog     123456
2 pidgeon 25255 
 

Теперь я left_join два тиббла и делаю case_when заявление:

 df_new <- left_join(
        df,
        new_vals,
        by = "animal"
    ) %>%
    mutate(
        ID = case_when(
            is.na(ID) ~ paste0(ID_new),
            TRUE ~ paste0(ID)
        )
    ) 

> df_new
# A tibble: 6 x 4
  animal  value ID     ID_new
  <chr>   <dbl> <chr>  <chr> 
1 cat     -2.71 2700   NA    
2 dog     -2.63 123456 123456
3 mouse   -2.66 NA     NA    
4 rat     -6.99 4821   NA    
5 pidgeon -2.11 55117  25255 
6 fish    -6.44 NA     NA 

sum(is.na(df_new$ID))
[1] 0
 

Хотя в df_new$ID явно есть значения NA, теперь они больше не считаются фактическими отсутствующими значениями. Где я ошибаюсь?

Ответ №1:

Причина paste0 в том, что в выражении есть ненужное

 paste0(NA)
#[1] "NA"
 

Это задокументировано в ?paste

Обратите внимание, что функция paste() преобразует значение NA_character_, пропущенное значение символа, в «NA», что может показаться нежелательным, например, при вставке двух векторов символов или очень желательно,

Если намерение состоит в том, чтобы преобразовать в character класс (хотя входные столбцы являются character классами)

 as.character(NA)
#[1] NA
 

возвращает правильный тип NA, т. е. NA_character_ . По сравнению с поведением paste , stringr::str_c возвращает правильный NA по умолчанию

 str_c(NA)
#[1] NA

is.na(str_c(NA))
#[1] TRUE
 

Поскольку это character столбцы, и мы не выполняем никакого type преобразования (при необходимости используйте as.character вместо paste0 вставки как для объединения двух строк или столбцов строк вместе)

 df_new <- left_join(
    df,
    new_vals,
    by = "animal"
) %>%
mutate(
    ID = case_when(
        is.na(ID) ~ ID_new,
        TRUE ~ ID
    )
) 
 

-тестирование на NA

 sum(is.na(df_new$ID))
#[1] 2