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
, но я не уверен, как это сделать. Или, может быть, структура моего существующего кода должна быть полностью изменена? Я ценю любую помощь!
Ответы
Ответ 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")