10 - Algorítmico

François Rebaudo, IRD francois.rebaudo@ird.fr

Marzo 2019 ; PUCE-Quito-Ecuador http://myrbooksp.netlify.com/

CC BY-NC-ND 3.0

Pruebas lógicas con if

Pruebas lógicas con if

SI [esto] ENTONCES [esto] SINO [esto]

myVar <- 2
if(myVar < 3){
  print("myVar < 3")
}else{
  print("myVar > 3")
}
## [1] "myVar < 3"

Pruebas lógicas con if

myVar <- TRUE
if(is.character(myVar)){
  print("myVar: character")
} else {
  if(is.numeric(myVar)){
    print("myVar: numeric")
  } else {
    if(is.logical(myVar)){
      print("myVar: logical")
    } else {
      print("myVar: ...")
    }
  }
}
## [1] "myVar: logical"

Pruebas lógicas con if

if evalua solo el primer elemento:

prueba <- c(TRUE, FALSE, FALSE)
if(prueba == TRUE){
  print("¡SI!")
}
## Warning in if (prueba == TRUE) {: the condition has length > 1 and only the
## first element will be used
## [1] "¡SI!"

Pruebas lógicas con if

if evalua solo el primer elemento:

prueba <- c(TRUE, FALSE, FALSE)
if(prueba[1] == TRUE){
  print("¡SI!")
}
## [1] "¡SI!"
if(prueba[2] == TRUE){
  print("¡SI (2)!")
}

Pruebas lógicas con if

prueba <- c(TRUE, FALSE, FALSE)
if(prueba[1] == TRUE & 
    prueba[2] == TRUE & 
    prueba[3] == TRUE){
  print("¡SI!")
}

Pruebas lógicas con if

prueba <- c(TRUE, FALSE, FALSE)
if(sum(prueba == TRUE) == length(prueba)){
  print("¡SI!")
}

Pruebas lógicas con if

prueba <- c(TRUE, TRUE, TRUE)
if(sum(prueba == TRUE) == length(prueba)){
  print("¡SI!")
}
## [1] "¡SI!"

& y &&

Con & R comprobará todas las condiciones, y con && R tomará cada condición una después de la otra y continuará solo si es verdadera.

miNumero <- 9
if(is.numeric(miNumero) & miNumero * 10 < 100){
  print("Numero menor a 10")
}
## [1] "Numero menor a 10"

& y &&

miNumero <- "55"
if(is.numeric(miNumero) & miNumero * 10 < 100){
  print("Numero menor a 10")
}

Error in miNumero * 10: non-numeric argument to binary operator

& y &&

miNumero <- "55"
if(is.numeric(miNumero) && miNumero * 10 < 100){
  print("Numero menor a 10")
}

Pruebas lógicas con switch

Pruebas lógicas con switch

miNombre <- "Pablo"
if(miNombre == "Alexa"){
  result <- "Hola Alexa"
}
if(miNombre == "Juan"){
  result <- "Hola Juan"
}
if(miNombre == "Pablo"){
  result <- "Hola Pablo"
}
if(miNombre == "Javier"){
  result <- "Hola Javier"
}
print(result)
## [1] "Hola Pablo"

Pruebas lógicas con switch

miNombre <- "Pablo"
switch(miNombre, 
  Alexa = result <- "Hola Alexa",
  Juan = result <- "Hola Juan",
  Pablo = result <- "Hola Pablo",
  Javier = result <- "Hola Javier")
print(result)
## [1] "Hola Pablo"

El bucle for

El bucle for

bdd <- data.frame(rep01 = rnorm(n = 100, mean = 10, sd = 1), 
                  rep02 = rnorm(n = 100, mean = 10, sd = 1))
print(head(bdd))
##       rep01     rep02
## 1  9.848500 10.795274
## 2 10.530403  9.525827
## 3  9.733653  9.393879
## 4  9.252658  9.606791
## 5 10.247308  8.976681
## 6 10.878104 10.051718

El bucle for

for (i in 1:5){
  print(bdd$rep01[i] - bdd$rep02[i])
}
## [1] -0.9467737
## [1] 1.004576
## [1] 0.3397732
## [1] -0.3541334
## [1] 1.270627

El bucle for

letras <- letters
for (i in seq_along(letras)){
  if(letras[i] %in% c("a", "e", "i", "o", "u", "y")){
    print(paste0("Vocal ", letras[i]," en posición: ", i))
  }
}
## [1] "Vocal a en posición: 1"
## [1] "Vocal e en posición: 5"
## [1] "Vocal i en posición: 9"
## [1] "Vocal o en posición: 15"
## [1] "Vocal u en posición: 21"
## [1] "Vocal y en posición: 25"

El bucle for y R

R no maneja bien las bucles de tipo for. Veremos mas tarde como usar alternativas. Mientras tanto, cuando posible, hay que preferir el trabajo con vectores.

La mayoría de los ejemplos que se pueden encontrar en Internet sobre el bucle for() pueden reemplazarse por operaciones vectoriales.

El bucle for y R

# [1] FOR
for (i in 1:5){
  print(bdd$rep01[i] - bdd$rep02[i])
}
## [1] -0.9467737
## [1] 1.004576
## [1] 0.3397732
## [1] -0.3541334
## [1] 1.270627
# [2] VECTOR
head(bdd$rep01 - bdd$rep02)
## [1] -0.9467737  1.0045758  0.3397732 -0.3541334  1.2706270  0.8263859

El bucle for

letras <- letters
# [1] FOR
for (i in seq_along(letras)){
  if(letras[i] %in% c("a", "e", "i", "o", "u", "y")){
    print(paste0("Vocal ", letras[i]," en posición: ", i))
  }
}
## [1] "Vocal a en posición: 1"
## [1] "Vocal e en posición: 5"
## [1] "Vocal i en posición: 9"
## [1] "Vocal o en posición: 15"
## [1] "Vocal u en posición: 21"
## [1] "Vocal y en posición: 25"
# [2] VECTOR
which(letras %in% c("a", "e", "i", "o", "u", "y"))
## [1]  1  5  9 15 21 25

El bucle for y R

# numero de números pares
# [1] FOR
x <- sample(1:100, size = 20)
count <- 0
for (val in x) {
  if(val %% 2 == 0){
    count <- count + 1
  }
}
print(count)
## [1] 8
# [2] VECTOR
sum(x %% 2 == 0)
## [1] 8

El bucle for y R

# calcular cuadrados
# [1] FOR
x <- rep(0, 20)
for (j in 1:20){
  x[j] <- j^2
}
print(x)
##  [1]   1   4   9  16  25  36  49  64  81 100 121 144 169 196 225 256 289
## [18] 324 361 400
# [2] VECTOR
(1:20)^2
##  [1]   1   4   9  16  25  36  49  64  81 100 121 144 169 196 225 256 289
## [18] 324 361 400

El bucle for y R

# repetir una tirada de dados y promediar
# [1] FOR
ntrials = 1000
trials = rep(0, ntrials)
for (j in 1:ntrials){
  trials[j] = sample(1:6, size = 1)
}
mean(trials)
## [1] 3.512
# [2] VECTOR
mean(sample(1:6, ntrials, replace = TRUE))
## [1] 3.538

El bucle for y R

Es un buen ejercicio explorar los muchos ejemplos disponibles en Internet en el bucle for() e intentar convertirlos en operaciones vectoriales. Esto nos permite adquirir buenos reflejos de programación con R.

En conclusión, se recomienda no usar el bucle for() con R siempre que sea posible, y en este capítulo veremos alternativas como los bucles familiares apply().

El bucle while

El bucle while

i <- 0
while(i < 4){
  print(i)
  i <- i + 1
}
## [1] 0
## [1] 1
## [1] 2
## [1] 3

En este ejemplo, la variable i tiene como valor inicial 0. MIENTRAS QUE i < 4, mostramos i con print(). Para que este bucle finalice, no olvidamos cambiar el valor de i, esto se hace con la línea i <- i + 1. Cuando la condición i < 4 ya no se cumple, el bucle se detiene.

El bucle while

El bucle while() es muy útil para crear scripts que realizarán cálculos en variables cuyo valor cambia con el tiempo. Por ejemplo, imaginamos un número entre 0 y 10000 y un generador aleatorio que intentará determinar el valor de este número. Si queremos limitar los intentos de R a 2 segundos, podemos escribir el siguiente script.

El bucle while

myNumber <- sample(x = 10000, size = 1)
myGuess <- sample(x = 10000, size = 1)
paste0("Mi numero es: ", myNumber)
## [1] "Mi numero es: 3516"
paste0("El intento de la computadora es: ", myGuess)
## [1] "El intento de la computadora es: 1020"

El bucle while

startTime <- Sys.time()
print(startTime)
## [1] "2019-02-15 12:37:12 CET"

El bucle while

print(Sys.time() - startTime)
## Time difference of 0.06940413 secs

El bucle while

repeticiones <- 0
startTime <- Sys.time()
while(Sys.time() - startTime < 0.5){
  repeticiones <- repeticiones + 1
}
print(repeticiones)
## [1] 10565

El bucle while

repeticiones <- 0
startTime <- Sys.time()
while(Sys.time() - startTime < 0.5){
  repeticiones <- repeticiones + 1
  if(repeticiones >= 1000){
    break
  }
}
print(repeticiones)
## [1] 1000

El bucle while

myNumber <- sample(x = 10000, size = 1)
myGuess <- sample(x = 10000, size = 1)
numberGuess <- 0
startTime <- Sys.time()
while(Sys.time() - startTime < 2){
  if(myGuess == myNumber){
    numberGuess <- numberGuess + 1
    print(paste0("Numero encontrado despues de ", 
      numberGuess, " intentos."))
    print(paste0("Y tengo mucho tiempo libre: ", 
      round(2 - as.numeric(Sys.time() - startTime), 
      digits = 2), " sec"))
    break
  }else{
    myGuess <- sample(x = 10000, size = 1)
    numberGuess <- numberGuess + 1
  }
}
## [1] "Numero encontrado despues de 2455 intentos."
## [1] "Y tengo mucho tiempo libre: 1.86 sec"

El bucle while

guessNumber <- function(myNumber, myGuess){
  numberGuess <- 0
  success <- FALSE
  startTime <- Sys.time()
  while(Sys.time() - startTime < 2){
    if(myGuess == myNumber){
      numberGuess <- numberGuess + 1
      success <- TRUE
      break
    }else{
      myGuess <- sample(x = 10000, size = 1)
      numberGuess <- numberGuess + 1
    }
  }
  return(list(numberGuess, success))
}

guessNumber(myNumber = sample(x = 10000, size = 1), 
            myGuess = sample(x = 10000, size = 1))
## [[1]]
## [1] 19880
## 
## [[2]]
## [1] TRUE

El bucle while

guessNumber <- function(mySample){
  myNumber <- sample(mySample, size = 1)
  myGuess <- sample(mySample, size = 1)
  numberGuess <- 0
  success <- FALSE
  startTime <- Sys.time()
  while(Sys.time() - startTime < 2){
    if(myGuess == myNumber){
      numberGuess <- numberGuess + 1
      success <- TRUE
      break
    }else{
      myGuess <- sample(mySample, size = 1)
      numberGuess <- numberGuess + 1
    }
  }
  return(list(numberGuess, success))
}

guessNumber(mySample = 1:10000)
## [[1]]
## [1] 13907
## 
## [[2]]
## [1] TRUE

El bucle while

guessNumber2 <- function(mySample){
  myNumber <- sample(mySample, size = 1)
  myGuess <- sample(mySample, size = 1)
  numberGuess <- 0
  success <- FALSE
  startTime <- Sys.time()
  while(Sys.time() - startTime < 2){
    if(myGuess == myNumber){
      numberGuess <- numberGuess + 1
      success <- TRUE
      break
    }else{
      mySample <- mySample[! mySample %in% myGuess]
      myGuess <- sample(mySample, size = 1)
      numberGuess <- numberGuess + 1
    }
  }
  return(list(numberGuess, success))
}

guessNumber2(mySample = 1:10000)
## [[1]]
## [1] 9040
## 
## [[2]]
## [1] TRUE

El bucle repeat

El bucle repeat

i <- 1
repeat{
  print(i)
  i <- i + 1
  if(i >= 5){
    break
  }
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4

El bucle repeat

startTime <- Sys.time()
i <- 1
repeat{
  guessNumber(mySample = 1:10000)
  i <- i + 1
  if(i >= 10){
    break
  }
}
totalTime <- Sys.time() - startTime
print(totalTime)
## Time difference of 4.049098 secs

El bucle repeat

startTime <- Sys.time()
i <- 1
repeat{
  guessNumber2(mySample = 1:10000)
  i <- i + 1
  if(i >= 10){
    break
  }
}
totalTime <- Sys.time() - startTime
print(totalTime)
## Time difference of 6.775087 secs

El bucle repeat

pruebaTiempo <- microbenchmark(
  "codigo01_100" = guessNumber(mySample = 1:100),
  "codigo01_1000" = guessNumber(mySample = 1:1000),
  "codigo01_10000" = guessNumber(mySample = 1:10000),
  "codigo02_100" = guessNumber2(mySample = 1:100), 
  "codigo02_1000" = guessNumber2(mySample = 1:1000), 
  "codigo02_10000" = guessNumber2(mySample = 1:10000), 
  times = 100
)
print(pruebaTiempo)
## Unit: microseconds
##            expr       min         lq       mean     median          uq
##    codigo01_100   117.123   1639.701   7428.349   5776.985   10081.349
##   codigo01_1000   219.452  11872.582  55720.541  42890.745   81753.780
##  codigo01_10000   935.463 124278.218 496601.759 280895.986  773756.559
##    codigo02_100    65.202   1349.765   2699.375   2760.052    4211.845
##   codigo02_1000   366.760  19433.857  36778.340  36333.001   55390.289
##  codigo02_10000 20690.649 563851.406 941584.892 999181.056 1367622.747
##          max neval
##    40456.702   100
##   536776.584   100
##  2007386.197   100
##     6168.799   100
##    74659.783   100
##  1659831.666   100

El bucle repeat

next y break

break

Ya hemos visto la palabra clave break que permite salir del bucle actual. Por ejemplo, si buscamos el primer dígito después de 111 que es divisible por 32:

myVars <- 111:1000
for(myVar in myVars){
  if(myVar %% 32 == 0){
    print(myVar)
    break
  }
}
## [1] 128

Nota…

Mejor no usar for:

(111:1000)[111:1000 %% 32 == 0][1]
## [1] 128

next

La palabra clave next permite pasar a la siguiente iteración de un bucle si se cumple una determinada condición. Por ejemplo, si queremos imprimir las letras del alfabeto sin las vocales:

for(myLetter in letters){
  if(myLetter %in% c("a", "e", "i", "o", "u", "y")){
    next
  }
  print(myLetter)
}
## [1] "b"
## [1] "c"
## [1] "d"
## [1] "f"
## [1] "g"
## [1] "h"
## [1] "j"
## [1] "k"
## [1] "l"
## [1] "m"
## [1] "n"
## [1] "p"
## [1] "q"
## [1] "r"
## [1] "s"
## [1] "t"
## [1] "v"
## [1] "w"
## [1] "x"
## [1] "z"

Nota…

Mejor no usar for:

letters[! letters %in% c("a", "e", "i", "o", "u", "y")]
##  [1] "b" "c" "d" "f" "g" "h" "j" "k" "l" "m" "n" "p" "q" "r" "s" "t" "v"
## [18] "w" "x" "z"

SIGUIENTE