Capítulo 3 Introdução ao tidyverse

Busque mais informações sobre os pacotes que compõem o tidyverse nas referências recomendadas.

3.1 Criando uma tibble

  • Uma tibble é uma tabela retangular.

  • Cada coluna é um vetor:

    cores <- tibble(
      pessoa = c('João', 'Maria', 'Pedro', 'Ana'),
      'cor favorita' = c('azul', 'rosa', 'preto', 'branco')
    )
    cores
  • Isto é um pouco diferente da maneira como estamos acostumados a ver tabelas (como uma coleção de linhas, em vez de uma coleção de colunas).

  • A função tribble permite a entrada de forma mais natural, linha a linha. Lembre-se de usar ~ antes dos nomes das colunas.

    cores <- tribble(
      ~pessoa, ~'cor favorita',
       "João",          "azul",
      "Maria",          "rosa",
      "Pedro",         "preto",
        "Ana",        "branco"
    )
    cores

    Mesmo que você crie uma tibble linha a linha, o R vai continuar tratando sua tibble como uma coleção de colunas.

    É importante lembrar disto para entender a forma como R manipula estas tabelas.

  • Se uma coluna não puder ser armazenada em um vetor, a coluna será uma lista (com vetores como elementos):

    cores <- tibble(
      pessoa = c('João', 'Maria', 'Pedro', 'Ana'),
      'cor favorita' = list(
        c('azul', 'roxo'),
        c('rosa', 'magenta'),
        NA,
        'branco'
      )
    )
    cores
  • Use View() para examinar interativamente o conteúdo de uma coluna-lista:

    cores %>% View()

3.2 Operador de pipe (%>%)

  • O tidyverse inclui o pacote magrittr, que contém o operador %>%, chamado pipe.1
  • A idéia é facilitar a leitura de composições de funções. O código

    y <- h(g(f(x)))

    pode ser escrito como

    y <- x %>% f() %>% g() %>% h()
  • Esta segunda versão é mais fiel à ordem em que as operações acontecem.

  • Na verdade, R tem um operador de atribuição para a direita, mas poucas pessoas recomendam usá-lo:

    x %>% f() %>% g() %>% h() -> y
  • Se f, g e h forem funções de um argumento só, os parênteses podem ser omitidos:

    y <- x %>% f %>% g %>% h
  • Se a função f tiver outros argumentos, escreva-os normalmente na chamada a f:

    y <- x %>% mean(na.rm = TRUE)
  • O pipe EXP %>% f(...) sempre insere o resultado da expressão EXP como o primeiro argumento da função f.

  • Se você precisar que o resultado da expressão EXP seja inserido em outra posição na lista de argumentos de f, use um ponto “.” para isso:

    x %>% consultar(df, .)

    equivale a

    consultar(df, x)

3.3 Formato tidy

  • Nossa última versão da tibble cores é um pouco mais complexa do que deveria ser:

    cores
  • O formato tidy exige que

    1. Cada linha da tibble corresponda a uma observação sobre um indivíduo,

    2. Cada coluna corresponda a uma variável observada, e

    3. Cada célula contenha um valor da variável.

  • Na tibble cores, a primeira e a segunda exigências são satisfeitas, mas a terceira não, pois algumas células contém valores múltiplos.

  • A tibble não está no formato tidy.

  • Podemos “extrair” estes vetores “aninhados” usando o comando unnest, do pacote tidyr:

    cores <- cores %>% 
      unnest(`cor favorita`)
    cores
  • A maioria das funções do tidyverse exige que as tibbles estejam neste formato tidy.

  • Um exemplo mais complexo é o dataset billboard, com as seguintes colunas (para cada música que estava no top 100 da Billboard no ano de \(2000\)):

    • Nome do artista ou banda;

    • Nome da música;

    • Data em que a música entrou no top 100 da Billboard;

    • Para cada uma das \(76\) semanas seguintes, a posição da música no top 100.

      billboard %>% glimpse()
      ## Rows: 317
      ## Columns: 79
      ## $ artist       <chr> "2 Pac", "2Ge+her", "3 Doors Down", "3 Doors Down", "504 Boyz"…
      ## $ track        <chr> "Baby Don't Cry (Keep...", "The Hardest Part Of ...", "Krypton…
      ## $ date.entered <date> 2000-02-26, 2000-09-02, 2000-04-08, 2000-10-21, 2000-04-15, 2…
      ## $ wk1          <dbl> 87, 91, 81, 76, 57, 51, 97, 84, 59, 76, 84, 57, 50, 71, 79, 80…
      ## $ wk2          <dbl> 82, 87, 70, 76, 34, 39, 97, 62, 53, 76, 84, 47, 39, 51, 65, 78…
      ## $ wk3          <dbl> 72, 92, 68, 72, 25, 34, 96, 51, 38, 74, 75, 45, 30, 28, 53, 76…
      ## $ wk4          <dbl> 77, NA, 67, 69, 17, 26, 95, 41, 28, 69, 73, 29, 28, 18, 48, 77…
      ## $ wk5          <dbl> 87, NA, 66, 67, 17, 26, 100, 38, 21, 68, 73, 23, 21, 13, 45, 9…
      ## $ wk6          <dbl> 94, NA, 57, 65, 31, 19, NA, 35, 18, 67, 69, 18, 19, 13, 36, NA…
      ## $ wk7          <dbl> 99, NA, 54, 55, 36, 2, NA, 35, 16, 61, 68, 11, 20, 11, 34, NA,…
      ## $ wk8          <dbl> NA, NA, 53, 59, 49, 2, NA, 38, 14, 58, 65, 9, 17, 1, 29, NA, 9…
      ## $ wk9          <dbl> NA, NA, 51, 62, 53, 3, NA, 38, 12, 57, 73, 9, 17, 1, 27, NA, N…
      ## $ wk10         <dbl> NA, NA, 51, 61, 57, 6, NA, 36, 10, 59, 83, 11, 17, 2, 30, NA, …
      ## $ wk11         <dbl> NA, NA, 51, 61, 64, 7, NA, 37, 9, 66, 92, 1, 17, 2, 36, NA, 99…
      ## $ wk12         <dbl> NA, NA, 51, 59, 70, 22, NA, 37, 8, 68, NA, 1, 3, 3, 37, NA, NA…
      ## $ wk13         <dbl> NA, NA, 47, 61, 75, 29, NA, 38, 6, 61, NA, 1, 3, 3, 39, NA, 96…
      ## $ wk14         <dbl> NA, NA, 44, 66, 76, 36, NA, 49, 1, 67, NA, 1, 7, 4, 49, NA, 96…
      ## $ wk15         <dbl> NA, NA, 38, 72, 78, 47, NA, 61, 2, 59, NA, 4, 10, 12, 57, NA, …
      ## $ wk16         <dbl> NA, NA, 28, 76, 85, 67, NA, 63, 2, 63, NA, 8, 17, 11, 63, NA, …
      ## $ wk17         <dbl> NA, NA, 22, 75, 92, 66, NA, 62, 2, 67, NA, 12, 25, 13, 65, NA,…
      ## $ wk18         <dbl> NA, NA, 18, 67, 96, 84, NA, 67, 2, 71, NA, 22, 29, 15, 68, NA,…
      ## $ wk19         <dbl> NA, NA, 18, 73, NA, 93, NA, 83, 3, 79, NA, 23, 29, 18, 79, NA,…
      ## $ wk20         <dbl> NA, NA, 14, 70, NA, 94, NA, 86, 4, 89, NA, 43, 40, 20, 86, NA,…
      ## $ wk21         <dbl> NA, NA, 12, NA, NA, NA, NA, NA, 5, NA, NA, 44, 43, 30, NA, NA,…
      ## $ wk22         <dbl> NA, NA, 7, NA, NA, NA, NA, NA, 5, NA, NA, NA, 50, 40, NA, NA, …
      ## $ wk23         <dbl> NA, NA, 6, NA, NA, NA, NA, NA, 6, NA, NA, NA, NA, 39, NA, NA, …
      ## $ wk24         <dbl> NA, NA, 6, NA, NA, NA, NA, NA, 9, NA, NA, NA, NA, 44, NA, NA, …
      ## $ wk25         <dbl> NA, NA, 6, NA, NA, NA, NA, NA, 13, NA, NA, NA, NA, NA, NA, NA,…
      ## $ wk26         <dbl> NA, NA, 5, NA, NA, NA, NA, NA, 14, NA, NA, NA, NA, NA, NA, NA,…
      ## $ wk27         <dbl> NA, NA, 5, NA, NA, NA, NA, NA, 16, NA, NA, NA, NA, NA, NA, NA,…
      ## $ wk28         <dbl> NA, NA, 4, NA, NA, NA, NA, NA, 23, NA, NA, NA, NA, NA, NA, NA,…
      ## $ wk29         <dbl> NA, NA, 4, NA, NA, NA, NA, NA, 22, NA, NA, NA, NA, NA, NA, NA,…
      ## $ wk30         <dbl> NA, NA, 4, NA, NA, NA, NA, NA, 33, NA, NA, NA, NA, NA, NA, NA,…
      ## $ wk31         <dbl> NA, NA, 4, NA, NA, NA, NA, NA, 36, NA, NA, NA, NA, NA, NA, NA,…
      ## $ wk32         <dbl> NA, NA, 3, NA, NA, NA, NA, NA, 43, NA, NA, NA, NA, NA, NA, NA,…
      ## $ wk33         <dbl> NA, NA, 3, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
      ## $ wk34         <dbl> NA, NA, 3, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
      ## $ wk35         <dbl> NA, NA, 4, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
      ## $ wk36         <dbl> NA, NA, 5, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
      ## $ wk37         <dbl> NA, NA, 5, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
      ## $ wk38         <dbl> NA, NA, 9, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
      ## $ wk39         <dbl> NA, NA, 9, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
      ## $ wk40         <dbl> NA, NA, 15, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk41         <dbl> NA, NA, 14, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk42         <dbl> NA, NA, 13, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk43         <dbl> NA, NA, 14, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk44         <dbl> NA, NA, 16, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk45         <dbl> NA, NA, 17, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk46         <dbl> NA, NA, 21, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk47         <dbl> NA, NA, 22, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk48         <dbl> NA, NA, 24, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk49         <dbl> NA, NA, 28, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk50         <dbl> NA, NA, 33, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk51         <dbl> NA, NA, 42, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk52         <dbl> NA, NA, 42, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk53         <dbl> NA, NA, 49, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk54         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk55         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk56         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk57         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk58         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk59         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk60         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk61         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk62         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk63         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk64         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk65         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk66         <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk67         <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk68         <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk69         <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk70         <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk71         <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk72         <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk73         <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk74         <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk75         <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
      ## $ wk76         <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
  • Vamos renomear as colunas:

    bb <- billboard %>% 
      rename(
        artista = artist,
        musica = track,
        entrou = date.entered
      )
    bb %>% head()
  • O que é uma observação neste conjunto de dados?

    A posição, em uma semana, de uma música que esteve no top \(100\) da Billboard durante o ano 2000.

  • Quais são as variáveis que qualificam cada observação?

    • O artista,

    • O título da música,

    • A posiçao da música no top \(100\) da Billboard em cada uma das \(76\) semanas depois que ela entrou na lista.

  • Este último item é complexo, e o criador da tibble decidiu criar uma coluna por semana.

  • Uma decisão ruim, pois existe informação embutida nos nomes das colunas. A coluna wk68 corresponde à posição da música na semana \(68\) após ela entrar na lista, mas o número da semana só aparece no nome da coluna!

  • Isto nunca deve acontecer. A informação deve sempre estar nas células.

  • Vamos simplificar as coisas criando duas colunas:

    • semana, com o número da semana; perceba que esta informação vem dos nomes das colunas,

    • pos, com a posição da música naquela semana; esta informação vem das células.

  • A tibble, que antes era larga, vai ser mais estreita e mais longa.

  • A função pivot_longer, do pacote tidyr, vai fazer o trabalho — inclusive extraindo os números das semanas dos nomes das colunas:

    bb_tidy <- bb %>% 
      pivot_longer(
        wk1:wk76,
        names_to = 'semana',
        names_prefix = 'wk',
        names_transform = list(
          semana = as.integer
        ),
        values_to = 'pos'
      )
    bb_tidy
  • O R só mostra, por default, as \(1000\) primeiras linhas de uma tibble.

  • Na verdade, o número de linhas da tabela original era

    bb %>% nrow()
    ## [1] 317
  • O número de linhas, depois de pivot_longer, ficou:

    bb_tidy %>% nrow()
    ## [1] 24092
  • Existem linhas onde pos tem o valor NA. São resultado da organização original dos dados, onde o NA indicava que a música não estava no top \(100\) naquela semana.

  • No novo formato, a ausência da linha com aquele número de semana já basta para indicar isto. Então, vamos eliminar as linhas onde pos é NA.

  • A função filter mantém as linhas que satisfazem a condição dada; por isso, a condição é “pos não é NA”:

    bb_tidy <- bb_tidy %>% 
      filter(!is.na(pos))
    bb_tidy
  • O número de linhas ficou

    bb_tidy %>% nrow()
    ## [1] 5307

3.3.1 Exercícios

  • Todas as semanas deste conjunto de dados são do ano \(2000\)?

  • Qual é o tipo do primeiro argumento da função filter()?

3.4 Manipulando os dados

3.4.1 Criando novas colunas: mutate, transmute

  • O data frame2 cars tem dados (de \(1920\)!) sobre as distâncias de frenagem (em pés) de um carro viajando a diversas velocidades (em milhas por hora):

    cars
  • Vamos criar colunas novas com os valores convertidos para km/h e metros; além disso, uma coluna com a taxa de frenagem:

    cars %>% 
      mutate(
        velocidade = speed * 1.6,
        distancia = dist * .33,
        taxa = velocidade / distancia
      )
  • Perceba que as colunas antigas continuam lá. Se quiser manter apenas as colunas novas, use transmute:

    cars %>% 
      transmute(
        velocidade = speed * 1.6,
        distancia = dist * .33,
        taxa = velocidade / distancia
      )
  • Ou use o argumento .keep de mutate para escolher com mais precisão. Veja a ajuda de mutate.

3.4.2 Selecionando colunas: select, distinct, pull

  • Vamos voltar à nossa tibble dos top \(100\) da Billboard.

  • Para ver só a coluna de artistas:

    bb_tidy %>% 
      select(artista)
  • Para eliminar as repetições:

    bb_tidy %>% 
      select(artista) %>% 
      distinct()
  • Para ver artistas e músicas:

    bb_tidy %>% 
      select(artista, musica) %>% 
      distinct()
  • Para especificar colunas a não mostrar, use o sinal de menos “-”:

    bb_tidy %>% 
      select(-c(entrou, semana, pos))
  • Para extrair uma coluna na forma de vetor (unique é uma função do R base, aplicável a vetores):

    bb_tidy %>% 
      pull(artista) %>% 
      unique()
    ##   [1] "2 Pac"                          "2Ge+her"                       
    ##   [3] "3 Doors Down"                   "504 Boyz"                      
    ##   [5] "98^0"                           "A*Teens"                       
    ##   [7] "Aaliyah"                        "Adams, Yolanda"                
    ##   [9] "Adkins, Trace"                  "Aguilera, Christina"           
    ##  [11] "Alice Deejay"                   "Allan, Gary"                   
    ##  [13] "Amber"                          "Anastacia"                     
    ##  [15] "Anthony, Marc"                  "Avant"                         
    ##  [17] "BBMak"                          "Backstreet Boys, The"          
    ##  [19] "Badu, Erkyah"                   "Baha Men"                      
    ##  [21] "Barenaked Ladies"               "Beenie Man"                    
    ##  [23] "Before Dark"                    "Bega, Lou"                     
    ##  [25] "Big Punisher"                   "Black Rob"                     
    ##  [27] "Black, Clint"                   "Blaque"                        
    ##  [29] "Blige, Mary J."                 "Blink-182"                     
    ##  [31] "Bloodhound Gang"                "Bon Jovi"                      
    ##  [33] "Braxton, Toni"                  "Brock, Chad"                   
    ##  [35] "Brooks & Dunn"                  "Brooks, Garth"                 
    ##  [37] "Byrd, Tracy"                    "Cagle, Chris"                  
    ##  [39] "Cam'ron"                        "Carey, Mariah"                 
    ##  [41] "Carter, Aaron"                  "Carter, Torrey"                
    ##  [43] "Changing Faces"                 "Chesney, Kenny"                
    ##  [45] "Clark Family Experience"        "Clark, Terri"                  
    ##  [47] "Common"                         "Counting Crows"                
    ##  [49] "Creed"                          "Cyrus, Billy Ray"              
    ##  [51] "D'Angelo"                       "DMX"                           
    ##  [53] "Da Brat"                        "Davidson, Clay"                
    ##  [55] "De La Soul"                     "Destiny's Child"               
    ##  [57] "Diffie, Joe"                    "Dion, Celine"                  
    ##  [59] "Dixie Chicks, The"              "Dr. Dre"                       
    ##  [61] "Drama"                          "Dream"                         
    ##  [63] "Eastsidaz, The"                 "Eiffel 65"                     
    ##  [65] "Elliott, Missy \"Misdemeanor\"" "Eminem"                        
    ##  [67] "En Vogue"                       "Estefan, Gloria"               
    ##  [69] "Evans, Sara"                    "Eve"                           
    ##  [71] "Everclear"                      "Fabian, Lara"                  
    ##  [73] "Fatboy Slim"                    "Filter"                        
    ##  [75] "Foo Fighters"                   "Fragma"                        
    ##  [77] "Funkmaster Flex"                "Ghostface Killah"              
    ##  [79] "Gill, Vince"                    "Gilman, Billy"                 
    ##  [81] "Ginuwine"                       "Goo Goo Dolls"                 
    ##  [83] "Gray, Macy"                     "Griggs, Andy"                  
    ##  [85] "Guy"                            "Hanson"                        
    ##  [87] "Hart, Beth"                     "Heatherly, Eric"               
    ##  [89] "Henley, Don"                    "Herndon, Ty"                   
    ##  [91] "Hill, Faith"                    "Hoku"                          
    ##  [93] "Hollister, Dave"                "Hot Boys"                      
    ##  [95] "Houston, Whitney"               "IMx"                           
    ##  [97] "Ice Cube"                       "Ideal"                         
    ##  [99] "Iglesias, Enrique"              "J-Shin"                        
    ## [101] "Ja Rule"                        "Jackson, Alan"                 
    ## [103] "Jagged Edge"                    "Janet"                         
    ## [105] "Jay-Z"                          "Jean, Wyclef"                  
    ## [107] "Joe"                            "John, Elton"                   
    ## [109] "Jones, Donell"                  "Jordan, Montell"               
    ## [111] "Juvenile"                       "Kandi"                         
    ## [113] "Keith, Toby"                    "Kelis"                         
    ## [115] "Kenny G"                        "Kid Rock"                      
    ## [117] "Kravitz, Lenny"                 "Kumbia Kings"                  
    ## [119] "LFO"                            "LL Cool J"                     
    ## [121] "Larrieux, Amel"                 "Lawrence, Tracy"               
    ## [123] "Levert, Gerald"                 "Lil Bow Wow"                   
    ## [125] "Lil Wayne"                      "Lil' Kim"                      
    ## [127] "Lil' Mo"                        "Lil' Zane"                     
    ## [129] "Limp Bizkit"                    "Lonestar"                      
    ## [131] "Lopez, Jennifer"                "Loveless, Patty"               
    ## [133] "Lox"                            "Lucy Pearl"                    
    ## [135] "Ludacris"                       "M2M"                           
    ## [137] "Madison Avenue"                 "Madonna"                       
    ## [139] "Martin, Ricky"                  "Mary Mary"                     
    ## [141] "Master P"                       "McBride, Martina"              
    ## [143] "McEntire, Reba"                 "McGraw, Tim"                   
    ## [145] "McKnight, Brian"                "Messina, Jo Dee"               
    ## [147] "Metallica"                      "Montgomery Gentry"             
    ## [149] "Montgomery, John Michael"       "Moore, Chante"                 
    ## [151] "Moore, Mandy"                   "Mumba, Samantha"               
    ## [153] "Musiq"                          "Mya"                           
    ## [155] "Mystikal"                       "N'Sync"                        
    ## [157] "Nas"                            "Nelly"                         
    ## [159] "Next"                           "Nine Days"                     
    ## [161] "No Doubt"                       "Nu Flavor"                     
    ## [163] "Offspring, The"                 "Paisley, Brad"                 
    ## [165] "Papa Roach"                     "Pearl Jam"                     
    ## [167] "Pink"                           "Price, Kelly"                  
    ## [169] "Profyle"                        "Puff Daddy"                    
    ## [171] "Q-Tip"                          "R.E.M."                        
    ## [173] "Rascal Flatts"                  "Raye, Collin"                  
    ## [175] "Red Hot Chili Peppers"          "Rimes, LeAnn"                  
    ## [177] "Rogers, Kenny"                  "Ruff Endz"                     
    ## [179] "Sammie"                         "Santana"                       
    ## [181] "Savage Garden"                  "SheDaisy"                      
    ## [183] "Sheist, Shade"                  "Shyne"                         
    ## [185] "Simpson, Jessica"               "Sisqo"                         
    ## [187] "Sister Hazel"                   "Smash Mouth"                   
    ## [189] "Smith, Will"                    "Son By Four"                   
    ## [191] "Sonique"                        "SoulDecision"                  
    ## [193] "Spears, Britney"                "Spencer, Tracie"               
    ## [195] "Splender"                       "Sting"                         
    ## [197] "Stone Temple Pilots"            "Stone, Angie"                  
    ## [199] "Strait, George"                 "Sugar Ray"                     
    ## [201] "TLC"                            "Tamar"                         
    ## [203] "Tamia"                          "Third Eye Blind"               
    ## [205] "Thomas, Carl"                   "Tippin, Aaron"                 
    ## [207] "Train"                          "Trick Daddy"                   
    ## [209] "Trina"                          "Tritt, Travis"                 
    ## [211] "Tuesday"                        "Urban, Keith"                  
    ## [213] "Usher"                          "Vassar, Phil"                  
    ## [215] "Vertical Horizon"               "Vitamin C"                     
    ## [217] "Walker, Clay"                   "Wallflowers, The"              
    ## [219] "Westlife"                       "Williams, Robbie"              
    ## [221] "Wills, Mark"                    "Worley, Darryl"                
    ## [223] "Wright, Chely"                  "Yankee Grey"                   
    ## [225] "Yearwood, Trisha"               "Ying Yang Twins"               
    ## [227] "Zombie Nation"                  "matchbox twenty"

3.4.3 Filtrando linhas: filter, slice

  • Apenas as músicas da Britney Spears:

    bb_tidy %>% 
      filter(artista == 'Spears, Britney')
  • Apenas músicas que chegaram à posição \(1\), sem mostrar a coluna pos:

    bb_tidy %>% 
      filter(pos == 1) %>% 
      select(-pos)
  • Apenas músicas que chegaram à posição \(1\) em menos de \(10\) semanas, mostrando apenas artista e música:

    bb_tidy %>% 
      filter(pos == 1, semana < 10) %>% 
      distinct(artista, musica)
  • As funções da família slice filtram linhas de diversas maneiras.

  • De acordo com seus índices (números de linha):

    bb_tidy %>% 
      slice(c(1, 1000, 5000))
    bb_tidy %>% 
      slice_head(n = 4)
    bb_tidy %>% 
      slice_tail(n = 4)
  • De acordo com a ordenação de uma coluna ou de uma função das colunas:

    bb_tidy %>% 
      slice_min(pos)
    bb_tidy %>% 
      slice_max(semana)
  • Aleatoriamente, criando uma amostra:

    bb_tidy %>% 
      slice_sample(n = 5)
  • Veja a ajuda de slice para saber mais sobre estas funções. Por exemplo:

    • slice_min e slice_max podem considerar ou não empates.

    • Você pode especificar uma proporção de linhas (usando prop) em vez da quantidade de linhas (n).

    • Você pode fazer amostragem com reposição, ou com probabilidades diferentes para cada linha.

3.4.4 Ordenando linhas: arrange

  • Por título, sem repetições:

    bb_tidy %>% 
      select(musica) %>% 
      distinct() %>% 
      arrange(musica)
  • Por título, sem repetições, em ordem inversa:

    bb_tidy %>% 
      select(musica) %>% 
      distinct() %>% 
      arrange(desc(musica))

3.4.5 Contando linhas: count

  • Quantas semanas cada artista ficou nos top \(100\)? Duas músicas na mesma semana contam como duas semanas.

    bb_tidy %>% 
      count(artista, sort = TRUE)
  • Quantas semanas cada música ficou nos top \(100\)?

    bb_tidy %>% 
      count(musica, sort = TRUE)
  • Se houve músicas com o mesmo nome, mas de artistas diferentes, o código acima está errado. O certo é

    bb_tidy %>% 
      count(musica, artista, sort = TRUE)

    De fato, há uma diferença de uma linha.

3.4.5.1 Exercício

  • Ache o título da música que tem dois artistas diferentes.

    Sugestão: conte por música e artista primeiro, depois só por música.

3.4.6 Agrupando linhas: group_by e summarize

  • Qual foi a melhor posição que cada artista alcançou?

    bb_tidy %>% 
      group_by(artista) %>% 
      summarize(melhor = min(pos)) %>% 
      arrange(melhor)
  • Qual foi a melhor posição que cada música alcançou?

    bb_tidy %>% 
      group_by(artista, musica) %>% 
      summarize(melhor = min(pos)) %>% 
      arrange(melhor)
    ## `summarise()` has grouped output by 'artista'. You can override using the
    ## `.groups` argument.
  • Quando usamos summarize, só o agrupamento mais interno é desfeito. Isto significa que o resultado acima ainda está agrupado por artista.

  • Quantas semanas cada artista ficou na posição \(1\)?

    A função n() é uma maneira conveniente de obter o número de linhas de um grupo (ou, se não houver agrupamento, de toda a tibble); mas n() só pode ser chamada em certos contextos, como summarise() ou mutate().

    bb_tidy %>% 
      filter(pos == 1) %>% 
      group_by(artista) %>%
      summarize(semanas = n()) %>% 
      arrange(desc(semanas))
  • Perceba que count, que vimos mais acima, faz agrupamentos do mesmo modo:

    bb_tidy %>% 
      filter(pos == 1) %>% 
      count(artista, sort = TRUE)
  • Uma pergunta diferente: quais são os artistas cujas músicas apareceram no top \(100\) mais tempo depois do lançamento da música?

    bb_tidy %>% 
      group_by(artista) %>% 
      summarize(semanas = max(semana)) %>% 
      arrange(desc(semanas))
  • Qual a posição média de cada música? Lembre-se de que eliminamos as linhas com NA; logo, a média vai ser sobre a quantidade de semanas em que a música esteve na lista.

    media1 <- bb_tidy %>% 
      group_by(artista, musica) %>% 
      summarize(media = mean(pos), .groups = 'drop') %>% 
      arrange(media)
    media1
  • E se quisermos a média sobre o número de semanas desde a entrada da música até a última semana em que a música apareceu na lista?

    media2 <- bb_tidy %>% 
      group_by(artista, musica) %>% 
      summarize(media = sum(pos)/max(semana), .groups = 'drop') %>% 
      arrange(media)
    media2

    As primeiras linhas são iguais, mas os resultados são diferentes:

    identical(media1, media2)
    ## [1] FALSE

3.5 Exercícios

  1. Vamos trabalhar com um conjunto de dados sobre super-heróis.

    Carregue o tidyverse com o comando

    Execute o seguinte comando para ler os dados para uma tibble:

    arquivo <- paste0(
      'https://github.com/fnaufel/',
      'probestr/raw/master/data/',
      'heroes_information.csv'      
    )
    
    herois_info <- read_csv(
      arquivo,
      na = c('', '-', 'NA')
    ) %>% 
      # Eliminar a primeira coluna (números de série)
      select(-1) %>% 
      # Renomear colunas restantes
      rename(
        nome = name,
        sexo = Gender,
        olhos = 'Eye color',
        raça = Race,
        cabelos = 'Hair color',
        altura = Height,
        editora = Publisher,
        pele = 'Skin color',
        lado = Alignment,
        peso = Weight
      )
  2. Quantas linhas tem a tibble?

    herois_info %>% nrow()
    ## [1] 734
  3. Existem heróis que aparecem em mais de uma linha?

    herois_info %>% 
      count(nome)

    Precisaríamos examinar a tabela acima, procurando linhas com \(n > 1\).

    Vamos pedir para o R fazer isto:

    repetidos <- herois_info %>% 
      count(nome) %>% 
      filter(n > 1)
    
    repetidos

    Vamos mostrar mais dados destes heróis:

    herois_info %>% 
      filter(nome %in% repetidos$nome) %>% 
      select(nome, editora, raça, everything())

    Em alguns casos, são editoras diferentes (como para Angel e Atlas).

    Em alguns casos, o mesmo herói aparece com várias características.

    São \(17\) heróis que aparecem mais de uma vez. É um número pequeno o bastante para corrigirmos a situação manualmente.

    Como não tenho conhecimento suficiente sobre heróis para fazer isso, vou ignorar esta confusão e usar os dados como estão.

  4. Quantas editoras diferentes existem na tibble? Liste-as em ordem decrescente de quantidade de heróis.

    herois_info %>% count(editora, sort = TRUE)
  5. Vamos colocar todas as editores menores em uma classe só.

    Na coluna editora, substitua

    • ‘Marvel Comics’ por ‘Marvel’,
    • ‘DC Comics’ por ‘DC’, e
    • todas as outras editoras pelo termo ‘Outras’.

    Dica: use a função case_when(), do tidyverse.

    herois_info <- herois_info %>% 
      mutate(
        editora = case_when(
          editora == 'Marvel Comics' ~ 'Marvel',
          editora == 'DC Comics' ~ 'DC',
          TRUE ~ 'Outras'
        )
    )
  6. Confira, novamente, a quantidade de valores diferentes na coluna editora.

    herois_info %>% count(editora, sort = TRUE)
  7. Existem heróis sem informação de editora. Quantos? Quais são?

    herois_info %>% filter(is.na(editora))

    Na verdade, a chamada a case_when(), da maneira como fiz, já substituiu os NA por ‘Outras’. Entenda por quê.

  8. Altere novamente a coluna editora, colocando o valor ‘Outras’ para os heróis sem informação de editora. Use a função if_else() (com underscore, não a função ifelse).

    Se, no seu caso, ainda houver valores NA em editora, basta fazer o seguinte:

    herois_info <- herois_info %>% 
      mutate(
        editora = if_else(is.na(editora), 'Outras', editora)
      )
  9. Confira, mais uma vez, a quantidade de valores diferentes na coluna editora.

    herois_info %>% count(editora, sort = TRUE)
  10. Existem heróis sem informação de sexo? Quantos? Para estes heróis, coloque o valor ‘Desconhecido’ na coluna sexo.

    herois_info %>% filter(is.na(sexo))
    herois_info <-  herois_info %>% 
      mutate(
        sexo = if_else(
          is.na(sexo),
          'Desconhecido',
          sexo
        )
      )

    Conferindo:

    herois_info %>% filter(is.na(sexo))
  11. Qual a altura mínima? Qual a altura máxima? Substitua as alturas negativas por NA.

    Podemos extrair o vetor de alturas com pull e usar a função summary do R base, que retorna um vetor:

    herois_info %>% 
      pull(altura) %>% 
      summary()
    ##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    ##   -99,0   -99,0   175,0   102,3   185,0   975,0

    Ou podemos usar summarize, do tidyverse, que retorna uma tibble:

    herois_info %>% 
      summarize(
        minimo = min(altura),
        maximo = max(altura)
      )

    Quantas alturas negativas existem?

    herois_info %>% count(altura < 0)

    Substituindo as alturas negativas por NA:

    herois_info <- herois_info %>% 
      mutate(
        altura = if_else(
          altura < 0,
          NA_real_,
          altura
        )
      )

    Como if_else (com underscore) é exigente, precisamos passar NA_real_ em vez de NA.

    Situação atual:

    herois_info %>% 
      pull(altura) %>% 
      summary()
    ##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
    ##    15,2   173,0   183,0   186,7   191,0   975,0     217
  12. Qual o peso mínimo? Qual o peso máximo? Substitua os pesos negativos por NA.

    Como fizemos com as alturas:

    herois_info %>% 
      pull(peso) %>% 
      summary()
    ##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
    ##  -99,00  -99,00   62,00   43,86   90,00  900,00       2

    Observe que existem valores NA em peso.

    herois_info %>% 
      summarize(
        minimo = min(peso),
        maximo = max(peso)
      )

    Para ignorar os valores NA nas funções min() e max():

    herois_info %>% 
      summarize(
        minimo = min(peso, na.rm = TRUE),
        maximo = max(peso, na.rm = TRUE)
      )

    Quantos pesos negativos existem?

    herois_info %>% count(peso < 0)

    Substituindo por NA:

    herois_info <- herois_info %>% 
      mutate(
        peso = if_else(
          peso < 0,
          NA_real_,
          peso
        )
      )

    Como if_else (com underscore) é exigente, precisamos passar NA_real_ em vez de NA.

    Situação atual:

    herois_info %>% 
      pull(peso) %>% 
      summary()
    ##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
    ##     2,0    61,0    81,0   112,3   108,0   900,0     239
  13. Qual é o peso médio de todos os heróis? Ignore os valores NA.

    herois_info %>% pull(peso) %>% mean(na.rm = TRUE)
    ## [1] 112,2525
  14. Qual é a altura média de todos os heróis? Ignore os valores NA.

    herois_info %>% pull(altura) %>% mean(na.rm = TRUE)
    ## [1] 186,7263
  15. Qual é a altura média dos heróis, por editora? Ignore os valores NA.

    herois_info %>% 
      group_by(editora) %>% 
      summarize(média = mean(altura, na.rm = TRUE))
  16. Quais são os \(3\) heróis mais altos de cada sexo?

    herois_info %>% 
      group_by(sexo) %>% 
      slice_max(altura, n = 3) %>% 
      select(nome, sexo, altura)

    Como houve empates, foram mostrados \(4\) de sexo desconhecido e \(4\) do sexo feminino.

    Leia a documentação da função slice_max para descobrir como mostrar exatamente \(n\) de cada grupo. (Dica: “empate”, em inglês, é “tie”.)

  17. Quais são as \(3\) cores de olhos mais comuns para cada sexo?

    herois_info %>% 
      group_by(sexo) %>% 
      count(olhos, sort = TRUE) %>% 
      slice_head(n = 3)
  18. Liste, por editora, as quantidades de heróis do bem, do mal, e neutros.

    herois_info %>% 
      group_by(editora) %>% 
      count(lado)

    ou

    herois_info %>% 
      group_by(editora, lado) %>% 
      summarize(n())
    ## `summarise()` has grouped output by 'editora'. You can override using the
    ## `.groups` argument.
  19. Quantas raças diferentes existem?

    herois_info %>% 
      pull(raça) %>% 
      n_distinct()
    ## [1] 62

    ou (mostrando os nomes das raças e as quantidades de heróis por raça)

    herois_info %>% 
      count(raça)

    ou

    herois_info %>% 
      group_by(raça) %>% 
      summarise(n())
  20. Qual a quantidade de raças diferentes de cada editora?

    herois_info %>% 
      group_by(editora) %>% 
      summarise(n = n_distinct(raça))
  21. DESAFIO: Liste as raças que só pertencem a uma única editora.

    Existem várias maneiras de fazer isto. Experimente várias, até achar uma que seja mais elegante.

    • Maneira simples, usando contagem:

      herois_info %>% 
        group_by(raça) %>% 
        summarise(n_ed = n_distinct(editora)) %>% 
        filter(n_ed == 1)
    • Maneira repetitiva, manual:

      racas_marvel <- herois_info %>% 
        filter(editora == 'Marvel') %>% 
        select(raça) %>% 
        unique()
      
      racas_dc <- herois_info %>% 
        filter(editora == 'DC') %>% 
        select(raça) %>% 
        unique()
      
      racas_outras <- herois_info %>% 
        filter(editora == 'Outras') %>% 
        select(raça) %>% 
        unique()

      Exclusivas da Marvel:

      racas_marvel %>% 
        setdiff(racas_dc) %>% 
        setdiff(racas_outras) %>% 
        arrange(raça)

      Exclusivas da DC:

      racas_dc %>% 
        setdiff(racas_marvel) %>% 
        setdiff(racas_outras) %>% 
        arrange(raça)

      Exclusivas de outras editoras:

      racas_outras %>% 
        setdiff(racas_dc) %>% 
        setdiff(racas_marvel) %>% 
        arrange(raça)
    • Mesma maneira, mas usando uma função:

      racas_exclusivas <- function(x) {
      
        esta_editora <- herois_info %>% 
          filter(editora == x) %>% 
          select(raça) %>% 
          unique()
      
        outras_editoras <- herois_info %>% 
          filter(editora != x) %>% 
          select(raça) %>% 
          unique()
      
        esta_editora %>%
          setdiff(outras_editoras) %>% 
          arrange(raça)
      }
      racas_exclusivas('Marvel')
      racas_exclusivas('DC')
      racas_exclusivas('Outras')
    • Maneira complicada, usando join:

      herois_info %>% 
        select(raça, editora) %>% 
        group_by(raça) %>% 
        summarise(n_editoras = n_distinct(editora)) %>% 
        filter(n_editoras == 1) %>% 
        inner_join(herois_info, by = 'raça') %>% 
        select(raça, editora) %>% 
        unique() %>% 
        arrange(editora)

3.6 Examinando tibbles intermediárias

  • O pacote ViewPipeSteps serve para exibir (no console ou em tabs no RStudio) as tibbles que são resultados de cada passo em uma sequência de comandos montada com o pipe %>%.

  • Instale o pacote com o comando

    install.packages("ViewPipeSteps")
  • Carregue o pacote com

    library(ViewPipeSteps)
  • Para exibir, no console, as tibbles intermediárias, acrescente print_pipe_steps(all = TRUE) após o último passo do pipe:

    resultado <- bb_tidy %>% 
      group_by(artista, musica) %>% 
      summarize(media = sum(pos)/max(semana), .groups = 'drop') %>% 
      arrange(media) %>% 
      print_pipe_steps(all = TRUE)
    ## 1. bb_tidy
    ## # A tibble: 5.307 × 5
    ##   artista musica                  entrou     semana   pos
    ##   <chr>   <chr>                   <date>      <int> <dbl>
    ## 1 2 Pac   Baby Don't Cry (Keep... 2000-02-26      1    87
    ## 2 2 Pac   Baby Don't Cry (Keep... 2000-02-26      2    82
    ## 3 2 Pac   Baby Don't Cry (Keep... 2000-02-26      3    72
    ## 4 2 Pac   Baby Don't Cry (Keep... 2000-02-26      4    77
    ## 5 2 Pac   Baby Don't Cry (Keep... 2000-02-26      5    87
    ## 6 2 Pac   Baby Don't Cry (Keep... 2000-02-26      6    94
    ## # ℹ 5.301 more rows
    ## 2. group_by(artista, musica)
    ## # A tibble: 5.307 × 5
    ##   artista musica                  entrou     semana   pos
    ##   <chr>   <chr>                   <date>      <int> <dbl>
    ## 1 2 Pac   Baby Don't Cry (Keep... 2000-02-26      1    87
    ## 2 2 Pac   Baby Don't Cry (Keep... 2000-02-26      2    82
    ## 3 2 Pac   Baby Don't Cry (Keep... 2000-02-26      3    72
    ## 4 2 Pac   Baby Don't Cry (Keep... 2000-02-26      4    77
    ## 5 2 Pac   Baby Don't Cry (Keep... 2000-02-26      5    87
    ## 6 2 Pac   Baby Don't Cry (Keep... 2000-02-26      6    94
    ## # ℹ 5.301 more rows
    ## 3. summarize(media = sum(pos)/max(semana), .groups = "drop")
    ## # A tibble: 317 × 3
    ##   artista      musica                  media
    ##   <chr>        <chr>                   <dbl>
    ## 1 2 Pac        Baby Don't Cry (Keep...  85.4
    ## 2 2Ge+her      The Hardest Part Of ...  90  
    ## 3 3 Doors Down Kryptonite               26.5
    ## 4 3 Doors Down Loser                    67.1
    ## 5 504 Boyz     Wobble Wobble            56.2
    ## 6 98^0         Give Me Just One Nig...  37.6
    ## # ℹ 311 more rows
    ## 4. arrange(media)
    ## # A tibble: 317 × 3
    ##   artista                          musica                  media
    ##   <chr>                            <chr>                   <dbl>
    ## 1 "Santana"                        Maria, Maria             10.5
    ## 2 "Madonna"                        Music                    13.5
    ## 3 "N'Sync"                         Bye Bye Bye              14.3
    ## 4 "Elliott, Missy \"Misdemeanor\"" Hot Boyz                 14.3
    ## 5 "Destiny's Child"                Independent Women Pa...  14.8
    ## 6 "Iglesias, Enrique"              Be With You              15.8
    ## # ℹ 311 more rows
  • Para exibir as tibbles intermediárias em tabs do RStudio (como com a função View()), você pode usar o addin viewPipeChain, que também faz parte deste pacote. Veja o exemplo no site do pacote.