apply en R

Aprende todo sobre la función apply en R

Las funciones de la familia apply en R son un conjunto bien conocido de funciones vectorizadas de R que permiten realizar tareas complejas sobre arrays evitando el uso de bucles for. En este tutorial, aprenderás cómo usar apply en R a través de varios ejemplos y casos de uso.

La función apply en R

El comando apply en R permite aplicar una función a través de una matriz, array o data frame. Puedes hacer esto de varias maneras, dependiendo de cómo configures el argumento MARGIN, que habitualmente puede tomar los valores 1, 2 o c(1, 2).

apply(X,       # Array, matriz o data frame
      MARGIN,  # 1: filas, 2: columnas, c(1, 2): filas y columnas
      FUN,     # Función a ser aplicada
      ...)     # Argumentos adicionales para ser pasados a FUN

A través de este tutorial usaremos los siguientes datos de ejemplo, así que asegúrate de tenerlos cargados en tu espacio de trabajo. Ten en cuenta que vamos a utilizar un data frame, pero también podríamos haber elegido una matriz o un array en su lugar.

# Data frame
df <- data.frame(x = 1:4, y = 5:8, z = 10:13)
df
  x  y   z
  1  5  10
  2  6  11
  3  7  12
  4  8  13

MARGIN = 1 aplica la función a las filas mientras que MARGIN = 2 aplica la función a las columnas.

Aplicar función a cada fila

Puedes aplicar una función a cada fila de un array pasando un 1 como parámetro al argumento MARGIN. Para este primer ejemplo, vamos a aplicar la función sum a las filas del data frame de ejemplo.

# Suma por filas
apply(X = df, MARGIN = 1, FUN = sum)

Ten en cuenta que al usar esta función es habitual no especificar los nombres de los argumentos debido a la simplicidad de la función, pero recuerda el orden de los argumentos.

# Suma por filas
apply(df, 1, sum)
16 19 22 25

También puedes aplicar la función a índices o datos específicos, creando un subconjunto de los datos que quieras de tu data frame.

# Suma por filas de un subconjunto de los datos
apply(df[c(1, 2), ], 1, sum)
16 19

Ten en cuenta que la salida es un vector que contiene la suma correspondiente de cada fila.

Aplicar función a cada columna

Estableciendo MARGIN = 2, la función se aplicará a cada columna del array con el que estés trabajando.

# Suma por columnas
apply(df, 2, sum)
 x  y  z
10 26 46

En este caso, la salida es un vector que contiene la suma de cada columna del data frame de muestra. También puedes aplicar la función a columnas específicas si las indicas.

# Suma por columnas a un subconjunto de los datos
apply(df[, c(1, 3)], 2, sum)
 x  z
10 46

Cabe destacar que esto es más eficiente que aplicar la función a todo el data frame si luego quieres quedarte con un subconjunto de los datos originales.

Los ejemplos anteriores son para fines educativos. Es más eficiente usar las funciones colSums y rowSums para calcular la suma de columnas y filas, respectivamente.

Aplicar función a todo el data frame

Puedes establecer el argumento MARGIN como c(1, 2) o equivalentemente como 1:2 para aplicar la función a cada valor del data frame.

apply(df, c(1, 2), sum)
      x  y   z
[1, ] 1  5  10
[2, ] 2  6  11
[3, ] 3  7  12
[4, ] 4  8  13

Si pones MARGIN = c(2, 1) en lugar de c(1, 2) la salida será la misma matriz, pero traspuesta.

apply(df, c(2, 1), sum)
  [, 1] [, 2] [, 3] [, 4]
x    1     2     3     4
y    5     6     7     8
z   10    11    12    13

El output es de clase “matrix” en lugar de “data.frame”.

Nótese que en este caso los elementos de la salida son los elementos del data frame en sí, ya que se está calculando la suma de cada celda individual.

En la sección donde explicamos cómo usar funciones propias con la función apply mostraremos un ejemplo donde aplicar por filas y columnas es lo mismo que aplicar la función por columnas y otro donde las salidas son diferentes en todos los casos, con el objetivo de comprender mejor el propósito de aplicar una función sobre filas y columnas al mismo tiempo.

Argumentos adicionales de la función apply

La función mean tiene un argumento adicional (na.rm) para especificar si se eliminan los valores de tipo NA o no. Si necesitas especificar argumentos de la función que estás aplicando, puedes pasarlos separados por comas de la siguiente manera:

# Media por filas eliminando NA
apply(df, 1, mean, na.rm = TRUE)

Apply en R con una función propia

La función que pases al argumento FUN no necesita ser una función de R base. Puedes aplicar una función de R incluso si es una función propia. En este ejemplo, crearemos una función llamada fun que calcula el cuadrado de un número y convertiremos la salida a carácter si el argumento character se establece como TRUE.

fun <- function(x, character = FALSE) {
  if (character == FALSE) {
    x ^ 2
  } else {
    as.character(x ^2)
  }
}

Primero, si aplicas la función por filas, la salida será una matriz que contiene el cuadrado de los elementos por fila.

apply(df, 1, fun)
  [, 1] [, 2] [, 3] [, 4]
x    1     4     9    16
y   25    36    49    64
z  100   121   144   169

Si especificas character = TRUE, cada elemento de la matriz se convertirá a tipo carácter.

apply(df, 1, fun, character = TRUE)
      [, 1]  [, 2]  [, 3]  [, 4]
[1, ]   "1"    "4"    "9"   "16"
[2, ]  "25"   "36"   "49"   "64"
[3, ] "100"  "121"  "144"  "169"

En segundo lugar, si aplicas la función por columnas, obtendrás el siguiente resultado, que corresponde a la matriz traspuesta de la que obtuviste al aplicar la función por filas.

apply(df, 2, fun)
       x   y   z
[1, ]  1  25  100
[2, ]  4  36  121
[3, ]  9  49  144
[4, ] 16  64  169

Por último, si aplicas la función a cada celda, obtendrás el siguiente resultado:

apply(df, c(1, 2), fun)
       x   y   z
[1, ]  1  25  100
[2, ]  4  36  121
[3, ]  9  49  144
[4, ] 16  64  169

Nótese que, en este caso, aplicar la función por filas y columnas es lo mismo que aplicar la función por columnas, porque la función está calculando la suma de cada elemento individual, es decir, el elemento en sí. A continuación mostraremos un ejemplo donde las tres salidas son diferentes. Considera, como ejemplo, la siguiente función:

f <- function(x) sum(exp(x))

Esta función calcula la suma de la exponencial de un número o vector. Entonces, si aplicas la función por filas, obtendrás lo siguiente:

apply(df, 1, f) 
22177.60  60284.96  163871.51  445448.95

Por ejemplo, el primer elemento de la salida (22177.60) se puede obtener con: sum(exp(1) + exp(5) + exp(10)). Ahora, si aplicas la función por columnas, la salida será completamente diferente.

apply(df, 2, f) 
   x           y            z
84.79102  4629.43310  687068.79094 

Finalmente, si aplicas la función por filas y columnas, la salida será una matriz que contiene el exponencial de cada elemento.

apply(df, 1:2, f)
            x         y         z
[1, ]  2.718282   148.4132   22026.47
[2, ]  7.389056   403.4288   59874.14
[3, ] 20.085537  1096.6332  162754.79
[4, ] 54.598150  2980.9580  442413.39

Ejemplos adicionales de la función apply() en R

A continuación se muestran más ejemplos de uso de la función apply en R, incluido uno en el que se aplica una función a un array multidimensional.

apply(df, 2, min)     # Valores mínimos por columna

apply(df, 2, range)   # Rango (valores mínimos y máximos) por columna

apply(df, 1, summary) # Resumen por fila

apply(df, 2, summary) # Resumen por columna

# Aplicando la función sum a un array multidimensional
ar <- array(data = 1:18, dim = c(3, 2, 3))
apply(ar, 3, sum) # <- El argumento MARGIN = 3

La última línea devuelve la suma de todas las componentes de cada elemento del array.