3.1 Explicación
3.1.1 Loops
Un loop es una estructura de código que nos permite aplicar iterativamente un mismo conjunto de comandos, variando el valor de una variable. Por ejemplo:
## [1] 1
## [1] 4
## [1] 9
## [1] 16
## [1] 25
## [1] 36
## [1] 49
## [1] 64
## [1] 81
## [1] 100
Esto se lee como : “Recorre cada uno de los valores (i) del vector numérico 1 a 10, y para cada uno de ellos imprimí el cuadrado (i^2)”.
Uno puede especificar la palabra que desee que tomé cada uno de los valores que debe tomar. En el ejemplo anterior fue i, pero bien podría ser la “Valores”
## [1] 1
## [1] 4
## [1] 9
## [1] 16
## [1] 25
## [1] 36
## [1] 49
## [1] 64
## [1] 81
## [1] 100
Un loop puede iterar sobre cualquier tipo de vector, independientemente de lo que contenga.
Los loops son una estructura básica que existen en cualquier lenguaje de programación. En R no recomendamos abusar de ellos porque hacen que el código sea más lento.
3.1.2 Estructuras Condicionales
Las estructuras condiconales nos permiten ejecutar una porción de código en caso de que cumplan una condición lógica
3.1.2.1 if
Su funcionamiento es el siguiente:
if(condicion){codigo a ejecutar si se cumple la condición}
## [1] "Menos Mal"
3.1.2.2 ifelse
La función if_else()
sirve para crear o modificar dicotómicamente un objeto/variable/vector a partir del cumplimiento de una o más condiciones lógicas.
Su funcionamiento es el siguiente:
if_else(condicion,función a aplicar si se cumple la condición,función a aplicar si no se cumple la condición)
## [1] "Joya"
3.1.3 Funciones
La creación de funciones propias nos permite automatizar todas aquellas partes del código que se repiten mucho. Una vez diseñadas, funcionan igual que cualquier comando.
Por ejemplo, podemos definir la suma de dos elementos como
## [1] 11
Obviamente las funciones no son sólo para variables numéricas. Por ejemplo, podemos pegar dos strings con una flecha en el medio
funcion_prueba <- function(parametro1,parametro2) {
paste(parametro1, parametro2, sep = " <--> ")
}
funcion_prueba(parametro1 = "A ver", parametro2 = "Que pasa")
## [1] "A ver <--> Que pasa"
También podemos asignar un valor por default para los parametros en caso de que el usuario no defina su valor al utilizar la función.
Otra_funcion_prueba <- function(parametro1 ,parametro2 = "String default") {
paste(parametro1, parametro2, sep = " <--> ")
}
Otra_funcion_prueba(parametro1 = "Valor 1 ")
## [1] "Valor 1 <--> String default"
Las funciones que creamos nosotros permanecen en el ambiente de R temporariamente. Cuando removemos los objetos del ambiente, la función deja de existir. Por ende, debemos incorporarla en cada uno de los scripts en la cual la necesitemos. Una buena práctica, es incorporar nuestras funciones útiles al comienzo de cada script junto a la carga de las librerías.
Vale mencionar que lo que ocurre en una función, queda en la función excepto que explícitamente pidamos que devuelva el resultado, con el comando print()
.
Las funciones siempre devuelven el último objeto que se crea en ellas, o si explicitamente se utiliza el comando return()
3.1.4 PURRR3
MAP es la forma tidy de hacer loops. Además de ser más prolijo el código, es mucho más eficiente.
La función map toma un input, una función para aplicar, y alguna otra cosa (por ejemplo parametros que necesite la función)
- map(.x, .f, …)
- map(VECTOR_O_LIST_INPUT, FUNCTION_A_APLICAR, OTROS_OPCIONALES)
Usamos map2 cuando tenemos que pasar dos input, que se aplican sobre una función:
- map2(.x, .y, .f, …)
- map2(INPUT_UNO, INPUT_DOS, FUNCTION_A_APLICAR, OTROS_OPCIONALES)
Si tenemos más de dos…
- pmap(.l, .f, …)
- pmap(VECTOR_O_LIST_INPUT, FUNCTION_A_APLICAR, OTROS_OPCIONALES)
Por ejemplo. Si queremos utilizar la función prueba sobre los datos del dataframe ABC_123
## function(parametro1,parametro2) {
## paste(parametro1, parametro2, sep = " <--> ")
## }
Si el resultado que queremos es que junte cada fila, necesitamos pasarle dos parámetros: utilizamos map2()
## [[1]]
## [1] "A <--> 1"
##
## [[2]]
## [1] "B <--> 2"
##
## [[3]]
## [1] "C <--> 3"
La salida de los map()
es una lista, no un vector, por lo que si lo metemos dentro de un dataframe se vería así:
## Letras Num resultado
## 1 A 1 A <--> 1
## 2 B 2 B <--> 2
## 3 C 3 C <--> 3
## 4 D 4 D <--> 4
## 5 E 5 E <--> 5
## 6 F 6 F <--> 6
## 7 G 7 G <--> 7
## 8 H 8 H <--> 8
## 9 I 9 I <--> 9
## 10 J 10 J <--> 10
## 11 K 11 K <--> 11
## 12 L 12 L <--> 12
## 13 M 13 M <--> 13
## 14 N 14 N <--> 14
## 15 O 15 O <--> 15
## 16 P 16 P <--> 16
## 17 Q 17 Q <--> 17
## 18 R 18 R <--> 18
## 19 S 19 S <--> 19
## 20 T 20 T <--> 20
al ponerlo dentro del dataframe desarma la lista y guarda cada elemento por separado. La magia de eso es que podemos guardar cualquier cosa en el dataframe no sólo valores, sino también listas, funciones, dataframes, etc.
Si queremos recuperar los valores originales en este caso podemos usar unlist()
## [1] "A <--> 1" "B <--> 2" "C <--> 3"
## Letras Num resultado
## 1 A 1 A <--> 1
## 2 B 2 B <--> 2
## 3 C 3 C <--> 3
## 4 D 4 D <--> 4
## 5 E 5 E <--> 5
## 6 F 6 F <--> 6
## 7 G 7 G <--> 7
## 8 H 8 H <--> 8
## 9 I 9 I <--> 9
## 10 J 10 J <--> 10
## 11 K 11 K <--> 11
## 12 L 12 L <--> 12
## 13 M 13 M <--> 13
## 14 N 14 N <--> 14
## 15 O 15 O <--> 15
## 16 P 16 P <--> 16
## 17 Q 17 Q <--> 17
## 18 R 18 R <--> 18
## 19 S 19 S <--> 19
## 20 T 20 T <--> 20
Si lo que queríamos era que la función nos haga todas las combinaciones de letras y número, entonces lo que necesitamos es pasarle el segúndo parametro como algo fijo, poniendolo después de la función.
## [[1]]
## [1] "A <--> 1" "A <--> 2" "A <--> 3" "A <--> 4" "A <--> 5"
## [6] "A <--> 6" "A <--> 7" "A <--> 8" "A <--> 9" "A <--> 10"
## [11] "A <--> 11" "A <--> 12" "A <--> 13" "A <--> 14" "A <--> 15"
## [16] "A <--> 16" "A <--> 17" "A <--> 18" "A <--> 19" "A <--> 20"
##
## [[2]]
## [1] "B <--> 1" "B <--> 2" "B <--> 3" "B <--> 4" "B <--> 5"
## [6] "B <--> 6" "B <--> 7" "B <--> 8" "B <--> 9" "B <--> 10"
## [11] "B <--> 11" "B <--> 12" "B <--> 13" "B <--> 14" "B <--> 15"
## [16] "B <--> 16" "B <--> 17" "B <--> 18" "B <--> 19" "B <--> 20"
En este caso, el map itera sobre cada elemento de letras
, y para cada elemento i hace
funcion_prueba(i,ABC$Num)
y guarda el resultado en la lista
si lo queremos meter en el dataframe
## Letras Num
## 1 A 1
## 2 B 2
## 3 C 3
## 4 D 4
## 5 E 5
## 6 F 6
## 7 G 7
## 8 H 8
## 9 I 9
## 10 J 10
## 11 K 11
## 12 L 12
## 13 M 13
## 14 N 14
## 15 O 15
## 16 P 16
## 17 Q 17
## 18 R 18
## 19 S 19
## 20 T 20
## resultado
## 1 A <--> 1, A <--> 2, A <--> 3, A <--> 4, A <--> 5, A <--> 6, A <--> 7, A <--> 8, A <--> 9, A <--> 10, A <--> 11, A <--> 12, A <--> 13, A <--> 14, A <--> 15, A <--> 16, A <--> 17, A <--> 18, A <--> 19, A <--> 20
## 2 B <--> 1, B <--> 2, B <--> 3, B <--> 4, B <--> 5, B <--> 6, B <--> 7, B <--> 8, B <--> 9, B <--> 10, B <--> 11, B <--> 12, B <--> 13, B <--> 14, B <--> 15, B <--> 16, B <--> 17, B <--> 18, B <--> 19, B <--> 20
## 3 C <--> 1, C <--> 2, C <--> 3, C <--> 4, C <--> 5, C <--> 6, C <--> 7, C <--> 8, C <--> 9, C <--> 10, C <--> 11, C <--> 12, C <--> 13, C <--> 14, C <--> 15, C <--> 16, C <--> 17, C <--> 18, C <--> 19, C <--> 20
## 4 D <--> 1, D <--> 2, D <--> 3, D <--> 4, D <--> 5, D <--> 6, D <--> 7, D <--> 8, D <--> 9, D <--> 10, D <--> 11, D <--> 12, D <--> 13, D <--> 14, D <--> 15, D <--> 16, D <--> 17, D <--> 18, D <--> 19, D <--> 20
## 5 E <--> 1, E <--> 2, E <--> 3, E <--> 4, E <--> 5, E <--> 6, E <--> 7, E <--> 8, E <--> 9, E <--> 10, E <--> 11, E <--> 12, E <--> 13, E <--> 14, E <--> 15, E <--> 16, E <--> 17, E <--> 18, E <--> 19, E <--> 20
## 6 F <--> 1, F <--> 2, F <--> 3, F <--> 4, F <--> 5, F <--> 6, F <--> 7, F <--> 8, F <--> 9, F <--> 10, F <--> 11, F <--> 12, F <--> 13, F <--> 14, F <--> 15, F <--> 16, F <--> 17, F <--> 18, F <--> 19, F <--> 20
## 7 G <--> 1, G <--> 2, G <--> 3, G <--> 4, G <--> 5, G <--> 6, G <--> 7, G <--> 8, G <--> 9, G <--> 10, G <--> 11, G <--> 12, G <--> 13, G <--> 14, G <--> 15, G <--> 16, G <--> 17, G <--> 18, G <--> 19, G <--> 20
## 8 H <--> 1, H <--> 2, H <--> 3, H <--> 4, H <--> 5, H <--> 6, H <--> 7, H <--> 8, H <--> 9, H <--> 10, H <--> 11, H <--> 12, H <--> 13, H <--> 14, H <--> 15, H <--> 16, H <--> 17, H <--> 18, H <--> 19, H <--> 20
## 9 I <--> 1, I <--> 2, I <--> 3, I <--> 4, I <--> 5, I <--> 6, I <--> 7, I <--> 8, I <--> 9, I <--> 10, I <--> 11, I <--> 12, I <--> 13, I <--> 14, I <--> 15, I <--> 16, I <--> 17, I <--> 18, I <--> 19, I <--> 20
## 10 J <--> 1, J <--> 2, J <--> 3, J <--> 4, J <--> 5, J <--> 6, J <--> 7, J <--> 8, J <--> 9, J <--> 10, J <--> 11, J <--> 12, J <--> 13, J <--> 14, J <--> 15, J <--> 16, J <--> 17, J <--> 18, J <--> 19, J <--> 20
## 11 K <--> 1, K <--> 2, K <--> 3, K <--> 4, K <--> 5, K <--> 6, K <--> 7, K <--> 8, K <--> 9, K <--> 10, K <--> 11, K <--> 12, K <--> 13, K <--> 14, K <--> 15, K <--> 16, K <--> 17, K <--> 18, K <--> 19, K <--> 20
## 12 L <--> 1, L <--> 2, L <--> 3, L <--> 4, L <--> 5, L <--> 6, L <--> 7, L <--> 8, L <--> 9, L <--> 10, L <--> 11, L <--> 12, L <--> 13, L <--> 14, L <--> 15, L <--> 16, L <--> 17, L <--> 18, L <--> 19, L <--> 20
## 13 M <--> 1, M <--> 2, M <--> 3, M <--> 4, M <--> 5, M <--> 6, M <--> 7, M <--> 8, M <--> 9, M <--> 10, M <--> 11, M <--> 12, M <--> 13, M <--> 14, M <--> 15, M <--> 16, M <--> 17, M <--> 18, M <--> 19, M <--> 20
## 14 N <--> 1, N <--> 2, N <--> 3, N <--> 4, N <--> 5, N <--> 6, N <--> 7, N <--> 8, N <--> 9, N <--> 10, N <--> 11, N <--> 12, N <--> 13, N <--> 14, N <--> 15, N <--> 16, N <--> 17, N <--> 18, N <--> 19, N <--> 20
## 15 O <--> 1, O <--> 2, O <--> 3, O <--> 4, O <--> 5, O <--> 6, O <--> 7, O <--> 8, O <--> 9, O <--> 10, O <--> 11, O <--> 12, O <--> 13, O <--> 14, O <--> 15, O <--> 16, O <--> 17, O <--> 18, O <--> 19, O <--> 20
## 16 P <--> 1, P <--> 2, P <--> 3, P <--> 4, P <--> 5, P <--> 6, P <--> 7, P <--> 8, P <--> 9, P <--> 10, P <--> 11, P <--> 12, P <--> 13, P <--> 14, P <--> 15, P <--> 16, P <--> 17, P <--> 18, P <--> 19, P <--> 20
## 17 Q <--> 1, Q <--> 2, Q <--> 3, Q <--> 4, Q <--> 5, Q <--> 6, Q <--> 7, Q <--> 8, Q <--> 9, Q <--> 10, Q <--> 11, Q <--> 12, Q <--> 13, Q <--> 14, Q <--> 15, Q <--> 16, Q <--> 17, Q <--> 18, Q <--> 19, Q <--> 20
## 18 R <--> 1, R <--> 2, R <--> 3, R <--> 4, R <--> 5, R <--> 6, R <--> 7, R <--> 8, R <--> 9, R <--> 10, R <--> 11, R <--> 12, R <--> 13, R <--> 14, R <--> 15, R <--> 16, R <--> 17, R <--> 18, R <--> 19, R <--> 20
## 19 S <--> 1, S <--> 2, S <--> 3, S <--> 4, S <--> 5, S <--> 6, S <--> 7, S <--> 8, S <--> 9, S <--> 10, S <--> 11, S <--> 12, S <--> 13, S <--> 14, S <--> 15, S <--> 16, S <--> 17, S <--> 18, S <--> 19, S <--> 20
## 20 T <--> 1, T <--> 2, T <--> 3, T <--> 4, T <--> 5, T <--> 6, T <--> 7, T <--> 8, T <--> 9, T <--> 10, T <--> 11, T <--> 12, T <--> 13, T <--> 14, T <--> 15, T <--> 16, T <--> 17, T <--> 18, T <--> 19, T <--> 20
Ahora cada fila tiene un vector de 20 elementos guardado en la columna resultado
3.1.5 Funciones implícitas
no es necesario que definamos la función de antemano. Podemos usar funciones implícitas
## [1] 1 4 9 16 25 36 49 64 81 100
## [1] 11 24 39 56 75 96 119 144 171 200
3.1.6 Funciones lambda
incluso más conciso que las funciones implíictas son las funciones lambda donde definimos las variables como .x .y, etc. La flexibilidad de estas expresiones es limitada, pero puede ser útil en algunos casos.
## [1] 1 4 9 16 25 36 49 64 81 100
## [1] 11 24 39 56 75 96 119 144 171 200
3.1.7 Walk
Las funciones Walk
Tienen la misma forma que los map
, pero se usan cuando lo que queremos iterar no genera una salida, sino que nos interesan los efectos secundarios que generan.
## [[1]]
## [1] "A <--> 1"
##
## [[2]]
## [1] "B <--> 2"
##
## [[3]]
## [1] "C <--> 3"
imprimir_salida <- function(x,y){
print(funcion_prueba(x,y))
}
walk2(ABC_123$Letras,ABC_123$Num,imprimir_salida)
## [1] "A <--> 1"
## [1] "B <--> 2"
## [1] "C <--> 3"
## [1] "D <--> 4"
## [1] "E <--> 5"
## [1] "F <--> 6"
## [1] "G <--> 7"
## [1] "H <--> 8"
## [1] "I <--> 9"
## [1] "J <--> 10"
## [1] "K <--> 11"
## [1] "L <--> 12"
## [1] "M <--> 13"
## [1] "N <--> 14"
## [1] "O <--> 15"
## [1] "P <--> 16"
## [1] "Q <--> 17"
## [1] "R <--> 18"
## [1] "S <--> 19"
## [1] "T <--> 20"
Eso que vemos es el efecto secundario dentro de la función (imprimir)
3.1.8 Cuando usar estas herramientas?
A lo largo del curso vimos diferentes técnicas para manipulación de datos. En particular, la librería dplyr nos permitía fácilmente modificar y crear nuevas variables, agrupando. Cuando usamos dplyr
y cuando usamos purrr
.
- Si trabajamos sobre un DF simple, sin variables anidadas (lo que conocíamos hasta hoy) podemos usar
dplyr
Si queremos trabajar con DF anidados, con cosas que no son DF, o si el resultado de la operación que vamos a realizar a nivel file es algo distinto a un valor único, nos conviene usar
map
ypurrr
Las funciones
walk
son útiles por ejemplo para escribir archivos en disco de forma iterativa. Algo que no genera una salida