aggregate
: Ejemplos y trucos.En R es fácil resumir información a partir de apliación de funciones sobre los subgrupos creados según las variables de agrupación (factor o numérica) por las cuales se desean hacer las agrupaciones. Es posible hacer esto con una gran variedad de funciones (aggregate
, split
, by
, tapply
y con otras funciones del paquete plyr), sin embargo este post sólo trata de la función aggregate
porque está en el paquete base de R y es muy manejable.
Según la documentación de la función aggregate
, esta función divide la muestra en subconjuntos, calcula los estadísticos deseados por cada subconjunto y devuelve el resultado en una forma conveniente, esto significa que el resutado puede ser un vector, un data.frame o una lista según sea más conveniente.
A continuación algunos ejemplos usando la base datos iris
.
data(iris) # cargando la base de datos `iris`
head(iris) # así lucen los datos.
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
## 4 4.6 3.1 1.5 0.2 setosa
## 5 5.0 3.6 1.4 0.2 setosa
## 6 5.4 3.9 1.7 0.4 setosa
Nota
En todo este post se usará la notación de fórmula dentro de la función aggregate
donde la lógica es escribir al lado izquierdo del símbolo ~
la variable que se quiere agrupar y al lado derecho, la variable de agrupación: variable_a_ser_agrupada ~ variable_de_agrupación
. Así la sintaxis entera será:
aggregate(variable_a_ser_agrupada ~ variable_de_agrupación, FUN=función_deseada, data=base_de_datos)
Ejemplo 1
Calculando la suma de Sepal.Length
por Species
, como ha de esperarse, el resultado final será un data.frame con la suma total de la variable Sepal.Length
por cada especie contenida en la variable Species
.
aggregate(Sepal.Length ~ Species, FUN = sum, data = iris)
## Species Sepal.Length
## 1 setosa 250.3
## 2 versicolor 296.8
## 3 virginica 329.4
Ejemplo 2
Una facilidad que permite la función aggregate
es que se pueden resumir más de una variable, veamos la suma de todas las demás varibles según la especie.
aggregate(cbind(Sepal.Length, Sepal.Width, Petal.Length, Petal.Width) ~ Species,
FUN = sum, data = iris)
## Species Sepal.Length Sepal.Width Petal.Length Petal.Width
## 1 setosa 250.3 171.4 73.1 12.3
## 2 versicolor 296.8 138.5 213.0 66.3
## 3 virginica 329.4 148.7 277.6 101.3
Nótese que cuando se quieren “agregar” muchas variables es necesario usar la función cbind
para que funcione. Sin embargo, no es muy práctico escribir el nombre de cada variable como se muestra en el ejemplo anterior, pero como se está utilizando el estilo de “fórmula” para escribir dentro de la función aggregate
esta permite reemplazar lo anterior por este nuevo código:
aggregate(. ~ Species, FUN = sum, data = iris)
## Species Sepal.Length Sepal.Width Petal.Length Petal.Width
## 1 setosa 250.3 171.4 73.1 12.3
## 2 versicolor 296.8 138.5 213.0 66.3
## 3 virginica 329.4 148.7 277.6 101.3
y como ha de esperarse, los resultados son los mismos.
Ejemplo 3
¿Qué tal si tuviéramos más de 1 variable de agregación, por ejemplo Species
y Petal.Size
?, Esto no representa ningún problema para aggregate
, veamos un ejemplo.
Primero se ha de crear la nueva variable Petal.Size
que indica si la longitud del pétalo (Petal.Length
) es mayor que su valor mediano (4.350 cm) tendrá el valor Big
y si es menor o igual, será Small
.
iris$Petal.Size <- with(iris, ifelse(Petal.Length > median(Petal.Length), "Big",
"Small"))
aggregate(Petal.Length ~ Species + Petal.Size, FUN = sum, data = iris) # resultado sólo para Petal.Length
## Species Petal.Size Petal.Length
## 1 versicolor Big 115.9
## 2 virginica Big 277.6
## 3 setosa Small 73.1
## 4 versicolor Small 97.1
aggregate(. ~ Species + Petal.Size, FUN = sum, data = iris) # resultado para todos
## Species Petal.Size Sepal.Length Sepal.Width Petal.Length Petal.Width
## 1 versicolor Big 156.4 72.8 115.9 36.5
## 2 virginica Big 329.4 148.7 277.6 101.3
## 3 setosa Small 250.3 171.4 73.1 12.3
## 4 versicolor Small 140.4 65.7 97.1 29.8
Ejemplo 4 (un truco sencillo)
¿Y si en lugar de sólo querer la suma, quiero además la media y desviación estándar de los datos de Petal.Length
agrupados por Species
?, Esto se puede hacer sin ningún problema.
resultado <- aggregate(Petal.Length ~ Species, FUN = function(x) c(Suma = sum(x),
Media = mean(x), SD = sd(x)), data = iris)
resultado
## Species Petal.Length.Suma Petal.Length.Media Petal.Length.SD
## 1 setosa 73.1000 1.4620 0.1737
## 2 versicolor 213.0000 4.2600 0.4699
## 3 virginica 277.6000 5.5520 0.5519
A pesar que el resultado mostrado es el adecuado, en realidad, no es muy útil si se desea guardar para luego volverlo a usar, porque en realidad el output de este último ejemplo es un data.frame que debería tener la información calculada, pero si intentamos acceder a esa info a través de su nombre o su posición nos dice que no existe tal información!!! :(
resultado[, "Petal.Length.Suma"] # Error en `[.data.frame`(resultado, , 3) : undefined columns selected :(
resultado[, "Petal.Length.Media"] # Error en `[.data.frame`(resultado, , 3) : undefined columns selected :(
resultado[, 3] # Error en `[.data.frame`(resultado, , 3) : undefined columns selected :(
Pero tranquilos,“calma! que no panda el cúnico”, hay una sencilla solución para ello, basta con convertir esto a un data.frame usado la función do.call
resultado2 <- do.call(data.frame, resultado)
Aparentemente no ha habido ningún cambio respecto a lo anterior, sin embargo, ahora sí se pueden acceder a los datos de las columnas, porque ahora sí existen!!! :D
resultado2[, "Petal.Length.Suma", drop = FALSE] # Sí funciona!!!
resultado2[, "Petal.Length.Media", drop = FALSE] # Sí funciona!!!
resultado2[, 3, drop = FALSE] # Sí funciona!!!
No hay comentarios:
Publicar un comentario