Cela semble être un doute très simple sur la structure de contrôle de flux, mais j'ai du mal à trouver la syntaxe correcte pour cela dans R, j'en ai essayé plusieurs sans succès. Il me manque quelque chose de vraiment évident.
Je voulais faire une boucle dans une liste avec les codes des états brésiliens et renvoyer la région dans laquelle elle se trouve. Mon objectif est de manipuler un ensemble de données plus grand, pas une liste, mais voici un MWE en utilisant une liste:
"North", "North", "North" ,"North", "North", "North","North", "Northeast", "Northeast",...
Lors de l'exécution du code ci-dessus, il semble que la boucle if casse également la boucle for, et elle ne renvoie que "North", qui est la réponse à le tout premier élément de la liste.
Je m'attendrais à une liste ressemblant à:
a <- c("RO", "AC", "AM" ,"RR", "PA", "AP", "TO", "MA", "PI", "CE", "RN", "PB", "PE", "AL", "SE", "BA", "MG", "ES", "RJ", "SP") setregion <- function(uf) { pb = txtProgressBar(min = 0, max = length(uf), initial = 0) region_out<-list() for (i in length(uf)) { if (uf %in% c("RO" ,"AC" ,"AM" ,"RR", "PA" , "AP" , "TO")) { region_out <- append(region_out,"North") } else if ( uf %in% c("MA","PI","CE","RN","PB","PE","AL","SE","BA")) { region_out <-append(region_out,"Northeast") } else if ( uf %in% c("MG","ES","RJ","SP")){ region_out <- append(region_out,"Southeast") } else if ( uf %in% c("PR", "SC", "RS")){ region_out <- append(region_out,"South") } else if ( uf %in% c("MS","MT","GO", "DF")){ region_out <-append(region_out,"Midwest") } setTxtProgressBar(pb,i) } return(region_out) } setregion(a)
4 Réponses :
Le problème avec if-else
normal est qu'il n'est pas vectorisé. Vous avez besoin d'une approche vectorisée, telle que la fonction ifelse
. Mais, dans votre cas, puisque vous avez tellement de conditions, la fonction case_when
de la bibliothèque dplyr
pourrait avoir plus de sens:
library(dplyr) setregion <- function(uf) { region_out <- case_when( uf %in% c("RO","AC","AM","RR","PA","AP","TO") ~ "North", uf %in% c("MA","PI","CE","RN","PB","PE","AL","SE","BA") ~ "Northeast", uf %in% c("MG","ES","RJ","SP") ~ "Southeast", uf %in% c("PR", "SC", "RS") ~ "South", uf %in% c("MS","MT","GO", "DF") ~ "Midwest" ) return(region_out) }
p >
Cela fonctionne, devra passer du temps avec la documentation de la fonction case_when.
Si vous n'aimez pas case_when ()
, vous pouvez utiliser within ()
et une simple affectation conditionnelle dans votre fonction.
regionizer <- function(dat, a) within(dat, { region_out[a %in% c("RO" ,"AC" ,"AM" ,"RR", "PA" , "AP" , "TO")] <- "North" region_out[a %in% c("MA","PI","CE","RN","PB","PE","AL","SE","BA")] <- "Northeast" region_out[a %in% c("MG","ES","RJ","SP")] <- "Southeast" region_out[a %in% c("PR", "SC", "RS")] <- "South" region_out[a %in% c("MS","MT","GO", "DF")] <- "Midwest" }) regionizer(dat, a) # a x region_out # 1 RO 0.15983063 North # 2 AC -0.24371961 North # 3 AM -0.52700098 North # 4 RR 0.38777302 North # 5 PA 0.91111258 North # 6 AP -1.31696659 North # 7 TO -0.16136374 North # 8 MA -0.85951191 Northeast # 9 PI 0.13187218 Northeast # 10 CE -1.62908394 Northeast ...
Données: dat
p >
La meilleure approche est d'éviter de coder en dur ce mappage; plutôt, il vaut mieux l'avoir sur un fichier / table et laisser le code être indépendant sur un tel mappage (qui pourrait changer dans un second moment).
Pensez à construire une table comme celle-là (j'ai peut-être commis des erreurs en associant la bonne région, mais peu importe):
setregion <- function(uf, ufToRegionMap) { ufToRegionMap$region[match(uf,ufToRegionMap$uf)] }
Ensuite, vous pouvez définir simplement votre fonction comme tel:
ufToRegionMap <- structure(list(uf = c("RO", "AC", "AM", "RR", "PA", "AP", "TO", "MA", "PI", "CE", "RN", "PB", "PE", "AL", "SE", "BA", "MG", "ES", "RJ", "SP", "PR", "SC", "RS", "MS", "MT", "GO", "DF"), region = c("North", "North", "North", "North", "North", "North", "North", "Northeast", "Northeast", "Northeast", "Northeast", "Northeast", "Northeast", "Northeast", "Northeast", "Northeast", "Southeast", "Southeast", "Southeast", "Southeast", "South", "South", "South", "Midwest", "Midwest", "Midwest", "Midwest")), class = "data.frame", row.names = c(NA, -27L))
en évitant tous les maux de tête if-else
et en ayant un code naturellement vectorisé. De plus, si vous souhaitez modifier et créer une autre région / association, il vous suffit de changer le ufToRegionMap
sans avoir besoin de changer la fonction setregion
.
Sinon, cela peut être résolu en fusionnant / en joignant une table de recherche lut
.
region V1 1: North RO 2: North AC 3: North AM 4: North RR 5: North PA 6: North AP 7: North TO 8: Northeast MA 9: Northeast PI 10: Northeast CE 11: Northeast RN 12: Northeast PB 13: Northeast PE 14: Northeast AL 15: Northeast SE 16: Northeast BA 17: Southeast MG 18: Southeast ES 19: Southeast RJ 20: Southeast SP 21: South PR 22: South SC 23: South RS 24: Midwest MS 25: Midwest MT 26: Midwest GO 27: Midwest DF region V1
a region_out 1: RO North 2: AC North 3: AM North 4: RR North 5: PA North 6: AP North 7: TO North 8: MA Northeast 9: PI Northeast 10: CE Northeast 11: RN Northeast 12: PB Northeast 13: PE Northeast 14: AL Northeast 15: SE Northeast 16: BA Northeast 17: MG Southeast 18: ES Southeast 19: RJ Southeast 20: SP Southeast
La table de recherche a été construite à partir des extraits de code fournis par l'OP:
a <- c("RO", "AC", "AM" ,"RR", "PA", "AP", "TO", "MA", "PI", "CE", "RN", "PB", "PE", "AL", "SE", "BA", "MG", "ES", "RJ", "SP") library(data.table) library(magrittr) # create look-up table from code snippets supplied by OP lut <- list( North = c("RO" ,"AC" ,"AM" ,"RR", "PA" , "AP" , "TO"), Northeast = c("MA","PI","CE","RN","PB","PE","AL","SE","BA"), Southeast = c("MG","ES","RJ","SP"), South = c("PR", "SC", "RS"), Midwest = c("MS","MT","GO", "DF") ) %>% lapply(as.data.table) %>% rbindlist(idcol = "region") # update join as.data.table(a)[lut, on = .(a == V1), region_out := region][]
Pourriez-vous montrer à quoi devrait ressembler votre résultat attendu?
Voir ci-dessus, comme demandé.
Vous pouvez utiliser un vecteur nommé comme décrit par ex. ici: Création d'une nouvelle variable à partir d'une table de recherche . Voir également Tables de recherche (sous-définition de caractères), mise en correspondance et fusion