apply
La función apply() pertenece al paquete base R y aplica una función a una matriz, lista o vector que se le pase como parámetro.
La documentación (ejecuta ?apply) de la base R dice que se llama de la siguiente manera: apply(X, MARGIN, FUN, …)
donde:
- Argumento 1: matriz, lista o vector
- Argumento 2: 1 para operar sobre las columnas y 2 sobre las filas, c(1, 2) indica filas y columnas
- Argumento 3: la función a aplicar según indique el argumento 2
- …: argumentos opcionales a FUN.
Por ejemplo, si queremos saber la media de cada fila de una matriz de 100 filas y 10 columnas:
myMat <- matrix(sample(1:100, size = 1000, replace = TRUE), ncol = 10)
apply(X = myMat, MARGIN = 1, FUN = mean)
## [1] 40.8 43.9 58.4 46.0 46.1 60.6 56.7 55.4 46.9 73.2 43.3 35.3 40.3 44.9
## [15] 54.0 55.8 30.7 57.7 64.2 61.0 52.0 35.0 65.1 54.4 41.2 30.0 38.6 33.8
## [29] 50.9 49.0 65.5 59.9 40.2 59.4 57.0 52.2 52.9 45.8 45.0 61.6 52.1 57.3
## [43] 57.2 63.3 58.0 63.2 64.5 44.1 60.0 44.9 51.7 53.0 56.0 55.6 48.3 42.1
## [57] 47.3 37.8 56.4 50.5 50.3 57.9 33.8 61.7 45.0 49.9 44.7 34.8 49.2 66.0
## [71] 65.4 62.3 39.7 64.6 41.3 44.8 54.1 49.5 37.0 62.6 70.4 56.0 49.1 45.4
## [85] 65.6 50.6 40.8 46.6 47.5 57.5 52.7 47.9 53.8 48.0 64.4 53.2 30.9 32.8
## [99] 38.7 38.9
Si queremos saber la media de cada columna, la expresión anterior se convierte en:
apply(X = myMat, MARGIN = 2, FUN = mean)
## [1] 48.86 53.92 47.65 50.39 49.33 45.90 49.49 53.11 54.44 54.25
lapply
Es usada cuando se desea aplicar una función determinada a cada elemento de una lista y obtener una lista como resultado. Al ejecutar ?lapply, la sintaxis se parece a la función apply().
La diferencia es que:
- Puede ser usado para otros objetos como dataframes, listas o vectores; y
- Devuelve una lista de la misma longitud que X, y cada elemento resulta de la aplicación FUN al elemento X correspondiente.
Para ver cómo funciona esto, tenenemos el siguiente ejemplo:
set.seed(12345)
(myList <- list(
a = sample(1:100, size = 10),
b = sample(1:100, size = 10),
c = sample(1:100, size = 10),
d = sample(1:100, size = 10),
e = sample(1:100, size = 10)
))
## $a
## [1] 73 87 75 86 44 16 31 48 67 91
##
## $b
## [1] 4 16 73 1 38 44 37 96 17 87
##
## $c
## [1] 46 33 95 69 62 38 66 51 21 45
##
## $d
## [1] 80 1 19 67 36 35 82 85 57 13
##
## $e
## [1] 79 43 91 76 25 31 6 5 94 57
Para obtener el promedio de cada elemento de la list:
lapply(myList, FUN = mean)
## $a
## [1] 61.8
##
## $b
## [1] 41.3
##
## $c
## [1] 52.6
##
## $d
## [1] 47.5
##
## $e
## [1] 50.7
sapply
La función sapply() es una versión modificada de la función lapply() que realiza la misma operación pero intenta simplificar la salida a la estructura de datos más elemental siempre que sea posible.
Por ejemplo digamos que se desea repetir la operación de calcular la media del ejemplo anterior:
sapply(myList, FUN = mean)
## a b c d e
## 61.8 41.3 52.6 47.5 50.7
Extraer el elemento “n” (en este caso el primer elemento) de cada elemento de una list. La función que se llama para hacer esto es ‘[[’.
sapply(myList, FUN = '[[', 1)
## a b c d e
## 73 4 46 80 79
tapply
La función tapply() permite aplicar una función tomando como elemento para iterar una variable existente, es decir realiza una operación (parámetro 3) respecto a un vector (parámetro 1) agrupada por los factores que se indiquen como argumento (parámetro 2).
Para este ejemplo se usa la base de datos iris para obtener fácilmente un resumen de las mediciones de Sepal.Length para cada Species con la función tapply() y la función summary()
data("iris")
tapply(iris$Sepal.Length, iris$Species, summary)
## $setosa
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 4.300 4.800 5.000 5.006 5.200 5.800
##
## $versicolor
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 4.900 5.600 5.900 5.936 6.300 7.000
##
## $virginica
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 4.900 6.225 6.500 6.588 6.900 7.900
mapply
La función mapply() significa apply “multivariante”, que aplica una función a múltiples listas o múltiples argumentos vectoriales.
Por ejemplo, para crear una matriz 4x4 se puede crear normalmente con la función matrix() y la función rep() repetidamente:
matrix(c(rep(1, 4), rep(2, 4), rep(3, 4), rep(4, 4)),4,4)
## [,1] [,2] [,3] [,4]
## [1,] 1 2 3 4
## [2,] 1 2 3 4
## [3,] 1 2 3 4
## [4,] 1 2 3 4
Ahora usando la función mapply() y la función rep() repetidamente:
mapply(rep, 1:4, 4)
## [,1] [,2] [,3] [,4]
## [1,] 1 2 3 4
## [2,] 1 2 3 4
## [3,] 1 2 3 4
## [4,] 1 2 3 4
Si tenemos tres matrices x, y y z para obtener la suma entre cada uno de los elementos de las matrices se puede usar la función mapply():
x <- matrix(1:9,3,3)
y <- matrix(11:19,3,3)
z <- matrix(21:29,3,3)
mapply(sum, x, y, z)
## [1] 33 36 39 42 45 48 51 54 57
vapply
Devuelve un vector con la longitud que tiene cada una de las listas introducidas como parámetro.
(x <- list(A = 1, B = 1:3, C = 1:7))
## $A
## [1] 1
##
## $B
## [1] 1 2 3
##
## $C
## [1] 1 2 3 4 5 6 7
vapply(x, FUN = length, FUN.VALUE = 0L)
## A B C
## 1 3 7
rapply
rapply() se utiliza cuando queremos aplicar una función a cada elemento de un objeto con estructura de lista anidada (una lista dentro de una lista), de manera recursiva (Máxima Formación n.d.).
Funciones relacionadas con apply()
En ocasiones se utilizan funciones estructuradas de forma similar junto con el elemento de la familia apply(), a continuación se presenta una visión general de algunas de ellas.
sweep
La función sweep() se utiliza cuando se desea duplicar diferentes acciones sobre los elementos MARGIN que se han elegido (limitándose aquí al caso de la matriz).
Supongamos que tiene un conjunto de datos. Primero se encuentran las medias y la dispersión o desviación estándar por columna con la ayuda de la función apply()
. Luego se centra los todos los datos con respecto a su centro (cada dato original menos la media). Finamente los datos centrados se utilizará para normalizar con respecto a su desviación estándar (dato original menos la media dividido para la desviación estándar del dato original) (Fanara 2016):
data <- matrix(c(seq(4, 7), seq(8, 11), seq(12, 15)), 4, 3)
# Calcular la media por columna con `apply()`
data.media <- apply(data, 2, mean)
# Encuentrar la desviación estándar con `apply()`
data.sd <- apply(data, 2, sd)
# Centrar los datos
(data.centrado <- sweep(data, 2, data.media, "-"))
## [,1] [,2] [,3]
## [1,] -1.5 -1.5 -1.5
## [2,] -0.5 -0.5 -0.5
## [3,] 0.5 0.5 0.5
## [4,] 1.5 1.5 1.5
# Normalizar los datos
(data.norm <- sweep(data.centrado, 2, data.sd, "/"))
## [,1] [,2] [,3]
## [1,] -1.1618950 -1.1618950 -1.1618950
## [2,] -0.3872983 -0.3872983 -0.3872983
## [3,] 0.3872983 0.3872983 0.3872983
## [4,] 1.1618950 1.1618950 1.1618950
Esta función sweep() espera los siguientes parámetros:
- Un x: una matriz de entrada;
- Un MARGIN, 2 para indicar las columnas;
- Un STATS, resumen de estadísticas (aquí mean); y
- FUN, una función a aplicar. En este caso se usa el operador aritmético “-” para la resta.
aggregate
Esta función está contenida en el paquete base stats y la utilizas así: aggregate(x, by, FUN, …, simplify = TRUE).
Funciona de manera similar a la función apply(): se especifica el objeto, la función y dice si desea simplificar, al igual que con la función sapply(). La diferencia clave es el uso de la cláusula by, que establece la variable o el campo de marco de datos mediante el cual queremos realizar la agregación.
Usando la base de datos iris se obtiene el promedio de las mediciones de Sepal.Length para cada Species:
data("iris")
aggregate(iris$Sepal.Length, by = iris["Species"], FUN = mean)
## Species x
## 1 setosa 5.006
## 2 versicolor 5.936
## 3 virginica 6.588
by
Similar a la función tapply(), pero by() funciona también cuando el tamaño de los 2 primeros argumentos son distintos, por ejemplo:
data("iris")
by(iris[1:4], iris$Species, summary)
## iris$Species: setosa
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## Min. :4.300 Min. :2.300 Min. :1.000 Min. :0.100
## 1st Qu.:4.800 1st Qu.:3.200 1st Qu.:1.400 1st Qu.:0.200
## Median :5.000 Median :3.400 Median :1.500 Median :0.200
## Mean :5.006 Mean :3.428 Mean :1.462 Mean :0.246
## 3rd Qu.:5.200 3rd Qu.:3.675 3rd Qu.:1.575 3rd Qu.:0.300
## Max. :5.800 Max. :4.400 Max. :1.900 Max. :0.600
## --------------------------------------------------------
## iris$Species: versicolor
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## Min. :4.900 Min. :2.000 Min. :3.00 Min. :1.000
## 1st Qu.:5.600 1st Qu.:2.525 1st Qu.:4.00 1st Qu.:1.200
## Median :5.900 Median :2.800 Median :4.35 Median :1.300
## Mean :5.936 Mean :2.770 Mean :4.26 Mean :1.326
## 3rd Qu.:6.300 3rd Qu.:3.000 3rd Qu.:4.60 3rd Qu.:1.500
## Max. :7.000 Max. :3.400 Max. :5.10 Max. :1.800
## --------------------------------------------------------
## iris$Species: virginica
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## Min. :4.900 Min. :2.200 Min. :4.500 Min. :1.400
## 1st Qu.:6.225 1st Qu.:2.800 1st Qu.:5.100 1st Qu.:1.800
## Median :6.500 Median :3.000 Median :5.550 Median :2.000
## Mean :6.588 Mean :2.974 Mean :5.552 Mean :2.026
## 3rd Qu.:6.900 3rd Qu.:3.175 3rd Qu.:5.875 3rd Qu.:2.300
## Max. :7.900 Max. :3.800 Max. :6.900 Max. :2.500
Bibliografía
Fanara, Carlo. 2016. “R tutorial on the Apply family of functions (article) - DataCamp.” https://www.datacamp.com/community/tutorials/r-tutorial-apply-family.
Máxima Formación, MF. n.d. “Cómo calcular resúmenes estadísticos por grupo rápidamente.” Accessed January 6, 2019. https://www.maximaformacion.es/blog-dat/como-calcular-resumenes-por-grupo-rapidamente/.