Programación en R para Data Science

Introducción a la manipulación de datos con el paquete Tidyverse

Author

Jesús Turpín

Published

October 24, 2023

Introducción a Tidyverse

El paquete tidyverse contiene otros paquetes (dplyr, ggplot2, etc.) y lo verás cuando cargue el paquete tidyverse usando library (). ¡Recuerda que el paquete debe estar instalado antes de que pueda cargarse!

library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.3     ✔ readr     2.1.4
✔ forcats   1.0.0     ✔ stringr   1.5.0
✔ ggplot2   3.4.4     ✔ tibble    3.2.1
✔ lubridate 1.9.3     ✔ tidyr     1.3.0
✔ purrr     1.0.2     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors

Los paquetes en R agrupan funciones específicas para ciertas tareas, como las funciones gráficas en ggplot2. Aunque necesitamos instalar un paquete solo una vez por actualización de R, es esencial cargarlo en cada sesión con library(). Esto trae todas sus funciones, documentación y datos al entorno actual de R.

¿Por qué no mantener todos los paquetes activos constantemente en R? El principal problema es el conflicto entre nombres de funciones en diferentes paquetes. Aunque los creadores de paquetes se esfuerzan por dar nombres únicos a sus funciones, las colisiones son inevitables debido a la limitada cantidad de nombres descriptivos y breves. Un claro ejemplo es la función filter, que existe tanto en dplyr como en stats y tiene diferentes comportamientos. R determina qué versión usar basándose en el último paquete cargado. Así, si cargas tidyverse (que a su vez carga dplyr) después del paquete stats, R usará la versión de filter de dplyr.

Para evitar el uso accidental de la función no deseada, algunos usuarios de R prefieren cargar funciones individuales en lugar de cargar una biblioteca completa. Si solo necesitas usar del paquete dplyr la función filter, puedes ejecutar lo siguiente:

# Cargar solo la función filter
dplyr::filter(...)
# Cargar todo
library(dplyr)
filter()

Lectura del archivo externo: readr::read_csv

La función read_csv (del paquete readr, que forma parte del tidyverse) y read.csv (R Base) son dos funciones de uso común para leer archivos CSV. Imprescindible consultar la ayuda de read.csv() y sus variantes, así como del paquete readr y las funciones read_csv() y sus variantes.

Ventajas de read_csv sobre read.csv:

  1. Velocidad:
    • read_csv suele ser significativamente más rápido que read.csv, especialmente para archivos grandes.
  2. Manejo de Tipos de Datos:
    • read_csv utiliza una lógica más sofisticada para adivinar los tipos de datos de las columnas.
  3. Manejo de Archivos Mal Formados:
    • read_csv suele ser más robusto al leer archivos CSV que no están perfectamente formateados.
  4. Flexibilidad en la Lectura:
    • read_csv permite una mayor flexibilidad en la lectura de archivos CSV.
  5. Tibbles:
    • read_csv devuelve “tibbles” en lugar de data frames estándar de R.
  6. Consistencia:
    • Usar read_csv proporciona una mayor consistencia en términos de sintaxis y estructura de datos.
  7. Menos Conversiones no Deseadas:
    • read_csv es menos propenso a convertir strings en factores automáticamente.

Si no puedes esperar a la clase de código eficiente, te animo a que apliques un benchmark con profvis de una lectura y/o escritura de un csv de grandes dimensiones con ambas funciones y compares el rendimiento.

Desventajas de read_csv del paquete readr en comparación con read.csv de R Base:

  1. Dependencia de Paquetes Externos:
    • Es necesario instalar y cargar el paquete readr o el conjunto de paquetes del tidyverse.
  2. Memoria Adicional:
    • Puede consumir más memoria que read.csv al leer archivos muy grandes.
  3. Retorno de Tibbles:
    • read_csv devuelve tibbles que pueden comportarse ligeramente diferente en algunas situaciones.
  4. Familiaridad y Compatibilidad:
    • Cambiar a read_csv podría requerir revisiones adicionales para asegurar compatibilidad con scripts antiguos.
  5. Conversión de Strings:
    • En algunos contextos, no convertir automáticamente las cadenas a factores podría ser visto como una desventaja.
  6. Comportamiento Predeterminado:
    • El comportamiento predeterminado de read_csv puede no ser adecuado para todos los escenarios.
  7. Errores y Advertencias:
    • read_csv es más estricto y puede emitir advertencias o errores en archivos que read.csv podría leer sin problemas.

Manipulación de datos: dplyr

dplyr es uno de los paquetes más populares del universo Tidyverse en R. Está diseñado para ayudar en la manipulación de datos, proporcionando un conjunto coherente de verbos para trabajar con conjuntos de datos (como data frames o tibbles).

Dataset Ejemplo: ?dplyr::starwars

Operador Pipe

El operador pipe facilita la escritura y lectura de código al encadenar operaciones de manera secuencial. En lugar de anidar funciones una dentro de otra, se pueden organizar en un flujo que sigue una dirección lógica.

Nomenclaturas y Orígenes

1. %>% - Pipe de magrittr

  • Origen: Paquete magrittr en R.
  • Uso: Este es el operador pipe más conocido en R, popularizado por tidyverse.
  • Ejemplo:
library(dplyr)
mtcars %>% filter(mpg > 20) %>% select(mpg, hp)
                mpg  hp
Mazda RX4      21.0 110
Mazda RX4 Wag  21.0 110
Datsun 710     22.8  93
Hornet 4 Drive 21.4 110
Merc 240D      24.4  62
Merc 230       22.8  95
Fiat 128       32.4  66
Honda Civic    30.4  52
Toyota Corolla 33.9  65
Toyota Corona  21.5  97
Fiat X1-9      27.3  66
Porsche 914-2  26.0  91
Lotus Europa   30.4 113
Volvo 142E     21.4 109

2. |> - Pipe nativo

  • Origen: R base (introducido en R versión 4.1.0).
  • Uso: Un intento de R core para tener un operador pipe nativo.
  • Ejemplo:
mtcars |> subset(mpg > 20) |> subset(select = c(mpg, hp))
                mpg  hp
Mazda RX4      21.0 110
Mazda RX4 Wag  21.0 110
Datsun 710     22.8  93
Hornet 4 Drive 21.4 110
Merc 240D      24.4  62
Merc 230       22.8  95
Fiat 128       32.4  66
Honda Civic    30.4  52
Toyota Corolla 33.9  65
Toyota Corona  21.5  97
Fiat X1-9      27.3  66
Porsche 914-2  26.0  91
Lotus Europa   30.4 113
Volvo 142E     21.4 109

3. Unix Pipe: |

  • Origen: Shell de Unix.
  • Uso: Permite encadenar comandos en la línea de comandos de Unix, pasando la salida de un comando como entrada al siguiente.
  • Ejemplo:
cat `data/file.txt` | grep "pattern"

¿Pertenece el operador pipe a dplyr?

El operador pipe %>% no es exclusivo de dplyr, sino que proviene del paquete magrittr. Sin embargo, dplyr y otros paquetes del tidyverse adoptaron y popularizaron su uso. Por lo tanto, es comúnmente asociado con dplyr y el tidyverse en general, aunque puede ser utilizado con cualquier conjunto de funciones en R.

Funciones populares de dplyr

1. filter()

Esta función se utiliza para extraer subconjuntos de filas basados en condiciones lógicas.

Ejemplo:

library(dplyr)
starwars %>% filter(species == "Droid")
# A tibble: 6 × 14
  name   height  mass hair_color skin_color  eye_color birth_year sex   gender  
  <chr>   <int> <dbl> <chr>      <chr>       <chr>          <dbl> <chr> <chr>   
1 C-3PO     167    75 <NA>       gold        yellow           112 none  masculi…
2 R2-D2      96    32 <NA>       white, blue red               33 none  masculi…
3 R5-D4      97    32 <NA>       white, red  red               NA none  masculi…
4 IG-88     200   140 none       metal       red               15 none  masculi…
5 R4-P17     96    NA none       silver, red red, blue         NA none  feminine
6 BB8        NA    NA none       none        black             NA none  masculi…
# ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
#   vehicles <list>, starships <list>

2. select()

Permite seleccionar columnas específicas del conjunto de datos.

Ejemplo:

starwars %>% select(name, species)
# A tibble: 87 × 2
   name               species
   <chr>              <chr>  
 1 Luke Skywalker     Human  
 2 C-3PO              Droid  
 3 R2-D2              Droid  
 4 Darth Vader        Human  
 5 Leia Organa        Human  
 6 Owen Lars          Human  
 7 Beru Whitesun lars Human  
 8 R5-D4              Droid  
 9 Biggs Darklighter  Human  
10 Obi-Wan Kenobi     Human  
# ℹ 77 more rows

3. arrange()

Ordena las filas de un conjunto de datos según una o más columnas.

Ejemplo:

starwars %>% arrange(desc(height))
# A tibble: 87 × 14
   name     height  mass hair_color skin_color eye_color birth_year sex   gender
   <chr>     <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr> 
 1 Yarael …    264    NA none       white      yellow          NA   male  mascu…
 2 Tarfful     234   136 brown      brown      blue            NA   male  mascu…
 3 Lama Su     229    88 none       grey       black           NA   male  mascu…
 4 Chewbac…    228   112 brown      unknown    blue           200   male  mascu…
 5 Roos Ta…    224    82 none       grey       orange          NA   male  mascu…
 6 Grievous    216   159 none       brown, wh… green, y…       NA   male  mascu…
 7 Taun We     213    NA none       grey       black           NA   fema… femin…
 8 Rugor N…    206    NA none       green      orange          NA   male  mascu…
 9 Tion Me…    206    80 none       grey       black           NA   male  mascu…
10 Darth V…    202   136 none       white      yellow          41.9 male  mascu…
# ℹ 77 more rows
# ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
#   vehicles <list>, starships <list>

4. mutate()

Añade nuevas variables o columnas a un conjunto de datos o modifica las existentes.

Ejemplo:

starwars %>% mutate(height_cm = height / 100)
# A tibble: 87 × 15
   name     height  mass hair_color skin_color eye_color birth_year sex   gender
   <chr>     <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr> 
 1 Luke Sk…    172    77 blond      fair       blue            19   male  mascu…
 2 C-3PO       167    75 <NA>       gold       yellow         112   none  mascu…
 3 R2-D2        96    32 <NA>       white, bl… red             33   none  mascu…
 4 Darth V…    202   136 none       white      yellow          41.9 male  mascu…
 5 Leia Or…    150    49 brown      light      brown           19   fema… femin…
 6 Owen La…    178   120 brown, gr… light      blue            52   male  mascu…
 7 Beru Wh…    165    75 brown      light      blue            47   fema… femin…
 8 R5-D4        97    32 <NA>       white, red red             NA   none  mascu…
 9 Biggs D…    183    84 black      light      brown           24   male  mascu…
10 Obi-Wan…    182    77 auburn, w… fair       blue-gray       57   male  mascu…
# ℹ 77 more rows
# ℹ 6 more variables: homeworld <chr>, species <chr>, films <list>,
#   vehicles <list>, starships <list>, height_cm <dbl>

5. summarise() (o summarize())

Resume múltiples valores en un único valor, como calcular la media, la suma o el conteo.

Ejemplo:

starwars %>% summarise(mean_height = mean(height, na.rm = TRUE))
# A tibble: 1 × 1
  mean_height
        <dbl>
1        174.

6. group_by()

Agrupa datos por valores únicos en una o más columnas, generalmente utilizado antes de summarise() para realizar cálculos por grupo.

Ejemplo:

starwars %>% group_by(species) %>% summarise(mean_height = mean(height, na.rm = TRUE))
# A tibble: 38 × 2
   species   mean_height
   <chr>           <dbl>
 1 Aleena            79 
 2 Besalisk         198 
 3 Cerean           198 
 4 Chagrian         196 
 5 Clawdite         168 
 6 Droid            131.
 7 Dug              112 
 8 Ewok              88 
 9 Geonosian        183 
10 Gungan           209.
# ℹ 28 more rows

Otras características de dplyr

  • Integración con otros paquetes: dplyr se integra bien con otros paquetes del Tidyverse, como tidyr, ggplot2, y readr.
  • Compatibilidad con bases de datos: dplyr puede trabajar no solo con data frames en memoria sino también interactuar directamente con bases de datos.