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"

31 comentarios:

  1. Problema para resolver con r. En algún pueblo, un grupo de niños juega fútbol.
    Junta a la cancha se encuentra un terreno privado delimitado por la siguiente función: f(x)=10-(x-7)^2/5 si x ∈ [0,14] y por el eje X. A 4 metros de la barda pasa un rió de 3 metros de ancho( es decir, entre Y=4 y Y=7). ¿Cuan el la probabilidad que al volarse el valor al terreno privado, no caiga en el rió?

    ResponderEliminar
  2. el problema que tengo es que a mi me piden que organice un salario entre bajo, medio y alto, el del medio me dice que debe de ser 900<=x<2500 pero yo cuando pongo eso en R me dice que eso así está mal y no se me ocurre otra manera de expresarlo

    ResponderEliminar
  3. Lo que tenés ahí en realidad son dos desigualdades: 900 <= x y x < 2500. Para escribirlo en R (o casi cualquier lenguaje de programación), tenés que unirlas con la conjunción lógica AND (https://es.wikipedia.org/wiki/Conjunci%C3%B3n_l%C3%B3gica), así: 900 <= x & x < 2500.

    ResponderEliminar
  4. Gracias y tengo otra duda; mi ejercicio va de asignar un nombre según el sueldo que gane cada persona. <900 es bajo 900<=x<2500 medio y >2500 alto en 474 sueldos. Yo pongo esto:


    clasif<-numeric(474)
    for(i in 1:474) {
    if(i<900) {
    salario<-paste(i,'bajo')
    print("salario bajo")
    clasif[i]<-salario
    }else {
    if(900<=i&&i<2500) {
    salario<-paste(i,'medio')
    print("salario medio")
    clasif[i]<-salario
    }else {
    salario<-paste(i,'alto')
    print("salario alto")
    clasif[i]<-salario
    }
    }
    }
    clasif

    y resulta que no me saca los salarios mayores o menores sino que me saca las posiciones, quiero decir, como hay 474 números, me indica que todos son bajos...porque son <900 pero no se como decirle que lea el salario.

    ResponderEliminar
  5. Claro, porque ahí estás evaluando i < 900, siendo que i es un número del vector 1:474. Tendrías que tener un vector x con todos los salarios y evaluar x[i] < 900.

    Saludos

    ResponderEliminar
  6. buenas... estoy luchando con if else para crear una nueva variable en una tabla que numere las observaciones de cada Unidad experimental. Es decir, cada Unidad experimental (UE) tiene diferente numero de observaciones y quiero numerarlas, la UE 1 tiene 10, la UE 2 tiene 22 y la UE 3 tiene 41. En mi tabla las observaciones están numeradas del 1 al 73 ( total)
    Gracias por la aydua

    ResponderEliminar
    Respuestas
    1. Hola, te paso dos formas de hacerlo:

      1. Con un loop for: http://pastebin.com/1rexKMAD

      2. Con el paquete dplyr: http://pastebin.com/aTKDJx0N

      La segunda forma es mi favorita personal, pero requiere entender comandos nuevos si no conocés dplyr. De todas formas, lo quiero mostrar porque dplyr es un paquete excelente para trabajar con data.frames (ver http://www.rstudio.com/wp-content/uploads/2015/02/data-wrangling-cheatsheet.pdf).

      Saludos!

      Eliminar
  7. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  8. Hola yo tengo dos vectores (s1 y s2) y quiero aplicar dos condiciones. Es decir, que se genere un vector nuevo (W) a partir de V,que muestre que si cada valor de los vectores s1 y s2 cumplen las dos condiciones, entonces en W tiene valor C y sino valor 0.
    Este es el código que he utilizado y R ha colapsado:

    for(i in 1:n) {
    if(s1<k&s2<k) {
    payoff=c}
    else {payoff=0 }}
    payoff

    ¿Está bien?

    ResponderEliminar
    Respuestas
    1. El problema está en que estás mezclando operaciones que son con muchos elementos al mismo tiempo (ej: s1 < k, s2 < k y s1 < k & s2 < k), con operaciones que son con un único elemento, como if o payoff = c.

      Si entendí bien, tu vector a crear es payoff. Entonces podés hacer esto:

      payoff <- 0
      payorff[s1 < k & s2 < k] <- c

      Saludos

      Eliminar
    2. Perdón, una corrección a mi respuesta: primero que nada, s1 y s2 tienen que tener la misma longitud (ie: cantidad de elementos). Luego:

      payoff <- numeric(length(s1))
      payorff[s1 < k & s2 < k] <- c

      Ahora sí

      Eliminar
  9. Hola Juan, gracias por tu ayuda en este teman, yo ya logre obtener mi vector como indicaste líneas arriba. Pero a la hora que quiero crear mi nueva variable a mi tabla , siempre me aparece el numero de orden ejmplo:

    1 chico
    2 chico
    3 mediano
    4 grande
    3 mediano

    lo que hice fue lo siguiente:
    clasif <- numeric(ntrees)
    for(i in 1:ntrees) {
    if((Data$DAP)[i]> 90) {
    texto <- paste(i, 'Grande')
    print(texto)
    clasif[i] <- texto
    } else {
    if((Data$DAP)[i] >=60 ) {
    texto <- paste(i, 'mediano')
    print(texto)
    clasif[i] <- texto
    } else {
    texto <- paste(i, 'chico')
    print(texto)
    clasif[i] <- texto
    }
    }
    }
    clasif

    ##adding variable clase diametrica
    Data$C_D <- clasif

    ResponderEliminar
  10. Buenas Arnaud, lo primero que te quiero recomendar es que en estos casos uses otras herramientas, en vez de if/else, ya que son más eficientes y fáciles de usar. Esta lección la escribí con un fin didáctico, porque no creo que sea realmente práctico trabajar así en R (aunque tal vez sí en otros lenguajes).

    No se cuál es el mensaje de error que te da este ejemplo, pero lo primero que puedo observar es que estás metiendo objetos de tipo texto dentro de un vector que originalmente debía ser numérico (clasif <- numeric). Si bien no se bien qué querés hacer con el vector, pero posiblemente sea fuente de problemas.

    Por último, te recomiendo usar esta estrategia: instalar el paquete "dplyr" y usar la función case_when, de esta forma:

    install.packages("dplyr")
    library(dplyr)
    case_when(Data$DAP > 90 ~ "Grande", Data$DAP <= 90 & Data$DAP >= 60 ~ "Mediano", Data$DAP < 60 ~ "Chico")


    ResponderEliminar
  11. Buenas, necesetaria solucionar una duda con R y no tengo claro si hay que usar el ifelse para ello, un poco de ayuda me iría genial!

    Tengo que construir un indicador cualitativa de consumo de los últimos meses a partir de una pregunta con distintas subpreguntas y las mismas respuestas en cada una de ellas (Si/No). Este indicador ha de tener tres valores: Nulo (no ha adquirido ninguno de los productos propuestos), Medio (tan solo ha adquirido UNO de los productos propuestos, y Alto (ha adquirido más de uno).

    Como ya he comentado antes, mi intención era hacerlo con if else, pero no acabo de tener claro cómo.


    Muchas gracias!!!
    Aina

    ResponderEliminar
    Respuestas
    1. Primero que nada... no había visto el mail, por eso no respondí, disculpa!

      Bueno, si se trata de un **único valor**, este código es suficiente (n_prod es la cantidad de productos):

      n_prod <- rpois(1, 1) # Ejemplo, da un valor entero aleatorio
      if (n_prod == 0) indicador <- "Nulo"
      if (n_prod == 1) indicador <- "Medio"
      if (n_prod > 1) indicador <- "Alto"

      Todos los casos posibles están cubiertos, porque se trata de valores enteros >= 0.


      Otra aproximación es usando un par de ifelse anidados. Esta funciona para vectores, ahorrando trabajo:

      n_prod <- rpois(30, 1) # Ahora n_prod es un vector con 30 valores
      indicador <- ifelse(n_prod > 0, ifelse(n_prod == 1, "Medio", "Alto"), "Nulo")


      Finalmente, pongo aca una opción acaso más sofisticada, cuya ventaja es que es más explícita y hace un
      único llamado a la función en cuestión (arriba puse 2 llamados a ifelse anidados):

      install.packages("dplyr")
      library(dplyr)

      n_prod <- rpois(30, 1)
      indicador <- case_when(n_prod == 0 ~ "Nulo",
      n_prod == 1 ~ "Meido",
      n_prod > 1 ~ "Alto")

      Eliminar
  12. Hola yo tengo un problema no sé cómo resolver el hecho de crear una una variable dado los resultados de una que ya tengo, son los resultados de una normal multivarida con dos variables.
    con la siguentes condiciones:
    La variable que debo generar es una que se llama estrato =1 si y solo si XY>0; o es 2 si y solo si XY<=0.

    ResponderEliminar
    Respuestas
    1. Una forma de hacerlo...

      estrato <- if (XY > 0) 1 else 2

      Otra sintaxis igualmente válida:

      if (XY > 0) {
      estrato <- 1
      } else {
      estrato <- 2
      }

      No había visto el mail, de ahí la demora en responder.

      Saludos

      Eliminar
  13. hola olle tengo un problema me dice que esta mal mi condicion
    #include
    #include
    int a;
    void main()
    {
    clrscr();
    printf("hola celeste");
    printf("sabes que me gustas un buen ñ.ñ");
    printf("¿crees que estoy mintiendo ?");
    clrscr();
    printf("te quiero mucho , el primer dia en que te vi fue muy lindo, me enamore desde la primera vez que te vi");
    printf("me gustas?");
    scanf("%d,&a"); }
    if(a==si){
    printf("daria lo que fuera por estar contigo");
    printf("te apoyare en las buenas, en las malas y hasta en las peores..");
    printf("eso si te digo...");
    printf("de mi no te olvidaras porque no me detendre hasta tenerte a mi lado");
    printf("TE QUIERO MUCHO");
    printf("CELESTE & ANTONIO");
    }else(a==no) {
    printf("entonces nimodo te apoyare ");
    printf("seremos ammigos y nos divertiremos bien .");
    printf("jajaja ... saludos bye xD");
    }

    ResponderEliminar
    Respuestas
    1. En primer lugar... esto no parece R, qué lenguaje de programación es?

      En segundo lugar, sospecho que el problema es que no pusiste comillas:

      if (a == "si")
      if (a == "no")

      Fijate si con eso funciona (a veces hay que usar comillas simples '').

      Eliminar
  14. buenas noches tengo un problema con un codigo


    ## 5. Escribe un if loop dentro de un for loop que anula en un vector todos los valores menores a 100: input:

    ```{r}
    b <- c(1, 129, 101, 120, 8, 1, 139)
    b1 <- b

    for(i in b1){
    if(b1 < 100) {
    b1 <- "Medición no valida "
    }
    return(b1)
    }
    b1

    ```

    solo me lee si coloco un codigo
    cuando trato de poner mas de uno no me corre.. alguien sabe que pasa

    ResponderEliminar
  15. Lo primero es sacar el return(b1): return se usa dentro de una función, no en código "suelto".

    Lo segundo es que tenés que usar el i dentro del loop.

    Por ejemplo, en vez de

    if (b1 < 100)

    tendrías que poner

    if (i < 100) # Recordar que i es: 1, 129, 101, 120 ...

    Porque i va tomando los valores de b1 de a uno por iteración.

    (también está el problema de que b1 no es un único número, si no un vector con varios números)

    Ahora, si hacés ese cambio, te queda resolver la otra parte:

    b1 <- "Mención no válida"

    Este comando te borra todo lo que había en b1, quedando un vector character con un único elemento: "Mención no válida".

    Tendrías que cambiar el enésimo elemento de b1... pero cómo hacés, si no estás "llevando la cuenta" de cuántas iteraciones vas? Bueno, la solución es cambiar la lógica:

    for (i in 1:length(b1)) { # Acá i es 1, 2, 3, 4, ....
    if (b1[i] < 100) { # Acá el "[i]" es clave
    b1[i] <- "Medición no válida" # Y acá también
    }
    }
    b1

    Listo

    PD: al final, b1 deja de ser numérico y pasa a ser caracteres.

    ResponderEliminar
  16. Disculpa, este comando se podra utilizar en una transpuesta de una matriz, y como lo emplearia?

    ResponderEliminar
    Respuestas
    1. En R la trasnpuesta de una matriz "m" se obtiene con el comando t(m).

      Eliminar
  17. Tengo el siguiente problema en R: Sume todos los numeros del 1 al 500 que no sean divisibles por 7. que opinan?

    ResponderEliminar
  18. dados los vertices de un triangulo (x1,y1), (x2,y2),(x3,y3)decir si el triangulo es equilatero, isoscelos o escaleno

    ResponderEliminar
  19. Hola, tengo un problema. Tengo que crear una funcion que define el movimiento de una particula y este movimiento depende de una probabilidad. HE asignado las probabilidades dependiendo de donde cae un dado del 1 al 10, pero a la hora de signar los valorfes no sé como funcionan:
    F<-function{(x+a,
    y+a,
    z+a)}

    clasif<-numeric(10)
    for(i in 1:10)
    {if(i<6) (a<-1)}
    else { if(i<9) a<--1}
    else {a <-0}

    ResponderEliminar
  20. Hola, tengo un proble m¡con el uso del == en un if
    al colocar una variable

    valores = function(x) {
    a = x[1]
    b = x[2]
    c = x[3]
    if(a==b & a==c & b==c){{print("Los nùmeros son iguales") return(x[c(1,2,3)])}
    if(a==b){print("Dos de los nùmeros son iguales") return(x[c(1,2)])}
    if(a==c){print("Dos de los nùmeros son iguales") return(x[c(1,3)])}
    if(c==b){print("Dos de los nùmeros son iguales") return(x[c(2,3)])}
    else {print("los nùmeros son distintos")} }

    }

    me dice que el == es invalido ¿Que ocurre?

    ResponderEliminar