2023/01/31 (updated: 2023-12-29)

Programa

Introdução

  • Começando a usar R e RStudio
  • Pacotes
  • Objetos e classes
  • Funções
  • Operações básicas com dados
  • Data frames
  • Importação de dados
  • Obtendo informações dos dados com tidyverse
  • Arrumando dados com tidyverse
  • Visualização de dados com ggplot2
  • Iterações com purrr

Causalidade

  • Subconjunto de dados no R
  • Efeito causal e contrafactual
  • Controle aleatório (RCT)
  • Estudos com dados observados
  • Estatísticas descritivas

Mensuração

  • Dados ausentes no R
  • Visualização de distribuições univariadas
  • Pesquisa por amostragem
  • Relações bivariadas
  • Agrupamento (clustering)

Previsão

  • Pevisão
  • Regressão linear
  • Experimentos aleatórios

Análise exploratória de dados

  • Dados de texto
  • Dados de rede
  • Dados espaciais

Probabilidade

  • Probabilidade
  • Probabilidade condicional
  • Variáveis aleatórias e distribuições de probabilidade
  • Lei dos Grande Números e Teorema Central do Limite

Incerteza

  • Estimação
  • Testes de hipóteses
  • Regressão linear

Referências

  • Kosuke Imai e Nora Webb Williams. Quantitative Social Science: an introduction in tidyverse. Princeton University Press, 2022.
  • Elena Llaudet e Kosuke Imai. Data Analysis for Social Science: a friendly and practical introduction. Prienceton University Press, 2023.
  • Hadley Wickham. ggplot2 - Elegant Graphics for Data Analysis. Springer, 2016.

Introdução

Instalar o R e o RStudio

Tela do RStudio

...

Operações básicas no R

5 + 7
## [1] 12
45/9
## [1] 5

Operações básicas no R

4*(12-7)
## [1] 20
sqrt(25)
## [1] 5

Scripts

# Um script permite salvar seu trabalho
# Esse aqui é só um exemplo

5 + 7     # o R pode somar
3 * 8     # Pode multiplicar
4*(12-7)  # sabe usar as propriedades da adição e da multiplicação
sqrt(25)  # sabe até encontrar a raiz de um número

# Em geral você vai trabalhar com scripts

Pacotes

  • Pacotes são fundamentais no R pois implementam funções que realizam operações que não estão disponíveis no R básico.
  • Pacotes são criados por usuários do R e geralmente são obtidos no CRAN, alguns pacotes, geralmente em desevolvimento, são obtidos no github.
  • No RStudio os pacotes podem ser instalados em Tools -> Install packages…
  • A função para instalar pacotes é install_packages().

Pacotes

  • Pacotes só precisam ser instalados uma vez por computador (salvo quando ocorrem atualizações).
  • Para usar um pacote instalado é preciso avisar para o R, isso é feito com a função library()
  • Uma boa prática é carregar os pacotes que serão usado logo no começo do script

Pacotes

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.4
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.4.4     ✔ tibble    3.2.1
## ✔ lubridate 1.9.3     ✔ tidyr     1.3.0
## ✔ purrr     1.0.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(readxl)

Objetos

  • O R guarda as informações em objetos, pense em um objeto como um atalho para peças de informação que desejamos guardar.
  • Uma vez criado um objeto é possível acessar a informação que ele guarda usando o nome do objeto. Por isso é importante dar nomes signficativos aos objetos. O símbolo <- é usado para dizer que a informação deve ser guardada em um objeto.
  • Objetos podem ser de várias classes a depender das características das informações que armazenam.

Objetos

soma <- 5 + 3
print(soma)
## [1] 8
soma <- 5 + 3
soma
## [1] 8

Classes de objetos

  • Objetos não guardam apenas números. Podem guardar textos, variáveis qualitativas (fatores), conjuntos de dados, relações lógicas, etc.
  • Cada tipo de informação é guardada em uma classe de objetos.

Classes de objetos

soma <- 5+3
class(soma)
## [1] "numeric"
curso <- "Economia"
class(curso)
## [1] "character"
logic <- 5 == 7
class(logic)
## [1] "logical"

Operações com objetos

x <- 5
y <- 3
x+y
## [1] 8
z <- x+y
z
## [1] 8

Operações com objetos

nome <- "Roberto"
sobrenome <- "Ellery"
paste(nome,sobrenome)
## [1] "Roberto Ellery"
nome.completo <- paste(nome,sobrenome)
nome.completo
## [1] "Roberto Ellery"

Vetores

  • Vetores permitem armazenar uma coleção de informações que seguem uma ordem específica.
  • A função c() é usada para inserir vetores no R.

Vetores

Vetores

world.pop <- c(2525779,3026003,3691173,4449049,5320817,6127700,6916183)
world.pop
## [1] 2525779 3026003 3691173 4449049 5320817 6127700 6916183

Vetores

pop.first <- c(2525779,3026003,3691173)
pop.second <- c(4449049,5320817,6127700,6916183)

pop.all <- c(pop.first, pop.second)
pop.all
## [1] 2525779 3026003 3691173 4449049 5320817 6127700 6916183

Vetores

  • Para acessar um elemento, ou conjunto de elementos, de um vetor é preciso indicar os elementos com [] após o nome do vetor
world.pop[2]
## [1] 3026003
world.pop[c(1,5)]
## [1] 2525779 5320817

Vetores

world.pop[-3]
## [1] 2525779 3026003 4449049 5320817 6127700 6916183
world.pop[1:3]
## [1] 2525779 3026003 3691173

Operações com vetores

pop.million <- world.pop/1000
pop.million
## [1] 2525.779 3026.003 3691.173 4449.049 5320.817 6127.700 6916.183
pop.rate <- world.pop/world.pop[1]
pop.rate
## [1] 1.000000 1.198047 1.461400 1.761456 2.106604 2.426063 2.738238

Operações com vetores

  • É possível fazer operações com múltiplos vetores. Por exemplo, podemos calcular o crescimento da população em cada década.
  • Se a população cresceu de 100 para 120, dizemos que cresceu 20%, que é \(100*\frac{120-100}{100}\), ou seja, \(100*\frac{\mbox{pop.final - pop.inicial}}{\mbox{pop.inicial}}\)
  • Para calcular o crescimento em cada década vamos criar um vetor com a população final, equivale a tirar o primeiro elemento do vetor completo, e outro vetor com a população final, equivale a tirar o último elemento. Depois é só fazer a conta.

Operações com vetores

world.pop
## [1] 2525779 3026003 3691173 4449049 5320817 6127700 6916183
pop.final <- world.pop[-1]
pop.final
## [1] 3026003 3691173 4449049 5320817 6127700 6916183
pop.inicial <- world.pop[-7]
pop.inicial
## [1] 2525779 3026003 3691173 4449049 5320817 6127700

Operações com vetores

pop.increase <- pop.final - pop.inicial
percent.increase <- (pop.increase/pop.inicial) * 100
percent.increase
## [1] 19.80474 21.98180 20.53212 19.59448 15.16464 12.86752

Operações com vetores

  • É possível substituir valores em posições específicas no vetor.
percent.increase
## [1] 19.80474 21.98180 20.53212 19.59448 15.16464 12.86752
percent.increase[c(1,2)] <- c(20,22)
percent.increase
## [1] 20.00000 22.00000 20.53212 19.59448 15.16464 12.86752

Funções

  • Funções são peças fundamentais no R, pois permitem salvar conjuntos de operações que realizam tarefas específicas.
  • Funções transformam múltiplos objetos (inputs) em outros objetos (outputs).
  • Por exemplo, no começo da aula usamos a função sqrt() para obter a raiz quadrada, especificamente essa função recebe um número como input e retorna a raiz quadrada desse número como output.
  • É comum chamarmos os inputs de argumentos da função.

Funções

length(world.pop)
## [1] 7
min(world.pop)
## [1] 2525779

Funções

mean(world.pop)
## [1] 4579529
sum(world.pop)/length(world.pop)
## [1] 4579529

Funções

year <- seq(from = 1950, to = 2010, by = 10)
year
## [1] 1950 1960 1970 1980 1990 2000 2010
seq(to = 2010, from = 1950, by = 10)
## [1] 1950 1960 1970 1980 1990 2000 2010

Funções

seq(from = 2010, to = 1950, by = -10)
## [1] 2010 2000 1990 1980 1970 1960 1950
2005:2010
## [1] 2005 2006 2007 2008 2009 2010
2010:2005
## [1] 2010 2009 2008 2007 2006 2005

Funções

names(world.pop)
## NULL
names(world.pop) <- year
names(world.pop)
## [1] "1950" "1960" "1970" "1980" "1990" "2000" "2010"
world.pop
##    1950    1960    1970    1980    1990    2000    2010 
## 2525779 3026003 3691173 4449049 5320817 6127700 6916183

Funções

  • A medida que usamos o R podemos nos deparar com a necessidade de criarmos nossas próprias funções. A função function() cria novas funções.
  • Estrutura da função function():
  • Cabeçalho: myfunction <- function(input1, input2, …, inputN) {
  • Corpo: definições do output a partir dos inputs
  • Final: return(output) }

Funções

  • Exemplo
my.summary <- function(x) { #a função usa um input que é o vetor x
  s.out <- sum(x)
  i.out <- length(x)
  m.out <- s.out/i.out
  out <- c(s.out, i.out, m.out) #define os outputs
  names(out) <- c("sum", "length", "mean") #adicionar rótulos
  return(out) #encerra a função e retorna o output
  }

Funções

z <- 1:10
my.summary(z)
##    sum length   mean 
##   55.0   10.0    5.5
my.summary(world.pop)
##      sum   length     mean 
## 32056704        7  4579529

Data frames

  • Na maioria das vezes estamos interessados em colecionar vários vetores em uma coleção de dados, por exemplo, podemos ter vetores com nomes dos países, PIB e dívida pública e desejamos colocar esses vetores em um único objeto.
  • O data frame faz esse trabalho no R.

Data frames

nomes <- c("Paulo", "José", "Maria", "Ana", "Pedro")
altura <- c(1.80, 1.75, 1.70, 1.60, 1.90)
genero <- factor(c("masc", "masc", "fem", "fem", "masc"))

my.df <- data.frame(nomes, altura, genero)

Data frames

Data frames

str(my.df)
## 'data.frame':    5 obs. of  3 variables:
##  $ nomes : chr  "Paulo" "José" "Maria" "Ana" ...
##  $ altura: num  1.8 1.75 1.7 1.6 1.9
##  $ genero: Factor w/ 2 levels "fem","masc": 2 2 1 1 2
summary(my.df)
##     nomes               altura      genero 
##  Length:5           Min.   :1.60   fem :2  
##  Class :character   1st Qu.:1.70   masc:3  
##  Mode  :character   Median :1.75           
##                     Mean   :1.75           
##                     3rd Qu.:1.80           
##                     Max.   :1.90

Data frames

my.df$nomes
## [1] "Paulo" "José"  "Maria" "Ana"   "Pedro"
my.df$altura
## [1] 1.80 1.75 1.70 1.60 1.90
my.df$genero
## [1] masc masc fem  fem  masc
## Levels: fem masc

Data frames

mean(my.df$altura)
## [1] 1.75

Importação de dados

  • Na maioria das vezes os dados que vamos usar estão armazenados em arquivos;
  • Esses arquivos podem estar em vários formatos: .csv, .xlsx, .dta, etc
  • Parte do trabalho em uma análise de dados é fazer com que o R leia o arquivo e armazene os dados, geralmente em um data frame.

Importação de dados

  • O R possui várias funções para importar dados de arquivos de texto;
  • A mais geral é a read.table(), mas funções como read.csv() e read.csv2() podem ser úteis;
  • O R não possui uma função para importar dados do Excel, felizmente existem pacotes com funções que fazem esse trabalho.

Importação de dados

  • O arquivo map1.txt possui dados de três variáveis.
  • A variáveis são separadas por “,”
  • Os decimais são separados por “.”

Arquivo de dados, map1

...

Importação de dados

dados <- read.table("map1.txt", header=TRUE, sep=",")
str(dados)
## 'data.frame':    5 obs. of  3 variables:
##  $ VarA: num  1.5 3.2 5.7 7.6 9.2
##  $ VarB: num  2.3 4.1 6.7 8.2 10.1
##  $ VarC: int  3 7 11 15 19

Importação de dados

Importação de dados

  • Passar informações erradas para o R não necessariamente vai gerar um erro, mas os dados não vão aparecer como deveriam;
  • Tome cuidado com separador de variáveis, com separador de decimais, se tem título, etc

Importação de dados

dados <- read.table("map1.txt", sep=",")
str(dados)
## 'data.frame':    6 obs. of  3 variables:
##  $ V1: chr  "VarA" "1.5" "3.2" "5.7" ...
##  $ V2: chr  " VarB" " 2.3" " 4.1" " 6.7" ...
##  $ V3: chr  " VarC" " 3" " 7" " 11" ...

Importação de dados

Importação de dados

dados <- read.table("map1.txt", sep=";")
str(dados)
## 'data.frame':    6 obs. of  1 variable:
##  $ V1: chr  "VarA, VarB, VarC" "1.5, 2.3, 3" "3.2, 4.1, 7" "5.7, 6.7, 11" ...

Importação de dados

Importação de dados

dados <- read.table("map1.txt", header=TRUE, 
                    sep = ",", dec=",")
str(dados)
## 'data.frame':    5 obs. of  3 variables:
##  $ VarA: chr  "1.5" "3.2" "5.7" "7.6" ...
##  $ VarB: chr  " 2.3" " 4.1" " 6.7" " 8.2" ...
##  $ VarC: int  3 7 11 15 19

Importação de dados

Importação de dados

  • O arquivo map2 tem informações com nome, altura e gênero de um conjunto de pessoas, o autor do arquivo colocou uma descrição dos dados no cabeçalho.

Arquivo de dados, map2

...

Importação de dados

dados <- read.table("map2.txt", header=TRUE, sep=";", 
                    dec=",", skip=4)
str(dados)
## 'data.frame':    7 obs. of  3 variables:
##  $ Nome  : chr  "Paulo" "Francisco" "Maria" "Natalia" ...
##  $ Altura: num  1.82 1.7 1.75 1.6 1.6 1.75 1.78
##  $ Genero: chr  " Masculino" " Masculino" " Feminino" " Feminino" ...

Importação de dados

Importação de dados

str(dados)
## 'data.frame':    7 obs. of  3 variables:
##  $ Nome  : chr  "Paulo" "Francisco" "Maria" "Natalia" ...
##  $ Altura: num  1.82 1.7 1.75 1.6 1.6 1.75 1.78
##  $ Genero: chr  " Masculino" " Masculino" " Feminino" " Feminino" ...
summary(dados)
##      Nome               Altura         Genero         
##  Length:7           Min.   :1.600   Length:7          
##  Class :character   1st Qu.:1.650   Class :character  
##  Mode  :character   Median :1.750   Mode  :character  
##                     Mean   :1.714                     
##                     3rd Qu.:1.765                     
##                     Max.   :1.820

Importação de dados

dados$Genero <- as.factor(dados$Genero)
summary(dados)
##      Nome               Altura             Genero 
##  Length:7           Min.   :1.600    Feminino :3  
##  Class :character   1st Qu.:1.650    Masculino:4  
##  Mode  :character   Median :1.750                 
##                     Mean   :1.714                 
##                     3rd Qu.:1.765                 
##                     Max.   :1.820

Importação de dados

  • Dados são encontrados em vários lugares, cada vez mais na internet.
  • O R permite ler dados diretamente da internet.

Páginas com dados em .csv

...

Importação de dados

url <- 
"https://people.sc.fsu.edu/~jburkardt/data/csv/deniro.csv"
deniro <- read.table(url, header = TRUE, sep=",")

Importação de dados

head(deniro, n=10)
##    Year Score                   Title
## 1  1968    86               Greetings
## 2  1970    17             Bloody Mama
## 3  1970    73                Hi, Mom!
## 4  1971    40             Born to Win
## 5  1973    98            Mean Streets
## 6  1973    88    Bang the Drum Slowly
## 7  1974    97  The Godfather, Part II
## 8  1976    41         The Last Tycoon
## 9  1976    99             Taxi Driver
## 10 1977    47                    1900

Importação de dados

str(deniro)
## 'data.frame':    87 obs. of  3 variables:
##  $ Year : int  1968 1970 1970 1971 1973 1973 1974 1976 1976 1977 ...
##  $ Score: int  86 17 73 40 98 88 97 41 99 47 ...
##  $ Title: chr  " Greetings" " Bloody Mama" " Hi, Mom!" " Born to Win" ...

Importação de dados

summary(deniro)
##       Year          Score          Title          
##  Min.   :1968   Min.   :  4.0   Length:87         
##  1st Qu.:1988   1st Qu.: 38.0   Class :character  
##  Median :1997   Median : 65.0   Mode  :character  
##  Mean   :1996   Mean   : 58.2                     
##  3rd Qu.:2007   3rd Qu.: 80.0                     
##  Max.   :2016   Max.   :100.0

Importação de dados

  • Existem vários pacotes com funções para importar dados.
  • O pacote readr aperfeiçoas as funções do R básico para ler arquivos de texto
  • O pacote readxl permite ler dados do Excel
  • Os pacotes foreign e haven permitem ler dados de outros softwares, por exemplo, do Stata.

Obtendo informações dos dados com tidyverse

  • A Penn World Table (PWT) é uma das principais bases de dados para estudos sobre crescimento econômico.
  • Para ilustrar o uso do tidyverse para obter informações a partir de dados vamos utilizar a versão 10.0 da PWT
load("PWT100a.Rda")

Obtendo informações dos dados com tidyverse

  • O tidyverse é estruturado por verbos, comandos são dados por funções que corresponde a um verbo.
  • Por exemplo, para selecionar variáveis usamos a função select() e para filtrar a função filter().

Obtendo informações dos dados com tidyverse

  • Para obter o PIB do Brasil, devemos selecionar uma variável para identificar o país, o PIB e os anos e filtrar o identificador de país para ser o do Brasil.
  • Isso pode ser feito com as funções select() e filter() “aninhadas” (nested), ou seja, uma como argumento da outra.

Obtendo informações dos dados com tidyverse

filter(select(pwt, countrycode, rgdpo, year), countrycode == "BRA")
## # A tibble: 70 × 3
##    countrycode   rgdpo  year
##    <fct>         <dbl> <dbl>
##  1 BRA          88443.  1950
##  2 BRA          91100.  1951
##  3 BRA         100770.  1952
##  4 BRA         104141.  1953
##  5 BRA         113028.  1954
##  6 BRA         121660.  1955
##  7 BRA         126157.  1956
##  8 BRA         137198.  1957
##  9 BRA         145166.  1958
## 10 BRA         151863.  1959
## # ℹ 60 more rows

Obtendo informações dos dados com tidyverse

  • A estratégia de aninhar as funções pode levar a linhas de códigos muito complexas em análises mais sofisticadas.
  • Para evitar que isso aconteça e manter o código simples o tidyverse usa pipes, %>%
  • O código abaixo faz o mesmo serviço do código anterior.

Obtendo informações dos dados com tidyverse

pwt %>%
  select(countrycode, year, rgdpo) %>%
  filter(countrycode == "BRA") %>%
  head()
## # A tibble: 6 × 3
##   countrycode  year   rgdpo
##   <fct>       <dbl>   <dbl>
## 1 BRA          1950  88443.
## 2 BRA          1951  91100.
## 3 BRA          1952 100770.
## 4 BRA          1953 104141.
## 5 BRA          1954 113028.
## 6 BRA          1955 121660.

Obtendo informações dos dados com tidyverse

  • Para colocar a informação obtida a um novo data frame basta informar ao R o nome do data frame.
pib_BR <- pwt %>%
  select(code = countrycode, ano = year, pib = rgdpo) %>%
  filter(code == "BRA")

Obtendo informações dos dados com tidyverse

Obtendo informações dos dados com tidyverse

  • A PWT apresenta três medidas de PIB: rgdpo, rgdpe e rgdpna, suponha que queiramos as três medidas para Brasil e Argentina em 2019
pwt %>%
  select(code = countrycode, pais = country, ano = year, 
         starts_with("rgdp")) %>%
  filter(code %in% c("ARG", "BRA"), ano == 2019)
## # A tibble: 2 × 6
##   code  pais        ano    rgdpe    rgdpo  rgdpna
##   <fct> <fct>     <dbl>    <dbl>    <dbl>   <dbl>
## 1 ARG   Argentina  2019  991646.  977421.  975569
## 2 BRA   Brazil     2019 3089274. 3080048. 3042119

Obtendo informações dos dados com tidyverse

  • Na PWT encontramos medidas de PIB e de população, mas não de PIB per capita. Para ter o PIB per capita é preciso criar uma nova variável a partir de operações com variáveis que estão no data frame.
  • A função mutate() faz esse trabalho.

Obtendo informações dos dados com tidyverse

pwt %>%
  select(code = countrycode, ano = year, pib = rgdpna, pop) %>%
  filter(code == "BRA", ano >= 2011) %>%
  mutate(pib.pc = pib/pop) %>%
  select(-code, -pib, - pop) %>%
  tail(n=5)
## # A tibble: 5 × 2
##     ano pib.pc
##   <dbl>  <dbl>
## 1  2015 14815.
## 2  2016 14212.
## 3  2017 14285.
## 4  2018 14360.
## 5  2019 14414.

Obtendo informações dos dados com tidyverse

  • As funções group_by() e summarize() permitem agrupar os dados de acordo com variáveis de interesse e obter estatísticas relativas aos grupo.
  • Por exemplo, suponha que você quer calcular PIB o per capita médio entre 2015 e 2019 de Brasil, Argentina, Colômbia, Peru, Bolívia e México.

Obtendo informações dos dados com tidyverse

paises <- c("BRA", "ARG", "COL", "PER", "BOL", "MEX")

pwt %>%
  select(code = countrycode, pais = country, ano = year, 
         pib = rgdpna, pop) %>%
  filter(code %in% paises, ano >= 2015) %>%
  mutate(pib.pc = pib/pop) %>%
  group_by(code) %>%
  summarise(m_pib.pc = mean(pib.pc)) %>%
  ungroup()

Obtendo informações dos dados com tidyverse

## # A tibble: 6 × 2
##   code  m_pib.pc
##   <fct>    <dbl>
## 1 ARG     22808.
## 2 BOL      8152.
## 3 BRA     14417.
## 4 COL     13521.
## 5 MEX     18830.
## 6 PER     11979.

Obtendo informações dos dados com tidyverse

  • Suponha que além da média você queira o desvio padrão, o máximo, o mínimo e a mediana

Obtendo informações dos dados com tidyverse

df.exemplo <- pwt %>%
  select(code = countrycode, pais = country, ano = year, 
         pib = rgdpna, pop) %>%
  filter(code %in% paises, ano >= 2015) %>%
  mutate(pib.pc = pib/pop) %>%
  group_by(code, pais) %>%
  summarise(media = mean(pib.pc),
            desv.pad = sd(pib.pc),
            max = max(pib.pc),
            min = min(pib.pc),
            mediana = median(pib.pc)) %>%
  ungroup()
## `summarise()` has grouped output by 'code'. You can override using the
## `.groups` argument.

Obtendo informações dos dados com tidyverse

Obtendo informações dos dados com tidyverse

  • Suponha que você quer construir uma base de dados com PIB per capita e PIB por trabalhador nos anos de 1960, 1990 e 2019.
  • A base de dados deve excluir países menos de 5 milhões de habitantes em 1960.
  • Os dados de PIB per capita e PIB por trabalhador devem estar em logaritmos.

Obtendo informações dos dados com tidyverse

pop5_1960 <- pwt %>%
  select(code = countrycode, pop, year) %>%
  filter(year == 1960, pop > 5) %>%
  pull(code)

df_pib.pc <- pwt %>%
  select(code = countrycode, pais = country, ano = year, 
         pib = rgdpo, pop, emp) %>%
  filter(code %in% pop5_1960) %>%
  filter(ano %in% c(1960, 1990, 2019)) %>%
  mutate(pib.pc = pib/(1000*pop),
         l_pib.pc = log(pib.pc),
         pib.emp = pib/(1000*emp),
         l_pib.emp = log(pib.emp))

Obtendo informações dos dados com tidyverse

Obtendo informações dos dados com tidyverse

  • Quais os 5 países mais ricos em 1960?
df_pib.pc %>%
  filter(ano == 1960) %>%
  select(pais, pib.pc) %>%
  slice_max(order_by = pib.pc, n = 5)
## # A tibble: 5 × 2
##   pais          pib.pc
##   <fct>          <dbl>
## 1 Switzerland     23.2
## 2 United States   19.1
## 3 Australia       15.8
## 4 Canada          15.4
## 5 Sweden          13.5

Obtendo informações dos dados com tidyverse

  • Quais os 5 países mais ricos em 2019?
df_pib.pc %>%
  filter(ano == 2019) %>%
  select(pais, pib.pc) %>%
  slice_max(order_by = pib.pc, n = 5)
## # A tibble: 5 × 2
##   pais          pib.pc
##   <fct>          <dbl>
## 1 Switzerland     75.3
## 2 United States   62.6
## 3 Netherlands     55.6
## 4 Australia       54.1
## 5 Austria         53.3

Obtendo informações dos dados com tidyverse

  • Os 10% mais ricos em 2019?
df_pib.pc %>%
  filter(ano == 2019) %>%
  select(pais, pib.pc) %>%
  slice_max(order_by = pib.pc, prop = 0.1)
## # A tibble: 5 × 2
##   pais          pib.pc
##   <fct>          <dbl>
## 1 Switzerland     75.3
## 2 United States   62.6
## 3 Netherlands     55.6
## 4 Australia       54.1
## 5 Austria         53.3

Obtendo informações dos dados com tidyverse

  • Os 10% mais pobres em 2019?
df_pib.pc %>%
  filter(ano == 2019) %>%
  select(pais, pib.pc) %>%
  slice_min(order_by = pib.pc, prop = 0.1)
## # A tibble: 5 × 2
##   pais                               pib.pc
##   <fct>                               <dbl>
## 1 Venezuela (Bolivarian Republic of)  0.251
## 2 D.R. of the Congo                   1.02 
## 3 Mozambique                          1.23 
## 4 Madagascar                          1.54 
## 5 Uganda                              2.09

Obtendo informações dos dados com tidyverse

  • Encontre a média das taxas de investimento de todos os países da amostra para todos os anos entre 1980 e 2019, mostre os cinco anos com maiores taxas de investimento.

Obtendo informações dos dados com tidyverse

pwt %>%
  select(code = countrycode, ano = year, tx_i = csh_i) %>%
  filter(code %in% pop5_1960, ano >= 1980) %>%
  group_by(ano) %>%
  summarise(m_tx_i = mean(tx_i)) %>%
  ungroup() %>%
  slice_max(order_by = m_tx_i, n=5)
## # A tibble: 5 × 2
##     ano m_tx_i
##   <dbl>  <dbl>
## 1  2008  0.255
## 2  2011  0.250
## 3  1980  0.250
## 4  2012  0.249
## 5  2007  0.246

Arrumando dados com tidyverse

  • É muito raro que uma base de dados já esteja arrumada do jeito que precisamos para fazer nossa análise de dados, o mais comum é que tenhamos que arrumar os dados antes de começar a análise.
  • Em alguns casos, não são poucos, arrumar os dados é a parte mais trabalhosa de uma análise de dados.
  • O tidyverse oferece várias funções que facilitam a vida de quem tem de arrumar uma base de dados.
  • tidy data: Toda coluna é uma variável e toda linha é uma observação.

Arrumando dados com tidyverse

  • Os dados em relig_income exploram a relação entre renda e religião nos EUA, os dados estão bagunçados (messy) e queremos que fiquem arrumados (tidy).
  • As variáveis são religião, renda e frequência, mas essas não são as colunas como deveriam ser em uma base de dados arrumada.
  • A forma que os dados estão organizados na relig_income pode facilitar o registro de dados, apresentações ou mesmo algumas análises, mas dificulta a maioria dos trabalhos.
  • Para arrumar os dados vamos usar o tidyverse.

Arrumando dados com tidyverse

Arrumando dados com tidyverse

relig_income %>% 
  pivot_longer(-religion, names_to = "income", 
               values_to = "frequency") %>%
  head(n=5)
## # A tibble: 5 × 3
##   religion income  frequency
##   <chr>    <chr>       <dbl>
## 1 Agnostic <$10k          27
## 2 Agnostic $10-20k        34
## 3 Agnostic $20-30k        60
## 4 Agnostic $30-40k        81
## 5 Agnostic $40-50k        76

Arrumando dados com tidyverse

  • Os dados em billboard informam quando uma música entrou no top100. São oferecidos dados para artista (artist), música (track), data que entrou no ranking (date.entered) e a posição em cada semana após a entrada no ranking (76 colunas de wk1 a wk76).
  • Se em uma semanda não aparece a posição da música é porque a música não ficou entre as top100.

Arrumando dados com tidyverse

Arrumando dados com tidyverse

  • O primeiro passo será usar um pivot para criar uma coluna para week e outra para rank.
  • Quando a informação está em branco é porque a música não estava no top100, logo pode ser retirada com segurança.
billboard2 <- billboard %>%
  pivot_longer(wk1:wk76,
               names_to = "week",
               values_to = "rank",
               values_drop_na = TRUE)

Arrumando dados com tidyverse

Arrumando dados com tidyverse

  • Para terminar, vamos transformar a variável (coluna) da semana em numérica e registrar a data de cada semana.
billboard3 <- billboard2 %>%
  mutate(week = as.integer(gsub("wk","",week)),
         date = as.Date(date.entered) + 7 * (week-1),
         date.entered = NULL)

Arrumando dados com tidyverse

Arrumando dados com tidyverse

  • Suponha que você quer estudar a correlação entre crescimento econômico e dívida pública na década passada.
  • Para isso você quer calcular as médias de crescimento e dívida pública e crescimento entre 2011 e 2020.
  • Para começar a análise você foi na base de dados do FMI e pegou dados de crescimento e dívida pública para todos os países com dados disponíveis.
  • Por via das dúvidas, você também pegou dados relativos ao PIB, PIB per capita, Taxa de investimento, Taxa de poupança, população e resultado da conta corrente.
  • Os dados estão no arquivo WEO_Data.xlsx

Arrumando dados com tidyverse

  • O primeiro passo é carregar os dados no R;
  • Para isso vamos usar a função read_excel() do pacote readxl
library(readxl)
dados <- read_excel("WEO_data.xlsx", na = c("","n/a", "--"))

Arrumando dados com tidyverse

Arrumando dados com tidyverse

  • Para começar vamos retirar as variáveis que não precisamos nessa etapa da análise
dados1 <- dados %>%
  select(-Units, -Scale,
         -`Country/Series-specific Notes`, -`Estimates Start After`)

Arrumando dados com tidyverse

Arrumando dados com tidyverse

  • O próximo passo é escolher apenas as variáveis de interesse, quais seja, dívida pública e crescimento
dados2 <- dados1 %>%
  filter(`Subject Descriptor` %in% 
           c("Gross domestic product, constant prices",
                                     "General government gross debt"))

Arrumando dados com tidyverse

Arrumando dados com tidyverse

  • vamos agora usar pivot_longer() para arrumar os dados
dados3 <- dados2 %>%
  pivot_longer(names_to = "ano", values_to = "valores", 
               `2011`:`2021`)

Arrumando dados com tidyverse

Arrumando dados com tidyverse

  • Para fazer nossa análise é melhor ter o crescimento em uma coluna e a dívida em outra, a função pivot_wider() faz esse trabalho
dados4 <- dados3 %>%
  pivot_wider(names_from = `Subject Descriptor`, 
              values_from = "valores") %>%
  rename(pais = Country, 
         cresc = `Gross domestic product, constant prices`,
         div_pib = `General government gross debt`) %>%
  filter(ano != 2021)

Arrumando dados com tidyverse

Arrumando dados com tidyverse

  • Falta agora tomar a média de crescimento e dívida para cada país.
dados5 <- dados4 %>%
  group_by(pais) %>%
  summarise(cresc = mean(cresc, na.rm = TRUE),
            div_pib = mean(div_pib, na.rm = TRUE)) %>%
  ungroup()

Arrumando dados com tidyverse

Arrumando dados com tidyverse

  • Agora podemos calcular a correlação entre crescimento e dívida
cor.test(dados5$cresc, dados5$div_pib)
## 
##  Pearson's product-moment correlation
## 
## data:  dados5$cresc and dados5$div_pib
## t = -3.9696, df = 190, p-value = 0.000102
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.4025674 -0.1406379
## sample estimates:
##        cor 
## -0.2767349

Arrumando dados com tidyverse

  • Não é necessário criar um data frame para cada passo!
dados.final <- dados %>%
  select(-Units, -Scale, -`Country/Series-specific Notes`, -`Estimates Start After`) %>%
  filter(`Subject Descriptor` %in% c("Gross domestic product, constant prices", 
                                     "General government gross debt")) %>% 
  pivot_longer(names_to = "ano", values_to = "valores", `2011`:`2021`) %>%
  pivot_wider(names_from = `Subject Descriptor`, values_from = "valores") %>%
  rename(pais = Country, cresc = `Gross domestic product, constant prices`,
         div_pib = `General government gross debt`) %>%
  filter(ano != 2021) %>%
  group_by(pais) %>%
  summarise(cresc = mean(cresc, na.rm = TRUE),
            div_pib = mean(div_pib, na.rm = TRUE)) %>%
  ungroup()

Arrumando dados com tidyverse

  • Calcular a correlação entre crescimento e dívida
cor.test(dados.final$cresc, dados.final$div_pib)
## 
##  Pearson's product-moment correlation
## 
## data:  dados.final$cresc and dados.final$div_pib
## t = -3.9696, df = 190, p-value = 0.000102
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.4025674 -0.1406379
## sample estimates:
##        cor 
## -0.2767349

Visualização de dados com ggplot2

  • Assim com o tidyverse, o ggplot2 permite realizar operações complexas por meio de uma sequência de operações simples.
  • Cada parte de um gráfico está associada a uma determinada ação que corresponde a uma função no ggplot2.
  • A combinação dessas ações permite criar gráficos capazes de passar a informação que desejamos.

Visualização de dados com ggplot2

  • Para ilustrar o ggplot2 vamos usar o tidyverse para, a partir da PWT, criar um data frame com dados de crescimento econômico.
df_cresc <- pwt %>%
  select(code = countrycode, pais = country, ano = year, pib = rgdpna,
         pop, grupo = group) %>%
  mutate(pib.pc = pib/pop) %>%
  filter(ano %in% c(1960, 2019), code %in% pop5_1960) %>%
  select(-pib, -pop) %>%
  pivot_wider(names_from = ano, values_from = pib.pc) %>%
  mutate(cresc = 100*((`2019`/`1960`)^(1/59) - 1),
         l_pib.pc60 = log(`1960`)) %>%
  select(code, pais, grupo, l_pib.pc60, cresc)

save(df_cresc, file="df_cresc.Rda")

Visualização de dados com ggplot2

  • Comecemos com um gráfico clássico de crescimento econômico que relaciona crescimento ao PIB per capita inicial.
ggplot(df_cresc, aes(x=l_pib.pc60, y=cresc)) +
  geom_point()

Visualização de dados com ggplot2

Visualização de dados com ggplot2

  • Em alguns casos é interessante identificar os países no gráfico
ggplot(df_cresc, aes(x=l_pib.pc60, y=cresc)) +
  geom_point() +
  geom_text(aes(label = code))

Visualização de dados com ggplot2

Visualização de dados com ggplot2

  • Com os códigos dos países os pontos parecem desnecessários
ggplot(df_cresc, aes(x=l_pib.pc60, y=cresc)) +
  geom_text(aes(label = code))

Visualização de dados com ggplot2

Visualização de dados com ggplot2

  • Que tal dar título ao gráfico e colocar texto explicando os eixos?
ggplot(df_cresc, aes(x=l_pib.pc60, y=cresc)) +
  geom_text(aes(label = code)) +
  labs(title = "Taxa de crescimento e PIB per capita inicial",
       subtitle = "1960 a 2019",
       x = "log do PIB per capita em 1960",
       y = "taxa de crescimento",
       caption = "Fonte: PWT 10.0")

Visualização de dados com ggplot2

Visualização de dados com ggplot2

  • Cores podem ajudar em um gráfico, ou não…
ggplot(df_cresc, aes(x=l_pib.pc60, y=cresc, color = grupo)) +
  geom_text(aes(label = code)) +
  labs(title = "Taxa de crescimento e PIB per capita inicial",
       subtitle = "1960 a 2019",
       x = "log do PIB per capita em 1960",
       y = "taxa de crescimento",
       caption = "Fonte: PWT 10.0")

Visualização de dados com ggplot2

Visualização de dados com ggplot2

  • O título da legenda parece desnecessário e os nomes dos grupos de países estão em inglês, vamos resolver.
ggplot(df_cresc, aes(x=l_pib.pc60, y=cresc, color = grupo)) +
  geom_text(aes(label = code)) +
  labs(title = "Taxa de crescimento e PIB per capita inicial",
       subtitle = "1960 a 2019",
       x = "log do PIB per capita em 1960",
       y = "taxa de crescimento",
       caption = "Fonte: PWT 10.0") +
  scale_color_brewer(name = "", palette = "Set1", labels = c("Países Avançados", 
                                                            "Emergentes da Ásia",
                                                            "Emergentes da Europa",
                                                            "América Latina e Caribe",
                                                            "Oriente Médio",
                                                            "África Subsaariana"))

Visualização de dados com ggplot2

Visualização de dados com ggplot2

  • Adicionar linhas de regressão
ggplot(df_cresc, aes(x=l_pib.pc60, y=cresc, color = grupo)) +
  geom_text(aes(label = code)) +
  geom_smooth(method = "lm", se = FALSE) +
  labs(title = "Taxa de crescimento e PIB per capita inicial",
       subtitle = "1960 a 2019",
       x = "log do PIB per capita em 1960",
       y = "taxa de crescimento",
       caption = "Fonte: PWT 10.0") +
  scale_color_brewer(name = "", palette = "Set1", labels = c("Países Avançados", 
                                                            "Emergentes da Ásia",
                                                            "Emergentes da Europa",
                                                            "América Latina e Caribe",
                                                            "Oriente Médio",
                                                            "África Subsaariana"))

Visualização de dados com ggplot2

Visualização de dados com ggplot2

  • o R fez uma regressão para cada grupo de países, isso aconteceu porque definimos as cores no cabeçalho da função, logo vale para todo o gráfico, se quisermos apenas uma linha de regressão para todos os países temos de colocar as cores (ou qualquer que seja o agrupamento) nas funções específicas.

Visualização de dados com ggplot2

ggplot(df_cresc, aes(x=l_pib.pc60, y=cresc)) +
  geom_text(aes(label = code, color = grupo)) +
  geom_smooth(method = "lm", se = FALSE) +
  labs(title = "Taxa de crescimento e PIB per capita inicial",
       subtitle = "1960 a 2019",
       x = "log do PIB per capita em 1960",
       y = "taxa de crescimento",
       caption = "Fonte: PWT 10.0") +
  scale_color_brewer(name = "", palette = "Set1", labels = c("Países Avançados", 
                                                            "Emergentes da Ásia",
                                                            "Emergentes da Europa",
                                                            "América Latina e Caribe",
                                                            "Oriente Médio",
                                                            "África Subsaariana"))

Visualização de dados com ggplot2

Visualização de dados com ggplot2

  • O ggplot2 permite modificar praticamente todos os parâmetros de uma figura, por exemplo, fonte dos textos nos títulos ou nos eixos, lugar onde aparece a legenda e cores de fundo.
  • Para explorar essas possibilidade é necessário aprender mais sobre o ggplot2 do que está previsto para esse curso, aos interessados recomendo o livro ggplot2: Elegant Graphics for Data Analysis do Hadley Wickham que é o criador do ggplot2 e do tidyverse.
  • Além disso convém conhecer maneiras adequadas de combinar cores e formas para passar mensagens visuaias, o que não é trivial.

Visualização de dados com ggplot2

  • O pacote ggthemes oferece uma grande variedade de temaos que podem ser usados para personalizar suas figuras, alguns seguem padrões da literatura sobre comunicação visual, outros emulam softwares conhecidos ou padrões de veículos de imprensa.
  • A seguir alguns exemplos.
library(ggthemes)

Visualização de dados com ggplot2

  • theme_hc()
ggplot(df_cresc, aes(x=l_pib.pc60, y=cresc)) +
  geom_text(aes(label = code, color = grupo)) +
  geom_smooth(method = "lm", se = FALSE) +
  labs(title = "Taxa de crescimento e PIB per capita inicial",
       subtitle = "1960 a 2019",
       x = "log do PIB per capita em 1960",
       y = "taxa de crescimento",
       caption = "Fonte: PWT 10.0") +
  scale_color_brewer(name = "", palette = "Set1", labels = c("Países Avançados", 
                                                            "Emergentes da Ásia",
                                                            "Emergentes da Europa",
                                                            "América Latina e Caribe",
                                                            "Oriente Médio",
                                                            "África Subsaariana")) +
  theme_hc()

Visualização de dados com ggplot2

Visualização de dados com ggplot2

  • theme_stata()

Visualização de dados com ggplot2

  • theme_economist()

Visualização de dados com ggplot2

  • theme_fivethirtyeight()

Visualização de dados com ggplot2

  • theme_excel()

Visualização de dados com ggplot2

  • Suponha que você quer um gráfico mostrando a média de crescimento dos países de cada grupo da base dados.
  • Para isso será necessário agrupar os dados por grupos, calcular as médias e fazer a figura. Vamos usar um gráfico de barras.
df_cresc %>%
  group_by(grupo) %>%
  summarise(m_cresc = mean(cresc)) %>%
  ggplot(aes(grupo, m_cresc)) +
  geom_col()

Visualização de dados com ggplot2

Visualização de dados com ggplot2

  • O gráfico passa o recado, mas pode melhorar muito. Nos próximos slides faremos isso, passo a passo.
  • Para começar vamos ordenar as colunas e associar cada grupo a uma cor, com isso os nomes dos grupos no eixo x ficam redundantes.
df_cresc %>%
  group_by(grupo) %>%
  summarise(m_cresc = mean(cresc)) %>%
  ggplot(aes(reorder(grupo, m_cresc), m_cresc, fill = grupo)) +
  geom_col() +
  scale_x_discrete(labels = NULL)

Visualização de dados com ggplot2

Visualização de dados com ggplot2

  • Só para ver como funciona vamos girar o gráfico, de forma que as barras fiquem deitadas.
df_cresc %>%
  group_by(grupo) %>%
  summarise(m_cresc = mean(cresc)) %>%
  ggplot(aes(reorder(grupo, m_cresc), m_cresc, fill = grupo)) +
  geom_col() +
  scale_x_discrete(labels = NULL) +
  coord_flip()

Visualização de dados com ggplot2

Visualização de dados com ggplot2

  • Agora vamos colocar textos nas barras.
df_cresc %>%
  group_by(grupo) %>%
  summarise(m_cresc = mean(cresc)) %>%
  ggplot(aes(reorder(grupo, m_cresc), m_cresc, fill = grupo)) +
  geom_col() +
  geom_text(aes(label = m_cresc)) +
  scale_x_discrete(labels = NULL)

Visualização de dados com ggplot2

Visualização de dados com ggplot2

  • Podemos melhorar esses textos, para isso vamos usar a função percent() do pacote scales
library(scales)

df_cresc %>%
  group_by(grupo) %>%
  summarise(m_cresc = mean(cresc)) %>%
  ggplot(aes(reorder(grupo, m_cresc), m_cresc, fill = grupo)) +
  geom_col() +
  geom_text(aes(label = percent(m_cresc, scale = 1)), vjust = 1.5, 
            color = "darkblue", size=6) +
  scale_x_discrete(labels = NULL)

Visualização de dados com ggplot2

Visualização de dados com ggplot2

  • O próximo passo é colocar títulos, nomes dos eixos e fonte dos dados.
df_cresc %>%
  group_by(grupo) %>%
  summarise(m_cresc = mean(cresc)) %>%
  ggplot(aes(reorder(grupo, m_cresc), m_cresc, fill = grupo)) +
  geom_col() +
  geom_text(aes(label = percent(m_cresc, scale = 1)), vjust = 1.5, 
            color = "darkblue", size=6) +
  scale_x_discrete(labels = NULL) +
  labs(title = "Média da taxa de crescimento dos países de cada grupo",
       subtitle = "1960 a 2019",
       x = NULL,
       y = "taxa de crescimento, %",
       caption = "Fonte: PWT 10.0")

Visualização de dados com ggplot2

Visualização de dados com ggplot2

  • Que tal mudar a paleta de cores?
df_cresc %>%
  group_by(grupo) %>%
  summarise(m_cresc = mean(cresc)) %>%
  ggplot(aes(reorder(grupo, m_cresc), m_cresc, fill = grupo)) +
  geom_col() +
  geom_text(aes(label = percent(m_cresc, scale = 1)), vjust = 1.5, 
            color = "darkblue", size=6) +
  scale_x_discrete(labels = NULL) +
  labs(title = "Média da taxa de crescimento dos países de cada grupo",
       subtitle = "1960 a 2019",
       x = NULL,
       y = "taxa de crescimento, %",
       caption = "Fonte: PWT 10.0") +
  scale_fill_brewer(name = "", palette = "Set1")

Visualização de dados com ggplot2

Visualização de dados com ggplot2

  • O toque final é colocar os nomes dos grupos em português e aplicar theme_hc().

Visualização de dados com ggplot2

df_cresc %>%
  group_by(grupo) %>% summarise(m_cresc = mean(cresc)) %>%
  ggplot(aes(reorder(grupo, m_cresc), m_cresc, fill = grupo)) +
  geom_col() +
  geom_text(aes(label = percent(m_cresc, scale = 1)), vjust = 1.5, 
            color = "darkblue", size=6) +
  scale_x_discrete(labels = NULL) +
  labs(title = "Média da taxa de crescimento dos países de cada grupo",
       subtitle = "1960 a 2019", x = NULL,
       y = "taxa de crescimento, %",
       caption = "Fonte: PWT 10.0") +
  scale_fill_brewer(name = "", palette = "Set1", labels = c("Países Avançados", 
                                                            "Emergentes da Ásia",               
                                                            "Emergentes da Europa",
                                                            "América Latina e Caribe",
                                                            "Oriente Médio",
                                                            "África Subsaariana")) +
  theme_hc()

Visualização de dados com ggplot2

Visualização de dados com ggplot2

  • Gráficos de linha são particularmente úteis para mostrar a evolução de variáveis no tempo, no ggplot2 gráficos de linha são feitos com a função geom_line().
  • O código abaixo faz o gráfico do PIB per capita do Brasil entre 1950 e 2019.
pwt %>%
  select(countrycode, year, rgdpna, pop) %>%
  filter(countrycode == "BRA") %>%
  mutate(pib.pc = rgdpna/pop) %>%
  ggplot(aes(year, pib.pc)) +
  geom_line(linewidth=1.5, color = "darkblue") +
  labs(title = "PIB per capita - Brasil",
       subtitle = "1960 a 2019",
       x = NULL,
       y = "PIB per capita",
       caption = "Fonte: PWT 10.0") +
  theme_hc()

Visualização de dados com ggplot2

Visualização de dados com ggplot2

  • Assim como nos exemplos anteriores é possível associar cores (ou outras proporiedades) a grupos, por exemplo, podemos mostrar o PIB per capita de Brasil, Argentina e México.
pwt %>%
  select(countrycode, year, rgdpna, pop) %>%
  filter(countrycode %in% c("ARG","BRA", "MEX")) %>%
  mutate(pib.pc = rgdpna/pop) %>%
  ggplot(aes(year, pib.pc, color = countrycode)) +
  geom_line(linewidth=1.5) +
  labs(title = "PIB per capita - Brasil",
       subtitle = "1960 a 2019",
       x = NULL,
       y = "PIB per capita",
       caption = "Fonte: PWT 10.0") +
  theme_hc()

Visualização de dados com ggplot2

Visualização de dados com ggplot2

  • Nosso último exemplo mostra o PIB per capita do Brasil, México e Argentina como proporção do americano, os países serão identificados por símbolos (shapes) diferentes.

Visualização de dados com ggplot2

pwt %>%
  select(countrycode, year, rgdpna, pop) %>%
  filter(countrycode %in% c("ARG","BRA", "MEX", "USA")) %>%
  mutate(pib.pc = rgdpna/pop) %>%  select(-rgdpna, -pop) %>%
  pivot_wider(names_from = countrycode, values_from = pib.pc) %>%
  mutate(Brasil = 100*BRA/USA,
         Argentina = 100*ARG/USA,
         Mexico = 100*MEX/USA) %>%
  select(-USA, - BRA, -MEX, - ARG) %>%
  pivot_longer(names_to = "pais", values_to = "pib_us", -year) %>%
  ggplot(aes(year, pib_us, shape = pais)) +
  geom_line(linewidth = 1) +  geom_point(size=3) +
  labs(title = "PIB per capita como proporção do PIB per capita dos Estados Unidos",
       subtitle = "1950 a 2019", x = NULL,
       y = "% do PIB per capita dos EUA",
       caption = "Fonte: PWT 10.0") +
  scale_shape_discrete(name = "") +
  theme_classic()

Visualização de dados com ggplot2

Iterações com purrr

  • Muitas vezes queremos aplicar uma função em vários elementos de um vetor, de uma data frame ou mesmo de uma lista.
  • No curso vamos falar de loops no R, mas, mesmo sem conhecer loops, é válido terminar essa introdução apresentando o pacote **purrr*.

Iterações com purrr

  • O R tem uma família de funções chamada de apply() que aplica uma determinada função a elementos de um vetor.
  • O pacote purrr traz funções que fazem trabalho semelhante ao feito pela apply(), porém com uma estrutura compatível com o tydiverse.

Iterações com purrr

Iterações com purrr

  • Principais funções do purrr:

    • map(.x,.f): principal função do pacote, retorna uma lista;
    • map_df(.x, .f): retorna um data frame;
    • map_dbl(.x,.f): retorna um vetor numérico (double);
    • map_chr(.x,.f): retorna um vetor de caracteres;
    • map_lgt(.x,.f): retorna um vetor lógico.

Iterações com purrr

  • O primeiro argumento é o objeto que você deseja mapear e o segundo argumento é a função.
  • O objeto a ser mapeado pode ser um vetor (iterações nos elementos), um data frame (iterações nas colunas) ou uma lista (iterações nos elementos).
  • Como o primeiro elemento é onde estão os dados, as função map() são compatíveis com o uso de pipes, %>%.

Iterações com purrr

  • Vamos para os exemplos. Comecemos criando a função que desejamos aplicar.
dobro <- function(.x){
  return(.x * 2)
}

Iterações com purrr

library(purrr)
map(c(1,2,3), dobro)
## [[1]]
## [1] 2
## 
## [[2]]
## [1] 4
## 
## [[3]]
## [1] 6

Iterações com purrr

map_dbl(c(1,2,3), dobro)
## [1] 2 4 6

Iterações com purrr

map_chr(c(1,2,3), dobro)
## Warning: Automatic coercion from double to character was deprecated in purrr 1.0.0.
## ℹ Please use an explicit call to `as.character()` within `map_chr()` instead.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## [1] "2.000000" "4.000000" "6.000000"

Iterações com purrr

map(list(1,2,3), dobro)
## [[1]]
## [1] 2
## 
## [[2]]
## [1] 4
## 
## [[3]]
## [1] 6

Iterações com purrr

map_dbl(list(1,2,3), dobro)
## [1] 2 4 6

Iterações com purrr

map(data.frame(a=1,b=2,c=3), dobro)
## $a
## [1] 2
## 
## $b
## [1] 4
## 
## $c
## [1] 6

Iterações com purrr

map_df(data.frame(a=1,b=2,c=3), dobro)
## # A tibble: 1 × 3
##       a     b     c
##   <dbl> <dbl> <dbl>
## 1     2     4     6

Iterações com purrr

  • Suponha que você quer criar um data frame com os números na primeira coluna e o dobro dos números na segunda coluna:
map_df(c(1,2,3), function(.x){
  return(data.frame(numero = .x,
                    dobro = dobro(.x)))
})
##   numero dobro
## 1      1     2
## 2      2     4
## 3      3     6

Iterações com purrr

  • A função usada dentro da função map_df() é chamada de função anônima, repare que ela não tem nome, esse tipo de função é de uso temporário nas iterações.
  • Uma função anônima pode ser definida com o símbolo ~.

Iterações com purrr

  • Suponha que você quer criar um data frame com os números na primeira coluna e o dobro dos números na segunda coluna:
map_dbl(c(1,2,3), ~{2*.x})
## [1] 2 4 6

Iterações com purrr

  • Para os próximos exemplos usaremos os dados em gapminder. Os dados são referentes a PIB per capita, população e expectativa de vida para 142 países.

Iterações com purrr

library(gapminder)
str(gapminder)
## tibble [1,704 × 6] (S3: tbl_df/tbl/data.frame)
##  $ 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 [1:1704] 1952 1957 1962 1967 1972 1977 1982 1987 1992 1997 ...
##  $ lifeExp  : num [1:1704] 28.8 30.3 32 34 36.1 ...
##  $ pop      : int [1:1704] 8425333 9240934 10267083 11537966 13079460 14880372 12881816 13867957 16317921 22227415 ...
##  $ gdpPercap: num [1:1704] 779 821 853 836 740 ...

Iterações com purrr

Iterações com purrr

  • Aplicar a função class() em cada coluna:
map_chr(gapminder, class)
##   country continent      year   lifeExp       pop gdpPercap 
##  "factor"  "factor" "integer" "numeric" "integer" "numeric"

Iterações com purrr

  • Mesmo exemplo usando %>%:
gapminder %>% map_chr(class)
##   country continent      year   lifeExp       pop gdpPercap 
##  "factor"  "factor" "integer" "numeric" "integer" "numeric"

Iterações com purrr

  • Elementos distintos em cada coluna:
gapminder %>% map_dbl(n_distinct)
##   country continent      year   lifeExp       pop gdpPercap 
##       142         5        12      1626      1704      1704

Iterações com purrr

  • Melhor colocar em um data.frame
gapminder %>% map_df(~(data.frame(n_distinct = n_distinct(.x),
                                  class = class(.x))))
##   n_distinct   class
## 1        142  factor
## 2          5  factor
## 3         12 integer
## 4       1626 numeric
## 5       1704 integer
## 6       1704 numeric

Iterações com purrr

  • A função map_df() aplica a função designada em cada coluna do data.frame, podemos usar o argumento .id para identificar a coluna utilizada em cada iteração.

Iterações com purrr

gapminder %>% map_df(~(data.frame(n_distinct = n_distinct(.x),
                                  class = class(.x))),
                     .id = "variable")
##    variable n_distinct   class
## 1   country        142  factor
## 2 continent          5  factor
## 3      year         12 integer
## 4   lifeExp       1626 numeric
## 5       pop       1704 integer
## 6 gdpPercap       1704 numeric

Iterações com purrr

  • A função map2() permite fazer iterações com dois objetos.
  • A primeira iteração combina o primeiro elemento do primeiro objeto com o primeiro elemento do segundo objeto, a segunda combina o segundo elemento de cada objeto e assim por diante.

Iterações com purrr

map2(c(1,3,5),c(2,4,6),~{.x+.y})
## [[1]]
## [1] 3
## 
## [[2]]
## [1] 7
## 
## [[3]]
## [1] 11

Iterações com purrr

map2_dbl(c(1,3,5),c(2,4,6),~{.x+.y})
## [1]  3  7 11

Iterações com purrr

  • Suponha que você deseja fazer um gráfico com PIB per capita e expectativa de vida para cada continente em cada ano.
  • Como são 5 continentes e 12 anos temos de fazer 60 gráficos! A função map2() facilita muito nossa vida.

Iterações com purrr

  • Para começar vamos fazer um vetor com todos os continentes e todos os anos:
continent_year <- gapminder %>% distinct(continent, year)

Iterações com purrr

Iterações com purrr

  • Agora vamos criar um objeto para os continentes e outro para os anos:
continents <- continent_year %>% pull(continent) %>% as.character
years <- continent_year %>% pull(year)

Iterações com purrr

  • Com os objetos criados podemos fazer os gráficos:
plot_list <- map2(.x = continents, 
                  .y = years, 
                  .f = ~{
                    gapminder %>% 
                      filter(continent == .x,
                             year == .y) %>%
                      ggplot() +
                      geom_point(aes(x = gdpPercap, y = lifeExp)) +
                      ggtitle(paste(.x, .y))
                  })

Iterações com purrr

plot_list[[15]]

Iterações com purrr

plot_list[[45]]

Iterações com purrr

  • A grande diferença entre tibble e data.frame é que as colunas de uma tibble podem ser listas.
  • O uso de colunas no formato de listas combinado com as função map() cria um grande número de possibilidades para realização de operações com dados no R.

Iterações com purrr

  • A função nest(), do pacote tidyr que á parte do tidyverse, cria coluna de listas em uma tibble.

Iterações com purrr

gapminder_nested <- gapminder %>% 
  group_by(continent) %>% 
  nest()

Iterações com purrr

Iterações com purrr

  • Cada elemento da coluna data é uma lista com os dados relativos ao continente da coluna continent.

Iterações com purrr

Iterações com purrr

  • Para obter os dados do slide anterior usei gapminder_nested$data[[5]].
  • A função pluck(), do tidyr, faz o mesmo serviço.

Iterações com purrr

gapminder_nested %>% pluck("data", 5)
## # A tibble: 24 × 5
##    country    year lifeExp      pop gdpPercap
##    <fct>     <int>   <dbl>    <int>     <dbl>
##  1 Australia  1952    69.1  8691212    10040.
##  2 Australia  1957    70.3  9712569    10950.
##  3 Australia  1962    70.9 10794968    12217.
##  4 Australia  1967    71.1 11872264    14526.
##  5 Australia  1972    71.9 13177000    16789.
##  6 Australia  1977    73.5 14074100    18334.
##  7 Australia  1982    74.7 15184200    19477.
##  8 Australia  1987    76.3 16257249    21889.
##  9 Australia  1992    77.6 17481977    23425.
## 10 Australia  1997    78.8 18565243    26998.
## # ℹ 14 more rows

Iterações com purrr

  • Qual a graça de colocar colunas como listas? Imagine as possibilidades de usar mutate() com os dados que estão na lista.
  • Mas para isso é preciso tomar cuidado. A função mutate() trabalha com colunas de um data.frame que são do tipo vetor, não pode ser aplicada diretamente em listas.

Iterações com purrr

  • Suponha que você queira somar elementos de uma coluna, a função mutate() faz o serviço:
tibble(vec_col = 1:10) %>%
  mutate(vec_sum = sum(vec_col))

Iterações com purrr

## # A tibble: 10 × 2
##    vec_col vec_sum
##      <int>   <int>
##  1       1      55
##  2       2      55
##  3       3      55
##  4       4      55
##  5       5      55
##  6       6      55
##  7       7      55
##  8       8      55
##  9       9      55
## 10      10      55

Iterações com purrr

  • Se tentar algo parecido com uma coluna na forma de lista o R retorna um erro:
tibble(list_col = list(c(1, 5, 7), 
                       5, 
                       c(10, 10, 11))) %>%
  mutate(list_sum = sum(list_col))
  • Retorna: Error in sum(x) : invalid 'type' (list) of argument

Iterações com purrr

  • Para somar os elementos de cada lista temos de usar uma função do tipo map():
tibble(list_col = list(c(1, 5, 7), 
                       5, 
                       c(10, 10, 11))) %>%
  mutate(list_sum = map(list_col, sum))

Iterações com purrr

## # A tibble: 3 × 2
##   list_col  list_sum 
##   <list>    <list>   
## 1 <dbl [3]> <dbl [1]>
## 2 <dbl [1]> <dbl [1]>
## 3 <dbl [3]> <dbl [1]>

Iterações com purrr

  • Fez o serviço, mas ficou ruim de ver o resultado, vamos tentar com map_dbl():
tibble(list_col = list(c(1, 5, 7), 
                       5, 
                       c(10, 10, 11))) %>%
  mutate(list_sum = map_dbl(list_col, sum))

Iterações com purrr

## # A tibble: 3 × 2
##   list_col  list_sum
##   <list>       <dbl>
## 1 <dbl [3]>       13
## 2 <dbl [1]>        5
## 3 <dbl [3]>       31

Iterações com purrr

  • Podemos usar a combinação de mutate() e uma função do tipo map() para obter a média da expectativa de vida em cada continente:
gapminder_nested %>% 
  mutate(avg_lifeExp = map_dbl(data, ~{mean(.x$lifeExp)}))

Iterações com purrr

## # A tibble: 5 × 3
## # Groups:   continent [5]
##   continent data               avg_lifeExp
##   <fct>     <list>                   <dbl>
## 1 Asia      <tibble [396 × 5]>        60.1
## 2 Europe    <tibble [360 × 5]>        71.9
## 3 Africa    <tibble [624 × 5]>        48.9
## 4 Americas  <tibble [300 × 5]>        64.7
## 5 Oceania   <tibble [24 × 5]>         74.3

Iterações com purrr

  • E daí? Podemos fazer o mesmo com group_by()
gapminder %>%
  group_by(continent) %>%
  summarise(avg_lifeExp = mean(lifeExp))

Iterações com purrr

## # A tibble: 5 × 2
##   continent avg_lifeExp
##   <fct>           <dbl>
## 1 Africa           48.9
## 2 Americas         64.7
## 3 Asia             60.1
## 4 Europe           71.9
## 5 Oceania          74.3

Iterações com purrr

  • Que tal a correlação entre expectativa de vida e PIB per capita em cada continente?
gapminder_nested %>%
  mutate(cor = map_dbl(data, ~cor(.x$lifeExp, .x$gdpPercap)))

Iterações com purrr

## # A tibble: 5 × 3
## # Groups:   continent [5]
##   continent data                 cor
##   <fct>     <list>             <dbl>
## 1 Asia      <tibble [396 × 5]> 0.382
## 2 Europe    <tibble [360 × 5]> 0.781
## 3 Africa    <tibble [624 × 5]> 0.426
## 4 Americas  <tibble [300 × 5]> 0.558
## 5 Oceania   <tibble [24 × 5]>  0.956

Iterações com purrr

  • O último exemplo é um exercício de teoria do crescimento econômico. A literatura sugere que em países ricos o crescimento é mais estável do que em países pobres.
  • Se isso for verdade o \(R^2\) de uma regressão entre o logaritmo PIB per capita e uma tendência linear deve ser maior em países ricos.

Iterações com purrr

Iterações com purrr

Iterações com purrr

  • Uma regressão mostra que a tendência linear explica bastante a variação do PIB per capita americano no período.
  • Isso é captado por um \(R^2\) próximo de 1, nos próximos capítulos vamos discutir melhor o significado do \(R^2\).

Iterações com purrr

  • A regressão é feita com a função lm().
reg.US <- lm(pib_pc ~ year, data=dados.reg.US)

Iterações com purrr

summary(reg.US)
## 
## Call:
## lm(formula = pib_pc ~ year, data = dados.reg.US)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.09562 -0.04831  0.02185  0.04120  0.07516 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept) -30.270695   0.609239  -49.69   <2e-16 ***
## year          0.020510   0.000307   66.81   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.0519 on 68 degrees of freedom
## Multiple R-squared:  0.985,  Adjusted R-squared:  0.9848 
## F-statistic:  4464 on 1 and 68 DF,  p-value: < 2.2e-16

Iterações com purrr

  • A função glance() do pacote broom cria um data.frame com as estatísticas da regressão.

Iterações com purrr

library(broom)
glance(reg.US)
## # A tibble: 1 × 12
##   r.squared adj.r.squared  sigma statistic  p.value    df logLik   AIC   BIC
##       <dbl>         <dbl>  <dbl>     <dbl>    <dbl> <dbl>  <dbl> <dbl> <dbl>
## 1     0.985         0.985 0.0519     4464. 9.55e-64     1   109. -212. -205.
## # ℹ 3 more variables: deviance <dbl>, df.residual <int>, nobs <int>

Iterações com purrr

  • Podemos fazer a mesma coisa para o Brasil
## # A tibble: 1 × 12
##   r.squared adj.r.squared sigma statistic  p.value    df logLik   AIC   BIC
##       <dbl>         <dbl> <dbl>     <dbl>    <dbl> <dbl>  <dbl> <dbl> <dbl>
## 1     0.874         0.872 0.187      471. 2.81e-32     1   19.2 -32.4 -25.7
## # ℹ 3 more variables: deviance <dbl>, df.residual <int>, nobs <int>

Iterações com purrr

  • Como esperado, o \(R^2\) da regressão com dados brasileiros é menor do que o da regressão com dados americanos.
  • Para seguir com o exercício vamos fazer uma regressão entre logaritmo do PIB per capita e umam tendência linear para cada país da amostra, agrupar os países por renda e compara a média do \(R^2\) em cada grupo.
  • Usaremos as funções, nest(), mutate(), map(), glance() e unnest().

Iterações com purrr

  • Preparar os dados:
reg_purr <- pwt %>%
  select(code = countrycode, ano = year, pib = rgdpna, pop) %>%
  filter(code %in% pop5_1960, ano >= 1960) %>%
  mutate(l_pib.pc = log(pib/pop)) %>%
  select(-pib, -pop)

Iterações com purrr

Iterações com purrr

  • Função nest():
reg_purr <- pwt %>%
  select(code = countrycode, ano = year, pib = rgdpna, pop) %>%
  filter(code %in% pop5_1960, ano >= 1960) %>%
  mutate(l_pib.pc = log(pib/pop)) %>%
  select(-pib, -pop) %>% 
  nest(data = -code)

Iterações com purrr

Iterações com purrr

  • Funções mutate(), map() e glance():
reg_purr <- pwt %>%
  select(code = countrycode, ano = year, pib = rgdpna, pop) %>%
  filter(code %in% pop5_1960, ano >= 1960) %>%
  mutate(l_pib.pc = log(pib/pop)) %>%
  select(-pib, -pop) %>%
  nest(data = -code) %>%
  mutate(fit = map(data, ~ lm(l_pib.pc ~ ano, data = .x)),
                   glanced = map(fit, glance))

Iterações com purrr

Iterações com purrr

  • Função unnest():
reg_purr <- pwt %>%
  select(code = countrycode, ano = year, pib = rgdpna, pop) %>%
  filter(code %in% pop5_1960, ano >= 1960) %>%
  mutate(l_pib.pc = log(pib/pop)) %>%
  select(-pib, -pop) %>%
  nest(data = -code) %>%
  mutate(fit = map(data, ~ lm(l_pib.pc ~ ano, data = .x)),
                   glanced = map(fit, glance)) %>%
  unnest(glanced)

Iterações com purrr

Iterações com purrr

  • Terminar a preparação dos dados:
reg_purr <- pwt %>%
  select(code = countrycode, ano = year, pib = rgdpna, pop) %>%
  filter(code %in% pop5_1960, ano >= 1960) %>%
  mutate(l_pib.pc = log(pib/pop)) %>%
  select(-pib, -pop) %>%
  nest(data = -code) %>%
  mutate(fit = map(data, ~ lm(l_pib.pc ~ ano, data = .x)),
                   glanced = map(fit, glance)) %>%
  unnest(glanced) %>%
  select(code, r2 = r.squared)

Iterações com purrr

Iterações com purrr

  • Grupos de países:
df_grupos <- pwt %>%
  select(code = countrycode, pais = country, ano = year, grupo = group) %>%
  filter(code %in% pop5_1960, ano == 2010) %>%
  select(code, pais, grupo) %>%
  mutate(grupo2 = case_when(grupo == "Advanced" ~ "Países Ricos",
                            grupo %in% c("Emerging Asia", "Latin America and Caribbean", 
                                         "Emerging Europe") ~ "Emergentes",
                            TRUE ~ "Outros"),
         grupo2 = as.factor(grupo2))

Iterações com purrr

Iterações com purrr

  • Juntar os data.frames com a função left_join(), voltaremos as funções do tipo _join() nas próximas unidades:
df_r2 <- left_join(df_grupos, reg_purr, by = "code")

Iterações com purrr

Iterações com purrr

  • Obter a média dos \(R^2\) para cada grupo de países:
df_r2 %>%
  group_by(grupo2) %>%
  summarise(media_r2 = mean(r2))
## # A tibble: 3 × 2
##   grupo2       media_r2
##   <fct>           <dbl>
## 1 Emergentes      0.826
## 2 Outros          0.625
## 3 Países Ricos    0.934