Menu

Agrupar y resumir en R (aggregate, tapply, dplyr)

Todas las formas de calcular estadísticas por grupo en R: contar con table(), tapply() para una estadística por grupo, la interfaz de fórmula de aggregate(), y el group_by() con summarize() de dplyr.

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

Contar filas por grupo: table()

La pregunta de agrupación más simple es "¿cuántos de cada uno?" - y R base la responde en una sola llamada. table() cuenta cuántas veces aparece cada valor:

Una columna da conteos por valor; dos columnas dan una tabla de contingencia completa (regiones como filas, planes como columnas). Para "¿qué proporción?" envuélvela en prop.table(table(...)). table() es la ruta más rápida a una respuesta de frecuencias en todo R - no recurras a nada más pesado cuando un conteo es todo lo que necesitas.

Una estadística por grupo: tapply()

tapply(values, groups, function) divide el primer vector según el segundo y aplica la función a cada trozo:

El resultado es un vector con nombres - las etiquetas de grupo como nombres, las estadísticas como valores - lo que lo hace perfecto para consultas rápidas (means["EU"]). El nombre se descifra como "table apply": aplicar una función a lo largo de una tabla de agrupación. Pertenece a la misma familia que sapply() y lapply(), cubiertas en la documentación de la familia apply.

El límite de tapply() es la forma: un vector con nombres es incómodo de combinar, graficar o seguir procesando. Cuando el resumen es un peldaño intermedio y no la respuesta final, quieres recuperar un data frame - que es exactamente lo que devuelve la siguiente herramienta.

El caballo de batalla de las fórmulas: aggregate()

aggregate() es el group-by completo de R base: devuelve un data frame, y su interfaz de fórmula se lee como la frase que dirías. value ~ group significa "value, desglosado por group":

Añadir agrupadores es simplemente + otra_columna en la fórmula - la segunda llamada suma por cada combinación de región y trimestre. También puedes agregar varias columnas de valores a la vez con cbind(a, b) ~ group. Como la salida es un data frame ordinario, encaja directamente en un merge, una ordenación o un gráfico - esta es la herramienta de base por defecto para resúmenes agrupados.

Un comportamiento discreto que conviene conocer: la interfaz de fórmula descarta las filas con NA en cualquier columna usada antes de agregar. Normalmente es lo que quieres; a veces es la explicación de un conteo que parece bajo.

La forma dplyr: group_by() + summarize()

El estándar moderno es el patrón de dos verbos de dplyr - group_by() declara la agrupación, summarize() colapsa cada grupo en una fila, calculando tantas estadísticas como nombres (estático; el sandbox solo ejecuta R base):

library(dplyr)

sales |>
    group_by(region) |>
    summarize(
        n     = n(),
        total = sum(amount),
        avg   = mean(amount)
    )

Aquí es donde dplyr supera de verdad a R base: varias estadísticas por grupo en una sola llamada legible - aggregate() necesita contorsiones para eso - más n() gratis, y el resultado fluye directo al siguiente pipe. (summarise() es la misma función, con grafía británica.)

Algo que desconcierta a los recién llegados: con varios agrupadores, summarize() retira solo el último, dejando el resultado todavía agrupado - e imprime un mensaje al respecto. Di lo que quieres explícitamente con el argumento .groups: summarize(avg = mean(amount), .groups = "drop") devuelve un data frame sin agrupar, que es el hábito correcto por defecto. Un data frame agrupado que se cuela en código posterior hace que mutate() y compañía operen silenciosamente por grupo - una fuente clásica de resultados confusos.

Cómo elegir entre ellas

  • Un conteo - table(), nada supera una sola llamada.
  • Una estadística, un vistazo rápido - tapply(), y lee la respuesta del vector con nombres.
  • Data frame de salida, entorno solo-base - aggregate() con una fórmula.
  • Varias estadísticas, parte de un pipeline, o cualquier cosa ambiciosa - group_by() |> summarize().

No hay respuesta equivocada entre ellas - todas calculan los mismos números - pero elegir la herramienta según la forma de salida que necesitas te ahorra el paso de conversión posterior. Las medias, medianas y dispersiones en sí se cubren en estadística descriptiva.

Ejemplo resuelto: mtcars por número de cilindros

Todo junto sobre un dataset integrado - por número de cilindros, cuántos coches hay, y su consumo y potencia medios:

Once coches de 4 cilindros con una media de unas 26.7 mpg, siete de 6 cilindros en torno a 19.7, catorce de 8 cilindros alrededor de 15.1 - y la potencia marchando en dirección opuesta. Dos llamadas, una tabla de resumen completa: este es el tipo de pregunta para el que existe la agregación por grupos.

Lo que te llevas

  • table() para conteos, prop.table() para proporciones.
  • tapply(values, groups, fn) devuelve un vector con nombres - vistazos rápidos, consultas fáciles.
  • aggregate(value ~ group, data, FUN) devuelve un data frame; + añade agrupadores, cbind() añade columnas de valores.
  • El group_by() |> summarize(n = n(), avg = mean(x), .groups = "drop") de dplyr es el estándar moderno para resúmenes de varias estadísticas.
  • Elige según la forma de salida; todas coinciden en los números.

A continuación: combinar tablas que comparten una clave - merge() y la familia de joins de dplyr.

Preguntas frecuentes

¿Cómo calculo la media por grupo en R?

R base tiene dos herramientas: tapply(df$value, df$group, mean) devuelve un vector con nombres de las medias por grupo, y aggregate(value ~ group, data = df, FUN = mean) devuelve el mismo resultado como data frame. En dplyr: df |> group_by(group) |> summarize(avg = mean(value)).

¿Cómo cuento ocurrencias por grupo en R?

table(df$group) cuenta las filas por valor de grupo en una sola llamada; table(df$a, df$b) cruza dos columnas en una tabla de contingencia. En dplyr, count(df, group) hace lo mismo y devuelve un data frame, que es más fácil de seguir procesando.

¿Qué hace aggregate() en R?

aggregate() divide un data frame por una o más columnas de agrupación, aplica una función a cada trozo y devuelve un data frame de resultados. La interfaz de fórmula se lee con naturalidad: aggregate(sales ~ region + quarter, data = df, FUN = mean) significa sales, agrupado por region y quarter, promediado.

¿Cuál es la diferencia entre tapply y aggregate?

El mismo cálculo, distinta forma de salida. tapply() devuelve un vector con nombres (o un array con dos agrupadores) - práctico para consultas rápidas. aggregate() devuelve un data frame - mejor cuando el resultado alimenta más análisis, un merge o un gráfico. En caso de duda, aggregate().

Coddy programming languages illustration

Aprende a programar con Coddy

COMENZAR