# 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)
)
9 dplyr - gramática para manipulación de datos
9.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.
9.2 Trabajo previo
9.2.1 Lecturas
Wickham, H., Çetinkaya-Rundel, M., & Grolemund, G. (s. f.). R for Data Science (2nd ed.) Chapter 4 - Data transformation. Recuperado 5 de mayo de 2024, de https://r4ds.hadley.nz/data-transform.html
9.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 (|>). En el material de este curso, se prefiere la segunda opción. Los pipes se utilizan para comunicar procesos y así formar pipelines (tuberías).
Todas las funciones de dplyr trabajan de manera similar:
- El primer argumento siempre es un data frame. Puede omitirse si la función recibe el data frame a través del operador pipe.
- Los argumentos siguientes describen que hacer con el data frame, utilizando los nombres de las columnas (sin comillas).
- 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.
A tibble: 2 × 2
species body_mass_g_mean
<fct> <dbl>
Adelie 3710.659
Gentoo 5076.016
9.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)
# Carga de knitr, paquete para integrar salidas en R en documentos dinámicos
# (ej. Quarto). En este capítulo se usa para generar tablas.
library(knitr)
9.5 Conjuntos de datos para ejemplos
En los ejemplos de este capítulo, se utilizan dos conjunto de datos:
- Pingüinos del archipiélago Palmer, contenido en el paquete palmerpenguins.
- Delitos cometidos en Costa Rica en 2023, disponibles en el sitio Datos Abiertos del Organismo de Investigación Judicial (OIJ).
9.5.1 Pingüinos del archipiélago Palmer
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…
La función también puede llamarse mediante un pipe:
# Estructura del conjunto de datos penguins
|>
penguins glimpse()
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. Note la diferencia, por ejemplo, con la forma en la que se despliega el conjunto de datos iris
(observe también la diferencia entre las salidas de class(iris)
y class(penguins)
). A pesar de estas diferencias en el despliegue, en general, un data frame regular y un tibble pueden tratarse indistintamente.
Para generar una salida más estilizada, puede usarse la función knitr::kable(), la cual genera tablas para documentos web. En el siguiente ejemplo, se obtienen los primeros registros de penguins con la función head() y se despliegan en una tabla mediante kable()
.
# Despliegue de los primeros registros de penguins en una tabla kable
|>
penguins head(n = 10) |>
kable(format = "html")
species | island | bill_length_mm | bill_depth_mm | flipper_length_mm | body_mass_g | sex | year |
---|---|---|---|---|---|---|---|
Adelie | Torgersen | 39.1 | 18.7 | 181 | 3750 | male | 2007 |
Adelie | Torgersen | 39.5 | 17.4 | 186 | 3800 | female | 2007 |
Adelie | Torgersen | 40.3 | 18.0 | 195 | 3250 | female | 2007 |
Adelie | Torgersen | NA | NA | NA | NA | NA | 2007 |
Adelie | Torgersen | 36.7 | 19.3 | 193 | 3450 | female | 2007 |
Adelie | Torgersen | 39.3 | 20.6 | 190 | 3650 | male | 2007 |
Adelie | Torgersen | 38.9 | 17.8 | 181 | 3625 | female | 2007 |
Adelie | Torgersen | 39.2 | 19.6 | 195 | 4675 | male | 2007 |
Adelie | Torgersen | 34.1 | 18.1 | 193 | 3475 | NA | 2007 |
Adelie | Torgersen | 42.0 | 20.2 | 190 | 4250 | NA | 2007 |
9.5.2 Delitos cometidos en Costa Rica en 2023
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 2023
<-
delitos_2023 read_csv(
"https://raw.githubusercontent.com/gf0604-procesamientodatosgeograficos/2024-i/main/datos/oij/estadisticas-policiales/estadisticaspoliciales2023.csv"
)
Estructura del conjunto de datos:
# Estructura de los datos de delitos cometidos en 2023
glimpse(delitos_2023)
Rows: 49,609
Columns: 12
$ Delito <chr> "ASALTO", "ASALTO", "HURTO", "ASALTO", "ASALTO", "HURTO",…
$ SubDelito <chr> "ARMA BLANCA", "ARMA BLANCA", "ARDID PREVIO/DISTRACCION",…
$ Fecha <chr> "12/31/2023", "12/31/2023", "12/31/2023", "12/31/2023", "…
$ Hora <chr> "21:00:00 - 23:59:59", "21:00:00 - 23:59:59", "21:00:00 -…
$ Victima <chr> "PERSONA", "PERSONA", "PERSONA", "PERSONA", "PERSONA", "V…
$ SubVictima <chr> "PEATON [PERSONA]", "PEATON [PERSONA]", "TAXISTA [PERSONA…
$ Edad <chr> "Mayor de edad", "Mayor de edad", "Mayor de edad", "Mayor…
$ Genero <chr> "HOMBRE", "MUJER", "HOMBRE", "HOMBRE", "HOMBRE", "MUJER",…
$ Nacionalidad <chr> "COSTA RICA", "COSTA RICA", "COSTA RICA", "NICARAGUA", "C…
$ Provincia <chr> "SAN JOSE", "SAN JOSE", "SAN JOSE", "SAN JOSE", "SAN JOSE…
$ Canton <chr> "SAN JOSE", "MORAVIA", "DESAMPARADOS", "SAN JOSE", "SAN J…
$ Distrito <chr> "MERCED", "SAN VICENTE", "SAN MIGUEL", "HOSPITAL", "HOSPI…
Despliegue de los datos (debido a que delitos_2023
es un data frame, pero no un tibble, se limitan manualmente las filas y columnas que se muestran):
# Despliegue de los primeros registros de delitos en una tabla kable
|>
delitos_2023 head(n = 10) |>
kable(format = "html")
Delito | SubDelito | Fecha | Hora | Victima | SubVictima | Edad | Genero | Nacionalidad | Provincia | Canton | Distrito |
---|---|---|---|---|---|---|---|---|---|---|---|
ASALTO | ARMA BLANCA | 12/31/2023 | 21:00:00 - 23:59:59 | PERSONA | PEATON [PERSONA] | Mayor de edad | HOMBRE | COSTA RICA | SAN JOSE | SAN JOSE | MERCED |
ASALTO | ARMA BLANCA | 12/31/2023 | 21:00:00 - 23:59:59 | PERSONA | PEATON [PERSONA] | Mayor de edad | MUJER | COSTA RICA | SAN JOSE | MORAVIA | SAN VICENTE |
HURTO | ARDID PREVIO/DISTRACCION | 12/31/2023 | 21:00:00 - 23:59:59 | PERSONA | TAXISTA [PERSONA] | Mayor de edad | HOMBRE | COSTA RICA | SAN JOSE | DESAMPARADOS | SAN MIGUEL |
ASALTO | INMOVILIZACION | 12/31/2023 | 21:00:00 - 23:59:59 | PERSONA | PEATON [PERSONA] | Mayor de edad | HOMBRE | NICARAGUA | SAN JOSE | SAN JOSE | HOSPITAL |
ASALTO | ARMA DE FUEGO | 12/31/2023 | 21:00:00 - 23:59:59 | PERSONA | PEATON [PERSONA] | Mayor de edad | HOMBRE | COSTA RICA | SAN JOSE | SAN JOSE | HOSPITAL |
HURTO | POR DESCUIDO | 12/31/2023 | 21:00:00 - 23:59:59 | VIVIENDA | NO APLICA [VIVIENDA] | Mayor de edad | MUJER | COSTA RICA | SAN JOSE | DOTA | JARDIN |
ASALTO | ARREBATO | 12/31/2023 | 21:00:00 - 23:59:59 | PERSONA | PASAJERO DE TRANSPORTE PUBLICO [PERSONA] | Mayor de edad | MUJER | COSTA RICA | SAN JOSE | SAN JOSE | DESCONOCIDO |
ASALTO | GOLPES | 12/31/2023 | 21:00:00 - 23:59:59 | PERSONA | PEATON [PERSONA] | Mayor de edad | HOMBRE | COSTA RICA | PUNTARENAS | CORREDORES | CORREDOR |
ASALTO | INMOVILIZACION | 12/31/2023 | 21:00:00 - 23:59:59 | PERSONA | PEATON [PERSONA] | Mayor de edad | HOMBRE | ITALIA | SAN JOSE | SAN JOSE | HATILLO |
HURTO | CON LLAVE | 12/31/2023 | 21:00:00 - 23:59:59 | VIVIENDA | NO APLICA [VIVIENDA] | Adulto Mayor | MUJER | COSTA RICA | GUANACASTE | NICOYA | NICOYA |
9.6 Funciones
En esta sección, se describen y ejemplifican las principales funciones de dplyr.
9.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
9.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 Sarapiquí
|>
delitos_2023 filter(Delito == "HOMICIDIO" & Canton == "SARAPIQUI") |>
select(Canton, SubDelito, Fecha, Edad, Nacionalidad) |>
kable()
Canton | SubDelito | Fecha | Edad | Nacionalidad |
---|---|---|---|---|
SARAPIQUI | DISCUSION/RIÑA | 12/06/2023 | Desconocido | COSTA RICA |
SARAPIQUI | AJUSTE DE CUENTAS/VENGANZA | 10/28/2023 | Desconocido | Desconocido |
SARAPIQUI | AJUSTE DE CUENTAS/VENGANZA | 10/16/2023 | Mayor de edad | COSTA RICA |
SARAPIQUI | AJUSTE DE CUENTAS/VENGANZA | 09/30/2023 | Mayor de edad | COSTA RICA |
SARAPIQUI | AJUSTE DE CUENTAS/VENGANZA | 09/28/2023 | Desconocido | Desconocido |
SARAPIQUI | AJUSTE DE CUENTAS/VENGANZA | 07/28/2023 | Desconocido | Desconocido |
SARAPIQUI | AJUSTE DE CUENTAS/VENGANZA | 07/07/2023 | Desconocido | Desconocido |
SARAPIQUI | AJUSTE DE CUENTAS/VENGANZA | 07/05/2023 | Mayor de edad | COSTA RICA |
SARAPIQUI | AJUSTE DE CUENTAS/VENGANZA | 06/25/2023 | Desconocido | Desconocido |
SARAPIQUI | AJUSTE DE CUENTAS/VENGANZA | 05/31/2023 | Mayor de edad | COSTA RICA |
SARAPIQUI | AJUSTE DE CUENTAS/VENGANZA | 05/22/2023 | Desconocido | COSTA RICA |
SARAPIQUI | DISCUSION/RIÑA | 05/16/2023 | Mayor de edad | COSTA RICA |
SARAPIQUI | AJUSTE DE CUENTAS/VENGANZA | 04/12/2023 | Mayor de edad | COSTA RICA |
SARAPIQUI | POR LA COMISION DE OTRO DELITO | 03/18/2023 | Mayor de edad | NICARAGUA |
SARAPIQUI | DISCUSION/RIÑA | 03/13/2023 | Mayor de edad | COSTA RICA |
SARAPIQUI | AJUSTE DE CUENTAS/VENGANZA | 02/16/2023 | Mayor de edad | Desconocido |
SARAPIQUI | AJUSTE DE CUENTAS/VENGANZA | 01/31/2023 | Adulto Mayor | COSTA RICA |
SARAPIQUI | AJUSTE DE CUENTAS/VENGANZA | 01/31/2023 | Mayor de edad | COSTA RICA |
SARAPIQUI | AJUSTE DE CUENTAS/VENGANZA | 01/07/2023 | Mayor de edad | COSTA RICA |
# Homicidios cometidos en el cantón de Sarapiquí
# a personas no costarricenses
|>
delitos_2023 filter(Delito == "HOMICIDIO" &
== "SARAPIQUI" & Nacionalidad != "COSTA RICA") |>
Canton select(Canton, SubDelito, Fecha, Edad, Nacionalidad) |>
kable()
Canton | SubDelito | Fecha | Edad | Nacionalidad |
---|---|---|---|---|
SARAPIQUI | AJUSTE DE CUENTAS/VENGANZA | 10/28/2023 | Desconocido | Desconocido |
SARAPIQUI | AJUSTE DE CUENTAS/VENGANZA | 09/28/2023 | Desconocido | Desconocido |
SARAPIQUI | AJUSTE DE CUENTAS/VENGANZA | 07/28/2023 | Desconocido | Desconocido |
SARAPIQUI | AJUSTE DE CUENTAS/VENGANZA | 07/07/2023 | Desconocido | Desconocido |
SARAPIQUI | AJUSTE DE CUENTAS/VENGANZA | 06/25/2023 | Desconocido | Desconocido |
SARAPIQUI | POR LA COMISION DE OTRO DELITO | 03/18/2023 | Mayor de edad | NICARAGUA |
SARAPIQUI | AJUSTE DE CUENTAS/VENGANZA | 02/16/2023 | Mayor de edad | Desconocido |
# 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
9.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.
9.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_2023 select(Fecha) |>
mutate(Fecha_Date = as.Date(delitos_2023$Fecha, format="%m/%d/%Y")) |>
mutate(Anio = as.integer(format(as.Date(delitos_2023$Fecha, format="%m/%d/%Y"), "%Y"))) |>
mutate(Dia = as.integer(format(as.Date(delitos_2023$Fecha, format="%m/%d/%Y"), "%m"))) |>
mutate(Mes = as.integer(format(as.Date(delitos_2023$Fecha, format="%m/%d/%Y"), "%d"))) |>
slice_head(n = 10)
# A tibble: 10 × 5
Fecha Fecha_Date Anio Dia Mes
<chr> <date> <int> <int> <int>
1 12/31/2023 2023-12-31 2023 12 31
2 12/31/2023 2023-12-31 2023 12 31
3 12/31/2023 2023-12-31 2023 12 31
4 12/31/2023 2023-12-31 2023 12 31
5 12/31/2023 2023-12-31 2023 12 31
6 12/31/2023 2023-12-31 2023 12 31
7 12/31/2023 2023-12-31 2023 12 31
8 12/31/2023 2023-12-31 2023 12 31
9 12/31/2023 2023-12-31 2023 12 31
10 12/31/2023 2023-12-31 2023 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
9.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:
# Mmínimo, máximo, promedio de masa y cantidad de individuos
# para cada especie de pingüinos
|>
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.
# Cantidad de homicidios por provincia y cantón
|>
delitos_2023 filter(Delito == "HOMICIDIO") |>
group_by(Provincia, Canton) |>
summarize(
homicidios_2023 = n()
|>
) arrange(desc(homicidios_2023)) |>
kable()
Provincia | Canton | homicidios_2023 |
---|---|---|
LIMON | LIMON | 91 |
SAN JOSE | SAN JOSE | 82 |
PUNTARENAS | PUNTARENAS | 68 |
LIMON | MATINA | 50 |
ALAJUELA | ALAJUELA | 44 |
LIMON | POCOCI | 31 |
GUANACASTE | NICOYA | 28 |
SAN JOSE | DESAMPARADOS | 26 |
GUANACASTE | SANTA CRUZ | 24 |
SAN JOSE | ALAJUELITA | 23 |
CARTAGO | CARTAGO | 21 |
LIMON | SIQUIRRES | 21 |
SAN JOSE | GOICOECHEA | 20 |
ALAJUELA | SAN CARLOS | 19 |
HEREDIA | SARAPIQUI | 19 |
CARTAGO | PARAISO | 17 |
HEREDIA | HEREDIA | 17 |
PUNTARENAS | PARRITA | 17 |
GUANACASTE | LIBERIA | 16 |
PUNTARENAS | CORREDORES | 16 |
CARTAGO | LA UNION | 15 |
PUNTARENAS | QUEPOS | 15 |
ALAJUELA | SAN RAMON | 13 |
PUNTARENAS | GARABITO | 13 |
SAN JOSE | PEREZ ZELEDON | 13 |
GUANACASTE | CARRILLO | 11 |
CARTAGO | TURRIALBA | 10 |
LIMON | GUACIMO | 10 |
LIMON | TALAMANCA | 10 |
SAN JOSE | ESCAZU | 8 |
SAN JOSE | ASERRI | 7 |
SAN JOSE | TIBAS | 7 |
SAN JOSE | VASQUEZ DE CORONADO | 7 |
ALAJUELA | LOS CHILES | 6 |
GUANACASTE | CANAS | 6 |
SAN JOSE | CURRIDABAT | 6 |
SAN JOSE | MONTES DE OCA | 6 |
GUANACASTE | ABANGARES | 5 |
PUNTARENAS | ESPARZA | 5 |
PUNTARENAS | GOLFITO | 5 |
PUNTARENAS | OSA | 5 |
ALAJUELA | GRECIA | 4 |
CARTAGO | EL GUARCO | 4 |
GUANACASTE | LA CRUZ | 4 |
HEREDIA | SAN RAFAEL | 4 |
ALAJUELA | ATENAS | 3 |
ALAJUELA | GUATUSO | 3 |
ALAJUELA | NARANJO | 3 |
ALAJUELA | OROTINA | 3 |
CARTAGO | OREAMUNO | 3 |
GUANACASTE | BAGACES | 3 |
HEREDIA | SANTO DOMINGO | 3 |
PUNTARENAS | MONTES DE ORO | 3 |
SAN JOSE | LEON CORTES | 3 |
SAN JOSE | MORAVIA | 3 |
ALAJUELA | POAS | 2 |
ALAJUELA | UPALA | 2 |
CARTAGO | ALVARADO | 2 |
GUANACASTE | TILARAN | 2 |
HEREDIA | SANTA BARBARA | 2 |
PUNTARENAS | COTO BRUS | 2 |
SAN JOSE | MORA | 2 |
ALAJUELA | RIO CUARTO | 1 |
CARTAGO | JIMENEZ | 1 |
GUANACASTE | NANDAYURE | 1 |
HEREDIA | BARVA | 1 |
HEREDIA | FLORES | 1 |
HEREDIA | SAN PABLO | 1 |
PUNTARENAS | BUENOS AIRES | 1 |
SAN JOSE | PURISCAL | 1 |
SAN JOSE | SANTA ANA | 1 |
SAN JOSE | TARRAZU | 1 |
# Cantidad de registros por delito y subdelito
|>
delitos_2023 group_by(Delito, SubDelito) |>
summarize(
n = n()
|>
) arrange(desc(n)) |>
kable()
Delito | SubDelito | n |
---|---|---|
HURTO | POR DESCUIDO | 8326 |
ROBO | FORZADURA | 6066 |
ASALTO | ARMA DE FUEGO | 4915 |
TACHA DE VEHICULO | TACHA DE VEHICULO | 3863 |
ASALTO | ARMA BLANCA | 2925 |
HURTO | POR CONFIANZA | 2924 |
HURTO | CARTERISTA | 2869 |
ROBO DE VEHICULO | DESCUIDO | 2356 |
ASALTO | ARREBATO | 1915 |
ROBO | BOQUETE | 1385 |
ROBO | ESCALAMIENTO | 1274 |
ASALTO | GOLPES | 1248 |
ROBO DE VEHICULO | ASALTO | 1070 |
ROBO DE VEHICULO | COCHERAZO | 750 |
HURTO | ARDID PREVIO/DISTRACCION | 728 |
ROBO | CORTA CANDADOS | 695 |
ROBO | RUPTURA VENTANA | 682 |
ASALTO | INTIMIDACION VERBAL | 666 |
HOMICIDIO | AJUSTE DE CUENTAS/VENGANZA | 633 |
HURTO | OTRO O INDETERMINADO | 633 |
ROBO | QUITAN CELOSIAS | 502 |
HURTO | CON LLAVE | 484 |
ROBO DE VEHICULO | POR CONFIANZA | 399 |
ASALTO | CANDADO CHINO | 352 |
ROBO | OTRO O INDETERMINADO | 345 |
ASALTO | INMOVILIZACION | 331 |
HURTO | PROGRESIVOS | 233 |
ASALTO | ARMA CONTUNDENTE | 170 |
ASALTO | OTRO O INDETERMINADO | 149 |
ROBO DE VEHICULO | OTRO O INDETERMINADO | 133 |
HOMICIDIO | DISCUSION/RIÑA | 118 |
HURTO | RETIRO DE CAJERO AUTOMATICO | 116 |
HOMICIDIO | POR LA COMISION DE OTRO DELITO | 83 |
HURTO | USO DE SOMNIFERO | 74 |
ROBO DE VEHICULO | ARDID PREVIO | 51 |
HURTO | GANZUA/VARILLA | 47 |
HOMICIDIO | VIOLENCIA DOMESTICA | 26 |
ASALTO | USO DE GAS | 19 |
HOMICIDIO | OTRO O INDETERMINADO | 16 |
HOMICIDIO | REPELIENDO ACTIVIDAD CRIMINAL | 12 |
HOMICIDIO | PROFESIONAL | 9 |
HOMICIDIO | NO DETERMINADO | 5 |
HURTO | DESCONOCIDO | 5 |
ASALTO | DESCONOCIDO | 3 |
ROBO | DESCONOCIDO | 3 |
HOMICIDIO | FEMICIDIO | 1 |
Ejemplo de cálculos sin agrupamiento:
# Promedio de masa y n cantidad de registros de pingüinos
|>
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
9.6.6 Otras
9.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_2023 distinct(Victima) |>
kable()
Victima |
---|
PERSONA |
VIVIENDA |
VEHICULO |
EDIFICACION |
OTROS |
9.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_2023 count(Victima)
# A tibble: 5 × 2
Victima n
<chr> <int>
1 EDIFICACION 6981
2 OTROS 1946
3 PERSONA 19448
4 VEHICULO 11476
5 VIVIENDA 9758
# Expresión equivalente con summarize
|>
delitos_2023 group_by(Victima) |>
summarize(n = n()) |>
kable()
Victima | n |
---|---|
EDIFICACION | 6981 |
OTROS | 1946 |
PERSONA | 19448 |
VEHICULO | 11476 |
VIVIENDA | 9758 |
9.7 Ejercicios
Utilice las funciones de dplyr para responder a las siguientes preguntas sobre el conjunto de datos penguins
:
- ¿Cuántos individuos de cada sexo hay en cada especie?
- ¿Cuál es el mínimo, máximo y promedio de masa corporal (peso) por especie y sexo?
- ¿Cuántos individuos se observaron durante cada año?
- ¿Cuántos individuos de cada especie se observaron durante cada año?
- ¿Cuántos individuos de cada especie y cada sexo se observaron durante cada año?
- ¿Cuál es el promedio de masa corporal (peso) por año?
- ¿Cuál es el promedio de masa corporal (peso) por año para cada especie?
9.8 Recursos de interés
RStudio. (2017). Data transformation with dplyr::Cheat Sheet. https://github.com/rstudio/cheatsheets/blob/45c1e642468695830fd8b724587ccfe8901e2185/data-transformation.pdf