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

Módulo práctico de ITA
(Grupo M)

Data munging: the tidyverse way



Aprendimos a cargar datos y a hacerlos TIDY. También vimos la “teoría” del tidyverse. Ahora nos centraremos en usar el tidyverse para transformar nuestros datos, para obtener resultados. Para ello usaremos ejemplos

CONTAR (observaciones)


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

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

… vamos a CONTAR

ya vimos que se puede contar con summarise() y n(); pero hay otra forma: count()

1. el nº de observaciones (o filas) de todo el df

aa <- gapminder %>% count()

count() devuelve una fila

gt::gt(aa)
n
1704

2. el nº de observaciones de cada continente

aa <- gapminder %>% count(continent)

… y ahora una fila por continente

gt::gt(aa)
continent n
Africa 624
Americas 300
Asia 396
Europe 360
Oceania 24

… 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)

con group_by() + summarise()

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

 

con count(): hace exactamente lo mismo

bb <- gapminder %>% count(continent, year)

 

Hay 60 grupos (5 continentes x 12 periodos), así que las dos devuelven 60 filas: una por grupo. Aquí vemos las 12 primeras

gt::gt(aa)
continent year n
Africa 1952 52
Africa 1957 52
Africa 1962 52
Africa 1967 52
Africa 1972 52
Africa 1977 52
Africa 1982 52
Africa 1987 52
Africa 1992 52
Africa 1997 52
Africa 2002 52
Africa 2007 52
gt::gt(bb)
continent year n
Africa 1952 52
Africa 1957 52
Africa 1962 52
Africa 1967 52
Africa 1972 52
Africa 1977 52
Africa 1982 52
Africa 1987 52
Africa 1992 52
Africa 1997 52
Africa 2002 52
Africa 2007 52

observaciones DISTINTAS


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

… ver y contar observaciones DISTINTAS: distinct() y n_distinct()

  • 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
  • ¿cuántos 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

obtener/calcular estadísticos


  • Ya os explicarán en Estadística y Econometría qué es un estadístico, cuáles 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 ESTADÍSTICOS: máximo, mínimo, media, ……

  • obtener el máximo, mínimo y media de “lifeExp” para cada 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
  • na.rm = TRUE: si la variable tiene valores perdidos (NA), los quita antes de calcular; si no lo pones, el resultado sería NA. En gapminder no hay NA, así que en las siguientes slides no lo pondremos

ESTADÍSTICOS 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),
            minimo = min(lifeExp), 
            media = mean(lifeExp) ) %>% 
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
Al 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 media
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(media = mean(lifeExp),
            media_pond = weighted.mean(lifeExp, w = pop)) %>%    
  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 media media_pond
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

calculando CRECIMIENTOS

  • Muchas veces interesa saber cuánto crecen las variables: el PIB, el desempleo … o la esperanza de vida
  • calcular el crecimiento de la esperanza de vida en España: de un periodo a otro y ACUMULADO
aa <- gapminder %>% 
  select(country, year, lifeExp) %>%   
1  group_by(country) %>%
2  arrange(year) %>%
3  mutate(crec = lifeExp - lag(lifeExp)) %>%
4  mutate(crec_acu = lifeExp - first(lifeExp)) %>%
5  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
Crecimiento acumulado: calculamos el incremento respecto a la 1ª observación
5
Al usar group_by() es una buena práctica hacer después un ungroup()
gt::gt(aa) %>% 
  gt::fmt_number(3:5, decimals = 2)
country year lifeExp crec crec_acu
Spain 1952 64.94 NA 0.00
Spain 1957 66.66 1.72 1.72
Spain 1962 69.69 3.03 4.75
Spain 1967 71.44 1.75 6.50
Spain 1972 73.06 1.62 8.12
Spain 1977 74.39 1.33 9.45
Spain 1982 76.30 1.91 11.36
Spain 1987 76.90 0.60 11.96
Spain 1992 77.57 0.67 12.63
Spain 1997 78.77 1.20 13.83
Spain 2002 79.78 1.01 14.84
Spain 2007 80.94 1.16 16.00

Calcular PORCENTAJES


  • Muchas veces no basta con saber cuánto vale algo en cada grupo: interesa saber el porcentaje que representa cada grupo respecto al total. Por ejemplo, ¿qué % de la población mundial vive en Asia?
  • Se calcula como siempre: el valor de cada grupo dividido por el total (y multiplicado por 100). Veamos cómo hacerlo à la tidyverse

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)) %>%
3  ungroup() %>%
4  group_by(year) %>%
5  mutate(pob_mundo = sum(pob_continent),
6         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
Desagrupamos
4
Vuelvo a agrupar, ahora solo por años
5
Calculo la población mundial para cada año
6
Finalmente calculamos el porcentaje


1bb <- aa %>% filter(year %in% c(1952, 2007))
1
Me quedo con el año inicial y final (para poder visualizar mejor los resultados)
gt::gt(bb) %>% 
  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 (en aa) el % que representa la población de cada continente a lo largo del tiempo, pero lo tenemos en formato largo

continent year pob_continent pob_mundo pob_percent
Africa 1952 237640501 2406957150 9.87
Africa 1957 264837738 2664404580 9.94
Americas 1952 345152446 2406957150 14.34

Los datos de aa no son presentables en una tabla porque tiene 60 filas!!!!

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) 
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

calculando RANKINGs

  • En CC.SS interesa saber el ranking que ocupa cada individuo/país/empresa/ …
  • 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(ranking = min_rank(desc(lifeExp))) %>%
  ungroup() 
1
Selecciono las variables relevantes
2
Agrupamos por año ya que queremos calcular el ranking cada año
3
Calculamos el ranking en función del valor de lifeExp, de mayor a menor
aa %>% 
  filter(country == "Spain") %>% 
  gt::gt() %>% 
  gt::fmt_number(3, decimals = 1)
country year lifeExp ranking
Spain 1952 64.9 24
Spain 1957 66.7 26
Spain 1962 69.7 18
Spain 1967 71.4 10
Spain 1972 73.1 8
Spain 1977 74.4 8
Spain 1982 76.3 4
Spain 1987 76.9 5
Spain 1992 77.6 7
Spain 1997 78.8 8
Spain 2002 79.8 8
Spain 2007 80.9 6

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(continent == "Europe", "europeo", "no europeo")) 


el resultado es:

aa %>% filter(country %in% c("Spain", "Angola")) %>% 
  filter(year %in% c(1952, 2007))

country continent year lifeExp gdpPercap X1 X2 X3
Angola Africa 1952 30.015 3520.610 no longevo pobre no europeo
Angola Africa 2007 42.731 4797.231 no longevo pobre no europeo
Spain Europe 1952 64.940 3834.035 no longevo pobre europeo
Spain Europe 2007 80.941 28821.064 longevo rico europeo

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

Con ifelse() solo hay 2 casos (sí/no). Con case_when() podemos tener todos los casos que queramos. Por ejemplo, clasificamos la esperanza de vida en 3 tramos:

aa <- gapminder %>% 
  filter(year == 2007) %>% 
  select(country, lifeExp) %>% 
  mutate(vida = case_when(
    lifeExp < 50 ~ "baja",
    lifeExp < 70 ~ "media",
    .default = "alta"))
  • Las condiciones se miran por orden y la primera que se cumple es la que vale

  • Por ejemplo, con 65 años no se cumple la 1ª condición, pero sí la 2ª: “media”

  • .default: lo que se pone si no se cumple ninguna

El resultado (para 3 países):

aa %>% 
  filter(country %in% c("Angola", "India", "Spain"))

country lifeExp vida
Angola 42,7 baja
India 64,7 media
Spain 80,9 alta

Extensión: un ejemplo más complicado de case_when()

A ver si entiendes este ejemplo:

aa <- gapminder %>%
  group_by(continent, year)  %>%
  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)
country continent year lifeExp gdpPercap GOOD_or_BAD
Spain Europe 1952 64,94 3.834,03 medium
Spain Europe 1957 66,66 4.564,80 bad
Spain Europe 1962 69,69 5.693,84 medium
Spain Europe 1967 71,44 7.993,51 medium
Spain Europe 1972 73,06 10.638,75 medium
Spain Europe 1977 74,39 13.236,92 medium
Spain Europe 1982 76,30 13.926,17 medium
Spain Europe 1987 76,90 15.764,98 medium
Spain Europe 1992 77,57 18.603,06 good
Spain Europe 1997 78,77 20.445,30 good
Spain Europe 2002 79,78 24.835,47 good
Spain Europe 2007 80,94 28.821,06 good

Resumen


  • Lo que hemos aprendido a hacer con dplyr

Resumen: qué hemos aprendido a calcular

  • Contar observaciones: n() y count()

  • Ver y contar observaciones distintas: distinct() y n_distinct()

  • Calcular estadísticos: summarise() con max(), min(), mean() o weighted.mean()

  • Calcular crecimientos: lag() y first()

  • Calcular porcentajes: dividir el valor de cada grupo por el total

  • Calcular rankings: min_rank()

  • Crear variables según una condición: ifelse() y case_when()

casi siempre con la misma receta: group_by()     +     summarise() o mutate()