10 Apply family
La familia apply
en R es un paquete integrado la base de R que permite evitar los bucles al explorar y analizar datos. La aplicación de estas funciones son increíblemente realmente útiles para trabajar con datos en R, además de que simplifican en trabajo.
La estructura de esta función es la siguiente.
apply(X, MARGIN, FUN)
Las apicaciones de las funciones de la familia son:
-lapply()
: recorre una lista y aplica una función a cada elemento de esa lista (lapply devuelve una lista).
-sapply()
: una versión de lapply que simplifica los resultados (sapply devuelve un vector o matriz si es posible).
-apply()
: recorre los márgenes (filas o columnas) de una matriz, útil para tomar resúmenes de matrices o matrices de mayor dimensión.
-tapply()
: abreviatura de “aplicación de tabla”. Aplica una función sobre subconjuntos de un vector.
10.1 Apply:
La función apply()
tiene tres argumentos:
X
: Una matriz o un objeto que pueda coercionarse a una matriz, generalmente, un data frame.MARGIN
: La dimensión (margen) que agrupará los elementos de la matrizX
, para aplicarles una función.-
Son identificadas con números,
-
1
son renglones y,
-
2
son colummnas.
-
FUN
: La función que aplicaremos a la matrizX
en su dimensiónMARGIN
.
Ejemplo
Por ejemplo, podemos usar apply()
para obtener la sumatoria de los elementos de una matriz, por renglón.
Se crea una matriz de cuatro renglones.
matriz <- matrix(1:16, nrow = 4, ncol = 4)
Se aplica la función apply()
, usando la función sum()
en el argumento FUN
, nota que sólo necesitamos el nombre de la función, sin paréntesis.
Por último, damos el argumento MARGIN = 1
, para aplicar la función por renglón.
apply(X = matriz, MARGIN = 1, FUN = sum)
## [1] 28 32 36 40
Esto es equivalente a hacer lo siguiente.
sum(matriz[1, ])
## [1] 28
Si cambiamos el argumento MARGIN
de MARGIN = 1
a MARGIN = 2
, entonces la función se aplicará por columna.
apply(X = matriz, MARGIN = 2, FUN = sum)
## [1] 10 26 42 58
En este caso, la función sum()
ha sido aplicado a cada elementos de nuestra matriz, los elementos son las columnas, y ahora cada columna es un vector.
10.1.1 FUN
El parametro FUN
es un argumento que nos pide el nombre de una función que se se aplicarla a todos los elementos de nuestra matriz. Algunas de las funciones mayormente usadas son:
mean()
sum()
-
sd(
) max()
min()
quantile()
¿Qué pasa si deseamos utilizar los demás argumentos de una función con apply? En los casos en los que una función tiene más de un argumento, asignamos los valores de estos del nombre de la función, separados por comas, usando sus propios nombres (a este procedimiento es al que se refiere el argumento ...
descrito en la documentación de apply). ?apply
apply(X = matriz, MARGIN = 2, FUN = quantile, probs = c(.33, .66))
## [,1] [,2] [,3] [,4]
## 33% 1.99 5.99 9.99 13.99
## 66% 2.98 6.98 10.98 14.98
Si además deseamos que el resultado aparezca sin nombres, entonces definimos el valor del argumento names de la misma manera.
apply(matriz, 2, quantile, probs = c(.33, .66), names = FALSE)
## [,1] [,2] [,3] [,4]
## [1,] 1.99 5.99 9.99 13.99
## [2,] 2.98 6.98 10.98 14.98
De este modo es posible aplicar funciones complejas que aceptan múltiples argumentos, con la ventaja que usamos pocas líneas de código.
10.2 Sappy
La función sapply()
en R es una función integrada que aplica una función a todos los elementos de entrada. El método sapply()
toma una lista, un vector o un data.frame como argumento y devuelve un vector o una matriz.
sapply(X, FUN, ..., simplify = TRUE, USE.NAMES = TRUE)
Para usar la función sapply()
en R, se deberá especificar la lista o el vector sobre el que desea iterar en el primer argumento y la función que desea aplicar a cada elemento del vector en el segundo.
Teniendo en cuenta que se puede usar una función de cualquier paquetería|repositorio o bien puede ser función personalizada :
sapply(1:4, sqrt)
## [1] 1.000000 1.414214 1.732051 2.000000
# Es equivalente a:
sapply(1:4, function(i) sqrt(i))
## [1] 1.000000 1.414214 1.732051 2.000000
# También es equivalente a:
# Also equivalent to:
my_fun <- function(i) {
sqrt(i)
}
sapply(1:4, my_fun)
## [1] 1.000000 1.414214 1.732051 2.000000
La tercera función es más compleja de realizar, pero es importante tomar en cuenta que se puede aplicar cualquier función que uno desee.
Consideramos, por ejemplo, que se desea calcular el cuadrado de los elementos de un vector. Usando la función for()
.
out <- numeric(10)
for (i in 1:10) {
out[i] <- i ^ 2
}
out
## [1] 1 4 9 16 25 36 49 64 81 100
Sin embargo, con la función sapply()
se puede escribir todo en una sola línea de código para obtener el mismo resultado:
sapply(1:10, function(i) i ^ 2)
## [1] 1 4 9 16 25 36 49 64 81 100
Ejemplo
Si se tiene una lista en lugar de un vector, los pasos son análogos, pero se tiene en cuenta que la función se aplicará a los elementos de la lista. En el siguiente ejemplo se cálcula el número de componentes de cada elemento de la lista con la función length()
.
La función sapply
en R permite usar argumentos adicionales a la función que está aplicando después de la función a usar. Se considera una lista con valor NA
:
Si se aplica la función sum
a cada elemento de la lista, devolverá la suma de los componentes de cada elemento, pero como el segundo elemento contiene un valor NA
, la suma también devuelve un valor NA
.
sapply(my_list, sum)
## A B
## 11 NA
Como la función sum
tiene un argumento adicional llamado na.rm
, se puede configurarlo la siguiente manera para eliminar los valores NA
. Véase ?sum
.
sapply(my_list, sum, na.rm = TRUE)
## A B
## 11 22
En consecuencia, el valor NA
no se tiene en cuenta y la función devuelve la suma de los valores finitos.
10.3 Lapply
La función lapply()
es un caso especial de apply()
, diseñado para aplicar funciones a todos los elementos de una lista. La l de su nombre se refiere, precisamente, a lista
.
Esta función intentará coercionar a una lista el objeto que demos como argumento y después aplicará una función a todos sus elementos.
La estructura de esta función es:
lapply(X, FUN)
En donde:
-
X
es una lista o un objeto coercionable a una lista. -
FUN
es la función a aplicar.
lapply(c(3, 5, 7), exp)
## [[1]]
## [1] 20.08554
##
## [[2]]
## [1] 148.4132
##
## [[3]]
## [1] 1096.633
# Se puede expresar de esta manera
lapply(1:5, function(i) exp(i))
## [[1]]
## [1] 2.718282
##
## [[2]]
## [1] 7.389056
##
## [[3]]
## [1] 20.08554
##
## [[4]]
## [1] 54.59815
##
## [[5]]
## [1] 148.4132
10.4 sapply vs lapply
La diferencia entre las funciones lapply
y sapply
es el tipo de resultado que arroja cada función:
-
sapply
\(\rightarrow\)vector
,
-
lapply
\(\rightarrow\)lista
.
En ambos casos depende mucho el contexto en el que se use una función u otra, alguna veces es mejor trabajar con listas cuando se intenta hacer manipulación de datos data mining
y guardar los resultados en listas.
Si se considera que se quiere calcular la exponencial de tres números. Como primer caso, si usa la función sapply
, se obtendrá un vector como salida. O bien, si se usa la función lapply
, se obtendrá una lista donde cada elemento corresponde a los componentes del vector anterior.
sapply(c(3, 5, 7), exp)
## [1] 20.08554 148.41316 1096.63316
lapply(c(3, 5, 7), exp)
## [[1]]
## [1] 20.08554
##
## [[2]]
## [1] 148.4132
##
## [[3]]
## [1] 1096.633
Sin embargo, por un lado, si establece el argumento simplify = FALSE
dentro de la función sapply
obtendrá el mismo resultado que la función lapply
. Teniendo en cuenta que esto es lo mismo que usar la función as.list()
:
sapply(c(3, 5, 7), exp, simplify = FALSE)
## [[1]]
## [1] 20.08554
##
## [[2]]
## [1] 148.4132
##
## [[3]]
## [1] 1096.633
as.list(sapply(c(3, 5, 7), exp)) # Equivalent
## [[1]]
## [1] 20.08554
##
## [[2]]
## [1] 148.4132
##
## [[3]]
## [1] 1096.633
Por otro lado, se puede convertir la salida de la función lapply
al mismo tipo de salida de la función sapply
con las funciones simplify2array
o unlist()
:
simplify2array(lapply(c(3, 5, 7), exp))
## [1] 20.08554 148.41316 1096.63316
unlist(lapply(c(3, 5, 7), exp)) # Equivalent
## [1] 20.08554 148.41316 1096.63316
En resumen, las funciones sapply
y lapply
son casi iguales, pero difieren en la clase de salida.