Mostrando entradas con la etiqueta if. Mostrar todas las entradas
Mostrando entradas con la etiqueta if. Mostrar todas las entradas

sábado, 23 de julio de 2011

if / else


En programación existen ciertas herramientas fundamentales y universales denominadas colectivamente Estructuras de Control. En esta categoría se encuentran los "loops" (lazos, ciclos) y "condicionales".
En esta entrada se va a mostrar el uso del "if" y "else" en R

### Condicionales: if
## Estructura básica:
if(condición) comando
## Se ejecuta el comando si la condición es TRUE
 
## Entonces:
if(3 > 2) print('  :-D  ')
if(3 < 2) print('  :-(  ')
 
## Al igual que vimos antes, se pueden usar las { } para insertar varios
## comandos juntos:
if(3 > 2) {
  print('Es verdadero!')
  print(' :-D ')
}
 
### Usando if / else
### La combinación de if + else sirve para lograr este flujo:
                        / Sí -----> comando1
Se cumple la condición? |
                        \ No -----> comando2

## La estructura básica de if / else es:
if(condición) comando1 else comando2
## Cuando se cumple una condición dada, se ejecuta el comando1, en caso
## contrario, se ejecuta el comando2
## Estructura básica, pero usando {}:
if(condición) {
  comando1 ## Si la condición se cumple (TRUE)
} else {
  comando2 ## Si la condición no se cumple (FALSE)
}
 
## Ejemplo: combinacion de un loop con if/else
## Clasificación de números del 1 al 10 en 2 grupos
clasif <- numeric(10) # Acá voy a guardar el resultado
for(i in 1:10) {
  if(i > 5) { ## Se si se cumple, entonces es "grande"
    texto <- paste(i, 'grande')
    print(texto)
    clasif[i] <- texto ## *1
  } else {    ## Si no se cumple, entonces es "chico"
    texto <- paste(i, 'chico')
    print(texto)
    clasif[i] <- texto ## *2
  }
  # clasif[i] <- texto ## Este comando puede sustituir las lineas *1 y *2
}
clasif
 
## Ídem, pero con ifelse
## esquema conceptual (no correr):
ifelse(condición, comando1, comando2)
x <- 1:10
clasif <- ifelse(x > 5, 'grande', 'chico')
clasif <- paste(x, clasif)
clasif
## Para este tipo de casos sencillos el ifelse es mucho más rápido y simple
## que usar un for + if + else
 
## Hay casos sin embargo, en que usar loops combinados con if y else es
## la mejor opción. Nótese que es necesario hacer un "anidamiento" de
## bloques de comando...
## Ejemplo: Clasificación en tres grupos
clasif <- numeric(10)
for(i in 1:10) {
  if(i > 5) {
    texto <- paste(i, 'grande')
    print(texto)
    clasif[i] <- texto
  } else {
    if(i > 2) {
      texto <- paste(i, 'mediano')
      print(texto)
      clasif[i] <- texto
    } else {
      texto <- paste(i, 'chico')
      print(texto)
      clasif[i] <- texto
    }
  }
}
clasif
 
## Esquemáticamente:
         / Sí -----> "grande"
(i > 5)? |                    / Sí -----> "mediano"
         \ No -----> (i > 2)? |
                              \ No -----> "chico"

Ejemplos extra


## Ejemplo: usar if + break para detener un loop
## Primero necesito la función para evaluar la serie de Leibniz:
leib <- function(n) {
  x <- 0:n
  imp <- 2 * x + 1
  inv <- 1 / imp
  elementos <- inv * (- 1) ^ x
  sum(elementos)
}
 
### Para alcanzar una presición predeterminada
n <- 5     # el n inicial es 5
error <- 0.001 # esta es la presición que queremos
out   <- NULL # en out vamos a ir pegando lo generado **
for(i in 1:100) {
  x   <- leib(n) * 4 # x es el valor de pi estimado
  dif <- abs(x - pi) # dif es |x - pi|
  out <- c(out, dif) # le agrego la diferencia a out
  if(dif < error) { # Si cumple la condición que interesa...
    break          # ... lo interrumpimos con un break
  }
  n <- n + 1
}
plot(out)
 
## ** Usar NULL es una forma de generar un objeto vacío, al cual luego
## se le van a concatenar elementos. En este caso, en cada iteración se
## le concatena un valor nuevo (dif).
 
## Ejemplo: usar un while para lograr lo mismo, pero sin molestarnos
## en poner un número de iteraciones.
#### Para este caso el while es una opción más conveniente
#### ya que a diferencia del for no tiene un límite de iteraciones
#### predeterminada.
#### Para ejecutar lo mismo haciendo un while:
n <- 5
error <- 0.001
dif <- Inf  # dif tiene que estar definido antes de empezar el while
            # porque es necesario para evaluar la condición entre paréntesis
out <- NULL 
while(dif > error) {  # Cáda vez que empieza el loop, se evalúa 
  x <- leib(n) * 4    # la condición entre paréntesis.
  dif <- abs(x - pi) # Si no es verdadera, se corta el loop.
  out <- c(out, dif)
  n <- n + 1        # si no pongo esto hace un loop infinito!
}
plot(out)
 
#### Este proceso se puede implementar en una función.
#### Para esto necesitamos algunos argumentos (n, error y show), aunque
#### show lo ponemos simplemente para que haga opcionalmente un gráfico...
estimaPi <- function(n=5, error=0.01, show=TRUE) {
  dif <- Inf
  while(dif > error) {
    x <- leib(n) * 4
    dif <- abs(x - pi)
    out <- c(out, dif)
    n <- n + 1 # si no pongo esto hace un loop infinito!
  }
  if(show) plot(out) # hace el plot si show == TRUE
 
list(estimacion=x, nfinal=n - 1, error=error, dif=out)
}
## Hasta hoar sólo me definió la función, aún no la corrí, para eso:
pi1 <- estimaPi()
str(pi1) # pi1 es una lista
pi1$     # usando la tecla "tab" se pueden ver los objetos contenidos en pi1
abs(pi1$estimacion - pi) ## ¿Qué tan distinto es?
 
## Ejercicio opcional:
## Modificar la función estimaPi para que haga un plot de los
## sucesivos estimados del valor pi.