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