library(dplyr)

Preparación de la Base de datos

Para empezar, diseñaremos una pequeña base de datos en la que podemos aplicar distintas técnicas de manipulación.

clase <- c(rep("A", 4), rep("B", 4), rep("C", 4))
tipo <- c(rep("uno", 6), rep("dos", 6))
valor <- c(20,31,24,44,67,70,95,84,52,43,54,61)
data <- data.frame(clase, tipo, valor)
data
##    clase tipo valor
## 1      A  uno    20
## 2      A  uno    31
## 3      A  uno    24
## 4      A  uno    44
## 5      B  uno    67
## 6      B  uno    70
## 7      B  dos    95
## 8      B  dos    84
## 9      C  dos    52
## 10     C  dos    43
## 11     C  dos    54
## 12     C  dos    61

Primero utilizaremos la librería dplyr la cual tiene la mayoría de las herramientas más utilizadas en la manipulación de dataframes, una de las principales características de esta librería es el uso un elemento para concatenar ordenes %>% el cual es sumamente útil ya que nos ahorra muchos pasos al momento de la manipulación. Para empezar utilizaremos filter() que permite filtrar los datos según alguna condición o condiciones:

filter(data, clase == "A" & valor > 30)
##   clase tipo valor
## 1     A  uno    31
## 2     A  uno    44

Como se puede ver, podemos filtrar más de una condición agregando &. Otra forma de llegar al mismo resultado es mediante la siguiente sintaxis:

data %>% filter(clase == "A" & valor > 30)
##   clase tipo valor
## 1     A  uno    31
## 2     A  uno    44

Esta es la sintaxis que utilizaremos en lo subsecuente ya que es más útil porque permite concatenar ordenes después de aplicar transformaciones, selecciones o filtrados. Podríamos ahora solo querer seleccionar algunas variables del dataframe, para esto utilizamos select():

data %>% select(clase, valor)
##    clase valor
## 1      A    20
## 2      A    31
## 3      A    24
## 4      A    44
## 5      B    67
## 6      B    70
## 7      B    95
## 8      B    84
## 9      C    52
## 10     C    43
## 11     C    54
## 12     C    61

Podríamos ahora concatenar esta orden con un filtrado, por ejemplo, solo para valores mayores a 50:

data %>% select(clase, valor) %>% filter(valor > 50)
##   clase valor
## 1     B    67
## 2     B    70
## 3     B    95
## 4     B    84
## 5     C    52
## 6     C    54
## 7     C    61

Si nos interesa un filtrado, no sobre características sino sobre un grupo de filas utilizaremos slice():

data %>% slice(2:5)
##   clase tipo valor
## 1     A  uno    31
## 2     A  uno    24
## 3     A  uno    44
## 4     B  uno    67

Podemos obtener muestras aleatorias de los datos con la función sample_n():

data %>%sample_n(5, replace = FALSE)
##   clase tipo valor
## 1     A  uno    44
## 2     C  dos    61
## 3     C  dos    52
## 4     A  uno    31
## 5     A  uno    24

En ocasiones nos interesa modificar la base de tal manera que no tengamos los valores originales, sino sumas, medias o alguna operación respecto a un factor en particular. Para nuestro ejemplo podría estar interesado en saber el promedio de cada valor por clase. Esto se logra con group_by() que nos dice cual es el factor a agrupar y summarise() que nos permite crear una variable nueva resultado de aplicar la función al grupo.

data %>% group_by(clase) %>% summarise(media  = mean(valor))
## # A tibble: 3 x 2
##   clase media
##   <fct> <dbl>
## 1 A      29.8
## 2 B      79  
## 3 C      52.5

Para ordenar la base de manera ascendente o descendente utilizamos arrange():

#ascendente
data %>% arrange(valor)
##    clase tipo valor
## 1      A  uno    20
## 2      A  uno    24
## 3      A  uno    31
## 4      C  dos    43
## 5      A  uno    44
## 6      C  dos    52
## 7      C  dos    54
## 8      C  dos    61
## 9      B  uno    67
## 10     B  uno    70
## 11     B  dos    84
## 12     B  dos    95
#descendente
data %>% arrange(desc(valor)) %>% head()
##   clase tipo valor
## 1     B  dos    95
## 2     B  dos    84
## 3     B  uno    70
## 4     B  uno    67
## 5     C  dos    61
## 6     C  dos    54

Para agregar una nueva fila a la base de datos podemos utilizar add_row():

data %>% add_row(clase = "D", tipo = "tres", valor = 100)
##    clase tipo valor
## 1      A  uno    20
## 2      A  uno    31
## 3      A  uno    24
## 4      A  uno    44
## 5      B  uno    67
## 6      B  uno    70
## 7      B  dos    95
## 8      B  dos    84
## 9      C  dos    52
## 10     C  dos    43
## 11     C  dos    54
## 12     C  dos    61
## 13     D tres   100

Otra característica importante es el conteo, podríamos estar interesados, dado un conjunto de clases cual es su frecuencia absoluta, para esto utilizaremos count() el cual genera una variable que contiene dichas frecuencias.

data %>% count(tipo)
## # A tibble: 2 x 2
##   tipo      n
##   <fct> <int>
## 1 dos       6
## 2 uno       6

En caso de tener NA dentro del dataframe y estemos interesados en omitir dichas filas podríamos omitirtas concatenando na.omit(): para esto agregaremos algunas filas:

dataNA<-data %>% add_row(clase = NA , tipo = "tres", valor = 100)
dataNA
##    clase tipo valor
## 1      A  uno    20
## 2      A  uno    31
## 3      A  uno    24
## 4      A  uno    44
## 5      B  uno    67
## 6      B  uno    70
## 7      B  dos    95
## 8      B  dos    84
## 9      C  dos    52
## 10     C  dos    43
## 11     C  dos    54
## 12     C  dos    61
## 13  <NA> tres   100

ahora para omitir los NA utilizamos el na.omit().

dataNA %>% na.omit()
##    clase tipo valor
## 1      A  uno    20
## 2      A  uno    31
## 3      A  uno    24
## 4      A  uno    44
## 5      B  uno    67
## 6      B  uno    70
## 7      B  dos    95
## 8      B  dos    84
## 9      C  dos    52
## 10     C  dos    43
## 11     C  dos    54
## 12     C  dos    61

Aunque es común que para la creación de variables solo se utiliza mutate() así como sus derivaciones, la realidad es que al crear una variable nueva debemos utilizar lo ya aprendido hasta ahora.

Primero realizamos una variable sencilla, crearemos el logaritmo de la variable valor y su función 1 / valor, estos valores nos interesa guardarlos en una nueva base de datos:

data1<- data %>% mutate(logaritmo = log(valor), inverso = 1/valor)
data1
##    clase tipo valor logaritmo    inverso
## 1      A  uno    20  2.995732 0.05000000
## 2      A  uno    31  3.433987 0.03225806
## 3      A  uno    24  3.178054 0.04166667
## 4      A  uno    44  3.784190 0.02272727
## 5      B  uno    67  4.204693 0.01492537
## 6      B  uno    70  4.248495 0.01428571
## 7      B  dos    95  4.553877 0.01052632
## 8      B  dos    84  4.430817 0.01190476
## 9      C  dos    52  3.951244 0.01923077
## 10     C  dos    43  3.761200 0.02325581
## 11     C  dos    54  3.988984 0.01851852
## 12     C  dos    61  4.110874 0.01639344

Podemos utilizar ifelse() para crear variables según ciertas condiciones:

data1<-data1 %>% mutate(categoría = ifelse(logaritmo > 4, "Mayor", "Menor"))

Podemos utilizar varios ifelse()para agregar varias categorías dentro de la variable, para esto utilizaremos la función de pertenencia %in% en el caso que los datos sean contables:

data %>% mutate(categoría = ifelse(valor %in% 0:30, "0-30",
                                      ifelse(valor %in% 31:60, "31-60",
                                             ifelse(valor %in% 61:90, "61-90", "más de 90" ))))
##    clase tipo valor categoría
## 1      A  uno    20      0-30
## 2      A  uno    31     31-60
## 3      A  uno    24      0-30
## 4      A  uno    44     31-60
## 5      B  uno    67     61-90
## 6      B  uno    70     61-90
## 7      B  dos    95 más de 90
## 8      B  dos    84     61-90
## 9      C  dos    52     31-60
## 10     C  dos    43     31-60
## 11     C  dos    54     31-60
## 12     C  dos    61     61-90

Podemos tambien renombrar las variables con la función rename():

data %>% rename(altura = valor)
##    clase tipo altura
## 1      A  uno     20
## 2      A  uno     31
## 3      A  uno     24
## 4      A  uno     44
## 5      B  uno     67
## 6      B  uno     70
## 7      B  dos     95
## 8      B  dos     84
## 9      C  dos     52
## 10     C  dos     43
## 11     C  dos     54
## 12     C  dos     61

Formato de tiempo

Supongamos que tenemos la siguiente fecha en nuestro dataframe 2020-04-11 podemos ver que el formato no es un dato temporal preguntando con str():

str("2020-04-11")
##  chr "2020-04-11"

Como vemos es una variable tipo caracter. Para darle formato podemos guiarnos con la siguiente tabla:

Formato Implementación
%d Día (número)
%a Día (tres letras)
%A Día (nombre completo)
%m mes (número)
%b mes (nombre abreviado)
%B mes (nombre completo)
%y año (dos dígitos)
%Y año (cuatro dígitos)

Supongamos que tenemos los siguientes datos de inicio y fin de algún evento.

inicio <- c("2020-01-06","2020-02-06","2020-01-06","2020-04-06",
            "2020-05-06","2020-03-06","2020-02-06","2020-02-06",
            "2020-01-06","2020-01-06","2020-02-06","2020-03-06")
fin    <- c("20-05-jul","20-03-jul","20-06-jul","20-07-jul",
            "20-09-jul","20-07-jul","20-04-jul","20-07-jul",
            "20-05-jul","20-03-jul","20-03-jul","20-06-jul")

Para ver el formato de las nuevas variables usamos nuevamente str():

str(inicio)
##  chr [1:12] "2020-01-06" "2020-02-06" "2020-01-06" "2020-04-06" ...
str(fin)
##  chr [1:12] "20-05-jul" "20-03-jul" "20-06-jul" "20-07-jul" ...

Ambas son de tipo caracter, ahora demos el formato de fecha con as.Date():

inicio <- as.Date(inicio, format = "%Y-%d-%m")
fin    <- as.Date(fin, format = "%y-%d-%b")
str(inicio)
##  Date[1:12], format: "2020-06-01" "2020-06-02" "2020-06-01" "2020-06-04" "2020-06-05" ...
str(fin)
##  Date[1:12], format: "2020-07-05" "2020-07-03" "2020-07-06" "2020-07-07" "2020-07-09" ...

Ahora ambas son fechas. Podríamos crear una nueva variable en nuestro dataframe por ejemplo, los días que transcurrieron entre la fecha de inicio y fin.

data$inicio <- inicio
data$fin <- fin
data %>%  mutate(dias = as.numeric(fin - inicio))
##    clase tipo valor     inicio        fin dias
## 1      A  uno    20 2020-06-01 2020-07-05   34
## 2      A  uno    31 2020-06-02 2020-07-03   31
## 3      A  uno    24 2020-06-01 2020-07-06   35
## 4      A  uno    44 2020-06-04 2020-07-07   33
## 5      B  uno    67 2020-06-05 2020-07-09   34
## 6      B  uno    70 2020-06-03 2020-07-07   34
## 7      B  dos    95 2020-06-02 2020-07-04   32
## 8      B  dos    84 2020-06-02 2020-07-07   35
## 9      C  dos    52 2020-06-01 2020-07-05   34
## 10     C  dos    43 2020-06-01 2020-07-03   32
## 11     C  dos    54 2020-06-02 2020-07-03   31
## 12     C  dos    61 2020-06-03 2020-07-06   33

Podríamos generar una variable que sea una semana después de la fecha de inicio:

data %>% mutate(inicio2 = inicio + 7 )
##    clase tipo valor     inicio        fin    inicio2
## 1      A  uno    20 2020-06-01 2020-07-05 2020-06-08
## 2      A  uno    31 2020-06-02 2020-07-03 2020-06-09
## 3      A  uno    24 2020-06-01 2020-07-06 2020-06-08
## 4      A  uno    44 2020-06-04 2020-07-07 2020-06-11
## 5      B  uno    67 2020-06-05 2020-07-09 2020-06-12
## 6      B  uno    70 2020-06-03 2020-07-07 2020-06-10
## 7      B  dos    95 2020-06-02 2020-07-04 2020-06-09
## 8      B  dos    84 2020-06-02 2020-07-07 2020-06-09
## 9      C  dos    52 2020-06-01 2020-07-05 2020-06-08
## 10     C  dos    43 2020-06-01 2020-07-03 2020-06-08
## 11     C  dos    54 2020-06-02 2020-07-03 2020-06-09
## 12     C  dos    61 2020-06-03 2020-07-06 2020-06-10

En general es muy útil tener las fechas con su formato para crear diversas variables donde tengamos que manipular la variable tiempo.

Agregando gráficos.

Podríamos concatenar nuestra dataframe modificada para hacer gráficos sin necesidad de tenerla almacenada, esto nos da un ahorro de memoria. Usaremos el código anterior de ifelse() :

library(ggplot2)

data %>% mutate(categoría = ifelse(valor %in% 0:30, "0-30",
                            ifelse(valor %in% 31:60, "31-60",
                            ifelse(valor %in% 61:90, "61-90", "más de 90")))) %>% 
  ggplot(aes(x = categoría, y = valor,  color = clase)) +
  geom_point() +
  labs(title = "Ejemplo de Gráfico")

Otro punto importante al manipular dataframes es lograr colocar los rownames extraídos del alguna columna de nuestro dataframe, crearemos para ilustrar esto otra variable:

data$pais <- c("MEX", "USA", "ARG", "ESP", "AUS", "HOL", "FRA", "JAP", "CHN", "RUS", "CAN", "COL")
data
##    clase tipo valor     inicio        fin pais
## 1      A  uno    20 2020-06-01 2020-07-05  MEX
## 2      A  uno    31 2020-06-02 2020-07-03  USA
## 3      A  uno    24 2020-06-01 2020-07-06  ARG
## 4      A  uno    44 2020-06-04 2020-07-07  ESP
## 5      B  uno    67 2020-06-05 2020-07-09  AUS
## 6      B  uno    70 2020-06-03 2020-07-07  HOL
## 7      B  dos    95 2020-06-02 2020-07-04  FRA
## 8      B  dos    84 2020-06-02 2020-07-07  JAP
## 9      C  dos    52 2020-06-01 2020-07-05  CHN
## 10     C  dos    43 2020-06-01 2020-07-03  RUS
## 11     C  dos    54 2020-06-02 2020-07-03  CAN
## 12     C  dos    61 2020-06-03 2020-07-06  COL

Vamos a colocar estos nombres de países como un rowname de nuestro dataframe:

rownames(data) <- data$pais
data
##     clase tipo valor     inicio        fin pais
## MEX     A  uno    20 2020-06-01 2020-07-05  MEX
## USA     A  uno    31 2020-06-02 2020-07-03  USA
## ARG     A  uno    24 2020-06-01 2020-07-06  ARG
## ESP     A  uno    44 2020-06-04 2020-07-07  ESP
## AUS     B  uno    67 2020-06-05 2020-07-09  AUS
## HOL     B  uno    70 2020-06-03 2020-07-07  HOL
## FRA     B  dos    95 2020-06-02 2020-07-04  FRA
## JAP     B  dos    84 2020-06-02 2020-07-07  JAP
## CHN     C  dos    52 2020-06-01 2020-07-05  CHN
## RUS     C  dos    43 2020-06-01 2020-07-03  RUS
## CAN     C  dos    54 2020-06-02 2020-07-03  CAN
## COL     C  dos    61 2020-06-03 2020-07-06  COL

Otra ventaja de utilizar dplyr es el uso de inner_join() y full_join() de manera similar a la forma en como se hacen consultas en sql. para esto crearemos una segunda base de datos:

x <- c(2,4,8,16,32,64,128,64,32,8,4,2)
y <- c(3,6,23,14,16,23,17,37,42,34,25,12)
pais <- c("MEX", "USA", "BEL", "ESP", "AUS", "HOL", "FRA", "JAP", "CHN", "RUS", "CAN", "NOR")
data2<- data.frame(x,y,pais)
data2
##      x  y pais
## 1    2  3  MEX
## 2    4  6  USA
## 3    8 23  BEL
## 4   16 14  ESP
## 5   32 16  AUS
## 6   64 23  HOL
## 7  128 17  FRA
## 8   64 37  JAP
## 9   32 42  CHN
## 10   8 34  RUS
## 11   4 25  CAN
## 12   2 12  NOR

Ahora vamos a unir ambas bases, notemos que ambas cuentan con la variable país, esta será nuestra variable utilizada para enlazarlas:

full_join(data, data2, by = "pais")
## Warning: Column `pais` joining character vector and factor, coercing into
## character vector
##    clase tipo valor     inicio        fin pais   x  y
## 1      A  uno    20 2020-06-01 2020-07-05  MEX   2  3
## 2      A  uno    31 2020-06-02 2020-07-03  USA   4  6
## 3      A  uno    24 2020-06-01 2020-07-06  ARG  NA NA
## 4      A  uno    44 2020-06-04 2020-07-07  ESP  16 14
## 5      B  uno    67 2020-06-05 2020-07-09  AUS  32 16
## 6      B  uno    70 2020-06-03 2020-07-07  HOL  64 23
## 7      B  dos    95 2020-06-02 2020-07-04  FRA 128 17
## 8      B  dos    84 2020-06-02 2020-07-07  JAP  64 37
## 9      C  dos    52 2020-06-01 2020-07-05  CHN  32 42
## 10     C  dos    43 2020-06-01 2020-07-03  RUS   8 34
## 11     C  dos    54 2020-06-02 2020-07-03  CAN   4 25
## 12     C  dos    61 2020-06-03 2020-07-06  COL  NA NA
## 13  <NA> <NA>    NA       <NA>       <NA>  BEL   8 23
## 14  <NA> <NA>    NA       <NA>       <NA>  NOR   2 12

Al usar full_join() se unen integras ambas bases, como vemos hay dos variables que no coinciden en cada base por lo que nos genera NA. Para evitarlo utilizaremos ìnner_join():

data %>% inner_join(data2, by = "pais")
## Warning: Column `pais` joining character vector and factor, coercing into
## character vector
##    clase tipo valor     inicio        fin pais   x  y
## 1      A  uno    20 2020-06-01 2020-07-05  MEX   2  3
## 2      A  uno    31 2020-06-02 2020-07-03  USA   4  6
## 3      A  uno    44 2020-06-04 2020-07-07  ESP  16 14
## 4      B  uno    67 2020-06-05 2020-07-09  AUS  32 16
## 5      B  uno    70 2020-06-03 2020-07-07  HOL  64 23
## 6      B  dos    95 2020-06-02 2020-07-04  FRA 128 17
## 7      B  dos    84 2020-06-02 2020-07-07  JAP  64 37
## 8      C  dos    52 2020-06-01 2020-07-05  CHN  32 42
## 9      C  dos    43 2020-06-01 2020-07-03  RUS   8 34
## 10     C  dos    54 2020-06-02 2020-07-03  CAN   4 25

Podemos concatenar esto ahora con un gráfico:

data %>% inner_join(data2, by = "pais") %>% 
  ggplot(aes(x = x, y = y, color = clase)) +
  geom_point(aes(size = valor ), alpha = 0.5)+
  scale_size(range=c(.1,8))+
  labs(title = "Ejemplo de Gráfico")
## Warning: Column `pais` joining character vector and factor, coercing into
## character vector

Existen muchas más funciones de dplyr pero considero que estas son las más utilizadas. Ahora pasemos a un caso real. La web https://ourworldindata.org/coronavirus-data recopila información de todo el mundo sobre el estado actual de la pandemia de covid19, para esto importaremos la base de datos de su web:

library(readr)
covid19 <- read.csv(url("https://covid.ourworldindata.org/data/owid-covid-data.csv"))

La base contiene información diaria sobre 212 países del mundo durante el 2020. Estas notas se elaboraron el 6 de junio de 2020 por lo que aun no hemos visto el pico de la pandemia.

Podríamos estar interesado en conocer la incidencia de contagio, es decir, los casos totales por cada 100 mil habitantes pero solo nos interesa para los países que actualmente tiene más de 50 mil casos confirmados. Además solo nos interesa analizar los países que reportaron datos al 5 de junio de 2020 y a qué región pertenecen.

Primero aplicaremos un filtro para sacar los datos correspondientes al 05 de junio de 2020. Después solo seleccionaremos el total de casos confirmados, la población total, continente, país y su código.

covid19 %>% filter(date == "2020-06-05") %>% select(location, total_cases, population, iso_code, continent) %>% head()
##      location total_cases population iso_code     continent
## 1 Afghanistan       18054   38928341      AFG          Asia
## 2     Albania        1197    2877800      ALB        Europe
## 3     Algeria        9831   43851043      DZA        Africa
## 4     Andorra         852      77265      AND        Europe
## 5      Angola          86   32866268      AGO        Africa
## 6    Anguilla           3      15002      AIA North America

Ahora concatenaremos un filtro para tener solo los países con más de 50 mil casos confirmados y crearemos una nueva variable llamada incidencia que será el total de casos por cada 100 mil habitantes. Finalmente quitaremos World que muestra el total mundial:

covid19 %>% filter(date == "2020-06-05") %>% select(location, total_cases, population, iso_code, continent) %>% filter(total_cases >= 50000) %>%  
  mutate(incidencia = total_cases*100000/population) %>% filter(location!= "World") %>% 
  head()
##     location total_cases population iso_code     continent incidencia
## 1 Bangladesh       57563  164689383      BGD          Asia  34.952466
## 2    Belgium       58767   11589616      BEL        Europe 507.065980
## 3     Brazil      614941  212559409      BRA South America 289.303119
## 4     Canada       93715   37742157      CAN North America 248.303244
## 5      Chile      118292   19116209      CHL South America 618.804701
## 6      China       84171 1439323774      CHN          Asia   5.847955

Finalmente lo visualizaremos con un gráfico de barras:

library(hrbrthemes)

covid19 %>% filter(date == "2020-06-05") %>% select(location, total_cases, population, iso_code, continent) %>% filter(total_cases >= 50000) %>%  
  mutate(incidencia = total_cases*100000/population) %>% 
  filter(location!= "World") %>% 
  ggplot(aes(x = reorder(iso_code, + incidencia), y = incidencia, fill = continent)) +
  geom_bar(stat='identity')+
  theme_ipsum_rc()+
  coord_flip() +
  labs(title = "Incidencia de COVID19 en el mundo",
       subtitle = "Países con más de 50 mil casos confirmados",
       x = "",
       y = "Incidencia",
       caption = "Elaboración propia con datos de \n https://ourworldindata.org/coronavirus-data al 6 de junio de 2020")

Hagamos otro ejemplo. Podríamos estar interesados en conocer la relación entre la incidencia de covid19 con el PIB percápita de cada país y eso ponderado por el total de defunciones. Sin embargo queremos que contenga una categoría respecto a la densidad de población dividida en alta, media y baja. Primero seleccionamos las variables:

covid19 %>% filter(date == "2020-06-05") %>% select(iso_code, total_cases, population, population_density, gdp_per_capita, total_deaths) %>% na.omit() %>% head()
##   iso_code total_cases population population_density gdp_per_capita
## 1      AFG       18054   38928341             54.422       1803.987
## 2      ALB        1197    2877800            104.871      11803.431
## 3      DZA        9831   43851043             17.348      13913.839
## 5      AGO          86   32866268             23.890       5819.495
## 7      ATG          26      97928            231.845      21490.943
## 8      ARG       19255   45195777             16.177      18933.907
##   total_deaths
## 1          300
## 2           33
## 3          681
## 5            4
## 7            3
## 8          588

Ahora crearemos la variable categórica para la densidad de población, primero veamos sus cuartiles omitiendo los NA:

quantile(covid19$population_density, na.rm = TRUE)
##        0%       25%       50%       75%      100% 
##     0.137    41.285    93.105   227.322 19347.500

Tomaremos el primer cuartil como baja, el segundo como medio y el tercero como alta densidad.

covid19 %>% filter(date == "2020-06-05") %>% select(iso_code, total_cases, population, population_density, gdp_per_capita, total_deaths) %>% na.omit() %>% 
  mutate(incidencia = total_cases*100000/population) %>% 
  mutate(densidad = ifelse(population_density <= 41.285, "Baja",
                    ifelse(population_density <= 277.322, "Media","Alta"))) %>% 
  head()
##   iso_code total_cases population population_density gdp_per_capita
## 1      AFG       18054   38928341             54.422       1803.987
## 2      ALB        1197    2877800            104.871      11803.431
## 3      DZA        9831   43851043             17.348      13913.839
## 4      AGO          86   32866268             23.890       5819.495
## 5      ATG          26      97928            231.845      21490.943
## 6      ARG       19255   45195777             16.177      18933.907
##   total_deaths incidencia densidad
## 1          300 46.3775222    Media
## 2           33 41.5942734    Media
## 3          681 22.4190791     Baja
## 4            4  0.2616665     Baja
## 5            3 26.5501185    Media
## 6          588 42.6035379     Baja

Realicemos ahora un gráfico de puntos:

options(scipen=999) #Quitar notación científica

covid19 %>% filter(date == "2020-06-05") %>% select(iso_code, total_cases, population, population_density, gdp_per_capita, total_deaths) %>% na.omit() %>% 
  mutate(incidencia = total_cases*100000/population) %>% 
  mutate(densidad = ifelse(population_density <= 41.285, "Baja",
                    ifelse(population_density <= 277.322, "Media","Alta"))) %>% 
  ggplot(aes(x = gdp_per_capita, y = incidencia, fill = densidad, color=densidad))+
  geom_point(aes(size = total_deaths), alpha = 0.5)+
  scale_size(range=c(.4, 10), name = "Total de defunciones")+
  theme_ipsum_rc()+
   labs(x = "GDP percápita", 
       y = "Incidencia", 
       title = "Comparativa entre Incidencia y GDP percápita",
       subtitle = "Clasificado por densidad poblacional y total de muertes",
       caption = "Elaboración propia con datos de https://ourworldindata.org/.
                  Actualización al 5 de junio  de 2020")