web-dev-qa-db-fra.com

Utilisation de switch () dans R pour remplacer les valeurs vectorielles

Cela devrait être assez simple, mais même après avoir vérifié toute la documentation et les exemples en ligne, je ne l’ai pas.

J'aimerais utiliser switch () pour remplacer les valeurs d'un vecteur de caractères.

Un exemple factice, extrêmement simple et reproductible:

test<-c("He is", "She has", "He has", "She is")

Supposons que je veuille attribuer "1" aux phrases incluant le verbe "être" et "2" aux phrases comprenant le verbe "avoir". Ce qui suit ne fonctionne pas:

test<-switch(test,
                "He is"=1,
                "She is"=1,
                "He has"=2,
                "She has"=2)

Message d'erreur: 

+ + + + Error in switch(test, `He is` = 1, `She is` = 1, `He has` = 2, `She has` = 2) : 
  EXPR must be a length 1 vector

Je pense que EXPR est en effet un vecteur de longueur 1, alors qu'est-ce qui ne va pas?

Je pensais que peut-être R attendait des caractères comme remplaçants, mais ni le wrapping switch () dans un "as.integer" ni le travail suivant:

test<-switch(test,
                "He is"="1",
                "She is"="1",
                "He has"="2",
                "She has"="2")

Peut-être que ça ne vectorise pas et que je devrais faire une boucle? Est-ce que c'est ça? Serait décevant, compte tenu de la force de R est la vectorisation. Merci d'avance!

15
torwart

La forme vectorisée de if est ifelse:

test <- ifelse(test == "He is", 1,
        ifelse(test == "She is", 1,
        ifelse(test == "He has", 2,
        2)))

ou

test <- ifelse(test %in% c("He is", "She is"), 1, 2)

switch est fondamentalement une façon d'écrire des tests imbriqués if-else. Pensez à if et switch en tant que flux de contrôle instructions, et non en tant qu'opérateurs de transformation de données. Vous les utilisez pour contrôler l'exécution d'un algorithme, par exemple pour tester la convergence ou pour choisir le chemin d'exécution à suivre. Vous ne les utiliseriez pas pour manipuler directement des données dans la plupart des cas.

11
Hong Ooi

Voici la bonne façon de vectoriser une fonction, par ex. commutateur :

# Data vector:
test<-c("He is", "She has", "He has", "She is")

# Vectorized SWITCH:
foo <- Vectorize(function(a) {
  switch(as.character(a),
                      "He is" = 1,
                      "She is" = 1,
                      "He has" = 2,
                      2)

}, "a")

# Result:
foo(test)

  He is She has  He has  She is 
      1       2       2       1

J'espère que ça aide.

15
Davit Sargsyan

Tu pourrais essayer 

test_out <- sapply(1:length(test), function(x) switch(test[x],
             "He is"=1,
             "She is"=1,
             "He has"=2,
             "She has"=2))

Ou équivalent 

test_out <- sapply(test, switch,
             "He is"=1,
             "She is"=1,
             "He has"=2,
             "She has"=2)
10
RHertel

J'ai trouvé cette approche la plus lisible:

# input
test <-c("He is", "She has", "He has", "She is", "Unknown", "She is")

# mapping
map <- c(
  "He is" = 1, 
  "She has" = 2, 
  "He has" = 2, 
  "She is" = 1)

answer <- map[test]

# output
answer
He is She has  He has  She is    <NA>  She is 
    1       2       2       1      NA       1 

Si test est numérique, vous devez convertir la valeur en character pour pouvoir utiliser ceci.

2
Gedrox

"Vectoriser" est basé sur la fonction "mapply", alors que "ifelse" est une fonction de base qui devrait déjà être vectorisée. Donc, en termes de performances, "Vectoriser" peut être plus lent. Il est facile de vectoriser une fonction R avec la famille "apply", mais les performances posent généralement problème pour les gros volumes. Mieux vaut utiliser des fonctions de base optimisées pour travailler avec des vecteurs.

2
Mikhail

Bien que je préfère généralement les approches de base R, il existe un package avec une fonction de commutateur vectorisé.

library(broman)

switchv(c("horse", "fish", "cat", "bug"),
horse="fast",
cat="cute",
"what?")

Ajouté basé sur le commentaire pour utiliser les données OP.

library(broman)

test<-c("He is", "She has", "He has", "She is")


test<-switchv(test,
                "He is"="1",
                "She is"="1",
                "He has"="2",
                "She has"="2")

test
1
James Holland

Voici une solution avec recode() de car:

# Data vector:
x <- c("He is", "She has", "He has", "She is")

library("car")
recode(x, "'He is'=1; 'She is'=1; 'He has'=2; 'She has'=2") # or
recode(x, "c('He is', 'She is')=1; c('He has', 'She has')=2")
0
jogo