Carregando os pacotes

Muitos já devem estar familiarizados com a apresentação do historiador Hans Rosling sobre a evolução da expectativa de vida e do PIB per capita dos países em torno do mundo. Este post vai mostrar como usar o ggplot2 e o tidyverse para explorar estes dados. Pode-se acessar uma versão simplificada da base de dados pelo pacote gapminder.

### Tutorial Gapminder ###
library(tidyverse)
library(extrafont)
library(ggplot2)
library(gapminder)
library(kableExtra)
##########################
data(gapminder)
d <- gapminder

Análise exploratória

De início é sempre importante verificar se há problemas com os dados. Como estamos usando uma base que já foi tratada é de se esperar que tudo esteja em ordem. Tipicamente, queremos verificar quantas observações ausentes (NAs) existem; se as variáveis estão no formato correto (ex: variáveis de texto como factor, números como numeric, etc.). Neste caso, além destas checagens também vamos criar uma nova variável que é o log do PIB per capita.

# Checagens iniciais #
# Verifica se há valores ausentes
d %>%
  select(everything()) %>%
  summarise_all(funs(sum(is.na(.))))
## # A tibble: 1 x 6
##   country continent  year lifeExp   pop gdpPercap
##     <int>     <int> <int>   <int> <int>     <int>
## 1       0         0     0       0     0         0
# Informações gerais sobre os dados
str(d)
## Classes 'tbl_df', 'tbl' and 'data.frame':    1704 obs. of  6 variables:
##  $ country  : Factor w/ 142 levels "Afghanistan",..: 1 1 1 1 1 1 1 1 1 1 ...
##  $ continent: Factor w/ 5 levels "Africa","Americas",..: 3 3 3 3 3 3 3 3 3 3 ...
##  $ year     : int  1952 1957 1962 1967 1972 1977 1982 1987 1992 1997 ...
##  $ lifeExp  : num  28.8 30.3 32 34 36.1 ...
##  $ pop      : int  8425333 9240934 10267083 11537966 13079460 14880372 12881816 13867957 16317921 22227415 ...
##  $ gdpPercap: num  779 821 853 836 740 ...
# Nome das variáveis minúsculas
names(d) <- tolower(names(d))
# Tranformações #
# Computa o log do pib per capita
d <- d %>%
  mutate(lgdppc = log10(gdppercap))

Para manter o padrão das visualizações pode-se criar um tema personalizado. A maneira mais simples de fazer isto é a partir de um tema padrão do ggplot2 mas é possível começar do zero. Aqui, por simplicidade, começo com o tema bw e apenas mudo a posição da legenda e o tamanho e a fonte do texto que será plotado nos eixos e no título do gráfico. Além disso, como o nome dos eixos vai ser repetido muitas vezes defino uma lista com o nome mais comum deles.

# Tema customizado #
theme_vini <- theme_bw() +
  theme(text = element_text(family = "Tw Cen MT", size = 12, colour = "gray20"),
        plot.title = element_text(size = 16),
        legend.text = element_text(size = 12),
        legend.position = "bottom")
# Nomes que serão usados várias vezes para os eixos
nomes <- list(title = "Expectativa de vida e PIB per capita",
              x = "Log do PIB per capita (US$ 2010)",
              y = "Expectativa de vida ao nascer",
              fonte = "Fonte: Gapmineder (www.gapminder.org) e World Bank Open Data.")

Visualizando

Note que não temos dados para todos os anos do período. Os dados estão disponíveis de cinco em cinco anos começando em 1952 e terminando em 2007. Podemos começar com um gráfico de dispersão para ver a relação entre a “economia” (PIB per capita) e a “qualidade da saúde/vida” (expectativa de vida ao nascer) de um país. Apenas como exemplo incluo também uma linha de regressão quadrática no gráfico.

unique(d$year)
##  [1] 1952 1957 1962 1967 1972 1977 1982 1987 1992 1997 2002 2007
d %>%
  filter(year == 2007) %>%
  ggplot(aes(lgdppc, lifeexp)) +
  geom_point() +
  geom_smooth(method = "lm", formula = y ~ poly(x, 2), se = FALSE) +
  labs(title = paste(nomes$title, "(2007)"),
       caption = nomes$fonte,
       subtitle = "Relação entre expectativa de vida ao nascer e o logaritmo do PIB per capita (fit quadrático)",
       x = nomes$x,
       y = nomes$y) +
  theme_vini

Podemos nos valer de outras informações disponíveis na base para alterar atributos estéticos do gráfico. O tamanho de cada círculo pode refletir o tamanho da população daquele país; a cor do círculo, por sua vez, pode representar o continente daquele país. Por conveniência uso as cores pré-definidas do pacote gapminder. Além disso também podemos destacar o nome de alguns países usando o pacote ggrepel.

data(continent_colors)
library(ggrepel)
destaque <- c("Australia", "Brazil", "Chile", "India", "Nigeria",
              "Sudan", "Taiwan")
d %>%
  filter(year == 2007) %>%
  mutate(country = as.character(country)) %>%
  mutate(sel = ifelse(country %in% destaque, country, NA)) %>%
  ggplot(aes(lgdppc, lifeexp)) +
  geom_point(aes(size = pop, colour = continent), alpha = .75) +
  geom_smooth(method = "lm", formula = y ~ poly(x, 2), se = FALSE,
              color = "black") +
  geom_text_repel(aes(label = sel), family = "Tw Cen MT", force = 20,
                  nudge_y = c(-2, -1, .5, 4, .5, .5, -.5),
                  nudge_x = c(0, .5, 0, 0, 0, 0, 0),
                  size = 5) + 
  labs(title = paste(nomes$title, "(2007)"),
       caption = nomes$fonte,
       x = nomes$x,
       y = nomes$y) +
  scale_color_manual(values = continent_colors, name = "") +
  scale_size_continuous(range = c(1, 20)) +
  guides(size = FALSE) + 
  theme_vini

Tendências

O gráfico acima é um retrato do momento, mas pode ser interessante entender como estas variáveis se comportaram ao longo do tempo.

Expectativa de vida (média mundial)

d %>%
  group_by(year) %>%
  summarise(media = mean(lifeexp)) %>%
  ggplot(aes(year, media, group = 1)) +
  geom_line() +
  geom_point() +
  labs(title = paste(nomes$title, "(média mundial)"),
       caption = nomes$fonte,
       x = nomes$x,
       y = nomes$y) +
  theme_vini

Expectativa de vida (todos os países)

Podemos desagregar a análise acima por país. É claro que fica difícil discernir um país específico, mas pode-se ver uma tendência geral de crescimento, ainda que haja alguns outliers. A maior parte das quedas significativas pode ser relacionada com alguma guerra. O país cuja expectativa de vida cai bruscamente no começo dos anos 90, por exemplo, é a Ruanda, que vivia uma guerra civil nesta época.

library(RColorBrewer)
ggplot(d, aes(year, lifeexp, group = country, colour = continent)) +
  geom_line() +
  labs(title = "Expecativa de vida (1952/2007)",
       caption = nomes$fonte,
       x = "",
       y = nomes$y) +
  scale_color_brewer(palette = 6, type = "qual", name = "") +
  scale_y_continuous(breaks = seq(from = 30, to = 80, by = 10)) +
  theme_vini

Se nos atermos somente ao nível de continente a visualização fica mais simples.

d %>%
  group_by(year, continent) %>%
  summarise(expec_media = mean(lifeexp)) %>%
  ggplot(aes(year, expec_media, group = continent, colour = continent)) +
  geom_line() +
  geom_point() +
  labs(title = "Expecativa de vida média (1952/2007)",
       caption = nomes$fonte,
       x = "",
       y = nomes$y) +
  scale_color_brewer(palette = 6, type = "qual", name = "") +
  theme_vini

Podemos fazer o mesmo para o log do PIB per capita. Aqui o gráfico é feito usando o log do PIB per capita, mas no eixo indico o valor equivalente em dólares para facilitar a interpretação.

eixo_y <- seq(from = 3, to = 4.5, by = .5)
d %>%
  group_by(year, continent) %>%
  summarise(expec_media = mean(lgdppc)) %>%
  ggplot(aes(year, expec_media, group = continent, colour = continent)) +
  geom_line() +
  geom_point() +
  labs(title = "PIB per capita médio (1952/2007)",
       caption = nomes$fonte,
       subtitle = "Escala computada em log (base 10) mas o valor impresso no eixo em US$.",
       x = "",
       y = nomes$x) +
  scale_color_brewer(palette = 6, type = "qual", name = "") +
  scale_y_continuous(breaks = eixo_y,
                labels = format(round(10^eixo_y, 0), big.mark = ".")) +
  theme_vini

Analisando os dados

Podemos encontrar fatos interessantes simplesmente agregando e reorganizando os dados. No gráfico anterior vimos que o continente com maior PIB per capita médio é a Oceania. Curiosamente, a base inclui somente dois países na Oceania: Austrália e Nove Zelândia.

# Note que na Oceania os dados só incluem Autrália e Nova Zelândia
d %>%
  filter(continent == "Oceania") %>%
  arrange(desc(lifeexp), desc(gdppercap)) %>%
  head(10)
## # A tibble: 10 x 7
##    country     continent  year lifeexp      pop gdppercap lgdppc
##    <fct>       <fct>     <int>   <dbl>    <int>     <dbl>  <dbl>
##  1 Australia   Oceania    2007    81.2 20434176    34435.   4.54
##  2 Australia   Oceania    2002    80.4 19546792    30688.   4.49
##  3 New Zealand Oceania    2007    80.2  4115771    25185.   4.40
##  4 New Zealand Oceania    2002    79.1  3908037    23190.   4.37
##  5 Australia   Oceania    1997    78.8 18565243    26998.   4.43
##  6 Australia   Oceania    1992    77.6 17481977    23425.   4.37
##  7 New Zealand Oceania    1997    77.6  3676187    21050.   4.32
##  8 New Zealand Oceania    1992    76.3  3437674    18363.   4.26
##  9 Australia   Oceania    1987    76.3 16257249    21889.   4.34
## 10 Australia   Oceania    1982    74.7 15184200    19477.   4.29
unique(d$country[d$continent == "Oceania"])
## [1] Australia   New Zealand
## 142 Levels: Afghanistan Albania Algeria Angola Argentina ... Zimbabwe

Podemos encontrar os países que mais cresceram (em termos absolutos e relativos) durante o período observado. Note como há vários países asiáticos listados qual seja a métrica escolhida.

# Países que mais cresceram no período da amostra
# termos absolutos
d %>%
  filter(year == min(year) | year == max(year)) %>%
  group_by(country) %>%
  summarise(gap = diff(gdppercap)) %>%
  arrange(desc(gap)) %>%
  head(10) %>%
  kable() %>%
  kable_styling(bootstrap_options = c("hover", "bordered"), full_width = FALSE)
country gap
Singapore 44828.04
Norway 39261.77
Hong Kong, China 36670.56
Ireland 35465.72
Austria 29989.42
United States 28961.17
Iceland 28913.10
Japan 28439.11
Netherlands 27856.36
Taiwan 27511.33
# termos relativos
d %>%
  filter(year == min(year) | year == max(year)) %>%
  group_by(country) %>%
  mutate(gap = gdppercap / dplyr::lag(gdppercap) * 100) %>%
  select(country, gap) %>%
  arrange(desc(gap)) %>%
  head(10) %>%
  kable() %>%
  kable_styling(bootstrap_options = c("hover", "bordered"), full_width = FALSE)
country gap
Equatorial Guinea 3235.5417
Taiwan 2379.4131
Korea, Rep.  2265.5071
Singapore 2036.3009
Botswana 1476.6499
Hong Kong, China 1300.5730
China 1238.3898
Oman 1220.6445
Thailand 984.2203
Japan 984.0378

A mesma análise também pode ser feita para a expectativa de vida. Adicionalmente também podemos encontrar qual foi a maior variação (negativa) entre um ponto observado e outro dentro da amostra.

# País que mais aumentou sua expectiativa de vida no período da amostra
# termos abolutos
d %>%
  filter(year == min(year) | year == max(year)) %>%
  group_by(country) %>%
  summarise(gap = diff(lifeexp)) %>%
  arrange(desc(gap)) %>%
  head(10) %>%
  kable() %>%
  kable_styling(bootstrap_options = c("hover", "bordered"), full_width = FALSE)
country gap
Oman 38.062
Vietnam 33.837
Indonesia 33.182
Saudi Arabia 32.902
Libya 31.229
Korea, Rep.  31.170
Nicaragua 30.585
West Bank and Gaza 30.262
Yemen, Rep.  30.150
Gambia 29.448
# termos relativos
d %>%
  filter(year == min(year) | year == max(year)) %>%
  group_by(country) %>%
  mutate(gap = lifeexp / dplyr::lag(lifeexp) * 100) %>%
  arrange(desc(gap)) %>%
  select(country, gap) %>%
  head(10) %>%
  kable() %>%
  kable_styling(bootstrap_options = c("hover", "bordered"), full_width = FALSE)
country gap
Oman 201.2880
Gambia 198.1600
Yemen, Rep.  192.6324
Indonesia 188.5609
Vietnam 183.7301
Saudi Arabia 182.5129
Nepal 176.4112
India 173.1143
Libya 173.0965
Nicaragua 172.2810
# Maior variação negativa na lifeexp ano a ano
d %>%
  group_by(country) %>%
  mutate(del = lifeexp - lag(lifeexp)) %>%
  filter(year != 1952) %>%
  arrange(del) %>%
  head() %>%
  kable() %>%
  kable_styling(bootstrap_options = c("hover", "bordered"), full_width = FALSE)
country continent year lifeexp pop gdppercap lgdppc del
Rwanda Africa 1992 23.599 7290203 737.0686 2.867508 -20.421
Zimbabwe Africa 1997 46.809 11404948 792.4500 2.898972 -13.568
Lesotho Africa 2002 44.593 2046772 1275.1846 3.105573 -10.965
Swaziland Africa 2002 43.869 1130269 4128.1169 3.615752 -10.420
Botswana Africa 1997 52.556 1536536 8647.1423 3.936873 -10.189
Cambodia Asia 1977 31.220 6978607 524.9722 2.720136 -9.097

Visualizando o Brasil

Agora vamos analisar o Brasil mais de perto. Para tornar a análise mais concreta escolho um pequeno grupo de países para acompanhar.

# Visualizando a trajetória do Brasil
sub <- c("Argentina", "Brazil", "Chile", "Korea, Rep.", "Venezuela")
sub_d <- d %>%
  filter(country %in% sub)

ggplot() +
  geom_line(data = d, aes(x = year, y = lgdppc, group = country),
            colour = "gray60", alpha = .5) +
  geom_point(data = sub_d, aes(x = year, y = lgdppc, colour = country),
             size = 2) +
  geom_line(data = sub_d, size = 1.25,
            aes(x = year, y = lgdppc, group = country, colour = country)) +
  labs(title = "PIB per capita (1952/2007)",
       caption = nomes$fonte,
       x = "",
       y = nomes$x) +
  scale_color_brewer(palette = 6, type = "qual", name = "") +
  theme_vini

O Brasil em 2007 tinha a 68ª maior expectativa de vida ao nascer a 60º PIB per capita (numa amostra de 142 países). Olhando para a distribuição dos dados, o Brasil não está tão mal em termos de expectativa de vida, mas ainda está bastante atrás dos demais países em termos de PIB. Note que neste último gráfico uso os valores absolutos para facilitar a interpretação. A posição do Brasil é indicada por uma linha vertical em vermelho.

d %>%
  filter(year == 2007) %>%
  ggplot(aes(lifeexp)) +
  geom_histogram(bins = 20) +
  geom_vline(xintercept = 72.4, colour = "tomato", size = 1) +
  scale_y_continuous(expand = c(0, 0), limits  = c(0, 25)) +
  labs(y = "", x = nomes$y,
       title = "Distribuição da expectativa de vida",
       subtitle = "A linha vermelha indica a posição do Brasil.",
       caption = nomes$fonte) +
  theme_vini

d %>%
  filter(year == 2007) %>%
  ggplot(aes(gdppercap)) +
  geom_histogram(bins = 20) +
  geom_vline(xintercept = 9066, colour = "tomato", size = 1) +
  scale_y_continuous(expand = c(0, 0), limits = c(0, 16)) +
  scale_x_continuous(label = format(seq(0, 50000, 10000), big.mark = ".")) + 
  labs(y = "", x = "PIB per capita (US$ 2010)",
       title = "Distribuição do PIB per capita (2007)",
       subtitle = "A linha vermelha indica a posição do Brasil.",
       caption = nomes$fonte) +
  theme_vini

Gráfico interativo

Também é possível produzir gráficos interativos com o R. Estes dados são particularmente bem adaptados a este de visualização pois eles mudam no tempo.

library(plotly)
info <- list(symbol = "circle", sizemode = "diameter",
             line = list(width = 2, color = '#FFFFFF'))
p <-
plot_ly(data = d,
        x = ~lgdppc,
        y = ~lifeexp,
        color = ~continent,
        colors = continent_colors,
        size = ~pop,
        frame = ~year,
        type = "scatter",
        mode = "markers",
        marker = info,
        text = ~paste("Country:", country,
                      "<br>Life Expectancy:", round(lifeexp, 2),
                      '<br>GDP per capita:', round(gdppercap, 2),
                      '<br>Pop.:', format(pop, big.mark = ","))
             ) %>%
plotly::layout( 
               title = "Expectativa de vida e PIB per capita",
               xaxis = list(title = "GDP per capita (US$, log)"),
               yaxis = list(title = "Life Expectancy (years)")
       )

chart_link = api_create(p, filename="Life Expectancy and GDP")
chart_link