R
Tutorial R: group_by y summarize para agrupación y resumen
Aprende a usar group_by y summarize en R para agrupar datos y obtener resúmenes estadísticos eficientes con dplyr.
Aprende R y certifícateAgrupación de datos con group_by()
La manipulación de datos en R se vuelve realmente potente cuando podemos trabajar con subconjuntos de nuestros datos de forma simultánea. La función group_by()
del paquete dplyr nos permite dividir nuestros datos en grupos según los valores de una o más variables, lo que facilita realizar operaciones específicas para cada grupo.
Imagina que tienes una tabla de ventas y quieres analizar los datos por región, por producto o por mes. En lugar de filtrar manualmente cada subconjunto, group_by()
te permite establecer estas agrupaciones de forma sencilla y elegante.
Funcionamiento básico de group_by()
La función group_by()
no modifica los datos visibles de tu dataframe, sino que añade metadatos que indican cómo están agrupadas las filas. Esto permite que las operaciones posteriores se apliquen a cada grupo por separado.
Primero, carguemos las librerías necesarias y creemos un conjunto de datos sencillo para trabajar:
# Cargar el paquete dplyr
library(dplyr)
# Crear un dataframe de ejemplo
ventas <- data.frame(
producto = c("A", "B", "A", "C", "B", "A", "C"),
region = c("Norte", "Norte", "Sur", "Norte", "Sur", "Sur", "Sur"),
unidades = c(20, 15, 25, 10, 30, 15, 20),
precio = c(10, 15, 10, 20, 15, 10, 20)
)
# Mostrar los datos
ventas
Para agrupar estos datos por la variable region
, simplemente usamos:
# Agrupar por región
ventas_por_region <- ventas %>%
group_by(region)
# Ver el resultado
ventas_por_region
Al imprimir ventas_por_region
, notarás que los datos se ven igual que antes, pero en la parte superior aparecerá un mensaje como # Groups: region [2]
, indicando que los datos están agrupados por la variable region
y que hay 2 grupos distintos (Norte y Sur).
Agrupación por múltiples variables
Una de las ventajas de group_by()
es que podemos agrupar por múltiples variables simultáneamente, creando subgrupos más específicos:
# Agrupar por región y producto
ventas_detalladas <- ventas %>%
group_by(region, producto)
# Ver el resultado
ventas_detalladas
Ahora los datos están agrupados primero por region
y luego por producto
dentro de cada región, lo que nos permitirá realizar análisis más detallados.
Verificando la estructura de agrupación
Para entender mejor cómo están agrupados nuestros datos, podemos usar la función group_vars()
que nos muestra las variables de agrupación:
# Ver las variables de agrupación
group_vars(ventas_por_region) # Devuelve "region"
group_vars(ventas_detalladas) # Devuelve c("region", "producto")
También podemos usar n_groups()
para saber cuántos grupos distintos tenemos:
# Contar el número de grupos
n_groups(ventas_por_region) # Devuelve 2 (Norte y Sur)
n_groups(ventas_detalladas) # Devuelve el número de combinaciones únicas
Eliminando agrupaciones
Si queremos eliminar todas las agrupaciones y volver a un dataframe normal, usamos ungroup()
:
# Eliminar todas las agrupaciones
ventas_sin_agrupar <- ventas_por_region %>%
ungroup()
# Verificar que ya no hay agrupaciones
group_vars(ventas_sin_agrupar) # Devuelve un vector vacío
Si solo queremos eliminar el último nivel de agrupación, podemos especificar la variable:
# Eliminar solo la agrupación por producto
ventas_solo_region <- ventas_detalladas %>%
ungroup(producto)
# Verificar las agrupaciones restantes
group_vars(ventas_solo_region) # Devuelve "region"
Ejemplo práctico con datos reales
Veamos un ejemplo más realista usando el conjunto de datos mtcars
que viene incluido en R:
# Cargar datos de ejemplo
data(mtcars)
# Añadir nombres de coches como columna
mtcars <- mtcars %>%
rownames_to_column(var = "car")
# Agrupar coches por número de cilindros y tipo de transmisión
coches_agrupados <- mtcars %>%
group_by(cyl, am)
# Ver la estructura de agrupación
glimpse(coches_agrupados)
En este ejemplo, hemos agrupado los coches por número de cilindros (cyl
) y tipo de transmisión (am
), creando grupos como "coches de 4 cilindros con transmisión manual", "coches de 6 cilindros con transmisión automática", etc.
Cuándo usar group_by()
La función group_by()
es especialmente útil en estas situaciones:
- Cuando necesitas calcular estadísticas por grupo (que veremos en la siguiente sección con
summarize()
) - Para aplicar transformaciones específicas a cada grupo de datos
- Al querer identificar patrones o tendencias dentro de categorías específicas
- Para filtrar datos basándote en condiciones que dependen del grupo
Es importante recordar que group_by()
por sí solo no modifica los datos visibles. Su verdadero poder se manifiesta cuando se combina con otras funciones como summarize()
, mutate()
, filter()
o arrange()
, que aplicarán sus operaciones a cada grupo de forma independiente.
Buenas prácticas al usar group_by()
- Verifica tus agrupaciones: Usa
group_vars()
on_groups()
para confirmar que tus datos están agrupados como esperas. - Elimina agrupaciones cuando termines: Usa
ungroup()
cuando ya no necesites la agrupación para evitar comportamientos inesperados en operaciones posteriores. - Considera el rendimiento: Agrupar por variables con muchos valores únicos puede afectar el rendimiento, especialmente con conjuntos de datos grandes.
- Mantén la claridad: Agrupa solo por las variables necesarias para tu análisis actual, evitando agrupaciones innecesariamente complejas.
La agrupación de datos con group_by()
es el primer paso para realizar análisis segmentados en R, permitiéndonos examinar patrones y tendencias específicas dentro de nuestros datos de manera eficiente y organizada.
Agregaciones con summarize() y funciones estadísticas
Una vez que hemos agrupado nuestros datos con group_by()
, el siguiente paso lógico es realizar cálculos resumidos para cada grupo. Aquí es donde entra en juego la función summarize()
(o summarise()
, ambas formas son válidas en dplyr), que nos permite calcular estadísticas para cada grupo y reducir nuestros datos a un resumen conciso.
La función summarize()
transforma nuestro dataframe agrupado en uno nuevo donde cada grupo se convierte en una sola fila, con columnas que contienen los resultados de las operaciones de resumen que especifiquemos.
Sintaxis básica de summarize()
La estructura básica de summarize()
es sencilla:
# Estructura básica
datos_agrupados %>%
summarize(
nombre_resultado1 = función_estadística1(columna),
nombre_resultado2 = función_estadística2(otra_columna)
)
Veamos un ejemplo práctico con nuestro dataframe de ventas:
# Cargar dplyr
library(dplyr)
# Crear dataframe de ejemplo
ventas <- data.frame(
producto = c("A", "B", "A", "C", "B", "A", "C"),
region = c("Norte", "Norte", "Sur", "Norte", "Sur", "Sur", "Sur"),
unidades = c(20, 15, 25, 10, 30, 15, 20),
precio = c(10, 15, 10, 20, 15, 10, 20)
)
# Calcular total de unidades y precio promedio por región
ventas %>%
group_by(region) %>%
summarize(
total_unidades = sum(unidades),
precio_promedio = mean(precio)
)
El resultado será un dataframe con tres columnas: region
, total_unidades
y precio_promedio
, y dos filas (una para "Norte" y otra para "Sur").
Funciones estadísticas comunes
R ofrece una amplia variedad de funciones estadísticas que podemos utilizar dentro de summarize()
. Estas son algunas de las más utilizadas:
- Medidas de tendencia central:
# Ejemplo con mtcars
mtcars %>%
group_by(cyl) %>%
summarize(
media_mpg = mean(mpg), # Media aritmética
mediana_mpg = median(mpg), # Mediana
moda_disp = names(sort(table(disp), decreasing = TRUE)[1]) # Moda aproximada
)
- Medidas de dispersión:
mtcars %>%
group_by(cyl) %>%
summarize(
desv_estandar = sd(mpg), # Desviación estándar
varianza = var(mpg), # Varianza
rango = max(mpg) - min(mpg), # Rango
iqr = IQR(mpg) # Rango intercuartílico
)
- Valores extremos y conteos:
mtcars %>%
group_by(cyl) %>%
summarize(
minimo = min(mpg), # Valor mínimo
maximo = max(mpg), # Valor máximo
conteo = n(), # Número de filas
valores_unicos = n_distinct(gear) # Número de valores únicos
)
La función n() y sus variantes
La función n()
merece una mención especial, ya que es específica de dplyr y muy útil para contar observaciones:
# Contar observaciones por grupo
mtcars %>%
group_by(cyl, am) %>%
summarize(
cantidad = n() # Cuenta filas en cada grupo
)
Otras funciones relacionadas incluyen:
n_distinct(x)
: cuenta valores únicos en la columna xsum(!is.na(x))
: cuenta valores no faltantessum(is.na(x))
: cuenta valores faltantes
Cálculos personalizados
Podemos ir más allá de las funciones estadísticas básicas y crear cálculos personalizados dentro de summarize()
:
# Calcular ingresos totales y promedio por región
ventas %>%
group_by(region) %>%
summarize(
ingresos_totales = sum(unidades * precio),
ingreso_promedio_por_unidad = sum(unidades * precio) / sum(unidades)
)
Múltiples niveles de agrupación
Cuando trabajamos con múltiples niveles de agrupación, summarize()
elimina el último nivel después de aplicar los cálculos:
# Agrupar por región y producto, luego resumir
ventas %>%
group_by(region, producto) %>%
summarize(
total_unidades = sum(unidades)
)
Este resultado mantendrá la agrupación por region
, permitiéndonos encadenar otro summarize()
si queremos:
# Resumen en cascada
ventas %>%
group_by(region, producto) %>%
summarize(
total_unidades = sum(unidades)
) %>%
summarize(
productos_distintos = n(),
promedio_unidades = mean(total_unidades)
)
Manteniendo todos los niveles de agrupación
Si queremos mantener todos los niveles de agrupación después de summarize()
, podemos usar el argumento .groups
:
ventas %>%
group_by(region, producto) %>%
summarize(
total_unidades = sum(unidades),
.groups = "keep" # Mantiene todos los niveles de agrupación
)
Otras opciones para .groups
son:
"drop_last"
: comportamiento predeterminado, elimina el último nivel"drop"
: elimina todos los niveles de agrupación"rowwise"
: convierte el resultado a una agrupación por fila
Ejemplo práctico: análisis de datos de iris
Veamos un ejemplo más completo con el conjunto de datos iris
:
# Cargar datos
data(iris)
# Análisis estadístico por especie
iris %>%
group_by(Species) %>%
summarize(
# Estadísticas para longitud de sépalo
media_sepal_length = mean(Sepal.Length),
min_sepal_length = min(Sepal.Length),
max_sepal_length = max(Sepal.Length),
sd_sepal_length = sd(Sepal.Length),
# Estadísticas para ancho de pétalo
media_petal_width = mean(Petal.Width),
min_petal_width = min(Petal.Width),
max_petal_width = max(Petal.Width),
# Conteo de observaciones
n_observaciones = n()
)
Combinando summarize() con otras funciones
Podemos combinar summarize()
con otras funciones de dplyr para análisis más sofisticados:
# Encontrar las regiones con más de 40 unidades vendidas
ventas %>%
group_by(region) %>%
summarize(
total_unidades = sum(unidades)
) %>%
filter(total_unidades > 40) %>%
arrange(desc(total_unidades))
Funciones estadísticas con condiciones
También podemos aplicar funciones estadísticas con condiciones dentro de summarize()
:
# Calcular estadísticas para productos específicos
ventas %>%
group_by(region) %>%
summarize(
unidades_producto_A = sum(unidades[producto == "A"]),
precio_promedio_excepto_C = mean(precio[producto != "C"])
)
Buenas prácticas al usar summarize()
- Nombres descriptivos: Usa nombres claros para las columnas de resultados.
- Manejo de NA: Considera usar argumentos como
na.rm = TRUE
en funciones comomean()
osum()
para manejar valores faltantes. - Verificación de resultados: Comprueba que los resultados tienen sentido, especialmente con cálculos complejos.
- Documentación: Añade comentarios para explicar cálculos no obvios.
# Ejemplo con manejo de NA
mtcars %>%
group_by(cyl) %>%
summarize(
# Ignorar NA en el cálculo
media_mpg = mean(mpg, na.rm = TRUE),
# Contar valores no faltantes
n_validos = sum(!is.na(mpg))
)
Resumen de múltiples columnas con across()
Para aplicar la misma función a múltiples columnas, podemos usar across()
dentro de summarize()
:
# Calcular media y desviación estándar para todas las medidas numéricas
iris %>%
group_by(Species) %>%
summarize(
across(
where(is.numeric),
list(media = mean, desv = sd),
.names = "{.col}_{.fn}"
)
)
Este código calculará la media y desviación estándar para todas las columnas numéricas, creando nombres como Sepal.Length_media
y Sepal.Length_desv
.
La combinación de group_by()
y summarize()
es una de las herramientas más potentes para el análisis de datos en R, permitiéndonos extraer información valiosa y patrones de nuestros datos de manera eficiente y organizada.
Operaciones por grupo sin resumir
Mientras que summarize()
reduce nuestros datos agrupados a un resumen por grupo, en muchas ocasiones necesitamos realizar operaciones por grupo manteniendo la estructura original de nuestros datos. Esto es especialmente útil cuando queremos añadir nuevas columnas basadas en cálculos grupales o filtrar filas según características de su grupo.
En dplyr, podemos aplicar operaciones a datos agrupados sin resumirlos utilizando funciones como mutate()
, filter()
, slice()
y arrange()
. Estas funciones, cuando se aplican a datos agrupados, operan de forma independiente dentro de cada grupo.
Añadir columnas por grupo con mutate()
La función mutate()
nos permite crear nuevas columnas o modificar las existentes. Cuando trabajamos con datos agrupados, los cálculos se realizan separadamente para cada grupo:
# Cargar las librerías necesarias
library(dplyr)
# Crear un dataframe de ejemplo
ventas <- data.frame(
producto = c("A", "B", "A", "C", "B", "A", "C"),
region = c("Norte", "Norte", "Sur", "Norte", "Sur", "Sur", "Sur"),
unidades = c(20, 15, 25, 10, 30, 15, 20),
precio = c(10, 15, 10, 20, 15, 10, 20)
)
# Calcular porcentaje de ventas dentro de cada región
ventas_con_porcentaje <- ventas %>%
group_by(region) %>%
mutate(
total_unidades_region = sum(unidades),
porcentaje_region = unidades / total_unidades_region * 100
)
# Ver el resultado
ventas_con_porcentaje
En este ejemplo, para cada fila calculamos qué porcentaje representa sus unidades respecto al total de su región. Observa que:
- El dataframe resultante mantiene todas las filas originales
- Las nuevas columnas contienen valores calculados por grupo
- Cada fila ahora incluye información contextual de su grupo
Cálculos relativos al grupo
Podemos crear columnas que muestren la relación de cada fila con su grupo:
# Añadir rankings y comparaciones con la media del grupo
mtcars %>%
group_by(cyl) %>%
mutate(
ranking_mpg = rank(-mpg), # Ranking de consumo dentro del grupo
diff_media = mpg - mean(mpg), # Diferencia respecto a la media del grupo
porcentaje_max = mpg / max(mpg) * 100 # Porcentaje respecto al máximo del grupo
)
Estas operaciones son muy útiles para análisis comparativos dentro de categorías, como identificar valores atípicos o destacar elementos que se desvían de la tendencia del grupo.
Estandarización y normalización por grupo
Una aplicación común es la estandarización de variables dentro de cada grupo:
# Estandarizar valores por grupo
iris %>%
group_by(Species) %>%
mutate(
# Calcular z-score para longitud de sépalo dentro de cada especie
sepal_length_z = (Sepal.Length - mean(Sepal.Length)) / sd(Sepal.Length),
# Normalizar ancho de pétalo a escala 0-1 dentro de cada especie
petal_width_norm = (Petal.Width - min(Petal.Width)) /
(max(Petal.Width) - min(Petal.Width))
)
Esta técnica es especialmente valiosa cuando queremos comparar valores entre grupos que tienen diferentes escalas o distribuciones.
Filtrar observaciones basadas en propiedades del grupo
Con filter()
podemos seleccionar filas basándonos en características de su grupo:
# Filtrar productos que representan más del 30% de las ventas de su región
ventas_importantes <- ventas %>%
group_by(region) %>%
mutate(
total_region = sum(unidades),
porcentaje = unidades / total_region * 100
) %>%
filter(porcentaje > 30)
# Ver el resultado
ventas_importantes
También podemos usar funciones de ventana para filtrar basándonos en rankings u ordenaciones dentro del grupo:
# Seleccionar los dos productos más vendidos de cada región
top_productos <- ventas %>%
group_by(region) %>%
arrange(desc(unidades)) %>%
slice(1:2)
# Ver el resultado
top_productos
Operaciones de ventana por grupo
Las funciones de ventana como lead()
, lag()
, cumsum()
o cummean()
son especialmente útiles cuando se aplican por grupo:
# Crear un dataframe con datos temporales
ventas_mensuales <- data.frame(
producto = rep(c("A", "B"), each = 6),
mes = rep(1:6, 2),
ventas = c(10, 12, 15, 14, 18, 20, 8, 9, 11, 13, 14, 16)
)
# Calcular cambios y acumulados por producto
ventas_mensuales %>%
group_by(producto) %>%
arrange(mes) %>%
mutate(
ventas_anterior = lag(ventas), # Valor del mes anterior
cambio = ventas - lag(ventas), # Cambio respecto al mes anterior
cambio_porcentual = (ventas / lag(ventas) - 1) * 100, # Cambio porcentual
ventas_acumuladas = cumsum(ventas), # Suma acumulada
media_movil = cummean(ventas) # Media móvil
)
Estas operaciones son fundamentales para análisis de series temporales y para entender la evolución de variables a lo largo del tiempo dentro de cada grupo.
Identificar valores extremos por grupo
Podemos identificar fácilmente los valores máximos o mínimos dentro de cada grupo:
# Marcar los valores máximos y mínimos por región
ventas %>%
group_by(region) %>%
mutate(
es_maximo = unidades == max(unidades),
es_minimo = unidades == min(unidades)
)
O identificar valores atípicos usando criterios estadísticos:
# Identificar outliers usando el criterio del rango intercuartílico
mtcars %>%
group_by(cyl) %>%
mutate(
q1 = quantile(mpg, 0.25),
q3 = quantile(mpg, 0.75),
iqr = q3 - q1,
es_outlier = mpg < (q1 - 1.5 * iqr) | mpg > (q3 + 1.5 * iqr)
) %>%
select(cyl, mpg, es_outlier)
Operaciones condicionales por grupo
Podemos aplicar transformaciones condicionales que dependan de propiedades del grupo:
# Aplicar descuentos basados en el volumen de ventas por región
ventas %>%
group_by(region) %>%
mutate(
total_region = sum(unidades),
# Aplicar descuento según volumen regional
descuento = case_when(
total_region > 50 ~ 0.15, # 15% de descuento para regiones con más de 50 unidades
total_region > 30 ~ 0.10, # 10% de descuento para regiones con más de 30 unidades
TRUE ~ 0.05 # 5% de descuento para el resto
),
precio_final = precio * (1 - descuento)
)
Ejemplo práctico: análisis de rendimiento académico
Veamos un ejemplo más completo con datos de calificaciones de estudiantes:
# Crear dataframe de calificaciones
calificaciones <- data.frame(
estudiante = rep(paste0("Estudiante", 1:10), each = 4),
asignatura = rep(c("Matemáticas", "Historia", "Ciencias", "Literatura"), 10),
nota = round(runif(40, 50, 100))
)
# Análisis completo por estudiante
analisis_estudiantes <- calificaciones %>%
group_by(estudiante) %>%
mutate(
# Estadísticas del estudiante
media_estudiante = mean(nota),
mejor_nota = max(nota),
peor_nota = min(nota),
# Comparación con su propio rendimiento
diferencia_media = nota - media_estudiante,
# Clasificación de asignaturas
rendimiento = case_when(
nota >= media_estudiante + 10 ~ "Excelente",
nota >= media_estudiante ~ "Bueno",
nota >= media_estudiante - 10 ~ "Regular",
TRUE ~ "Necesita mejorar"
)
)
# Ver resultados para algunos estudiantes
analisis_estudiantes %>%
filter(estudiante %in% c("Estudiante1", "Estudiante2"))
Consejos para trabajar con operaciones por grupo
Mantén la claridad: Cuando encadenes múltiples operaciones, considera crear variables intermedias para facilitar la comprensión.
Verifica tus resultados: Comprueba que los cálculos por grupo funcionan como esperas, especialmente con grupos pequeños.
Considera el rendimiento: Para conjuntos de datos grandes, algunas operaciones por grupo pueden ser costosas computacionalmente.
Combina con ungroup(): Si necesitas realizar operaciones que comparen entre grupos después de operaciones grupales, usa
ungroup()
en el momento adecuado.
# Ejemplo de combinación de operaciones grupales y globales
ventas %>%
# Primero calculamos estadísticas por grupo
group_by(region) %>%
mutate(
media_region = mean(unidades)
) %>%
# Luego eliminamos la agrupación para comparar con la media global
ungroup() %>%
mutate(
media_global = mean(unidades),
rendimiento_relativo = media_region / media_global
)
Las operaciones por grupo sin resumir nos permiten enriquecer nuestros datos con contexto grupal mientras mantenemos el nivel de detalle original, lo que resulta fundamental para análisis exploratorios profundos y para preparar datos para visualizaciones detalladas.
Otros ejercicios de programación de R
Evalúa tus conocimientos de esta lección group_by y summarize para agrupación y resumen con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.
Todas las lecciones de R
Accede a todas las lecciones de R y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Instalación De R Y Rstudio
Introducción Y Entorno
Introducción A R
Introducción Y Entorno
Operadores
Sintaxis
Estructuras De Datos
Sintaxis
Funciones
Sintaxis
Estructuras De Control Iterativo
Sintaxis
Scopes Y Closures
Sintaxis
Estructuras De Control Condicional
Sintaxis
Funciones Anónimas
Sintaxis
Tipos De Datos Y Variables
Sintaxis
Sistema R6: Clases Referenciales Y Encapsulamiento
Programación Orientada A Objetos
Sistema S4: Clases Formales Y Validación
Programación Orientada A Objetos
Herencia Y Polimorfismo En R
Programación Orientada A Objetos
Sistemas De Oop En R
Programación Orientada A Objetos
Sistema S3: Clases Implícitas Y Métodos Genéricos
Programación Orientada A Objetos
Tidyverse Para Transformación De Datos
Manipulación De Datos
Lubridate Para Fechas Y Tiempo
Manipulación De Datos
Group_by Y Summarize Para Agrupación Y Resumen
Manipulación De Datos
Stringr Para Expresiones Regulares
Manipulación De Datos
Tidyr Para Limpieza De Valores Faltantes
Manipulación De Datos
Joins En R Para Combinación Y Relaciones De Tablas
Manipulación De Datos
Pivot_longer Y Pivot_wider Para Reestructuración
Manipulación De Datos
Mutate Y Transmute Para Transformación
Manipulación De Datos
Dplyr Para Filtrado Y Selección
Manipulación De Datos
Readr Y Read.csv Para Importar Datos
Manipulación De Datos
Gráficos Bivariantes En R
Visualización De Datos
Gráficos Univariantes En R
Visualización De Datos
Facetas En Ggplot2
Visualización De Datos
Personalización Y Temas
Visualización De Datos
Ggplot2 Para Visualización De Datos
Visualización De Datos
Gráficos Multivariantes En R
Visualización De Datos
Correlación En R
Estadística
Regresión Lineal En R
Estadística
Pruebas De Hipótesis En R
Estadística
Anova En R
Estadística
Estadística Descriptiva En R
Estadística
En esta lección
Objetivos de aprendizaje de esta lección
- Comprender cómo agrupar datos con group_by() para segmentar análisis.
- Aprender a resumir datos agrupados usando summarize() con funciones estadísticas.
- Realizar operaciones por grupo sin resumir, utilizando mutate(), filter() y funciones de ventana.
- Aplicar buenas prácticas en el manejo de agrupaciones y resúmenes para evitar errores.
- Interpretar y manipular agrupaciones múltiples y mantener niveles de agrupación según convenga.