× ¿Necesitas ayuda para aprender R? Inscríbete en el Curso de introducción a R de Applied Epi, prueba nuestros Tutoriales gratuitos de R, escribe en nuestro Foro de preguntas y respuestas, o pregunta por nuestra Asistencia técnica para R.

13 Agrupar datos

Esta página cubre cómo agrupar y agregar datos para el análisis descriptivo. Hace uso de la familia de paquetes tidyverse para funciones comunes y fáciles de usar.

La agrupación de datos es un componente esencial de la gestión y el análisis de datos. Los datos agrupados se resumen estadísticamente y pueden representarse gráficamente por grupos. Las funciones del paquete dplyr (parte del tidyverse) facilitan la agrupación y las operaciones posteriores.

En esta página se tratarán los siguientes temas:

13.1 Preparación

Cargar paquetes

Este trozo de código (chunk) muestra la carga de los paquetes necesarios para el análisis. En este manual destacamos p_load() de pacman, que instala el paquete si es necesario y lo carga para su uso. También puedes cargar los paquetes instalados con library() de R base. Consulta la página sobre Fundamentos de R para obtener más información sobre los paquetes de R.

pacman::p_load(
  rio,       # para importar datos
  here,      # para identificar las carpetas donde se encuentran
  tidyverse, # para limpiar, manipular y dibujar los datos (incluye dplyr)
  janitor)   # para añadir totales en las filas y columnas

Importar datos

Importamos los datos de casos de una epidemia de ébola simulada. Si quieres seguirlo, clica para descargar linelist “limpio” (como archivo .rds). Los datos se importan mediante la función import() del paquete rio. Consulta la página sobre importación y exportación para conocer las distintas formas de importar datos.

#{r, eval=F} #linelist <- import("linelist_cleaned.rds") #

Las primeras 50 filas de linelist:

13.2 Agrupar

La función group_by() de dplyr agrupa las filas por los valores únicos de la columna que se le especifica. Si se especifican varias columnas, las filas se agrupan por las combinaciones únicas de valores entre las columnas. Cada valor único (o combinación de valores) constituye un grupo. Los cambios posteriores en los datos o los cálculos pueden realizarse en el contexto de cada grupo.

Por ejemplo, el siguiente comando toma linelist y agrupa las filas por valores únicos en la columna outcome, guardando la salida como un nuevo dataframe ll_by_outcome. La(s) columna(s) de agrupación se colocan dentro de los paréntesis de la función group_by().

ll_by_outcome <- linelist %>% 
  group_by(outcome)

Ten en cuenta que no hay ningún cambio perceptible en los datos después de ejecutar group_by(), hasta que se aplique otro verbo de dplyr como mutate(), summarise(), o arrange() en el dataframe “agrupado”.

Sin embargo, puedes “ver” las agrupaciones imprimiendo el dataframe. Al imprimir un dataframe agrupado, verás que se ha transformado en un objeto de clase tibble que, al imprimirse, muestra qué agrupaciones se han aplicado y cuántos grupos están -escritos justo encima de la fila de cabecera.

# print para ver los grupos que están activos
ll_by_outcome
## # A tibble: 5,888 × 30
## # Groups:   outcome [3]
##    case_id generat…¹ date_inf…² date_onset date_hos…³ date_out…⁴ outcome gender   age age_u…⁵ age_y…⁶ age_cat age_c…⁷ hospi…⁸   lon   lat infec…⁹ source wt_kg ht_cm ct_bl…˟ fever chills cough aches vomit  temp time_…˟
##    <chr>       <dbl> <date>     <date>     <date>     <date>     <chr>   <chr>  <dbl> <chr>     <dbl> <fct>   <fct>   <chr>   <dbl> <dbl> <chr>   <chr>  <dbl> <dbl>   <dbl> <chr> <chr>  <chr> <chr> <chr> <dbl> <chr>  
##  1 5fe599          4 2014-05-08 2014-05-13 2014-05-15 NA         <NA>    m          2 years         2 0-4     0-4     Other   -13.2  8.47 f547d6  other     27    48      22 no    no     yes   no    yes    36.8 <NA>   
##  2 8689b7          4 NA         2014-05-13 2014-05-14 2014-05-18 Recover f          3 years         3 0-4     0-4     Missing -13.2  8.45 <NA>    <NA>      25    59      22 <NA>  <NA>   <NA>  <NA>  <NA>   36.9 09:36  
##  3 11f8ea          2 NA         2014-05-16 2014-05-18 2014-05-30 Recover m         56 years        56 50-69   55-59   St. Ma… -13.2  8.46 <NA>    <NA>      91   238      21 <NA>  <NA>   <NA>  <NA>  <NA>   36.9 16:48  
##  4 b8812a          3 2014-05-04 2014-05-18 2014-05-20 NA         <NA>    f         18 years        18 15-19   15-19   Port H… -13.2  8.48 f90f5f  other     41   135      23 no    no     no    no    no     36.8 11:22  
##  5 893f25          3 2014-05-18 2014-05-21 2014-05-22 2014-05-29 Recover m          3 years         3 0-4     0-4     Milita… -13.2  8.46 11f8ea  other     36    71      23 no    no     yes   no    yes    36.9 12:60  
##  6 be99c8          3 2014-05-03 2014-05-22 2014-05-23 2014-05-24 Recover f         16 years        16 15-19   15-19   Port H… -13.2  8.46 aec8ec  other     56   116      21 no    no     yes   no    yes    37.6 14:13  
##  7 07e3e8          4 2014-05-22 2014-05-27 2014-05-29 2014-06-01 Recover f         16 years        16 15-19   15-19   Missing -13.2  8.46 893f25  other     47    87      21 <NA>  <NA>   <NA>  <NA>  <NA>   37.3 14:33  
##  8 369449          4 2014-05-28 2014-06-02 2014-06-03 2014-06-07 Death   f          0 years         0 0-4     0-4     Missing -13.2  8.46 133ee7  other      0    11      22 no    no     yes   no    yes    37   09:25  
##  9 f393b4          4 NA         2014-06-05 2014-06-06 2014-06-18 Recover m         61 years        61 50-69   60-64   Missing -13.2  8.46 <NA>    <NA>      86   226      22 no    no     yes   no    yes    36.4 11:16  
## 10 1389ca          4 NA         2014-06-05 2014-06-07 2014-06-09 Death   f         27 years        27 20-29   25-29   Missing -13.3  8.47 <NA>    <NA>      69   174      22 no    no     yes   no    no     35.9 10:55  
## # … with 5,878 more rows, 2 more variables: bmi <dbl>, days_onset_hosp <dbl>, and abbreviated variable names ¹​generation, ²​date_infection, ³​date_hospitalisation, ⁴​date_outcome, ⁵​age_unit, ⁶​age_years, ⁷​age_cat5,
## #   ⁸​hospital, ⁹​infector, ˟​ct_blood, ˟​time_admission

Grupos únicos

Los grupos creados reflejan cada combinación única de valores en las columnas de agrupación.

Para ver los grupos y el número de filas en cada grupo, pasa los datos agrupados a tally(). Para ver sólo los grupos únicos sin recuento puedes pasárselos a group_keys().

Mira a continuación que hay tres valores únicos en el resultado de la columna outcome: “Death”, “Recover”, y NA. Fíjate que hubo nrow(linelist %\>% filter(outcome == "Death")) muertes, nrow(linelist %\>% filter(outcome == "Recover")) recuperaciones, y nrow(linelist %\>% filter(is.na(outcome)) sin resultado registrado.

linelist %>% 
  group_by(outcome) %>% 
  tally()
## # A tibble: 3 × 2
##   outcome     n
##   <chr>   <int>
## 1 Death    2582
## 2 Recover  1983
## 3 <NA>     1323

Se puede agrupar por más de una columna. A continuación, el dataframe se agrupa por outcome y gender, y luego se cuenta. Observa cómo cada combinación única de outcome y gender se registra como su propio grupo, incluyendo los valores faltantes para cualquier columna.

linelist %>% 
  group_by(outcome, gender) %>% 
  tally()
## # A tibble: 9 × 3
## # Groups:   outcome [3]
##   outcome gender     n
##   <chr>   <chr>  <int>
## 1 Death   f       1227
## 2 Death   m       1228
## 3 Death   <NA>     127
## 4 Recover f        953
## 5 Recover m        950
## 6 Recover <NA>      80
## 7 <NA>    f        627
## 8 <NA>    m        625
## 9 <NA>    <NA>      71

Columnas nuevas

También puedes crear una nueva columna de agrupación dentro de la sentencia group_by(). Esto equivale a llamar a mutate() antes de group_by(). Para una tabulación rápida este estilo puede ser útil, pero para una mayor claridad en el código mejor crear esta columna en su propio paso mutate() y luego canalizarla a group_by().

# agrupar datos en base a una columna binaria creada *dentro* del comando group_by()
linelist %>% 
  group_by(
    age_class = ifelse(age >= 18, "adult", "child")) %>% 
  tally(sort = T)
## # A tibble: 3 × 2
##   age_class     n
##   <chr>     <int>
## 1 child      3618
## 2 adult      2184
## 3 <NA>         86

Añadir/descartar columnas de agrupación

Por defecto, si ejecutas group_by() sobre datos que ya están agrupados, se eliminarán los grupos antiguos y se aplicarán los nuevos. Si deseas añadir nuevos grupos a los existentes, incluye el argumento .add = TRUE.

# Agrupado por outcome (resultado)
by_outcome <- linelist %>% 
  group_by(outcome)

# Además añadir agrupación por género 
by_outcome_gender <- by_outcome %>% 
  group_by(gender, .add = TRUE)

** Mantener todos los grupos**

Si se agrupa en una columna de tipo factor, puede haber niveles del factor que no estén presentes en los datos. Si agrupas en esta columna, por defecto esos niveles no presentes se descartan y no se incluyen como grupos. Para cambiar esto de manera que todos los niveles aparezcan como grupos (incluso si no están presentes en los datos), escribe .drop = FALSE en su comando group_by().

13.3 Des-agrupar

Los datos que han sido agrupados permanecerán agrupados hasta que sean específicamente desagrupados mediante ungroup(). Si se olvida desagrupar, puede dar lugar a cálculos incorrectos. A continuación se muestra un ejemplo de eliminación de todas las agrupaciones:

linelist %>% 
  group_by(outcome, gender) %>% 
  tally() %>% 
  ungroup()

También puedes eliminar la agrupación sólo para columnas específicas, colocando el nombre de la columna dentro de ungroup().

linelist %>% 
  group_by(outcome, gender) %>% 
  tally() %>% 
  ungroup(gender) # eliminar la agrupación por género, dejar la agrupación por resultado

NOTA: El verbo count() desagrupa automáticamente los datos después del recuento.

13.4 Resumir

Véase la sección dplyr de la página Tablas descriptivas para una descripción detallada de cómo producir tablas de resumen con summarise(). Aquí abordamos brevemente cómo cambia su comportamiento cuando se aplica a datos agrupados.

La función dplyr summarise() (o summarize()) toma un dataframe y lo convierte en un nuevo dataframe de resumen, con columnas que contienen los estadísticos de resumen que definas. En un dataframe sin agrupar, las estadísticas de resumen se calcularán a partir de todas las filas. La aplicación de summarise() a los datos agrupados produce esas estadísticas de resumen para cada grupo.

La sintaxis de summarise() es tal que se proporciona el nombre de la(s) nueva(s) columna(s) de resumen, un signo de igualdad y, a continuación, una función estadística para aplicar a los datos, como se muestra a continuación. Por ejemplo, min(), max(), median(), o sd(). Dentro de la función estadística, indica la columna con la que se va a operar y cualquier argumento relevante (por ejemplo, na.rm = TRUE). Puedes utilizar sum() para contar el número de filas que cumplen un criterio lógico (con doble igual ==).

A continuación se muestra un ejemplo de summarise() aplicado sin datos agrupados. Las estadísticas devueltas se producen a partir del set de datos completo.

# estadísticas resumidas de linelist sin agrupar
linelist %>% 
  summarise(
    n_cases  = n(),
    mean_age = mean(age_years, na.rm=T),
    max_age  = max(age_years, na.rm=T),
    min_age  = min(age_years, na.rm=T),
    n_males  = sum(gender == "m", na.rm=T))
##   n_cases mean_age max_age min_age n_males
## 1    5888 16.01831      84       0    2803

Por el contrario, a continuación se muestra la misma sentencia summarise() aplicada a los datos agrupados. Las estadísticas se calculan para cada grupo de outcome. Observa cómo se trasladan las columnas de agrupación al nuevo dataframe.

# estadísticas resumidas de linelist agrupados
linelist %>% 
  group_by(outcome) %>% 
  summarise(
    n_cases  = n(),
    mean_age = mean(age_years, na.rm=T),
    max_age  = max(age_years, na.rm=T),
    min_age  = min(age_years, na.rm=T),
    n_males    = sum(gender == "m", na.rm=T))
## # A tibble: 3 × 6
##   outcome n_cases mean_age max_age min_age n_males
##   <chr>     <int>    <dbl>   <dbl>   <dbl>   <int>
## 1 Death      2582     15.9      76       0    1228
## 2 Recover    1983     16.1      84       0     950
## 3 <NA>       1323     16.2      69       0     625

SUGERENCIA: La función summarise funciona tanto con la ortografía del Reino Unido como con la de EE.UU. - summarise() y summarize() llaman a la misma función.

13.5 Counts y tallies

count() y tally() proporcionan una funcionalidad similar pero son diferentes. Lee más sobre la distinción entre tally() y count() aquí

tally()

tally() es la abreviatura de summarise(n = n()), y no agrupa los datos. Por lo tanto, para lograr recuentos agrupados debe seguir un comando group_by(). Puedes añadir sort = TRUE para ver primero los grupos más grandes.

linelist %>% 
  tally()
##      n
## 1 5888
linelist %>% 
  group_by(outcome) %>% 
  tally(sort = TRUE)
## # A tibble: 3 × 2
##   outcome     n
##   <chr>   <int>
## 1 Death    2582
## 2 Recover  1983
## 3 <NA>     1323

count()

En cambio, count() hace lo siguiente:

  1. aplica group_by() a la(s) columna(s) especificada(s)
  2. aplica summarise() y devuelve la columna n con el número de filas por grupo
  3. aplica ungroup()
linelist %>% 
  count(outcome)
##   outcome    n
## 1   Death 2582
## 2 Recover 1983
## 3    <NA> 1323

Al igual que con group_by() puedes crear una nueva columna dentro del comando count():

linelist %>% 
  count(age_class = ifelse(age >= 18, "adult", "child"), sort = T)
##   age_class    n
## 1     child 3618
## 2     adult 2184
## 3      <NA>   86

Puedes llamar varias veces a count(), con la funcionalidad “combinada”. Por ejemplo, para resumir el número de hospitales presentes para cada género, ejecuta lo siguiente. Ten en cuenta que el nombre de la columna final se ha cambiado de “n” por defecto para mayor claridad (con name =).

linelist %>% 
   # producir recuentos por grupos únicos de resultado-género
  count(gender, hospital) %>% 
  # reunir filas por género (3) y contar el número de hospitales por género (6)
  count(gender, name = "hospitals per gender" ) 
##   gender hospitals per gender
## 1      f                    6
## 2      m                    6
## 3   <NA>                    6

Añadir recuentos

A diferencia de count() y summarise(), puedes utilizar add_count() para añadir una nueva columna n con los recuentos de filas por grupo conservando todas las demás columnas del dataframe.

Esto significa que el número de recuentos de un grupo, en la nueva columna n, se imprimirá en cada fila del grupo. Para fines de demostración, añadimos esta columna y luego reordenamos las columnas para facilitar la visualización. Consulta la sección siguiente sobre filtrar por tamaño del grupo para ver otro ejemplo.

linelist %>% 
  as_tibble() %>%                   # convertir a tibble para una mejor impresión  
  add_count(hospital) %>%           # añadir la columna n con los recuentos por hospital
  select(hospital, n, everything()) # reordenar para fines de demostración
## # A tibble: 5,888 × 31
##    hospital        n case_id gener…¹ date_inf…² date_onset date_hos…³ date_out…⁴ outcome gender   age age_u…⁵ age_y…⁶ age_cat age_c…⁷   lon   lat infec…⁸ source wt_kg ht_cm ct_bl…⁹ fever chills cough aches vomit  temp
##    <chr>       <int> <chr>     <dbl> <date>     <date>     <date>     <date>     <chr>   <chr>  <dbl> <chr>     <dbl> <fct>   <fct>   <dbl> <dbl> <chr>   <chr>  <dbl> <dbl>   <dbl> <chr> <chr>  <chr> <chr> <chr> <dbl>
##  1 Other         885 5fe599        4 2014-05-08 2014-05-13 2014-05-15 NA         <NA>    m          2 years         2 0-4     0-4     -13.2  8.47 f547d6  other     27    48      22 no    no     yes   no    yes    36.8
##  2 Missing      1469 8689b7        4 NA         2014-05-13 2014-05-14 2014-05-18 Recover f          3 years         3 0-4     0-4     -13.2  8.45 <NA>    <NA>      25    59      22 <NA>  <NA>   <NA>  <NA>  <NA>   36.9
##  3 St. Mark's…   422 11f8ea        2 NA         2014-05-16 2014-05-18 2014-05-30 Recover m         56 years        56 50-69   55-59   -13.2  8.46 <NA>    <NA>      91   238      21 <NA>  <NA>   <NA>  <NA>  <NA>   36.9
##  4 Port Hospi…  1762 b8812a        3 2014-05-04 2014-05-18 2014-05-20 NA         <NA>    f         18 years        18 15-19   15-19   -13.2  8.48 f90f5f  other     41   135      23 no    no     no    no    no     36.8
##  5 Military H…   896 893f25        3 2014-05-18 2014-05-21 2014-05-22 2014-05-29 Recover m          3 years         3 0-4     0-4     -13.2  8.46 11f8ea  other     36    71      23 no    no     yes   no    yes    36.9
##  6 Port Hospi…  1762 be99c8        3 2014-05-03 2014-05-22 2014-05-23 2014-05-24 Recover f         16 years        16 15-19   15-19   -13.2  8.46 aec8ec  other     56   116      21 no    no     yes   no    yes    37.6
##  7 Missing      1469 07e3e8        4 2014-05-22 2014-05-27 2014-05-29 2014-06-01 Recover f         16 years        16 15-19   15-19   -13.2  8.46 893f25  other     47    87      21 <NA>  <NA>   <NA>  <NA>  <NA>   37.3
##  8 Missing      1469 369449        4 2014-05-28 2014-06-02 2014-06-03 2014-06-07 Death   f          0 years         0 0-4     0-4     -13.2  8.46 133ee7  other      0    11      22 no    no     yes   no    yes    37  
##  9 Missing      1469 f393b4        4 NA         2014-06-05 2014-06-06 2014-06-18 Recover m         61 years        61 50-69   60-64   -13.2  8.46 <NA>    <NA>      86   226      22 no    no     yes   no    yes    36.4
## 10 Missing      1469 1389ca        4 NA         2014-06-05 2014-06-07 2014-06-09 Death   f         27 years        27 20-29   25-29   -13.3  8.47 <NA>    <NA>      69   174      22 no    no     yes   no    no     35.9
## # … with 5,878 more rows, 3 more variables: time_admission <chr>, bmi <dbl>, days_onset_hosp <dbl>, and abbreviated variable names ¹​generation, ²​date_infection, ³​date_hospitalisation, ⁴​date_outcome, ⁵​age_unit,
## #   ⁶​age_years, ⁷​age_cat5, ⁸​infector, ⁹​ct_blood

Añadir totales

Para añadir fácilmente filas o columnas del total de la suma después de utilizar tally() o count(), consulta la sección de janitor de la página Tablas descriptivas. Este paquete ofrece funciones como adorn_totals() y adorn_percentages() para añadir totales y convertirlos para mostrar porcentajes. A continuación se muestra un breve ejemplo:

linelist %>%                                  # listado de casos
  tabyl(age_cat, gender) %>%                  # tabulación cruzada de los recuentos de dos columnas
  adorn_totals(where = "row") %>%             # añadir una fila de totales
  adorn_percentages(denominator = "col") %>%  # convertir a proporciones con denominador de columna
  adorn_pct_formatting() %>%                  # convertir proporciones a porcentajes
  adorn_ns(position = "front") %>%            # mostrar como "count (percent)"
  adorn_title(                                # ajustar títulos
    row_name = "Age Category",
    col_name = "Gender")
##                      Gender                           
##  Age Category             f             m          NA_
##           0-4  640  (22.8%)  416  (14.8%)  39  (14.0%)
##           5-9  641  (22.8%)  412  (14.7%)  42  (15.1%)
##         10-14  518  (18.5%)  383  (13.7%)  40  (14.4%)
##         15-19  359  (12.8%)  364  (13.0%)  20   (7.2%)
##         20-29  468  (16.7%)  575  (20.5%)  30  (10.8%)
##         30-49  179   (6.4%)  557  (19.9%)  18   (6.5%)
##         50-69    2   (0.1%)   91   (3.2%)   2   (0.7%)
##           70+    0   (0.0%)    5   (0.2%)   1   (0.4%)
##          <NA>    0   (0.0%)    0   (0.0%)  86  (30.9%)
##         Total 2807 (100.0%) 2803 (100.0%) 278 (100.0%)

Para añadir filas de totales más complejas que incluyan estadísticas de resumen distintas de las sumas, consulta esta sección de la página Tablas descriptivas.

13.6 Agrupar por fechas

Al agrupar datos por fecha, debes tener (o crear) una columna para la unidad de fecha de interés - por ejemplo “día”, “epiweek”, “mes”, etc. Puedes crear esta columna utilizando floor_date() de lubridate, como se explica en la sección Semanas epidemiológicas de la página Trabajar con fechas. Una vez que tengas esta columna, puedes utilizar count() de dplyr para agrupar las filas por esos valores de fecha únicos y lograr recuentos agregados.

Un paso adicional común para las situaciones de fechas, es “rellenar” cualquier fecha en la que no haya datos. Utiliza complete() de tidyr para que la serie de fechas agregadas esté completa, incluyendo todas las unidades de fecha posibles dentro del rango. Sin este paso, una semana sin casos reportados podría no aparecer en tus datos.

Dentro de complete() redefine la columna de fecha como una secuencia de fechas seq.Date() desde el mínimo hasta el máximo - así las fechas se expanden. Por defecto, los valores del recuento de casos en cualquier nueva fila “expandida” serán NA. Puedes establecerlos a 0 utilizando el argumento fill = de complete(), que espera una lista con nombre (si la columna de recuentos se llama n, escribe fill = list(n = 0). Consulta ?complete para obtener más detalles y la página Trabajar con fechas para ver un ejemplo.

Casos por día

Aquí hay un ejemplo de agrupación de casos en días sin usar complete(). Obsérvese que las primeras filas omiten las fechas sin casos.

daily_counts <- linelist %>% 
  drop_na(date_onset) %>%        # eliminar los que no tienen date_onset
  count(date_onset)              # contar el número de filas por fecha única

A continuación añadimos el comando complete() para asegurarnos de que todos los días del rango están representados.

daily_counts <- linelist %>% 
  drop_na(date_onset) %>%                 # eliminar los que no tienen date_onset
  count(date_onset) %>%                   # contar el número de filas por fecha única
  complete(                               # asegurar que aparecen todos los días aunque no haya casos
    date_onset = seq.Date(                # redefinir el conjunto de fechas como una secuencia diaria de fechas
      from = min(date_onset, na.rm=T), 
      to = max(date_onset, na.rm=T),
      by = "day"),
    fill = list(n = 0))                   # establecer que las nuevas filas rellenadas muestren 0 en la columna n (no NA por defecto)

Casos por semana

Se puede aplicar el mismo principio para las semanas. Primero crea una nueva columna que sea la semana del caso utilizando floor_date() con unit = "week". A continuación, utiliza count() como en el caso anterior para obtener los recuentos de casos semanales. Termina con complete() para asegurarte de que todas las semanas están representadas, incluso si no contienen casos.

# Make dataset of weekly case counts
weekly_counts <- linelist %>% 
  drop_na(date_onset) %>%                 # eliminar los que no tienen date_onset
  mutate(week = lubridate::floor_date(date_onset, unit = "week")) %>%  # nueva columna de semana de inicio
  count(week) %>%                         # agrupar los datos por semana y contar las filas por grupo
  complete(                               # asegurar que aparecen todos los días aunque no haya casos
    week = seq.Date(                      # redefinir el conjunto de fechas como una secuencia diaria de fechas
      from = min(week, na.rm=T), 
      to = max(week, na.rm=T),
      by = "week"),
    fill = list(n = 0))                   # establecer que las nuevas filas rellenadas muestren 0 en la columna n (no NA por defecto) 

Aquí están las primeras 50 filas del dataframe resultante:

Casos por mes

Para agregar casos en meses, vuelve a utilizar floor_date() del paquete lubridate, pero con el argumento unit = "months". Esto redondea cada fecha hacia abajo al día 1 de su mes. La salida será el tipo Date. Ten en cuenta que en el paso complete() también utilizamos by = "months".

# Make dataset of monthly case counts
monthly_counts <- linelist %>% 
  drop_na(date_onset) %>% 
  mutate(month = lubridate::floor_date(date_onset, unit = "months")) %>%  # nueva columna, 1º del mes de inicio
  count(month) %>%                          # recuento de casos por mes
  complete(
    month = seq.Date(
      min(month, na.rm=T),     # incluir todos los meses sin casos declarados
      max(month, na.rm=T),
      by="month"),
    fill = list(n = 0))

Recuentos diarios en semanas

Para agregar los recuentos diarios en recuentos semanales, utiliza floor_date() igual queo arriba. Sin embargo, utiliza group_by() y summarize() en lugar de count() porque necesita sum() los recuentos de casos diarios en lugar de limitarse a contar el número de filas por semana.

Daily counts into months

Para agregar los recuentos diarios en recuentos por meses, utiliza floor_date() con unit = "month" como en el caso anterior. Sin embargo, utiliza group_by() y summarize() en lugar de count() porque necesitasum()los recuentos de casos diarios en lugar de limitarse a contar el número de filas por mes.

13.7 Ordenar los datos agrupados

El verbo arrange() de dplyr para ordenar las filas de un dataframe se comporta igual cuando los datos están agrupados, a menos que se establezca el argumento .by_group =TRUE. En este caso, las filas se ordenan primero por las columnas de agrupación y luego por cualquier otra columna que se especifique en arrange().

13.8 Filtrar sobre datos agrupados

filter()

Cuando se aplica junto con funciones que evalúan el dataframe (como max(), min(), mean()), estas funciones se aplicarán ahora a los grupos. Por ejemplo, si deseas filtrar y mantener las filas en las que los pacientes están por encima de la edad media, esto se aplicará ahora por grupo, filtrando para mantener las filas por encima de la edad media del grupo.

Clasificar filas por grupo

La función slice() de dplyr, que filtra las filas según su posición en los datos, también puede aplicarse por grupo. Recuerda que debes tener en cuenta la ordenación de los datos dentro de cada grupo para obtener la “rebanada” deseada.

Por ejemplo, para recuperar sólo los últimos 5 ingresos de cada hospital:

  1. Agrupar linelist por columna hospital
  2. Ordenar los registros por date_hospitalisation de más reciente a la más antigua dentro de cada grupo de hospitales
  3. Clasificar para recuperar las 5 primeras filas de cada hospital
linelist %>%
  group_by(hospital) %>%
  arrange(hospital, date_hospitalisation) %>%
  slice_head(n = 5) %>% 
  arrange(hospital) %>%                            # para mostrar
  select(case_id, hospital, date_hospitalisation)  # para mostrar
## # A tibble: 30 × 3
## # Groups:   hospital [6]
##    case_id hospital          date_hospitalisation
##    <chr>   <chr>             <date>              
##  1 20b688  Central Hospital  2014-05-06          
##  2 d58402  Central Hospital  2014-05-10          
##  3 b8f2fd  Central Hospital  2014-05-13          
##  4 acf422  Central Hospital  2014-05-28          
##  5 275cc7  Central Hospital  2014-05-28          
##  6 d1fafd  Military Hospital 2014-04-17          
##  7 974bc1  Military Hospital 2014-05-13          
##  8 6a9004  Military Hospital 2014-05-13          
##  9 09e386  Military Hospital 2014-05-14          
## 10 865581  Military Hospital 2014-05-15          
## # … with 20 more rows

slice_head() - selecciona n filas de la parte superior slice_tail() - selecciona n filas del final slice_sample() - selecciona aleatoriamente n filas slice_min() - selecciona n filas con los valores más altos en order_by =columna, usa with_ties = TRUE para mantener los empates slice_max() - selecciona n filas con los valores más bajos en order_by =columna, utiliza with_ties = TRUE para mantener los empates

Consulta la página de De-duplicación para ver más ejemplos y detalles sobre slice().

Filtro por tamaño de grupo

La función add_count() añade una columna n a los datos originales dando el número de filas en el grupo de esa fila.

A continuación, add_count() se aplica a la columna hospital, por lo que los valores de la nueva columna n reflejan el número de filas del grupo de hospitales de esa fila. Observe cómo se repiten los valores de la columna n. En el ejemplo siguiente, el nombre de la columna n podría cambiarse utilizando name = dentro de add_count(). Para fines de demostración reordenamos las columnas con select().

linelist %>% 
  as_tibble() %>% 
  add_count(hospital) %>%          # añadir "número de filas admitidas en el mismo hospital que esta fila" 
  select(hospital, n, everything())
## # A tibble: 5,888 × 31
##    hospital        n case_id gener…¹ date_inf…² date_onset date_hos…³ date_out…⁴ outcome gender   age age_u…⁵ age_y…⁶ age_cat age_c…⁷   lon   lat infec…⁸ source wt_kg ht_cm ct_bl…⁹ fever chills cough aches vomit  temp
##    <chr>       <int> <chr>     <dbl> <date>     <date>     <date>     <date>     <chr>   <chr>  <dbl> <chr>     <dbl> <fct>   <fct>   <dbl> <dbl> <chr>   <chr>  <dbl> <dbl>   <dbl> <chr> <chr>  <chr> <chr> <chr> <dbl>
##  1 Other         885 5fe599        4 2014-05-08 2014-05-13 2014-05-15 NA         <NA>    m          2 years         2 0-4     0-4     -13.2  8.47 f547d6  other     27    48      22 no    no     yes   no    yes    36.8
##  2 Missing      1469 8689b7        4 NA         2014-05-13 2014-05-14 2014-05-18 Recover f          3 years         3 0-4     0-4     -13.2  8.45 <NA>    <NA>      25    59      22 <NA>  <NA>   <NA>  <NA>  <NA>   36.9
##  3 St. Mark's…   422 11f8ea        2 NA         2014-05-16 2014-05-18 2014-05-30 Recover m         56 years        56 50-69   55-59   -13.2  8.46 <NA>    <NA>      91   238      21 <NA>  <NA>   <NA>  <NA>  <NA>   36.9
##  4 Port Hospi…  1762 b8812a        3 2014-05-04 2014-05-18 2014-05-20 NA         <NA>    f         18 years        18 15-19   15-19   -13.2  8.48 f90f5f  other     41   135      23 no    no     no    no    no     36.8
##  5 Military H…   896 893f25        3 2014-05-18 2014-05-21 2014-05-22 2014-05-29 Recover m          3 years         3 0-4     0-4     -13.2  8.46 11f8ea  other     36    71      23 no    no     yes   no    yes    36.9
##  6 Port Hospi…  1762 be99c8        3 2014-05-03 2014-05-22 2014-05-23 2014-05-24 Recover f         16 years        16 15-19   15-19   -13.2  8.46 aec8ec  other     56   116      21 no    no     yes   no    yes    37.6
##  7 Missing      1469 07e3e8        4 2014-05-22 2014-05-27 2014-05-29 2014-06-01 Recover f         16 years        16 15-19   15-19   -13.2  8.46 893f25  other     47    87      21 <NA>  <NA>   <NA>  <NA>  <NA>   37.3
##  8 Missing      1469 369449        4 2014-05-28 2014-06-02 2014-06-03 2014-06-07 Death   f          0 years         0 0-4     0-4     -13.2  8.46 133ee7  other      0    11      22 no    no     yes   no    yes    37  
##  9 Missing      1469 f393b4        4 NA         2014-06-05 2014-06-06 2014-06-18 Recover m         61 years        61 50-69   60-64   -13.2  8.46 <NA>    <NA>      86   226      22 no    no     yes   no    yes    36.4
## 10 Missing      1469 1389ca        4 NA         2014-06-05 2014-06-07 2014-06-09 Death   f         27 years        27 20-29   25-29   -13.3  8.47 <NA>    <NA>      69   174      22 no    no     yes   no    no     35.9
## # … with 5,878 more rows, 3 more variables: time_admission <chr>, bmi <dbl>, days_onset_hosp <dbl>, and abbreviated variable names ¹​generation, ²​date_infection, ³​date_hospitalisation, ⁴​date_outcome, ⁵​age_unit,
## #   ⁶​age_years, ⁷​age_cat5, ⁸​infector, ⁹​ct_blood

De este modo, resulta fácil filtrar los casos que fueron hospitalizados en un hospital “pequeño”, por ejemplo, un hospital que admitió a menos de 500 pacientes:

linelist %>% 
  add_count(hospital) %>% 
  filter(n < 500)

13.9 Mutate con datos agrupados

Para conservar todas las columnas y filas (no resumir) y añadir una nueva columna que contenga estadísticas de grupo, utiliza mutate() después de group_by() en lugar de summarise().

Esto es útil si se desea obtener estadísticas de grupo en los datos originales con todas las demás columnas presentes, por ejemplo, para los cálculos que comparan una fila con su grupo.

Por ejemplo, este código calcula la diferencia entre la demora en el ingreso de una fila y la demora media de su hospital. Los pasos son:

  1. Agrupar los datos por hospital
  2. Utiliza la columna days_onset_hosp (retraso hasta la hospitalización) para crear una nueva columna que contenga el retraso medio en el hospital de esa fila
  3. Calcular la diferencia entre las dos columnas

Seleccionamos (select()) sólo ciertas columnas para mostrarlas, con fines de demostración.

linelist %>% 
  # agrupar datos por hospital (aún no hay cambios en linelist)
  group_by(hospital) %>% 
  
  # nuevas columnas
  mutate(
    # media de días hasta el ingreso por hospital (redondeada a 1 decimal)
    group_delay_admit = round(mean(days_onset_hosp, na.rm=T), 1),
    
    # diferencia entre la demora de la fila y la demora media en su hospital (redondeada a 1 decimal)
    diff_to_group     = round(days_onset_hosp - group_delay_admit, 1)) %>%
  
  # seleccionar sólo ciertas filas - con fines de demostración/visualización
  select(case_id, hospital, days_onset_hosp, group_delay_admit, diff_to_group)
## # A tibble: 5,888 × 5
## # Groups:   hospital [6]
##    case_id hospital                             days_onset_hosp group_delay_admit diff_to_group
##    <chr>   <chr>                                          <dbl>             <dbl>         <dbl>
##  1 5fe599  Other                                              2               2             0  
##  2 8689b7  Missing                                            1               2.1          -1.1
##  3 11f8ea  St. Mark's Maternity Hospital (SMMH)               2               2.1          -0.1
##  4 b8812a  Port Hospital                                      2               2.1          -0.1
##  5 893f25  Military Hospital                                  1               2.1          -1.1
##  6 be99c8  Port Hospital                                      1               2.1          -1.1
##  7 07e3e8  Missing                                            2               2.1          -0.1
##  8 369449  Missing                                            1               2.1          -1.1
##  9 f393b4  Missing                                            1               2.1          -1.1
## 10 1389ca  Missing                                            2               2.1          -0.1
## # … with 5,878 more rows

13.10 Seleccionar sobre datos agrupados

El verbo select() funciona con datos agrupados, pero las columnas de agrupación siempre se incluyen (aunque no se mencionen en select()). Si no deseas estas columnas de agrupación, utiliza primero ungroup().

13.11 Recursos

A continuación, algunos recursos útiles para obtener más información:

Puedes realizar cualquier función de resumen sobre datos agrupados; consulta la hoja de trucos de transformación de datos de RStudio

La página de Data Carpentry sobre dplyr

Las páginas de referencia de tidyverse sobre group_by() y agrupación

Esta página sobre Manipulación de datos

Resumir con condiciones en dplyr