Подтвердить что ты не робот

R: Как включить NA в ifelse?

Я пытаюсь создать столбец ID на основе логических операторов для значений других столбцов. Например, в следующем фрейме данных

test <- structure(list(time = c(10L, 20L, NA, 30L), type = structure(c(1L, 
2L, 3L, NA), .Label = c("A", "B", "C"), class = "factor"), ID = c(NA, 
"1", NA, NA)), .Names = c("time", "type", "ID"), row.names = c(NA, 
-4L), class = "data.frame")

который выглядит как

    time    type
1   10      A
2   20      B
3   NA      C
4   30      NA

Я хочу создать новый столбец ID, содержащий значение 1 для всех time, которые не являются NA и все type, которые не являются A. Для этого я использую следующий код:

test$ID <- ifelse(is.na(test$time) | test$type == "A", NA, "1")

Это дает результат как

    time    type    ID
1   10      A       NA
2   20      B       1
3   NA      C       NA
4   30      NA      NA

Однако этот код игнорирует NA в столбце type, что приводит к значению NA в столбце ID. Мне нужно, чтобы это значение было 1, поэтому мое необходимое решение должно дать:

    time    type    ID
1   10      A       NA
2   20      B       1
3   NA      C       NA
4   30      NA      1

Может ли кто-нибудь сказать мне, как я могу это сделать? Я мог бы заставить это работать с моим существующим кодом, если бы я мог каким-то образом изменить результат is.na(test$type), чтобы вернуть FALSE вместо TRUE, но я не уверен, как это сделать. Или, может быть, структура моего существующего кода должна быть полностью изменена? Я ценю любую помощь!

4b9b3361

Ответ 1

Вы не можете сравнить NA с другим значением, поэтому использование == не будет работать. Рассмотрим следующее:

NA == NA
# [1] NA

Вы можете просто изменить свое сравнение с == на %in%:

ifelse(is.na(test$time) | test$type %in% "A", NA, "1")
# [1] NA  "1" NA  "1"

Относительно вашего другого вопроса,

Я мог бы заставить это работать с моим существующим кодом, если бы я мог каким-то образом изменить результат is.na(test$type), чтобы вернуть FALSE вместо TRUE, но я не уверен, как это сделать.

просто используйте !, чтобы свести на нет результаты:

!is.na(test$time)
# [1]  TRUE  TRUE FALSE  TRUE

Ответ 2

@AnandaMahto обратилась к тому, почему вы получаете эти результаты и предоставляете самый лучший способ получить то, что хотите. Но другой вариант - использовать identical вместо ==.

test$ID <- ifelse(is.na(test$time) | sapply(as.character(test$type), identical, "A"), NA, "1")

Или используйте isTRUE:

test$ID <- ifelse(is.na(test$time) | Vectorize(isTRUE)(test$type == "A"), NA, "1")

Ответ 3

Похоже, вы хотите, чтобы оператор ifelse интерпретировал значения NA как FALSE вместо NA в сравнении. Я использую следующие функции для обработки этой ситуации, поэтому мне не нужно постоянно обрабатывать ситуацию с НС:

falseifNA <- function(x){
  ifelse(is.na(x), FALSE, x)
}

ifelse2 <- function(x, a, b){
  ifelse(falseifNA(x), a, b)
}

Вы могли бы также объединить эти функции в один, чтобы быть более эффективными. Чтобы вернуть нужный результат, вы можете использовать:

test$ID <- ifelse2(is.na(test$time) | test$type == "A", NA, "1")