Ver el código
<- read_csv("../data/summer.csv") summer
En la gran mayoría de las ejemplos y ejercicios de este libro vamos a usar una computadora (te quiero mucho Skynet ♥️). Con ella nos vamos a comunicar utilizando un lenguaje de programación muy popular en el campo de la estadística: R(R Core Team 2023). Por eso mi recomendación es que lo que primero tenés que hacer es instalar R y RStudio. RStudio es una interfaz muy popular utilizada para, mayormente, programar en R. En el recuadro siguiente van a encontrar información de cómo instalar ambas cosas.
Lo primero que hay que hacer para poder correr scripts de R es, como resulta evidente, instalar R. Lo pueden hacer seleccionando su sistema operativo en este link y siguiendo los pasos de la instalación.
Pueden bajar la versión gratuita de RStudio del siguiente link. En caso de que el link no haya detectado correctamente el sistema operativo, en la sección All Installers pueden seleccionarlo manualmente. Una vez descargado el instalador sólo hay que seguir los pasos de la intalación.
Si bien la mayoría de las cosas que vamos a ahcer en este libro se pueden hacer con funciones de R base1, la propuesta es utilizar los paquetes y funciones del tidyverse. El tidyverse es una colección de paquetes diseñados para el campo de la ciencia de datos y que comparten una filosofía de diseño subyacente, una gramática y una estructura de datos(Wickham et al. 2019). Tranquilos que en la sección siguiente se va a ir aclarando la cosa.
1 Es decir, sin tener que cargar ningún paquete de funciones adicional.
Lo primero que tenemos que pensar cuando trabajamos con el tidyverse es que nuestros datos estén en formato tidy. ¿Qué significa esto? Cuando un dataset está en formato tidy, cada columna corresponde a una variable y cada fila a una única observación2. Veamos un ejemplo. Tenemos tres sujetos a los cuales les medimos el tiempo de respuesta en una tarea. Cada sujeto realiza dos repeticiones de esta medición, el trial 1 y el trial 2. En la tabla Tabla 1.1 podemos ver las dos formas de organizar esta información.
2 El caso contrario sería en el que una fila contiene varios mediciones para distintos niveles de una variable. Este formato se conoce como wide.
sujeto | trial | tiempo_respuesta |
---|---|---|
Jerry | 1 | 0.0807501 |
Jerry | 2 | 0.8343330 |
Elaine | 1 | 0.6007609 |
Elaine | 2 | 0.1572084 |
George | 1 | 0.0073994 |
George | 2 | 0.4663935 |
sujeto | trial_1 | trial_2 |
---|---|---|
Jerry | 0.4977774 | 0.7725215 |
Elaine | 0.2897672 | 0.8746007 |
George | 0.7328820 | 0.1749406 |
A lo largo de este capítulo iremos viendo los beneficios de almacenar los datos en formato tidy. Por supuesto que estas ventajas tienen su precio, principalemente que las bases de datos crecen mucho en tamaño si tenemos muchas medidas repetidas con distintos valores de las variables.
Como contamos más arriba, el tidyverse es una colección cerca de 25 paquetes, todos relacionados con la carga, manejo, modificación y visualización de datos. La idea de este libro no es profundizar en todas sus capacidades pero consideramos importante presentar algunas de las funciones que más vamos a utilizar a lo largo del libro. Estas son funciones para leer datos del paquete {readr}, los verbos de {dplyr} para manipularlos, las funciones de {tidyR} para acomodarlos y el poderosísimo {ggplot2} para visualizarlos.
Una de las cosas que vamos a hacer más a menudo en este libro es cargar algún dataset. Para esto vamos a usar varias de las funcionalidades del paquete {readr}.
El caso más simple al que nos vamos a enfrentar es la carga de una base de datos organizada en columnas y separadas por comas en un archivo de extensión .csv. En este caso lo que tenemos que hacer es bastante simple, usar la función read_csv() como a continuación:
<- read_csv("../data/summer.csv") summer
Podemos ver que al cargar los datos read_csv
nos dice que hay ocho columnas chr
(o sea de texto) y una dbl
(o sea, un número). Si usamos la función summary
podemos ver un detalle de cada avriable con su tipo y alguna descripción3:
3 Existen alternativas para visualizar rápidamente un conjunto de datos como str
o glimpse
o la función skim
del paquete {skimr}.
summary(summer)
#> Year City Sport Discipline
#> Min. :1896 Length:31165 Length:31165 Length:31165
#> 1st Qu.:1948 Class :character Class :character Class :character
#> Median :1980 Mode :character Mode :character Mode :character
#> Mean :1970
#> 3rd Qu.:2000
#> Max. :2012
#> Athlete Country Gender Event
#> Length:31165 Length:31165 Length:31165 Length:31165
#> Class :character Class :character Class :character Class :character
#> Mode :character Mode :character Mode :character Mode :character
#>
#>
#>
#> Medal
#> Length:31165
#> Class :character
#> Mode :character
#>
#>
#>
Los datos adentro de summer.csv
son los ganadores de medallas en los juegos olímpicos de verano. Podemos ver algunas filas de muestra:
head(summer)
#> # A tibble: 6 × 9
#> Year City Sport Discipline Athlete Country Gender
#> <dbl> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 1896 Athens Aquatics Swimming HAJOS, Alfred HUN Men
#> 2 1896 Athens Aquatics Swimming HERSCHMANN, Otto AUT Men
#> 3 1896 Athens Aquatics Swimming DRIVAS, Dimitrios GRE Men
#> 4 1896 Athens Aquatics Swimming MALOKINIS, Ioannis GRE Men
#> 5 1896 Athens Aquatics Swimming CHASAPIS, Spiridon GRE Men
#> 6 1896 Athens Aquatics Swimming CHOROPHAS, Efstathios GRE Men
#> # ℹ 2 more variables: Event <chr>, Medal <chr>
El formato en el que read_csv
almacena los datos se llama tibble y es el formato por excelencia del tidyverse. De momento lo único que nos importa es que es un formato que almacena los casos en filas y las variables en columnas (cada variable tiene un formato). Para más información sobre las cualidades de este formato, les recomiendo revisar la documentación.
El operador pipe nos permite concatenar funciones que utilizan como entrada los mismos datos. El principio de operación es el siguiente, supongan que nosotros queremos cargar un dataset y aplicarle la función summary. Esto lo podemos hacer simplemente cargando el dataset en una lìnea de código y ejecutanco la función summary() en la siguiente.
<- read_csv("../data/summer.csv")
data summary(data)
#> Year City Sport Discipline
#> Min. :1896 Length:31165 Length:31165 Length:31165
#> 1st Qu.:1948 Class :character Class :character Class :character
#> Median :1980 Mode :character Mode :character Mode :character
#> Mean :1970
#> 3rd Qu.:2000
#> Max. :2012
#> Athlete Country Gender Event
#> Length:31165 Length:31165 Length:31165 Length:31165
#> Class :character Class :character Class :character Class :character
#> Mode :character Mode :character Mode :character Mode :character
#>
#>
#>
#> Medal
#> Length:31165
#> Class :character
#> Mode :character
#>
#>
#>
Pero, también podemos aprovechar el operador pipe y hacer todo en una única línea de código.
read_csv("../data/summer.csv") |> summary()
#> Year City Sport Discipline
#> Min. :1896 Length:31165 Length:31165 Length:31165
#> 1st Qu.:1948 Class :character Class :character Class :character
#> Median :1980 Mode :character Mode :character Mode :character
#> Mean :1970
#> 3rd Qu.:2000
#> Max. :2012
#> Athlete Country Gender Event
#> Length:31165 Length:31165 Length:31165 Length:31165
#> Class :character Class :character Class :character Class :character
#> Mode :character Mode :character Mode :character Mode :character
#>
#>
#>
#> Medal
#> Length:31165
#> Class :character
#> Mode :character
#>
#>
#>
Al dejar vacío el paréntesis de la función summary(), la misma va a tomar como variable de entrada a la que está antes del operador pipe, es decir, a la que antes llamamos data
. En el caso que la función summary() tuviera más de una variable de entrada, lo que viene antes del pipe tomaría el lugar de la primera de ellas.
Si bien esta funcionalidad parece algo que complica las cosas y que no trae demasiados beneficios con un ejemplo tan simple, más adelante veremos que puede ser de gran utilidad, ayudando a disminuir la cantidad de línes de código y de variables intermedias.
Una de las cosas más útiles del tidyverse para el tipo de procesamiento de datos que vamos a llevar a cabo en este libro son los verbos de dplyr. Estas funciones no permiten agregar columnas, resumir la información, filtrar filas, seleccionar columnas, etc4. Y todas estas acciones las podemos hacer en la base de datos completa o en una parte de ella agrupada de acuerdo a algún criterio. Vayamos de a poco.
4 Para más detalles sobre los verbos disponibles en el paquete {dplyr} pueden visital este la página de referencia.
filter
Volvamos a los datos de los JJOO de verano. Supongamos que nos queremos quedar sólo con las medallas de Argentina. Para este tipo de filtrado de filas (o casos, o mediciones) {dplyr} tiene un verbo que se llama filter
y funciona de la siguiente forma5:
5 Se preguntarán por qué antes de la función filter
aparece un ::dplyr
. Esto es simplemente una forma de decirle a R que la función filter
que debe utilizar es la del paquete {dplyr}. Esta es una práctica recomendable sobre todo para funciones con nombres comunes como filter
o select
.
|> dplyr::filter(Country == "ARG") |> head(10)
summer #> # A tibble: 10 × 9
#> Year City Sport Discipline Athlete Country Gender
#> <dbl> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 1924 Paris Athletics Athletics BRUNETO, Luis ARG Men
#> 2 1924 Paris Boxing Boxing PORZIO, Alfredo ARG Men
#> 3 1924 Paris Boxing Boxing QUARTUCCI, Pedro ARG Men
#> 4 1924 Paris Boxing Boxing COPELLO, Alfredo ARG Men
#> 5 1924 Paris Boxing Boxing MENDEZ, Hector ARG Men
#> 6 1924 Paris Polo Polo KENNY, Arturo ARG Men
#> # ℹ 4 more rows
#> # ℹ 2 more variables: Event <chr>, Medal <chr>
Noten que estamos utilizando el operador |>
para concatenar las acciones: Con los datos de summer
hacemos el filtrado y, luego, mostramos las primeras diez filas de esos datos ya filtrados.
También podríamos quere quedarnos con las medallas de Argenitna en los JJOO de Atenas 2004, para esto debemos el operador lógico “y”, cuyo símbolo en R es &
:
|> dplyr::filter(Country == "ARG" & Year == 2004) |> head(5)
summer #> # A tibble: 5 × 9
#> Year City Sport Discipline Athlete Country Gender
#> <dbl> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 2004 Athens Aquatics Swimming BARDACH, Georgina ARG Women
#> 2 2004 Athens Basketball Basketball DELFINO, Carlos Francisco ARG Men
#> 3 2004 Athens Basketball Basketball FERNANDEZ, Gabriel Diego ARG Men
#> 4 2004 Athens Basketball Basketball GINOBILI, Emanuel David ARG Men
#> 5 2004 Athens Basketball Basketball GUTIERREZ, Leonardo Mart… ARG Men
#> # ℹ 2 more variables: Event <chr>, Medal <chr>
Que linda esa Generación Dorada🏅, ¿No?.Por otro lado, si nos queremos quedar con las medallas de Argentina o Brasil debemos utilizar el operador lógico “o”, cuyo símbolo en R es |
:
|> dplyr::filter(Country == "ARG" | Country == "BRA") |> head(10)
summer #> # A tibble: 10 × 9
#> Year City Sport Discipline Athlete Country Gender
#> <dbl> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 1920 Antwerp Shooting Shooting PARAENSE, Guilherme BRA Men
#> 2 1920 Antwerp Shooting Shooting BARBOSA, Dario BRA Men
#> 3 1920 Antwerp Shooting Shooting DA COSTA, Afranio Antonio BRA Men
#> 4 1920 Antwerp Shooting Shooting PARAENSE, Guilherme BRA Men
#> 5 1920 Antwerp Shooting Shooting SOLEDADE, Fernando BRA Men
#> 6 1920 Antwerp Shooting Shooting WOLF, Sebastiao BRA Men
#> # ℹ 4 more rows
#> # ℹ 2 more variables: Event <chr>, Medal <chr>
Aunque, una alternativa muy útil cuando tenemos los valores de una variable que queremos filtrar en un array es:
|> dplyr::filter(Country %in% c("ARG", "BRA")) |> head(10)
summer #> # A tibble: 10 × 9
#> Year City Sport Discipline Athlete Country Gender
#> <dbl> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 1920 Antwerp Shooting Shooting PARAENSE, Guilherme BRA Men
#> 2 1920 Antwerp Shooting Shooting BARBOSA, Dario BRA Men
#> 3 1920 Antwerp Shooting Shooting DA COSTA, Afranio Antonio BRA Men
#> 4 1920 Antwerp Shooting Shooting PARAENSE, Guilherme BRA Men
#> 5 1920 Antwerp Shooting Shooting SOLEDADE, Fernando BRA Men
#> 6 1920 Antwerp Shooting Shooting WOLF, Sebastiao BRA Men
#> # ℹ 4 more rows
#> # ℹ 2 more variables: Event <chr>, Medal <chr>
Finalmente, si tenemos una variable numérica, podemos filtrar con condiciones como mayor o menor:
|> dplyr::filter(Year > 2010) |> head(5)
summer #> # A tibble: 5 × 9
#> Year City Sport Discipline Athlete Country Gender
#> <dbl> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 2012 London Aquatics Diving BOUDIA, David USA Men
#> 2 2012 London Aquatics Diving QIU, Bo CHN Men
#> 3 2012 London Aquatics Diving DALEY, Thomas GBR Men
#> 4 2012 London Aquatics Diving CHEN, Ruolin CHN Women
#> 5 2012 London Aquatics Diving BROBEN, Brittany AUS Women
#> # ℹ 2 more variables: Event <chr>, Medal <chr>
select
El verbo select
es similar a filter
pero nos permite filtrar no casos sino variables. Por ejemplo, ¿Qué pasa si solo nos interesa el año, la ciudad y el nombre del atleta?:
|> dplyr::select(c(Year, City, Athlete)) |> head(5)
summer #> # A tibble: 5 × 3
#> Year City Athlete
#> <dbl> <chr> <chr>
#> 1 1896 Athens HAJOS, Alfred
#> 2 1896 Athens HERSCHMANN, Otto
#> 3 1896 Athens DRIVAS, Dimitrios
#> 4 1896 Athens MALOKINIS, Ioannis
#> 5 1896 Athens CHASAPIS, Spiridon
mutate
Ahora las cosas se complican un poco. mutate
es un verbo que nos permite crear nuevas columnas ya sea con datos nuevos o en función de los datos existentes. Por ejemplo, creemos una columna nueva que tenga un chr con el país, un guión y el nombre del atleta y llamémosla nationality_athlete
. Nos vamos a quedar sólo con el año, la medalla que ganó y el nuevo nombre combinado con la nacionalidad:
|>
summer ::mutate(nationality_athlete = paste(Country, "-", Athlete)) |>
dplyr::select(c(Year, Medal, nationality_athlete)) |>
dplyrhead(5)
#> # A tibble: 5 × 3
#> Year Medal nationality_athlete
#> <dbl> <chr> <chr>
#> 1 1896 Gold HUN - HAJOS, Alfred
#> 2 1896 Silver AUT - HERSCHMANN, Otto
#> 3 1896 Bronze GRE - DRIVAS, Dimitrios
#> 4 1896 Gold GRE - MALOKINIS, Ioannis
#> 5 1896 Silver GRE - CHASAPIS, Spiridon
O, por ejemplo, podemos querer crear una variable que nos ponga un \(1\) si es griego y un \(0\) si no6:
6 Para más detalles sobre la función if_else
pueden ver el siguiente link.
|>
summer ::mutate(is_greek = if_else(Country == "GRE", 1, 0)) |>
dplyr::select(c(Year, Medal, Country, is_greek)) |>
dplyrhead(5)
#> # A tibble: 5 × 4
#> Year Medal Country is_greek
#> <dbl> <chr> <chr> <dbl>
#> 1 1896 Gold HUN 0
#> 2 1896 Silver AUT 0
#> 3 1896 Bronze GRE 1
#> 4 1896 Gold GRE 1
#> 5 1896 Silver GRE 1
Ahora vamos a aprender algo muy importante y cool 🆒: A agrupar los casos de acuerdo a una variable. Por ejemplo, si queremos agregar una columna que contenga la cantidad total de medallas ganadas por un país a cada atleta de ese país podemos hacer lo siguiente:
|>
summer group_by(Country) |>
::mutate(num_medals = n()) |>
dplyr::select(c(Year, Medal, Athlete, num_medals)) |>
dplyrhead(5)
#> # A tibble: 5 × 5
#> # Groups: Country [3]
#> Country Year Medal Athlete num_medals
#> <chr> <dbl> <chr> <chr> <int>
#> 1 HUN 1896 Gold HAJOS, Alfred 1079
#> 2 AUT 1896 Silver HERSCHMANN, Otto 146
#> 3 GRE 1896 Bronze DRIVAS, Dimitrios 148
#> 4 GRE 1896 Gold MALOKINIS, Ioannis 148
#> 5 GRE 1896 Silver CHASAPIS, Spiridon 148
¿Perdidos? Tomensé su tiepo para tratar de entender qué pasó y prueben distintas alternativas en sus computadoras.
summarise
Por último, el verbo summarise
nos permite sacar medidas resumen de nuestros datos. Empecemos con algo obvio: ¿Cuántas medallas de oro ganó cada país en la historia de los juegos olímpicos?. Podemos hacer algo parecido a lo último que hicimos con mutate
pero el resultados será ligeramente diferente7:
7 La función arrange
nos ordena los datos de acuerdo a la variable que le enviemos como parámetro de menos a mayor. Si queremos que ordene de mayor a menor debemos agregar la función desc
en el argumento. Más detalles acá.
|>
summer ::filter(Medal == "Gold") |>
dplyrgroup_by(Country) |>
::summarise(num_medals = n()) |>
dplyrarrange(desc(num_medals)) |>
head(10)
#> # A tibble: 10 × 2
#> Country num_medals
#> <chr> <int>
#> 1 USA 2235
#> 2 URS 838
#> 3 GBR 546
#> 4 ITA 476
#> 5 GER 452
#> 6 HUN 412
#> # ℹ 4 more rows
Hay algo raro, ¿No? Bueno, sí, de esta forma estamos contando a todos los atletas que tuvieron la misma medalla (por ejemplo, si la medalla fue por fútbol estamos contando cerca de 30 medallas). Para resolver esto nos podemos sacar de encima los casos duplicados por año, deporte, disciplina, evento y género8:
8 La función distinct
nos conserva una sola realización de cada caso que es igual de acuerdo a las variables que le pasemos como parámetros. Más detalles acá.
|>
summer distinct(Year, Sport, Discipline, Event, Gender, .keep_all = TRUE) |>
::filter(Medal == "Gold") |>
dplyrgroup_by(Country) |>
::summarise(num_medals = n()) |>
dplyrarrange(desc(num_medals)) |>
head(5)
#> # A tibble: 5 × 2
#> Country num_medals
#> <chr> <int>
#> 1 USA 67
#> 2 GBR 46
#> 3 CHN 40
#> 4 RUS 22
#> 5 GER 19
Vayamos con lo último, calculemos la media y la desviación estándar de las medallas de Argentina por JJOO combinando todo lo que vimos.
|>
summer distinct(Year, Sport, Discipline, Event, Medal, Gender, .keep_all = TRUE) |>
::filter(Country == "ARG") |>
dplyrgroup_by(Country, Year) |>
::summarise(num_medals = n()) |>
dplyrungroup() |>
summarise(media = mean(num_medals),
desvio = sd(num_medals))
#> # A tibble: 1 × 2
#> media desvio
#> <dbl> <dbl>
#> 1 3.83 2.28
Digieran esto tranquilos.
El paquete {tidyR} tiene muchas herramientas de manejo de tablas como reformatear, expandir tablas, manejar valores faltantes, dividir celdas, anidar datos, etc9. Sin embargo, en esta breve introducción sólo vamos a presentar muy brevemente las herramientas que nos permiten convertir una tabla wide en tidy (o long) y viceverse.
9 Para más información ver el cheatsheet.
pivot_longer
Volvamos a la tabla iniicial que teníamos en formato wide:
<- tibble(sujeto = rep(c("Jerry", "Elaine", "George")),
tabla_wide trial_1 = runif(3),
trial_2 = runif(3))
tabla_wide#> # A tibble: 3 × 3
#> sujeto trial_1 trial_2
#> <chr> <dbl> <dbl>
#> 1 Jerry 0.320 0.404
#> 2 Elaine 0.402 0.0637
#> 3 George 0.196 0.389
Si nosotros quisiñeramos transformar esta tabla en una tabla en formato tidy podemos utilizar la función pivot_longer
10. Veamos como funciona y después la desmenuzamos:
10 Más información acá.
pivot_longer(data = tabla_wide,
cols = trial_1:trial_2,
names_to = "trial",
values_to = "tiempo_respuesta")
#> # A tibble: 6 × 3
#> sujeto trial tiempo_respuesta
#> <chr> <chr> <dbl>
#> 1 Jerry trial_1 0.320
#> 2 Jerry trial_2 0.404
#> 3 Elaine trial_1 0.402
#> 4 Elaine trial_2 0.0637
#> 5 George trial_1 0.196
#> 6 George trial_2 0.389
Los argumentos son los siguientes: data
es la tabla a la que le vamos a realizar el cambio de formato; cols
son las columnas que vamos a cambiar, en este caso desde trial_1
a trial_2
; en names_to
indicamos la variable a la que vamos a mandar los nombres de las columnas actuales; y values_to
la variables a la que vamos a mandar los valores.
Algo ligeramente raro es que la columna trial no es numérica y, sólo por completitud, lo vamos a solucionar usando a nuestro gran amigo |>
y al verbo mutate
11:
11 Y la función parse_number
del paquete {readr}.
pivot_longer(data = tabla_wide,
cols = trial_1:trial_2,
names_to = "trial",
values_to = "tiempo_respuesta") |>
mutate(trial = parse_number(trial))
#> # A tibble: 6 × 3
#> sujeto trial tiempo_respuesta
#> <chr> <dbl> <dbl>
#> 1 Jerry 1 0.320
#> 2 Jerry 2 0.404
#> 3 Elaine 1 0.402
#> 4 Elaine 2 0.0637
#> 5 George 1 0.196
#> 6 George 2 0.389
pivot_wider
Ahora vamos con el caso contrario en el que tenemos una tabla en formato long y la queremos convertir en wide:
<- pivot_longer(data = tabla_wide,
tabla_long cols = trial_1:trial_2,
names_to = "trial",
values_to = "tiempo_respuesta") |>
mutate(trial = parse_number(trial))
tabla_long#> # A tibble: 6 × 3
#> sujeto trial tiempo_respuesta
#> <chr> <dbl> <dbl>
#> 1 Jerry 1 0.320
#> 2 Jerry 2 0.404
#> 3 Elaine 1 0.402
#> 4 Elaine 2 0.0637
#> 5 George 1 0.196
#> 6 George 2 0.389
Para esto vamos a hechar mano a la función pivot_wider
12 que tiene una sintáxis parecida a su prima pivot_longer
:
12 Más información acá.
pivot_wider(data = tabla_long,
names_from = trial,
values_from = tiempo_respuesta)
#> # A tibble: 3 × 3
#> sujeto `1` `2`
#> <chr> <dbl> <dbl>
#> 1 Jerry 0.320 0.404
#> 2 Elaine 0.402 0.0637
#> 3 George 0.196 0.389
Et Voilà!, ya tenemos nuestra tabla en formato wide. En este caso le dijimos de que variable tomar los nombres de las nuevas columnas en names_from
y de que variable tomar los valores en values_from
.
Finalmente, y sólo para alimnetar nuestra obsesión, vamos a corregir los nombres de las columnas agregando el prefijo trial_
utilizando el parámetro de la función names_prefix
:
pivot_wider(data = tabla_long,
names_from = trial,
names_prefix = "trial_",
values_from = tiempo_respuesta)
#> # A tibble: 3 × 3
#> sujeto trial_1 trial_2
#> <chr> <dbl> <dbl>
#> 1 Jerry 0.320 0.404
#> 2 Elaine 0.402 0.0637
#> 3 George 0.196 0.389
Como vimos brevemente en este capítulo, los paquetes del tidyverse son una herramineta importantísima para el análisis de datos utilizando R. Para más detalles sobre estas funcionalidades les recomendamos la guía de Hadley Wickham(Wickham et al. 2019) o, si ya se quieren sumergir de lleno en el mundo del análisis de datos con R, este fantástico libro (Wickham, Çetinkaya-Rundel, y Grolemund 2023)13. Es decir, sin tener que cargar ningún paquete de funciones adicional..
13 Disponible gratis online en acá.