web-dev-qa-db-fra.com

Comment inclure NA dans ifelse?

J'essaie de créer une colonne ID basée sur des instructions logiques pour les valeurs des autres colonnes. Par exemple, dans le dataframe suivant

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")

qui ressemble

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

Je souhaite créer une nouvelle colonne ID contenant la valeur 1 pour toutes les time qui ne sont pas NA et toutes les type qui ne sont pas A. J'utilise le code suivant pour cela:

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

Cela donne le résultat 

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

Toutefois, ce code ignore la variable NA dans la colonne type, ce qui donne la valeur NA dans la colonne ID. J'ai besoin que cela soit une valeur de 1, donc la solution dont j'ai besoin devrait donner:

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

Quelqu'un peut-il me dire comment je pourrais faire cela? Je pourrais faire en sorte que cela fonctionne avec mon code existant si je pouvais modifier le résultat de is.na(test$type) pour renvoyer FALSE au lieu de TRUE, mais je ne sais pas comment faire. Ou peut-être que la structure de mon code existant doit être entièrement modifiée? J'apprécie toute aide!

22
Thomas

Vous ne pouvez pas vraiment comparer NA avec une autre valeur, donc utiliser == ne fonctionnerait pas. Considérer ce qui suit:

NA == NA
# [1] NA

Vous pouvez simplement changer votre comparaison de == à %in%:

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

Concernant votre autre question, 

Je pourrais faire en sorte que cela fonctionne avec mon code existant si je pouvais modifier le résultat de is.na(test$type) pour renvoyer FALSE au lieu de TRUE, mais je ne sais pas comment faire.

utilisez simplement ! pour annuler les résultats:

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

@AnandaMahto a expliqué pourquoi vous obtenez ces résultats et vous a fourni le moyen le plus clair d'obtenir ce que vous voulez. Mais une autre option serait d’utiliser identical au lieu de ==.

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

Ou utilisez isTRUE:

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

Il semble que vous souhaitiez que l'instruction ifelse interprète les valeurs de NA comme étant FALSE au lieu de NA dans la comparaison. J'utilise les fonctions suivantes pour gérer cette situation afin de ne pas avoir à gérer en permanence la situation de NA:

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

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

Vous pouvez également combiner ces fonctions en une seule pour être plus efficace. Donc, pour retourner le résultat souhaité, vous pouvez utiliser:

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

Alors, j'entends que ça marche:

Data$X1<-as.character(Data$X1)
Data$GEOID<-as.character(Data$BLKIDFP00)
Data<-within(Data,X1<-ifelse(is.na(Data$X1),GEOID,Data$X2)) 

Mais j'avoue que ma chance est intermittente. 

0
Mox

Vous pourriez aussi essayer un elseif.

x <- 1
if (x ==1){
    print('same')
} else if (x > 1){
    print('bigger')
} else {
    print('smaller')
}
0
Mox