10  dplyr - gramática para manipulación de datos

10.1 Resumen

El paquete dplyr proporciona un conjunto de funciones que ayudan a solucionar las tareas de transformación de datos más comunes, entre las que están la selección de columnas, el ordenamiento de filas, el filtrado de filas, la creación o modificación de columnas y los cálculos en grupos de filas. Estas transformaciones son usualmente requeridas antes de la visualización y el modelado de los datos.

10.2 Trabajo previo

10.2.1 Lecturas

Wickham, H., Çetinkaya-Rundel, M., & Grolemund, G. (s. f.). R for Data Science (2nd ed.) Chapter 4 - Data transformation. Recuperado 28 de abril de 2023, de https://r4ds.hadley.nz/data-transform.html

10.3 Introducción

El paquete dplyr de Tidyverse es descrito como una gramática para la manipulación de datos, la cual proporciona un conjunto consistente de verbos que ayuda a solucionar los retos de procesamiento de datos más comunes. Los principales “verbos” (i.e. funciones) de esta gramática son:

  • select(): selecciona columnas con base en sus nombres.

  • filter(): selecciona filas con base en sus valores.

  • arrange(): cambia el orden de las filas.

  • mutate(): crea nuevas columnas, las cuales se expresan como funciones de columnas existentes.

  • summarize(): agrupa y resume valores.

Todas estas operaciones pueden combinarse con la función group_by(), la cual ejecuta cualquiera de las operaciones anteriores “en grupo”. Además, dplyr proporciona funciones adicionales para tareas más específicas.

Las funciones de dplyr pueden encadenarse a través del operador pipe (tubo), ya sea el del paquete magrittr (%>%) o el del paquete base de R (|>). Los procesos se enlazan con pipes para formar pipelines (tuberías).

Todas las funciones de dplyr trabajan de manera similar:

  1. El primer argumento siempre es un data frame. Puede omitirse si la función recibe el data frame a través del operador pipe.
  2. Los argumentos siguientes describen que hacer con el data frame, utilizando los nombres de las columnas (sin comillas).
  3. El resultado siempre es un nuevo data frame.

Ya que cada función de dplyr se especializa en una sola tarea, usualmente es necesario encadenar funciones mediante pipes para lograr un objetivo de procesamiento de datos. Por ejemplo, el siguiente bloque de código usa tres verbos, o funciones, de dplyr para obtener la masa promedio de cada especie de pingüinos que habita en la isla Biscoe.

# Cálculo de la masa promedio para cada especie de pingüinos
# que habita en la isla Biscoe
penguins |>
  filter(island == "Biscoe") |> 
  group_by(species) |> 
  summarize(
    body_mass_g_mean = mean(body_mass_g, na.rm = TRUE)
  )
A tibble: 2 × 2
species body_mass_g_mean
<fct>              <dbl>
Adelie          3710.659
Gentoo          5076.016

10.4 Instalación y carga

El paquete dplyr puede instalarse junto con todos los demás paquete de Tidyverse o de manera individual:

# Instalación conjunta de Tidyverse
install.packages("tidyverse")

# Instalación individual
install.packages("dplyr")

Una vez instalado, dplyr puede cargarse con la función library():

# Carga conjunta de Tidyverse
library(tidyverse)

# Carga individual
library(dplyr)

Seguidamente, se cargan algunos paquetes adicionales que se utilizan en este capítulo.

# Carga de readr, paquete para lectura de datos
library(readr)

# Carga de tidyr, paquete para creación de datos "tidy"
library(tidyr)

10.5 Conjuntos de datos para ejemplos

En los ejemplos de este capítulo, se utilizan dos conjunto de datos:

10.5.1 penguins

Para cargar el conjunto de datos penguins, basta con cargar el paquete palmerpenguins.

# Carga del paquete de datos palmerpenguins
library(palmerpenguins)

La función glimpse() despliega la estructura de un conjunto de datos, incluyendo los nombres de las columnas, sus tipos de datos y una muestra de estos:

# Estructura del conjunto de datos penguins
glimpse(penguins)
Rows: 344
Columns: 8
$ species           <fct> Adelie, Adelie, Adelie, Adelie, Adelie, Adelie, Adel…
$ island            <fct> Torgersen, Torgersen, Torgersen, Torgersen, Torgerse…
$ bill_length_mm    <dbl> 39.1, 39.5, 40.3, NA, 36.7, 39.3, 38.9, 39.2, 34.1, …
$ bill_depth_mm     <dbl> 18.7, 17.4, 18.0, NA, 19.3, 20.6, 17.8, 19.6, 18.1, …
$ flipper_length_mm <int> 181, 186, 195, NA, 193, 190, 181, 195, 193, 190, 186…
$ body_mass_g       <int> 3750, 3800, 3250, NA, 3450, 3650, 3625, 4675, 3475, …
$ sex               <fct> male, female, female, NA, female, male, female, male…
$ year              <int> 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007…

Un conjunto de datos puede visualizarse al escribir su nombre en la consola de R o en un programa:

# Despliegue de los datos de penguins
penguins
# A tibble: 344 × 8
   species island    bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
   <fct>   <fct>              <dbl>         <dbl>             <int>       <int>
 1 Adelie  Torgersen           39.1          18.7               181        3750
 2 Adelie  Torgersen           39.5          17.4               186        3800
 3 Adelie  Torgersen           40.3          18                 195        3250
 4 Adelie  Torgersen           NA            NA                  NA          NA
 5 Adelie  Torgersen           36.7          19.3               193        3450
 6 Adelie  Torgersen           39.3          20.6               190        3650
 7 Adelie  Torgersen           38.9          17.8               181        3625
 8 Adelie  Torgersen           39.2          19.6               195        4675
 9 Adelie  Torgersen           34.1          18.1               193        3475
10 Adelie  Torgersen           42            20.2               190        4250
# ℹ 334 more rows
# ℹ 2 more variables: sex <fct>, year <int>

penguins es un tibble, un tipo especial de data frame que se utiliza en Tidyverse. La diferencia más importante entre un tibble y un data frame es la manera en la que se imprimen: los tibbles están diseñados para conjuntos de datos grandes, por lo que solo muestran los primeros registros y las columnas que caben en la pantalla. Un data frame regular muestra todas sus columnas y muchos más registros, lo que dificulta su visualización. En general, un data frame regular y un tibble pueden tratarse indistintamente.

10.5.2 Estadísticas de delitos cometidos en 2022

Se utiliza la función readr::read_csv() para leer un archivo CSV almacenado en el repositorio GitHub de este curso, con los datos de las estadísticas policiales proporcionados por el OIJ en formato Excel. readr::read_csv() es más eficiente que read.csv() (del paquete base de R) y tiene otras ventajas como detección automática de tipos de datos y mejor integración con otros paquetes de Tidyverse (ej. dplyr, tidyr, ggplot2).

# Carga de los datos de delitos cometidos en 2022
delitos_2022 <-
  read.csv(
    "https://raw.githubusercontent.com/gf0604-procesamientodatosgeograficos/2023-i/main/datos/oij/estadisticas-policiales/estadisticaspoliciales2022.csv"
  )

Estructura del conjunto de datos:

# Estructura de los datos de delitos cometidos en 2022
glimpse(delitos_2022)
Rows: 96,651
Columns: 12
$ Delito       <chr> "DELITOS CONTRA LA ADMINISTRACION DE JUSTICIA", "DELITOS …
$ SubDelito    <chr> "FALSAS ACUSACIONES", "AMENAZA A UN FUNCIONARIO PUBLICO",…
$ Fecha        <chr> "12/31/2022", "12/31/2022", "12/31/2022", "12/31/2022", "…
$ Hora         <chr> "09:00:00 - 11:59:59", "12:00:00 - 14:59:59", "15:00:00 -…
$ Victima      <chr> "VEHICULO", "PERSONA", "PERSONA", "PERSONA", "PERSONA", "…
$ SubVictima   <chr> "SERVICIO PUBLICO/TAXI LEGAL O PIRATA/AUTOBUS", "OTRO O I…
$ Edad         <chr> "Adulto Mayor", "Mayor de edad", "Mayor de edad", "Mayor …
$ Genero       <chr> "Adulto Mayor", "Mayor de edad", "Mayor de edad", "Mayor …
$ Nacionalidad <chr> "COSTA RICA", "COSTA RICA", "COSTA RICA", "COSTA RICA", "…
$ Provincia    <chr> "SAN JOSE", "SAN JOSE", "LIMON", "CARTAGO", "PUNTARENAS",…
$ Canton       <chr> "SAN JOSE", "PEREZ ZELEDON", "SIQUIRRES", "CARTAGO", "QUE…
$ Distrito     <chr> "HOSPITAL", "DANIEL FLORES", "SIQUIRRES", "GUADALUPE", "Q…

Despliegue de los datos (debido a que delitos_2022 es un data frame, pero no un tibble, se limitan las filas y columnas que se muestran):

# Despliegue de una muestra de los datos de delitos cometidos en 2022
delitos_2022[1:10, c("Delito", "Victima", "Provincia")]
                                         Delito  Victima  Provincia
1  DELITOS CONTRA LA ADMINISTRACION DE JUSTICIA VEHICULO   SAN JOSE
2           DELITOS CONTRA LA AUTORIDAD PUBLICA  PERSONA   SAN JOSE
3                    DELITOS CONTRA LA LIBERTAD  PERSONA      LIMON
4                    DELITOS CONTRA LA LIBERTAD  PERSONA    CARTAGO
5                    DELITOS CONTRA LA LIBERTAD  PERSONA PUNTARENAS
6                    DELITOS CONTRA LA LIBERTAD  PERSONA   SAN JOSE
7                    DELITOS CONTRA LA LIBERTAD  PERSONA   SAN JOSE
8                    DELITOS CONTRA LA LIBERTAD  PERSONA   SAN JOSE
9                    DELITOS CONTRA LA LIBERTAD  PERSONA   SAN JOSE
10                   DELITOS CONTRA LA LIBERTAD  PERSONA   SAN JOSE

En RStudio, un conjunto de datos completo puede verse más cómodamente con la función View().

10.6 Funciones

En esta sección, se describen y ejemplifican las principales funciones de dplyr.

10.6.1 select()

La función select() selecciona (y opcionalmente renombra) columnas de un data frame con base en sus nombres.

# Selección de las columnas species, bill_length_mm y sex
penguins |>
  select(species, bill_length_mm, sex)
# A tibble: 344 × 3
   species bill_length_mm sex   
   <fct>            <dbl> <fct> 
 1 Adelie            39.1 male  
 2 Adelie            39.5 female
 3 Adelie            40.3 female
 4 Adelie            NA   <NA>  
 5 Adelie            36.7 female
 6 Adelie            39.3 male  
 7 Adelie            38.9 female
 8 Adelie            39.2 male  
 9 Adelie            34.1 <NA>  
10 Adelie            42   <NA>  
# ℹ 334 more rows

Cambio de nombres de columnas:

# Selección y cambio de nombre de las columnas 
# species, bill_length_mm y sex
penguins |>
  select(especie = species,
         longitud_pico_mm = bill_length_mm,
         sexo = sex)
# A tibble: 344 × 3
   especie longitud_pico_mm sexo  
   <fct>              <dbl> <fct> 
 1 Adelie              39.1 male  
 2 Adelie              39.5 female
 3 Adelie              40.3 female
 4 Adelie              NA   <NA>  
 5 Adelie              36.7 female
 6 Adelie              39.3 male  
 7 Adelie              38.9 female
 8 Adelie              39.2 male  
 9 Adelie              34.1 <NA>  
10 Adelie              42   <NA>  
# ℹ 334 more rows

El operador : permite seleccionar un rango de columnas continuas:

# Selección de las columnas desde species a flipper_length_mm
penguins |>
  select(species:flipper_length_mm)
# A tibble: 344 × 5
   species island    bill_length_mm bill_depth_mm flipper_length_mm
   <fct>   <fct>              <dbl>         <dbl>             <int>
 1 Adelie  Torgersen           39.1          18.7               181
 2 Adelie  Torgersen           39.5          17.4               186
 3 Adelie  Torgersen           40.3          18                 195
 4 Adelie  Torgersen           NA            NA                  NA
 5 Adelie  Torgersen           36.7          19.3               193
 6 Adelie  Torgersen           39.3          20.6               190
 7 Adelie  Torgersen           38.9          17.8               181
 8 Adelie  Torgersen           39.2          19.6               195
 9 Adelie  Torgersen           34.1          18.1               193
10 Adelie  Torgersen           42            20.2               190
# ℹ 334 more rows

Selección de todas las columnas que cumplen una condición:

# Selección de las columnas numéricas
penguins |>
  select(where(is.numeric))
# A tibble: 344 × 5
   bill_length_mm bill_depth_mm flipper_length_mm body_mass_g  year
            <dbl>         <dbl>             <int>       <int> <int>
 1           39.1          18.7               181        3750  2007
 2           39.5          17.4               186        3800  2007
 3           40.3          18                 195        3250  2007
 4           NA            NA                  NA          NA  2007
 5           36.7          19.3               193        3450  2007
 6           39.3          20.6               190        3650  2007
 7           38.9          17.8               181        3625  2007
 8           39.2          19.6               195        4675  2007
 9           34.1          18.1               193        3475  2007
10           42            20.2               190        4250  2007
# ℹ 334 more rows

10.6.2 filter()

La función filter() retorna un subconjunto de un data frame con todas las filas que satisfacen una condición (i.e. expresión lógica).

Puede utilizar los operadores relacionales:

  • == (igual que) Note la diferencia con el operador de asignación: =
  • != (diferente de)
  • > (estrictamente mayor que), >= (mayor o igual que)
  • < (estrictamente menor que), <= (menor o igual que)

Y los operadores lógicos:

  • & (AND o Y lógico)
  • | (OR u O lógico)
  • ! (NOT o NO lógico)

Ejemplos de uso de expresiones y operadores lógicos:

# Pingüinos de la especie 'Adelie' 
# con longitud del pico mayor o igual a 45 mm
penguins |>
  filter(species == 'Adelie' & bill_length_mm >= 45)
# A tibble: 3 × 8
  species island    bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
  <fct>   <fct>              <dbl>         <dbl>             <int>       <int>
1 Adelie  Torgersen           46            21.5               194        4200
2 Adelie  Torgersen           45.8          18.9               197        4150
3 Adelie  Biscoe              45.6          20.3               191        4600
# ℹ 2 more variables: sex <fct>, year <int>
# Pingüinos de las especies 'Adelie' o 'Gentoo'
penguins |>
  filter(species == 'Adelie' | species == 'Gentoo')
# A tibble: 276 × 8
   species island    bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
   <fct>   <fct>              <dbl>         <dbl>             <int>       <int>
 1 Adelie  Torgersen           39.1          18.7               181        3750
 2 Adelie  Torgersen           39.5          17.4               186        3800
 3 Adelie  Torgersen           40.3          18                 195        3250
 4 Adelie  Torgersen           NA            NA                  NA          NA
 5 Adelie  Torgersen           36.7          19.3               193        3450
 6 Adelie  Torgersen           39.3          20.6               190        3650
 7 Adelie  Torgersen           38.9          17.8               181        3625
 8 Adelie  Torgersen           39.2          19.6               195        4675
 9 Adelie  Torgersen           34.1          18.1               193        3475
10 Adelie  Torgersen           42            20.2               190        4250
# ℹ 266 more rows
# ℹ 2 more variables: sex <fct>, year <int>
# Pingüinos de especies diferentes a 'Chinstrap'
penguins |>
  filter(!(species == 'Chinstrap'))
# A tibble: 276 × 8
   species island    bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
   <fct>   <fct>              <dbl>         <dbl>             <int>       <int>
 1 Adelie  Torgersen           39.1          18.7               181        3750
 2 Adelie  Torgersen           39.5          17.4               186        3800
 3 Adelie  Torgersen           40.3          18                 195        3250
 4 Adelie  Torgersen           NA            NA                  NA          NA
 5 Adelie  Torgersen           36.7          19.3               193        3450
 6 Adelie  Torgersen           39.3          20.6               190        3650
 7 Adelie  Torgersen           38.9          17.8               181        3625
 8 Adelie  Torgersen           39.2          19.6               195        4675
 9 Adelie  Torgersen           34.1          18.1               193        3475
10 Adelie  Torgersen           42            20.2               190        4250
# ℹ 266 more rows
# ℹ 2 more variables: sex <fct>, year <int>
# Homicidios cometidos en el cantón de Esparza
delitos_2022 |>
  filter(SubDelito == "HOMICIDIO" & Canton == "ESPARZA") |>
  select(SubDelito, Canton, Fecha, Victima, Edad, Nacionalidad)
  SubDelito  Canton      Fecha Victima          Edad Nacionalidad
1 HOMICIDIO ESPARZA 12/24/2022 PERSONA Mayor de edad   COSTA RICA
2 HOMICIDIO ESPARZA 06/13/2022 PERSONA Mayor de edad   COSTA RICA
3 HOMICIDIO ESPARZA 05/13/2022 PERSONA   Desconocido  Desconocido
4 HOMICIDIO ESPARZA 04/08/2022 PERSONA Mayor de edad     COLOMBIA
5 HOMICIDIO ESPARZA 03/20/2022 PERSONA Mayor de edad   COSTA RICA
6 HOMICIDIO ESPARZA 01/06/2022 PERSONA Menor de edad   COSTA RICA
# Homicidios cometidos en el cantón de Esparza 
# a personas no costarricenses
delitos_2022 |>
  filter(SubDelito == "HOMICIDIO" &
      Canton == "ESPARZA" & Nacionalidad != "COSTA RICA") |>
  select(SubDelito, Canton, Fecha, Victima, Edad, Nacionalidad)
  SubDelito  Canton      Fecha Victima          Edad Nacionalidad
1 HOMICIDIO ESPARZA 05/13/2022 PERSONA   Desconocido  Desconocido
2 HOMICIDIO ESPARZA 04/08/2022 PERSONA Mayor de edad     COLOMBIA
# Pingüinos con longitud del pico mayor o igual al promedio
#   El argumento lógico na.rm de mean() 
#   indica si los valores NA ("not available") 
#   deben ser removidos antes del cálculo
penguins |>
  filter(bill_length_mm >= mean(bill_length_mm, na.rm = TRUE))
# A tibble: 175 × 8
   species island    bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
   <fct>   <fct>              <dbl>         <dbl>             <int>       <int>
 1 Adelie  Torgersen           46            21.5               194        4200
 2 Adelie  Dream               44.1          19.7               196        4400
 3 Adelie  Torgersen           45.8          18.9               197        4150
 4 Adelie  Biscoe              45.6          20.3               191        4600
 5 Adelie  Torgersen           44.1          18                 210        4000
 6 Gentoo  Biscoe              46.1          13.2               211        4500
 7 Gentoo  Biscoe              50            16.3               230        5700
 8 Gentoo  Biscoe              48.7          14.1               210        4450
 9 Gentoo  Biscoe              50            15.2               218        5700
10 Gentoo  Biscoe              47.6          14.5               215        5400
# ℹ 165 more rows
# ℹ 2 more variables: sex <fct>, year <int>

Condiciones relacionadas con valores NA (nulos):

# Filas con valor NA en la columna sex
penguins |>
  select(species, island, sex) |>
  filter(is.na(sex))
# A tibble: 11 × 3
   species island    sex  
   <fct>   <fct>     <fct>
 1 Adelie  Torgersen <NA> 
 2 Adelie  Torgersen <NA> 
 3 Adelie  Torgersen <NA> 
 4 Adelie  Torgersen <NA> 
 5 Adelie  Torgersen <NA> 
 6 Adelie  Dream     <NA> 
 7 Gentoo  Biscoe    <NA> 
 8 Gentoo  Biscoe    <NA> 
 9 Gentoo  Biscoe    <NA> 
10 Gentoo  Biscoe    <NA> 
11 Gentoo  Biscoe    <NA> 

La función tidyr::drop_na() remueve las filas con valores NA en una o varias columnas.

# Filas con valor diferente a NA en la columna sex
penguins |>
  select(species,
         bill_length_mm,
         bill_depth_mm,
         flipper_length_mm,
         body_mass_g,
         sex) |>
  drop_na(sex)
# A tibble: 333 × 6
   species bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex   
   <fct>            <dbl>         <dbl>             <int>       <int> <fct> 
 1 Adelie            39.1          18.7               181        3750 male  
 2 Adelie            39.5          17.4               186        3800 female
 3 Adelie            40.3          18                 195        3250 female
 4 Adelie            36.7          19.3               193        3450 female
 5 Adelie            39.3          20.6               190        3650 male  
 6 Adelie            38.9          17.8               181        3625 female
 7 Adelie            39.2          19.6               195        4675 male  
 8 Adelie            41.1          17.6               182        3200 female
 9 Adelie            38.6          21.2               191        3800 male  
10 Adelie            34.6          21.1               198        4400 male  
# ℹ 323 more rows
# Filas con valor diferente a NA en cualquier columna
penguins |>
  select(species,
         bill_length_mm,
         bill_depth_mm,
         flipper_length_mm,
         body_mass_g,
         sex) |>
  drop_na()
# A tibble: 333 × 6
   species bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex   
   <fct>            <dbl>         <dbl>             <int>       <int> <fct> 
 1 Adelie            39.1          18.7               181        3750 male  
 2 Adelie            39.5          17.4               186        3800 female
 3 Adelie            40.3          18                 195        3250 female
 4 Adelie            36.7          19.3               193        3450 female
 5 Adelie            39.3          20.6               190        3650 male  
 6 Adelie            38.9          17.8               181        3625 female
 7 Adelie            39.2          19.6               195        4675 male  
 8 Adelie            41.1          17.6               182        3200 female
 9 Adelie            38.6          21.2               191        3800 male  
10 Adelie            34.6          21.1               198        4400 male  
# ℹ 323 more rows

10.6.3 arrange()

La función arrange() cambia el orden de las filas de un data frame de acuerdo con los valores de las columnas seleccionadas.

# Ordenamiento ascendente por las columnas 
# bill_length_mm y bill_depth_mm
penguins |>
  arrange(bill_length_mm, bill_depth_mm)
# A tibble: 344 × 8
   species island    bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
   <fct>   <fct>              <dbl>         <dbl>             <int>       <int>
 1 Adelie  Dream               32.1          15.5               188        3050
 2 Adelie  Dream               33.1          16.1               178        2900
 3 Adelie  Torgersen           33.5          19                 190        3600
 4 Adelie  Dream               34            17.1               185        3400
 5 Adelie  Torgersen           34.1          18.1               193        3475
 6 Adelie  Torgersen           34.4          18.4               184        3325
 7 Adelie  Biscoe              34.5          18.1               187        2900
 8 Adelie  Torgersen           34.6          17.2               189        3200
 9 Adelie  Torgersen           34.6          21.1               198        4400
10 Adelie  Biscoe              35            17.9               190        3450
# ℹ 334 more rows
# ℹ 2 more variables: sex <fct>, year <int>

Por defecto, las columnas se ordenan de manera acendente. Si se desea un orden descendente, puede utilizarse la función desc().

# Ordenamiento descendente por las columnas 
# bill_length_mm y bill_depth_mm
penguins |>
  arrange(desc(bill_length_mm), desc(bill_depth_mm))
# A tibble: 344 × 8
   species   island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
   <fct>     <fct>           <dbl>         <dbl>             <int>       <int>
 1 Gentoo    Biscoe           59.6          17                 230        6050
 2 Chinstrap Dream            58            17.8               181        3700
 3 Gentoo    Biscoe           55.9          17                 228        5600
 4 Chinstrap Dream            55.8          19.8               207        4000
 5 Gentoo    Biscoe           55.1          16                 230        5850
 6 Gentoo    Biscoe           54.3          15.7               231        5650
 7 Chinstrap Dream            54.2          20.8               201        4300
 8 Chinstrap Dream            53.5          19.9               205        4500
 9 Gentoo    Biscoe           53.4          15.8               219        5500
10 Chinstrap Dream            52.8          20                 205        4550
# ℹ 334 more rows
# ℹ 2 more variables: sex <fct>, year <int>

Nótese que los valores NA se ubican al final de cualquier ordenamiento.

10.6.4 mutate()

La función mutate() crea o modifica columnas en un data frame.

# Creación de la columna body_mass_kg,
# correspondiente al valor de body_mass_g, pero expresado en kg
penguins |>
  select(species, body_mass_g) |>
  mutate(body_mass_kg = body_mass_g/1000)
# A tibble: 344 × 3
   species body_mass_g body_mass_kg
   <fct>         <int>        <dbl>
 1 Adelie         3750         3.75
 2 Adelie         3800         3.8 
 3 Adelie         3250         3.25
 4 Adelie           NA        NA   
 5 Adelie         3450         3.45
 6 Adelie         3650         3.65
 7 Adelie         3625         3.62
 8 Adelie         4675         4.68
 9 Adelie         3475         3.48
10 Adelie         4250         4.25
# ℹ 334 more rows
# Creación de las columnas body_mass_g_mean (promedio de masa) y
# body_mass_g_normalized (masa normalizada con respecto al promedio)
penguins |>
  select(species, body_mass_g) |>
  mutate(body_mass_g_mean = mean(body_mass_g, na.rm = TRUE)) |>
  mutate(body_mass_g_normalized = body_mass_g / body_mass_g_mean)
# A tibble: 344 × 4
   species body_mass_g body_mass_g_mean body_mass_g_normalized
   <fct>         <int>            <dbl>                  <dbl>
 1 Adelie         3750            4202.                  0.892
 2 Adelie         3800            4202.                  0.904
 3 Adelie         3250            4202.                  0.773
 4 Adelie           NA            4202.                 NA    
 5 Adelie         3450            4202.                  0.821
 6 Adelie         3650            4202.                  0.869
 7 Adelie         3625            4202.                  0.863
 8 Adelie         4675            4202.                  1.11 
 9 Adelie         3475            4202.                  0.827
10 Adelie         4250            4202.                  1.01 
# ℹ 334 more rows
# Creación de las columnas 
# Fecha_Date (tipo Date), Anio, Mes y Dia (enteros)
delitos_2022 |>
  select(Fecha) |>
  mutate(Fecha_Date = as.Date(delitos_2022$Fecha, format="%m/%d/%Y")) |>
  mutate(Anio = as.integer(format(as.Date(delitos_2022$Fecha, format="%m/%d/%Y"), "%Y"))) |>  
  mutate(Dia = as.integer(format(as.Date(delitos_2022$Fecha, format="%m/%d/%Y"), "%m"))) |>
  mutate(Mes = as.integer(format(as.Date(delitos_2022$Fecha, format="%m/%d/%Y"), "%d"))) |>
  slice_head(n = 10)
        Fecha Fecha_Date Anio Dia Mes
1  12/31/2022 2022-12-31 2022  12  31
2  12/31/2022 2022-12-31 2022  12  31
3  12/31/2022 2022-12-31 2022  12  31
4  12/31/2022 2022-12-31 2022  12  31
5  12/31/2022 2022-12-31 2022  12  31
6  12/31/2022 2022-12-31 2022  12  31
7  12/31/2022 2022-12-31 2022  12  31
8  12/31/2022 2022-12-31 2022  12  31
9  12/31/2022 2022-12-31 2022  12  31
10 12/31/2022 2022-12-31 2022  12  31

La función group_by() agrupa una o más columnas. Generalmente, esto se hace con el objetivo de rea

# Creación de la columnas 
# body_mass_g_mean_species (promedio de masa de la especie) y
# body_mass_g_species_normalized (masa normalizada con respecto al promedio de la especie)
penguins |>
  select(species, body_mass_g) |>
  group_by(species) |>
  mutate(body_mass_g_mean_species = mean(body_mass_g, na.rm = TRUE)) |>
  mutate(body_mass_g_species_normalized = body_mass_g / body_mass_g_mean_species)
# A tibble: 344 × 4
# Groups:   species [3]
   species body_mass_g body_mass_g_mean_species body_mass_g_species_normalized
   <fct>         <int>                    <dbl>                          <dbl>
 1 Adelie         3750                    3701.                          1.01 
 2 Adelie         3800                    3701.                          1.03 
 3 Adelie         3250                    3701.                          0.878
 4 Adelie           NA                    3701.                         NA    
 5 Adelie         3450                    3701.                          0.932
 6 Adelie         3650                    3701.                          0.986
 7 Adelie         3625                    3701.                          0.980
 8 Adelie         4675                    3701.                          1.26 
 9 Adelie         3475                    3701.                          0.939
10 Adelie         4250                    3701.                          1.15 
# ℹ 334 more rows

10.6.5 summarize()

La función summarize() se utiliza generalmente junto con la función group_by() para realizar cálculos en grupos de filas de un data frame. group_by() agrupa las filas y summarize() realiza los cálculos (ej. sumas, promedios) en las columnas, para cada grupo. El resultado es un nuevo data frame con una fila por grupo. Si no hay agrupación, se retorna una sola fila correspondiente a los cálculos para todo el data frame.

Ejemplos de cálculos en grupos:

# Creación de un data frame con las columnas calculadas de 
# mínimo, máximo y promedio de masa,
# y cantidad de individuos para cada especie
penguins |>
  group_by(species) |>
  summarize(
    body_mass_g_min = min(body_mass_g, na.rm = TRUE),
    body_mass_g_max = max(body_mass_g, na.rm = TRUE),
    body_mass_g_mean = mean(body_mass_g, na.rm = TRUE),
    n = n()
  )
# A tibble: 3 × 5
  species   body_mass_g_min body_mass_g_max body_mass_g_mean     n
  <fct>               <int>           <int>            <dbl> <int>
1 Adelie               2850            4775            3701.   152
2 Chinstrap            2700            4800            3733.    68
3 Gentoo               3950            6300            5076.   124

La función n() cuenta la cantidad de filas en un grupo.

# Creación de un data frame con la cantidad de homicidios 
# por provincia, cantón
delitos_2022 |>
  filter(SubDelito == "HOMICIDIO") |>
  group_by(Provincia, Canton) |>
  summarize(
    homicidios_2022 = n()
  ) |>
  arrange(desc(homicidios_2022)) |>
  print(n = Inf)
# A tibble: 68 × 3
# Groups:   Provincia [7]
   Provincia  Canton        homicidios_2022
   <chr>      <chr>                   <int>
 1 SAN JOSE   SAN JOSE                   48
 2 LIMON      LIMON                      47
 3 PUNTARENAS PUNTARENAS                 43
 4 ALAJUELA   ALAJUELA                   42
 5 LIMON      POCOCI                     38
 6 LIMON      MATINA                     25
 7 LIMON      GUACIMO                    17
 8 ALAJUELA   SAN CARLOS                 16
 9 ALAJUELA   SAN RAMON                  15
10 CARTAGO    CARTAGO                    15
11 SAN JOSE   GOICOECHEA                 15
12 HEREDIA    SARAPIQUI                  14
13 PUNTARENAS CORREDORES                 14
14 CARTAGO    LA UNION                   12
15 HEREDIA    HEREDIA                    12
16 PUNTARENAS GARABITO                   11
17 GUANACASTE LIBERIA                    10
18 GUANACASTE SANTA CRUZ                 10
19 LIMON      SIQUIRRES                   9
20 GUANACASTE NICOYA                      8
21 LIMON      TALAMANCA                   8
22 SAN JOSE   ASERRI                      8
23 HEREDIA    SANTO DOMINGO               7
24 PUNTARENAS BUENOS AIRES                7
25 SAN JOSE   DESAMPARADOS                7
26 SAN JOSE   TIBAS                       7
27 GUANACASTE CARRILLO                    6
28 GUANACASTE LA CRUZ                     6
29 PUNTARENAS ESPARZA                     6
30 SAN JOSE   ALAJUELITA                  6
31 ALAJUELA   GRECIA                      5
32 GUANACASTE BAGACES                     5
33 GUANACASTE CANAS                       5
34 PUNTARENAS GOLFITO                     5
35 PUNTARENAS OSA                         5
36 PUNTARENAS PARRITA                     5
37 PUNTARENAS QUEPOS                      5
38 SAN JOSE   PEREZ ZELEDON               5
39 ALAJUELA   LOS CHILES                  4
40 ALAJUELA   POAS                        4
41 CARTAGO    TURRIALBA                   4
42 HEREDIA    BARVA                       4
43 HEREDIA    SAN RAFAEL                  4
44 PUNTARENAS COTO BRUS                   4
45 PUNTARENAS MONTES DE ORO               4
46 ALAJUELA   ATENAS                      3
47 ALAJUELA   NARANJO                     3
48 ALAJUELA   RIO CUARTO                  3
49 CARTAGO    EL GUARCO                   3
50 CARTAGO    OREAMUNO                    3
51 CARTAGO    PARAISO                     3
52 GUANACASTE TILARAN                     3
53 SAN JOSE   ESCAZU                      3
54 SAN JOSE   MORAVIA                     3
55 ALAJUELA   OROTINA                     2
56 ALAJUELA   SARCHÍ                      2
57 ALAJUELA   UPALA                       2
58 SAN JOSE   CURRIDABAT                  2
59 SAN JOSE   SANTA ANA                   2
60 SAN JOSE   TURRUBARES                  2
61 ALAJUELA   PALMARES                    1
62 ALAJUELA   ZARCERO                     1
63 CARTAGO    JIMENEZ                     1
64 HEREDIA    FLORES                      1
65 HEREDIA    SAN ISIDRO                  1
66 HEREDIA    SANTA BARBARA               1
67 SAN JOSE   MONTES DE OCA               1
68 SAN JOSE   PURISCAL                    1

La función print() se utiliza para especificar la cantidad de filas que se imprimirán (Inf quiere decir que se imprimirán todas).

# Creación de un data frame con la cantidad de registros 
# por delito y subdelito
delitos_2022 |>
  group_by(Delito, SubDelito) |>
  summarize(
    n = n()
  ) |>
  arrange(desc(n)) |>
  print(n = Inf)
# A tibble: 112 × 3
# Groups:   Delito [27]
    Delito                                                       SubDelito     n
    <chr>                                                        <chr>     <int>
  1 DELITOS CONTRA LA PROPIEDAD                                  HURTO     15744
  2 DELITOS CONTRA LA PROPIEDAD                                  ROBO      14228
  3 DELITOS CONTRA LA PROPIEDAD                                  ASALTO    10794
  4 ESTAFAS Y OTRAS DEFRAUDACIONES                               TIMOS     10430
  5 ESTAFAS Y OTRAS DEFRAUDACIONES                               ESTAFA     6746
  6 DELITOS CONTRA LA PROPIEDAD                                  ROBO DE …  4225
  7 DELITOS CONTRA LA LIBERTAD                                   DELITOS …  4081
  8 DELITOS CONTRA LA VIDA                                       AGRESION   3424
  9 DELITOS INFORMATICOS                                         ESTAFA I…  3002
 10 OTROS DELITOS                                                OTRO O I…  2745
 11 OTROS DELITOS CONTRA LA PROPIEDAD                            DAÑOS      2559
 12 DELITOS CONTRA LA VIDA                                       LESIONES   2218
 13 OTROS DELITOS CONTRA LA PROPIEDAD                            ADMINIST…  1336
 14 DELITOS SEXUALES                                             VIOLACIO…  1285
 15 OTROS DELITOS CONTRA LA PROPIEDAD                            EXTORSIO…  1249
 16 DELITOS CONTRA LOS DEBERES DE LA FUNCION PUBLICA             ABUSO DE…  1234
 17 ESTAFAS Y OTRAS DEFRAUDACIONES                               FRAUDE     1084
 18 DELITOS CONTRA LA PROPIEDAD                                  ROBO DE …   863
 19 DELITOS INFORMATICOS                                         SUPLANTA…   771
 20 DELITOS CONTRA LA VIDA                                       HOMICIDI…   654
 21 DELITOS CONTRA LA VIDA                                       HOMICIDIO   604
 22 DELITOS CONTRA LA ADMINISTRACION DE JUSTICIA                 ENCUBRIM…   526
 23 DELITOS CONTRA LA VIDA                                       MUERTE I…   522
 24 NO DELITO                                                    DESAPARI…   476
 25 INFRACCION A LA LEY DE PSICOTROPICOS                         TRAFICO …   434
 26 DELITOS CONTRA LA SEGURIDAD COMUN                            INCENDIO…   410
 27 DELITOS SEXUALES                                             CORRUPCI…   378
 28 NO DELITO                                                    DESAPARI…   376
 29 DELITOS CONTRA LA FAMILIA                                    VIOLENCI…   279
 30 DELITOS INFORMATICOS                                         SUPLANTA…   276
 31 OTROS DELITOS CONTRA LA PROPIEDAD                            USURPACI…   272
 32 LEY CONTRA EL ACOSO SEXUAL CALLEJERO                         LEY CONT…   240
 33 DELITOS CONTRA LA SEGURIDAD COMUN                            DELITOS …   238
 34 INFRACCION A LA LEY DE BIENESTAR ANIMAL                      MUERTE D…   209
 35 DELITOS INFORMATICOS                                         OTRO O I…   206
 36 DELITOS INFORMATICOS                                         DIFUSION…   205
 37 DELITOS CONTRA LA VIDA                                       SUICIDIO    174
 38 DELITOS CONTRA LA VIDA                                       MUERTE A…   163
 39 DELITOS INFORMATICOS                                         FACILITA…   155
 40 DELITOS CONTRA LA FAMILIA                                    SUSTRACC…   152
 41 DELITOS CONTRA LA LIBERTAD                                   DELITOS …   140
 42 DELITOS CONTRA EL AMBITO DE LA INTIMIDAD                     VIOLACIO…   136
 43 DELITOS INFORMATICOS                                         ESPIONAJ…   127
 44 DELITOS CONTRA LA VIDA                                       ABANDONO…   116
 45 INFRACCION A LA LEY DE BIENESTAR ANIMAL                      MALTRATO…    98
 46 DELITOS CONTRA EL HONOR                                      INJURIA,…    87
 47 DELITOS CONTRA LA VIDA                                       MUERTE N…    84
 48 DELITOS INFORMATICOS                                         SEDUCCIO…    80
 49 DELITOS AMBIENTALES                                          LEY FORE…    74
 50 DELITOS CONTRA LA FAMILIA                                    INCUMPLI…    73
 51 INFRACCION A LA LEY DE PSICOTROPICOS                         LEGITIMA…    56
 52 DELITOS CONTRA LA AUTORIDAD PUBLICA                          DESOBEDI…    54
 53 INFRACCION A LA LEY DE BIENESTAR ANIMAL                      CRUELDAD…    50
 54 DELITOS CONTRA LOS DEBERES DE LA FUNCION PUBLICA             CORRUPCI…    46
 55 DELITOS CONTRA EL AMBITO DE LA INTIMIDAD                     VIOLACIO…    45
 56 DELITOS INFORMATICOS                                         INSTALAC…    43
 57 DELITOS AMBIENTALES                                          LEY DE C…    33
 58 DELITOS CONTRA LA ADMINISTRACION DE JUSTICIA                 FALSAS A…    30
 59 ESTAFAS Y OTRAS DEFRAUDACIONES                               ADMINIST…    28
 60 DELITOS INFORMATICOS                                         SABOTAJE…    22
 61 DELITOS SEXUALES                                             OTRO O I…    19
 62 DELITOS CONTRA LOS DEBERES DE LA FUNCION PUBLICA             PECULADO…    17
 63 DELITOS INFORMATICOS                                         DAÑO INF…    15
 64 ESTAFAS Y OTRAS DEFRAUDACIONES                               OTRO O I…    14
 65 DELITOS CONTRA LA AUTORIDAD PUBLICA                          RESISTEN…    13
 66 DELITOS CONTRA LA AUTORIDAD PUBLICA                          AMENAZA …    12
 67 DELITOS CONTRA LOS DEBERES DE LA FUNCION PUBLICA             CONCUSIO…    12
 68 DELITOS AMBIENTALES                                          USURPACI…    10
 69 DELITOS CONTRA LA FE PUBLICA                                 OTRO O I…    10
 70 DELITOS CONTRA LA SEGURIDAD COMUN                            DELITOS …    10
 71 INFRACCION A LA LEY DE PSICOTROPICOS                         TRAFICO …     9
 72 DELITOS CONTRA LA FAMILIA                                    PROTECCI…     8
 73 DELITOS CONTRA LA SEGURIDAD COMUN                            DELITOS …     8
 74 DELITOS CONTRA LA VIDA                                       ABORTO        8
 75 NO DELITO                                                    OTRO IND…     8
 76 DELITOS CONTRA EL AMBITO DE LA INTIMIDAD                     INFRACCI…     7
 77 OTROS DELITOS                                                INFRACCI…     7
 78 DELITOS AMBIENTALES                                          LEY DE G…     6
 79 INFRACCION A LA LEY DE BIENESTAR ANIMAL                      PELEA EN…     5
 80 TRATA DE PERSONAS                                            TRATA SE…     5
 81 DELITOS CONTRA LA AUTORIDAD PUBLICA                          EJERCICI…     4
 82 DELITOS CONTRA LA VIDA                                       OTRO O I…     4
 83 DELITOS AMBIENTALES                                          LEY DE L…     3
 84 DELITOS CONTRA EL AMBITO DE LA INTIMIDAD                     OTRO O I…     3
 85 DELITOS CONTRA EL AMBITO DE LA INTIMIDAD                     TURBACIO…     3
 86 DELITOS CONTRA LA AUTORIDAD PUBLICA                          USO ILEG…     3
 87 DELITOS CONTRA LA TRANQUILIDAD PUBLICA                       INTIMIDA…     3
 88 OTROS DELITOS CONTRA LA PROPIEDAD                            INFRACCI…     3
 89 DELITOS AMBIENTALES                                          LEY DE P…     2
 90 DELITOS CONTRA LA ADMINISTRACION DE JUSTICIA                 EVASION …     2
 91 DELITOS CONTRA LA BUENA FE DELOS NEGOCIOS                    USURA Y …     2
 92 DELITOS CONTRA LOS DEBERES DE LA FUNCION PUBLICA             PREVARIC…     2
 93 DESCONOCIDO                                                  DESCONOC…     2
 94 INFRACCION A LA LEY DE PSICOTROPICOS                         OTRO O I…     2
 95 OTROS DELITOS CONTRA LA PROPIEDAD                            OTRO O I…     2
 96 TRAFICO DE PERSONAS                                          PERSONAS…     2
 97 TRATA DE PERSONAS                                            OTRO O I…     2
 98 DELITOS CONTRA LA ADMINISTRACION DE JUSTICIA                 FALSO TE…     1
 99 DELITOS CONTRA LA AUTORIDAD PUBLICA                          FACILITA…     1
100 DELITOS CONTRA LA AUTORIDAD PUBLICA                          VIOLACIO…     1
101 DELITOS CONTRA LA AUTORIDAD PUBLICA                          VIOLACIO…     1
102 DELITOS CONTRA LA BUENA FE DELOS NEGOCIOS                    DELITOS …     1
103 DELITOS CONTRA LA FAMILIA                                    MATRIMON…     1
104 DELITOS CONTRA LA FAMILIA                                    OTRO O I…     1
105 DELITOS CONTRA LA FE PUBLICA                                 FALSEDAD…     1
106 DELITOS CONTRA LA LIBERTAD                                   OTRO O I…     1
107 DELITOS CONTRA LOS PODERES PUBLICOS Y EL ORDEN CONSTITUCION… ATENTADO…     1
108 DELITOS CONTRA LOS PODERES PUBLICOS Y EL ORDEN CONSTITUCION… OTRO          1
109 DELITOS INFORMATICOS                                         NARCOTRF…     1
110 DELITOS SEXUALES                                             RAPTO         1
111 TRATA DE PERSONAS                                            MENDICID…     1
112 TRATA DE PERSONAS                                            TRATA LA…     1

Ejemplo de cálculos sin agrupamiento:

# Creación de un data frame con las columnas 
# body_mass_g_mean (promedio de masa) y n (cantidad de registros)
penguins |>
  summarise(body_mass_g_mean = mean(body_mass_g, na.rm = TRUE),
            n = n())
# A tibble: 1 × 2
  body_mass_g_mean     n
             <dbl> <int>
1            4202.   344

10.6.6 Otras

10.6.6.1 distinct()

La función distinct() retorna las combinaciones únicas de filas en un data frame.

# Valores distintos de la columna Victima

delitos_2022 |>
  distinct(Victima)
      Victima
1    VEHICULO
2     PERSONA
3       OTROS
4    VIVIENDA
5 EDIFICACION

10.6.6.2 count()

Una forma alternativa a summarize() para realizar un conteo es con la función count():

# Conteo de delitos por tipo de Victima
delitos_2022 |>
  count(Victima)
      Victima     n
1 EDIFICACION  6705
2       OTROS  4756
3     PERSONA 62046
4    VEHICULO 11752
5    VIVIENDA 11392
# Expresión equivalente con summarize
delitos_2022 |>
  group_by(Victima) |>
  summarize(n = n())
# A tibble: 5 × 2
  Victima         n
  <chr>       <int>
1 EDIFICACION  6705
2 OTROS        4756
3 PERSONA     62046
4 VEHICULO    11752
5 VIVIENDA    11392

10.7 Ejercicios

Utilice las funciones de dplyr para responder a las siguientes preguntas sobre el conjunto de datos penguins:

  1. ¿Cuántos individuos de cada sexo hay en cada especie?
  2. ¿Cuál es el mínimo, máximo y promedio de masa corporal (peso) por especie y sexo?
  3. ¿Cuántos individuos se observaron durante cada año?
  4. ¿Cuántos individuos de cada especie se observaron durante cada año?
  5. ¿Cuántos individuos de cada especie y cada sexo se observaron durante cada año?
  6. ¿Cuál es el promedio de masa corporal (peso) por año?
  7. ¿Cuál es el promedio de masa corporal (peso) por año para cada especie?

10.8 Recursos de interés

RStudio. (2017). Data transformation with dplyr::Cheat Sheet. https://github.com/rstudio/cheatsheets/blob/45c1e642468695830fd8b724587ccfe8901e2185/data-transformation.pdf