Capítulo 45 Manipulação de dados

45.1 Tibbles

Tibbles são uma versão moderna e melhorada dos data frames em R, introduzida pelo pacote tibble, que faz parte do tidyverse — um conjunto de pacotes desenvolvido para facilitar a ciência de dados em R. Os tibbles foram projetados para ultrapassar algumas das limitações dos data frames tradicionais, oferecendo uma estrutura de dados mais robusta e intuitiva para manipulação e análise de dados.

Diferenças Principais entre Tibble e Data Frame

Os tibbles têm várias vantagens em relação aos data frames, especialmente em termos de usabilidade e integração com o tidyverse. A tabela abaixo resume as principais diferenças:

Característica Data Frame Tibble
Impressão no Console Exibe todos os dados Exibe um resumo com 10 linhas e colunas visíveis
Conversão de Strings Converte strings para fatores por padrão Mantém strings como caracteres
Manuseio de Colunas Apenas vetores, listas podem ser problemáticas Permite listas, funções, outros tibbles
Nomes de Colunas Nomes devem ser únicos e sem espaços Nomes podem ter espaços, ser duplicados, etc.
Retorno de Subsetting ([) Pode retornar um vetor ou data frame Sempre retorna um tibble
Compatibilidade e Integração Totalmente compatível com base R Compatível, mas otimizado para uso com tidyverse
Manipulação de Dados Menos intuitivo para algumas operações. Mais intuitivo e fácil de usar, especialmente com operações encadeadas.

45.1.1 Criar e trabalhar com Tibbles

Criar um tibble é semelhante a criar um data frame, mas com uma sintaxe ligeiramente diferente que facilita a criação de colunas complexas.

# Carregar o pacote tibble
library(tibble)

# Criando um tibble
tb <- tibble(
  x = 1:5,
  y = c("A", "B", "C", "D", "E"),
  z = x * 2
)

print(tb)
## # A tibble: 5 × 3
##       x y         z
##   <int> <chr> <dbl>
## 1     1 A         2
## 2     2 B         4
## 3     3 C         6
## 4     4 D         8
## 5     5 E        10

Também pode converter um data frame existente para um tibble usando a função as_tibble():

# Criar um data frame
df <- data.frame(
  x = 1:5,
  y = c("A", "B", "C", "D", "E")
)

# Converter para tibble
tb <- as_tibble(df)

print(tb)
## # A tibble: 5 × 2
##       x y    
##   <int> <chr>
## 1     1 A    
## 2     2 B    
## 3     3 C    
## 4     4 D    
## 5     5 E

45.2 Manipulação de Dados com dplyr

O dplyr é um pacote fundamental no tidyverse para manipulação de dados em R. Ele proporciona uma sintaxe mais limpa e legível para operações comuns em data frames e tibbles, como seleção, filtragem, mutação (criação/modificação de colunas), ordenação e agrupamento de dados.

As principais funções do dplyr são:

  • select(): Seleciona colunas de um data frame.
  • arrange(): Ordena as linhas de um data frame com base nos valores de uma ou mais colunas.
  • filter(): Filtra linhas com base em condições lógicas.
  • mutate(): Adiciona novas colunas ou modifica colunas existentes.
  • group_by(): Agrupa os dados com base nos valores de uma ou mais colunas.
  • summarise(): Resuma os dados, tipicamente usado após group_by() para calcular estatísticas agregadas.

Vamos explorar cada uma dessas funções usando o dataset starwars disponível no pacote dplyr.

Assim, utilizaremos o objeto sw para acessar os dados.

library(dplyr)

# Carregar o dataset Star Wars
sw <- starwars
glimpse(sw) # Exibe uma visão geral dos dados
## Rows: 87
## Columns: 14
## $ name       <chr> "Luke Skywalker", "C-3PO", "R2-D2", "Darth Vader", "Leia Or…
## $ height     <int> 172, 167, 96, 202, 150, 178, 165, 97, 183, 182, 188, 180, 2…
## $ mass       <dbl> 77.0, 75.0, 32.0, 136.0, 49.0, 120.0, 75.0, 32.0, 84.0, 77.…
## $ hair_color <chr> "blond", NA, NA, "none", "brown", "brown, grey", "brown", N…
## $ skin_color <chr> "fair", "gold", "white, blue", "white", "light", "light", "…
## $ eye_color  <chr> "blue", "yellow", "red", "yellow", "brown", "blue", "blue",…
## $ birth_year <dbl> 19.0, 112.0, 33.0, 41.9, 19.0, 52.0, 47.0, NA, 24.0, 57.0, …
## $ sex        <chr> "male", "none", "none", "male", "female", "male", "female",…
## $ gender     <chr> "masculine", "masculine", "masculine", "masculine", "femini…
## $ homeworld  <chr> "Tatooine", "Tatooine", "Naboo", "Tatooine", "Alderaan", "T…
## $ species    <chr> "Human", "Droid", "Droid", "Human", "Human", "Human", "Huma…
## $ films      <list> <"A New Hope", "The Empire Strikes Back", "Return of the J…
## $ vehicles   <list> <"Snowspeeder", "Imperial Speeder Bike">, <>, <>, <>, "Imp…
## $ starships  <list> <"X-wing", "Imperial shuttle">, <>, <>, "TIE Advanced x1",…

45.2.1 Seleção de Colunas com select()

A função select() é usada para selecionar uma ou mais colunas de um tibble ou data frame. Pode usar nomes de colunas diretamente sem aspas.

# Selecionar uma coluna
select(sw, name)
## # A tibble: 87 × 1
##    name              
##    <chr>             
##  1 Luke Skywalker    
##  2 C-3PO             
##  3 R2-D2             
##  4 Darth Vader       
##  5 Leia Organa       
##  6 Owen Lars         
##  7 Beru Whitesun Lars
##  8 R5-D4             
##  9 Biggs Darklighter 
## 10 Obi-Wan Kenobi    
## # ℹ 77 more rows
# Selecionar várias colunas
select(sw, name, mass, hair_color)
## # A tibble: 87 × 3
##    name                mass hair_color   
##    <chr>              <dbl> <chr>        
##  1 Luke Skywalker        77 blond        
##  2 C-3PO                 75 <NA>         
##  3 R2-D2                 32 <NA>         
##  4 Darth Vader          136 none         
##  5 Leia Organa           49 brown        
##  6 Owen Lars            120 brown, grey  
##  7 Beru Whitesun Lars    75 brown        
##  8 R5-D4                 32 <NA>         
##  9 Biggs Darklighter     84 black        
## 10 Obi-Wan Kenobi        77 auburn, white
## # ℹ 77 more rows
# Selecionar um intervalo de colunas
select(sw, name:hair_color)
## # A tibble: 87 × 4
##    name               height  mass hair_color   
##    <chr>               <int> <dbl> <chr>        
##  1 Luke Skywalker        172    77 blond        
##  2 C-3PO                 167    75 <NA>         
##  3 R2-D2                  96    32 <NA>         
##  4 Darth Vader           202   136 none         
##  5 Leia Organa           150    49 brown        
##  6 Owen Lars             178   120 brown, grey  
##  7 Beru Whitesun Lars    165    75 brown        
##  8 R5-D4                  97    32 <NA>         
##  9 Biggs Darklighter     183    84 black        
## 10 Obi-Wan Kenobi        182    77 auburn, white
## # ℹ 77 more rows

O dplyr possui um conjunto de funções auxiliares muito úteis para seleção de colunas. As principais são:

  • starts_with(): para colunas que começam com um texto específico.
  • ends_with(): para colunas que terminam com um texto específico.
  • contains(): para colunas que contêm um texto específico.
# Selecionar colunas que terminam com "color"
select(sw, ends_with("color"))
## # A tibble: 87 × 3
##    hair_color    skin_color  eye_color
##    <chr>         <chr>       <chr>    
##  1 blond         fair        blue     
##  2 <NA>          gold        yellow   
##  3 <NA>          white, blue red      
##  4 none          white       yellow   
##  5 brown         light       brown    
##  6 brown, grey   light       blue     
##  7 brown         light       blue     
##  8 <NA>          white, red  red      
##  9 black         light       brown    
## 10 auburn, white fair        blue-gray
## # ℹ 77 more rows

Para remover colunas, basta acrescentar um - antes da seleção.

select(sw, -name, -hair_color)
## # A tibble: 87 × 12
##    height  mass skin_color  eye_color birth_year sex    gender homeworld species
##     <int> <dbl> <chr>       <chr>          <dbl> <chr>  <chr>  <chr>     <chr>  
##  1    172    77 fair        blue            19   male   mascu… Tatooine  Human  
##  2    167    75 gold        yellow         112   none   mascu… Tatooine  Droid  
##  3     96    32 white, blue red             33   none   mascu… Naboo     Droid  
##  4    202   136 white       yellow          41.9 male   mascu… Tatooine  Human  
##  5    150    49 light       brown           19   female femin… Alderaan  Human  
##  6    178   120 light       blue            52   male   mascu… Tatooine  Human  
##  7    165    75 light       blue            47   female femin… Tatooine  Human  
##  8     97    32 white, red  red             NA   none   mascu… Tatooine  Droid  
##  9    183    84 light       brown           24   male   mascu… Tatooine  Human  
## 10    182    77 fair        blue-gray       57   male   mascu… Stewjon   Human  
## # ℹ 77 more rows
## # ℹ 3 more variables: films <list>, vehicles <list>, starships <list>
# Remover múltiplas colunas
select(sw, -ends_with("color"))
## # A tibble: 87 × 11
##    name    height  mass birth_year sex   gender homeworld species films vehicles
##    <chr>    <int> <dbl>      <dbl> <chr> <chr>  <chr>     <chr>   <lis> <list>  
##  1 Luke S…    172    77       19   male  mascu… Tatooine  Human   <chr> <chr>   
##  2 C-3PO      167    75      112   none  mascu… Tatooine  Droid   <chr> <chr>   
##  3 R2-D2       96    32       33   none  mascu… Naboo     Droid   <chr> <chr>   
##  4 Darth …    202   136       41.9 male  mascu… Tatooine  Human   <chr> <chr>   
##  5 Leia O…    150    49       19   fema… femin… Alderaan  Human   <chr> <chr>   
##  6 Owen L…    178   120       52   male  mascu… Tatooine  Human   <chr> <chr>   
##  7 Beru W…    165    75       47   fema… femin… Tatooine  Human   <chr> <chr>   
##  8 R5-D4       97    32       NA   none  mascu… Tatooine  Droid   <chr> <chr>   
##  9 Biggs …    183    84       24   male  mascu… Tatooine  Human   <chr> <chr>   
## 10 Obi-Wa…    182    77       57   male  mascu… Stewjon   Human   <chr> <chr>   
## # ℹ 77 more rows
## # ℹ 1 more variable: starships <list>

45.2.2 Exercícios

Utilize a base sw nos exercícios a seguir.

1. Utilize a função glimpse() do pacote dplyr na base sw. O que ela faz?

2. Crie uma tabela chamada sw_simples contendo apenas as colunas name, gender e films.

3. Selecione apenas as colunas hair_color, skin_color e eye_color usando a função auxiliar contains().

4. Usando a função select() e as suas funções auxiliares, escreva códigos que retornem a base sw sem as colunas hair_color, skin_color e eye_color. Escreva todas as soluções diferentes que conseguir pensar.

45.2.3 Ordenando a Base de Dados

A função arrange() permite ordenar as linhas de uma tabela com base nos valores de uma ou mais colunas. Pode ordenar em ordem crescente ou decrescente, conforme a necessidade.

# Exemplo de ordenação crescente
arrange(sw, mass)
## # A tibble: 87 × 14
##    name     height  mass hair_color skin_color eye_color birth_year sex   gender
##    <chr>     <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr> 
##  1 Ratts T…     79    15 none       grey, blue unknown           NA male  mascu…
##  2 Yoda         66    17 white      green      brown            896 male  mascu…
##  3 Wicket …     88    20 brown      brown      brown              8 male  mascu…
##  4 R2-D2        96    32 <NA>       white, bl… red               33 none  mascu…
##  5 R5-D4        97    32 <NA>       white, red red               NA none  mascu…
##  6 Sebulba     112    40 none       grey, red  orange            NA male  mascu…
##  7 Padmé A…    185    45 brown      light      brown             46 fema… femin…
##  8 Dud Bolt     94    45 none       blue, grey yellow            NA male  mascu…
##  9 Wat Tam…    193    48 none       green, gr… unknown           NA male  mascu…
## 10 Sly Moo…    178    48 none       pale       white             NA <NA>  <NA>  
## # ℹ 77 more rows
## # ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
## #   vehicles <list>, starships <list>
# Exemplo de ordenação decrescente
arrange(sw, desc(mass))
## # A tibble: 87 × 14
##    name     height  mass hair_color skin_color eye_color birth_year sex   gender
##    <chr>     <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr> 
##  1 Jabba D…    175  1358 <NA>       green-tan… orange         600   herm… mascu…
##  2 Grievous    216   159 none       brown, wh… green, y…       NA   male  mascu…
##  3 IG-88       200   140 none       metal      red             15   none  mascu…
##  4 Darth V…    202   136 none       white      yellow          41.9 male  mascu…
##  5 Tarfful     234   136 brown      brown      blue            NA   male  mascu…
##  6 Owen La…    178   120 brown, gr… light      blue            52   male  mascu…
##  7 Bossk       190   113 none       green      red             53   male  mascu…
##  8 Chewbac…    228   112 brown      unknown    blue           200   male  mascu…
##  9 Jek Ton…    180   110 brown      fair       blue            NA   <NA>  <NA>  
## 10 Dexter …    198   102 none       brown      yellow          NA   male  mascu…
## # ℹ 77 more rows
## # ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
## #   vehicles <list>, starships <list>
# Ordenar por múltiplas colunas
arrange(sw, desc(height), desc(mass))
## # A tibble: 87 × 14
##    name     height  mass hair_color skin_color eye_color birth_year sex   gender
##    <chr>     <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr> 
##  1 Yarael …    264    NA none       white      yellow          NA   male  mascu…
##  2 Tarfful     234   136 brown      brown      blue            NA   male  mascu…
##  3 Lama Su     229    88 none       grey       black           NA   male  mascu…
##  4 Chewbac…    228   112 brown      unknown    blue           200   male  mascu…
##  5 Roos Ta…    224    82 none       grey       orange          NA   male  mascu…
##  6 Grievous    216   159 none       brown, wh… green, y…       NA   male  mascu…
##  7 Taun We     213    NA none       grey       black           NA   fema… femin…
##  8 Tion Me…    206    80 none       grey       black           NA   male  mascu…
##  9 Rugor N…    206    NA none       green      orange          NA   male  mascu…
## 10 Darth V…    202   136 none       white      yellow          41.9 male  mascu…
## # ℹ 77 more rows
## # ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
## #   vehicles <list>, starships <list>

45.2.4 Exercícios

1. Ordene a base sw pela coluna mass em ordem crescente e pela coluna birth_year em ordem decrescente. Guarde o resultado em um objeto chamado sw_ordenados.

sw_ordenados <- arrange(sw, mass, desc(birth_year))
sw_ordenados

2. Selecione apenas as colunas name e birth_year, então ordene de forma decrescente pelo birth_year.

# Usando aninhamento de funções
arrange(select(sw, name, birth_year), desc(birth_year))

# Usando um objeto intermediário
sw_aux <- select(sw, name, birth_year)
arrange(sw_aux, desc(birth_year))

# Usando pipes para simplificar
sw %>% 
  select(name, birth_year) %>% 
  arrange(desc(birth_year))

45.2.5 Filtrando Linhas da Base de Dados

Para selecionar linhas específicas com base em uma ou mais condições, utilizamos a função filter().

# filter(sw, height > 170)
# Ou
sw %>% filter(height > 170)
## # A tibble: 55 × 14
##    name     height  mass hair_color skin_color eye_color birth_year sex   gender
##    <chr>     <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr> 
##  1 Luke Sk…    172    77 blond      fair       blue            19   male  mascu…
##  2 Darth V…    202   136 none       white      yellow          41.9 male  mascu…
##  3 Owen La…    178   120 brown, gr… light      blue            52   male  mascu…
##  4 Biggs D…    183    84 black      light      brown           24   male  mascu…
##  5 Obi-Wan…    182    77 auburn, w… fair       blue-gray       57   male  mascu…
##  6 Anakin …    188    84 blond      fair       blue            41.9 male  mascu…
##  7 Wilhuff…    180    NA auburn, g… fair       blue            64   male  mascu…
##  8 Chewbac…    228   112 brown      unknown    blue           200   male  mascu…
##  9 Han Solo    180    80 brown      fair       brown           29   male  mascu…
## 10 Greedo      173    74 <NA>       green      black           44   male  mascu…
## # ℹ 45 more rows
## # ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
## #   vehicles <list>, starships <list>

Podemos selecionar apenas as colunas name e height para visualizarmos as alturas:

sw %>% 
  filter(height > 170) %>% 
  select(name, height)
## # A tibble: 55 × 2
##    name              height
##    <chr>              <int>
##  1 Luke Skywalker       172
##  2 Darth Vader          202
##  3 Owen Lars            178
##  4 Biggs Darklighter    183
##  5 Obi-Wan Kenobi       182
##  6 Anakin Skywalker     188
##  7 Wilhuff Tarkin       180
##  8 Chewbacca            228
##  9 Han Solo             180
## 10 Greedo               173
## # ℹ 45 more rows

Podemos estender o filtro para duas ou mais colunas.

filter(sw, height>170, mass>80)
## # A tibble: 21 × 14
##    name     height  mass hair_color skin_color eye_color birth_year sex   gender
##    <chr>     <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr> 
##  1 Darth V…    202   136 none       white      yellow          41.9 male  mascu…
##  2 Owen La…    178   120 brown, gr… light      blue            52   male  mascu…
##  3 Biggs D…    183    84 black      light      brown           24   male  mascu…
##  4 Anakin …    188    84 blond      fair       blue            41.9 male  mascu…
##  5 Chewbac…    228   112 brown      unknown    blue           200   male  mascu…
##  6 Jabba D…    175  1358 <NA>       green-tan… orange         600   herm… mascu…
##  7 Jek Ton…    180   110 brown      fair       blue            NA   <NA>  <NA>  
##  8 IG-88       200   140 none       metal      red             15   none  mascu…
##  9 Bossk       190   113 none       green      red             53   male  mascu…
## 10 Ackbar      180    83 none       brown mot… orange          41   male  mascu…
## # ℹ 11 more rows
## # ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
## #   vehicles <list>, starships <list>
sw %>% filter(height > 170, mass > 80)
## # A tibble: 21 × 14
##    name     height  mass hair_color skin_color eye_color birth_year sex   gender
##    <chr>     <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr> 
##  1 Darth V…    202   136 none       white      yellow          41.9 male  mascu…
##  2 Owen La…    178   120 brown, gr… light      blue            52   male  mascu…
##  3 Biggs D…    183    84 black      light      brown           24   male  mascu…
##  4 Anakin …    188    84 blond      fair       blue            41.9 male  mascu…
##  5 Chewbac…    228   112 brown      unknown    blue           200   male  mascu…
##  6 Jabba D…    175  1358 <NA>       green-tan… orange         600   herm… mascu…
##  7 Jek Ton…    180   110 brown      fair       blue            NA   <NA>  <NA>  
##  8 IG-88       200   140 none       metal      red             15   none  mascu…
##  9 Bossk       190   113 none       green      red             53   male  mascu…
## 10 Ackbar      180    83 none       brown mot… orange          41   male  mascu…
## # ℹ 11 more rows
## # ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
## #   vehicles <list>, starships <list>

Podemos filtrar colunas categóricas. O exemplo abaixo retorna uma tabela apenas com os personagens com cabelo preto ou castanho.

# Filtrar texto com correspondência exata
filter(sw, hair_color == "black" | hair_color == "brown")
## # A tibble: 31 × 14
##    name     height  mass hair_color skin_color eye_color birth_year sex   gender
##    <chr>     <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr> 
##  1 Leia Or…    150  49   brown      light      brown           19   fema… femin…
##  2 Beru Wh…    165  75   brown      light      blue            47   fema… femin…
##  3 Biggs D…    183  84   black      light      brown           24   male  mascu…
##  4 Chewbac…    228 112   brown      unknown    blue           200   male  mascu…
##  5 Han Solo    180  80   brown      fair       brown           29   male  mascu…
##  6 Wedge A…    170  77   brown      fair       hazel           21   male  mascu…
##  7 Jek Ton…    180 110   brown      fair       blue            NA   <NA>  <NA>  
##  8 Boba Fe…    183  78.2 black      fair       brown           31.5 male  mascu…
##  9 Lando C…    177  79   black      dark       brown           31   male  mascu…
## 10 Arvel C…     NA  NA   brown      fair       brown           NA   male  mascu…
## # ℹ 21 more rows
## # ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
## #   vehicles <list>, starships <list>
# Filtrar texto com correspondência exata
sw %>% filter(hair_color %in% c("black","brown"))
## # A tibble: 31 × 14
##    name     height  mass hair_color skin_color eye_color birth_year sex   gender
##    <chr>     <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr> 
##  1 Leia Or…    150  49   brown      light      brown           19   fema… femin…
##  2 Beru Wh…    165  75   brown      light      blue            47   fema… femin…
##  3 Biggs D…    183  84   black      light      brown           24   male  mascu…
##  4 Chewbac…    228 112   brown      unknown    blue           200   male  mascu…
##  5 Han Solo    180  80   brown      fair       brown           29   male  mascu…
##  6 Wedge A…    170  77   brown      fair       hazel           21   male  mascu…
##  7 Jek Ton…    180 110   brown      fair       blue            NA   <NA>  <NA>  
##  8 Boba Fe…    183  78.2 black      fair       brown           31.5 male  mascu…
##  9 Lando C…    177  79   black      dark       brown           31   male  mascu…
## 10 Arvel C…     NA  NA   brown      fair       brown           NA   male  mascu…
## # ℹ 21 more rows
## # ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
## #   vehicles <list>, starships <list>

Para filtrar textos sem correspondência exata, podemos utilizar a função auxiliar str_detect() do pacote {stringr}. Ela serve para verificar se cada string de um vetor contém um determinado padrão de texto.

library(stringr)

str_detect(
  string = c("a", "aa","abc", "bc", "A", NA), 
  pattern = "a"
)
## [1]  TRUE  TRUE  TRUE FALSE FALSE    NA

Podemos utilizá-la para filtrar apenas os personagens com cabelo grey.

# Podemos detetar se o cabelo grey aparece na string
str_detect(
  string = sw$hair_color,
  pattern = "grey"
)
##  [1] FALSE    NA    NA FALSE FALSE  TRUE FALSE    NA FALSE FALSE FALSE  TRUE
## [13] FALSE FALSE    NA    NA FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE
## [25] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [37] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [49] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [61] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [73] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [85] FALSE FALSE FALSE
library(stringr)
sw %>% filter(str_detect(hair_color,"grey"))
## # A tibble: 3 × 14
##   name      height  mass hair_color skin_color eye_color birth_year sex   gender
##   <chr>      <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr> 
## 1 Owen Lars    178   120 brown, gr… light      blue              52 male  mascu…
## 2 Wilhuff …    180    NA auburn, g… fair       blue              64 male  mascu…
## 3 Palpatine    170    75 grey       pale       yellow            82 male  mascu…
## # ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
## #   vehicles <list>, starships <list>

45.2.6 Exercícios

Utilize a base sw nos exercícios a seguir.

1. Crie um objeto chamado humanos apenas com personagens que sejam humanos.

2. Crie um objeto chamado altos_fortes com personagens que tenham mais de 200 cm de altura e peso maior que 100 kg.

3. Retorne tabelas (tibbles) apenas com:

a. Personagens humanos que nasceram antes de 100 anos antes da batalha de Yavin (birth_year < 100).

b. Personagens com cor light ou red.

c. Personagens com massa maior que 100 kg, ordenados de forma decrescente por altura, mostrando apenas as colunas name, mass e height.

d. Personagens que sejam “Humano” ou “Droid”, e tenham uma altura maior que 170 cm.

e. Personagens que não possuem informação tanto de altura (height) quanto de massa (mass), ou seja, possuem NA em ambas as colunas.

45.2.7 Modificar e criar novas colunas

A função mutate() permite criar novas colunas ou modificar colunas existentes, facilitando transformações de dados. O código abaixo divide os valores da coluna height por 100, mudando a unidade de medida dessa variável de centímetros para metros.

# Modificar a unidade de medida da coluna height
sw %>% mutate(height = height/100)
## # A tibble: 87 × 14
##    name     height  mass hair_color skin_color eye_color birth_year sex   gender
##    <chr>     <dbl> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr> 
##  1 Luke Sk…   1.72    77 blond      fair       blue            19   male  mascu…
##  2 C-3PO      1.67    75 <NA>       gold       yellow         112   none  mascu…
##  3 R2-D2      0.96    32 <NA>       white, bl… red             33   none  mascu…
##  4 Darth V…   2.02   136 none       white      yellow          41.9 male  mascu…
##  5 Leia Or…   1.5     49 brown      light      brown           19   fema… femin…
##  6 Owen La…   1.78   120 brown, gr… light      blue            52   male  mascu…
##  7 Beru Wh…   1.65    75 brown      light      blue            47   fema… femin…
##  8 R5-D4      0.97    32 <NA>       white, red red             NA   none  mascu…
##  9 Biggs D…   1.83    84 black      light      brown           24   male  mascu…
## 10 Obi-Wan…   1.82    77 auburn, w… fair       blue-gray       57   male  mascu…
## # ℹ 77 more rows
## # ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
## #   vehicles <list>, starships <list>

Também poderíamos ter criado essa variável em uma nova coluna. Repare que a nova coluna height_meters é colocada no final da tabela.

sw %>% mutate(height_meters = height/100)
## # A tibble: 87 × 15
##    name     height  mass hair_color skin_color eye_color birth_year sex   gender
##    <chr>     <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr> 
##  1 Luke Sk…    172    77 blond      fair       blue            19   male  mascu…
##  2 C-3PO       167    75 <NA>       gold       yellow         112   none  mascu…
##  3 R2-D2        96    32 <NA>       white, bl… red             33   none  mascu…
##  4 Darth V…    202   136 none       white      yellow          41.9 male  mascu…
##  5 Leia Or…    150    49 brown      light      brown           19   fema… femin…
##  6 Owen La…    178   120 brown, gr… light      blue            52   male  mascu…
##  7 Beru Wh…    165    75 brown      light      blue            47   fema… femin…
##  8 R5-D4        97    32 <NA>       white, red red             NA   none  mascu…
##  9 Biggs D…    183    84 black      light      brown           24   male  mascu…
## 10 Obi-Wan…    182    77 auburn, w… fair       blue-gray       57   male  mascu…
## # ℹ 77 more rows
## # ℹ 6 more variables: homeworld <chr>, species <chr>, films <list>,
## #   vehicles <list>, starships <list>, height_meters <dbl>

Podemos fazer qualquer operação com uma ou mais colunas. Abaixo vamos criar um tibble que contenha as colunas name, height, mass, e uma nova coluna BMI, que calcule o Índice de Massa Corporal (IMC) de cada personagem, usando a fórmula mass / (height/100)^2. Caso height ou mass seja NA, a coluna BMI deve ser NA.

sw %>%
  mutate(BMI = ifelse(!is.na(height) & !is.na(mass), mass / (height/100)^2, NA)) %>%
  select(name, height, mass, BMI)
## # A tibble: 87 × 4
##    name               height  mass   BMI
##    <chr>               <int> <dbl> <dbl>
##  1 Luke Skywalker        172    77  26.0
##  2 C-3PO                 167    75  26.9
##  3 R2-D2                  96    32  34.7
##  4 Darth Vader           202   136  33.3
##  5 Leia Organa           150    49  21.8
##  6 Owen Lars             178   120  37.9
##  7 Beru Whitesun Lars    165    75  27.5
##  8 R5-D4                  97    32  34.0
##  9 Biggs Darklighter     183    84  25.1
## 10 Obi-Wan Kenobi        182    77  23.2
## # ℹ 77 more rows

45.2.8 Exercícios

1. Crie uma coluna chamada dif_peso_altura (diferença entre altura e peso) e salve a nova tabela em um objeto chamado starwars_dif. Em seguida, filtre apenas os personagens que têm altura maior que o peso e ordene a tabela por ordem crescente de dif_peso_altura.

2. Crie as seguintes colunas:

a. indice_massa_altura = mass / height

b. indice_massa_medio = mean(mass, na.rm = TRUE)

c. indice_relativo = (indice_massa_altura - indice_massa_medio) / indice_massa_medio

d. acima_media = ifelse(indice_massa_altura > indice_massa_medio, “sim”, “não”)

3. Crie uma nova coluna que classifique o personagem em “recente” (nascido após 100 anos antes da batalha de Yavin) e “antigo” (nascido há 100 anos ou mais).

45.2.9 Sumarizar a Base de Dados

A função summarize() permite calcular estatísticas agregadas, como média, mediana, variância, etc. Para agregar dados por categorias, combinamos summarize() com group_by().

O código abaixo resume a coluna mass pela sua média.

# Exemplo de sumarização
sw %>% summarize(media_massa = mean(mass, na.rm = TRUE))
## # A tibble: 1 × 1
##   media_massa
##         <dbl>
## 1        97.3
# Sumarização agrupada por categorias
sw %>%
  group_by(species) %>%
  summarize(media_massa = mean(mass, na.rm = TRUE))
## # A tibble: 38 × 2
##    species   media_massa
##    <chr>           <dbl>
##  1 Aleena           15  
##  2 Besalisk        102  
##  3 Cerean           82  
##  4 Chagrian        NaN  
##  5 Clawdite         55  
##  6 Droid            69.8
##  7 Dug              40  
##  8 Ewok             20  
##  9 Geonosian        80  
## 10 Gungan           74  
## # ℹ 28 more rows

Podemos calcular ao mesmo tempo sumarizações diferentes.

sw %>% summarize(
  media_massa = mean(mass, na.rm = TRUE),
  mediana_massa = median(mass, na.rm = TRUE),
  variancia_massa = var(mass, na.rm = TRUE)
)
## # A tibble: 1 × 3
##   media_massa mediana_massa variancia_massa
##         <dbl>         <dbl>           <dbl>
## 1        97.3            79          28716.

Podemos também sumarizar diversas colunas.

sw %>% summarize(
  media_massa = mean(mass, na.rm = TRUE),
  media_altura = mean(height, na.rm = TRUE),
  media_ano = mean(birth_year, na.rm = TRUE)
)
## # A tibble: 1 × 3
##   media_massa media_altura media_ano
##         <dbl>        <dbl>     <dbl>
## 1        97.3         175.      87.6

Para sumarizar uma coluna agrupada pelas categorias de uma segunda coluna usamos além do summarize() a função group_by().

O código a abaixo calcula a altura média dos personagens para cada categoria da coluna hair_color.

sw %>% 
  filter(!is.na(hair_color), !is.na(height)) %>% 
  group_by(hair_color) %>% 
  summarize(media_altura = mean(height, na.rm = TRUE))
## # A tibble: 11 × 2
##    hair_color    media_altura
##    <chr>                <dbl>
##  1 auburn                150 
##  2 auburn, grey          180 
##  3 auburn, white         182 
##  4 black                 174.
##  5 blond                 177.
##  6 blonde                168 
##  7 brown                 177.
##  8 brown, grey           178 
##  9 grey                  170 
## 10 none                  181.
## 11 white                 156

45.2.10 Exerícios

Utilize a base sw nos exercícios a seguir.

1. Calcule a altura média e mediana dos personagens.

2. Calcule a massa média dos personagens cuja altura é maior que 175 cm.

3. Apresente na mesma tabela a massa média dos personagens com altura menor que 175 cm e a massa média dos personagens com altura maior ou igual a 175 cm.

4. Retorne tabelas (tibbles) apenas com:

a. A altura média dos personagens por espécie. b. A massa média e mediana dos personagens por espécie. c. Apenas o nome dos personagens que participaram de mais de 2 filmes.

45.2.11 Juntando Tabelas em R com dplyr

Em ciência de dados, é comum precisar combinar informações de diferentes fontes em uma única tabela. No R, o pacote dplyr oferece várias funções para realizar operações de junção, que permitem combinar duas ou mais tabelas (data frames ou tibbles) com base em uma ou mais colunas compartilhadas.

Tipos de Junção

As junções mais comuns em manipulação de dados são:

  • left_join(): Mantém todas as linhas da tabela à esquerda e adiciona as colunas da tabela à direita onde há correspondência de valores na coluna chave.
  • right_join(): Mantém todas as linhas da tabela à direita e adiciona as colunas da tabela à esquerda onde há correspondência.
  • full_join(): Mantém todas as linhas de ambas as tabelas e adiciona NA onde não há correspondência.

Essas funções são extremamente úteis quando é necessário combinar dados de diferentes fontes que compartilham uma chave comum, como um identificador único.

Exemplo: Personagens de Star Wars

Para ilustrar como estas funções funcionam, vamos usar a base de dados sw e criar dois subconjuntos de dados:

  1. personagens_altos: Tabela contendo apenas personagens com altura superior a 180 cm.
  2. personagens_humanos: Tabela contendo apenas personagens que são humanos.

Vamos criar os nossos subconjuntos de dados usando a função filter() do dplyr.

# Criar subconjunto de personagens altos (altura > 180 cm)
personagens_altos <- sw %>%
  filter(height > 180) %>%
  select(name, height)

# Criar subconjunto de personagens humanos
personagens_humanos <- sw %>%
  filter(species == "Human") %>%
  select(name, species)

Agora que temos duas tabelas, personagens_altos e personagens_humanos, podemos usar as funções de junção para combiná-las: left_join(), right_join(), e full_join().

A função left_join() junta duas tabelas, mantendo todas as linhas da tabela à esquerda (primeira tabela) e adicionando colunas da tabela à direita (segunda tabela) para as quais existe uma correspondência. Valores sem correspondência entre as bases receberão NA na nova base.

# Combinar tabelas mantendo todas as linhas de personagens_altos
humanos_altos_left_join <- left_join(personagens_altos, personagens_humanos, by = "name")

# Visualizar o resultado
print(humanos_altos_left_join)
## # A tibble: 39 × 3
##    name              height species
##    <chr>              <int> <chr>  
##  1 Darth Vader          202 Human  
##  2 Biggs Darklighter    183 Human  
##  3 Obi-Wan Kenobi       182 Human  
##  4 Anakin Skywalker     188 Human  
##  5 Chewbacca            228 <NA>   
##  6 Boba Fett            183 Human  
##  7 IG-88                200 <NA>   
##  8 Bossk                190 <NA>   
##  9 Qui-Gon Jinn         193 Human  
## 10 Nute Gunray          191 <NA>   
## # ℹ 29 more rows

Neste exemplo, a tabela resultante humanos_altos_left_join inclui todos os personagens altos e adiciona informações sobre a espécie (se disponível) da tabela personagens_humanos. Se um personagem não for humano, as colunas de espécie serão preenchidas com NA.

A função right_join() faz o oposto de left_join(): mantém todas as linhas da tabela à direita e adiciona colunas da tabela à esquerda para as quais existe uma correspondência.

# Combinar tabelas mantendo todas as linhas de personagens_humanos
humanos_altos_right_join <- right_join(personagens_altos, personagens_humanos, by = "name")

# Visualizar o resultado
print(humanos_altos_right_join)
## # A tibble: 35 × 3
##    name              height species
##    <chr>              <int> <chr>  
##  1 Darth Vader          202 Human  
##  2 Biggs Darklighter    183 Human  
##  3 Obi-Wan Kenobi       182 Human  
##  4 Anakin Skywalker     188 Human  
##  5 Boba Fett            183 Human  
##  6 Qui-Gon Jinn         193 Human  
##  7 Padmé Amidala        185 Human  
##  8 Ric Olié             183 Human  
##  9 Quarsh Panaka        183 Human  
## 10 Mace Windu           188 Human  
## # ℹ 25 more rows

A tabela humanos_altos_right_join inclui todos os personagens humanos e adiciona informações sobre a altura (se disponível) da tabela personagens_altos. Se um personagem humano não for alto, a coluna de altura será preenchida com NA.

A função full_join() mantém todas as linhas de ambas as tabelas e adiciona NA onde não há correspondência.

# Combinar todas as informações de personagens altos e humanos
humanos_altos_full_join <- full_join(personagens_altos, personagens_humanos, by = "name")

# Visualizar o resultado
print(humanos_altos_full_join)
## # A tibble: 59 × 3
##    name              height species
##    <chr>              <int> <chr>  
##  1 Darth Vader          202 Human  
##  2 Biggs Darklighter    183 Human  
##  3 Obi-Wan Kenobi       182 Human  
##  4 Anakin Skywalker     188 Human  
##  5 Chewbacca            228 <NA>   
##  6 Boba Fett            183 Human  
##  7 IG-88                200 <NA>   
##  8 Bossk                190 <NA>   
##  9 Qui-Gon Jinn         193 Human  
## 10 Nute Gunray          191 <NA>   
## # ℹ 49 more rows

A tabela humanos_altos_full_join contém todos os personagens altos e humanos. Se um personagem está em apenas uma das tabelas, as colunas da outra tabela são preenchidas com NA.

45.2.12 Exercícios

1. Crie uma tabela personagens_altos contendo apenas personagens com altura superior a 180 cm e uma outra tabela personagens_leves contendo apenas personagens com massa inferior a 75 kg. Use left_join() para combinar as duas tabelas com base no nome do personagem.

# Criação dos subconjuntos
personagens_altos <- sw %>% 
  filter(height > 180) %>% 
  select(name, height)

personagens_leves <- sw %>% 
  filter(mass < 75) %>% 
  select(name, mass)

# Combinação com left_join
left_join(personagens_altos, personagens_leves, by = "name")

Dica: Observe como left_join() mantém todos os personagens altos e adiciona informações sobre massa apenas para aqueles que também são leves.

2. Crie uma tabela personagens_humanos contendo apenas personagens humanos e uma outra tabela cor_cabelo contendo apenas personagens com cor de cabelo diferente de NA. Use right_join() para combinar personagens_humanos e cor_cabelo com base no nome do personagem.

# Criação dos subconjuntos
personagens_humanos <- sw %>% 
  filter(species == "Human") %>% 
  select(name, species)

cor_cabelo <- sw %>% 
  filter(!is.na(hair_color)) %>% 
  select(name, hair_color,)

# Combinação com right_join
right_join(personagens_humanos, cor_cabelo, by = "name")

Dica: Observe como right_join() mantém todos os personagens com cor de cabelo conhecida e adiciona informações sobre a espécie apenas para aqueles que também são humanos.

3. Crie uma tabela especies_personagens contendo apenas personagens de espécies conhecidas (não NA) e uma outra tabela cor_olhos contendo apenas personagens com cor de olho conhecida (não NA). Use full_join() para combinar as duas tabelas com base no nome do personagem.

# Criação dos subconjuntos
especies_personagens <- sw %>% 
  filter(!is.na(species)) %>% 
  select(name, species)

cor_olhos <- sw %>% 
  filter(!is.na(eye_color)) %>% 
  select(name, eye_color)

# Combinação com full_join
full_join(especies_personagens, cor_olhos, by = "name")

Dica: full_join() combina todas as informações disponíveis, preenchendo com NA onde não há correspondências.