Chapter 4 Módulo IV
Script da aula do Módulo IV abaixo. Download aula4.R
4.1 Manipulação de dados com dplyr
Nesta seção, trataremos do pacote dplyr
, que é um dos pacotes mais importantes da coleção tidyverse. Ele traz uma “gramática” específica de manipulação de dados, provendo um conjunto de funções que ajudam a resolver os desafios mais comuns na manipulação de dados. O objetivo é que você se familiarize com as funções do pacote dplyr
; com as tarefas que elas executam; e veja exemplos de como aplicá-las a data.frames.
Para tanto vamos utilizar três datasets que vamos citar e descrever abaixo:
- Chess game dataset
Este é um conjunto de pouco mais de 20.000 jogos coletados de uma seleção de usuários no site Lichess.org
.
<- read_csv(file="https://raw.githubusercontent.com/brunolucian/cursoBasicoR/master/datasets/chess_games.csv") tb_chess_game
##
## -- Column specification ---------------------------------------------------------------------------------------
## cols(
## id = col_character(),
## rated = col_logical(),
## created_at = col_double(),
## last_move_at = col_double(),
## turns = col_double(),
## victory_status = col_character(),
## winner = col_character(),
## increment_code = col_character(),
## white_id = col_character(),
## white_rating = col_double(),
## black_id = col_character(),
## black_rating = col_double(),
## moves = col_character(),
## opening_eco = col_character(),
## opening_name = col_character(),
## opening_ply = col_double()
## )
## # A tibble: 20,058 x 16
## id rated created_at last_move_at turns victory_status winner increment_code white_id white_rating
## <chr> <lgl> <dbl> <dbl> <dbl> <chr> <chr> <chr> <chr> <dbl>
## 1 TZJHLl~ FALSE 1.50e12 1.50e12 13 outoftime white 15+2 bourgris 1500
## 2 l1NXvw~ TRUE 1.50e12 1.50e12 16 resign black 5+10 a-00 1322
## 3 mIICvQ~ TRUE 1.50e12 1.50e12 61 mate white 5+10 ischia 1496
## 4 kWKvrq~ TRUE 1.50e12 1.50e12 61 mate white 20+0 daniamurash~ 1439
## 5 9tXo1A~ TRUE 1.50e12 1.50e12 95 mate white 30+3 nik221107 1523
## 6 MsoDV9~ FALSE 1.50e12 1.50e12 5 draw draw 10+0 trelynn17 1250
## 7 qwU9ra~ TRUE 1.50e12 1.50e12 33 resign white 10+0 capa_jr 1520
## 8 RVN0N3~ FALSE 1.50e12 1.50e12 9 resign black 15+30 daniel_like~ 1413
## 9 dwF3DJ~ TRUE 1.50e12 1.50e12 66 resign black 15+0 ehabfanri 1439
## 10 afoMwn~ TRUE 1.50e12 1.50e12 119 mate white 10+0 daniel_like~ 1381
## # ... with 20,048 more rows, and 6 more variables: black_id <chr>, black_rating <dbl>, moves <chr>,
## # opening_eco <chr>, opening_name <chr>, opening_ply <dbl>
- Netflix dataset
Programas de TV e filmes listados no Netflix Este conjunto de dados consiste em programas de TV e filmes disponíveis no Netflix a partir de 2019. O conjunto de dados é coletado do Flixable, um mecanismo de busca Netflix de terceiros.
Em 2018, eles lançaram um relatório interessante que mostra que o número de programas de TV na Netflix quase triplicou desde 2010. O número de filmes do serviço de streaming diminuiu em mais de 2.000 títulos desde 2010, enquanto seu número de programas de TV quase triplicou. Será interessante explorar o que todos os outros insights podem ser obtidos no mesmo conjunto de dados.
<- read_csv("https://raw.githubusercontent.com/brunolucian/cursoBasicoR/master/datasets/netflix_titles.csv") tb_netflix
##
## -- Column specification ---------------------------------------------------------------------------------------
## cols(
## show_id = col_character(),
## type = col_character(),
## title = col_character(),
## director = col_character(),
## cast = col_character(),
## country = col_character(),
## date_added = col_character(),
## release_year = col_double(),
## rating = col_character(),
## duration = col_character(),
## listed_in = col_character(),
## description = col_character()
## )
## # A tibble: 7,787 x 12
## show_id type title director cast country date_added release_year rating duration listed_in description
## <chr> <chr> <chr> <chr> <chr> <chr> <chr> <dbl> <chr> <chr> <chr> <chr>
## 1 s1 TV Sh~ 3% <NA> João ~ Brazil August 14~ 2020 TV-MA 4 Seaso~ Internat~ In a future~
## 2 s2 Movie 7:19 Jorge Mi~ Demiá~ Mexico December ~ 2016 TV-MA 93 min Dramas, ~ After a dev~
## 3 s3 Movie 23:59 Gilbert ~ Tedd ~ Singap~ December ~ 2011 R 78 min Horror M~ When an arm~
## 4 s4 Movie 9 Shane Ac~ Elija~ United~ November ~ 2009 PG-13 80 min Action &~ In a postap~
## 5 s5 Movie 21 Robert L~ Jim S~ United~ January 1~ 2008 PG-13 123 min Dramas A brilliant~
## 6 s6 TV Sh~ 46 Serdar A~ Erdal~ Turkey July 1, 2~ 2016 TV-MA 1 Season Internat~ A genetics ~
## 7 s7 Movie 122 Yasir Al~ Amina~ Egypt June 1, 2~ 2019 TV-MA 95 min Horror M~ After an aw~
## 8 s8 Movie 187 Kevin Re~ Samue~ United~ November ~ 1997 R 119 min Dramas After one o~
## 9 s9 Movie 706 Shravan ~ Divya~ India April 1, ~ 2019 TV-14 118 min Horror M~ When a doct~
## 10 s10 Movie 1920 Vikram B~ Rajne~ India December ~ 2008 TV-MA 143 min Horror M~ An architec~
## # ... with 7,777 more rows
- Games sales dataset
Este conjunto de dados contém uma lista de videogames com vendas superiores a 100.000 cópias.
<- read_csv("https://raw.githubusercontent.com/brunolucian/cursoBasicoR/master/datasets/vgsales.csv") tb_game_sales
##
## -- Column specification ---------------------------------------------------------------------------------------
## cols(
## Rank = col_double(),
## Name = col_character(),
## Platform = col_character(),
## Year = col_character(),
## Genre = col_character(),
## Publisher = col_character(),
## NA_Sales = col_double(),
## EU_Sales = col_double(),
## JP_Sales = col_double(),
## Other_Sales = col_double(),
## Global_Sales = col_double()
## )
## # A tibble: 16,598 x 11
## Rank Name Platform Year Genre Publisher NA_Sales EU_Sales JP_Sales Other_Sales Global_Sales
## <dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 Wii Sports Wii 2006 Sports Nintendo 41.5 29.0 3.77 8.46 82.7
## 2 2 Super Mario Bro~ NES 1985 Platform Nintendo 29.1 3.58 6.81 0.77 40.2
## 3 3 Mario Kart Wii Wii 2008 Racing Nintendo 15.8 12.9 3.79 3.31 35.8
## 4 4 Wii Sports Reso~ Wii 2009 Sports Nintendo 15.8 11.0 3.28 2.96 33
## 5 5 Pokemon Red/Pok~ GB 1996 Role-Pl~ Nintendo 11.3 8.89 10.2 1 31.4
## 6 6 Tetris GB 1989 Puzzle Nintendo 23.2 2.26 4.22 0.58 30.3
## 7 7 New Super Mario~ DS 2006 Platform Nintendo 11.4 9.23 6.5 2.9 30.0
## 8 8 Wii Play Wii 2006 Misc Nintendo 14.0 9.2 2.93 2.85 29.0
## 9 9 New Super Mario~ Wii 2009 Platform Nintendo 14.6 7.06 4.7 2.26 28.6
## 10 10 Duck Hunt NES 1984 Shooter Nintendo 26.9 0.63 0.28 0.47 28.3
## # ... with 16,588 more rows
Conforme os próprios autores do pacote apontam, quando trabalhamos com dados, nós precisamos:
Descobrir o que desejamos fazer;
Descrever essas tarefas na forma de um programa de computador;
Executar o programa.
O pacote dplyr
torna estes passos mais rápidos e fáceis de executar, pois:
ao invés de disponibilizar uma imensidão de funções, igual temos no R base e outros pacotes, ele restringe nossas opções e com isso nos ajuda a raciocinar de forma mais direta sobre o que desejamos e podemos fazer com os dados;
provém “verbos” (ou funções) mais simples, ou seja, funções que correspondem às tarefas mais comuns de manipulação de dados, ajudando-nos assim a traduzir pensamentos em código;
utiliza backends (códigos de final de processo, ou seja, mais próximos ao usuário) eficientes, de modo que gastamos menos tempo esperando pelo computador.
O pacote dplyr
proporciona uma função para cada “verbo” considerado importante em manipulação de dados:
filter()
para selecionar “casos” baseados em seus valores;arrange()
para reordenar os “casos”;select()
e rename() para selecionar variáveis baseadas em seus nomes;mutate()
etransmute()
para adicionar novas variáveis que são funções de variáveis já existentes nos dados;summarise()
ousummarize()
para condensar multiplos valores em um único;group_by()
embora não seja considerado um dos “verbos”, serve para agruparmos os dados em torno de uma ou mais variáveis. As funções consideradas “verbos” podem ser utilizadas antes ou após o agrupamentodos dados.
Veremos agora alguns exemplos de aplicação destas funções.
library(dplyr)
Note que pelo print que temos novamente um tibble, que é uma forma moderna de data.frame implementada pelo pessoal do tidyverse . Este formato é particularmente útil para grandes datasets porque só é impresso na tela as primeiras linhas e diversos resumos/informações sobre nossas variáveis. Para converter data.frames em tibbles, usamos as_tibble()
.
4.1.1 Filtrando linhas com filter()
filter()
permite fazer um subset das linhas de um tibble/dataframe. Como todos os verbos simples de dplyr
, o primeiro argumento será um tibble (ou data.frame). O segundo argumento e os subsequentes se referem a variáveis dentro do data.frame, em que se selecionam as linhas onde a expressão é verdadeira (TRUE).
Vamos selecionar todos as linhas em que o jogador que estava com as peças pretas foi o vencedor da partida:
filter(tb_chess_game, winner == "black")
## # A tibble: 9,107 x 16
## id rated created_at last_move_at turns victory_status winner increment_code white_id white_rating
## <chr> <lgl> <dbl> <dbl> <dbl> <chr> <chr> <chr> <chr> <dbl>
## 1 l1NXvw~ TRUE 1.50e12 1.50e12 16 resign black 5+10 a-00 1322
## 2 RVN0N3~ FALSE 1.50e12 1.50e12 9 resign black 15+30 daniel_like~ 1413
## 3 dwF3DJ~ TRUE 1.50e12 1.50e12 66 resign black 15+0 ehabfanri 1439
## 4 Vf5fKW~ FALSE 1.50e12 1.50e12 38 resign black 20+60 daniel_like~ 1381
## 5 HRti5m~ FALSE 1.50e12 1.50e12 60 resign black 5+40 daniel_like~ 1381
## 6 2fEjSe~ FALSE 1.50e12 1.50e12 31 resign black 8+0 daniel_like~ 1381
## 7 guanvM~ FALSE 1.50e12 1.50e12 43 resign black 15+15 sureka_aksh~ 1141
## 8 PmpkWk~ FALSE 1.50e12 1.50e12 52 resign black 15+15 shivangithe~ 1094
## 9 EwaK0I~ FALSE 1.50e12 1.50e12 66 mate black 15+16 sureka_aksh~ 1141
## 10 yrSDoz~ FALSE 1.50e12 1.50e12 101 resign black 15+15 shivangithe~ 1094
## # ... with 9,097 more rows, and 6 more variables: black_id <chr>, black_rating <dbl>, moves <chr>,
## # opening_eco <chr>, opening_name <chr>, opening_ply <dbl>
filter(tb_chess_game, winner == "black", black_rating < 1500)
## # A tibble: 2,947 x 16
## id rated created_at last_move_at turns victory_status winner increment_code white_id white_rating
## <chr> <lgl> <dbl> <dbl> <dbl> <chr> <chr> <chr> <chr> <dbl>
## 1 l1NXvw~ TRUE 1.50e12 1.50e12 16 resign black 5+10 a-00 1322
## 2 dwF3DJ~ TRUE 1.50e12 1.50e12 66 resign black 15+0 ehabfanri 1439
## 3 guanvM~ FALSE 1.50e12 1.50e12 43 resign black 15+15 sureka_aksh~ 1141
## 4 PmpkWk~ FALSE 1.50e12 1.50e12 52 resign black 15+15 shivangithe~ 1094
## 5 EwaK0I~ FALSE 1.50e12 1.50e12 66 mate black 15+16 sureka_aksh~ 1141
## 6 yrSDoz~ FALSE 1.50e12 1.50e12 101 resign black 15+15 shivangithe~ 1094
## 7 mCij4h~ TRUE 1.50e12 1.50e12 13 resign black 10+0 shivangithe~ 1113
## 8 srz9Qf~ TRUE 1.50e12 1.50e12 54 mate black 10+10 mannat1 1328
## 9 NS6ccs~ TRUE 1.50e12 1.50e12 53 resign black 10+10 shivangithe~ 1056
## 10 M3vpf2~ TRUE 1.50e12 1.50e12 66 mate black 10+10 shivangithe~ 1077
## # ... with 2,937 more rows, and 6 more variables: black_id <chr>, black_rating <dbl>, moves <chr>,
## # opening_eco <chr>, opening_name <chr>, opening_ply <dbl>
filter(tb_chess_game, winner == "black" | opening_eco =="A10")
## # A tibble: 9,178 x 16
## id rated created_at last_move_at turns victory_status winner increment_code white_id white_rating
## <chr> <lgl> <dbl> <dbl> <dbl> <chr> <chr> <chr> <chr> <dbl>
## 1 l1NXvw~ TRUE 1.50e12 1.50e12 16 resign black 5+10 a-00 1322
## 2 RVN0N3~ FALSE 1.50e12 1.50e12 9 resign black 15+30 daniel_like~ 1413
## 3 dwF3DJ~ TRUE 1.50e12 1.50e12 66 resign black 15+0 ehabfanri 1439
## 4 Vf5fKW~ FALSE 1.50e12 1.50e12 38 resign black 20+60 daniel_like~ 1381
## 5 HRti5m~ FALSE 1.50e12 1.50e12 60 resign black 5+40 daniel_like~ 1381
## 6 2fEjSe~ FALSE 1.50e12 1.50e12 31 resign black 8+0 daniel_like~ 1381
## 7 guanvM~ FALSE 1.50e12 1.50e12 43 resign black 15+15 sureka_aksh~ 1141
## 8 PmpkWk~ FALSE 1.50e12 1.50e12 52 resign black 15+15 shivangithe~ 1094
## 9 EwaK0I~ FALSE 1.50e12 1.50e12 66 mate black 15+16 sureka_aksh~ 1141
## 10 yrSDoz~ FALSE 1.50e12 1.50e12 101 resign black 15+15 shivangithe~ 1094
## # ... with 9,168 more rows, and 6 more variables: black_id <chr>, black_rating <dbl>, moves <chr>,
## # opening_eco <chr>, opening_name <chr>, opening_ply <dbl>
4.1.2 Ordenando linhas com arrange()
arrange()
funciona de modo semelhante a filter, mas ao invés de filtrar e selecionar linhas, ele apenas as reordena de acordo com alguma condição que passamos. Essa função recebe um data.frame e um conjunto de column names pelo qual vai ordenar. Se você fornecer mais de um nome de coluna, cada coluna adicional passada será usada como critério de desempate.
arrange(tb_chess_game, white_rating)
## # A tibble: 20,058 x 16
## id rated created_at last_move_at turns victory_status winner increment_code white_id white_rating
## <chr> <lgl> <dbl> <dbl> <dbl> <chr> <chr> <chr> <chr> <dbl>
## 1 YwaFfX~ TRUE 1.50e12 1.50e12 61 mate white 10+0 ragnarlothb~ 784
## 2 XJoTQF~ TRUE 1.50e12 1.50e12 2 resign black 10+0 crazyscient~ 784
## 3 APnsyo~ FALSE 1.40e12 1.40e12 27 resign black 20+12 lucatiel-of~ 788
## 4 lWZQsM~ TRUE 1.49e12 1.49e12 62 resign black 15+15 natalua 793
## 5 t6GU62~ TRUE 1.49e12 1.49e12 144 resign black 15+0 epicchess66 795
## 6 yRIvgI~ TRUE 1.50e12 1.50e12 23 resign white 0+25 mr_zilgaze 798
## 7 yRIvgI~ TRUE 1.50e12 1.50e12 23 resign white 0+25 mr_zilgaze 798
## 8 q5xbB1~ TRUE 1.41e12 1.41e12 6 resign black 10+8 canabidiol 801
## 9 wr2hpx~ FALSE 1.39e12 1.39e12 92 mate black 20+8 alliekatxox~ 807
## 10 4Oie3k~ TRUE 1.50e12 1.50e12 47 mate white 10+0 mata1234 808
## # ... with 20,048 more rows, and 6 more variables: black_id <chr>, black_rating <dbl>, moves <chr>,
## # opening_eco <chr>, opening_name <chr>, opening_ply <dbl>
Se quiser ordenar de forma decrescente, utilize a função desc(nome_da_coluna)
dentro de arrange()
. Isso seria particularmente interessante se você quisesse ordenar os dados na coluna final do maior volume para o maior.
arrange(tb_chess_game, desc(white_rating), desc(black_rating) )
## # A tibble: 20,058 x 16
## id rated created_at last_move_at turns victory_status winner increment_code white_id white_rating
## <chr> <lgl> <dbl> <dbl> <dbl> <chr> <chr> <chr> <chr> <dbl>
## 1 Y1oXTO75 FALSE 1494548121994 1.49e12 20 resign white 30+30 justicebot 2700
## 2 qIn8fg1t TRUE 1477763880499 1.48e12 149 resign white 5+5 blitzbull~ 2622
## 3 upN6B2c0 FALSE 1503524835210 1.50e12 69 resign white 10+15 lance5500 2621
## 4 TVQunaRl FALSE 1503432282759 1.50e12 40 resign black 10+15 lance5500 2621
## 5 fPm9lH2d FALSE 1502485078188 1.50e12 58 outoftime black 10+10 lance5500 2621
## 6 woqCHd9g FALSE 1501877320309 1.50e12 42 resign black 10+15 lance5500 2621
## 7 lh41ycUX FALSE 1497214098420 1.50e12 49 resign white 5+60 lance5500 2621
## 8 zA4LDp7x FALSE 1496885486497 1.50e12 77 resign white 15+0 lance5500 2621
## 9 HWw4eAWR FALSE 1503514029547 1.50e12 14 resign white 10+25 lance5500 2621
## 10 2hNUHRUA FALSE 1501593317978 1.50e12 47 outoftime white 10+25 lance5500 2621
## # ... with 20,048 more rows, and 6 more variables: black_id <chr>, black_rating <dbl>, moves <chr>,
## # opening_eco <chr>, opening_name <chr>, opening_ply <dbl>
4.1.3 Selecionando colunas com select()
Geralmente trabalhamos com grandes datasets com muitas colunas, mas somente algumas poucas colunas serão de nosso interesse. select()
nos permite rapidamente focar num subconjunto dos dados. O melhor é que podemos utilizar operações - que normalmente só funcionam com as posições das colunas - direto nos nomes das variáveis.
# Seleção por nome
select(tb_netflix, title, country, rating)
## # A tibble: 7,787 x 3
## title country rating
## <chr> <chr> <chr>
## 1 3% Brazil TV-MA
## 2 7:19 Mexico TV-MA
## 3 23:59 Singapore R
## 4 9 United States PG-13
## 5 21 United States PG-13
## 6 46 Turkey TV-MA
## 7 122 Egypt TV-MA
## 8 187 United States R
## 9 706 India TV-14
## 10 1920 India TV-MA
## # ... with 7,777 more rows
# Selecionando todas as colunas num intervalo de colunas (inclusive)
select(tb_netflix, title:release_year)
## # A tibble: 7,787 x 6
## title director cast country date_added release_year
## <chr> <chr> <chr> <chr> <chr> <dbl>
## 1 3% <NA> João Miguel, Bianca Comparato, Michel Gomes, Rodol~ Brazil August 14, 2~ 2020
## 2 7:19 Jorge Michel~ Demián Bichir, Héctor Bonilla, Oscar Serrano, Azal~ Mexico December 23,~ 2016
## 3 23:59 Gilbert Chan Tedd Chan, Stella Chung, Henley Hii, Lawrence Koh,~ Singapore December 20,~ 2011
## 4 9 Shane Acker Elijah Wood, John C. Reilly, Jennifer Connelly, Ch~ United S~ November 16,~ 2009
## 5 21 Robert Luket~ Jim Sturgess, Kevin Spacey, Kate Bosworth, Aaron Y~ United S~ January 1, 2~ 2008
## 6 46 Serdar Akar Erdal Besikçioglu, Yasemin Allen, Melis Birkan, Sa~ Turkey July 1, 2017 2016
## 7 122 Yasir Al Yas~ Amina Khalil, Ahmed Dawood, Tarek Lotfy, Ahmed El ~ Egypt June 1, 2020 2019
## 8 187 Kevin Reynol~ Samuel L. Jackson, John Heard, Kelly Rowan, Clifto~ United S~ November 1, ~ 1997
## 9 706 Shravan Kumar Divya Dutta, Atul Kulkarni, Mohan Agashe, Anupam S~ India April 1, 2019 2019
## 10 1920 Vikram Bhatt Rajneesh Duggal, Adah Sharma, Indraneil Sengupta, ~ India December 15,~ 2008
## # ... with 7,777 more rows
# Selecionando todas as colunas exceto aquelas em um intervalo (inclusive)
select(tb_netflix, -(date_added:description))
## # A tibble: 7,787 x 6
## show_id type title director cast country
## <chr> <chr> <chr> <chr> <chr> <chr>
## 1 s1 TV Show 3% <NA> João Miguel, Bianca Comparato, Michel Gomes, Rodolfo Valente~ Brazil
## 2 s2 Movie 7:19 Jorge Michel~ Demián Bichir, Héctor Bonilla, Oscar Serrano, Azalia Ortiz, ~ Mexico
## 3 s3 Movie 23:59 Gilbert Chan Tedd Chan, Stella Chung, Henley Hii, Lawrence Koh, Tommy Kua~ Singapore
## 4 s4 Movie 9 Shane Acker Elijah Wood, John C. Reilly, Jennifer Connelly, Christopher ~ United St~
## 5 s5 Movie 21 Robert Luket~ Jim Sturgess, Kevin Spacey, Kate Bosworth, Aaron Yoo, Liza L~ United St~
## 6 s6 TV Show 46 Serdar Akar Erdal Besikçioglu, Yasemin Allen, Melis Birkan, Saygin Soysa~ Turkey
## 7 s7 Movie 122 Yasir Al Yas~ Amina Khalil, Ahmed Dawood, Tarek Lotfy, Ahmed El Fishawy, M~ Egypt
## 8 s8 Movie 187 Kevin Reynol~ Samuel L. Jackson, John Heard, Kelly Rowan, Clifton Collins ~ United St~
## 9 s9 Movie 706 Shravan Kumar Divya Dutta, Atul Kulkarni, Mohan Agashe, Anupam Shyam, Raay~ India
## 10 s10 Movie 1920 Vikram Bhatt Rajneesh Duggal, Adah Sharma, Indraneil Sengupta, Anjori Ala~ India
## # ... with 7,777 more rows
DICA: Existem helper functions que podemos usar dentro de select()
. São funções que lembram o funcionamento de uma regular expression (Vamos ver no curso avançado com mais detalhes) para identificarmos nomes de colunas que atendem a determinado critério. São muito úteis com grandes datasets: starts_with()
, ends_with()
, matches()
e contains()
.
Vamos por exemplo selecionar todas as colunas que começam com a letra d
:
select(tb_netflix, starts_with("d"))
## # A tibble: 7,787 x 4
## director date_added duration description
## <chr> <chr> <chr> <chr>
## 1 <NA> August 14, 2020 4 Seaso~ In a future where the elite inhabit an island paradise far from the~
## 2 Jorge Michel ~ December 23, 2~ 93 min After a devastating earthquake hits Mexico City, trapped survivors ~
## 3 Gilbert Chan December 20, 2~ 78 min When an army recruit is found dead, his fellow soldiers are forced ~
## 4 Shane Acker November 16, 2~ 80 min In a postapocalyptic world, rag-doll robots hide in fear from dange~
## 5 Robert Luketic January 1, 2020 123 min A brilliant group of students become card-counting experts with the~
## 6 Serdar Akar July 1, 2017 1 Season A genetics professor experiments with a treatment for his comatose ~
## 7 Yasir Al Yasi~ June 1, 2020 95 min After an awful accident, a couple admitted to a grisly hospital are~
## 8 Kevin Reynolds November 1, 20~ 119 min After one of his high school students attacks him, dedicated teache~
## 9 Shravan Kumar April 1, 2019 118 min When a doctor goes missing, his psychiatrist wife treats the bizarr~
## 10 Vikram Bhatt December 15, 2~ 143 min An architect and his wife move into a castle that is slated to beco~
## # ... with 7,777 more rows
select()
pode ser usada inclusive para renomear variáveis:
select(tb_netflix, listed_category = listed_in)
## # A tibble: 7,787 x 1
## listed_category
## <chr>
## 1 International TV Shows, TV Dramas, TV Sci-Fi & Fantasy
## 2 Dramas, International Movies
## 3 Horror Movies, International Movies
## 4 Action & Adventure, Independent Movies, Sci-Fi & Fantasy
## 5 Dramas
## 6 International TV Shows, TV Dramas, TV Mysteries
## 7 Horror Movies, International Movies
## 8 Dramas
## 9 Horror Movies, International Movies
## 10 Horror Movies, International Movies, Thrillers
## # ... with 7,777 more rows
A nova variável será chamada listed_category e receberá toda a informação da original listed_in.
No entanto, select()
“abandona” todas as demais variáveis quando você faz uma renomeação. É melhor então é usar rename()
:
rename(tb_netflix, listed_category = listed_in)
## # A tibble: 7,787 x 12
## show_id type title director cast country date_added release_year rating duration listed_category
## <chr> <chr> <chr> <chr> <chr> <chr> <chr> <dbl> <chr> <chr> <chr>
## 1 s1 TV Sh~ 3% <NA> João Migue~ Brazil August 14~ 2020 TV-MA 4 Seaso~ International TV~
## 2 s2 Movie 7:19 Jorge Mi~ Demián Bic~ Mexico December ~ 2016 TV-MA 93 min Dramas, Internat~
## 3 s3 Movie 23:59 Gilbert ~ Tedd Chan,~ Singap~ December ~ 2011 R 78 min Horror Movies, I~
## 4 s4 Movie 9 Shane Ac~ Elijah Woo~ United~ November ~ 2009 PG-13 80 min Action & Adventu~
## 5 s5 Movie 21 Robert L~ Jim Sturge~ United~ January 1~ 2008 PG-13 123 min Dramas
## 6 s6 TV Sh~ 46 Serdar A~ Erdal Besi~ Turkey July 1, 2~ 2016 TV-MA 1 Season International TV~
## 7 s7 Movie 122 Yasir Al~ Amina Khal~ Egypt June 1, 2~ 2019 TV-MA 95 min Horror Movies, I~
## 8 s8 Movie 187 Kevin Re~ Samuel L. ~ United~ November ~ 1997 R 119 min Dramas
## 9 s9 Movie 706 Shravan ~ Divya Dutt~ India April 1, ~ 2019 TV-14 118 min Horror Movies, I~
## 10 s10 Movie 1920 Vikram B~ Rajneesh D~ India December ~ 2008 TV-MA 143 min Horror Movies, I~
## # ... with 7,777 more rows, and 1 more variable: description <chr>
4.1.4 Adicionando novas colunas com mutate()
Além de selecionar conjuntos de colunas existentes, é geralmente útil adicionar novas colunas que são funções de colunas já presentes no tibble/dataframe. Veja um exemplo com mutate()
, onde queremos calcular o preço por unidade de volume:
mutate(tb_game_sales,
part_na_sales = NA_Sales/Global_Sales,
)
## # A tibble: 16,598 x 12
## Rank Name Platform Year Genre Publisher NA_Sales EU_Sales JP_Sales Other_Sales Global_Sales part_na_sales
## <dbl> <chr> <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 Wii ~ Wii 2006 Spor~ Nintendo 41.5 29.0 3.77 8.46 82.7 0.501
## 2 2 Supe~ NES 1985 Plat~ Nintendo 29.1 3.58 6.81 0.77 40.2 0.723
## 3 3 Mari~ Wii 2008 Raci~ Nintendo 15.8 12.9 3.79 3.31 35.8 0.442
## 4 4 Wii ~ Wii 2009 Spor~ Nintendo 15.8 11.0 3.28 2.96 33 0.477
## 5 5 Poke~ GB 1996 Role~ Nintendo 11.3 8.89 10.2 1 31.4 0.359
## 6 6 Tetr~ GB 1989 Puzz~ Nintendo 23.2 2.26 4.22 0.58 30.3 0.767
## 7 7 New ~ DS 2006 Plat~ Nintendo 11.4 9.23 6.5 2.9 30.0 0.379
## 8 8 Wii ~ Wii 2006 Misc Nintendo 14.0 9.2 2.93 2.85 29.0 0.483
## 9 9 New ~ Wii 2009 Plat~ Nintendo 14.6 7.06 4.7 2.26 28.6 0.510
## 10 10 Duck~ NES 1984 Shoo~ Nintendo 26.9 0.63 0.28 0.47 28.3 0.951
## # ... with 16,588 more rows
mutate()
nos permite ainda nos referir a colunas que acabamos de criar no mesmo comando. Vamos salvar esta alteração em um novo tibble, chamado tb_game_sales_trans
<- mutate(tb_game_sales,
tb_game_sales_trans part_na_sales = NA_Sales/Global_Sales,
part_eu_sales = EU_Sales/Global_Sales,
part_jp_sales = JP_Sales/Global_Sales,
part_os_sales = Other_Sales/Global_Sales
)
Se só nos interessarem as novas variáveis, usaríamos transmute():
transmute(tb_game_sales,
part_na_sales = NA_Sales/Global_Sales,
part_eu_sales = EU_Sales/Global_Sales,
part_jp_sales = JP_Sales/Global_Sales,
part_os_sales = Other_Sales/Global_Sales
)
## # A tibble: 16,598 x 4
## part_na_sales part_eu_sales part_jp_sales part_os_sales
## <dbl> <dbl> <dbl> <dbl>
## 1 0.501 0.351 0.0456 0.102
## 2 0.723 0.0890 0.169 0.0191
## 3 0.442 0.360 0.106 0.0924
## 4 0.477 0.334 0.0994 0.0897
## 5 0.359 0.283 0.326 0.0319
## 6 0.767 0.0747 0.139 0.0192
## 7 0.379 0.308 0.217 0.0966
## 8 0.483 0.317 0.101 0.0982
## 9 0.510 0.247 0.164 0.0790
## 10 0.951 0.0223 0.00989 0.0166
## # ... with 16,588 more rows
4.1.5 Modificando entradas com mutate()
ou transmute()
+ case_when()
case_when()
é uma função do pacote dplyr
que nos permite modificar as variáveis a partir de uma sequência de condições que devem ser respeitadas.
SE CONDIÇÃO1 VERDADEIRA ~ FAÇA TAL COISA;
SENÃO ~ FAÇA OUTRA COISA
Ela substitui as estruturas condicionais nativas do R (função ifelse()
) e é inspirada na declaração equivalente em SQL CASE WHEN
. Os argumentos da função case_when()
obedecem à seguinte estrutura: operação condicional ~ novo valor
. No lado esquerdo do ~
, você tem a comparação a ser feita. No lado direito, temos o novo valor a ser atribuído caso o resultado da comparação seja TRUE
. Você pode tratar, inclusive, mais de uma condição, desde que parta do caso mais específico para o mais geral.
case_when(
~ "novo_valor1",
condição1 ~ "novo_valor2",
condição2 ~ "novo_valor3",
condição3 TRUE ~ "valor para os demais casos não atendidos pelas condições acima"
)
Geralmente, no contexto de análise de dados com dplyr
, utilizamos case_when()
dentro de uma função mutate()
ou transmute
(que traz a apenas a nova coluna criada), uma vez que pretendemos alterar as entradas de uma coluna, alterando, portanto, a própria coluna.
No tibble tb_games_sales
, vamos criar uma nova coluna de caracteres chamada nivel
, em que classificaremos um valor em: alto
se NA_sales > mean(NA_sales)
; baixo
se NA_sales < mean(NA_sales)
ou razoavel
nos demais casos:
transmute(tb_game_sales,
nivel_na =
case_when(
> mean(NA_Sales) ~ "alto",
NA_sales < mean(NA_Sales) ~ "baixo",
NA_sales TRUE ~ "razoável"
))
4.1.6 Sumarizando valores com summarise()
O último “verbo” de dplyr
é summarise()
(ou summarize
). Ele colapsa um tibble/dataframe em uma única linha.
summarise(tb_game_sales,
max_venda_na = max(NA_Sales, na.rm = TRUE)
)
## # A tibble: 1 x 1
## max_venda_na
## <dbl>
## 1 41.5
DICA: O parâmetro na.rm = TRUE
dentro da função max()
serve para que esta desconsidere os valores falatantes (NA
) ao calcular a máximo Do contrário, na existência de missing values NA
, a função sempre retornará NA
. Isso também vale para outras funções matemáticas de funcionamento vetorizado, como sum()
, mean
e min
, por exemplo.
Dependendo do seu objetivo, pode ser mais útil utilizar o “verbo” group_by()
que veremos mais a frente. Com ele poderemos calcular o valor médio por plataforma por exemplo.
4.2 Estrutura do dplyr
Note que a sintaxe e funcionamento de todos os verbos de dplyr
apresentados até aqui são bem similares:
o primeiro argumento é um tibble/dataframe;
os argumentos subsequentes descrevem o que fazer com os dados. Podemos nos referir às colunas do tibble/dataframe diretamente sem a necessidade de usar
$
ou indexação por[]
.o resultado é um novo tibble/dataframe.
Juntas, essas propriedades facilitam encadear múltiplos passos simples para alcançar um resultado complexo. O restante do que dplyr
faz, vem de aplicar as 5 funções que vimos até aqui a diferentes tipos de dados. Ao invpes de trabalharmos com dados desagregados, vamos passar a trabalhar agora com dados agrupados por uma ou mais variáveis.
4.2.1 Operações agrupadas
Os verbos de dplyr
tornam-se ainda mais poderosos quando os aplicamos a grupos de observações dentro de um conjunto de dados. Fazemos isso com a função group_by()
. Ela “quebra” o dataset em grupos específicos de linhas. No início, não vemos qualquer alteração. É como se elas ficassem em segundo plano. No entanto, ao aplicarmos algum dos verbos principais no dataset “alterado” por group_by
, eles automaticamente serão aplicados por grupo ou “by group”.
O uso de agrupamento afeta o resultado dos verbos principais da seguinte forma:
select()
agrupado é o mesmo que não agrupado, exceto pelo fato que as variáveis de agrupamento são sempre preservadas.arrange()
agrupado é mesmo que não agrupado, a não ser que usemos.by_group = TRUE
, caso em que ordena primeiro pelas variáveis de agrupamento;mutate()
efilter()
são bastante úteis em conjunto com window functions (comorank()
oumin(x) == x
) (Ver vignette de “window-functions” dodplyr
);summarise()
calcula o sumário para cada grupo.
No exemplo a seguir, nós separamos o dataset por Platform
, contando o número de registros para cada um das plataformas (count = n()
), computando a valor médio por plataforma (valor_medio_plataforma = mean(Global_Sales, na.rm = TRUE
)).
<- group_by(tb_game_sales, Platform)
by_platform <- summarise(
valor_medio_plataforma
by_platform,count = n(),
mvp = mean(Global_Sales, na.rm = TRUE)
)
Note que summarise()
é normalmente utilizada com aggregate functions, as quais recebem um vetor de valores e retornam um único número. Há muito exemplos úteis do base R que podem ser utilizados, como min()
, max()
, mean()
, sum()
, sd()
, median()
, etc. dplyr
fornece mais algumas outras bem úteis:
n()
: número de observações no grupo atual;n_distinct(x)
: número de valores únicos em x;first(x)
,last(x)
enth(x, n)
funcionam de forma similar ax[1]
,x[length(x)]
ex[n]
, mas nos dão maior controle sobre resultado caso algum valor seja missing.
4.2.2 Cuidados com os nomes de variáveis
Uma das melhores características do pacote dplyr
é que podemos nos referir as variáveis de um tibble ou dataframe como se fossem variáveis regulares (aquelas que estão no Global Environment). No entanto, a sintaxe de referência para nomes de colunas escondem algumas diferenças entre os verbos. Por exemplo, um nome ou valor de coluna passado para select()
não tem o mesmo significado do que teria em mutate()
.
Veja formas equivalentes do ponto de vista de dplyr:
select(tb_chess_game, victory_status)
## # A tibble: 20,058 x 1
## victory_status
## <chr>
## 1 outoftime
## 2 resign
## 3 mate
## 4 mate
## 5 mate
## 6 draw
## 7 resign
## 8 resign
## 9 resign
## 10 mate
## # ... with 20,048 more rows
select(tb_chess_game, 6)
## # A tibble: 20,058 x 1
## victory_status
## <chr>
## 1 outoftime
## 2 resign
## 3 mate
## 4 mate
## 5 mate
## 6 draw
## 7 resign
## 8 resign
## 9 resign
## 10 mate
## # ... with 20,048 more rows
Se houver uma variável no Global Environment com o mesmo nome de uma coluna de nosso tibble/dataframe, o dplyr
dará prioridade à variável que está no tibble.
<- "Vencedor"
victory_status select(tb_chess_game, victory_status)
## # A tibble: 20,058 x 1
## victory_status
## <chr>
## 1 outoftime
## 2 resign
## 3 mate
## 4 mate
## 5 mate
## 6 draw
## 7 resign
## 8 resign
## 9 resign
## 10 mate
## # ... with 20,048 more rows
4.3 Usando o Pipe %>%
dplyr é funcional no sentido de que os chamados às funções não tem efeitos colaterais. Ou seja, você sempre precisa salvar seus resultados. Isso faz com que não tenhámos um código tão elegante, especialmente quando vamos fazer várias operações.
Para dar uma solução elegante ao problema, dplyr utiliza o operador pipe %>%
do pacote magritrr
. x %>% f(y)
equivale a f(x, y)
. Então, podemos utilizar esse operador para reescrever múltiplas operações que podemos ler da esquerda para direita e de cima para baixo.
%>%
tb_game_sales group_by(Platform) %>%
summarise(count = n(),
mvp = mean(Global_Sales, na.rm = TRUE))
## # A tibble: 31 x 3
## Platform count mvp
## <chr> <int> <dbl>
## 1 2600 133 0.730
## 2 3DO 3 0.0333
## 3 3DS 509 0.486
## 4 DC 52 0.307
## 5 DS 2163 0.380
## 6 GB 98 2.61
## 7 GBA 822 0.387
## 8 GC 556 0.359
## 9 GEN 27 1.05
## 10 GG 1 0.04
## # ... with 21 more rows
DICA: Note que o nome do tibble ou dataframe só precisa ser informado uma única vez logo ao início do processo.
4.4 Referências da seção
Wickham H.; François, R.; Henry, L.; Müller K. (2019). dplyr: A Grammar of Data Manipulation. R package version 0.8.1. URL https://CRAN.R-project.org/package=dplyr.
Wickham H.; François, R.; Henry, L.; Müller K. (2020). dplyr vignette: Introduction. URL http://dplyr.tidyverse.org.
Wickham, H.; Grolemund, G. (2016). R for Data Science: Import, Tidy, Transform, Visualize, and Model Data. O’Reilly Media. december 2016. 522 pages. Disponível em: https://www.r4ds.co.nz.
4.4.1 Exercícios
Importe a tabela selecionada contendo uma projeção do Censo Escolar Agregado por número de alunos por etapa de ensino para os anos de 2020 e 2021 .
Qual é o número de alunos por série de ensino em 2019? Escreva uma nova tabela txt ou csv com esses dados.
Agrupe os dados pelos UFs de SP, RJ e MG e salve uma tabela separada (txt ou csv) para cada um dos agrupamentos. DICA: Pesquise sobre como separar dataframes por grupos com dplyr e como indexar listas.
Identifique o estado com menor número de alunos projetado para 2020.
Crie e salve uma nova tabela contendo o número de escolas por UF.