Manejo de datos con R (II):
the tidyverse way

Curso de Introducción a R (SFPIE)
(Web del curso aquí)

Data munging: the tidyverse way



Aprendimos a cargar datos y a hacerlos TIDY, pero es raro que los datos estén preparados para empezar nuestro análisis, así que hay que “arreglar/limpiar” los datos

Arreglando los datos

  • Aprenderemos a limpiar y transformar datos en R. Priorizaremos la nueva forma de hacer las cosas en R (o workflow) conocido como tidyverse.


  • El procesado/limpieza de los datos suele ocupar un 80% del tiempo de un análisis de datos; así que el workflow sería más bien así:

DPLYR


  • el paquete dplyr es el paquete más importante a la hora de manipular datos.

dplyr

  • dplyr es un paquete que permite manipular datos de forma intuitiva


Tiene 6-7 funciones (o verbos) principales

  • Cada función hace “una sola cosa”, así que para realizar transformaciones complejas hay que ir concatenando instrucciones sencillas con el operador pipe (%>%)

sintaxis de dplyr

Todas las funciones tienen una estructura o comportamiento similar:

  • el primer argumento siempre es un df

  • los siguientes argumentos describen que hacer con los datos.

  • el resultado es siempre un nuevo df


Las siguientes 3 expresiones hacen exactamente lo mismo:

filter(df, X1 >= 10)

df %>% filter(. , X1 >= 10)

df %>% filter(X1 >= 10)

principales funciones de dplyr

  • select() : selecciona columnas
  • filter() : filtra/selecciona filas (que cumplen una o varias condiciones)


  • mutate() : crea nuevas columnas (variables)
  • arrange(): reordena las filas
  • rename() : cambia los nombres de las columnas


  • summarise() : resume (colapsa) los valores de una columna a un solo valor. Por ejemplo, calcula la media, máximo, mínimo, etc…

hay una séptima función (que da mucha potencia a dplyr)

  • group_by() : “agrupa” filas (en función de una o varias condiciones)

Extensión: across() y where()


  • Con dplyr 1.0.0, en mayo de 2020, aparecieron dos funciones importantes más: across() y where()


  • Estas funciones son un poco diferentes, solo se usan en combinación de otra función/verbo

  • Son 2 funciones que en la jerga del tidyverse no son verbos sino adverbios.


  • Lo vemos (en las extensiones)

Vamos a aprender a usar dplyr con ejemplos



trabajaremos con datos del pkg gapminder

  • ¿Supongo que ya sabéis que hace el siguiente código?

    • Claro que sí: hacemos accesibles en memoria de R el fichero de datos gapminder que está en el paquete gapminder
gapminder <- gapminder::gapminder   

select() se utiliza para seleccionar variables

  • Seleccionar variables por nombre
aa <- gapminder %>% select(year, lifeExp) 
  • Eliminar variables por nombre
aa <- gapminder %>% select(-year, -lifeExp)


  • Seleccionar variables por posición
aa <- gapminder %>% select(1:3, 5)
  • Eliminar variables por posición
aa <- gapminder %>% select(-c(1:3, 5))

A veces queremos reordenar las columnas/variables

  • Podemos hacerlo con relocate()
aa <- gapminder %>% dplyr::relocate(country, .after = lifeExp)

aa <- gapminder %>% dplyr::relocate(country, .before = lifeExp)

A veces queremos renombrar las columnas

  • Podemos hacerlo rename()
gapminder %>% rename(life_exp = lifeExp)



la función names() de R-base es útil

aa <- gapminder

names(aa)
[1] "country"   "continent" "year"      "lifeExp"   "pop"       "gdpPercap"

A veces queremos CREAR nuevas columnas

  • Podemos hacerlo con mutate()

  • Por ejemplo, podemos crear la variable: GDP = pop * gdpperCap

aa <- gapminder %>% mutate(GDP = pop * gdpPercap)


Extensión:

Por defecto, la nueva variable creada se situará al final del df, a no ser que usemos los argumentos .after y .before

aa <- gapminder %>% mutate(GDP = pop * gdpPercap, .after = pop)

filter(): permite seleccionar filas

filas que cumplan una determinadas condiciones o criterios lógicos

gapminder <- gapminder::gapminder  #- cargamos los datos

#- Observaciones de España (country == "Spain")
aa <- gapminder %>% filter(country == "Spain") 

#- filas con valores de "lifeExp" < 29
aa <- gapminder %>% filter(lifeExp < 29)       

#- filas con valores de "lifeExp" entre [29, 32]
aa <- gapminder %>% filter(lifeExp >=  29 &  lifeExp <= 32)  
aa <- gapminder %>% filter(between(lifeExp, 29, 32))       

#- observaciones de países de África con lifeExp > 32
aa <- gapminder %>% filter(lifeExp > 72 &  continent == "Africa") 

#- observaciones de países de África o Asia con lifeExp > 32
aa <- gapminder %>% filter(lifeExp > 72 &  continent %in% c("Africa", "Asia") )  
aa <- gapminder %>% filter(lifeExp > 72 & (continent == "Africa" | continent == "Asia") ) 

slice() es una variante de filter()

permite seleccionar filas pero por posición


  • filter() y slice() ambas seleccionan filas, la primera por condiciones y la segunda por posición:


#- selecciona las observaciones de la décima a la quinceava
aa <- gapminder %>% slice(c(10:15)) 

#- selecciona las 4 primeras observaciones, de la 41 a a la 43, y las 4 últimas 
aa <- gapminder %>%
  slice( c(1:4, 41:43, (n()-3):n() ) ) 

variantes de slice()

  • slice_max() y slice_min(): seleccionan filas con valor máximo (o mínimo) de una variable:
#- selecciona las 3 filas con mayor valor de lifeExp
aa <- gapminder %>% slice_max(lifeExp, n = 3)

#- selecciona las 4 filas con MENOR valor de pop
aa <- gapminder %>% slice_min(pop, n = 4)

#- observaciones en el primer décil en cuanto a esperanza de vida, 10% con menor esperanza de vida
aa <- gapminder %>% slice_min(lifeExp, prop = 0.1)

#- 1% de observaciones con mayor población. Imagino que estarán China e India
aa <- gapminder %>% slice_max(pop, prop = 0.01)

variantes de slice()

  • slice_sample(): permite obtener una muestra aleatoria de los datos


#- selecciona (aleatoriamente) 100 filas de los datos
aa <- gapminder %>% slice_sample(n = 100)

#- selecciona (aleatoriamente) un 5% de los datos
aa <- gapminder %>% slice_sample(prop = 0.05)

arrange(): permite reordenar las filas de un df


#- ordena las filas de MENOR a mayor según los valores de la v. lifeExp 
aa <- gapminder %>% arrange(lifeExp)

#- ordena las filas de MAYOR a menor según los valores de la v. lifeExp
aa <- gapminder %>% arrange(desc(lifeExp))  

#- ordena las filas de MENOR a mayor según los valores de la v. lifeExp. 
#- Si hubiesen empates se resuelve con la variable "pop"
aa <- gapminder %>% arrange(lifeExp, pop) 

summarize() para “resumir” variables

  • summarize(): coge una variable como input y devuelve un solo valor; por ejemplo, calcula la media aritmética (o el mínimo, o el máximo …) de una columna/variable


  • Empezamos “resumiendo” una sola variable:


aa <- gapminder %>% summarise(maximo = max(pop))  #- el valor máximo de la variable "pop"

aa <- gapminder %>% summarise(NN = n())           #- el número de observaciones

aa <- gapminder %>% summarise(media = mean(lifeExp))  #- la media de la variable "lifeExp"

aa <- gapminder %>% summarise(desviacion_tipica = sd(lifeExp))  #- os lo explicarán en Estadística 

summarize(): “resumimos” dos variables


#- retornará 2 valores: las medias de "lifeExp" y "gdpPercap"
aa <- gapminder %>% summarise(mean(lifeExp), mean(gdpPercap))  



summarize(): hacemos 2 resúmenes de una variable


#- retornará 2 valores: la media y máximo de la v. "lifeExp"
aa <- gapminder %>% summarise(mean(lifeExp), max(lifeExp))

group_by(): con está función ya se puede ver la potencia de dplyr

En análisis de datos muchas operaciones queremos calcularlas para distintos grupos (p. ej. mujer/hombre, diferentes países, provincias …). group_by() permite hacerlo.

  • group_by() coge un df y lo convierte en un “df agrupado”. En ese nuevo “df agrupado”, las operaciones que hagamos, se harán por separado para cada uno de los grupos que hayamos definido. Ahora lo vemos.
  • Por ejemplo: queremos calcular el nº de observaciones en el df y el nº de observaciones de cada continente
# calculamos el nº de observaciones en el df
aa <- gapminder %>% summarise(NN = n()) 
gt::gt(aa)
NN
1704
# ahora queremos calcular el nº de observaciones de cada continente
# cogemos df y lo (des)agrupamos por grupos definidos por la variable "continent"
# o sea, habrá 5 grupos (5 continentes)
# después con summarise() calcularemos el nº de observaciones en cada grupo;
# es decir, nos retornará un df con una fila por cada continente
# con el nº de observaciones de cada continente

bb <- gapminder %>% group_by(continent) %>% summarise(NN = n())
gt::gt(bb)
continent NN
Africa 624
Americas 300
Asia 396
Europe 360
Oceania 24

Extensiones




con dplyr 1.0.0, en 2020, aparecieron dos funciones importantes: across() y where()

  • across() y where(): estas funciones son un poco diferentes, solo se usan en combinación de otra función/verbo. Son 2 funciones que en la jerga del tidyverse no son verbos sino adverbios, cualifican/cambian lo que hacen otras funciones como select()

Ejemplo de uso: select() junto a la función where() [🌶🌶🌶🌶]

  • En gapminder las 2 primeras variables (country y continent) son factores y las 4 siguientes son variable numéricas.


  • Imagina que queremos seleccionar sólo las variables numéricas. Podemos hacerlo por nombre o por posición pero mejor hacerlo con select() y where()
aa <- gapminder %>% select(is.numeric)        #- funciona, pero ...

aa <- gapminder %>% select(where(is.numeric)) #- es "preferible" esta segunda expresión


  • Si quisiseramos seleccionar las variables que NO son numéricas haríamos:
aa <- gapminder %>% select(!where(is.numeric)) 

más ejemplos de across() y where()


  • Imagina que queremos calcular la media de todas las variables de gapminder. Tendríamos que repetir código 6 veces … o usar across()
#- media de todas (everything()) las variables. 
#- Devuelve 2 warnings porque las 2 primeras son textuales. No se puede calcular la media de continent y country
gapminder %>% summarise(across(everything(), mean) )


  • Ahora calculamos la media de la tercera a la sexta variable:
gapminder %>% summarise(across(3:6, mean) )

across() y where() con summarise()       😱


  • Dentro de across() se puede utilizar where()

  • Con esto conseguimos poder aplicar criterios lógicos en la selección de variables: [🌶] [ 🌟 ]


Si quisiéramos calcular la media de las variables numéricas

gapminder %>% summarise(across(where(is.numeric), mean))



Ahora no os asustéis de lo que salga: es lo mismo que lo de arriba pero con los nombres de los argumentos

#- con los nombres de los argumentos (más largo pero conviene verlo de vez en cuando)
gapminder %>% summarise(across(.cols = where(is.numeric), .fns = mean))

summarise() con across() y varias funciones         😱😱😱😱

  • Si quieres calcular varios estadísticos de varias variables; por ejemplo, la media y la desviación típica de un grupo de variables

  • Tendrás que seguir utilizando summarise() con across() pero, además, tendrás que poner la lista de funciones dentro de list(). [🌶] [ 🌟 ]

Si quisiéramos calcular la media y la desviación típica de las variables 3 a 6

gapminder %>% summarise(across(3:6, list(media = mean, desv = sd)))


Otra vez, no os asustéis de lo que salga: es lo mismo que lo de arriba pero con los nombres de los argumentos

#- lo mismo, pero explicitando los nombres de los argumentos [🌶] 
gapminder %>% summarise(across(.cols = 3:6, .fns = list(media = mean, desv = sd) ))


Ya lo último: añadimos un argumento más .names, que nos permite controlar el nombre de las nuevas variables

#- lo mismo otra vez, pero eligiendo el nombre de las variables que se van a crear con .names [🌶] [🌶] 
gapminder %>% summarise(across(3:6, list(media = mean, desv = sd), .names = "{fn}_{col}"))

Más ejemplos para afianzar el uso de across()


Creamos un nuevo df: “gapminder_gr” o “gapminder agrupado”

gapminder_gr <- gapminder %>% filter(year %in% c(1952, 2007)) %>%
                 group_by(continent, year) 

Hacemos cálculos partiendo de “gapminder_gr”. Recuerda que esta “agrupado” por continente y año

#- si queremos calcular la media de varias variables tenemos que usar across()
gapminder_gr %>% summarise(across(c(lifeExp, gdpPercap), mean))

#- si queremos calcular la media de todas las variables numéricas tenemos que usar across() y where()
gapminder_gr %>% summarise(across(where(is.numeric), mean))

#- si queremos calcular la media y la mediana, hay que usar list()
gapminder_gr %>% summarise(across(c(lifeExp, gdpPercap), 
                            list (media = mean, mediana = median) ))

#- si ponemos los nombres de los argumentos quedaría como
gapminder_gr %>% summarise(across(.cols = c(lifeExp, gdpPercap), 
                                  .fns = list (media = mean, mediana = median)))

#- además, podemos controlar el nombre de las variables creadas con el argumento .names
gapminder_gr %>% summarise(across(c(lifeExp, gdpPercap), 
                        list (media = mean, mediana = median), 
                        .names = "{fn}_{col}"))

Seguimos con dplyr



  • Seguimos con más ejemplos para afianzar nuestros conocimientos

  • Empezamos con ejemplos sencillos; pronto llegaremos a “preguntas de verdad”

vimos ya la la “teoría” del tidyverse

  • El tidyverse es un conjunto de paquetes de R que facilitan la manipulación de datos, su visualización y modelización


  • dplyr es el paquete más importante a la hora de manipular datos.


  • Sus funciones más importantes son: select(), filter(), mutate(), arrange(), rename, summarise() y group_by().


  • Cada función hace “una sola cosa”, así que para realizar transformaciones complejas hay que ir concatenando instrucciones sencillas con el operador pipe (%>%)

Ejemplos


para aprender a manipular datos con dplyr

CONTAR (observaciones)


  • Es importante saber cómo contar las observaciones que tenemos en distintos grupos

  • Por ejemplo, contar cuantas mujeres hay, o cuantas observaciones hay en cada continente, o cuantas empresas en diferentes sectores, …

… vamos a CONTAR

tenemos 3 formas distintas de contar el nº de observaciones (o filas)

1. Usando mutate() con n()

#- fíjate q con mutate() se mantienen todas las filas y todas las columnas
aa <- gapminder %>% mutate(NN = n())  

nrow(aa)  #- se mantienen las 1704 observaciones
[1] 1704

1. mutate() mantiene el nº de filas originales (1704)

bb <- head(aa, n = 3)
gt::gt(bb)
country continent year lifeExp pop gdpPercap NN
Afghanistan Asia 1952 28.801 8425333 779.4453 1704
Afghanistan Asia 1957 30.332 9240934 820.8530 1704
Afghanistan Asia 1962 31.997 10267083 853.1007 1704

2. Usando summarise() con n()

#- fíjate q  summarise() solo devuelve una fila y una columna
aa <- gapminder %>% summarise(NN = n())

2. summarise() devuelve una fila (por grupo)

gt::gt(aa)
NN
1704

3. Usando count()

aa <- gapminder %>% count()

3. count() devuelve una fila (por grupo)

gt::gt(aa)
n
1704

… seguimos CONTANDO

Pero ahora contamos el nº de observaciones de distintos grupos (por ejemplo el nº de observaciones de cada continente)

  • También podríamos usar mutate() pero esta vez solo usaremos summarise() y count()
# fíjate q  summarise() devuelve una fila por cada grupo
# una fila por cada continente
aa <- gapminder %>% 
  group_by(continent) %>% summarise(NN = n())
gt::gt(aa)
continent NN
Africa 624
Americas 300
Asia 396
Europe 360
Oceania 24
aa <- gapminder %>% count(continent)
gt::gt(aa)
continent n
Africa 624
Americas 300
Asia 396
Europe 360
Oceania 24

… aún seguimos CONTANDO

Contamos el nº de observaciones de distintos grupos, pero ahora definidos por dos variables (por ejemplo el nº de observaciones de cada continente y año)

# fíjate q hay 60 grupos (5 continentes x 12 periodos)
# por lo que devuelve 60 filas, una por grupo

aa <- gapminder %>% 
  group_by(continent, year) %>% summarise(NN = n())


aa <- gapminder %>% count(year, continent)
bb <- head(aa, n = 14)
gt::gt(bb) 
year continent n
1952 Africa 52
1952 Americas 25
1952 Asia 33
1952 Europe 30
1952 Oceania 2
1957 Africa 52
1957 Americas 25
1957 Asia 33
1957 Europe 30
1957 Oceania 2
1962 Africa 52
1962 Americas 25
1962 Asia 33
1962 Europe 30

Extensión: n() versus nrow()

  • n() es una función auxiliar en el tidyverse. Devuelve en nº de filas “in the current group”. Solo funciona en el tidyverse, concretamente en funciones como mutate() y summarise()
#- como agrupamos por año y continente, saldrán 60 grupos (12 x 5)

aa <- gapminder %>%
  group_by(continent, year) %>% 
  summarise(NN = n()) %>% 
  ungroup()
aa %>% slice(1, 2, 12, 13) %>% 
  gt::gt() %>% 
  gtExtras::gt_theme_guardian()
continent year NN
Africa 1952 52
Africa 1957 52
Africa 2007 52
Americas 1952 25
  • nrow(x) es una función de R-base. Devuelve el número de filas en x
#- como agrupamos por año y continente, saldrán 60 grupos (12 x 5)

#- con nrow()
bb <- gapminder %>% 
  group_by(continent, year) %>% 
  summarise(NN = nrow(.)) %>% 
  ungroup()
bb %>% slice(1, 2, 12, 13) %>% 
  gt::gt() %>% 
  gtExtras::gt_theme_dark()
continent year NN
Africa 1952 1704
Africa 1957 1704
Africa 2007 1704
Americas 1952 1704

observaciones DISTINTAS


  • A veces es importante ver (y contar) las observaciones DISTINTAS que tengamos (en los distintos grupos de nuestros datos)

… ver/obtener observaciones DISTINTAS con distinct()

  • gapminder tiene 1.704 filas: ninguna repetida
# gapminder tiene 1.704 filas: ninguna repetida
aa <- gapminder %>% distinct()
# gapminder no tiene filas repetidas
nrow(aa) == nrow(gapminder)
[1] TRUE
  • En gapminder hay 5 valores distintos para los continentes
# en gapminder hay 5 valores distintos para los continentes
aa <- gapminder %>% distinct(continent)
# efectivamente 5 continentes
gt::gt(aa)
continent
Asia
Europe
Africa
Americas
Oceania
  • gapminder tiene 60 filas/combinaciones distintas para continente-año (5 x 12 = 60)
# en gapminder hay 5 valores distintos para los continentes
aa <- gapminder %>% distinct(continent, year)
# efectivamente 60:  5 continentes x 12 periodos
nrow(aa)
[1] 60

CONTAR observaciones DISTINTAS con n_distinct()

  • cuantos países (distintos) hay en cada continente?
# nº de países distintos en cada continente
aa <- gapminder %>% 
  group_by(continent) %>% 
  summarise(NN = n_distinct(country))
gt::gt(aa)
continent NN
Africa 52
Americas 25
Asia 33
Europe 30
Oceania 2
  • cuantos países (distintos) hay cada año en cada continente?
# nº de países distintos en cada continente
aa <- gapminder %>% 
  group_by(year, continent) %>% 
  summarise(NN = n_distinct(country)) %>% 
  ungroup()
gt::gt(head(aa, n = 7))
year continent NN
1952 Africa 52
1952 Americas 25
1952 Asia 33
1952 Europe 30
1952 Oceania 2
1957 Africa 52
1957 Americas 25

obtener/calcular estadísticos


  • Ya os explicaran en Estadística y Econometría qué es un estadístico, cuales son los más importantes y cómo se calculan 😉
  • Los estadísticos más sencillos de entender son: el máximo, el mínimo y la media

calculando ESTADISTICOS: máximo, mínimo, media, ……

  • obtener el máximo, mínimo y media de “lifeExp”:
aa <- gapminder %>% 
  summarise(maximo = max(lifeExp, na.rm = TRUE), 
            minimo = min(lifeExp, na.rm = TRUE), 
            media = mean(lifeExp, na.rm = TRUE) )
gt::gt(aa)
maximo minimo media
82.603 23.599 59.47444


calcular ESTADISTICOS (máximo, mínimo y media) por continente


#- calcular estadísticos por continente
aa <- gapminder %>% group_by(continent) %>% 
  summarise(maximo = max(lifeExp, na.rm = TRUE), 
            minimo = min(lifeExp, na.rm = TRUE), 
            media = mean(lifeExp, na.rm = TRUE) )
aa %>% gt::gt()
continent maximo minimo media
Africa 76.442 23.599 48.86533
Americas 80.653 37.579 64.65874
Asia 82.603 28.801 60.06490
Europe 81.757 43.585 71.90369
Oceania 81.235 69.120 74.32621

ESTADISTICOS para Europa año a año ……


#- calcular estadísticos por CONTINENTE Y AÑO
aa <- gapminder %>% 
1  group_by(continent, year) %>%
2  summarise(maximo = max(lifeExp, na.rm = TRUE),
            minimo = min(lifeExp, na.rm = TRUE), 
            mean = mean(lifeExp, na.rm = TRUE) ) %>% 
3  ungroup() %>%
4  filter(continent == "Europe")
1
primero agrupamos por continente y año
2
Calculamos los estadísticos (para las observaciones de cada año y continente)
3
Usar group_by() es una buena práctica hacer después un ungroup()
4
Seleccionamos solo los datos de Europa
aa %>% gt::gt() %>% gt::fmt_number(3:5, decimals = 2)
continent year maximo minimo mean
Europe 1952 72.67 43.59 64.41
Europe 1957 73.47 48.08 66.70
Europe 1962 73.68 52.10 68.54
Europe 1967 74.16 54.34 69.74
Europe 1972 74.72 57.01 70.78
Europe 1977 76.11 59.51 71.94
Europe 1982 76.99 61.04 72.81
Europe 1987 77.41 63.11 73.64
Europe 1992 78.77 66.15 74.44
Europe 1997 79.39 68.83 75.51
Europe 2002 80.62 70.84 76.70
Europe 2007 81.76 71.78 77.65

en la slide anterior, al calcular la esperanza de vida media por continente,
estábamos promediando países con diferente población 🫣


  • Vuelve a calcular la esperanza de vida media por continente y año, PERO ahora, ten en cuenta que los países tienen distinto nº de habitantes

  • Es decir, hemos de calcular la media, pero ponderada por la población (pop)

  • Pista: Igual puedes reusar el código de la página anterior, pero en lugar de usar mean() usar weighted.mean()

  • Tendrás que mirar la ayuda de weighted.mean() para usar un nuevo argumento

aa <- gapminder %>% 
  group_by(continent, year) %>%   
1  summarise(mean = mean(lifeExp, na.rm = TRUE),
            mean_w = weighted.mean(lifeExp, w = pop, na.rm = TRUE)) %>%    
  ungroup() %>%   
2  filter(year == 2007)
1
Calculamos la media y la media ponderada (para las observaciones de cada año y continente)
2
Ahora en lugar de ver los resultados para Europa, filtramos el año 2007
aa %>% gt::gt() %>% 
  gt::fmt_number(3:4, decimals = 2)
continent year mean mean_w
Africa 2007 54.81 54.56
Americas 2007 73.61 75.36
Asia 2007 70.73 69.44
Europe 2007 77.65 77.89
Oceania 2007 80.72 81.06

Seguimos con más ejemplos



Por favor, sed conscientes de que: “las cosas no salen a la primera


En palabras de Jennyfer Bryan:

Break the code into pieces, starting at the top, and inspect the intermediate results. That’s certainly how I was able to write such a thing. These commands do not leap fully formed out of anyone’s forehead – they are built up gradually, with lots of errors and refinements along the way. Is the statement above really hard for you to read? If yes, then by all means break it into pieces and make some intermediate objects. Your code should be easy to write and read when you’re done.

empezamos con una pregunta sencilla, pero …

  • ¿Cuantos países distintos hay en gapminder?

Algunas funciones del tidyverse que te podrían servir:

  • count()

  • summarise() junto a otras funciones

  • distinct()

  • n_distinct(): es un poco peculiar

  • n()

Lógicamente con R-base también se puede contar:

  • nrow()

  • length()

  • unique()

aa <- gapminder %>% group_by(country) %>%  
  summarize(NN = n())


aa <- gapminder %>% count(country)
aa %>% slice(1, 2, 142) %>% gt::gt()
country n
Afghanistan 12
Albania 12
Zimbabwe 12
aa <- gapminder %>% 
  summarise(NN_paises = n_distinct(country))
aa %>% gt::gt()
NN_paises
142
aa <- distinct(gapminder, country) 
aa %>% slice(1, 2, 142) %>% gt::gt()
country
Afghanistan
Albania
Zimbabwe
aa <- n_distinct(gapminder$country)

aa <- n_distinct(gapminder %>% select(country))
aa 
[1] 142
  • Solución “canónica” en R-base (además, se sigue viendo mucho):
length(unique(gapminder$country))


  • lo más equivalente en el tidyverse sería:
gapminder %>% count(country) %>% nrow()



  • Con esta pregunta “tan sencilla” quería:

    • mostrar algunas funciones (lenght(), unique() y nrow()) de R-base

    • mostraros que … cuando hay que obtener “una sola cosa” , y está cosa no es complicada, entonces, la solución en R-base suele ser sencilla


  • PERO los análisis de datos son bastante más complejos, y es entonces, cuando el tidyverse se hace casi “indispensable”

otra pregunta


  • En gapminder ¿Cuantos países distintos hay en cada continente?

  • Después, calcula el porcentaje de países de cada continente sobre el total

#- Solución à la tidyverse
aa <- gapminder %>% 
  group_by(continent) %>% 
  summarize(NN = n_distinct(country)) %>% 
  mutate(NN_total = sum(NN)) %>%
  mutate(porcentaje = (NN / NN_total) * 100) 
gt::gt(aa)
continent NN NN_total porcentaje
Africa 52 142 36.619718
Americas 25 142 17.605634
Asia 33 142 23.239437
Europe 30 142 21.126761
Oceania 2 142 1.408451
#- solución à la R-base (seguro q se puede mejorar algo ...)
bb <- unique(gapminder[, c("country", "continent")])
cc <- aggregate(country ~ continent, data = bb, FUN = length)

# Renombrar la columna de conteo
colnames(cc)[colnames(cc) == "country"] <- "NN"

# Calcular el número total de países únicos en gapminder
NN_total <- sum(cc$NN)
cc$NN_total <- NN_total

# Calcular el porcentaje de países de cada continente sobre el total
cc$porcentaje <- (cc$NN / cc$NN_total) * 100
gt::gt(cc)
continent NN NN_total porcentaje
Africa 52 142 36.619718
Americas 25 142 17.605634
Asia 33 142 23.239437
Europe 30 142 21.126761
Oceania 2 142 1.408451


Se podrá mejorar algo el código, pero, fíjate que hemos tenido que crear varios objetos intermedios

ahora … una pregunta de verdad

  • ¿En que continente ha aumentado más la esperanza de vida en el periodo 1952-2007?


#- esta parte va a ser común en las 4 soluciones

aa <- gapminder %>% 
  filter(year %in% c(1952, 2007)) %>%  
  group_by(continent, year) %>% 
  summarize(media = mean(lifeExp)) %>% ungroup()
gt::gt(aa)
continent year media
Africa 1952 39.13550
Africa 2007 54.80604
Americas 1952 53.27984
Americas 2007 73.60812
Asia 1952 46.31439
Asia 2007 70.72848
Europe 1952 64.40850
Europe 2007 77.64860
Oceania 1952 69.25500
Oceania 2007 80.71950


#- se podría hacer de una vez, pero partimos el código en 2 trozos

aa <- gapminder %>% filter(year %in% c(1952, 2007)) %>%  
  group_by(continent, year) %>% 
  summarize(media = mean(lifeExp)) %>% ungroup()

bb <- aa %>% group_by(continent) %>% 
  summarise(min_l = min(media), max_l = max(media)) %>% 
  mutate(dif = max_l-min_l) %>% 
  arrange(desc(dif))


En esta solución “podría haber un problema”

gt::gt(aa)
continent year media
Africa 1952 39.13550
Africa 2007 54.80604
Americas 1952 53.27984
Americas 2007 73.60812
Asia 1952 46.31439
Asia 2007 70.72848
Europe 1952 64.40850
Europe 2007 77.64860
Oceania 1952 69.25500
Oceania 2007 80.71950
gt::gt(bb)
continent min_l max_l dif
Asia 46.31439 70.72848 24.41409
Americas 53.27984 73.60812 20.32828
Africa 39.13550 54.80604 15.67054
Europe 64.40850 77.64860 13.24010
Oceania 69.25500 80.71950 11.46450
#- el primer trozo sigue siendo comuún

aa <- gapminder %>% filter(year %in% c(1952, 2007)) %>%  
         group_by(continent, year) %>% 
         summarize(media = mean(lifeExp)) %>% ungroup() 

#- usamos lag()
bb <- aa %>% group_by(continent) %>% 
              arrange(year) %>%
              mutate(variacion = media - lag(media)) %>% ungroup()

#- para mostrar  los resultados
cc <- bb %>% filter(year == 2007) %>% arrange(desc(variacion))
gt::gt(bb)
continent year media variacion
Africa 1952 39.13550 NA
Americas 1952 53.27984 NA
Asia 1952 46.31439 NA
Europe 1952 64.40850 NA
Oceania 1952 69.25500 NA
Africa 2007 54.80604 15.67054
Americas 2007 73.60812 20.32828
Asia 2007 70.72848 24.41409
Europe 2007 77.64860 13.24010
Oceania 2007 80.71950 11.46450
gt::gt(cc)
continent year media variacion
Asia 2007 70.72848 24.41409
Americas 2007 73.60812 20.32828
Africa 2007 54.80604 15.67054
Europe 2007 77.64860 13.24010
Oceania 2007 80.71950 11.46450
#- ya sabemos que la primera parte es común

aa <- gapminder %>% 
  filter(year %in% c(1952, 2007)) %>%  
  group_by(continent, year) %>% 
  summarize(media = mean(lifeExp)) %>% ungroup()

#- pero ahora usamos pivot_wider()
bb <- aa %>% pivot_wider(names_from = year, values_from = media) %>% 
     mutate(dif_l = 2007 - 1952) %>% 
     arrange(desc(dif_l))


          ¿qué error cometí?
gt::gt(aa)
continent year media
Africa 1952 39.13550
Africa 2007 54.80604
Americas 1952 53.27984
Americas 2007 73.60812
Asia 1952 46.31439
Asia 2007 70.72848
Europe 1952 64.40850
Europe 2007 77.64860
Oceania 1952 69.25500
Oceania 2007 80.71950
gt::gt(bb)
continent 1952 2007 dif_l
Africa 39.13550 54.80604 55
Americas 53.27984 73.60812 55
Asia 46.31439 70.72848 55
Europe 64.40850 77.64860 55
Oceania 69.25500 80.71950 55

preguntas de verdad (II)

  • ¿qué hace el código de abajo?


aa <- gapminder %>% 
  group_by(continent, year) %>% 
  select(continent, year, lifeExp) %>% 
  summarise(mean_life = mean(lifeExp)) %>% 
  arrange(year) %>% 
  mutate(incre_mean_life_0 = mean_life - first(mean_life)) %>% 
  mutate(incre_mean_life_t = mean_life - lag(mean_life)) %>% 
  arrange(continent) %>% 
  ungroup()

#- por ejemplo veamos el resultado para Europe
bb <- aa %>% filter(continent == "Europe")


gt::gt(bb)
continent year mean_life incre_mean_life_0 incre_mean_life_t
Europe 1952 64.40850 0.000000 NA
Europe 1957 66.70307 2.294567 2.2945667
Europe 1962 68.53923 4.130733 1.8361667
Europe 1967 69.73760 5.329100 1.1983667
Europe 1972 70.77503 6.366533 1.0374333
Europe 1977 71.93777 7.529267 1.1627333
Europe 1982 72.80640 8.397900 0.8686333
Europe 1987 73.64217 9.233667 0.8357667
Europe 1992 74.44010 10.031600 0.7979333
Europe 1997 75.50517 11.096667 1.0650667
Europe 2002 76.70060 12.292100 1.1954333
Europe 2007 77.64860 13.240100 0.9480000

preguntas de verdad (III)

  • ¿Cómo ha evolucionado la esperanza de vida en España?


#- variación de lifeExp en Spain año a año (bueno lustro a lustro)

aa <- gapminder %>% group_by(country) %>% 
  select(country, year, lifeExp) %>% 
  mutate(life_gain = lifeExp - lag(lifeExp)) %>% 
  filter(country == "Spain" ) %>% 
  ungroup()


gt::gt(aa)
country year lifeExp life_gain
Spain 1952 64.940 NA
Spain 1957 66.660 1.720
Spain 1962 69.690 3.030
Spain 1967 71.440 1.750
Spain 1972 73.060 1.620
Spain 1977 74.390 1.330
Spain 1982 76.300 1.910
Spain 1987 76.900 0.600
Spain 1992 77.570 0.670
Spain 1997 78.770 1.200
Spain 2002 79.780 1.010
Spain 2007 80.941 1.161
  • ¿Y la variación acumulada? Fácil!!

  • Sólo tendríamos que sumar o acumular la variable “life_gain” que hemos generado anteriormente, así que sólo habría que añadir una linea a nuestro código


aa <- gapminder %>% group_by(country) %>% 
  select(country, year, lifeExp) %>% 
  mutate(life_gain = lifeExp - lag(lifeExp)) %>% 
   #- Al final para hacerlo (como había pensado) me han hecho falta 2 lineas, 
   #- xq la primera observación de "life_gain" es un NA 
   #- y eso hacía que la función cumsum() no funcionase.
  mutate(life_gain_2 = 
  ifelse(is.na(life_gain), 0, life_gain)) %>% 
  mutate(life_gain_acu = cumsum(life_gain_2)) %>%   
  filter(country == "Spain") %>% 
  ungroup()


gt::gt(aa)
country year lifeExp life_gain life_gain_2 life_gain_acu
Spain 1952 64.940 NA 0.000 0.000
Spain 1957 66.660 1.720 1.720 1.720
Spain 1962 69.690 3.030 3.030 4.750
Spain 1967 71.440 1.750 1.750 6.500
Spain 1972 73.060 1.620 1.620 8.120
Spain 1977 74.390 1.330 1.330 9.450
Spain 1982 76.300 1.910 1.910 11.360
Spain 1987 76.900 0.600 0.600 11.960
Spain 1992 77.570 0.670 0.670 12.630
Spain 1997 78.770 1.200 1.200 13.830
Spain 2002 79.780 1.010 1.010 14.840
Spain 2007 80.941 1.161 1.161 16.001
  • Otra solución; además, más fácil


#- ganancia acumulada (otra forma de hacer lo mismo)

aa <- gapminder %>% group_by(country) %>% 
  select(country, year, lifeExp) %>% 
  mutate(life_gain_acu = lifeExp - lifeExp[1])  %>% 
  filter(country == "Spain") %>% 
  ungroup()


gt::gt(aa)
country year lifeExp life_gain_acu
Spain 1952 64.940 0.000
Spain 1957 66.660 1.720
Spain 1962 69.690 4.750
Spain 1967 71.440 6.500
Spain 1972 73.060 8.120
Spain 1977 74.390 9.450
Spain 1982 76.300 11.360
Spain 1987 76.900 11.960
Spain 1992 77.570 12.630
Spain 1997 78.770 13.830
Spain 2002 79.780 14.840
Spain 2007 80.941 16.001

a ver si entendéis estos ejemplos


aa <- gapminder %>%
  filter(continent == "Asia") %>%
  select(year, country, lifeExp) %>%
  group_by(year) %>%
  slice_max(n = 3, lifeExp) %>% 
  arrange(year) %>% 
  ungroup()


aa %>% head(10) %>% gt::gt()
year country lifeExp
1952 Israel 65.39
1952 Japan 63.03
1952 Hong Kong, China 60.96
1957 Israel 67.84
1957 Japan 65.50
1957 Hong Kong, China 64.75
1962 Israel 69.39
1962 Japan 68.73
1962 Hong Kong, China 67.65
1967 Japan 71.43


aa <- gapminder %>%
  group_by(continent, year)  %>%
  mutate(media_life = mean(lifeExp)) %>% 
  mutate(media_gdp = mean(gdpPercap)) %>% 
  mutate(GOOD_or_BAD = case_when( 
    lifeExp > mean(lifeExp) & gdpPercap > mean(gdpPercap)  ~ "good",
    lifeExp < mean(lifeExp) & gdpPercap < mean(gdpPercap)  ~ "bad" ,
    lifeExp < mean(lifeExp) | gdpPercap < mean(gdpPercap)  ~ "medium",
    .default = "otros casos"
  )) %>%
  filter(country == "Spain") %>% 
  ungroup()


aa %>% 
  select(year, country, continent, lifeExp, gdpPercap, 
         media_life, media_gdp, GOOD_or_BAD) %>%  
  gt::gt()
year country continent lifeExp gdpPercap media_life media_gdp GOOD_or_BAD
1952 Spain Europe 64.940 3834.035 64.40850 5661.057 medium
1957 Spain Europe 66.660 4564.802 66.70307 6963.013 bad
1962 Spain Europe 69.690 5693.844 68.53923 8365.487 medium
1967 Spain Europe 71.440 7993.512 69.73760 10143.824 medium
1972 Spain Europe 73.060 10638.751 70.77503 12479.575 medium
1977 Spain Europe 74.390 13236.921 71.93777 14283.979 medium
1982 Spain Europe 76.300 13926.170 72.80640 15617.897 medium
1987 Spain Europe 76.900 15764.983 73.64217 17214.311 medium
1992 Spain Europe 77.570 18603.065 74.44010 17061.568 good
1997 Spain Europe 78.770 20445.299 75.50517 19076.782 good
2002 Spain Europe 79.780 24835.472 76.70060 21711.732 good
2007 Spain Europe 80.941 28821.064 77.64860 25054.482 good

Calcular CRECIMIENTOS



  • Muchas veces interesa saber cuanto crecen las variables, por ejemplo el PIB, o el desempleo , …, o la esperanza de vida

calculando CRECIMIENTOS


  • calcular el crecimiento de la esperanza de vida, de un periodo a otro, en España
aa <- gapminder %>% 
1  select(country, year, lifeExp) %>%
2  group_by(country) %>%
3  arrange(year) %>%
4  mutate(crecimiento =  lifeExp - lag(lifeExp)) %>%
5  mutate(crecimiento2 = lifeExp - lag(lifeExp, default = first(lifeExp))) %>%
6  ungroup() %>%
7  filter(country == "Spain")
1
Selecciono las variables relevantes
2
Agrupamos por país: los cálculos siguientes se harán para cada país
3
Ordenamos por año: el año más antiguo (1952) el primero
4
Calculamos el crecimiento de la esperanza de vida de un año a otro
5
Mejoramos el calculo anterior de “crecimiento”
6
Al usar group_by() es una buena práctica hacer después un ungroup()
7
Seleccionamos solo los datos de España
gt::gt(aa) %>% 
  gt::fmt_number(3:5, decimals = 2)
country year lifeExp crecimiento crecimiento2
Spain 1952 64.94 NA 0.00
Spain 1957 66.66 1.72 1.72
Spain 1962 69.69 3.03 3.03
Spain 1967 71.44 1.75 1.75
Spain 1972 73.06 1.62 1.62
Spain 1977 74.39 1.33 1.33
Spain 1982 76.30 1.91 1.91
Spain 1987 76.90 0.60 0.60
Spain 1992 77.57 0.67 0.67
Spain 1997 78.77 1.20 1.20
Spain 2002 79.78 1.01 1.01
Spain 2007 80.94 1.16 1.16

calculando CRECIMIENTOS ACUMULADOS

  • calcular el crecimiento de la esperanza de vida ACUMULADO en España
aa <- gapminder %>% 
  select(country, year, lifeExp) %>%   
1  group_by(country) %>%
2  arrange(year) %>%
3  mutate(crec_1 = lifeExp - lag(lifeExp)) %>%
4  mutate(crec_2 = lifeExp - lag(lifeExp, default = first(lifeExp))) %>%
5  mutate(crec_acu_1 = cumsum(crec_1)) %>%
6  mutate(crec_acu_2 = cumsum(crec_2)) %>%
7  mutate(crec_acu_3 = lifeExp - first(lifeExp)) %>%
8  ungroup() %>%
  filter(country == "Spain") 
1
Agrupamos por país: los cálculos siguientes se harán para cada país
2
Ordenamos por año: el año más antiguo (1952) el primero
3
Calculamos el crecimiento de la esperanza de vida de un año a otro
4
“Mejoramos” el calculo anterior de “crecimiento”
5
Usamos cumsum() pero no va a funcionar: saldrá todo NA
6
Usamos cumsum() para calcular el crecimiento acumulado
7
Crecimiento acumulado: calculamos el incremento respecto a la 1ª observación
8
Al usar group_by() es una buena práctica hacer después un ungroup()
gt::gt(aa) %>% 
  gt::fmt_number(3:8, decimals = 2)
country year lifeExp crec_1 crec_2 crec_acu_1 crec_acu_2 crec_acu_3
Spain 1952 64.94 NA 0.00 NA 0.00 0.00
Spain 1957 66.66 1.72 1.72 NA 1.72 1.72
Spain 1962 69.69 3.03 3.03 NA 4.75 4.75
Spain 1967 71.44 1.75 1.75 NA 6.50 6.50
Spain 1972 73.06 1.62 1.62 NA 8.12 8.12
Spain 1977 74.39 1.33 1.33 NA 9.45 9.45
Spain 1982 76.30 1.91 1.91 NA 11.36 11.36
Spain 1987 76.90 0.60 0.60 NA 11.96 11.96
Spain 1992 77.57 0.67 0.67 NA 12.63 12.63
Spain 1997 78.77 1.20 1.20 NA 13.83 13.83
Spain 2002 79.78 1.01 1.01 NA 14.84 14.84
Spain 2007 80.94 1.16 1.16 NA 16.00 16.00

Calcular PORCENTAJES


  • Muchas veces interesa saber cuantas observaciones hay en cada grupo: eso se hace contando, que ya lo hemos visto


  • Una vez hemos contado, muchas veces interesa saber el porcentaje que representa cada grupo respecto al total

  • Para calcular esos porcentajes, hay que contar el total y dividirlo por el nº de observaciones en cada grupo. Veamos cómo hacerlo

calculando PORCENTAJES (con R à la tidyverse)

  • Calcular el % que representa cada continente en la población mundial:
#- Calcular % de población de cada continente 
aa <- gapminder %>% 
1  group_by(continent, year) %>%
2  summarise(pob_continent = sum(pop, na.rm = TRUE)) %>% ungroup() %>%
3  group_by(year) %>%
4  mutate(pob_mundo = sum(pob_continent),
5         pob_percent = pob_continent/pob_mundo * 100) %>%
  ungroup()
1
Agrupamos por continente y año
2
Calculo la población de cada continente para cada año
3
Vuelvo a agrupar, ahora solo por años
4
Calculo la población mundial para cada año
5
Finalmente calculamos el porcentaje


1bb <- aa %>% filter(year %in% c(1952, 2007))
1
Me quedo con el año inicial y final
gt::gt(head(bb, n = 15)) %>% 
  gt::fmt_number(pob_percent, decimals = 2)
continent year pob_continent pob_mundo pob_percent
Africa 1952 237640501 2406957150 9.87
Africa 2007 929539692 6251013179 14.87
Americas 1952 345152446 2406957150 14.34
Americas 2007 898871184 6251013179 14.38
Asia 1952 1395357351 2406957150 57.97
Asia 2007 3811953827 6251013179 60.98
Europe 1952 418120846 2406957150 17.37
Europe 2007 586098529 6251013179 9.38
Oceania 1952 10686006 2406957150 0.44
Oceania 2007 24549947 6251013179 0.39

Extensión: tabla con la importancia (en términos de población) de cada continente en el tiempo

- Antes hemos calculado el % que representa la población de cada continente, pero lo tenemos en formato largo

continent year pob_continent pob_mundo pob_percent
Africa 1952 237640501 2406957150 9.9
Africa 1957 264837738 2664404580 9.9
Africa 1962 296516865 2899782974 10.2
Americas 1952 345152446 2406957150 14.3
Americas 1957 386953916 2664404580 14.5

Ahora quiero hacer la tabla presentable: he de pasarla a formato ancho

bb <- aa %>% 
  select(continent, year, pob_mundo, pob_percent) %>%
  tidyr::pivot_wider(names_from = continent, 
                     values_from = pob_percent) 
gt::gt(bb) %>% 
  gt::fmt_number(2, sep_mark = ".", decimals = 0) %>% 
  gt::fmt_number(3:7, decimals = 1)
year pob_mundo Africa Americas Asia Europe Oceania
1952 2.406.957.150 9.9 14.3 58.0 17.4 0.4
1957 2.664.404.580 9.9 14.5 58.7 16.4 0.4
1962 2.899.782.974 10.2 14.9 58.5 15.9 0.5
1967 3.217.478.384 10.4 14.9 59.2 15.0 0.5
1972 3.576.977.158 10.6 14.8 60.1 14.0 0.5
1977 3.930.045.807 11.0 14.7 60.7 13.2 0.4
1982 4.289.436.840 11.6 14.7 60.9 12.4 0.4
1987 4.691.477.418 12.3 14.6 61.2 11.6 0.4
1992 5.110.710.260 12.9 14.5 61.3 10.9 0.4
1997 5.515.204.472 13.5 14.4 61.3 10.3 0.4
2002 5.886.977.579 14.2 14.4 61.2 9.8 0.4
2007 6.251.013.179 14.9 14.4 61.0 9.4 0.4

Calcular RANKINGS


  • En CC.SS interesa saber el ranking que ocupa cada individuo/país/empresa/ …

calculando RANKINGs

  • Calcular el ranking de España en cuanto a Esperanza de vida
aa <- gapminder %>% 
1  select(country, year, lifeExp) %>%
2  group_by(year) %>%
3    mutate(rank_1 = row_number(desc(lifeExp))) %>%
    mutate(rank_2 = min_rank(desc(lifeExp)) ) %>% 
    #- también puedo calcular el ranking a mano
4    arrange(desc(lifeExp)) %>%
    mutate(rank_mio = 1:n())  %>%
  ungroup() 
1
Selecciono las variables relevantes
2
Agrupamos por año ya que queremos calcular el ranking cada año
3
Podemos usar distintos métodos para calcular el ranking, siempre en función del valor de lifeExp de mayor a menor
4
También puedo calcular el ranking “a mano”. Para ello, antes, he de ordenar las observaciones por desc(lifeExp)
aa %>% 
  filter(country == "Spain") %>% 
  gt::gt() %>% 
  gt::fmt_number(3:5, decimals = 0)
country year lifeExp rank_1 rank_2 rank_mio
Spain 2007 81 6 6 6
Spain 2002 80 8 8 8
Spain 1997 79 8 8 8
Spain 1992 78 7 7 7
Spain 1987 77 5 5 5
Spain 1982 76 4 4 4
Spain 1977 74 8 8 8
Spain 1972 73 8 8 8
Spain 1967 71 10 10 10
Spain 1962 70 18 18 18
Spain 1957 67 26 26 26
Spain 1952 65 24 24 24

2 funciones muy útiles: ifelse() y case_when()


  • ifelse(): ejecuta “algo” de manera condicional

  • case_when(): es una generalización de ifelse()


  • Sí, no parece muy sencillo, pero con ejemplos se entiende mucho mejor

ifelse(): ejecuta “algo” de manera condicional

veamos algunos ejemplos

aa <- gapminder %>% 
  select(-pop) %>% 
  mutate(X1 = ifelse(lifeExp > 70, "longevo", "no longevo")) %>% 
  mutate(X2 = ifelse(gdpPercap > 10000, "rico", "pobre")) %>% 
  mutate(X3 = ifelse(lifeExp > 70 & gdpPercap > 10000, 
                     "longevo y rico", 
                     "no longevo y/o pobre")) %>% 
  mutate(X4 = ifelse(continent == "Europe", "europeo", "no europeo")) 


el resultado es:

aa %>% filter(country %in% c("Spain", "Angola")) %>% 
  filter(year %in% c(1952, 2007)) %>% 
  gt::gt() %>% 
  gt::opt_stylize(style = 3) %>% 
  gt::cols_align(align = "center")
country continent year lifeExp gdpPercap X1 X2 X3 X4
Angola Africa 1952 30.015 3520.610 no longevo pobre no longevo y/o pobre no europeo
Angola Africa 2007 42.731 4797.231 no longevo pobre no longevo y/o pobre no europeo
Spain Europe 1952 64.940 3834.035 no longevo pobre no longevo y/o pobre europeo
Spain Europe 2007 80.941 28821.064 longevo rico longevo y rico europeo

case_when(): es una generalización de ifelse()

A ver si entiendes este ejemplo:

aa <- gapminder %>%
  group_by(continent, year)  %>%
  mutate(media_lifeExp = mean(lifeExp)) %>% 
  mutate(media_gdpPercap = mean(gdpPercap)) %>% 
  mutate(GOOD_or_BAD = case_when( 
    lifeExp > mean(lifeExp) & gdpPercap > mean(gdpPercap)  ~ "good",
    lifeExp < mean(lifeExp) & gdpPercap < mean(gdpPercap)  ~ "bad" ,
    lifeExp < mean(lifeExp) | gdpPercap < mean(gdpPercap)  ~ "medium",
    .default = "otros casos"  ) )

El resultado es:

aa %>% ungroup() %>% filter(country == "Spain") %>% select(-pop) %>%
  gt::gt() %>% 
  gt::fmt_number(4:7, sep_mark = ".",   dec_mark = ",", decimals = 2) %>% 
  gt::opt_stylize(style = 2) %>% 
  gt::cols_align(align = "center")
country continent year lifeExp gdpPercap media_lifeExp media_gdpPercap GOOD_or_BAD
Spain Europe 1952 64,94 3.834,03 64,41 5.661,06 medium
Spain Europe 1957 66,66 4.564,80 66,70 6.963,01 bad
Spain Europe 1962 69,69 5.693,84 68,54 8.365,49 medium
Spain Europe 1967 71,44 7.993,51 69,74 10.143,82 medium
Spain Europe 1972 73,06 10.638,75 70,78 12.479,58 medium
Spain Europe 1977 74,39 13.236,92 71,94 14.283,98 medium
Spain Europe 1982 76,30 13.926,17 72,81 15.617,90 medium
Spain Europe 1987 76,90 15.764,98 73,64 17.214,31 medium
Spain Europe 1992 77,57 18.603,06 74,44 17.061,57 good
Spain Europe 1997 78,77 20.445,30 75,51 19.076,78 good
Spain Europe 2002 79,78 24.835,47 76,70 21.711,73 good
Spain Europe 2007 80,94 28.821,06 77,65 25.054,48 good

COMBINANDO tablas (joining df’s)


Hasta ahora hemos trabajado con un único df, pero …

… muchas veces tenemos que trabajar con datos que están en varias tablas


  • así que, a veces tendremos que juntar o fusionar tablas

dos casos ideales (sencillos de unir): bind_cols() y bind_rows()


A) Si los 2 dfs tienen exactamente las mismas filas o unidades de análisis (y además en el mismo orden)

Solo habría que juntar en una misma tabla las columnas de df1 y de df2

Esto lo podemos hacer con bind_cols() (o con cbind() de R-base)

df_1 <- iris[ , 1:2]  ; df_2 <- iris[ , 3:5]

df_1 <- iris %>% select(1:2)  ; df_2 <- iris %>% select(3:5) 

df_3 <- bind_cols(df_1, df_2)

identical(iris, df_3)


B) Si los 2 dfs tienen exactamente las mismas columnas (y además en el mismo orden)

Solo habría que juntar en una misma tabla las filas de los dos df’s

Esto lo podemos hacer con bind_rows() (o con rbind() de R-base)

df_1 <- iris[1:75, ]  ; df_2 <- iris[76:150, ]

df_1 <- iris %>% slice(1:75)  ; df_2 <- iris %>% slice(76:150) 

df_3 <- bind_rows(df_1, df_2)

identical(iris, df_3)

joining df’s

  • Hay diversos tipos de uniones de tablas: un buen recurso para estos temas es el capítulo dedicado a JOINS en R4DS2ed

  • Las uniones más comunes son las “mutating joins”, que añaden columnas de una tabla a otra. Lo vemos:


mutating joins (juntando df1 con df2)

  • Las mutating joins lo que hacen es añadir las variables de df2 a df1
  • Hay 3/4 tipos de mutating joins. Todas añaden las columnas de df2 al df1; PERO …


  • se diferencian en las filas que se seleccionan

  • Las filas que se seleccionan dependen del criterio para hacer el match. Lo vemos:

3/4 tipos de mutating joins

Recuerda que todas ellas añaden columnas (las columnas de df1 a df2) pero que se diferencian en las filas que se seleccionan

  • inner_join(df1,df2): retorna las filas de df1 que también existen en df2
  • left_join(df1,df2): retorna TODAS las filas de df1
  • full_join(df1,df2): retorna TODAS las filas de df1 y de df2; (osea, retorna TODAS las filas y TODAS las columnas de las 2 tablas)

mutating joins: un ejemplo

  • En el ejemplo usaremos estos 2 df’s:
df1 <- tibble(id = 1:3, x = paste0("x", 1:3))
df2 <- tibble(id = 1:4, y = paste0("y", 1:4)) %>% slice(-3)
df1
id x
1 x1
2 x2
3 x3
df2
id y
1 y1
2 y2
4 y4

mutating joins: un ejemplo


df_inner <- inner_join(df1, df2)             #- inner_join() only includes observations that match in df1 and df2

df_full_join <- full_join(df1, df2)             #- full_join() includes all observations from df1 and df2

df_left_join <- left_join(df1, df2)            #- left_join()  includes all observations in df1.