Condicionales

Los condicionales corresponden a una estructura en la cual ejecutaremos una acción si cierta condición es verdadera, y ejecutaremos otra acción para el caso en que dicha condición sea falsa. Para entender de manera más sencilla la idea anterior, consideremos el siguiente ejemplo:

  • Si el semáforo está en verde, entonces no cruzamos la calle. Tenemos en dicho ejemplo que la condición impuesta es “el semáforo está en verde”; si dicha condición es verdadera, entonces no cruzamos la calle; si dicha condición es falsa, cruzaremos la calle. De tal modo realizaremos alguna acción en caso de que la condición impuesta sea o no verdadera.

Así, con el ejemplo del semáforo tendríamos el siguiente diagrama

Podemos implementar condicionales en R siguiendo la siguiente estructura:

if (condicion) {
  acciones a realizar en caso de que la condicion
  sea verdadera
} else {
  acciones a realizar en caso de que la condicion
  sea verdadera
}

Continuando con nuestro ejemplo, escribimos

# Condicion
semaforo_en_verde = TRUE

# Implementamos el condicional if
if (semaforo_en_verde) {
  # Accion a realizar en caso de que la condicion sea verdadera:
  # Imprimieremos un mensaje
  print("No cruzar")
} else {
  # Accion a realizar en caso de que la condicion sea falsa:
  # Imprimieremos un mensaje
  print("Puedes cruzar")
}
## [1] "No cruzar"

Dado que la condición impuesta es verdadera, entonces se ha impreso el mensaje "No cruzar". Veamos ahora el resultado en caso de que la condición sea falsa

# Condicion
semaforo_en_verde = F

# Implementamos el condicional if
if (semaforo_en_verde) {
  # Accion a realizar en caso de que la condicion sea verdadera:
  # Imprimieremos un mensaje
  print("No cruzar")
} else {
  # Accion a realizar en caso de que la condicion sea falsa:
  # Imprimieremos un mensaje
  print("Puedes cruzar")
}
## [1] "Puedes cruzar"

Veamos otro ejemplo práctico. Escribiremos un código para determinar si un número es par o impar. Para ello utilizaremos el siguiente criterio: un número entero \(n\) es par si el residuo de la división \(\frac{n}{2}\) es cero. En caso contrario el número \(n\) será impar, por ejemplo:

  • El residuo de \(\frac{5}{2}\) es 1, donde el 5 es impar.
  • El residuo de \(\frac{6}{2}\) es 0, donde el 6 es impar.

Así:

# Identificador de numeros pares e impares.
# Definimos el numero n:
n = 7

# Implementamos un condicional
if (n %% 2 == 0) {
  print("El número considerado es par")
} else {
  print("El número considerado es impar")
}
## [1] "El número considerado es impar"

donde el símbolo == significa igualdad, pues recordemos que el símbolo = significa asignación. Luego, la condición n %% 2 == 0 puede leerse como: el residuo de dividir n entre 2 es igual a 0. Lo anterior puede ser verdadero o falso, según sea el valor de \(n\), lo cual nos arrojará un booleano (FALSE o TRUE), y con base a él ejecutaremos la acción en caso de que la condición sea verdadera o falsa. Podemos probar el código anterior con diferentes números de n

# Identificador de numeros pares e impares.
# Definimos el numero n:
n = 240

# Implementamos un condicional
if (n %% 2 == 0) {
  print("El número considerado es par")
} else {
  print("El número considerado es impar")
}
## [1] "El número considerado es par"

o también

# Identificador de numeros pares e impares.
# Definimos el numero n:
n = 1179

# Implementamos un condicional
if (n %% 2 == 0) {
  print("El número considerado es par")
} else {
  print("El número considerado es impar")
}
## [1] "El número considerado es impar"

veamos que, cada que queremos utilizar el código para determinar si un número n es par o impar, debemos de escribir de nuevo todo el código del condicional, lo cual no es lo óptimo. Para este tipo de situaciones donde queremos utilizar un mismo código para diferentes valores de una variable, en este caso de la n, podemos implementar el concepto de Función definida por el usuario.

Vistazo rápido a las funciones

Dentro de R existen muchas funciones ya integradas, por ejemplo

# Funcion sample
sample(1:10, 20, replace = T)
##  [1]  3  6  2  3  4  6  3  2  3  2  3  6  2  3  9  7  5  1 10  8
# Funcion para crear un vector c()
v1 <- c(1:100)

# Funcion para calcular el promedio de un vector
mean(v1)
## [1] 50.5

etcétera. Asimismo, podremos definir nuestras propias funciones. Para ello utilizaremos la siguiente estructura:

nombre_de_la_funcion <- function(<<parametros>>){
  <<acciones que realiza la funcion>>
  return(<<valores que regresa la funcion>>)
}

Por ejemplo, en nuestro caso queremos definir una función que, dado un número n, nos diga si el número es par o impar. De tal manera escribimos:

# Definimos nuestra primera funcion
par_impar <- function(n){
  
  # Implementamos un condicional
  if (n %% 2 == 0) {
    
    return("El número considerado es par")
    
  } else {
    
    return("El número considerado es impar")
    
  }
}

donde, dado un valor de n, la función nos regresará un mensaje diciéndonos si el número es par o impar. Algo que es importante de mencionar es que, dentro de R la identación o el “sangrado” de las líneas de código es importante

Esto es, cada estructura en R tiene su propio nivel de identación, además, podemos anidar estructuras (así como lo hicimos colocando dentro de la función un condicional)

Las funciones definidas por el usuario son realmente flexibles y versátiles, lo que nos permite definir muchas, muchas, cosas. Por ejemplo:

# Definimos una funcion que calcule el promedio de un vector
mi_promedio <- function(vector){
  # Calculamos la suma de las entradas del vector
  suma = sum(vector)
  # Calculamos el numero total de entradas del vector
  n = length(vector)
  # Regresamos el promedio del vector
  return(suma / n)
}

# Probemos la funcion:
mi_promedio(c(1,2,3,4,5))
## [1] 3
# Comprobamos
mean(c(1,2,3,4,5))
## [1] 3

Con esta misma idea, podemos definir, tal cual, funciones matemáticas. Por ejemplo, considerando la función \(f(x)=x^{2}\), escribimos

# Definiendo funciones matematicas
f <- function(x){
  return(x ** 2)
}

# Probamos la funcion para distintos valores
f(0)
## [1] 0
f(-5)
## [1] 25
f(25)
## [1] 625

Podemos definir una función que calcule al área de un círculo dependiendo el valor del radio:

area_circ <- function(r){
  return(pi * r ^ 2)
}

# Probamos la funcion
area_circ(5)
## [1] 78.53982

donde

pi
## [1] 3.141593

nos da el valor del número \(\pi\).

Para finalizar, notemos que, dado un vector, podemos acceder de manera individual a cada uno de sus elementos. Por ejemplo

# Definimos un vector
vc <- seq(0, 10, by=2)
vc
## [1]  0  2  4  6  8 10

donde el 0 está en la primera posición del vector; el 2 está en la segunda posición; el 4 está en la tercera posición; y así sucesivamente. Podremos acceder a los elementos de un vector utilizando, el nombre del vector, y corchetes como sigue

# Elemento en la primera posicion
vc[1]
## [1] 0
# Elemento en la segunda posicion
vc[2]
## [1] 2
# Elemento en la quinta posicion
vc[5]
## [1] 8

Adicionalmente, podemos obtener ciertos elementos del vector

# Obtendremos los elementos de la posicion 1 a la posicion 3
vc[1:3]
## [1] 0 2 4

Bucles

Los bucles son estructuras que nos permiten realizar cierta acción de manera repetida. Principalmente tendremos dos tipos de bucles: el bucle for y el bucle while.

  • El bucle for nos permitirá repetir una acción un determinado número de veces.

  • El bucle while nos permitirá repetir una acción mientras cierta condición sea verdadera.

Bucle for

Como su nombre lo indica, el bucle for representa un proceso repetitivo, donde ciertas instrucciones se estarán repitiendo un número determinado de veces. Por ejemplo, consideremos un vector e imprimamos cada uno de sus elementos

# Vector con entradas de varios tipos de datos
vect2 <- c(10, 'nombre', FALSE)
# Podemos imprimir el PRIMER ELEMENTO del vector anterior colocando entre corchetes el numero 1
print(vect2[1])
## [1] "10"
# Imprimimos el segundo elemento
print(vect2[2])
## [1] "nombre"
# Imprimimos el tercer elemento
print(vect2[3])
## [1] "FALSE"

Supongamos que tenemos un vector con 100 entradas y queremos imprimir cada una de ellas. Si realizamos el mismo proceso anterior pero ahora para el vector de 100 entradas, tardaremos un tiempo considerable. Como alternativa podemos utilizar un bucle for cuya estructura básica es:

for (recorrido) {
  acción a repetir
}

Lo que haremos será imprimir cada uno de los elementos del vector vect2 utilizando un bucle for. Notamos que dicho vector tiene en total 3 elementos, de modo que necesitaremos crear un vector:

# Creamos un vector 
vect_recorrido <- 1:3
vect_recorrido
## [1] 1 2 3

el cual tiene los elementos que ocupamos para acceder a todos los elementos del vector vect2. Luego implementamos el for

for (i in vect_recorrido){
  
  # Accion a ejecutar repetidamente
  print(vect2[i])
  
}
## [1] "10"
## [1] "nombre"
## [1] "FALSE"

donde la i es una variable propia del bucle for (y en realidad puede llamarse como sea). La variable del for recorrerá cada elemento del vector vect_recorrido de la siguiente manera:

  • Inicialmente en el bucle la i vale 1 (que es el primer valor del vector vect_recorrido) y así se ejecuta la acción print(vect2[i]), pero i vale 1, por lo cual se ejecuta print(vect2[1]), lo que nos arroja "10".
  • Luego, la i vale 2 (que es el segundo elemento del vector vect_recorrido) y por ello se ejecuta print(vect2[2]) que nos arroja "nombre".
  • Finalmente se ejecuta ``print(vect2[3]) que nos arroja "FALSE".

El bucle finaliza cuando la i recorre todos los elementos de vect_recorrido. Veamos una alternativa del código anterior

# directamente colocamos la secuencia del 1 al 3
for (i in 1:3){
  # Accion a ejecutar repetidamente
  print(vect2[i])
}
## [1] "10"
## [1] "nombre"
## [1] "FALSE"

o también

# directamente colocamos la secuencia del 1 al 3
for (i in 1:length(vect2)){
  # Accion a ejecutar repetidamente
  print(vect2[i])
}
## [1] "10"
## [1] "nombre"
## [1] "FALSE"

Asimismo, directamente podemos recorrer los elementos del vector Vect2 sin la necesidad de acceder a las posiciones con los corchetes:

# Recorremos directamente los elementos de vect2
for (i in vect2){
  # Accion a ejecutar repetidamente
  print(i)
}
## [1] "10"
## [1] "nombre"
## [1] "FALSE"

donde en este caso:

  • Al inicio la i tomará el valor de "10".
  • En la siguiente iteración la i tomará el valor de "nombre".
  • Finalmente la i tomará el valor de "FALSE" y el bucle termina.

Veamos un ejemplo práctico. Lo que haremos será definir un vector sin elementos, y en éste le iremos agregando únicamente los números pares en el rango del 1 al 50:

# Definimos un vector con la secuencia de numeros del 1 al 50
secuencia <- 1:50

# definimos un vector vacio para ir almacenando los numeros pares
pares <- c()

# Implementamos el for que recorrera cada uno de los numeros de la secuencia anterior
for (i in secuencia){
  # Utilizaremos un condicional para detectar los numeros pares
  if (i %% 2 == 0){
    # Si i es par, lo agregamos a la lista pares
    pares = append(pares, i)
  }
}
# Veamos
pares
##  [1]  2  4  6  8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50

donde:

  • Con el bucle for recorrimos todos los elementos del 1 al 50.
  • Con el condicional if filtramos solo los numeros pares. Dichos paremos los agregamos a la lista pares append(pares, i), pero para guardar la lista paremos con los elementos nuevos debemos estar actualizando la variable pares, por lo cual escribimos pares = append(pares, i).
  • El bucle funciona de la siguiente manera:
    • En la primera iteración la i vale 1, como el 1 no es par, entonces pasamos a la siguiente iteración.
    • En la siguiente iteración la i vale 2, como el dos es par, entonces append(pares, i) resulta en el vector c(2). Para guardar ese vector resultanto lo almacenamos en la variable pares.
    • En la cuarta iteración la i vale 4, de modo que append(pares, i) resulta en el vector c(2, 4) y guardamos ese vector en la variable pares.
    • Y así sucesivamente.

Recordemos que definimos la función \(f(x)=x^{2}\). Podemos evaluar con distintos valores de la \(x\) utilizando un bucle for

# Evaluamos la funcion para los numeros del -5 al 5
for (x in seq(-5,5)) {
  print(f(x))
}
## [1] 25
## [1] 16
## [1] 9
## [1] 4
## [1] 1
## [1] 0
## [1] 1
## [1] 4
## [1] 9
## [1] 16
## [1] 25

Bucle while

El bucle while es muy similar al for. El bucle for repite instrucciones un número determinado de veces, pero el bucle while repetirá la instrucción mientras una condición sea verdadera. Cuando dicha condición impuesta sea falsa, el bucle while finalizará. La estructura básica es

while (condicion) {
  acción a repetir mientras la condicion sea verdadera
}

Debemos ser cuidadosos con el bucle while pues si la condición que imponemos nunca sea falsa, entonces, en teoría, el bucle while tampoco se detendrá. Así, dentro del código del while debemos escribir el código necesario para evitar que el bucle while sea “infinito”. Una de las tantas estrategias para hacer que el bucle while se detenga en cierto punto es utilizando la idea de un contador, por ejemplo

contador = 0

# Implementamos el while imponiendo que la condicion a evaluar sea que el contador sea menor a 10
while (contador < 10) {
  # Imprimimos el valor del contador
  print(contador)
  
  # En cada iteracion aumentaremos un 1 el contador
  contador = contador + 1
}
## [1] 0
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
## [1] 9

en la última iteración tenemos que el contador vale 9, después se le sumará un 1 y por ello el valor se actualiza al 10. El bucle while evalúa contador < 10, donde en ese momento el contador vale 10, y como la condición es falsa, entonces el bucle se detiene.

Veamos otros ejemplos

# Definimos la condicion del while
continuar = TRUE

# Definiremos un contador auxiliar
contador <- 0

while (continuar){
  # Imprimimos un mensaje
  print("Hola")
  
  # Aumentaremos en uno el contador
  contador = contador + 1
  
  # Implementamos un condicional para hacer que el
  # bucle no sea infinito
  if (contador == 3){
    continuar = FALSE
  }
}
## [1] "Hola"
## [1] "Hola"
## [1] "Hola"

donde:

  • En la primer iteración la variable continuar es verdadera por lo que se ejecuta print("hola"). Aumentamos en uno el contador, por lo cual contador ahora vale 1. Luego, en el if vemos su contador==3, lo cual es falso pues ahora contador vale 1, de modo que continuar sigue siendo verdadera.
  • En la segunda iteración contador vale 2 y de nuevo se ejecuta print("hola").
  • En la tercera iteración contador vale 3 y de nuevo se ejecuta print("hola"). Pero ahora continuar==3 es verdadera, por lo cual se ejecuta la acción del condicional, así continuar ahora será falsa y por ende el bucle while finaliza. Es usual utilizar variables como contadores para hacer que el bucle while no sea infinito. Abordemos otro ejemplo
# Definimos una variable inicial en 0
suma <- 0

# Definimos un contador
n <- 1

# Ejecutamos un bucle while mientras n sea menor o igual a 100
while (n <= 100){
  # En cada iteracion, a la variable suma le sumaremos el valor actual de la n
  suma = suma + n
  # aumentamos en 1 el valor de la n para que eventualmente el bucle se detenga
  n = n + 1
}

# Veamos el resultado final almacenado en la variable suma
suma
## [1] 5050

donde, con el código anterior hemos obtenido el resultado de

\[ 1+2+3+4+\cdots+100 \] donde dicha suma se suele denotar por \(\sum_{i=1}^{100}i\), esto es:

\[ \sum_{i=1}^{100}i=1+2+3+4+\cdots+100 \]

¿Cómo funciona el bucle while anterior?

  • En la primera iteración n vale 1 y suma vale cero, de modo que el resultado de suma + n es 1, por lo que ahora la variable suma vale 1.
  • En la segunda iteración n vale 2 y suma vale uno, de modo que el resultado de suma + n es \(1+2=3\), por lo que ahora la variable suma vale 3. Hasta ahora el proceso es \(1+2\).
  • En la tercera iteración n vale 3 y suma vale tres, de modo que el resultado de suma + n es \(3+3=6=1+2+3\), por lo que ahora la variable suma vale 3. Hasta ahora el proceso es \(1+2+3\).
  • En la cuarta iteración n vale 4 y suma vale seis, de modo que el resultado de suma + n es \(6+4=10=1+2+3+4\), por lo que ahora la variable suma vale 3. Hasta ahora el proceso es \(1+2+3+4\).

Y así sucesivamente, lo cual nos da como resultado \(\sum_{i=1}^{100}i=1+2+3+4+\cdots+100\). Podemos utilizar un bucle while para hallar el valor de

\[ \sum_{i=1}^{100}(2\cdot i+4)=[2\cdot (1)+4]+[2\cdot (2)+4]+[2\cdot (3)+4]+\cdots+[2\cdot (100)+4] \] escribiendo

# Definimos una variable inicial en 0
suma <- 0

# Definimos un contador
n <- 1

# Ejecutamos un bucle while mientras n sea menor o igual a 100
while (n <= 100){
  # En cada iteracion, a la variable suma le sumaremos el valor de 2*n + 4
  suma = suma + 2 * n + 4
  # aumentamos en 1 el valor de la n para que eventualmente el bucle se detenga
  n = n + 1
}

# Veamos el resultado final almacenado en la variable suma
suma
## [1] 10500

También podemos calcular

\[ \sum_{i=1}^{100}i^{2}=1^{2}+2^{2}+\cdots+100^{2} \] escribiendo

# Definimos una variable inicial en 0
suma <- 0

# Definimos un contador
n <- 1

# Ejecutamos un bucle while mientras n sea menor o igual a 100
while (n <= 100){
  # En cada iteracion, a la variable suma le sumaremos el valor n al cuadrado
  suma = suma + (n ^ 2)
  # aumentamos en 1 el valor de la n para que eventualmente el bucle se detenga
  n = n + 1
}

# Veamos el resultado final almacenado en la variable suma
suma
## [1] 338350

Entro otros muchos ejemplos. Es preciso mencionar que, respecto a la notación, la \(i\) de las sumas la representamos por la n del código, realmente no importa el nombre que le demos a la \(i\) o a la n. No obstante, para que sea más concerde la notación, podemos escribir

# Definimos una variable inicial en 0
suma <- 0

# Definimos un contador
i <- 1

# Ejecutamos un bucle while mientras n sea menor o igual a 100
while (i <= 100){
  # En cada iteracion, a la variable suma le sumaremos el valor n al cuadrado
  suma = suma + (i ^ 2)
  # aumentamos en 1 el valor de la n para que eventualmente el bucle se detenga
  i = i + 1
}

# Veamos el resultado final almacenado en la variable suma
suma
## [1] 338350

En resumen vemos que el funcionamiento del while y del for son muy similares.

Ejercicios

  1. Define una función que reciba como parámetro un número n. Luego, implementa dentro de dicha función un condicional que actúe de la siguiente manera: si el número n es mayor a 5, la función nos deberá regresar el mensaje "El número que ingresaste es mayor a 5". Si el número es menor o igual a 5, entonces deberá regresar un mensaje indicando justamente eso.

  2. Define una función para calcular el área de un cuadrado dependiendo la longitud de su lado.

  3. Define una función de dos parámetros para calcular el área y el perímetro de un rectángulo. Para retornar el resultado deberás de utilizar return(paste(...)), donde en paste(...) deberás combinar cadenas de texto y los valores obtenidos del área y el perímetro.

  4. Define una función que reciba como parámetros dos vectores y que retorne la unión por filas (u horizontal) de dichos vectores.

  5. Define en código la función matemática \(f(x)=3x^{3}+2x^{2}-1\).

Observación: Deberás probar todas las funciones que definas.

  1. Calcula el valor de \(\sum_{i=1}^{50}i^{3}\) y \(\sum_{i=}^{50}(2\cdot i - 3)\), utilizando bucles while.

  2. Crea un vector aleatorio de 20 entradas y recorre cada uno de sus elementos utilizando un bucle for.

  3. Crea una función que reciba como parámetro un vector con entradas de números enteros (e.j. c(1,2,3)). Dentro de tu función define una lista vacía y mediante un bucle for recorre todos los elementos del vector que se ingresó como parámetro y agrega a la lista vacía que creaste aquellos números que sean pares. La función deberá regresar la lista con los números pares del vector que se ingresó.

El “esqueleto” de lo que se te pide en el ejercicio anterior es:

tu_funcion <- function(vector_parametro){
  # Defines el vector vacio
  vect_vacio <- c()
  
  # Recorres el vector vector_parametro
  for (i in vector_parametro) {
    # con un if filtras los elementos del vector vector_parametro que sean numeros pares y los agregas al vector vacio
    if (condition) {
      # implementa el codico para hacer el filtro y agregar los pares al vector vect_vacio
    }
  }
  return(vect_vacio)
}