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().