Chapter 10 LOOP FOR E IF ELSE PARA MÁS DE UN ELEMENTO.
En este capítulo se se mostrará como usar el loop for
que nos permitirá realizar múltiples procesos con una sencilla sintaxis. Asimismo, gracias al loop for
podremos evaluar más de un elemento al usar las condicionales if else
. Por último, veremos el uso de la función ifelse()
que nos otorgará el mismo resultado que si usaramos el loop for
con las condicionales if else
.
10.1 Loop for.
Gracias al loop for
podremos realizar tareas similares automáticamente. El loop permite hacer el recorrido de todos los elementos de un vector con el fin de asignar a la operación procedente cada uno de los elementos del recorrido. La sintaxis del loop for
es la siguiente:
for (var in seq) {expression}
Donde se le asigna un iterador (var
), que puede ser cualquier letra o palabra, que hará el recorrido por el vector (seq
) para asignar cada elemento de este en la expresión
.
El iterador puede jugar el papel de objeto o de subobjeto, es decir, en el primer caso el iterador entra en la expresión como un objeto que será argumento de una función, en el segundo caso el iterador entra como un subobjeto de otro objeto y en conjunto servirán de argumento de una función.
10.1.1 El iterador como objeto.
Veamos un ejemplo para que quede más claro. Vamos a imprimir el siguiente texto “Este es el número: …”, en los tres puntos asignaremos los números desde el 1 al 10.
# Usando el loop for.
for (i in 1:10) {
print(paste0("Este es el número: ",i))
}
## [1] "Este es el número: 1"
## [1] "Este es el número: 2"
## [1] "Este es el número: 3"
## [1] "Este es el número: 4"
## [1] "Este es el número: 5"
## [1] "Este es el número: 6"
## [1] "Este es el número: 7"
## [1] "Este es el número: 8"
## [1] "Este es el número: 9"
## [1] "Este es el número: 10"
Primero, hemos asignado un iterador llamado i
que hará el recorrido por todos los elementos del vector 1:10
, cada elemento lo usará en la ejecución de la expresión print(paste0("Este es el número: ",i))
, es decir, el iterador i
tomará cada uno de los elementos del vector 1:10
y los asignará en la expresión print(paste0("Este es el número: ",i))
.
Gracias a esto hemos obtenido el resultado esperado en donde se ha impreso el texto “Este es el número: 1”, “Este es el número: 2”, y así sucesivamente hasta “Este es el número: 10”.
Como se habrá podida dar cuenta una de las características principales del loop for
en R es su sencilles para su uso. Se le invita a realizar la misma operación en otros softwares1 y verá la diferencia.
10.1.2 El iterador como un subobjeto.
Ahora veamos un ejemplo en donde el vector por donde se hará el recorrido es una vector caracter.
# Ejemplo usando un vector caracter.
<-c("Azul","Rojo","Amarillo","Rosado","Marrón")
x
for (i in 1:length(x)) {
print(paste0("Este es el color: ",x[i]))
}
## [1] "Este es el color: Azul"
## [1] "Este es el color: Rojo"
## [1] "Este es el color: Amarillo"
## [1] "Este es el color: Rosado"
## [1] "Este es el color: Marrón"
En esta ocasión hemos complicado un poco el uso, pero con el fin de que usted se de cuenta que el iterador también puede ser usado como un subobjeto, en este caso el iterador i
es un subobjeto del objeto x
.
Primero, se ha definido el vector x
con los nombres: “Azul”,“Rojo”,“Amarillo”,“Rosado”,“Marrón”. Posteriormente, en la sintaxis del loop for
se ha asignado un iterador llamado i
que hará el recorrido por el vector 1:length(x)
, es decir, desde el número 1 hasta el tamaño del vector x
(desde 1 al 5). Cada uno de estos elementos se asignarán en la expresión x[i]
(llamará a cada uno de los elementos del vector x
, desde el primero al último, ya que se convertirá en x[1]
, x[2]
, x[3]
, x[4]
y x[5]
).
Lo principal de este ejemplo, es darse cuenta de la importancia que juega el iterador que ya no solo juega el papel de objeto, como en el primer ejemplo, sino como subobjeto de otro objeto.
Quizá le parezca un poco complicado al inicio, pero como se comentó al inicio este loop puede ser escrito de una manera más sencilla, a continuación, se muestra la sintaxis.
# El ejemplo 2 con una sintaxis más sencilla.
for (i in x) {
print(paste0("Este es el color: ", i))
}
## [1] "Este es el color: Azul"
## [1] "Este es el color: Rojo"
## [1] "Este es el color: Amarillo"
## [1] "Este es el color: Rosado"
## [1] "Este es el color: Marrón"
En este caso se puede observar que el iterador juega el papel de objeto. ¿Cómo así? El iterador i
recorrerá el vector x
, es decir, todos los elementos de x
(“Azul”,“Rojo”,“Amarillo”,“Rosado”,“Marrón”) y los asignará en la expresión print(paste0("Este es el color: ", i))
.
Usted se puede estar preguntando ¿Cuál es el fin de colocar al iterador como subobjeto si la sintaxis es más sencilla considerando al iterador como objeto? En el ejemplo que hemos visto y por su sencilles es más fácil usar al iterador como objeto, pero cuando avancemos más y deseemos hacer loops más complicados en donde haya más de un iterador o dentro de funciones, tendremos que usar al iterador como subobjeto. Así que por el momento es preciso aprender las dos formas.
Avancemos un poco más y realicemos un ejemplo un poquillo más complicado.
Vamos a realizar un loop en el cual se guardan los resultados en un vector externo.
# Guardando los resultados en un vector externo.
<-c()
xfor (t in 1:5) {
<-t^2
y<-c(x,y)
x }
Primero hemos creado un vector vacio x
donde guardaremos los resultados del loop, posteriormente en el loop for
se asigna el iterador t
que hará el recorrido por el vector 1:5
, asignando cada elemento en la expresión y<-t^2; x<-c(x,y)
. Lo que hará será elevar los elementos del vector 1:5
al cuadrado y guardarlo en el objeto y
. En la expresión x<-c(x,y)
le decimos al software que guarde en el objeto x
el vector que se genera al juntar el objeto x
con el objeto y
. Como el valor de y
cambiará con cada elemento ya que el iterador tomará uno por uno los elementos del vector 1:5
, entonces, es preciso guardar cada resultado.
Para observar que se ha guardado en el objeto x
corramos este vector.
x
## [1] 1 4 9 16 25
Como se puede dar cuenta el vector x
tiene los elementos 1, 4, 9, 16, 25 que resultan al elevar cada elementos del vector 1:5
al cuadrado.
Usted puede ser perpicaz y al haber leído todos los capítulos de este libro, usted puede decir que el resultado anterior saldría solo con ejecutar (1:5)^2
. En efecto, sí, el resultado es el mismo, pero repito, por el momento estamos haciendo ejemplos muy sencillos para que se tenga una total comprensión de los usos del loop for
.
10.2 El loop for con las condicionales if else.
Usted recuerda del capítulo anterior la unicidad de las condicionales if else
, el cual implicaba que solo se evaluara el primer elemento de un vector. Ahora gracias al loop for
podremos evaluar todos los elementos del vector.
Veamos un ejemplo en donde se da a conocer el problema y cómo podríamos solucionar esto usando el loop for
.
El ejemplo es el siguiente, queremos saber que elementos del vector p
son menores a 30, y si es así que imprima los elementos. Es obvio que tenemos que usar la condicional if
.
# Creando el vector p.
set.seed(3000)
<-sample(20:50, 20, T)
p
# El vector p tiene los elementos.
p
## [1] 42 49 34 26 34 44 29 30 40 42 38 30 36 22 42 21 46 21 28 34
# Realizando la condicional if.
if(p<30){
print(p)
}
# Error in if (p < 30) { : the condition has length > 1
¿Cómo es posible que no haya impreso ningún elemento? Como se mencionó, la condicional if
sólo evaluó el primer elemento del vector p
y este al no ser 42 menor que 30, nos resulta que la prueba lógica p<30
es FALSE
por lo cual no ejecuta el proceso print(p)
.
Entonces, estamos atados de manos, pero usted puede observar una posible solución usando la siguiente sintaxis:
if(p[1]<30){
print(p)
}
if(p[2]<30){
print(p)
}
if(p[3]<30){
print(p)
}
# Así sucesivamente hasta
if(p[20]<30){
print(p)
}
Pero esto no es para nade eficiente, y sería un demente si pierde su tiempo escribiendo esa sintaxis.
Entonces, nuestra salvación es el loop for
. A continuación se muestra la sintaxis usando al iterador como un objeto.
# Resolviendo el problema usando el loop for.
for (i in p) {
if(i<30){
print(i)
} }
## [1] 26
## [1] 29
## [1] 22
## [1] 21
## [1] 21
## [1] 28
Y a continuación la solución usando al iterador como un subobjeto.
# Resolviendo el problema usando el loop for.
for (i in 1:length(p)) {
if(p[i]<30){
print(p[i])
} }
## [1] 26
## [1] 29
## [1] 22
## [1] 21
## [1] 21
## [1] 28
Con estas soluciones se puede observar el tiempo que nos hemos ahorrado si sabemos usar correctamente el loop for
.
Ahora veamos otro ejemplo en donde tenemos el vector sexo que tiene 30 elementos que pueden ser 0 y 1. Asimismo, nos indican que 0 indica que el sexo es femenino y que 1 indica que el sexo es masculino. Entonces, nos piden que cambiemos los 0 y 1 por los nombres femenino y masculino.
Con los conocimientos que tenemos podemos aplicar el loop for de la siguiente manera.
# creando el vector sexo.
set.seed(2021)
<-sample(0:1, 30, T)
sexo
# Los elementos del vector sexo.
sexo
## [1] 0 1 1 1 0 1 1 1 1 1 0 1 1 0 0 0 0 0 1 0 1 1 0 1 0 0 1 1 1 1
# Aplicando el loop for.
for (i in 1:length(sexo)) {
if(sexo[i]==0){
<-"Femenino"
sexo[i]else if (sexo[i]==1){
} <-"Masculino"
sexo[i]
} }
Estamos usando el método donde se considera al iterador como subobjeto ¿Le invitamos a realizar el mismo ejericio pero usando el iterador como objeto? ¿Con qué método le resultó más fácil?
Viendo como quedó el vector sexo
luego de aplicar el loop for
.
sexo
## [1] "Femenino" "Masculino" "Masculino" "Masculino" "Femenino" "Masculino"
## [7] "Masculino" "Masculino" "Masculino" "Masculino" "Femenino" "Masculino"
## [13] "Masculino" "Femenino" "Femenino" "Femenino" "Femenino" "Femenino"
## [19] "Masculino" "Femenino" "Masculino" "Masculino" "Femenino" "Masculino"
## [25] "Femenino" "Femenino" "Masculino" "Masculino" "Masculino" "Masculino"
En efecto, todos los elementos que eran 0 se han cambiado por “Femenino” y todos los que era 1 se han cambiado por “Masculino”.
Estoy seguro que usted se está preguntando ¿Todo eso para cambiar los 0 por “Femenino” y los 1 por “Masculino”? En realidad sí. ¿Pero si con otros softwares se obtiene el mismo resultado muchó más fácil? En realidad sí. Pero repito, aquí estamos viendo las formas de usar el loop for
con la condicional if else
. Esto que parece innecesario, a la hora de aplicarlo a matrices, listas o dataframe será tan útil y verá la facilidad con lo que resuelve futuras cuestiones. Veremos estas aplicaciones más útiles cuando completemos el tema de data frame, por el momento, será suficiente con conocer como se aplica el loop con sus dos variantes. Pero sí ha quedado insatisfecho, a continuación, se muestra como resolver este tipo de cuestiones usando la función ifelse()
.
10.3 Función ifelse().
Una forma de realizar el proceso anterior sin la necesidad de usar el loop for
explícitamente y sin tanto código, es usar la función ifelse()
, el cuál realiza el loop for
implícitamente y resulta muchísimo más sencillo de usar. Pero como todo proceso que genere simplicidad, solo servirá para un número pequeño de aplicaciones, por lo cual, no englobará en al loop for
.
Vamos a realizar el mismo ejercicio que el anterior.
# creando el vector sexo.
set.seed(2021)
<-sample(0:1, 30, T)
sexo
# Los elementos del vector sexo.
sexo
## [1] 0 1 1 1 0 1 1 1 1 1 0 1 1 0 0 0 0 0 1 0 1 1 0 1 0 0 1 1 1 1
# Resolviendo con la función ifelse.
ifelse(sexo==0,"Femenino","Masculino")
## [1] "Femenino" "Masculino" "Masculino" "Masculino" "Femenino" "Masculino"
## [7] "Masculino" "Masculino" "Masculino" "Masculino" "Femenino" "Masculino"
## [13] "Masculino" "Femenino" "Femenino" "Femenino" "Femenino" "Femenino"
## [19] "Masculino" "Femenino" "Masculino" "Masculino" "Femenino" "Masculino"
## [25] "Femenino" "Femenino" "Masculino" "Masculino" "Masculino" "Masculino"
Y en efecto, hemos obtenido el mismo resultado.
¿Cómo se hizo?
La función ifelse()
tiene la siguiente sintaxis.
ifelse(test, yes, no)
En donde el primero argumento test
es una prueba lógica que puede ser TRUE o FALSE; el segundo argumento yes
es el valor que retornará la función si el test
resulta TRUE; por último, el argumento no
es el valor que retornará la función si el test
resulta FALSE.
En ese sentido, la prueba lógica o test
en nuestro ejemplo fue sexo==0
, en yes
hemos asignado el valor de “Femenino” y en no
el valor de “Masculino”, lo que implica que si la variable sexo==0
es TRUE, entonces asignará “Femenino”, pero si es FALSE asignará “Masculino”.
El uso de esta función es muy sencilla y puede anidarla. Para observar un pequeño ejemplo supongamos que tenemos el vector civil, el cual tiene elementos entre 0, 1 y 2. Y nos indican que 0 es soltero, 1 casado y 2 viudo.
# Creando el vector civil.
set.seed(2021)
<-sample(0:2, 20, T)
civil
# Viendo los elementos del vector civil.
civil
## [1] 2 1 1 1 2 1 1 2 1 1 0 2 2 0 2 2 1 2 0 2
# Resolviendo el problema usando la función ifelse.
ifelse(civil==0, "Soltero",
ifelse(civil==1, "Casado", "viudo"))
## [1] "viudo" "Casado" "Casado" "Casado" "viudo" "Casado" "Casado"
## [8] "viudo" "Casado" "Casado" "Soltero" "viudo" "viudo" "Soltero"
## [15] "viudo" "viudo" "Casado" "viudo" "Soltero" "viudo"
En efecto, hemos obtenido el resultado esperado. Cuando se vea los capítulos del paquete dplyr
se mostrará el uso de la función case_when()
que realiza el mismo procedimiento que la función ifelse()
, pero con una menor sintaxis y con código más limpio y entendible.
10.4 Declaración Break y Next.
En R se tiene las declaraciones break
y next
. La declaración break
nos permite detener el loop for
o el ciclo while
2, mientras que la declaración next
nos permite saltar una deteminada iteración en el loop for
. Veamos a continuación la aplicación de cada uno.
Como se mencionó la declaración break
detiene el loop for
siempre y cuando una determinada condición lógica sea TRUE
. Por ejemplo, vamos a imprimir las letras del abecedario hasta la letra H. Una vez que se ha impreso la letra H que se detenga el loop for
.
Para esto vamos a usar la función LETTERS
que nos arroja las letras del abecedario en mayúscula.
# Las letras del abecedario en mayúscula.
LETTERS
## [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S"
## [20] "T" "U" "V" "W" "X" "Y" "Z"
# Construyendo el loop for.
for (i in LETTERS) {
if(i=="H"){
print(i)
break
else {
} print(i)
} }
## [1] "A"
## [1] "B"
## [1] "C"
## [1] "D"
## [1] "E"
## [1] "F"
## [1] "G"
## [1] "H"
En efecto, solo se ha impreso hasta la letra “H”. Pero ¿cómo sucedió? Primero, si nosotros no consideramos a la declaración break
el loop for
hubiese impreso todas las letras del abecedario. Entonces, al incluir el break
le decimos al software que cuando el iterador sea igual a “H” entonces imprima la letra de la iteración y que detenga el loop. Ahora, si no se cumple la condión, entonces que imprima la letra de la iteración. Es así que cuando el iterador vale “H” se cumple la condición entonces imprime “H” y detiene el loop.
Por otro lado, la declaración next
nos permite saltar la iteración siempre y cuando la condición lógica sea TRUE
. Veamos un ejemplo para ver su aplicación.
Por ejemplo, vamos a ser el mismo loop que en el ejemplo anterior, pero ahora vamos a saltar la iteración, siempre y cuando la iteracción sea igual a la letra “H”. Es decir, si la iteración es igual a “H” entonces no será impreso.
for (i in LETTERS) {
if(i=="H"){
next
else {
} print(i)
} }
## [1] "A"
## [1] "B"
## [1] "C"
## [1] "D"
## [1] "E"
## [1] "F"
## [1] "G"
## [1] "I"
## [1] "J"
## [1] "K"
## [1] "L"
## [1] "M"
## [1] "N"
## [1] "O"
## [1] "P"
## [1] "Q"
## [1] "R"
## [1] "S"
## [1] "T"
## [1] "U"
## [1] "V"
## [1] "W"
## [1] "X"
## [1] "Y"
## [1] "Z"
Y en efecto, no se ha impreso la letra “H” y esto sucede porque en la sintaxis indicamos que si el iterador es igual a “H” entonces ejecute next
, es decir, no imprima a la letra “H”.
En el siguiente capítulo veremos el tema del ciclo while()
que es complementario al ciclo for()
. Este ciclo, también usa las declaraciones next
y break
, incluso, su aplicación es más útil que en el loop for()
.