18 FUNCIONES POR GRUPOS

La familia de funciones apply, que forma parte del paquete stats, permite operar sobre subconjuntos de datos. Las más comunes son apply, sapply, lapply y tapply.

La función apply se usa para aplicar una función sobre cada uno de los elementos dimensionales de un arreglo. Si el arreglo en cuestión fuera bidimensional, es decir, una matriz, esto significa aplicar una función dada a cada una de sus filas o columnas. El formato general es el siguiente:

apply(arreglo, dimensión(es), función)

El primer argumento de la función corresponde al nombre del arreglo; el segundo se refiere al indicador numérico de la dimensión: 1 para las filas de una matriz, 2 para las columnas de una matriz, 3 para la tercera dimensión de un arreglo y así sucesivamente; el tercer argumento es el nombre de la función, sin paréntesis; si fuera necesario especificar argumentos para dicha función, estos irían a continuación, separados por comas.

Considérese la matriz m2 (cf. sección 8.2), conformada por 2 filas y 3 columnas.

#>      [,1] [,2] [,3]
#> [1,]    2    0    5
#> [2,]   -1    9    1

Para obtener los promedios por fila de la matriz m2, indicando que deben retirarse los valores perdidos, en caso de que los hubiese, se usa la siguiente instrucción:

apply(m2, 1, mean, na.rm = T)
#> [1] 2.333333 3.000000

El resultado es un vector con dos elementos: el promedio de la primera fila y el promedio de la segunda fila.

Considérese ahora la obtención de la suma de los elementos en cada una de las columnas.

apply(m2, 2, sum)
#> [1] 1 9 6

El resultado es un vector con la suma de los elementos de cada una de las tres columnas de m2.

Aunque el resultado de los dos casos ilustrados anteriormente ha sido un vector, ello se debe a la naturaleza de las funciones usadas (media y suma), pero no siempre será así. Supóngase que se quiere obtener el rango de los elementos dentro de cada una de las filas.

apply(m2, 1, rank)
#>      [,1] [,2]
#> [1,]    2    1
#> [2,]    1    3
#> [3,]    3    2

Este resultado puede no ser fácilmente visualizable, pues si bien se han calculado los rangos dentro de cada fila, los correspondientes resultados aparecen organizados por columnas: en la primera columna de la matriz resultante están los rangos de los elementos de la primera fila de m2, mientras que en la segunda columna de la matriz resultante están los rangos de los elementos de la segunda fila de m2. Para tener una visualización más directa del resultado, basta con trasponer la matriz resultante.

t(apply(m2, 1, rank))
#>      [,1] [,2] [,3]
#> [1,]    2    1    3
#> [2,]    1    3    2

Definamos ahora, un arreglo tetradimensional, con 5 elementos en la primera dimensión, 4 elementos en la segunda, 2 elementos en la tercera y 3 elementos en la cuarta.

arreglo <- array(1:120, c(5, 4, 2, 3))

Para obtener los promedios de la cuarta dimensión, se usa la siguiente instrucción:

apply(arreglo, 4, mean)
#> [1]  20.5  60.5 100.5

También es posible consolidar información de dos o más dimensiones. Así, por ejemplo, pueden obtenerse los promedios podados de las dimensiones 1 y 3, lo que equivale a promediar sobre las dimensiones 2 y 4. El resultado será una matriz de 5 filas (número de elementos dimensionales de la dimensión 1 de arreglo) y 2 columnas (número de elementos dimensionales de la dimensión 3 de arreglo).

apply(arreglo, c(1, 3), mean, trim = 0.1)
#>      [,1] [,2]
#> [1,] 48.5 68.5
#> [2,] 49.5 69.5
#> [3,] 50.5 70.5
#> [4,] 51.5 71.5
#> [5,] 52.5 72.5

Las funciones sapply y lapply están diseñadas para operar sobre las columnas de un data frame o sobre los elementos de mayor jerarquía de una lista30. Los resultados de la función sapply generan un vector, mientras que la función lapply genera una lista.

Considérese el siguiente data frame, conformado por 10 filas y 3 columnas:

dataf <- data.frame(x1 = 1:10, x2 = 11:20, x3 = 21:30)
sapply(dataf, mean)
#>   x1   x2   x3 
#>  5.5 15.5 25.5
lapply(dataf, mean)
#> $x1
#> [1] 5.5
#> 
#> $x2
#> [1] 15.5
#> 
#> $x3
#> [1] 25.5

La función tapply permite aplicar una función sobre grupos o subconjuntos de elementos dentro de un arreglo, definidos con base en los niveles de uno o más factores.

Considérese el siguiente data frame, conformado por dos factores (f1 y f2) y por un vector numérico, y.

set.seed(12)
df <- data.frame(f1 = c("a", "b", "c"),
                 f2 = c(rep("A", 3), rep("B", 3), rep("C", 3),
                 rep("D", 3)), y <- rnorm(36))

La siguiente instrucción genera los promedios de y, para cada uno de los niveles del factor f1.

(medias.f1 <- tapply(df$y, df$f1, mean))
#>          a          b          c 
#> -0.2122834  0.1392543 -0.2819433

Análogamente, pueden obtenerse los promedios de y, para cada uno de los niveles de f2.

(medias.f2 <- tapply(df$y, df$f2, mean))
#>           A           B           C           D 
#> -0.36354544 -0.19166989  0.17691388 -0.09499511

Asimismo, pueden obtenerse los promedios para cada una de las combinaciones de los niveles de f1 con los niveles de f2.

(medias.f1f2 <- with(df, tapply(y, list(f1, f2), mean)))
#>            A          B          C           D
#> a -1.0951263 -0.4974490  0.2885335  0.45490803
#> b  0.4405788 -0.2209877  0.3834918 -0.04606573
#> c -0.4360888  0.1434270 -0.1412837 -0.69382763