48 votes

Instruction SI vectorisée dans R ?

x <- seq(0.1,10,0.1)
y <- if (x < 5) 1 else 2

Je voudrais que le if opère sur chaque cas au lieu d'opérer sur l'ensemble du vecteur. Que dois-je changer ?

64voto

Roman Luštrik Points 19295
x <- seq(0.1,10,0.1)

> x
  [1]  0.1  0.2  0.3  0.4  0.5  0.6  0.7  0.8  0.9  1.0  1.1  1.2  1.3  1.4  1.5
 [16]  1.6  1.7  1.8  1.9  2.0  2.1  2.2  2.3  2.4  2.5  2.6  2.7  2.8  2.9  3.0
 [31]  3.1  3.2  3.3  3.4  3.5  3.6  3.7  3.8  3.9  4.0  4.1  4.2  4.3  4.4  4.5
 [46]  4.6  4.7  4.8  4.9  5.0  5.1  5.2  5.3  5.4  5.5  5.6  5.7  5.8  5.9  6.0
 [61]  6.1  6.2  6.3  6.4  6.5  6.6  6.7  6.8  6.9  7.0  7.1  7.2  7.3  7.4  7.5
 [76]  7.6  7.7  7.8  7.9  8.0  8.1  8.2  8.3  8.4  8.5  8.6  8.7  8.8  8.9  9.0
 [91]  9.1  9.2  9.3  9.4  9.5  9.6  9.7  9.8  9.9 10.0

> ifelse(x < 5, 1, 2)
  [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 [38] 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 [75] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2

16voto

Joris Meys Points 38980

Pour être complet : dans les grands vecteurs, vous pouvez utiliser les indices pour accélérer les choses (nous le faisons souvent dans les simulations, où les fonctions s'exécutent généralement 1 000 à 10 000 fois). Mais tant que ce n'est pas nécessaire, utilisez simplement ifelse . Cela se lit beaucoup plus facilement.

 > set.seed(100)
> x <- runif(1000,1,10)

> system.time(replicate(10000,{
+     y <- ifelse(x < 5,1,2)
+ }))
   user  system elapsed 
   2.56    0.08    2.64 

> system.time(replicate(10000,{
+   y <- rep(2,length(x))
+   y[x < 5]<- 1
+ }))
   user  system elapsed 
   0.48    0.00    0.48 

15voto

Joshua Ulrich Points 68776

y <- if (x < 5) 1 else 2 ne fonctionne pas sur l'ensemble du vecteur (l'avertissement que vous recevez vous indique que seul le premier élément de la condition sera utilisé). Vous voulez ifelse :

 y <- ifelse(x < 5, 1, 2)

ifelse opère sur l'ensemble du vecteur logique, élément par élément. if n'accepte qu'une seule valeur logique. Voir ?"if" et ?ifelse

3voto

David Arenburg Points 14239

Vous pouvez également simplement créer un vecteur logique et 1 pour celui-ci

 x <- seq(0.1, 10, 0.1) # Your data set   
(x >= 5) + 1
#  [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
# [92] 2 2 2 2 2 2 2 2 2

Si vous souhaitez comparer les performances, ce serait la solution la plus rapide

 set.seed(100)
x <- runif(1e6, 1, 10)

RL <- function(x) y <- ifelse(x < 5,1,2)
JM <- function(x) {y <- rep(2, length(x)); y[x < 5] <- 1}
DA <- function(x) y <- (x >= 5) + 1

library(microbenchmark)
microbenchmark(RL(x),
               JM(x),
               DA(x))

# Unit: milliseconds
#  expr       min        lq      mean    median        uq       max neval
# RL(x) 331.83448 366.52940 378.89182 374.99741 381.08659 609.21218   100
# JM(x)  38.72894  42.18745  44.36493  43.25086  44.09626  82.76168   100
# DA(x)  10.01644  11.96482  14.21593  13.17825  14.12930  53.76923   100

0voto

DJJ Points 149

Suite à la publication ci-dessus, vous pouvez même utiliser et modifier les éléments d'un vecteur répondant aux critères. À mon avis, si ce n'est pas plus coûteux de calculer plus rapidement, il faut toujours le faire.

 x = seq(0.1,10,0.1)
y <- rep(2,length(x))
y[x<5] <- x[x<5]*2

Le code du post précédent est le mieux pour répondre à la question. Mais si je devais utiliser le code ci-dessus, je ferais:

 x = seq(0.1,10,0.1)
y <- rep(2,length(x))
y[x<5] <- x[x<5]*0 +1

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X