4
votes

Comment tester plusieurs conditions dans le contrôle de flux if else dans r

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)
  • Que me manque-t-il?


3 commentaires

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


4 Réponses :


4
votes

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 >


1 commentaires

Cela fonctionne, devra passer du temps avec la documentation de la fonction case_when.



2
votes

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 >


0 commentaires

3
votes

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 .


0 commentaires

2
votes

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][]


0 commentaires