9.2 for

La estructura for nos permite ejecutar un bucle (loop), realizando una operación para cada elemento de un conjunto de datos.

Su estructura es la siguiente:

for(elemento in objeto) {
  operacion_con_elemento
}

Con lo anterior le decimos a R:

  • PARA cada elemento EN un objeto, haz la siguiente operación.

Al escribir un bucle for la parte que corresponde al elemento la podemos llamar como nosotros deseemos, pero la parte que corresponde al objeto debe ser el nombre de un objeto existente.

Los dos bucles siguientes son equivalentes, sólo cambia el nombre que le hemos puesto al elemento.

objeto <- 1:10

for(elemento in objeto) {
  operacion_con_elemento
}

for(i in objeto) {
  operacion_con_elemento
}

Tradicionalmente se usa la letra i para denotar al elemento, pero nosotros usaremos nombres más descriptivos en este capítulo.

9.2.1 Usando for

Vamos a obtener el cuadrado de cada uno de los elementos en un vector numérico del 1 al 6, que representa las caras de un dado.

dado <- 1:6

for(cara in dado) {
  dado ^ 2 
}

Notarás que al ejecutar el código anterior parece que no ha ocurrido nada. En realidad, sí se han realizado las operaciones, pero R no ha devuelto sus resultados.

Las operaciones en un for se realizan pero sus resultados nunca son devueltos automáticamente, es necesario pedirlos de manera explícita.

A diferencia de otros lenguajes de programación en los que pedimos los resultados de un bucle con return(), en R este procedimiento sólo funciona con funciones.

Una solución para mostrar los resultados de un bucle for es usar la función print().

for(cara in dado) {
  print(cara ^ 2)
}
## [1] 1
## [1] 4
## [1] 9
## [1] 16
## [1] 25
## [1] 36

Comprobamos que la operación ha sido realizada a cada elemento de nuestro objeto. Sin embargo, usar print() sólo mostrará los resultados de las operaciones en la consola, no los asignará a un objeto.

Si deseamos asignar los resultados de un bucle for a un objeto, usamos índices.

Aprovechamos que el primer elemento en un bucle siempre es identificado con el número 1 y que continuará realizando operaciones hasta llegar al total de elementos que hemos especificado.

for(numero in 1:10) {
  print(numero)
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
## [1] 9
## [1] 10

En nuestro ejemplo, pasamos por los valores de dado, cara por cara. La primera cara será igual a 1, la segunda a 2, y así sucesivamente hasta el 6.

Podemos usar estos valores para asignar cada valor resultante de nuestras operaciones a una posición específica en un vector, incluso si este está vacio.

Creamos un vector vacío, asignándole como NULL como valor.

mi_vector <- NULL

Ejecutamos nuestro bucle.

for(cara in dado) {
  mi_vector[cara] <- cara ^ 2
}

Aunque no fueron mostrados en la consola, los resultados han sido asignados al objeto mi_vector.

mi_vector
## [1]  1  4  9 16 25 36

9.2.2 for y vectorización

Notarás que el resultado que obtuvimos usando for es el mismo que si vectorizamos la operación.

dado ^ 2
## [1]  1  4  9 16 25 36

Dado que en R contamos con vectorización de operaciones, que podemos usar las funciones de la familia apply (discutido en siguiente capítulo) en objetos diferentes a vectores y que la manera de recuperar los resultados de un for es un tanto laboriosa, este tipo de bucle no es muy popular en R.

En R generalmente hay opciones mejores, en cuanto a simplicidad y velocidad de cómputo, que un bucle for.

Sin embargo, es conveniente que conozcas esta estructura de control, pues hay ocasiones en la que es la mejor herramienta para algunos problemas específicos.