Capítulo 10 Estructuras de control: if-else

Hasta ahora hemos trasteado con datos: hemos empezado desde una celda, para luego construir columnas, para luego juntarlas en algo parecido a una base de datos.

Para poder manejarnos con soltura con dichos datos es importante que conozcamos como se usan las expresiones de control más típicas. Una expresión de control será un conjunto de órdenes que nos permiten decidir por donde queremos que avance nuestro programa: ¿qué hacemos si sucede A? ¿Y si sucede B?

Si has programado en algún otro lenguaje, estarás familiarizado/a con elementos como un if (blabla) {...} else {...} (que los usaremos a veces) o bucles for y while. Si es la primera que programas en algún lenguaje, no te preocupes, las empezamos desde cero, empezando por las estructuras condicionales

  • if (x == 1) { código A } else { código B }: si condición (por ejemplo, x == 1) es cierta, se ejecuta código A; si es falsa, se ejecuta código B.

10.1 if

Una de las estructuras de control más famosas de cualquier lenguaje de programación: SI las condiciones impuestas se cumplen (TRUE), ejecuta las órdenes que tengamos dentro del if {}. Definamos por ejemplo una variable sencilla, las edades de 8 personas.

edades <- c(14, 17, 24, 56, 31, 20, 87, 73)

Para comprobar cuales son menores de edades podemos aplicar lo aprendido en temas anteriores, realizando una comparación lógica: si es menor de edad, devuelve un TRUE; en caso contrario, devuelve un FALSE.

edades < 18
## [1]  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE

Con las funciones any() y all() podemos saber si todos o alguno de los elementos de un vector cumplen una condición.

all(edades >= 18) # todos mayores de edad
## [1] FALSE
any(edades < 18) # existe algun menor de edad
## [1] TRUE

Con dichos elementos vamos a construir nuestra primera estructura condicional: queremos que si existe algún menor de edad, nos imprima un mensaje indicándolo.

if (any(edades < 18)) { # TRUE si al menos una persona mayor de edad
  
  print("existe alguna persona mayor de edad")
  
}
## [1] "existe alguna persona mayor de edad"

En caso de que no se cumplan las condiciones dentro del if() (condiciones que devuelvan un FALSE), no sucederá nada.

if (all(edades >= 18)) { # TRUE si TODOS son mayores de edad
  
  print("todas las personas son mayores de edad")
  
}

Fíjate que en este caso no hemos obtenido ningún mensaje porque la condición all(edades >= 18) no es cierta (no son todos mayores de 18 años).

10.2 if - else

La estructura if (condicion) { } puede ser combinada con un else { }, de forma que cuando la condición no se cumpla (como en el último ejemplo), se ejecutará el código que haya dentro del else { }, permitiéndonos decidir que sucede cuando SÍ se cumple y cuando NO se cumple

if (all(edades >= 18)) { # TRUE si TODOS son mayores de edad
  
  print("todas las personas son mayores de edad")
  
} else { # si hay alguno menor de edad 
  
  print("existe alguna persona menor de edad")
}
## [1] "existe alguna persona menor de edad"

Podemos ya complicar un poco el código con lo que hemos aprendido de temas anteriores: en caso de que haya alguno menor de edad, queremos extraer la edad por pantalla (con edades[edades < 18] extraeremos las edades que cumplen la condición de ser menor de edad).

if (all(edades >= 18)) { # TRUE si TODOS son mayores de edad
  
  print("todas las personas son mayores de edad")
  
} else { # si hay alguno menor de edad 
  
  print(glue("Existe alguna persona menor de edad. Sus edades son: {edades[edades < 18]}"))
}
## Existe alguna persona menor de edad. Sus edades son: 14
## Existe alguna persona menor de edad. Sus edades son: 17

10.3 if - else anidados

Dicha estructura if - else puede anidarse, de forma que vayamos concatenando dichas estructuras, como en el ejemplo que tenemos debajo. Imagina que queremos realizar una acción si todos fuesen mayores de edad; en caso contrario, pero si todos los menores de edad tienen 16 años o más, realizar otra acción; en caso contrario, otra acción

if (all(edades >= 18)) { # TRUE si TODOS son mayores de edad
  
  print("todas las personas son mayores de edad")
  
} else if (all(edades >= 16)) { # si todos los menores de edad tienen >=16
  
  print("Existe alguna persona menor de edad pero todos con 16 años o más")
  
} else {
  
  print("Existe alguna persona menor de 16 años")

}
## [1] "Existe alguna persona menor de 16 años"

10.4 ifelse () vectorizado

Esta estructura condicional puede ser vectorizada, de forma que podamos reunir en una sola fila un número elevado de estructuras de comparación la función ifelse(), cuyos argumentos de entrada serán la condición a evaluar, lo que sucede cuando se cumple y lo que no, que aplicará a cada elemento del vector de entrada. Con el ejemplo de las edades, vamos a dejar el dato ausente si son menores de edad, y si son mayores de edad se queda como está.

# NA si no cumple la condición, la edad si se cumple.
ifelse(edades >= 18, edades, NA)
## [1] NA NA 24 56 31 20 87 73

Todas estas estructuras no solo sirven para datos numéricos. Vamos a definir un vector de nombres con algunos ausentes (NA), y vamos a sustituir los ausentes por el texto "nombre_desconocido" (los que no sean ausentes se quedan como están).

nombres <- c("Juan", "María", NA, NA, "Lucía", "Carmen", "Javier",
             NA, "Carlos", NA, "Gregorio", "Paloma")

# Si tiene ausente --> "nombre_desconocido"
# Si no tiene ausente --> nombres originales
nombres <- ifelse(is.na(nombres), "nombre_desconocido", nombres)
nombres
##  [1] "Juan"               "María"              "nombre_desconocido"
##  [4] "nombre_desconocido" "Lucía"              "Carmen"            
##  [7] "Javier"             "nombre_desconocido" "Carlos"            
## [10] "nombre_desconocido" "Gregorio"           "Paloma"

Esta función ifelse() es muy util para codificar variables o averiguar cuales cumplen una condición.

10.5 Consejos

CONSEJOS

 

Rainbow parentheses

Uno de los errores más habituales, y que seguirás cometiendo aunque lleves años programando, es no cerrar un paréntesis que has abierto, por lo que el programa no sabe si has acabado de llamar a una orden o no. Para ello en las nuevas versiones de RStudio, en el menú Tools < Global Options < Code < Display podemos habilitar la opción Rainbow Parentheses que nos escribe cada par de () de un color distinto

Activando Rainbow Parentheses.

Imagen/gráfica 10.1: Activando Rainbow Parentheses.

 

Minimiza estructuras de control en el código

Puedes colapsar las estructuras de control pulsando en la flecha que aparece a la izquierda de ellas en tu script.

 

10.6 📝 Ejercicios

(haz click en las flechas para ver soluciones)

📝Ejercicio 1: modifica el código inferior para imprimir un mensaje por pantalla si todos los datos del conjunto airquality son de meses que no sean enero.

library(datasets) # paquete con los adtos
mes <- airquality$Month

if (mes == 2) {
  
  print("Ningún dato es del mes de enero")
  
}

  • Solución:
library(datasets) # paquete con los datos
mes <- airquality$Month

if (all(mes != 1)) { # todos con mes distinto de 1
  
  print("Ningún dato es del mes de enero")
  
}
## [1] "Ningún dato es del mes de enero"

 

📝Ejercicio 2: modifica el código inferior para imprimir un mensaje por pantalla si alguno de los registros tiene una temperatura mayor a 90 (Farenheit).

temperatura <- airquality$Temp

if (temperatura  == 100) {
  
  print("Alguno de los registros tiene temperatura superior a 90 Farenheit")
  
}

  • Solución:
temperatura <- airquality$Temp

if (any(temperatura > 90)) {
  
  print("Alguno de los registros tiene temperatura superior a 90 Farenheit")
  
}
## [1] "Alguno de los registros tiene temperatura superior a 90 Farenheit"

 

📝Ejercicio 3: modifica el código inferior para imprimir un mensaje por pantalla si alguno de los días supera la temperatura de 100.

temperatura <- airquality$Temp

if (all(temperatura < 50)) {
  
  print("Alguno de los registros tiene temperatura superior a 100 Farenheit")
  
}

  • Solución:
temperatura <- airquality$Temp

if (any(temperatura > 100)) { # nos basta con uno
  
  print("Alguno de los registros tiene temperatura superior a 100 Farenheit")
  
}

No imprime nada porque ninguno cumple la condición.

 

📝Ejercicio 4: del paquete lubridate, la función hour() nos devuelve la hora de una fecha dada, y la función now() nos devuelve fecha y hora del momento actual. Con ambas funciones, y usando if, imprime por pantalla "buenas noches" solo a partir de las 21 horas.

  • Solución:
# Cargamos librería
library(lubridate)

# Fecha-hora actual
fecha_actual <- now()

# Estructura if
if (hour(fecha_actual) > 21) {
  
  cat("Buenas noches") # print/cat dos formas de imprimir por pantalla
}

 

📝Ejercicio 5: con las funciones del ejercicio anterior, y usando una estructura if-else, imprime por pantalla "buenos días" (de 6 a 14 horas), "buenas tardes" (de 14 a 21 horas) o "buenas noches" (de las 21 a las 6 horas).

  • Solución:
# Fecha actual
fecha_actual <- now()

# Estructura if-else
if (hour(fecha_actual) > 6 & hour(fecha_actual) < 14) {
  
  cat("Buenos días")
  
} else if (hour(fecha_actual) > 14 & hour(fecha_actual) < 21) {
  
  cat("Buenas tardes")
  
} else {
  
  cat("Buenas noches")
}
## Buenas noches

 

📝Ejercicio 6: realiza el ejercicio anterior pero sin estructura de llaves, de forma concisa con ifelse(). Mira la ayuda si la necesitases poniendo ? ifelse.

  • Solución:
# Fecha actual
fecha_actual <- now()

# Estructura if-else
cat(ifelse(hour(fecha_actual) > 6 & hour(fecha_actual) < 14,
           "Buenos días",
           ifelse(hour(fecha_actual) > 14 &
                    hour(fecha_actual) < 21,
                  "Buenas tardes", "Buenas noches")))
## Buenas noches